GDB (API)
|
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 }