#include "defs.h"
#include "symtab.h"
#include "symfile.h"
#include "linespec.h"
#include "breakpoint.h"
#include "tracepoint.h"
#include "gdb_string.h"
#include <tcl.h>
#include "gdbtk.h"
#include "gdbtk-cmds.h"
extern struct breakpoint *breakpoint_chain;
extern void report_error (void);
char *bptypes[] =
{"none", "breakpoint", "hw breakpoint", "until",
"finish", "watchpoint", "hw watchpoint",
"read watchpoint", "acc watchpoint",
"longjmp", "longjmp resume", "step resume",
"sigtramp", "watchpoint scope",
"call dummy", "shlib events", "catch load",
"catch unload", "catch fork", "catch vfork",
"catch exec", "catch catch", "catch throw"
};
char *bpdisp[] =
{"delete", "delstop", "disable", "donttouch"};
#define BREAKPOINT_IS_INTERESTING(bp) \
((bp)->type == bp_breakpoint \
|| (bp)->type == bp_hardware_breakpoint \
|| (bp)->type == bp_watchpoint \
|| (bp)->type == bp_hardware_watchpoint \
|| (bp)->type == bp_read_watchpoint \
|| (bp)->type == bp_access_watchpoint)
#define BREAKPOINT_IS_WATCHPOINT(bp) \
((bp)->type == bp_watchpoint \
|| (bp)->type == bp_hardware_watchpoint \
|| (bp)->type == bp_read_watchpoint \
|| (bp)->type == bp_access_watchpoint)
extern struct breakpoint *set_raw_breakpoint (struct symtab_and_line sal,
enum bptype bp_type);
extern void set_breakpoint_count (int);
extern int breakpoint_count;
#define DEFAULT_LIST_SIZE 32
static struct breakpoint **breakpoint_list;
static int breakpoint_list_size = DEFAULT_LIST_SIZE;
static int gdb_find_bp_at_addr (ClientData, Tcl_Interp *, int,
Tcl_Obj * CONST objv[]);
static int gdb_find_bp_at_line (ClientData, Tcl_Interp *, int,
Tcl_Obj * CONST objv[]);
static int gdb_get_breakpoint_info (ClientData, Tcl_Interp *, int,
Tcl_Obj * CONST[]);
static int gdb_get_breakpoint_list (ClientData, Tcl_Interp *, int,
Tcl_Obj * CONST[]);
static int gdb_set_bp (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST objv[]);
static int gdb_set_bp_addr (ClientData, Tcl_Interp *, int,
Tcl_Obj * CONST objv[]);
static int gdb_actions_command (ClientData, Tcl_Interp *, int,
Tcl_Obj * CONST objv[]);
static int gdb_get_trace_frame_num (ClientData, Tcl_Interp *, int,
Tcl_Obj * CONST objv[]);
static int gdb_get_tracepoint_info (ClientData, Tcl_Interp *, int,
Tcl_Obj * CONST objv[]);
static int gdb_get_tracepoint_list (ClientData, Tcl_Interp *, int,
Tcl_Obj * CONST objv[]);
static int gdb_trace_status (ClientData, Tcl_Interp *, int,
Tcl_Obj * CONST[]);
static int gdb_tracepoint_exists_command (ClientData, Tcl_Interp *,
int, Tcl_Obj * CONST objv[]);
static Tcl_Obj *get_breakpoint_commands (struct command_line *cmd);
static int tracepoint_exists (char *args);
void gdbtk_create_breakpoint (int);
void gdbtk_delete_breakpoint (int);
void gdbtk_modify_breakpoint (int);
void gdbtk_create_tracepoint (int);
void gdbtk_delete_tracepoint (int);
void gdbtk_modify_tracepoint (int);
static void breakpoint_notify (int, const char *);
static void tracepoint_notify (int, const char *);
int
Gdbtk_Breakpoint_Init (Tcl_Interp *interp)
{
Tcl_CreateObjCommand (interp, "gdb_find_bp_at_addr", gdbtk_call_wrapper,
gdb_find_bp_at_addr, NULL);
Tcl_CreateObjCommand (interp, "gdb_find_bp_at_line", gdbtk_call_wrapper,
gdb_find_bp_at_line, NULL);
Tcl_CreateObjCommand (interp, "gdb_get_breakpoint_info", gdbtk_call_wrapper,
gdb_get_breakpoint_info, NULL);
Tcl_CreateObjCommand (interp, "gdb_get_breakpoint_list", gdbtk_call_wrapper,
gdb_get_breakpoint_list, NULL);
Tcl_CreateObjCommand (interp, "gdb_set_bp", gdbtk_call_wrapper, gdb_set_bp, NULL);
Tcl_CreateObjCommand (interp, "gdb_set_bp_addr", gdbtk_call_wrapper,
gdb_set_bp_addr, NULL);
Tcl_CreateObjCommand (interp, "gdb_actions",
gdbtk_call_wrapper, gdb_actions_command, NULL);
Tcl_CreateObjCommand (interp, "gdb_get_trace_frame_num",
gdbtk_call_wrapper, gdb_get_trace_frame_num, NULL);
Tcl_CreateObjCommand (interp, "gdb_get_tracepoint_info",
gdbtk_call_wrapper, gdb_get_tracepoint_info, NULL);
Tcl_CreateObjCommand (interp, "gdb_get_tracepoint_list",
gdbtk_call_wrapper, gdb_get_tracepoint_list, NULL);
Tcl_CreateObjCommand (interp, "gdb_is_tracing",
gdbtk_call_wrapper, gdb_trace_status, NULL);
Tcl_CreateObjCommand (interp, "gdb_tracepoint_exists",
gdbtk_call_wrapper, gdb_tracepoint_exists_command, NULL);
breakpoint_list = (struct breakpoint **) xmalloc (breakpoint_list_size * sizeof (struct breakpoint *));
memset (breakpoint_list, 0, breakpoint_list_size * sizeof (struct breakpoint *));
return TCL_OK;
}
static int
gdb_find_bp_at_addr (ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
int i;
CORE_ADDR addr;
Tcl_WideInt waddr;
if (objc != 2)
{
Tcl_WrongNumArgs (interp, 1, objv, "address");
return TCL_ERROR;
}
if (Tcl_GetWideIntFromObj (interp, objv[1], &waddr) != TCL_OK)
return TCL_ERROR;
addr = waddr;
Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
for (i = 0; i < breakpoint_list_size; i++)
{
if (breakpoint_list[i] != NULL
&& breakpoint_list[i]->loc->address == addr)
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewIntObj (i));
}
return TCL_OK;
}
static int
gdb_find_bp_at_line (ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
struct symtab *s;
int i, line;
if (objc != 3)
{
Tcl_WrongNumArgs (interp, 1, objv, "filename line");
return TCL_ERROR;
}
s = lookup_symtab (Tcl_GetStringFromObj (objv[1], NULL));
if (s == NULL)
return TCL_ERROR;
if (Tcl_GetIntFromObj (interp, objv[2], &line) == TCL_ERROR)
{
result_ptr->flags = GDBTK_IN_TCL_RESULT;
return TCL_ERROR;
}
Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
for (i = 0; i < breakpoint_list_size; i++)
if (breakpoint_list[i] != NULL
&& breakpoint_list[i]->line_number == line
&& !strcmp (breakpoint_list[i]->source_file, s->filename))
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewIntObj (i));
return TCL_OK;
}
static int
gdb_get_breakpoint_info (ClientData clientData, Tcl_Interp *interp, int objc,
Tcl_Obj *CONST objv[])
{
struct symtab_and_line sal;
int bpnum;
struct breakpoint *b;
char *funcname, *filename;
Tcl_Obj *new_obj;
if (objc != 2)
{
Tcl_WrongNumArgs (interp, 1, objv, "breakpoint");
return TCL_ERROR;
}
if (Tcl_GetIntFromObj (NULL, objv[1], &bpnum) != TCL_OK)
{
result_ptr->flags = GDBTK_IN_TCL_RESULT;
return TCL_ERROR;
}
b = (bpnum <= breakpoint_list_size ? breakpoint_list[bpnum] : NULL);
if (!b || b->type != bp_breakpoint)
{
gdbtk_set_result (interp, "Breakpoint #%d does not exist.", bpnum);
return TCL_ERROR;
}
sal = find_pc_line (b->loc->address, 0);
filename = symtab_to_filename (sal.symtab);
if (filename == NULL)
filename = "";
Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewStringObj (filename, -1));
funcname = pc_function_name (b->loc->address);
new_obj = Tcl_NewStringObj (funcname, -1);
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, new_obj);
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewIntObj (b->line_number));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewStringObj (core_addr_to_string
(b->loc->address),
-1));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewStringObj (bptypes[b->type], -1));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewBooleanObj (b->enable_state == bp_enabled));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewStringObj (bpdisp[b->disposition], -1));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewIntObj (b->ignore_count));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
get_breakpoint_commands (b->commands));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewStringObj (b->cond_string, -1));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewIntObj (b->thread));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewIntObj (b->hit_count));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewStringObj (BREAKPOINT_IS_WATCHPOINT (b)
? b->exp_string
: b->addr_string, -1));
return TCL_OK;
}
static Tcl_Obj *
get_breakpoint_commands (struct command_line *cmd)
{
Tcl_Obj *obj, *tmp;
obj = Tcl_NewObj ();
while (cmd != NULL)
{
switch (cmd->control_type)
{
case simple_control:
Tcl_ListObjAppendElement (NULL, obj,
Tcl_NewStringObj (cmd->line, -1));
break;
case break_control:
Tcl_ListObjAppendElement (NULL, obj,
Tcl_NewStringObj ("loop_break", -1));
break;
case continue_control:
Tcl_ListObjAppendElement (NULL, obj,
Tcl_NewStringObj ("loop_continue", -1));
break;
case while_control:
tmp = Tcl_NewStringObj ("while ", -1);
Tcl_AppendToObj (tmp, cmd->line, -1);
Tcl_ListObjAppendElement (NULL, obj, tmp);
Tcl_ListObjAppendList (NULL, obj,
get_breakpoint_commands (*cmd->body_list));
Tcl_ListObjAppendElement (NULL, obj,
Tcl_NewStringObj ("end", -1));
break;
case if_control:
tmp = Tcl_NewStringObj ("if ", -1);
Tcl_AppendToObj (tmp, cmd->line, -1);
Tcl_ListObjAppendElement (NULL, obj, tmp);
Tcl_ListObjAppendList (NULL, obj,
get_breakpoint_commands (cmd->body_list[0]));
if (cmd->body_count == 2)
{
Tcl_ListObjAppendElement (NULL, obj,
Tcl_NewStringObj ("else", -1));
Tcl_ListObjAppendList (NULL, obj,
get_breakpoint_commands(cmd->body_list[1]));
}
Tcl_ListObjAppendElement (NULL, obj,
Tcl_NewStringObj ("end", -1));
break;
case invalid_control:
break;
}
cmd = cmd->next;
}
return obj;
}
static int
gdb_get_breakpoint_list (ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
int i;
Tcl_Obj *new_obj;
if (objc != 1)
{
Tcl_WrongNumArgs (interp, 1, objv, NULL);
return TCL_ERROR;
}
for (i = 0; i < breakpoint_list_size; i++)
{
if (breakpoint_list[i] != NULL
&& breakpoint_list[i]->type == bp_breakpoint)
{
new_obj = Tcl_NewIntObj (i);
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, new_obj);
}
}
return TCL_OK;
}
static int
gdb_set_bp (ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
struct symtab_and_line sal;
int line, thread = -1;
struct breakpoint *b;
char *buf, *typestr;
enum bpdisp disp;
if (objc != 4 && objc != 5)
{
Tcl_WrongNumArgs (interp, 1, objv, "filename line type ?thread?");
return TCL_ERROR;
}
sal.symtab = lookup_symtab (Tcl_GetStringFromObj (objv[1], NULL));
if (sal.symtab == NULL)
return TCL_ERROR;
if (Tcl_GetIntFromObj (interp, objv[2], &line) == TCL_ERROR)
{
result_ptr->flags = GDBTK_IN_TCL_RESULT;
return TCL_ERROR;
}
typestr = Tcl_GetStringFromObj (objv[3], NULL);
if (strncmp (typestr, "temp", 4) == 0)
disp = disp_del;
else if (strncmp (typestr, "normal", 6) == 0)
disp = disp_donttouch;
else
{
gdbtk_set_result (interp, "type must be \"temp\" or \"normal\"");
return TCL_ERROR;
}
if (objc == 5)
{
if (Tcl_GetIntFromObj (interp, objv[4], &thread) == TCL_ERROR)
{
result_ptr->flags = GDBTK_IN_TCL_RESULT;
return TCL_ERROR;
}
}
sal.line = line;
if (!find_line_pc (sal.symtab, sal.line, &sal.pc))
return TCL_ERROR;
sal.section = find_pc_overlay (sal.pc);
b = set_raw_breakpoint (sal, bp_breakpoint);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->disposition = disp;
b->thread = thread;
xasprintf (&buf, "%s:%d", basename (Tcl_GetStringFromObj (objv[1], NULL)),
line);
b->addr_string = xstrdup (buf);
free(buf);
breakpoint_create_event (b->number);
return TCL_OK;
}
static int
gdb_set_bp_addr (ClientData clientData, Tcl_Interp *interp, int objc,
Tcl_Obj *CONST objv[])
{
struct symtab_and_line sal;
int thread = -1;
CORE_ADDR addr;
Tcl_WideInt waddr;
struct breakpoint *b;
char *saddr, *typestr;
enum bpdisp disp;
if (objc != 3 && objc != 4)
{
Tcl_WrongNumArgs (interp, 1, objv, "address type ?thread?");
return TCL_ERROR;
}
if (Tcl_GetWideIntFromObj (interp, objv[1], &waddr) != TCL_OK)
return TCL_ERROR;
addr = waddr;
saddr = Tcl_GetStringFromObj (objv[1], NULL);
typestr = Tcl_GetStringFromObj (objv[2], NULL);
if (strncmp (typestr, "temp", 4) == 0)
disp = disp_del;
else if (strncmp (typestr, "normal", 6) == 0)
disp = disp_donttouch;
else
{
gdbtk_set_result (interp, "type must be \"temp\" or \"normal\"");
return TCL_ERROR;
}
if (objc == 4)
{
if (Tcl_GetIntFromObj (interp, objv[3], &thread) == TCL_ERROR)
{
result_ptr->flags = GDBTK_IN_TCL_RESULT;
return TCL_ERROR;
}
}
sal = find_pc_line (addr, 0);
sal.pc = addr;
b = set_raw_breakpoint (sal, bp_breakpoint);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->disposition = disp;
b->thread = thread;
b->addr_string = xstrdup (saddr);
breakpoint_create_event (b->number);
return TCL_OK;
}
void
gdbtk_create_breakpoint (int num)
{
struct breakpoint *b;
for (b = breakpoint_chain; b != NULL; b = b->next)
{
if (b->number == num)
break;
}
if (b == NULL || !BREAKPOINT_IS_INTERESTING (b))
return;
if (num >= breakpoint_list_size)
{
int oldsize = breakpoint_list_size;
while (num >= breakpoint_list_size)
breakpoint_list_size += DEFAULT_LIST_SIZE;
breakpoint_list = (struct breakpoint **) xrealloc (breakpoint_list, breakpoint_list_size * sizeof (struct breakpoint *));
memset (&(breakpoint_list[oldsize]), 0, (breakpoint_list_size - oldsize) * sizeof (struct breakpoint *));
}
breakpoint_list[num] = b;
breakpoint_notify (num, "create");
}
void
gdbtk_delete_breakpoint (int num)
{
if (num >= 0
&& num <= breakpoint_list_size
&& breakpoint_list[num] != NULL)
{
breakpoint_notify (num, "delete");
breakpoint_list[num] = NULL;
}
}
void
gdbtk_modify_breakpoint (int num)
{
if (num >= 0)
breakpoint_notify (num, "modify");
}
static void
breakpoint_notify (int num, const char *action)
{
char *buf;
if (num > breakpoint_list_size
|| num < 0
|| breakpoint_list[num] == NULL
|| breakpoint_list[num]->type != bp_breakpoint)
return;
xasprintf (&buf, "gdbtk_tcl_breakpoint %s %d", action, num);
if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK)
report_error ();
free(buf);
}
static int
gdb_actions_command (ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
struct tracepoint *tp;
Tcl_Obj **actions;
int nactions, i, len;
char *number, *args, *action;
long step_count;
struct action_line *next = NULL, *temp;
enum actionline_type linetype;
if (objc != 3)
{
Tcl_WrongNumArgs (interp, 1, objv, "number actions");
return TCL_ERROR;
}
args = number = Tcl_GetStringFromObj (objv[1], NULL);
tp = get_tracepoint_by_number (&args, 0, 0);
if (tp == NULL)
{
Tcl_AppendStringsToObj (result_ptr->obj_ptr, "Tracepoint \"",
number, "\" does not exist", NULL);
return TCL_ERROR;
}
if (tp->actions != NULL)
free_actions (tp);
step_count = 0;
Tcl_ListObjGetElements (interp, objv[2], &nactions, &actions);
for (i = 0; i < nactions; i++)
{
temp = xmalloc (sizeof (struct action_line));
temp->next = NULL;
action = Tcl_GetStringFromObj (actions[i], &len);
temp->action = savestring (action, len);
linetype = validate_actionline (&(temp->action), tp);
if (linetype == BADLINE)
{
free (temp);
continue;
}
if (next == NULL)
{
tp->actions = temp;
next = temp;
}
else
{
next->next = temp;
next = temp;
}
}
return TCL_OK;
}
static int
gdb_get_trace_frame_num (ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
if (objc != 1)
{
Tcl_WrongNumArgs (interp, 1, objv, "linespec");
return TCL_ERROR;
}
Tcl_SetIntObj (result_ptr->obj_ptr, get_traceframe_number ());
return TCL_OK;
}
static int
gdb_get_tracepoint_info (ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
struct symtab_and_line sal;
int tpnum;
struct tracepoint *tp;
struct action_line *al;
Tcl_Obj *action_list;
char *filename, *funcname;
if (objc != 2)
{
Tcl_WrongNumArgs (interp, 1, objv, "tpnum");
return TCL_ERROR;
}
if (Tcl_GetIntFromObj (NULL, objv[1], &tpnum) != TCL_OK)
{
result_ptr->flags |= GDBTK_IN_TCL_RESULT;
return TCL_ERROR;
}
ALL_TRACEPOINTS (tp)
if (tp->number == tpnum)
break;
if (tp == NULL)
{
gdbtk_set_result (interp, "Tracepoint #%d does not exist", tpnum);
return TCL_ERROR;
}
Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
sal = find_pc_line (tp->address, 0);
filename = symtab_to_filename (sal.symtab);
if (filename == NULL)
filename = "N/A";
Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
Tcl_NewStringObj (filename, -1));
funcname = pc_function_name (tp->address);
Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, Tcl_NewStringObj
(funcname, -1));
Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
Tcl_NewIntObj (sal.line));
Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
Tcl_NewStringObj (core_addr_to_string (tp->address), -1));
Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
Tcl_NewIntObj (tp->enabled_p));
Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
Tcl_NewIntObj (tp->pass_count));
Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
Tcl_NewIntObj (tp->step_count));
Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
Tcl_NewIntObj (tp->thread));
Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
Tcl_NewIntObj (tp->hit_count));
action_list = Tcl_NewObj ();
for (al = tp->actions; al != NULL; al = al->next)
{
Tcl_ListObjAppendElement (interp, action_list,
Tcl_NewStringObj (al->action, -1));
}
Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, action_list);
return TCL_OK;
}
static int
gdb_get_tracepoint_list (ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[])
{
struct tracepoint *tp;
Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
ALL_TRACEPOINTS (tp)
Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
Tcl_NewIntObj (tp->number));
return TCL_OK;
}
static int
gdb_trace_status (ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[])
{
int result = 0;
if (trace_running_p)
result = 1;
Tcl_SetIntObj (result_ptr->obj_ptr, result);
return TCL_OK;
}
static int
tracepoint_exists (char *args)
{
struct tracepoint *tp;
char **canonical;
struct symtabs_and_lines sals;
char *file = NULL;
int result = -1;
sals = decode_line_1 (&args, 1, NULL, 0, &canonical, NULL);
if (sals.nelts == 1)
{
resolve_sal_pc (&sals.sals[0]);
file = xmalloc (strlen (sals.sals[0].symtab->dirname)
+ strlen (sals.sals[0].symtab->filename) + 1);
if (file != NULL)
{
strcpy (file, sals.sals[0].symtab->dirname);
strcat (file, sals.sals[0].symtab->filename);
ALL_TRACEPOINTS (tp)
{
if (tp->address == sals.sals[0].pc)
result = tp->number;
#if 0
else if (tp->source_file != NULL
&& strcmp (tp->source_file, file) == 0
&& sals.sals[0].line == tp->line_number)
result = tp->number;
#endif
}
}
}
if (file != NULL)
free (file);
return result;
}
static int
gdb_tracepoint_exists_command (ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[])
{
char *args;
if (objc != 2)
{
Tcl_WrongNumArgs (interp, 1, objv,
"function:line|function|line|*addr");
return TCL_ERROR;
}
args = Tcl_GetStringFromObj (objv[1], NULL);
Tcl_SetIntObj (result_ptr->obj_ptr, tracepoint_exists (args));
return TCL_OK;
}
void
gdbtk_create_tracepoint (int num)
{
tracepoint_notify (num, "create");
}
void
gdbtk_delete_tracepoint (int num)
{
tracepoint_notify (num, "delete");
}
void
gdbtk_modify_tracepoint (int num)
{
tracepoint_notify (num, "modify");
}
static void
tracepoint_notify (int num, const char *action)
{
char *buf;
xasprintf (&buf, "gdbtk_tcl_tracepoint %s %d", action, num);
if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK)
report_error ();
free(buf);
}