GDB (API)
/home/stan/gdb/src/gdb/gdbtk/generic/gdbtk-bp.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines