blob: bc4e5912838ed83050b5e9faded344ca5ffcee35 [file]
/******************************************************************************
* 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 "gdb.h"
#include "dbg.h"
#include "dbg_event.h"
#include "backend.h"
#include "signal_info.h"
#include "bpmap.h"
static MISession * DebugSession;
static List * EventList;
static void (*EventCallback)(dbg_event *);
static int ServerExit;
static int Started;
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 *);
static int GDBMIBreakpointAfter(int, int);
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 GDBCLIHandle(char*);
static int GDBMIQuit(void);
static int GDBEvaluatePartialExpression(char *, char *, int, int);
static int GDBMIVarDelete(char*);
static int SetAndCheckBreakpoint(int, int, int, char *, char *, int, int);
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,
NULL,
GDBCLIHandle,
NULL,
GDBEvaluatePartialExpression,
GDBMIVarDelete,
GDBMIQuit
};
#define CHECK_SESSION() \
if (DebugSession == NULL) { \
DbgSetError(DBGERR_NOSESSION, NULL); \
return DBGRES_ERR; \
}
#define ERROR_TO_EVENT(e) \
e = DbgErrorEvent(DbgGetError(), DbgGetErrorStr())
static char *
GetLastErrorStr(void)
{
return MIGetErrorStr();
}
static void
SaveEvent(dbg_event *e)
{
AddToList(EventList, (void *)e);
}
/**** aysnc stop ****/
static int
AsyncStop(void *data)
{
dbg_event * e;
stackframe * frame;
MIEvent * evt = (MIEvent *)data;
switch (evt->type)
{
case MIEventTypeBreakpointHit:
if (!IsTempBP(evt->bkptno)) {
e = NewDbgEvent(DBGEV_SUSPEND);
e->dbg_event_u.suspend_event.reason = DBGEV_SUSPEND_BPHIT;
e->dbg_event_u.suspend_event.ev_u.bpid = GetRemoteBPID(evt->bkptno);
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 = GetMIInfoDepth(DebugSession);
e->dbg_event_u.suspend_event.changed_vars = GetChangedVariables(DebugSession);
break;
}
/* else must be a temporary breakpoint drop through... */
RemoveBPMap(evt->bkptno);
case MIEventTypeSuspended:
if (evt->frame != NULL) {
frame = ConvertMIFrame(evt->frame);
} else {
frame = GetCurrentFrame(DebugSession);
}
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 = GetMIInfoDepth(DebugSession);
e->dbg_event_u.suspend_event.changed_vars = GetChangedVariables(DebugSession);
}
break;
case MIEventTypeFunctionFinished:
case MIEventTypeSteppingRange:
if (evt->frame != NULL) {
frame = ConvertMIFrame(evt->frame);
} else {
frame = GetCurrentFrame(DebugSession);
}
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 = GetMIInfoDepth(DebugSession);
e->dbg_event_u.suspend_event.changed_vars = GetChangedVariables(DebugSession);
}
break;
case MIEventTypeSignal:
if (evt->frame != NULL) {
frame = ConvertMIFrame(evt->frame);
} else {
frame = GetCurrentFrame(DebugSession);
}
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 = GetMIInfoDepth(DebugSession);
e->dbg_event_u.suspend_event.changed_vars = GetChangedVariables(DebugSession);
}
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;
}
static void
StreamTargetCallback(char *str) {
dbg_event *e = NewDbgEvent(DBGEV_OUTPUT);
e->dbg_event_u.output = strdup(str);
SaveEvent(e);
}
/*
* Initialize GDB
*/
static int
GDBMIInit(void (*event_callback)(dbg_event *))
{
EventCallback = event_callback;
DebugSession = NULL;
EventList = NewList();
ServerExit = 0;
signal(SIGTERM, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
return DBGRES_OK;
}
/*
* 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;
float version;
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 (GetGDBVersion(sess, &version) < 0) {
return DBGRES_ERR;
}
DEBUG_PRINTF(DEBUG_LEVEL_BACKEND, "------------------- gdb version: %f\n", version);
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);
MISessionRegisterTargetCallback(sess, StreamTargetCallback);
DebugSession = sess;
Started = 0;
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
/*
* Progress gdb commands.
*/
static int
GDBMIProgress(void)
{
dbg_event * e;
/*
* Check for existing events
*/
if (!EmptyList(EventList)) {
e = (dbg_event *)RemoveFirst(EventList);
if (EventCallback != NULL) {
EventCallback(e);
}
if (ServerExit && e->event_id == DBGEV_OK) {
if (DebugSession != NULL) {
MISessionFree(DebugSession);
DebugSession = NULL;
}
}
FreeDbgEvent(e);
return 0;
}
if (DebugSession != NULL) {
if (MISessionProgress(DebugSession) < 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 = SetAndCheckBreakpoint(bpid, isTemp, isHard, where, condition, ignoreCount, tid);
free(where);
return res;
}
/*
* Set breakpoint at start of specified function.
*
* If the function is "main" and this is a temporary breakpoint, assume that
* this is a result of the "Stop in main() on startup" setting. To deal with
* Fortran in this situation, we first try to set a breakpoint at "MAIN__"
* which is the main Fortran entry point. If this fails, we assume that we
* are debugging C/C++ and set the breakpoint on "main".
*/
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') && isTemp && strcmp(func, "main") == 0) {
res = SetAndCheckBreakpoint(bpid, isTemp, isHard, "MAIN__", condition, ignoreCount, tid);
if (res == DBGRES_OK) {
return res;
}
}
if (file == NULL || *file == '\0')
asprintf(&where, "%s", func);
else
asprintf(&where, "%s:%s", file, func);
res = SetAndCheckBreakpoint(bpid, isTemp, isHard, where, condition, ignoreCount, tid);
free(where);
return res;
}
/*
** Check that breakpoint command has succeeded and
** extract appropriate information. Returns breakpoint id.
** Adds to breakpoint list if necessary.
*/
static int
SetAndCheckBreakpoint(int bpid, int isTemp, int isHard, char *where, char *condition, int ignoreCount, int tid)
{
dbg_event * e;
MIBreakpoint * bpt;
MICommand * cmd;
MIList * bpts;
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);
return DBGRES_ERR;
}
MIListSet(bpts);
bpt = (MIBreakpoint *)MIListGet(bpts);
AddBPMap(bpt->number, bpid, isTemp);
/*
* if the type is temporary, no need to send DBGEV_BPSET event
*/
if (isTemp) {
SaveEvent(NewDbgEvent(DBGEV_OK));
MIListFree(bpts, MIBreakpointFree);
return DBGRES_OK;
}
e = NewDbgEvent(DBGEV_BPSET);
e->dbg_event_u.bpset_event.bpid = bpid;
e->dbg_event_u.bpset_event.bp = ConvertMIBreakpoint(bpt);
SaveEvent(e);
MIListFree(bpts, MIBreakpointFree);
return DBGRES_OK;
}
/*
** Delete a breakpoint.
*/
static int
GDBMIDeleteBreakpoint(int bpid)
{
int bpid_local;
char * bpstr;
MICommand * cmd;
CHECK_SESSION();
if ((bpid_local = GetLocalBPID(bpid)) < 0) {
asprintf(&bpstr, "%d", bpid);
DbgSetError(DBGERR_NOBP, bpstr);
free(bpstr);
return DBGRES_ERR;
}
cmd = MIBreakDelete(1, &bpid_local);
SendCommandWait(DebugSession, cmd);
if (!MICommandResultOK(cmd)) {
SetDebugError(cmd);
MICommandFree(cmd);
return DBGRES_ERR;
}
RemoveBPMap(bpid_local);
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}
/*
** Enable a breakpoint.
*/
static int
GDBMIEnableBreakpoint(int bpid)
{
int bpid_local;
char * bpstr;
MICommand * cmd;
CHECK_SESSION();
if ((bpid_local = GetLocalBPID(bpid)) < 0) {
asprintf(&bpstr, "%d", bpid);
DbgSetError(DBGERR_NOBP, bpstr);
free(bpstr);
return DBGRES_ERR;
}
cmd = MIBreakEnable(1, &bpid_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)
{
int bpid_local;
char * bpstr;
MICommand * cmd;
CHECK_SESSION();
if ((bpid_local = GetLocalBPID(bpid)) < 0) {
asprintf(&bpstr, "%d", bpid);
DbgSetError(DBGERR_NOBP, bpstr);
free(bpstr);
return DBGRES_ERR;
}
cmd = MIBreakDisable(1, &bpid_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)
{
int bpid_local;
char * bpstr;
MICommand * cmd;
CHECK_SESSION();
if ((bpid_local = GetLocalBPID(bpid)) < 0) {
asprintf(&bpstr, "%d", bpid);
DbgSetError(DBGERR_NOBP, bpstr);
free(bpstr);
return DBGRES_ERR;
}
cmd = MIBreakCondition(1, &bpid_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)
{
int bpid_local;
char * bpstr;
MICommand * cmd;
CHECK_SESSION();
if ((bpid_local = GetLocalBPID(bpid)) < 0) {
asprintf(&bpstr, "%d", bpid);
DbgSetError(DBGERR_NOBP, bpstr);
free(bpstr);
return DBGRES_ERR;
}
cmd = MIBreakAfter(1, &bpid_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;
MIList * 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;
}
MIListSet(bpts);
bpt = (MIBreakpoint *)MIListGet(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);
MIListFree(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();
/*
* 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;
}
/*
** List current or all stack frames.
*/
static int
GDBMIListStackframes(int low, int high)
{
dbg_event * e;
List * frames;
CHECK_SESSION();
if (GetStackframes(DebugSession, 0, low, high, &frames) != DBGRES_OK)
return DBGRES_ERR;
e = NewDbgEvent(DBGEV_FRAMES);
e->dbg_event_u.list = frames;
SaveEvent(e);
return DBGRES_OK;
}
/*
** List local variables.
*/
static int
GDBMIGetLocalVariables(void)
{
dbg_event * e;
MICommand * cmd;
MIArg * arg;
MIList * 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 (MIListSet(args); (arg = (MIArg *)MIListGet(args)) != NULL; ) {
AddToList(e->dbg_event_u.list, (void *)strdup(arg->name));
}
MIListFree(args, MIArgFree);
SaveEvent(e);
return DBGRES_OK;
}
/*
** List arguments.
*/
static int
GDBMIListArguments(int low, int high)
{
dbg_event * e;
MICommand * cmd;
MIArg * arg;
MIFrame * frame;
MIList * 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 *****
*/
MIListSet(frames);
if ((frame = (MIFrame *)MIListGet(frames)) != NULL) {
#if GDB_BUG_2188
if (!CurrentFrame(DebugSession, frame->level, "main")) {
#endif /* GDB_BUG_2188 */
for (MIListSet(frame->args); (arg = (MIArg *)MIListGet(frame->args)) != NULL; ) {
AddToList(e->dbg_event_u.list, (void *)strdup(arg->name));
}
#if GDB_BUG_2188
}
#endif /* GDB_BUG_2188 */
}
MIListFree(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);
}
ClearBPMaps();
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 (MIListSet(info->thread_ids); (tid = (char *)MIListGet(info->thread_ids)) != NULL;) {
AddToList(e->dbg_event_u.threads_event.list, (void *)strdup(tid));
}
MIListFree(info->thread_ids, free);
free(info);
SaveEvent(e);
return DBGRES_OK;
}
static int
GDBMISetThreadSelect(int threadNum)
{
MICommand * cmd;
dbg_event * e;
MIThreadSelectInfo * info;
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 = ConvertMIFrame(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 = GetMIInfoDepth(DebugSession)) == -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 (MIListSet(info->memories); (mem = (MIMemory *)MIListGet(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 (MIListSet(mem->data); (d = (char *)MIListGet(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;
MIList * signals;
MISignalInfo * sig;
dbg_event * e;
signal_info * s;
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 = NewList();
for (MIListSet(signals); ((sig = (MISignalInfo *)MIListGet(signals)) != NULL); ) {
s = NewSignalInfo();
s->name = strdup(sig->name);
s->pass = sig->pass;
s->print = sig->print;
s->desc = strdup(sig->desc != NULL ? sig->desc : "");
AddToList(e->dbg_event_u.list, s);
}
SaveEvent(e);
MIListFree(signals, MISignalInfoFree);
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;
}
/*
** Evaluate the expression exp.
*/
static int
GDBMIEvaluateExpression(char *exp)
{
char * type;
AIF * a;
dbg_event * e;
if (GetAIFVar(DebugSession, 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;
e->dbg_event_u.data_event.name = strdup("");
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(DebugSession, 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;
}
/*
* Evaluate a partial expression.
*
* - if 'var_id' is not zero length, use this to look up an existing MI variable
* - if 'var_id' can't be found, or is zero length, create a new variable using 'expr'
* - if 'list_child' is true, get the first level of children for the variable, otherwise
* get minimal information about the variable. Note that the child information is
* always fetched for pointers
*/
static int
GDBEvaluatePartialExpression(char* expr, char* var_id, int list_child, int express)
{
MIVar * mivar = NULL;
AIF * a;
dbg_event * e;
CHECK_SESSION();
DEBUG_PRINTF(DEBUG_LEVEL_BACKEND, "---------------------- GDBGetPartialAIF expr: %s, var_id: %s, list_child: %d, exp: %d\n",
expr, var_id, list_child, express);
if (strlen(var_id) != 0) {
mivar = GetMIVarDetails(DebugSession, var_id, NULL, list_child);
}
if (mivar == NULL) {
mivar = CreateMIVar(DebugSession, expr);
}
if (mivar != NULL) {
if (mivar->numchild == 1 && mivar->children == NULL) {
list_child = 1;
}
mivar = GetMIVarDetails(DebugSession, mivar->name, mivar, list_child);
}
if (mivar == NULL) {
DbgSetError(DBGERR_UNKNOWN_VARIABLE, strlen(var_id) != 0 ? var_id : expr);
return DBGRES_ERR;
}
if ((a = GetPartialAIF(DebugSession, expr, mivar)) == 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_DATA);
e->dbg_event_u.data_event.data = a;
e->dbg_event_u.data_event.type_desc = strdup(mivar->type);
e->dbg_event_u.data_event.name = strdup(mivar->name);
MIVarFree(mivar);
SaveEvent(e);
return DBGRES_OK;
}
static int
GDBMIVarDelete(char *name)
{
CHECK_SESSION();
DeleteMIVar(DebugSession, name);
SaveEvent(NewDbgEvent(DBGEV_OK));
return DBGRES_OK;
}