blob: 29a207c5badcdfa454bf496277c3bb738ff65138 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2005 The Regents of the University of California.
* This material was produced under U.S. Government contract W-7405-ENG-36
* for Los Alamos National Laboratory, which is operated by the University
* of California for the U.S. Department of Energy. The U.S. Government has
* rights to use, reproduce, and distribute this software. NEITHER THE
* GOVERNMENT NOR THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR
* ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified
* to produce derivative works, such modified software should be clearly
* marked, so as not to confuse it with the version available from LANL.
*
* Additionally, this program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* LA-CC 04-115
******************************************************************************/
#ifdef __gnu_linux__
#define _GNU_SOURCE
#endif /* __gnu_linux__ */
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <aif.h>
#include "dbg.h"
#include "dbg_event.h"
#include "backend.h"
#include "list.h"
#include "MI.h"
struct bpentry {
int local;
int remote;
int temp;
};
typedef struct bpentry bpentry;
struct bpmap {
int nels; // number of elements currently in map
int size; // total size of map
struct bpentry * maps;
};
struct varinfo {
char * name; //variable name
MIVar *mivar;
};
typedef struct varinfo varinfo;
struct varmap {
int nels; // number of elements currently in map
int size; // total size of map
struct varinfo * maps;
};
static double GDB_Version;
static int ADDRESS_LENGTH = 0;
static MISession * DebugSession;
static dbg_event * LastEvent;
static void (*EventCallback)(dbg_event *);
static int ServerExit;
static int Started;
static struct bpmap BPMap = { 0, 0, NULL };
#if 0
static struct varmap VARMap = { 0, 0, NULL };
#endif
static int (*AsyncFunc)(void *) = NULL;
static void * AsyncFuncData;
static int GDBMIInit(void (*)(dbg_event *));
static int GDBMIProgress(void);
static int GDBMIInterrupt(void);
static int GDBMIStartSession(char *, char *, char *, char *, char **, char **, long);
static int GDBMISetLineBreakpoint(int, int, int, char *, int, char*, int, int);
static int GDBMISetFuncBreakpoint(int, int, int, char *, char *, char*, int, int);
static int GDBMIDeleteBreakpoint(int);
static int GDBMIEnableBreakpoint(int);
static int GDBMIDisableBreakpoint(int);
static int GDBMIConditionBreakpoint(int, char *expr);
static int GDBMIBreakpointAfter(int, int icount);
static int GDBMIWatchpoint(int, char *, int, int, char *, int);
static int GDBMIGo(void);
static int GDBMIStep(int, int);
static int GDBMITerminate(void);
static int GDBMIListStackframes(int, int);
static int GDBMISetCurrentStackframe(int);
static int GDBMIEvaluateExpression(char *);
static int GDBMIGetNativeType(char *);
static int GDBMIGetLocalVariables(void);
static int GDBMIListArguments(int, int);
static int GDBMIGetInfoThread(void);
static int GDBMISetThreadSelect(int);
static int GDBMIStackInfoDepth(void);
static int GDBMIDataReadMemory(long, char*, char*, int, int, int, char*);
static int GDBMIDataWriteMemory(long, char*, char*, int, char*);
static int GDBMIGetGlobalVariables(void);
static int GDBCLIListSignals(char*);
static int GDBCLISignalInfo(char*);
static int GDBCLIHandle(char*);
static int GDBMIQuit(void);
static int GDBMIDataEvaluateExpression(char*);
static int GDBGetPartialAIF(char *, char *, int, int);
static int GDBMIVarDelete(char*);
static void SendCommandWait(MISession *, MICommand *);
static int SetAndCheckBreak(int, int, int, char *, char *, int, int);
static int GetStackframes(int, int, int, List **);
static int GetAIFVar(char *, AIF **, char **);
static AIF * GetAIF(MIVar *, char *, int);
static AIF * GetPartialAIF(MIVar *, char *);
static void RemoveAllMaps();
dbg_backend_funcs GDBMIBackend =
{
GDBMIInit,
GDBMIProgress,
GDBMIInterrupt,
GDBMIStartSession,
GDBMISetLineBreakpoint,
GDBMISetFuncBreakpoint,
GDBMIDeleteBreakpoint,
GDBMIEnableBreakpoint,
GDBMIDisableBreakpoint,
GDBMIConditionBreakpoint,
GDBMIBreakpointAfter,
GDBMIWatchpoint,
GDBMIGo,
GDBMIStep,
GDBMITerminate,
GDBMIListStackframes,
GDBMISetCurrentStackframe,
GDBMIEvaluateExpression,
GDBMIGetNativeType,
GDBMIGetLocalVariables,
GDBMIListArguments,
GDBMIGetGlobalVariables,
GDBMIGetInfoThread,
GDBMISetThreadSelect,
GDBMIStackInfoDepth,
GDBMIDataReadMemory,
GDBMIDataWriteMemory,
GDBCLIListSignals,
GDBCLISignalInfo,
GDBCLIHandle,
GDBMIDataEvaluateExpression,
GDBGetPartialAIF,
GDBMIVarDelete,
GDBMIQuit
};
#define CHECK_SESSION() \
if (DebugSession == NULL) { \
DbgSetError(DBGERR_NOSESSION, NULL); \
return DBGRES_ERR; \
}
#define ERROR_TO_EVENT(e) \
e = NewDbgEvent(DBGEV_ERROR); \
e->dbg_event_u.error_event.error_code = DbgGetError(); \
e->dbg_event_u.error_event.error_msg = strdup(DbgGetErrorStr())
static char *
GetLastErrorStr(void)
{
return MIGetErrorStr();
}
static void
SaveEvent(dbg_event *e)
{
if (LastEvent != NULL)
FreeDbgEvent(LastEvent);
LastEvent = e;
}
/**** Variable ****/
static MIVar*
CreateMIVar(char *name)
{
MICommand *cmd;
MIVar *mivar;
cmd = MIVarCreate("-", "*", name);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
//DbgSetError(DBGERR_UNKNOWN_VARIABLE, GetLastErrorStr());
MICommandFree(cmd);
return NULL;
}
mivar = MIGetVarCreateInfo(cmd);
MICommandFree(cmd);
return mivar;
}
static void
DeleteMIVar(char *mi_name)
{
MICommand *cmd;
cmd = MIVarDelete(mi_name);
SendCommandWait(DebugSession, cmd);
MICommandFree(cmd);
}
static void
AddBPMap(int local, int remote, int temp)
{
int i;
struct bpentry * map;
if (BPMap.size == 0) {
BPMap.maps = (struct bpentry *)malloc(sizeof(struct bpentry) * 100);
BPMap.size = 100;
for (i = 0; i < BPMap.size; i++) {
map = &BPMap.maps[i];
map->remote = map->local = -1;
map->temp = 0;
}
}
if (BPMap.nels == BPMap.size) {
i = BPMap.size;
BPMap.size *= 2;
BPMap.maps = (struct bpentry *)realloc(BPMap.maps, sizeof(struct bpentry) * BPMap.size);
for (; i < BPMap.size; i++) {
map = &BPMap.maps[i];
map->remote = map->local = -1;
map->temp = 0;
}
}
for (i = 0; i < BPMap.size; i++) {
map = &BPMap.maps[i];
if (map->remote == -1) {
map->remote = remote;
map->local = local;
map->temp = temp;
BPMap.nels++;
break;
}
}
}
static void
RemoveBPMap(bpentry *bp)
{
int i;
struct bpentry * map;
for (i = 0; i < BPMap.size; i++) {
map = &BPMap.maps[i];
if (map == bp) {
map->remote = -1;
map->local = -1;
map->temp = 0;
BPMap.nels--;
break;
}
}
}
static bpentry *
FindLocalBP(int local)
{
int i;
struct bpentry * map;
for (i = 0; i < BPMap.size; i++) {
map = &BPMap.maps[i];
if (map->local == local) {
return map;
}
}
return NULL;
}
static bpentry *
FindRemoteBP(int remote)
{
int i;
struct bpentry * map;
for (i = 0; i < BPMap.size; i++) {
map = &BPMap.maps[i];
if (map->remote == remote) {
return map;
}
}
return NULL;
}
static void
RemoveAllBPMap()
{
int i;
struct bpentry * map;
int length = BPMap.size;
for (i = 0; i < length; i++) {
map = &BPMap.maps[i];
if (map == NULL)
return;
map->remote = -1;
map->local = -1;
map->temp = 0;
BPMap.nels--;
}
}
static stackframe *
get_current_frame()
{
stackframe *f;
List * frames;
if (GetStackframes(1, 0, 0, &frames) != DBGRES_OK)
return NULL;
if (EmptyList(frames)) {
DbgSetError(DBGERR_DEBUGGER, "Could not get current stack frame");
return NULL;
}
SetList(frames);
f = (stackframe *)GetListElement(frames);
DestroyList(frames, NULL);
return f;
}
static stackframe *
ConvertMIFrameToStackframe(MIFrame *f)
{
stackframe * s;
if (f == NULL) {//by default return current frame
return get_current_frame();
}
s = NewStackframe(f->level);
if ( f->addr != NULL )
s->loc.addr = strdup(f->addr);
if ( f->func != NULL )
s->loc.func = strdup(f->func);
if ( f->file != NULL )
s->loc.file = strdup(f->file);
s->loc.line = f->line;
return s;
}
#if 0
static void
AddVARMap(char *name, MIVar *mivar)
{
int i;
struct varinfo *map;
if (VARMap.size == 0) {
VARMap.maps = (struct varinfo *)malloc(sizeof(struct varinfo) * 100);
VARMap.size = 100;
for (i=0; i<VARMap.size; i++) {
map = &VARMap.maps[i];
map->name = NULL;
map->mivar = NULL;
}
}
if (VARMap.nels == VARMap.size) {
i = VARMap.size;
VARMap.size *= 2;
VARMap.maps = (struct varinfo *)realloc(VARMap.maps, sizeof(struct varinfo) * VARMap.size);
for (; i<VARMap.size; i++) {
map = &VARMap.maps[i];
map->name = NULL;
map->mivar = NULL;
}
}
for (i=0; i<VARMap.size; i++) {
map = &VARMap.maps[i];
if (map->name == NULL) {
map->name = strdup(name);
map->mivar = mivar;
VARMap.nels++;
break;
}
}
}
static varinfo *
FindVARByName(char *name)
{
int i;
struct varinfo *map;
for (i=0; i<VARMap.size; i++) {
map = &VARMap.maps[i];
if (map != NULL && strcmp(map->name, name) == 0) {
return map;
}
}
return NULL;
}
static varinfo *
FindVARByMIName(char *mi_name)
{
int i;
struct varinfo *map;
for (i=0; i<VARMap.size; i++) {
map = &VARMap.maps[i];
if (map != NULL && strcmp(map->mivar->name, mi_name) == 0) {
return map;
}
}
return NULL;
}
static void
RemoveVARMap(varinfo *map)
{
if (map != NULL) {
if (map->name != NULL) {
free(map->name);
map->name = NULL;
}
if (map->mivar != NULL) {
DeleteMIVar(map->mivar->name);
MIVarFree(map->mivar);
map->mivar = NULL;
}
VARMap.nels--;
}
}
static void
RemoveVARMapByName(char *name)
{
struct varinfo *map;
map = FindVARByName(name);
RemoveVARMap(map);
}
static void
RemoveVARMapByMIName(char *mi_name)
{
struct varinfo *map;
map = FindVARByMIName(mi_name);
RemoveVARMap(map);
}
static void
RemoveAllVARMap()
{
int i;
struct varinfo *map;
int length = VARMap.size;
for (i = 0; i < length; i++) {
map = &VARMap.maps[i];
if (map == NULL)
return;
RemoveVARMap(map);
}
}
#endif
static void
RemoveAllMaps()
{
RemoveAllBPMap();
#if 0
RemoveAllVARMap();
#endif
}
static void
SetDebugError(MICommand * cmd)
{
if (MICommandResultClass(cmd) == MIResultRecordERROR) {
char *err = MICommandResultErrorMessage(cmd);
if (err != NULL) {
DbgSetError(DBGERR_DEBUGGER, err);
free(err);
} else {
DbgSetError(DBGERR_DEBUGGER, "got error from gdb, but no message");
}
} else {
DbgSetError(DBGERR_DEBUGGER, "bad response from gdb");
}
}
static List *
GetChangedVariables()
{
MICommand *cmd;
List *changes;
List *changedVars;
MIVarChange *var;
cmd = MIVarUpdate("*");
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
DEBUG_PRINTS(DEBUG_LEVEL_BACKEND, "------------------- GetChangedVariables error\n");
SetDebugError(cmd);
MICommandFree(cmd);
return NULL;
}
MIGetVarUpdateInfo(cmd, &changes);
MICommandFree(cmd);
changedVars = NewList();
for (SetList(changes); (var = (MIVarChange *)GetListElement(changes)) != NULL;) {
if (var->in_scope == 1) {
AddToList(changedVars, (void *)strdup(var->name));
}
else {
DeleteMIVar(var->name);
}
}
DestroyList(changes, MIVarChangeFree);
return changedVars;
}
static int
get_info_depth()
{
MICommand *cmd;
int depth;
cmd = MIStackInfoDepth();
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
DEBUG_PRINTS(DEBUG_LEVEL_BACKEND, "------------------- GDBMIStackInfoDepth error\n");
SetDebugError(cmd);
MICommandFree(cmd);
return -1;
}
depth = MIGetStackInfoDepth(cmd);
MICommandFree(cmd);
return depth;
}
/**
* not used
*
static void
set_frame_with_line(stackframe *current_f, int depth)
{
stackframe *f;
List * frames;
if (GetStackframes(0, 1, depth, &frames) != DBGRES_OK) {
return NULL;
}
for (SetList(frames); (f = (stackframe *)GetListElement(frames)) != NULL;) {
if (f->loc.line > 0) {
current_f->level = f->level;
current_f->loc.file = strdup(f->loc.file);
current_f->loc.func = strdup(f->loc.func);
current_f->loc.addr = strdup(f->loc.addr);
current_f->loc.line = f->loc.line;
break;
}
}
DestroyList(frames, FreeStackframe);
}
*/
/**** aysn stop ****/
static int
AsyncStop(void *data)
{
dbg_event * e;
stackframe * frame;
bpentry * bpmap;
MIEvent * evt = (MIEvent *)data;
switch (evt->type)
{
case MIEventTypeBreakpointHit:
bpmap = FindLocalBP(evt->bkptno);
if (!bpmap->temp) {
e = NewDbgEvent(DBGEV_SUSPEND);
e->dbg_event_u.suspend_event.reason = DBGEV_SUSPEND_BPHIT;
e->dbg_event_u.suspend_event.ev_u.bpid = bpmap->remote;
e->dbg_event_u.suspend_event.thread_id = evt->threadId;
e->dbg_event_u.suspend_event.frame = NULL;
e->dbg_event_u.suspend_event.depth = get_info_depth();
e->dbg_event_u.suspend_event.changed_vars = GetChangedVariables();
break;
}
/* else must be a temporary breakpoint drop through... */
RemoveBPMap(bpmap);
case MIEventTypeSuspended:
frame = ConvertMIFrameToStackframe(evt->frame);
if (frame == NULL) {
ERROR_TO_EVENT(e);
}
else {
e = NewDbgEvent(DBGEV_SUSPEND);
e->dbg_event_u.suspend_event.reason = DBGEV_SUSPEND_INT;
e->dbg_event_u.suspend_event.thread_id = evt->threadId;
e->dbg_event_u.suspend_event.frame = frame;
e->dbg_event_u.suspend_event.depth = get_info_depth();
e->dbg_event_u.suspend_event.changed_vars = GetChangedVariables();
}
break;
case MIEventTypeFunctionFinished:
case MIEventTypeSteppingRange:
frame = ConvertMIFrameToStackframe(evt->frame);
if (frame == NULL) {
ERROR_TO_EVENT(e);
}
else {
e = NewDbgEvent(DBGEV_SUSPEND);
e->dbg_event_u.suspend_event.reason = DBGEV_SUSPEND_STEP;
e->dbg_event_u.suspend_event.thread_id = evt->threadId;
e->dbg_event_u.suspend_event.frame = frame;
e->dbg_event_u.suspend_event.depth = get_info_depth();
e->dbg_event_u.suspend_event.changed_vars = GetChangedVariables();
}
break;
case MIEventTypeSignal:
frame = ConvertMIFrameToStackframe(evt->frame);
if (frame == NULL) {
ERROR_TO_EVENT(e);
}
else {
e = NewDbgEvent(DBGEV_SUSPEND);
e->dbg_event_u.suspend_event.reason = DBGEV_SUSPEND_SIGNAL;
e->dbg_event_u.suspend_event.ev_u.sig = NewSignalInfo();
e->dbg_event_u.suspend_event.ev_u.sig->name = strdup(evt->sigName);
e->dbg_event_u.suspend_event.ev_u.sig->desc = strdup(evt->sigMeaning);
e->dbg_event_u.suspend_event.thread_id = evt->threadId;
e->dbg_event_u.suspend_event.frame = frame;
e->dbg_event_u.suspend_event.depth = get_info_depth();
e->dbg_event_u.suspend_event.changed_vars = GetChangedVariables();
}
break;
case MIEventTypeInferiorSignalExit:
e = NewDbgEvent(DBGEV_EXIT);
e->dbg_event_u.exit_event.reason = DBGEV_EXIT_SIGNAL;
e->dbg_event_u.exit_event.ev_u.sig = NewSignalInfo();
e->dbg_event_u.exit_event.ev_u.sig->name = strdup(evt->sigName);
e->dbg_event_u.exit_event.ev_u.sig->desc = strdup(evt->sigMeaning);
//RemoveAllMaps();
break;
case MIEventTypeInferiorExit:
e = NewDbgEvent(DBGEV_EXIT);
e->dbg_event_u.exit_event.reason = DBGEV_EXIT_NORMAL;
e->dbg_event_u.exit_event.ev_u.exit_status = evt->code;
//RemoveAllMaps();
break;
default:
DbgSetError(DBGERR_DEBUGGER, "Unknown reason for stopping");
return DBGRES_ERR;
}
MIEventFree(evt);
if (EventCallback != NULL)
EventCallback(e);
FreeDbgEvent(e);
return DBGRES_OK;
}
/*
** AsyncCallback is called by mi_get_response() when an async response is
** detected. It can't issue any gdb commands or there's a potential
** for deadlock. If commands need to be issues (e.g. to obtain
** current stack frame, they must be called from the main select
** loop using the AsyncFunc() mechanism.
*/
static void
AsyncCallback(MIEvent *evt)
{
AsyncFunc = AsyncStop;
AsyncFuncData = (void *)evt;
}
/*
* Initialize GDB
*/
static int
GDBMIInit(void (*event_callback)(dbg_event *))
{
EventCallback = event_callback;
DebugSession = NULL;
LastEvent = NULL;
GDB_Version = -1.0;
ServerExit = 0;
signal(SIGTERM, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
return DBGRES_OK;
}
#if 0
static int
timeout_cb(void *data)
{
return 0;
}
#endif
/*
* Send command and wait for immediate response.
*/
static void
SendCommandWait(MISession *sess, MICommand *cmd)
{
MISessionSendCommand(sess, cmd);
MIOutput *output = MIOutputNew();
do {
MISessionProgress(sess, output);
if (sess->out_fd == -1) {
DEBUG_PRINTS(DEBUG_LEVEL_BACKEND, "------------------- SendCommandWait sess->out_fd = -1\n");
break;
}
} while (!MISessionCommandCompleted(sess));
}
/*
* Start GDB session
*/
static int
GDBMIStartSession(char *gdb_path, char *prog, char *path, char *work_dir, char **args, char **env, long timeout)
{
char * prog_path;
char ** e;
struct stat st;
MICommand * cmd;
MISession * sess;
if (DebugSession != NULL) {
DbgSetError(DBGERR_SESSION, NULL);
return DBGRES_ERR;
}
/*
* see if we can find the gdb executable
*/
if (*gdb_path == '/') {
if (stat(gdb_path, &st) < 0 || !S_ISREG(st.st_mode)) {
DbgSetError(DBGERR_NOBACKEND, gdb_path);
return DBGRES_ERR;
}
}
if (*work_dir != '\0' && chdir(work_dir) < 0) {
DbgSetError(DBGERR_CHDIR, work_dir);
return DBGRES_ERR;
}
if (path != NULL)
asprintf(&prog_path, "%s/%s", path, prog);
else
prog_path = strdup(prog);
if (access(prog_path, R_OK) < 0) {
DbgSetError(DBGERR_NOFILEDIR, prog_path);
free(prog_path);
return DBGRES_ERR;
}
sess = MISessionNew();
#ifdef DEBUG
MISessionSetDebug(TEST_DEBUG_LEVEL(DEBUG_LEVEL_BACKEND));
#endif /* DEBUG */
MISessionSetTimeout(sess, 0, timeout);
MISessionSetGDBPath(sess, gdb_path);
if (MISessionStartLocal(sess, prog_path) < 0) {
DbgSetError(DBGERR_DEBUGGER, GetLastErrorStr());
MISessionFree(sess);
free(prog_path);
return DBGRES_ERR;
}
free(prog_path);
if (*args != NULL) {
cmd = MIExecArguments(args);
SendCommandWait(sess, cmd);
MICommandFree(cmd);
}
for (e = env; e != NULL && *e != NULL; e++) {
cmd = MIGDBSet("environment", *e);
SendCommandWait(sess, cmd);
MICommandFree(cmd);
}
cmd = MIGDBSet("confirm", "off");
SendCommandWait(sess, cmd);
MICommandFree(cmd);
MISessionRegisterEventCallback(sess, AsyncCallback);
DebugSession = sess;
cmd = MIGDBVersion();
SendCommandWait(sess, cmd);
if (MICommandResultOK(cmd)) {
GDB_Version = CLIGetGDBVersion(cmd);
DEBUG_PRINTF(DEBUG_LEVEL_BACKEND, "------------------- gdb version: %f\n", GDB_Version);
}
MICommandFree(cmd);
Started = 0;
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
/*
* Progress gdb commands.
*/
static int
GDBMIProgress(void)
{
dbg_event * e;
/*
* Check for existing events
*/
if (LastEvent != NULL) {
if (EventCallback != NULL) {
EventCallback(LastEvent);
}
if (ServerExit && LastEvent->event_id == DBGEV_OK) {
if (DebugSession != NULL) {
MISessionFree(DebugSession);
DebugSession = NULL;
}
}
FreeDbgEvent(LastEvent);
LastEvent = NULL;
return 0;
}
if (DebugSession != NULL) {
if (MISessionProgress(DebugSession, MIOutputNew()) < 0) {
MISessionFree(DebugSession);
DebugSession = NULL;
DbgSetError(DBGERR_DEBUGGER, GetLastErrorStr());
ERROR_TO_EVENT(e);
SaveEvent(e);
return 0;
}
/*
* Do any extra async functions. We can call gdbmi safely here
*/
if (AsyncFunc != NULL) {
AsyncFunc(AsyncFuncData);
AsyncFunc = NULL;
return 0;
}
}
return 0;
}
/*
** Set breakpoint at specified line.
*/
static int
GDBMISetLineBreakpoint(int bpid, int isTemp, int isHard, char *file, int line, char *condition, int ignoreCount, int tid)
{
int res;
char * where;
CHECK_SESSION();
if (file == NULL || *file == '\0')
asprintf(&where, "%d", line);
else
asprintf(&where, "%s:%d", file, line);
res = SetAndCheckBreak(bpid, isTemp, isHard, where, condition, ignoreCount, tid);
free(where);
return res;
}
/*
** Set breakpoint at start of specified function.
*/
static int
GDBMISetFuncBreakpoint(int bpid, int isTemp, int isHard, char *file, char *func, char *condition, int ignoreCount, int tid)
{
int res;
char * where;
CHECK_SESSION();
if (file == NULL || *file == '\0')
asprintf(&where, "%s", func);
else
asprintf(&where, "%s:%s", file, func);
res = SetAndCheckBreak(bpid, isTemp, isHard, where, condition, ignoreCount, tid);
free(where);
return res;
}
/*
** Check that breakpoint command has succeded and
** extract appropriate information. Returns breakpoint
** id in bid. Adds to breakpoint list if necessary.
*/
static int
SetAndCheckBreak(int bpid, int isTemp, int isHard, char *where, char *condition, int ignoreCount, int tid)
{
dbg_event * e;
MIBreakpoint * bpt;
MICommand * cmd;
List * bpts;
breakpoint * bp;
if (condition != NULL && strlen(condition) == 0)
condition = NULL;
cmd = MIBreakInsert(isTemp, isHard, condition, ignoreCount, where, tid);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
DbgSetError(DBGERR_NOFILE, GetLastErrorStr());
MICommandFree(cmd);
return DBGRES_ERR;
}
bpts = MIBreakpointGetBreakInsertInfo(cmd);
MICommandFree(cmd);
if (bpts == NULL) {
DbgSetError(DBGERR_NOFILE, where);
//DbgSetError(DBGERR_NOFILE, "error getting breakpoint information");
return DBGRES_ERR;
}
SetList(bpts);
bpt = (MIBreakpoint *)GetListElement(bpts);
AddBPMap(bpt->number, bpid, isTemp);
//if the type is temporary, no need to send bpt set event
if (isTemp) {
SaveEvent(NewDbgEvent(DBGEV_OK));
DestroyList(bpts, MIBreakpointFree);
return DBGRES_OK;
}
bp = NewBreakpoint(bpt->number);
bp->ignore = bpt->ignore;
bp->type = strdup(bpt->type);
bp->hits = bpt->times;
if ( bpt->file != NULL )
bp->loc.file = strdup(bpt->file);
if ( bpt->func != NULL )
bp->loc.func = strdup(bpt->func);
if ( bpt->address != NULL )
bp->loc.addr = strdup(bpt->address);
bp->loc.line = bpt->line;
e = NewDbgEvent(DBGEV_BPSET);
e->dbg_event_u.bpset_event.bpid = bpid;
e->dbg_event_u.bpset_event.bp = bp;
SaveEvent(e);
DestroyList(bpts, MIBreakpointFree);
return DBGRES_OK;
}
/*
** Delete a breakpoint.
*/
static int
GDBMIDeleteBreakpoint(int bpid)
{
bpentry * bp;
char * bpstr;
MICommand * cmd;
CHECK_SESSION();
if ((bp = FindRemoteBP(bpid)) == NULL) {
asprintf(&bpstr, "%d", bpid);
DbgSetError(DBGERR_NOBP, bpstr);
free(bpstr);
return DBGRES_ERR;
}
cmd = MIBreakDelete(1, &bp->local);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
RemoveBPMap(bp);
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
/*
** Enable a breakpoint.
*/
static int
GDBMIEnableBreakpoint(int bpid)
{
bpentry * bp;
char * bpstr;
MICommand * cmd;
CHECK_SESSION();
if ((bp = FindRemoteBP(bpid)) == NULL) {
asprintf(&bpstr, "%d", bpid);
DbgSetError(DBGERR_NOBP, bpstr);
free(bpstr);
return DBGRES_ERR;
}
cmd = MIBreakEnable(1, &bp->local);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
/*
** Disable a breakpoint.
*/
static int
GDBMIDisableBreakpoint(int bpid)
{
bpentry * bp;
char * bpstr;
MICommand * cmd;
CHECK_SESSION();
if ((bp = FindRemoteBP(bpid)) == NULL) {
asprintf(&bpstr, "%d", bpid);
DbgSetError(DBGERR_NOBP, bpstr);
free(bpstr);
return DBGRES_ERR;
}
cmd = MIBreakDisable(1, &bp->local);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
/*
** Condition a breakpoint.
*/
static int
GDBMIConditionBreakpoint(int bpid, char *expr)
{
bpentry * bp;
char * bpstr;
MICommand * cmd;
CHECK_SESSION();
if ((bp = FindRemoteBP(bpid)) == NULL) {
asprintf(&bpstr, "%d", bpid);
DbgSetError(DBGERR_NOBP, bpstr);
free(bpstr);
return DBGRES_ERR;
}
cmd = MIBreakCondition(1, &bp->local, expr);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
/*
** breakpoint after.
*/
static int
GDBMIBreakpointAfter(int bpid, int icount)
{
bpentry * bp;
char * bpstr;
MICommand * cmd;
CHECK_SESSION();
if ((bp = FindRemoteBP(bpid)) == NULL) {
asprintf(&bpstr, "%d", bpid);
DbgSetError(DBGERR_NOBP, bpstr);
free(bpstr);
return DBGRES_ERR;
}
cmd = MIBreakAfter(1, &bp->local, icount);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
/*
* Set watch point
*/
static int
GDBMIWatchpoint(int bpid, char *expr, int isAccess, int isRead, char *condition, int ignoreCount)
{
dbg_event * e;
MIBreakpoint * bpt;
MICommand * cmd;
List * bpts;
breakpoint * bp;
if (condition != NULL && strlen(condition) == 0)
condition = NULL;
cmd = MIBreakWatch(expr, isAccess, isRead);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
bpts = MIBreakpointGetBreakInsertInfo(cmd);
MICommandFree(cmd);
if (bpts == NULL) {
DbgSetError(DBGERR_DEBUGGER, "error getting breakpoint information");
return DBGRES_ERR;
}
SetList(bpts);
bpt = (MIBreakpoint *)GetListElement(bpts);
AddBPMap(bpt->number, bpid, 0); //0 is not temp??
bp = NewBreakpoint(bpt->number);
bp->ignore = bpt->ignore;
bp->type = strdup(bpt->type);
bp->hits = bpt->times;
if (condition != NULL) {
GDBMIConditionBreakpoint(bpid, condition);
}
if (ignoreCount > 0) {
GDBMIBreakpointAfter(bpid, ignoreCount);
}
e = NewDbgEvent(DBGEV_BPSET);
e->dbg_event_u.bpset_event.bpid = bpid;
e->dbg_event_u.bpset_event.bp = bp;
SaveEvent(e);
DestroyList(bpts, MIBreakpointFree);
return DBGRES_OK;
}
/*
** Start/continue executing program.
*/
static int
GDBMIGo(void)
{
MICommand * cmd;
CHECK_SESSION();
if (Started)
cmd = MIExecContinue();
else {
cmd = MIExecRun();
Started = 1;
}
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
MICommandFree(cmd);
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
/*
* Execute count statements.
*
* type step kind
* 0 enter function calls
* 1 do not enter function calls
* 2 step out of function (count ignored)
*/
static int
GDBMIStep(int count, int type)
{
MICommand * cmd;
CHECK_SESSION();
switch ( type ) {
case 0:
cmd = MIExecStep(count);
break;
case 1:
cmd = MIExecNext(count);
break;
case 2:
cmd = MIExecFinish();
break;
default:
DbgSetError(DBGERR_DEBUGGER, "Unknown step type");
return DBGRES_ERR;
}
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
MICommandFree(cmd);
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
/*
** Terminate program execution.
*/
static int
GDBMITerminate(void)
{
MICommand * cmd;
CHECK_SESSION();
cmd = MICommandNew("kill", MIResultRecordDONE);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
MICommandFree(cmd);
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
/*
** Interrupt an executing program.
*/
static int
GDBMIInterrupt(void)
{
MICommand * cmd;
CHECK_SESSION();
/*
* Don't do anything if there's an event pending or the
* target is not running.
*
if (LastEvent != NULL || !gmi_exec_interrupt(MIHandle))
return DBGRES_OK;*/
/*
* Must check async here due to broken MI implementation. AsyncCallback will
* be called inside gmi_exec_interrupt().
*
if (AsyncFunc != NULL) {
AsyncFunc(AsyncFuncData);
AsyncFunc = NULL;
}*/
/*
* Ignore error if target is not running
*/
cmd = MIExecInterrupt();
SendCommandWait(DebugSession, cmd);
MICommandFree(cmd);
return DBGRES_OK;
}
/*
** Move up or down count stack frames.
*/
static int
GDBMISetCurrentStackframe(int level)
{
MICommand * cmd;
CHECK_SESSION();
cmd = MIStackSelectFrame(level);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
MICommandFree(cmd);
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
static int
GetStackframes(int current, int low, int high, List **flist)
{
List * frames;
MIFrame * f;
MICommand * cmd;
stackframe * s;
//checking gdb version
if (current) {
if (GDB_Version > 6.3) {
cmd = MIStackInfoFrame();
}
else {
cmd = CLIFrame();
}
}
else {
if (low == 0 && high == 0) {
cmd = MIStackListAllFrames();
}
else {
cmd = MIStackListFrames(low, high);
}
}
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
DEBUG_PRINTS(DEBUG_LEVEL_BACKEND, "------------------- GetStackframes error\n");
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
if (current)
frames = MIGetFrameInfo(cmd);
else
frames = MIGetStackListFramesInfo(cmd);
MICommandFree(cmd);
if ( frames == NULL )
{
DbgSetError(DBGERR_DEBUGGER, "Failed to get stack frames from backend");
return DBGRES_ERR;
}
*flist = NewList();
for (SetList(frames); (f = (MIFrame *)GetListElement(frames)) != NULL; ) {
s = ConvertMIFrameToStackframe(f);
AddToList(*flist, (void *)s);
}
DestroyList(frames, MIFrameFree);
return DBGRES_OK;
}
/*
** List current or all stack frames.
*/
static int
GDBMIListStackframes(int low, int high)
{
dbg_event * e;
List * frames;
CHECK_SESSION();
if (GetStackframes(0, low, high, &frames) != DBGRES_OK)
return DBGRES_ERR;
e = NewDbgEvent(DBGEV_FRAMES);
e->dbg_event_u.list = frames;
SaveEvent(e);
return DBGRES_OK;
}
#ifdef notdef
struct mi_aif_struct
{
char *fds;
char *data;
};
typedef struct mi_aif_struct mi_aif;
mi_aif *
mi_alloc_aif(void)
{
return (mi_aif *)mi_calloc1(sizeof(mi_aif));
}
mi_aif *
mi_parse_aif(mi_results *c)
{
mi_aif *res = mi_alloc_aif();
if ( res )
{
while ( c )
{
if ( c->type == t_const )
{
if ( strcmp(c->var, "fds") == 0 )
res->fds = c->v.cstr;
else if ( strcmp(c->var, "data") == 0 )
res->data = c->v.cstr;
}
c = c->next;
}
}
return res;
}
mi_aif *
mi_res_aif(mi_h *h)
{
mi_results *r = mi_res_done_var(MIHandle, "aif");
mi_aif *a = NULL;
if (r && r->type == t_tuple)
a = mi_parse_aif(r->v.rs);
mi_free_results(r);
return a;
}
mi_aif *
gmi_aif_evaluate_expression(mi_h *h, char *exp)
{
mi_send(h, "-aif-evaluate-expression \"%s\"\n", exp);
return mi_res_aif(h);
}
int
DumpBinaryValue(MISession *sess, char *exp, char *file)
{
MICommand * cmd;
cmd = MICommandNew("dump binary value", MIResultRecordDONE);
MICommandAddOption(cmd, file, exp);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return -1;
}
MICommandFree(cmd);
return 0;
}
#endif
/*
** List local variables.
*/
static int
GDBMIGetLocalVariables(void)
{
dbg_event * e;
MICommand * cmd;
MIArg * arg;
List * args;
CHECK_SESSION();
cmd = MIStackListLocals(0);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
args = MIGetStackListLocalsInfo(cmd);
MICommandFree(cmd);
e = NewDbgEvent(DBGEV_VARS);
e->dbg_event_u.list = NewList();
for (SetList(args); (arg = (MIArg *)GetListElement(args)) != NULL; ) {
AddToList(e->dbg_event_u.list, (void *)strdup(arg->name));
}
DestroyList(args, MIArgFree);
SaveEvent(e);
return DBGRES_OK;
}
/*
* This is needed to check for a bug in the Linux x86 GCC 4.1 compiler
* that causes gdb 6.4 and 6.5 to crash under certain conditions.
*/
#define GDB_BUG_2188 __gnu_linux__ && __i386__ && __GNUC__ == 4 && __GNUC_MINOR__ == 1
#if GDB_BUG_2188
static int
CurrentFrame(int level, char *name)
{
MICommand * cmd;
MIFrame * frame;
List * frames;
int val = 0;
if (GDB_Version > 6.3 && GDB_Version < 6.7) {
cmd = MIStackListFrames(level, level);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
MICommandFree(cmd);
return val;
}
frames = MIGetStackListFramesInfo(cmd);
//only one frame
SetList(frames);
if ((frame = (MIFrame *)GetListElement(frames)) != NULL) {
if (frame->func != NULL && strncmp(frame->func, name, 4) == 0) {
val = 1;
}
}
DestroyList(frames, MIFrameFree);
}
return val;
}
#endif /* GDB_BUG_2188 */
/*
** List arguments.
*/
static int
GDBMIListArguments(int low, int high)
{
dbg_event * e;
MICommand * cmd;
MIArg * arg;
MIFrame * frame;
List * frames;
CHECK_SESSION();
cmd = MIStackListArguments(0, low, high);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
frames = MIGetStackListArgumentsInfo(cmd);
MICommandFree(cmd);
e = NewDbgEvent(DBGEV_ARGS);
e->dbg_event_u.list = NewList();
/*
* Just look at first frame - we should only get
* one anyway...
* ****** If frame is more than one, no arg needs *****
*/
SetList(frames);
if ((frame = (MIFrame *)GetListElement(frames)) != NULL) {
#if GDB_BUG_2188
if (!CurrentFrame(frame->level, "main")) {
#endif /* GDB_BUG_2188 */
for (SetList(frame->args); (arg = (MIArg *)GetListElement(frame->args)) != NULL; )
AddToList(e->dbg_event_u.list, (void *)strdup(arg->name));
#if GDB_BUG_2188
}
#endif /* GDB_BUG_2188 */
}
DestroyList(frames, MIFrameFree);
SaveEvent(e);
return DBGRES_OK;
}
/*
** List global variables.
*/
static int
GDBMIGetGlobalVariables(void)
{
CHECK_SESSION();
DbgSetError(DBGERR_NOTIMP, NULL);
return DBGRES_ERR;
}
/*
** Quit debugger.
*/
static int
GDBMIQuit(void)
{
MICommand * cmd;
if (DebugSession != NULL) {
cmd = MIGDBExit();
SendCommandWait(DebugSession, cmd);
MICommandFree(cmd);
}
RemoveAllMaps();
SaveEvent(NewDbgEvent(DBGEV_OK));
ServerExit++;
return DBGRES_OK;
}
static int
GDBMIGetInfoThread(void)
{
MICommand * cmd;
dbg_event * e;
char * tid;
CLIInfoThreadsInfo * info;
CHECK_SESSION();
cmd = CLIInfoThreads();
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
DEBUG_PRINTS(DEBUG_LEVEL_BACKEND, "------------------- GDBMIGetInfoThread error\n");
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
info = CLIGetInfoThreadsInfo(cmd);
MICommandFree(cmd);
e = NewDbgEvent(DBGEV_THREADS);
e->dbg_event_u.threads_event.thread_id = info->current_thread_id;
e->dbg_event_u.threads_event.list = NewList();
for (SetList(info->thread_ids); (tid = (char *)GetListElement(info->thread_ids)) != NULL;) {
AddToList(e->dbg_event_u.threads_event.list, (void *)strdup(tid));
}
DestroyList(info->thread_ids, free);
free(info);
SaveEvent(e);
return DBGRES_OK;
}
static int
GDBMISetThreadSelect(int threadNum)
{
MICommand * cmd;
dbg_event * e;
MIThreadSelectInfo * info;
//MIFrame *f;
stackframe *s = NULL;
CHECK_SESSION();
cmd = MIThreadSelect(threadNum);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
info = MISetThreadSelectInfo(cmd);
MICommandFree(cmd);
if (info->frame != NULL) {
s = ConvertMIFrameToStackframe(info->frame);
}
e = NewDbgEvent(DBGEV_THREAD_SELECT);
e->dbg_event_u.thread_select_event.thread_id = info->current_thread_id;
e->dbg_event_u.thread_select_event.frame = s;
MIFrameFree(info->frame);
free(info);
SaveEvent(e);
return DBGRES_OK;
}
static int
GDBMIStackInfoDepth()
{
int depth;
dbg_event * e;
CHECK_SESSION();
if ((depth = get_info_depth()) == -1) {
return DBGRES_ERR;
}
e = NewDbgEvent(DBGEV_STACK_DEPTH);
e->dbg_event_u.stack_depth = depth;
SaveEvent(e);
return DBGRES_OK;
}
static int
GDBMIDataReadMemory(long offset, char* address, char* format, int wordSize, int rows, int cols, char* asChar)
{
MICommand * cmd;
dbg_event * e;
MIDataReadMemoryInfo * info;
MIMemory * mem;
memoryinfo *meminfo = NULL;
memory * m;
CHECK_SESSION();
cmd = MIDataReadMemory(offset, address, format, wordSize, rows, cols, asChar);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
info = MIGetDataReadMemoryInfo(cmd);
MICommandFree(cmd);
e = NewDbgEvent(DBGEV_DATAR_MEM);
if (info != NULL) {
meminfo = NewMemoryInfo();
if (info->addr != NULL) {
meminfo->addr = strdup(info->addr);
}
meminfo->nextRow = info->nextRow;
meminfo->prevRow = info->prevRow;
meminfo->nextPage = info->nextPage;
meminfo->prevPage = info->prevPage;
meminfo->numBytes = info->numBytes;
meminfo->totalBytes = info->totalBytes;
if (info->memories != NULL ) {
meminfo->memories = NewList();
for (SetList(info->memories); (mem = (MIMemory *)GetListElement(info->memories)) != NULL;) {
m = NewMemory();
if (mem->addr != NULL) {
m->addr = strdup(mem->addr);
}
if (mem->ascii != NULL) {
m->ascii = strdup(mem->ascii);
}
if (mem->data != NULL) {
char* d;
m->data = NewList();
for (SetList(mem->data); (d = (char *)GetListElement(mem->data)) != NULL;) {
AddToList(m->data, (void *) strdup(d));
}
}
AddToList(meminfo->memories, (void *)m);
}
}
}
e->dbg_event_u.meminfo = meminfo;
MIDataReadMemoryInfoFree(info);
SaveEvent(e);
return DBGRES_OK;
}
static int
GDBMIDataWriteMemory(long offset, char* address, char* format, int wordSize, char* value)
{
MICommand * cmd;
CHECK_SESSION();
//DEBUG_PRINTS(DEBUG_LEVEL_BACKEND, "----- gdbmi_sevrer: GDBMIDataWriteMemory called ---------\n");
cmd = MIDataWriteMemory(offset, address, format, wordSize, value);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
MICommandFree(cmd);
//TODO
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
static int
GDBCLIListSignals(char* name)
{
MICommand * cmd;
List *signals;
dbg_event * e;
CHECK_SESSION();
cmd = CLIListSignals(name);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
CLIGetSigHandleList(cmd, &signals);
MICommandFree(cmd);
e = NewDbgEvent(DBGEV_SIGNALS);
e->dbg_event_u.list = signals;
SaveEvent(e);
return DBGRES_OK;
}
static int
GDBCLISignalInfo(char* arg)
{
MICommand * cmd;
CHECK_SESSION();
cmd = CLISignalInfo(arg);
MICommandRegisterCallback(cmd, ProcessCLIResultRecord, DebugSession);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
MICommandFree(cmd);
return DBGRES_OK;
}
static int
GDBCLIHandle(char *arg)
{
MICommand *cmd;
CHECK_SESSION();
cmd = CLIHandle(arg);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
MICommandFree(cmd);
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
static int
GDBMIDataEvaluateExpression(char *arg)
{
MICommand *cmd;
dbg_event * e;
char *res = NULL;
CHECK_SESSION();
cmd = MIDataEvaluateExpression(arg);
SendCommandWait(DebugSession, cmd);
if (MICommandResultOK(cmd)) {
res = MIGetDataEvaluateExpressionInfo(cmd);
}
if (res == NULL) {
res = strdup("No value found.");
}
MICommandFree(cmd);
e = NewDbgEvent(DBGEV_DATA_EVA_EX);
e->dbg_event_u.data_expression = res;
SaveEvent(e);
return DBGRES_OK;
}
/*
** Evaluate the expression exp.
*/
static int
GDBMIEvaluateExpression(char *exp)
{
char * type;
AIF * a;
dbg_event * e;
if (GetAIFVar(exp, &a, &type) != DBGRES_OK)
return DBGRES_ERR;
e = NewDbgEvent(DBGEV_DATA);
e->dbg_event_u.data_event.data = a;
e->dbg_event_u.data_event.type_desc = type;
SaveEvent(e);
return DBGRES_OK;
}
/*
** Find native type of variable.
*/
static int
GDBMIGetNativeType(char *var)
{
dbg_event * e;
AIF * a;
char * type;
CHECK_SESSION();
if (GetAIFVar(var, &a, &type) != DBGRES_OK)
return DBGRES_ERR;
e = NewDbgEvent(DBGEV_TYPE);
e->dbg_event_u.type_desc = type;
SaveEvent(e);
AIFFree(a);
return DBGRES_OK;
}
static int
GetAIFVar(char *var, AIF **val, char **type)
{
AIF * res;
MIVar *mivar;
mivar = CreateMIVar(var);
if (mivar == NULL) {
DbgSetError(DBGERR_UNKNOWN_VARIABLE, var);
return DBGRES_ERR;
}
if ((res = GetAIF(mivar, var, 0)) == NULL) {
DbgSetError(DBGERR_UNKNOWN_TYPE, mivar->type);
DeleteMIVar(mivar->name);
MIVarFree(mivar);
return DBGRES_ERR;
}
*type = strdup(mivar->type);
*val = res;
DeleteMIVar(mivar->name);
MIVarFree(mivar);
return DBGRES_OK;
}
static char *
GetVarValue(char *var)
{
char * res;
MICommand * cmd = MIVarEvaluateExpression(var);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return "";
}
res = MIGetVarEvaluateExpressionInfo(cmd);
MICommandFree(cmd);
return res;
}
static int
GetAddressLength()
{
if (ADDRESS_LENGTH != 0) {
return ADDRESS_LENGTH;
}
char * res;
MICommand * cmd = MIDataEvaluateExpression("\"sizeof(char *)\"");
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return 0;
}
res = MIGetDataEvaluateExpressionInfo(cmd);
MICommandFree(cmd);
ADDRESS_LENGTH = (int)strtol(res, NULL, 10);
return ADDRESS_LENGTH;
}
static char *
GetPtypeValue(char *exp)
{
char * type = NULL;
MICommand* cmd = CLIPType(exp);
SendCommandWait(DebugSession, cmd);
type = CLIGetPTypeInfo(cmd);
MICommandFree(cmd);
return type;
}
/********************************************************
* TYPE CONVERSION
********************************************************/
#define T_OTHER 0
#define T_CHAR 1
#define T_SHORT 2
#define T_USHORT 3
#define T_INT 4
#define T_UINT 5
#define T_LONG 6
#define T_ULONG 7
#define T_LONGLONG 8
#define T_ULONGLONG 9
#define T_FLOAT 10
#define T_DOUBLE 11
#define T_STRING 12
#define T_BOOLEAN 13
#define T_CHAR_PTR 14
#define T_FUNCTION 15
#define T_VOID_PTR 16
#define T_UNION 17
#define T_ENUM 18
#define T_ARRAY 19
#define T_STRUCT 20
#define T_POINTER 21
static int
get_simple_type(char *type)
{
char *t = NULL;
int id;
int len = strlen(type);
if (type[len - 1] == ')') { // function
return T_FUNCTION;
}
if (strncmp(type, "void *", 6) == 0) { // void pointer
return T_VOID_PTR;
}
if (strncmp(type, "enum", 4) == 0) { // enum
return T_ENUM;
}
//check modifiers
if (strncmp(type, "const volatile", 14) == 0)
t = strdup(&type[15]); //+ 1 remove whitespeace
else if (strncmp(type, "volatile", 8) == 0)
t = strdup(&type[9]); //+ 1 remove whitespeace
else if (strncmp(type, "const", 5) == 0)
t = strdup(&type[6]); //+ 1 remove whitespeace
else
t = strdup(type);
if (strncmp(t, "char *", 6) == 0)
id = T_CHAR_PTR;
else if (strncmp(t, "char", 4) == 0)
id = T_CHAR;
else if (strncmp(t, "unsigned char", 13) == 0)
id = T_CHAR;
else if (strncmp(t, "short int", 9) == 0 || strncmp(t, "int2", 4) == 0)
id = T_SHORT;
else if (strncmp(t, "short unsigned int", 18) == 0)
id = T_USHORT;
else if (strncmp(t, "int", 3) == 0 || strncmp(t, "int4", 4) == 0)
id = T_INT;
else if (strncmp(t, "unsigned int", 12) == 0)
id = T_UINT;
else if (strncmp(t, "long int", 8) == 0 || strncmp(t, "int8", 4) == 0)
id = T_LONG;
else if (strncmp(t, "long unsigned int", 17) == 0)
id = T_ULONG;
#ifdef CC_HAS_LONG_LONG
else if (strncmp(t, "long long int", 13) == 0 || strncmp(t, "real*16", 7) == 0)
id = T_LONGLONG;
else if (strncmp(t, "long long unsigned int", 22) == 0)
id = T_ULONGLONG;
#endif /* CC_HAS_LONG_LONG */
else if (strncmp(t, "long", 4) == 0 || strncmp(t, "real*4", 6) == 0)
id = T_LONG;
else if (strncmp(t, "float", 5) == 0 || strncmp(t, "real*8", 6) == 0)
id = T_FLOAT;
else if (strncmp(t, "double", 6) == 0)
id = T_DOUBLE;
else if (strncmp(t, "string", 6) == 0)
id = T_STRING;
else if (strncmp(t, "logical4", 8) == 0)
id = T_BOOLEAN;
else
id = T_OTHER;
free(t);
return id;
}
static int
get_complex_type(char *type)
{
int len = strlen(type);
switch (type[len - 1]) {
case ']':
return T_ARRAY;
case '*':
if (type[len - 2] == '*') //pointer pointer
return T_POINTER;
if (strncmp(type, "char", 4) == 0) //char pointer
return T_CHAR_PTR;
return T_POINTER; //normal pointer
default:
if (strncmp(type, "union", 5) == 0)
return T_UNION;
if (strncmp(type, "struct", 6) == 0)
return T_STRUCT;
return T_OTHER;
}
}
static AIF*
GetPrimitiveAIF(int id, char *res)
{
char *pch;
if (res == NULL) {
return NULL;
}
switch (id) {
case T_STRING:
case T_CHAR:
if ((pch = strchr(res, ' ')) != NULL) {
pch++;
if (*pch == '\'') { //character
pch--;
*pch = '\0';
return CharToAIF((char)strtol(res, NULL, 10));
}
else { //string
return StringToAIF(pch);
}
}
else {
return CharToAIF((char)strtol(res, NULL, 10));
}
break;
case T_SHORT:
return ShortToAIF((short)strtol(res, NULL, 10));
case T_USHORT:
return UnsignedShortToAIF((unsigned short)strtoul(res, NULL, 10));
case T_INT:
return IntToAIF((int)strtol(res, NULL, 10));
case T_UINT:
return UnsignedIntToAIF((unsigned int)strtoul(res, NULL, 10));
case T_LONG:
return LongToAIF(strtol(res, NULL, 10));
case T_ULONG:
return UnsignedLongToAIF((unsigned long)strtoul(res, NULL, 10));
#ifdef CC_HAS_LONG_LONG
case T_LONGLONG:
return LongLongToAIF(strtoll(res, NULL));
case T_ULONGLONG:
return UnsignedLongLongToAIF((unsigned long long)strtoull(res, NULL));
#endif /* CC_HAS_LONG_LONG */
case T_FLOAT:
return FloatToAIF((float)strtod(res, NULL));
case T_DOUBLE:
return DoubleToAIF(strtod(res, NULL));
default://other type
return VoidToAIF(0, 0);
}
}
static AIF *
GetAIFPointer(char *addr, AIF *i)
{
AIF *ac;
AIF *a;
char *pch;
if (addr == NULL) {
ac = VoidToAIF(0, 0);
}
else {
if ((pch = strchr(addr, ' ')) != NULL) {
*pch = '\0';
}
addr += 2; //skip 0x
ac = AddressToAIF(addr, GetAddressLength());
}
a = PointerToAIF(ac, i);
AIFFree(ac);
return a;
}
static AIF *
GetCharPointerAIF(char *res)
{
char *pch;
char *val;
AIF *a;
AIF *ac;
if ((pch = strchr(res, ' ')) != NULL) {
val = strdup(pch+1);
*pch = '\0';
res += 2; //skip 0x
ac = AddressToAIF(res, GetAddressLength());
a = CharPointerToAIF(ac, val);
free(val);
AIFFree(ac);
return a;
}
return VoidToAIF(0, 0);
}
static AIF *
GetSimpleAIF(MIVar *var, char *exp)
{
AIF *a = NULL;
AIF *ac;
char *pt;
int id = get_simple_type(var->type);
if (id == T_OTHER) {
pt = GetPtypeValue(var->type);
if (pt != NULL) {
var->type = strdup(pt);
id = get_simple_type(var->type);
free(pt);
}
}
switch (id) {
case T_FUNCTION:
return MakeAIF("&/is4", exp);
case T_VOID_PTR:
ac = VoidToAIF(0, 0);
a = GetAIFPointer(GetVarValue(var->name), ac);
AIFFree(ac);
return a;
case T_ENUM:
return (var->type[4] == ' ') ? EmptyEnumToAIF(&var->type[5]) : EmptyEnumToAIF(NULL);
case T_OTHER:
if (exp == NULL)
return NULL;
return GetSimpleAIF(var, NULL);
default:
return GetPrimitiveAIF(id, GetVarValue(var->name));
}
}
static AIF*
GetNamedAIF(AIF *a, int named)
{
if (FDSType(AIF_FORMAT(a)) != AIF_NAME) {
return NameAIF(a, named);
}
return a;
}
static AIF *
GetStructAIF(MIVar *var, int named)
{
int i;
MIVar * v;
AIF * a;
AIF * ac;
char *pch;
char *struct_name = strdup(var->type);
named++;
if ((pch = strchr(struct_name, ' ')) != NULL) {
pch++;
a = EmptyStructToAIF(pch);
}
else {
a = EmptyStructToAIF(struct_name);
}
free(struct_name);
for (i=0; i<var->numchild; i++) {
v = var->children[i];
//check whether child contains parent
if (strcmp(var->type, v->type) == 0 && strcmp(var->name, v->name)) {
a = GetNamedAIF(a, named);
ac = AIFNull(a);
}
else {
if ((ac = GetAIF(v, v->exp, named)) == NULL) {
AIFFree(a);
return NULL;
}
}
AIFAddFieldToStruct(a, v->exp, ac);
}
return a;
}
static AIF *
GetUnionAIF(MIVar *var, int named)
{
int i;
MIVar * v;
AIF * a;
AIF * ac;
char *union_name = NULL;
named++;
if (var->type[5] == ' ') {
union_name = strdup(&var->type[6]);
}
a = EmptyUnionToAIF(union_name);
if (union_name != NULL)
free(union_name);
for (i=0; i<var->numchild; i++) {
v = var->children[i];
//check whether child contains parent
if (strcmp(var->type, v->type) == 0 && strcmp(var->name, v->name)) {
a = GetNamedAIF(a, named);
ac = AIFNull(a);
}
else {
if ((ac = GetAIF(v, v->exp, named)) == NULL) {
AIFFree(a);
return NULL;
}
}
AIFAddFieldToUnion(a, v->exp, AIF_FORMAT(ac));
//Set the union value
if (i == var->numchild - 1)
AIFSetUnion(a, v->exp, ac);
AIFFree(ac);
}
return a;
}
static AIF *
GetArrayAIF(MIVar *var, int named)
{
int i;
MIVar * v;
AIF * a = NULL;
AIF * ac;
for (i = 0; i < var->numchild; i++) {
v = var->children[i];
if ((ac = GetAIF(v, v->exp, named)) == NULL) {
return NULL;
}
if (a == NULL)
a = EmptyArrayToAIF(0, var->numchild-1, ac);
AIFAddArrayElement(a, i, ac);
AIFFree(ac);
}
return a;
}
static AIF *
GetPointerAIF(MIVar *var, int named)
{
AIF *ac;
AIF *a;
int id;
var->type[strlen(var->type) - 1] = '\0'; //remove pointer
while (var->type[strlen(var->type) - 1] == ' ') {//remove whilespace
var->type[strlen(var->type) - 1] = '\0';
}
id = get_complex_type(var->type);
switch (id) {
case T_POINTER:
ac = GetAIF(var->children[0], var->children[0]->exp, named);
break;
case T_CHAR_PTR:
return GetCharPointerAIF(GetVarValue(var->children[0]->name));
case T_UNION:
ac = GetUnionAIF(var, named);
break;
default:
if (var->numchild == 1) {
ac = GetAIF(var->children[0], var->children[0]->exp, named);
}
else {
ac = GetStructAIF(var, named);
}
break;
}
if (ac == NULL) {
ac = VoidToAIF(0, 0);
}
a = GetAIFPointer(GetVarValue(var->name), ac);
AIFFree(ac);
return a;
}
static AIF *
GetComplexAIF(MIVar *var, char *exp, int named)
{
int id = get_complex_type(var->type);
switch (id) {
case T_ARRAY:
return GetArrayAIF(var, named);
case T_CHAR_PTR:
return GetCharPointerAIF(GetVarValue(var->name));
case T_POINTER:
return GetPointerAIF(var, named);
case T_UNION:
return GetUnionAIF(var, named);
default://struct
return GetStructAIF(var, named);
}
}
static AIF *
GetAIF(MIVar *var, char *exp, int named)
{
MICommand *cmd;
if (strcmp(var->type, "<text variable, no debug info>") == 0) {
DbgSetError(DBGERR_NOSYMS, "");
return NULL;
}
if (var->numchild == 0) { //simple type
return GetSimpleAIF(var, exp);
}
//complex type
cmd = MIVarListChildren(var->name);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
if (MICommandResultClass(cmd) == MIResultRecordERROR) {
char *err = MICommandResultErrorMessage(cmd);
if (err != NULL) {
DbgSetError(DBGERR_DEBUGGER, err);
free(err);
} else {
DbgSetError(DBGERR_DEBUGGER, "got error from gdb, but no message");
}
} else {
DbgSetError(DBGERR_DEBUGGER, "bad response from gdb");
}
MICommandFree(cmd);
return NULL;
}
MIGetVarListChildrenInfo(var, cmd);
MICommandFree(cmd);
return GetComplexAIF(var, exp, named);
}
/*************************** PARTIAL AIF ***************************/
static AIF *
GetPartialArrayAIF(MIVar *var)
{
AIF *a = NULL;
AIF *ac;
int i;
char *pch;
char *pt;
int id;
if (var->children == NULL) {
pch = strchr(var->type, '[');
*pch = '\0';
while (var->type[strlen(var->type) - 1] == ' ') {//remove whilespace
var->type[strlen(var->type) - 1] = '\0';
}
id = get_simple_type(var->type);
if (id == T_OTHER) {
pt = GetPtypeValue(var->type);
if (pt != NULL) {
var->type = strdup(pt);
id = get_simple_type(var->type);
free(pt);
}
}
ac = GetPrimitiveAIF(id, "");
a = EmptyArrayToAIF(0, var->numchild-1, ac);
AIFFree(ac);
}
else {
for (i=0; i<var->numchild; i++) {
ac = GetPartialAIF(var->children[i], NULL);
if (a == NULL) {
a = EmptyArrayToAIF(0, var->numchild-1, ac);
}
AIFAddArrayElement(a, i, ac);
AIFFree(ac);
}
}
return a;
}
static AIF *
GetPartialStructAIF(MIVar *var)
{
AIF *ac;
AIF *a;
int i;
char *pch;
char *struct_name = strdup(var->type);
if ((pch = strchr(struct_name, ' ')) != NULL) {
pch++;
a = EmptyStructToAIF(pch);
}
else {
a = EmptyStructToAIF(struct_name);
}
free(struct_name);
if (var->children != NULL) {
for (i=0; i<var->numchild; i++) {
ac = GetPartialAIF(var->children[i], var->children[i]->exp);
AIFAddFieldToStruct(a, var->children[i]->exp, ac);
AIFFree(ac);
}
}
return a;
}
static AIF *
GetPartialUnionAIF(MIVar *var)
{
AIF *ac;
AIF *a;
int i;
char *union_name = NULL;
if (var->type[5] == ' ') {
union_name = strdup(&var->type[6]);
}
a = EmptyUnionToAIF(union_name);
if (union_name != NULL)
free(union_name);
if (var->children != NULL) {
for (i=0; i<var->numchild; i++) {
ac = GetPartialAIF(var->children[i], var->children[i]->exp);
AIFAddFieldToUnion(a, var->children[i]->exp, AIF_FORMAT(ac));
if (i == var->numchild - 1) {
AIFSetUnion(a, var->children[i]->exp, ac);
}
AIFFree(ac);
}
}
return a;
}
static AIF *
GetPartialPointerAIF(MIVar *var)
{
AIF *ac;
AIF *a;
int id;
if (var->children != NULL) {
var->type[strlen(var->type) - 1] = '\0'; //remove pointer
while (var->type[strlen(var->type) - 1] == ' ') {//remove whilespace
var->type[strlen(var->type) - 1] = '\0';
}
id = get_complex_type(var->type);
switch (id) {
case T_CHAR_PTR:
//replace miname
var->name = strdup(var->children[0]->exp);
a = GetCharPointerAIF(GetVarValue(var->children[0]->name));
break;
case T_POINTER:
//replace miname
var->name = strdup(var->children[0]->exp);
ac = VoidToAIF(0, 0);
a = GetAIFPointer(GetVarValue(var->children[0]->name), ac);
AIFFree(ac);
break;
case T_UNION:
a = GetPartialUnionAIF(var);
break;
default:
if (var->numchild == 1) {
//replace miname
var->name = strdup(var->children[0]->exp);
a = GetPartialAIF(var->children[0], var->children[0]->exp);
}
else {
a = GetPartialStructAIF(var);
}
break;
}
}
else {
id = get_complex_type(var->type);
switch (id) {
case T_CHAR_PTR:
a = GetCharPointerAIF(GetVarValue(var->name));
break;
default:
ac = VoidToAIF(0, 0);
a = GetAIFPointer(GetVarValue(var->name), ac);
AIFFree(ac);
break;
}
}
return a;
}
static AIF *
GetPartialComplexAIF(MIVar *var, char *exp)
{
char *pt;
int id = get_complex_type(var->type);
if (id == T_OTHER) {
pt = GetPtypeValue(var->type);
if (pt != NULL) {
var->type = pt;
id = get_complex_type(var->type);
}
}
switch (id) {
case T_ARRAY:
return GetPartialArrayAIF(var);
case T_CHAR_PTR:
return GetCharPointerAIF(GetVarValue(var->name));
case T_POINTER:
return GetPartialPointerAIF(var);
case T_UNION:
return GetPartialUnionAIF(var);
default://struct
return GetPartialStructAIF(var);
}
}
static AIF *
GetPartialAIF(MIVar *var, char *exp)
{
if (strcmp(var->type, "<text variable, no debug info>") == 0) {
DbgSetError(DBGERR_NOSYMS, "");
return NULL;
}
if (var->numchild == 0) {
return GetSimpleAIF(var, exp);
}
return GetPartialComplexAIF(var, exp);
}
static MIVar *
GetChildrenMIVar(char *mivar_name, MIVar *mivar, int showParentType)
{
MICommand *cmd;
if (showParentType || mivar == NULL) {
cmd = MIVarInfoType(mivar_name);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
MICommandFree(cmd);
return NULL;
}
mivar = MIGetVarInfoType(cmd);
mivar->name = strdup(mivar_name);
MICommandFree(cmd);
}
cmd = MIVarListChildren(mivar_name);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
MICommandFree(cmd);
return NULL;
}
MIGetVarListChildrenInfo(mivar, cmd);
MICommandFree(cmd);
return mivar;
}
static MIVar *
GetMIVarDetails(char *name)
{
MICommand *cmd;
MIVar *mivar;
cmd = MIVarInfoType(name);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
MICommandFree(cmd);
return NULL;
}
mivar = MIGetVarInfoType(cmd);
mivar->name = strdup(name);
MICommandFree(cmd);
cmd = MIVarInfoNumChildren(name);
SendCommandWait(DebugSession, cmd);
MIGetVarInfoNumChildren(cmd, mivar);
MICommandFree(cmd);
return mivar;
}
static int
GDBGetPartialAIF(char* name, char* key, int listChildren, int express)
{
MIVar *mivar;
AIF *a;
dbg_event * e;
char* var_name;
CHECK_SESSION();
//key is first perference if it exists
var_name = (key == NULL || strlen(key) == 0)?name:key;
if (express) {
mivar = GetMIVarDetails(var_name);
}
else {
//@ - for partial array
if (!listChildren || strchr(var_name, '@') != NULL) {
mivar = CreateMIVar(var_name);
if (listChildren) {
mivar = GetChildrenMIVar(mivar->name, mivar, 0);
}
}
else {
mivar = GetChildrenMIVar(var_name, NULL, 1);
}
}
if (mivar == NULL) {
//try again with original variable name
var_name = name;
if ((mivar = CreateMIVar(var_name)) == NULL) {
DbgSetError(DBGERR_UNKNOWN_VARIABLE, var_name);
return DBGRES_ERR;
}
}
if ((a = GetPartialAIF(mivar, var_name)) == NULL) {
DbgSetError(DBGERR_UNKNOWN_TYPE, mivar->type);
MIVarFree(mivar);
return DBGRES_ERR;
}
DEBUG_PRINTF(DEBUG_LEVEL_BACKEND, "---------------------- GDBGetPartialAIF found key: %s, format: %s\n", mivar->name, AIF_FORMAT(a));
e = NewDbgEvent(DBGEV_PARTIAL_AIF);
e->dbg_event_u.partial_aif_event.data = a;
e->dbg_event_u.partial_aif_event.type_desc = strdup(mivar->type);
e->dbg_event_u.partial_aif_event.name = strdup(mivar->name);
MIVarFree(mivar);
SaveEvent(e);
return DBGRES_OK;
}
static int
GDBMIVarDelete(char *name)
{
CHECK_SESSION();
DeleteMIVar(name);
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
#if 0
char tohex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
static int
GDBMIBuildAIFVar(char *var, char *type, char *file, AIF **aif)
{
int n;
int fd;
char * data;
char * ap;
char * bp;
char buf[BUFSIZ];
struct stat sb;
if ( stat(file, &sb) < 0 )
{
DbgSetError(DBGERR_DEBUGGER, (char *)strerror(errno));
return DBGRES_ERR;
}
if ( FDSType(type) == AIF_FUNCTION )
{
/*
** Data is function name
*/
ap = data = malloc(strlen(var) * 2 + 1);
for ( bp = var ; *bp != '\0' ; bp++ )
{
*ap++ = tohex[(*bp >> 4) & 0xf];
*ap++ = tohex[*bp & 0xf];
}
*ap++ = '\0';
}
else
{
if ( (fd = open(file, O_RDONLY)) < 0 )
{
DbgSetError(DBGERR_DEBUGGER, (char *)strerror(errno));
return DBGRES_ERR;
}
ap = data = malloc(sb.st_size * 2 + 1);
while ((n = read(fd, buf, BUFSIZ)) > 0)
{
bp = buf;
while ( n-- > 0 )
{
*ap++ = tohex[(*bp >> 4) & 0xf];
*ap++ = tohex[*bp++ & 0xf];
}
}
*ap++ = '\0';
(void)close(fd);
}
if ( FDSType(type) == AIF_POINTER )
{
/*
* Need to add marker to data
*/
ap = malloc(sb.st_size * 2 + 3);
*ap++ = '0';
*ap++ = '1'; // normal pointer
memcpy(ap, data, sb.st_size * 2 + 1);
data = ap;
}
if ( (*aif = AsciiToAIF(type, data)) == NULL )
{
DbgSetError(DBGERR_DEBUGGER, AIFErrorStr());
return DBGRES_ERR;
}
return DBGRES_OK;
}
#endif