GDB (API)
|
00001 /* Tcl/Tk command definitions for Insight - Breakpoints. 00002 Copyright (C) 2001-2013 Free Software Foundation, Inc. 00003 00004 This file is part of GDB. 00005 00006 This program is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program; if not, write to the Free Software 00018 Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. */ 00020 00021 #include "defs.h" 00022 #include "symtab.h" 00023 #include "symfile.h" 00024 #include "source.h" 00025 #include "linespec.h" 00026 #include "breakpoint.h" 00027 #include "tracepoint.h" 00028 #include "gdb_string.h" 00029 #include <tcl.h> 00030 #include "gdbtk.h" 00031 #include "gdbtk-cmds.h" 00032 #include "observer.h" 00033 #include "arch-utils.h" 00034 #include "exceptions.h" 00035 00036 /* Globals to support action and breakpoint commands. */ 00037 static Tcl_Obj **gdbtk_obj_array; 00038 static int gdbtk_obj_array_cnt; 00039 static int gdbtk_obj_array_ptr; 00040 00041 /* From breakpoint.c */ 00042 extern struct breakpoint *breakpoint_chain; 00043 00044 #define ALL_BREAKPOINTS(B) for (B = breakpoint_chain; B; B = B->next) 00045 00046 /* From gdbtk-hooks.c */ 00047 extern void report_error (void); 00048 00049 /* These two lookup tables are used to translate the type & disposition fields 00050 of the breakpoint structure (respectively) into something gdbtk understands. 00051 They are also used in gdbtk-hooks.c */ 00052 00053 char *bptypes[] = 00054 {"none", "breakpoint", "hw breakpoint", "until", 00055 "finish", "watchpoint", "hw watchpoint", 00056 "read watchpoint", "acc watchpoint", 00057 "longjmp", "longjmp resume", "step resume", 00058 "sigtramp", "watchpoint scope", 00059 "call dummy", "shlib events", "catch load", 00060 "catch unload", "catch fork", "catch vfork", 00061 "catch exec", "catch catch", "catch throw" 00062 }; 00063 char *bpdisp[] = 00064 {"delete", "delstop", "disable", "donttouch"}; 00065 00066 /* Is this breakpoint interesting to a user interface? */ 00067 #define BREAKPOINT_IS_INTERESTING(bp) \ 00068 ((bp)->type == bp_breakpoint \ 00069 || (bp)->type == bp_hardware_breakpoint \ 00070 || (bp)->type == bp_watchpoint \ 00071 || (bp)->type == bp_hardware_watchpoint \ 00072 || (bp)->type == bp_read_watchpoint \ 00073 || (bp)->type == bp_access_watchpoint) 00074 00075 /* 00076 * Forward declarations 00077 */ 00078 00079 /* Breakpoint-related functions */ 00080 static int gdb_find_bp_at_addr (ClientData, Tcl_Interp *, int, 00081 Tcl_Obj * CONST objv[]); 00082 static int gdb_find_bp_at_line (ClientData, Tcl_Interp *, int, 00083 Tcl_Obj * CONST objv[]); 00084 static int gdb_get_breakpoint_info (ClientData, Tcl_Interp *, int, 00085 Tcl_Obj * CONST[]); 00086 static int gdb_get_breakpoint_list (ClientData, Tcl_Interp *, int, 00087 Tcl_Obj * CONST[]); 00088 static int gdb_set_bp (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST objv[]); 00089 00090 /* Tracepoint-related functions */ 00091 static int gdb_actions_command (ClientData, Tcl_Interp *, int, 00092 Tcl_Obj * CONST objv[]); 00093 static int gdb_get_trace_frame_num (ClientData, Tcl_Interp *, int, 00094 Tcl_Obj * CONST objv[]); 00095 static int gdb_get_tracepoint_info (ClientData, Tcl_Interp *, int, 00096 Tcl_Obj * CONST objv[]); 00097 static int gdb_get_tracepoint_list (ClientData, Tcl_Interp *, int, 00098 Tcl_Obj * CONST objv[]); 00099 static int gdb_trace_status (ClientData, Tcl_Interp *, int, 00100 Tcl_Obj * CONST[]); 00101 static int gdb_tracepoint_exists_command (ClientData, Tcl_Interp *, 00102 int, Tcl_Obj * CONST objv[]); 00103 static Tcl_Obj *get_breakpoint_commands (struct command_line *cmd); 00104 00105 static int tracepoint_exists (char *args); 00106 00107 /* Breakpoint/tracepoint events and related functions */ 00108 00109 void gdbtk_create_breakpoint (struct breakpoint *); 00110 void gdbtk_delete_breakpoint (struct breakpoint *); 00111 void gdbtk_modify_breakpoint (struct breakpoint *); 00112 static void breakpoint_notify (int, const char *); 00113 00114 int 00115 Gdbtk_Breakpoint_Init (Tcl_Interp *interp) 00116 { 00117 /* Breakpoint commands */ 00118 Tcl_CreateObjCommand (interp, "gdb_find_bp_at_addr", gdbtk_call_wrapper, 00119 gdb_find_bp_at_addr, NULL); 00120 Tcl_CreateObjCommand (interp, "gdb_find_bp_at_line", gdbtk_call_wrapper, 00121 gdb_find_bp_at_line, NULL); 00122 Tcl_CreateObjCommand (interp, "gdb_get_breakpoint_info", gdbtk_call_wrapper, 00123 gdb_get_breakpoint_info, NULL); 00124 Tcl_CreateObjCommand (interp, "gdb_get_breakpoint_list", gdbtk_call_wrapper, 00125 gdb_get_breakpoint_list, NULL); 00126 Tcl_CreateObjCommand (interp, "gdb_set_bp", gdbtk_call_wrapper, gdb_set_bp, NULL); 00127 00128 /* Tracepoint commands */ 00129 Tcl_CreateObjCommand (interp, "gdb_actions", 00130 gdbtk_call_wrapper, gdb_actions_command, NULL); 00131 Tcl_CreateObjCommand (interp, "gdb_get_trace_frame_num", 00132 gdbtk_call_wrapper, gdb_get_trace_frame_num, NULL); 00133 Tcl_CreateObjCommand (interp, "gdb_get_tracepoint_info", 00134 gdbtk_call_wrapper, gdb_get_tracepoint_info, NULL); 00135 Tcl_CreateObjCommand (interp, "gdb_get_tracepoint_list", 00136 gdbtk_call_wrapper, gdb_get_tracepoint_list, NULL); 00137 Tcl_CreateObjCommand (interp, "gdb_is_tracing", 00138 gdbtk_call_wrapper, gdb_trace_status, NULL); 00139 Tcl_CreateObjCommand (interp, "gdb_tracepoint_exists", 00140 gdbtk_call_wrapper, gdb_tracepoint_exists_command, NULL); 00141 00142 return TCL_OK; 00143 } 00144 00145 /* A line buffer for breakpoint commands and tracepoint actions 00146 input validation. */ 00147 static char * 00148 gdbtk_read_next_line (void) 00149 { 00150 if (gdbtk_obj_array_ptr == gdbtk_obj_array_cnt) 00151 return NULL; 00152 00153 return Tcl_GetStringFromObj (gdbtk_obj_array[gdbtk_obj_array_ptr++], NULL); 00154 } 00155 00156 /* 00157 * This section contains commands for manipulation of breakpoints. 00158 */ 00159 00160 /* set a breakpoint by source file and line number 00161 flags are as follows: 00162 least significant 2 bits are disposition, rest is 00163 type (normally 0). 00164 00165 enum bptype { 00166 bp_breakpoint, Normal breakpoint 00167 bp_hardware_breakpoint, Hardware assisted breakpoint 00168 } 00169 00170 Disposition of breakpoint. Ie: what to do after hitting it. 00171 enum bpdisp { 00172 del, Delete it 00173 del_at_next_stop, Delete at next stop, whether hit or not 00174 disable, Disable it 00175 donttouch Leave it alone 00176 }; 00177 */ 00178 00179 00180 /* This implements the tcl command "gdb_find_bp_at_addr" 00181 00182 * Tcl Arguments: 00183 * addr: CORE_ADDR 00184 * Tcl Result: 00185 * It returns a list of breakpoint numbers 00186 */ 00187 static int 00188 gdb_find_bp_at_addr (ClientData clientData, Tcl_Interp *interp, 00189 int objc, Tcl_Obj *CONST objv[]) 00190 { 00191 CORE_ADDR addr; 00192 Tcl_WideInt waddr; 00193 struct breakpoint *b; 00194 00195 if (objc != 2) 00196 { 00197 Tcl_WrongNumArgs (interp, 1, objv, "address"); 00198 return TCL_ERROR; 00199 } 00200 00201 if (Tcl_GetWideIntFromObj (interp, objv[1], &waddr) != TCL_OK) 00202 return TCL_ERROR; 00203 addr = waddr; 00204 00205 Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL); 00206 ALL_BREAKPOINTS (b) 00207 { 00208 if (b->loc != NULL && b->loc->address == addr) 00209 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00210 Tcl_NewIntObj (b->number)); 00211 } 00212 00213 return TCL_OK; 00214 } 00215 00216 /* This implements the tcl command "gdb_find_bp_at_line" 00217 00218 * Tcl Arguments: 00219 * filename: the file in which to find the breakpoint 00220 * line: the line number for the breakpoint 00221 * Tcl Result: 00222 * It returns a list of breakpoint numbers 00223 */ 00224 static int 00225 gdb_find_bp_at_line (ClientData clientData, Tcl_Interp *interp, 00226 int objc, Tcl_Obj *CONST objv[]) 00227 00228 { 00229 struct symtab *s; 00230 int line; 00231 struct breakpoint *b; 00232 00233 if (objc != 3) 00234 { 00235 Tcl_WrongNumArgs (interp, 1, objv, "filename line"); 00236 return TCL_ERROR; 00237 } 00238 00239 s = lookup_symtab (Tcl_GetStringFromObj (objv[1], NULL)); 00240 if (s == NULL) 00241 return TCL_ERROR; 00242 00243 if (Tcl_GetIntFromObj (interp, objv[2], &line) == TCL_ERROR) 00244 { 00245 result_ptr->flags = GDBTK_IN_TCL_RESULT; 00246 return TCL_ERROR; 00247 } 00248 00249 Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL); 00250 ALL_BREAKPOINTS (b) 00251 { 00252 if (b->loc && b->loc->symtab && b->loc->line_number == line 00253 && !strcmp (b->loc->symtab->filename, s->filename)) 00254 { 00255 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00256 Tcl_NewIntObj (b->number)); 00257 } 00258 } 00259 00260 return TCL_OK; 00261 } 00262 00263 /* This implements the tcl command gdb_get_breakpoint_info 00264 * 00265 * Tcl Arguments: 00266 * breakpoint_number 00267 * Tcl Result: 00268 * A list with {file, function, line_number, address, type, enabled?, 00269 * disposition, ignore_count, {list_of_commands}, 00270 * condition, thread, hit_count user_specification} 00271 */ 00272 static int 00273 gdb_get_breakpoint_info (ClientData clientData, Tcl_Interp *interp, int objc, 00274 Tcl_Obj *CONST objv[]) 00275 { 00276 struct symtab_and_line sal; 00277 int bpnum; 00278 struct breakpoint *b; 00279 struct watchpoint *w; 00280 const char *funcname, *filename; 00281 int isPending = 0; 00282 00283 Tcl_Obj *new_obj; 00284 00285 if (objc != 2) 00286 { 00287 Tcl_WrongNumArgs (interp, 1, objv, "breakpoint"); 00288 return TCL_ERROR; 00289 } 00290 00291 if (Tcl_GetIntFromObj (NULL, objv[1], &bpnum) != TCL_OK) 00292 { 00293 result_ptr->flags = GDBTK_IN_TCL_RESULT; 00294 return TCL_ERROR; 00295 } 00296 00297 b = get_breakpoint (bpnum); 00298 if (!b || b->type != bp_breakpoint) 00299 { 00300 gdbtk_set_result (interp, "Breakpoint #%d does not exist.", bpnum); 00301 return TCL_ERROR; 00302 } 00303 00304 w = (is_watchpoint (b)) ? (struct watchpoint *) b : NULL; 00305 00306 isPending = (b->loc == NULL); 00307 Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL); 00308 /* Pending breakpoints will display "<PENDING>" as the file name and the 00309 user expression into the Function field of the breakpoint view. 00310 "0" and "0" in the line number and address field. */ 00311 if (isPending) 00312 { 00313 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00314 Tcl_NewStringObj ("<PENDING>", -1)); 00315 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00316 Tcl_NewStringObj (b->addr_string, -1)); 00317 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00318 Tcl_NewIntObj (0)); 00319 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00320 Tcl_NewIntObj (0)); 00321 } 00322 else 00323 { 00324 sal = find_pc_line (b->loc->address, 0); 00325 00326 filename = symtab_to_filename (sal.symtab); 00327 if (filename == NULL) 00328 filename = ""; 00329 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00330 Tcl_NewStringObj (filename, -1)); 00331 funcname = pc_function_name (b->loc->address); 00332 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00333 Tcl_NewStringObj (funcname, -1)); 00334 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00335 Tcl_NewIntObj (b->loc->line_number)); 00336 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00337 Tcl_NewStringObj (core_addr_to_string 00338 (b->loc->address), -1)); 00339 } 00340 00341 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00342 Tcl_NewStringObj (bptypes[b->type], -1)); 00343 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00344 Tcl_NewBooleanObj (b->enable_state == bp_enabled)); 00345 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00346 Tcl_NewStringObj (bpdisp[b->disposition], -1)); 00347 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00348 Tcl_NewIntObj (b->ignore_count)); 00349 00350 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00351 get_breakpoint_commands ((breakpoint_commands (b)) ? breakpoint_commands (b) : NULL)); 00352 00353 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00354 Tcl_NewStringObj (b->cond_string, -1)); 00355 00356 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00357 Tcl_NewIntObj (b->thread)); 00358 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00359 Tcl_NewIntObj (b->hit_count)); 00360 00361 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 00362 Tcl_NewStringObj (w ? w->exp_string 00363 : b->addr_string, -1)); 00364 00365 return TCL_OK; 00366 } 00367 00368 /* Helper function for gdb_get_breakpoint_info, this function is 00369 responsible for figuring out what to type at the "commands" command 00370 in gdb's cli in order to get at the same command list passed here. */ 00371 00372 static Tcl_Obj * 00373 get_breakpoint_commands (struct command_line *cmd) 00374 { 00375 Tcl_Obj *obj, *tmp; 00376 00377 obj = Tcl_NewObj (); 00378 while (cmd != NULL) 00379 { 00380 switch (cmd->control_type) 00381 { 00382 case simple_control: 00383 /* A simple command. Just append it. */ 00384 Tcl_ListObjAppendElement (NULL, obj, 00385 Tcl_NewStringObj (cmd->line, -1)); 00386 break; 00387 00388 case break_control: 00389 /* A loop_break */ 00390 Tcl_ListObjAppendElement (NULL, obj, 00391 Tcl_NewStringObj ("loop_break", -1)); 00392 break; 00393 00394 case continue_control: 00395 /* A loop_continue */ 00396 Tcl_ListObjAppendElement (NULL, obj, 00397 Tcl_NewStringObj ("loop_continue", -1)); 00398 break; 00399 00400 case while_control: 00401 /* A while loop. Must append "end" to the end of it. */ 00402 tmp = Tcl_NewStringObj ("while ", -1); 00403 Tcl_AppendToObj (tmp, cmd->line, -1); 00404 Tcl_ListObjAppendElement (NULL, obj, tmp); 00405 Tcl_ListObjAppendList (NULL, obj, 00406 get_breakpoint_commands (*cmd->body_list)); 00407 Tcl_ListObjAppendElement (NULL, obj, 00408 Tcl_NewStringObj ("end", -1)); 00409 break; 00410 00411 case if_control: 00412 /* An if statement. cmd->body_list[0] is the true part, 00413 cmd->body_list[1] contains the "else" (false) part. */ 00414 tmp = Tcl_NewStringObj ("if ", -1); 00415 Tcl_AppendToObj (tmp, cmd->line, -1); 00416 Tcl_ListObjAppendElement (NULL, obj, tmp); 00417 Tcl_ListObjAppendList (NULL, obj, 00418 get_breakpoint_commands (cmd->body_list[0])); 00419 if (cmd->body_count == 2) 00420 { 00421 Tcl_ListObjAppendElement (NULL, obj, 00422 Tcl_NewStringObj ("else", -1)); 00423 Tcl_ListObjAppendList (NULL, obj, 00424 get_breakpoint_commands(cmd->body_list[1])); 00425 } 00426 Tcl_ListObjAppendElement (NULL, obj, 00427 Tcl_NewStringObj ("end", -1)); 00428 break; 00429 00430 case invalid_control: 00431 /* Something invalid. Just skip it. */ 00432 break; 00433 } 00434 00435 cmd = cmd->next; 00436 } 00437 00438 return obj; 00439 } 00440 00441 /* This implements the tcl command gdb_get_breakpoint_list 00442 * It builds up a list of the current breakpoints. 00443 * 00444 * Tcl Arguments: 00445 * None. 00446 * Tcl Result: 00447 * A list of breakpoint numbers. 00448 */ 00449 static int 00450 gdb_get_breakpoint_list (ClientData clientData, Tcl_Interp *interp, 00451 int objc, Tcl_Obj *CONST objv[]) 00452 { 00453 Tcl_Obj *new_obj; 00454 struct breakpoint *b; 00455 00456 if (objc != 1) 00457 { 00458 Tcl_WrongNumArgs (interp, 1, objv, NULL); 00459 return TCL_ERROR; 00460 } 00461 00462 ALL_BREAKPOINTS (b) 00463 { 00464 if (b->type == bp_breakpoint) 00465 { 00466 new_obj = Tcl_NewIntObj (b->number); 00467 Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, new_obj); 00468 } 00469 } 00470 00471 return TCL_OK; 00472 } 00473 00474 /* This implements the tcl command "gdb_set_bp" 00475 * It sets breakpoints, and notifies the GUI. 00476 * 00477 * Tcl Arguments: 00478 * addr: the "address" for the breakpoint (either *ADDR or file:line) 00479 * type: the type of the breakpoint 00480 * thread: optional thread number 00481 * Tcl Result: 00482 * The return value of the call to gdbtk_tcl_breakpoint. 00483 */ 00484 static int 00485 gdb_set_bp (ClientData clientData, Tcl_Interp *interp, 00486 int objc, Tcl_Obj *CONST objv[]) 00487 { 00488 int temp, ignore_count, thread, pending, enabled; 00489 char *address, *typestr, *condition; 00490 struct gdb_exception e; 00491 00492 /* Insight does not use all of these (yet?). */ 00493 ignore_count = 0; 00494 condition = NULL; 00495 pending = 0; 00496 enabled = 1; 00497 00498 if (objc != 3 && objc != 4) 00499 { 00500 Tcl_WrongNumArgs (interp, 1, objv, "addr type ?thread?"); 00501 return TCL_ERROR; 00502 } 00503 00504 address = Tcl_GetStringFromObj (objv[1], NULL); 00505 if (address == NULL) 00506 { 00507 result_ptr->flags = GDBTK_IN_TCL_RESULT; 00508 return TCL_ERROR; 00509 } 00510 00511 typestr = Tcl_GetStringFromObj (objv[2], NULL); 00512 if (strncmp (typestr, "temp", 4) == 0) 00513 temp = 1; 00514 else if (strncmp (typestr, "normal", 6) == 0) 00515 temp = 0; 00516 else 00517 { 00518 gdbtk_set_result (interp, "type must be \"temp\" or \"normal\""); 00519 return TCL_ERROR; 00520 } 00521 00522 if (objc == 4) 00523 { 00524 if (Tcl_GetIntFromObj (interp, objv[3], &thread) == TCL_ERROR) 00525 { 00526 result_ptr->flags = GDBTK_IN_TCL_RESULT; 00527 return TCL_ERROR; 00528 } 00529 } 00530 00531 TRY_CATCH (e, RETURN_MASK_ALL) 00532 { 00533 create_breakpoint (get_current_arch (), address, condition, thread, 00534 NULL, 00535 0 /* condition and thread are valid */, 00536 temp, 00537 bp_breakpoint /* type wanted */, 00538 ignore_count, 00539 (pending ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE), 00540 &bkpt_breakpoint_ops, 00541 0 /* from_tty */, 00542 enabled, 0, 0); 00543 } 00544 00545 if (e.reason < 0) 00546 return TCL_ERROR; 00547 00548 return TCL_OK; 00549 } 00550 00551 /* 00552 * This section contains functions that deal with breakpoint 00553 * events from gdb. 00554 */ 00555 00556 /* The next three functions use breakpoint_notify to allow the GUI 00557 * to handle creating, deleting and modifying breakpoints. These three 00558 * functions are put into the appropriate gdb hooks in gdbtk_init. 00559 */ 00560 00561 void 00562 gdbtk_create_breakpoint (struct breakpoint *b) 00563 { 00564 if (b == NULL || !BREAKPOINT_IS_INTERESTING (b)) 00565 return; 00566 00567 breakpoint_notify (b->number, "create"); 00568 } 00569 00570 void 00571 gdbtk_delete_breakpoint (struct breakpoint *b) 00572 { 00573 breakpoint_notify (b->number, "delete"); 00574 } 00575 00576 void 00577 gdbtk_modify_breakpoint (struct breakpoint *b) 00578 { 00579 if (b->number >= 0) 00580 breakpoint_notify (b->number, "modify"); 00581 } 00582 00583 /* This is the generic function for handling changes in 00584 * a breakpoint. It routes the information to the Tcl 00585 * command "gdbtk_tcl_breakpoint" (or "gdbtk_tcl_tracepoint") in the form: 00586 * gdbtk_tcl_breakpoint action b_number b_address b_line b_file 00587 * On error, the error string is written to gdb_stdout. 00588 */ 00589 static void 00590 breakpoint_notify (int num, const char *action) 00591 { 00592 char *buf; 00593 struct breakpoint *b; 00594 00595 b = get_breakpoint (num); 00596 if (b == NULL) 00597 { 00598 struct tracepoint *tp; 00599 00600 tp = get_tracepoint (num); 00601 if (tp == NULL) 00602 return; 00603 b = &tp->base; 00604 } 00605 00606 if (b->number < 0 00607 /* FIXME: should not be so restrictive... */ 00608 || (b->type != bp_breakpoint 00609 && b->type != bp_tracepoint 00610 && b->type != bp_fast_tracepoint)) 00611 return; 00612 00613 /* We ensure that ACTION contains no special Tcl characters, so we 00614 can do this. */ 00615 if (b->type == bp_breakpoint) 00616 buf = xstrprintf ("gdbtk_tcl_breakpoint %s %d", action, b->number); 00617 else 00618 buf = xstrprintf ("gdbtk_tcl_tracepoint %s %d", action, b->number); 00619 00620 if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK) 00621 report_error (); 00622 xfree(buf); 00623 } 00624 00625 /* 00626 * This section contains the commands that deal with tracepoints: 00627 */ 00628 00629 /* This implements the tcl command gdb_actions 00630 * It sets actions for a given tracepoint. 00631 * 00632 * Tcl Arguments: 00633 * number: the tracepoint in question 00634 * actions: the actions to add to this tracepoint 00635 * Tcl Result: 00636 * None. 00637 */ 00638 00639 static int 00640 gdb_actions_command (ClientData clientData, Tcl_Interp *interp, 00641 int objc, Tcl_Obj *CONST objv[]) 00642 { 00643 int tpnum; 00644 struct tracepoint *tp; 00645 struct command_line *commands; 00646 00647 if (objc != 3) 00648 { 00649 Tcl_WrongNumArgs (interp, 1, objv, "number actions"); 00650 return TCL_ERROR; 00651 } 00652 00653 if (Tcl_GetIntFromObj (NULL, objv[1], &tpnum) != TCL_OK) 00654 { 00655 result_ptr->flags |= GDBTK_IN_TCL_RESULT; 00656 return TCL_ERROR; 00657 } 00658 00659 tp = get_tracepoint (tpnum); 00660 00661 if (tp == NULL) 00662 { 00663 gdbtk_set_result (interp, "Tracepoint #%d does not exist", tpnum); 00664 return TCL_ERROR; 00665 } 00666 00667 /* Validate and set new tracepoint actions. */ 00668 Tcl_ListObjGetElements (interp, objv[2], &gdbtk_obj_array_cnt, 00669 &gdbtk_obj_array); 00670 gdbtk_obj_array_ptr = 1; 00671 commands = read_command_lines_1 (gdbtk_read_next_line, 1, 00672 check_tracepoint_command, tp); 00673 00674 breakpoint_set_commands ((struct breakpoint *) tp, commands); 00675 return TCL_OK; 00676 } 00677 00678 static int 00679 gdb_get_trace_frame_num (ClientData clientData, Tcl_Interp *interp, 00680 int objc, Tcl_Obj *CONST objv[]) 00681 { 00682 if (objc != 1) 00683 { 00684 Tcl_WrongNumArgs (interp, 1, objv, "linespec"); 00685 return TCL_ERROR; 00686 } 00687 00688 Tcl_SetIntObj (result_ptr->obj_ptr, get_traceframe_number ()); 00689 return TCL_OK; 00690 00691 } 00692 00693 static int 00694 gdb_get_tracepoint_info (ClientData clientData, Tcl_Interp *interp, 00695 int objc, Tcl_Obj *CONST objv[]) 00696 { 00697 struct symtab_and_line sal; 00698 int tpnum; 00699 struct tracepoint *tp; 00700 struct breakpoint *bp; 00701 struct command_line *cl; 00702 Tcl_Obj *action_list; 00703 const char *filename, *funcname; 00704 00705 if (objc != 2) 00706 { 00707 Tcl_WrongNumArgs (interp, 1, objv, "tpnum"); 00708 return TCL_ERROR; 00709 } 00710 00711 if (Tcl_GetIntFromObj (NULL, objv[1], &tpnum) != TCL_OK) 00712 { 00713 result_ptr->flags |= GDBTK_IN_TCL_RESULT; 00714 return TCL_ERROR; 00715 } 00716 00717 tp = get_tracepoint (tpnum); 00718 bp = (struct breakpoint *) tp; 00719 if (tp == NULL) 00720 { 00721 gdbtk_set_result (interp, "Tracepoint #%d does not exist", tpnum); 00722 return TCL_ERROR; 00723 } 00724 00725 Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL); 00726 sal = find_pc_line (bp->loc->address, 0); 00727 filename = symtab_to_filename (sal.symtab); 00728 if (filename == NULL) 00729 filename = "N/A"; 00730 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, 00731 Tcl_NewStringObj (filename, -1)); 00732 00733 funcname = pc_function_name (bp->loc->address); 00734 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, Tcl_NewStringObj 00735 (funcname, -1)); 00736 00737 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, 00738 Tcl_NewIntObj (sal.line)); 00739 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, 00740 Tcl_NewStringObj (core_addr_to_string (bp->loc->address), -1)); 00741 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, 00742 Tcl_NewIntObj (bp->enable_state == bp_enabled)); 00743 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, 00744 Tcl_NewIntObj (tp->pass_count)); 00745 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, 00746 Tcl_NewIntObj (tp->step_count)); 00747 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, 00748 Tcl_NewIntObj (bp->thread)); 00749 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, 00750 Tcl_NewIntObj (bp->hit_count)); 00751 00752 /* Append a list of actions */ 00753 action_list = Tcl_NewObj (); 00754 if (bp->commands != NULL) 00755 { 00756 for (cl = breakpoint_commands (bp); cl != NULL; cl = cl->next) 00757 { 00758 Tcl_ListObjAppendElement (interp, action_list, 00759 Tcl_NewStringObj (cl->line, -1)); 00760 } 00761 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, action_list); 00762 } 00763 00764 return TCL_OK; 00765 } 00766 00767 /* return a list of all tracepoint numbers in interpreter */ 00768 static int 00769 gdb_get_tracepoint_list (ClientData clientData, 00770 Tcl_Interp *interp, 00771 int objc, 00772 Tcl_Obj *CONST objv[]) 00773 { 00774 VEC(breakpoint_p) *tp_vec = NULL; 00775 int ix; 00776 struct breakpoint *tp; 00777 00778 Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL); 00779 00780 tp_vec = all_tracepoints (); 00781 for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, tp); ix++) 00782 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, 00783 Tcl_NewIntObj (tp->number)); 00784 VEC_free (breakpoint_p, tp_vec); 00785 00786 return TCL_OK; 00787 } 00788 00789 static int 00790 gdb_trace_status (ClientData clientData, 00791 Tcl_Interp *interp, 00792 int objc, 00793 Tcl_Obj *CONST objv[]) 00794 { 00795 int result = 0; 00796 00797 if (current_trace_status ()->running) 00798 result = 1; 00799 00800 Tcl_SetIntObj (result_ptr->obj_ptr, result); 00801 return TCL_OK; 00802 } 00803 00804 /* returns -1 if not found, tracepoint # if found */ 00805 static int 00806 tracepoint_exists (char *args) 00807 { 00808 VEC(breakpoint_p) *tp_vec = NULL; 00809 int ix; 00810 struct breakpoint *tp; 00811 struct symtabs_and_lines sals; 00812 char *file = NULL; 00813 int result = -1; 00814 00815 sals = decode_line_1 (&args, DECODE_LINE_FUNFIRSTLINE, NULL, 0); 00816 if (sals.nelts == 1) 00817 { 00818 resolve_sal_pc (&sals.sals[0]); 00819 file = xmalloc (strlen (sals.sals[0].symtab->dirname) 00820 + strlen (sals.sals[0].symtab->filename) + 1); 00821 if (file != NULL) 00822 { 00823 strcpy (file, sals.sals[0].symtab->dirname); 00824 strcat (file, sals.sals[0].symtab->filename); 00825 00826 tp_vec = all_tracepoints (); 00827 for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, tp); ix++) 00828 { 00829 if (tp->loc && tp->loc->address == sals.sals[0].pc) 00830 result = tp->number; 00831 #if 0 00832 /* Why is this here? This messes up assembly traces */ 00833 else if (tp->source_file != NULL 00834 && strcmp (tp->source_file, file) == 0 00835 && sals.sals[0].line == tp->line_number) 00836 result = tp->number; 00837 #endif 00838 } 00839 VEC_free (breakpoint_p, tp_vec); 00840 } 00841 } 00842 if (file != NULL) 00843 free (file); 00844 return result; 00845 } 00846 00847 static int 00848 gdb_tracepoint_exists_command (ClientData clientData, 00849 Tcl_Interp *interp, 00850 int objc, 00851 Tcl_Obj *CONST objv[]) 00852 { 00853 char *args; 00854 00855 if (objc != 2) 00856 { 00857 Tcl_WrongNumArgs (interp, 1, objv, 00858 "function:line|function|line|*addr"); 00859 return TCL_ERROR; 00860 } 00861 00862 args = Tcl_GetStringFromObj (objv[1], NULL); 00863 00864 Tcl_SetIntObj (result_ptr->obj_ptr, tracepoint_exists (args)); 00865 return TCL_OK; 00866 }