GDB (API)
/home/stan/gdb/src/gdb/gdbtk/generic/gdbtk-stack.c
Go to the documentation of this file.
00001 /* Tcl/Tk command definitions for Insight - Stack.
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 "target.h"
00023 #include "breakpoint.h"
00024 #include "linespec.h"
00025 #include "block.h"
00026 #include "dictionary.h"
00027 #include "varobj.h"
00028 #include "arch-utils.h"
00029 #include "stack.h"
00030 #include "solib.h"
00031 
00032 #include <tcl.h>
00033 #include "gdbtk.h"
00034 #include "gdbtk-cmds.h"
00035 #include "gdbtk-wrapper.h"
00036 
00037 static int gdb_block_vars (ClientData clientData,
00038                            Tcl_Interp * interp, int objc,
00039                            Tcl_Obj * CONST objv[]);
00040 static int gdb_get_args_command (ClientData, Tcl_Interp *, int,
00041                                  Tcl_Obj * CONST objv[]);
00042 static int gdb_get_blocks (ClientData clientData,
00043                            Tcl_Interp * interp, int objc,
00044                            Tcl_Obj * CONST objv[]);
00045 static int gdb_get_locals_command (ClientData, Tcl_Interp *, int,
00046                                    Tcl_Obj * CONST objv[]);
00047 static int gdb_get_vars_command (ClientData, Tcl_Interp *, int,
00048                                  Tcl_Obj * CONST objv[]);
00049 static int gdb_selected_block (ClientData clientData,
00050                                Tcl_Interp * interp, int argc,
00051                                Tcl_Obj * CONST objv[]);
00052 static int gdb_selected_frame (ClientData clientData,
00053                                Tcl_Interp * interp, int argc,
00054                                Tcl_Obj * CONST objv[]);
00055 static int gdb_stack (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00056 static void get_frame_name (Tcl_Interp *interp, Tcl_Obj *list,
00057                             struct frame_info *fi);
00058 
00059 int
00060 Gdbtk_Stack_Init (Tcl_Interp *interp)
00061 {
00062   Tcl_CreateObjCommand (interp, "gdb_block_variables", gdbtk_call_wrapper,
00063                         gdb_block_vars, NULL);
00064   Tcl_CreateObjCommand (interp, "gdb_get_blocks", gdbtk_call_wrapper,
00065                         gdb_get_blocks, NULL);
00066   Tcl_CreateObjCommand (interp, "gdb_get_args", gdbtk_call_wrapper,
00067                         gdb_get_args_command, NULL);
00068   Tcl_CreateObjCommand (interp, "gdb_get_locals", gdbtk_call_wrapper,
00069                         gdb_get_locals_command, NULL);
00070   Tcl_CreateObjCommand (interp, "gdb_selected_block", gdbtk_call_wrapper,
00071                         gdb_selected_block, NULL);
00072   Tcl_CreateObjCommand (interp, "gdb_selected_frame", gdbtk_call_wrapper,
00073                         gdb_selected_frame, NULL);
00074   Tcl_CreateObjCommand (interp, "gdb_stack", gdbtk_call_wrapper, gdb_stack, NULL);
00075 
00076   return TCL_OK;
00077 }
00078 
00079 /* This implements the tcl command gdb_block_vars.
00080  *
00081  * Returns all variables valid in the specified block.
00082  *
00083  * Arguments:
00084  *    The start and end addresses which identify the block.
00085  * Tcl Result:
00086  *    All variables defined in the given block.
00087  */
00088 static int
00089 gdb_block_vars (ClientData clientData, Tcl_Interp *interp,
00090                 int objc, Tcl_Obj *CONST objv[])
00091 {
00092   struct block *block;
00093   struct block_iterator iter;
00094   struct symbol *sym;
00095   CORE_ADDR start, end;
00096 
00097   if (objc < 3)
00098     {
00099       Tcl_WrongNumArgs (interp, 1, objv, "startAddr endAddr");
00100       return TCL_ERROR;
00101     }
00102 
00103   Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
00104   if (!target_has_registers)
00105     return TCL_OK;
00106 
00107   start = string_to_core_addr (Tcl_GetStringFromObj (objv[1], NULL));
00108   end   = string_to_core_addr (Tcl_GetStringFromObj (objv[2], NULL));
00109   
00110   block = get_frame_block (get_selected_frame (NULL), 0);
00111 
00112   while (block != 0)
00113     {
00114       if (BLOCK_START (block) == start && BLOCK_END (block) == end)
00115         {
00116           ALL_BLOCK_SYMBOLS (block, iter, sym)
00117             {
00118               switch (SYMBOL_CLASS (sym))
00119                 {
00120                 case LOC_ARG:             /* argument              */
00121                 case LOC_REF_ARG:         /* reference arg         */
00122                 case LOC_REGPARM_ADDR:    /* indirect register arg */
00123                 case LOC_LOCAL:           /* stack local           */
00124                 case LOC_STATIC:          /* static                */
00125                 case LOC_REGISTER:        /* register              */
00126                 case LOC_COMPUTED:        /* computed location     */
00127                   Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
00128                                             Tcl_NewStringObj (SYMBOL_PRINT_NAME (sym),
00129                                                               -1));
00130                   break;
00131 
00132                 default:
00133                   break;
00134                 }
00135             }
00136 
00137           return TCL_OK;
00138         }
00139       else if (BLOCK_FUNCTION (block))
00140         break;
00141       else
00142         block = BLOCK_SUPERBLOCK (block);
00143     }
00144 
00145   return TCL_OK;
00146 }
00147 
00148 /* This implements the tcl command gdb_get_blocks
00149  *
00150  * Returns the start and end addresses for all blocks in
00151  * the selected frame.
00152  *
00153  * Arguments:
00154  *    None
00155  * Tcl Result:
00156  *    A list of all valid blocks in the selected_frame.
00157  */
00158 static int
00159 gdb_get_blocks (ClientData clientData, Tcl_Interp *interp,
00160                 int objc, Tcl_Obj *CONST objv[])
00161 {
00162   struct block *block;
00163   struct block_iterator iter;
00164   int junk;
00165   struct symbol *sym;
00166   CORE_ADDR pc;
00167 
00168   Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
00169   
00170   if (target_has_registers)
00171     {
00172       struct frame_info *frame = get_selected_frame (NULL);
00173 
00174       block = get_frame_block (frame, 0);
00175       pc = get_frame_pc (frame);
00176       while (block != 0)
00177         {
00178           junk = 0;
00179           ALL_BLOCK_SYMBOLS (block, iter, sym)
00180             {
00181               switch (SYMBOL_CLASS (sym))
00182                 {
00183                 default:
00184                 case LOC_UNDEF:           /* catches errors        */
00185                 case LOC_CONST:           /* constant              */
00186                 case LOC_TYPEDEF:         /* local typedef         */
00187                 case LOC_LABEL:           /* local label           */
00188                 case LOC_BLOCK:           /* local function        */
00189                 case LOC_CONST_BYTES:     /* loc. byte seq.        */
00190                 case LOC_UNRESOLVED:      /* unresolved static     */
00191                 case LOC_OPTIMIZED_OUT:   /* optimized out         */
00192                   junk = 1;
00193                   break;
00194 
00195                 case LOC_ARG:             /* argument              */
00196                 case LOC_REF_ARG:         /* reference arg         */
00197                 case LOC_REGPARM_ADDR:    /* indirect register arg */
00198 
00199                 case LOC_LOCAL:           /* stack local           */
00200                 case LOC_STATIC:          /* static                */
00201                 case LOC_REGISTER:        /* register              */
00202                 case LOC_COMPUTED:        /* computed location     */
00203                   junk = 0;
00204                   break;
00205                 }
00206             }
00207 
00208           /* If we found a block with locals in it, add it to the list. 
00209              Note that the ranges of start and end address for blocks
00210              are exclusive, so double-check against the PC */
00211           
00212           if (!junk && pc < BLOCK_END (block))
00213             {
00214               char *addr;
00215 
00216               Tcl_Obj *elt = Tcl_NewListObj (0, NULL);
00217               addr = xstrprintf ("%s", paddress (get_current_arch (),
00218                                                  BLOCK_START (block)));
00219               Tcl_ListObjAppendElement (interp, elt,
00220                                         Tcl_NewStringObj (addr, -1));
00221               free(addr);
00222               addr = xstrprintf ("%s", paddress (get_current_arch (),
00223                                                  BLOCK_END (block)));
00224               Tcl_ListObjAppendElement (interp, elt,
00225                                         Tcl_NewStringObj (addr, -1));
00226               Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, elt);
00227               free(addr);
00228             }
00229 
00230           if (BLOCK_FUNCTION (block))
00231             break;
00232           else
00233             block = BLOCK_SUPERBLOCK (block);
00234         }
00235     }
00236 
00237   return TCL_OK;
00238 }
00239 
00240 /* gdb_get_args -
00241  * This and gdb_get_locals just call gdb_get_vars_command with the right
00242  * value of clientData.  We can't use the client data in the definition
00243  * of the command, because the call wrapper uses this instead...
00244  */
00245 static int
00246 gdb_get_args_command (ClientData clientData, Tcl_Interp *interp,
00247                       int objc, Tcl_Obj *CONST objv[])
00248 {
00249   return gdb_get_vars_command ((ClientData) 1, interp, objc, objv);
00250 }
00251 
00252 
00253 static int
00254 gdb_get_locals_command (ClientData clientData, Tcl_Interp *interp,
00255                         int objc, Tcl_Obj *CONST objv[])
00256 {
00257   return gdb_get_vars_command ((ClientData) 0, interp, objc, objv);
00258 }
00259 
00260 /* This implements the tcl commands "gdb_get_locals" and "gdb_get_args"
00261 
00262 * This function sets the Tcl interpreter's result to a list of variable names
00263 * depending on clientData. If clientData is one, the result is a list of
00264 * arguments; zero returns a list of locals -- all relative to the block
00265 * specified as an argument to the command. Valid commands include
00266 * anything decode_line_1 can handle (like "main.c:2", "*0x02020202",
00267 * and "main").
00268 *
00269 * Tcl Arguments:
00270 *   linespec - the linespec defining the scope of the lookup. Empty string
00271 *              to use the current block in the innermost frame.
00272 * Tcl Result:
00273 *   A list of the locals or args
00274 */
00275 static int
00276 gdb_get_vars_command (ClientData clientData, Tcl_Interp *interp,
00277                       int objc, Tcl_Obj *CONST objv[])
00278 {
00279   struct symtabs_and_lines sals;
00280   struct symbol *sym;
00281   struct block *block;
00282   char *args;
00283   struct block_iterator iter;
00284   int i, arguments;
00285 
00286   if (objc > 2)
00287     {
00288       Tcl_WrongNumArgs (interp, 1, objv,
00289                         "[function:line|function|line|*addr]");
00290       return TCL_ERROR;
00291     }
00292 
00293   arguments = clientData != NULL ? 1 : 0;
00294 
00295   /* Initialize the result pointer to an empty list. */
00296 
00297   Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
00298 
00299   if (objc == 2)
00300     {
00301       args = Tcl_GetStringFromObj (objv[1], NULL);
00302       sals = decode_line_1 (&args, DECODE_LINE_FUNFIRSTLINE, NULL, 0);
00303       if (sals.nelts == 0)
00304         {
00305           gdbtk_set_result (interp, "error decoding line");
00306           return TCL_ERROR;
00307         }
00308 
00309       /* Resolve all line numbers to PC's */
00310       for (i = 0; i < sals.nelts; i++)
00311         resolve_sal_pc (&sals.sals[i]);
00312 
00313       block = block_for_pc (sals.sals[0].pc);
00314     }
00315   else
00316     {
00317       /* Specified currently selected frame */
00318       if (!target_has_registers)
00319         return TCL_OK;
00320 
00321       block = get_frame_block (get_selected_frame (NULL), 0);
00322     }
00323 
00324   while (block != 0)
00325     {
00326       ALL_BLOCK_SYMBOLS (block, iter, sym)
00327         {
00328           switch (SYMBOL_CLASS (sym))
00329             {
00330             default:
00331             case LOC_UNDEF:     /* catches errors        */
00332             case LOC_CONST:     /* constant              */
00333             case LOC_TYPEDEF:   /* local typedef         */
00334             case LOC_LABEL:     /* local label           */
00335             case LOC_BLOCK:     /* local function        */
00336             case LOC_CONST_BYTES:       /* loc. byte seq.        */
00337             case LOC_UNRESOLVED:        /* unresolved static     */
00338             case LOC_OPTIMIZED_OUT:     /* optimized out         */
00339               break;
00340             case LOC_ARG:       /* argument              */
00341             case LOC_REF_ARG:   /* reference arg         */
00342             case LOC_REGPARM_ADDR:      /* indirect register arg */
00343               if (arguments)
00344                 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
00345                                           Tcl_NewStringObj (SYMBOL_PRINT_NAME (sym), -1));
00346               break;
00347             case LOC_LOCAL:     /* stack local           */
00348             case LOC_STATIC:    /* static                */
00349             case LOC_REGISTER:  /* register              */
00350             case LOC_COMPUTED:  /* computed location     */
00351               if (!arguments)
00352                 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
00353                                           Tcl_NewStringObj (SYMBOL_PRINT_NAME (sym), -1));
00354               break;
00355             }
00356         }
00357       if (BLOCK_FUNCTION (block))
00358         break;
00359       else
00360         block = BLOCK_SUPERBLOCK (block);
00361     }
00362 
00363   return TCL_OK;
00364 }
00365 
00366 /* This implements the tcl command gdb_selected_block
00367  *
00368  * Returns the start and end addresses of the innermost
00369  * block in the selected frame.
00370  *
00371  * Arguments:
00372  *    None
00373  * Tcl Result:
00374  *    The currently selected block's start and end addresses
00375  */
00376 static int
00377 gdb_selected_block (ClientData clientData, Tcl_Interp *interp,
00378                     int objc, Tcl_Obj *CONST objv[])
00379 {
00380   char *start = NULL;
00381   char *end   = NULL;
00382 
00383   if (!target_has_registers)
00384     {
00385       start = xstrprintf ("%s", "");
00386       end = xstrprintf ("%s", "");
00387     }
00388   else
00389     {
00390       struct block *block;
00391       block = get_frame_block (get_selected_frame (NULL), 0);
00392       start = xstrprintf ("%s", paddress (get_current_arch (),
00393                                           BLOCK_START (block)));
00394       end = xstrprintf ("%s", paddress (get_current_arch (),
00395                                         BLOCK_END (block)));
00396     }
00397 
00398   Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
00399   Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
00400                             Tcl_NewStringObj (start, -1));
00401   Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
00402                             Tcl_NewStringObj (end, -1));
00403 
00404   free(start);
00405   free(end);
00406   return TCL_OK;
00407 }
00408 
00409 /* This implements the tcl command gdb_selected_frame
00410 
00411 * Returns the address of the selected frame
00412 * frame.
00413 *
00414 * Arguments:
00415 *    None
00416 * Tcl Result:
00417 *    The currently selected frame's address
00418 */
00419 static int
00420 gdb_selected_frame (ClientData clientData, Tcl_Interp *interp,
00421                     int objc, Tcl_Obj *CONST objv[])
00422 {
00423   char *frame;
00424 
00425   if (!target_has_registers)
00426     frame = xstrprintf ("%s","");
00427   else
00428     /* FIXME: cagney/2002-11-19: This should be using get_frame_id()
00429        to identify the frame and *NOT* get_frame_base().  */
00430     frame = xstrprintf ("%s",paddress (get_current_arch (),
00431                         get_frame_base (get_selected_frame (NULL))));
00432 
00433   Tcl_SetStringObj (result_ptr->obj_ptr, frame, -1);
00434 
00435   free(frame);
00436   return TCL_OK;
00437 }
00438 
00439 /* This implements the tcl command gdb_stack.
00440  * It builds up a list of stack frames.
00441  *
00442  * Tcl Arguments:
00443  *    start  - starting stack frame
00444  *    count - number of frames to inspect
00445  * Tcl Result:
00446  *    A list of function names
00447  */
00448 static int
00449 gdb_stack (ClientData clientData, Tcl_Interp *interp,
00450            int objc, Tcl_Obj *CONST objv[])
00451 {
00452   int start, count;
00453 
00454   if (objc < 3)
00455     {
00456       Tcl_WrongNumArgs (interp, 1, objv, "start count");
00457       return TCL_ERROR;
00458     }
00459 
00460   if (Tcl_GetIntFromObj (NULL, objv[1], &start))
00461     {
00462       result_ptr->flags |= GDBTK_IN_TCL_RESULT;
00463       return TCL_ERROR;
00464     }
00465   if (Tcl_GetIntFromObj (NULL, objv[2], &count))
00466     {
00467       result_ptr->flags |= GDBTK_IN_TCL_RESULT;
00468       return TCL_ERROR;
00469     }
00470 
00471   if (target_has_stack)
00472     {
00473       gdb_result r;
00474       struct frame_info *top;
00475       struct frame_info *fi;
00476 
00477       /* Find the outermost frame */
00478       r  = GDB_get_current_frame (&fi);
00479       if (r != GDB_OK)
00480         return TCL_ERROR;
00481 
00482       while (fi != NULL)
00483         {
00484           top = fi;
00485           r = GDB_get_prev_frame (fi, &fi);
00486           if (r != GDB_OK)
00487             fi = NULL;
00488         }
00489 
00490       result_ptr->obj_ptr = Tcl_NewListObj (0, NULL);
00491 
00492       /* top now points to the top (outermost frame) of the
00493          stack, so point it to the requested start */
00494       start = -start;
00495       r = GDB_find_relative_frame (top, &start, &top);
00496       if (r != GDB_OK)
00497         return TCL_OK;
00498 
00499       /* If start != 0, then we have asked to start outputting
00500          frames beyond the innermost stack frame */
00501       if (start == 0)
00502         {
00503           fi = top; 
00504           while (fi && count--)
00505             {
00506               get_frame_name (interp, result_ptr->obj_ptr, fi);
00507               r = GDB_get_next_frame (fi, &fi);
00508               if (r != GDB_OK)
00509                 break;
00510             }
00511         }
00512     }
00513 
00514   return TCL_OK;
00515 }
00516 
00517 /* A helper function for get_stack which adds information about
00518  * the stack frame FI to the caller's LIST.
00519  *
00520  * This is stolen from print_frame_info/print_frame in stack.c.
00521  */
00522 
00523 static void
00524 get_frame_name (Tcl_Interp *interp, Tcl_Obj *list, struct frame_info *fi)
00525 {
00526   struct symbol *func = NULL;
00527   char *funname = NULL;
00528   enum language funlang = language_unknown;
00529   Tcl_Obj *objv[1];
00530 
00531   if (get_frame_type (fi) == DUMMY_FRAME)
00532     {
00533       objv[0] = Tcl_NewStringObj ("<function called from gdb>", -1);
00534       Tcl_ListObjAppendElement (interp, list, objv[0]);
00535       return;
00536     }
00537   if (get_frame_type (fi) == SIGTRAMP_FRAME)
00538     {
00539       objv[0] = Tcl_NewStringObj ("<signal handler called>", -1);
00540       Tcl_ListObjAppendElement (interp, list, objv[0]);
00541       return;
00542     }
00543   if (get_frame_type (fi) == ARCH_FRAME)
00544     {
00545       objv[0] = Tcl_NewStringObj ("<cross-architecture call>", -1);
00546       Tcl_ListObjAppendElement (interp, list, objv[0]);
00547       return;
00548     }
00549 
00550   find_frame_funname (fi, &funname, &funlang, &func);
00551 
00552   if (funname)
00553     {
00554       objv[0] = Tcl_NewStringObj (funname, -1);
00555       Tcl_ListObjAppendElement (interp, list, objv[0]);
00556       xfree (funname);
00557     }
00558   else
00559     {
00560       char *lib = NULL;
00561       objv[0] = Tcl_NewStringObj (funname ? funname : "??", -1);
00562 #ifdef PC_SOLIB
00563       lib = PC_SOLIB (get_frame_pc (fi));
00564 #else
00565       lib = solib_name_from_address (get_frame_program_space (fi),
00566                                      get_frame_pc (fi));
00567 #endif
00568       if (lib)
00569         Tcl_AppendStringsToObj (objv[0], " from ", lib, (char *) NULL);
00570 
00571       Tcl_ListObjAppendElement (interp, list, objv[0]);
00572     }
00573 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines