1 /* Tcl/Tk command definitions for Insight - Stack.
2 Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
4 This file is part of GDB.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA. */
23 #include "breakpoint.h"
26 #include "dictionary.h"
30 #include "gdbtk-cmds.h"
31 #include "gdbtk-wrapper.h"
33 static int gdb_block_vars (ClientData clientData,
34 Tcl_Interp * interp, int objc,
35 Tcl_Obj * CONST objv[]);
36 static int gdb_get_args_command (ClientData, Tcl_Interp *, int,
37 Tcl_Obj * CONST objv[]);
38 static int gdb_get_blocks (ClientData clientData,
39 Tcl_Interp * interp, int objc,
40 Tcl_Obj * CONST objv[]);
41 static int gdb_get_locals_command (ClientData, Tcl_Interp *, int,
42 Tcl_Obj * CONST objv[]);
43 static int gdb_get_vars_command (ClientData, Tcl_Interp *, int,
44 Tcl_Obj * CONST objv[]);
45 static int gdb_selected_block (ClientData clientData,
46 Tcl_Interp * interp, int argc,
47 Tcl_Obj * CONST objv[]);
48 static int gdb_selected_frame (ClientData clientData,
49 Tcl_Interp * interp, int argc,
50 Tcl_Obj * CONST objv[]);
51 static int gdb_stack (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
52 static void get_frame_name (Tcl_Interp *interp, Tcl_Obj *list,
53 struct frame_info *fi);
56 Gdbtk_Stack_Init (Tcl_Interp *interp)
58 Tcl_CreateObjCommand (interp, "gdb_block_variables", gdbtk_call_wrapper,
59 gdb_block_vars, NULL);
60 Tcl_CreateObjCommand (interp, "gdb_get_blocks", gdbtk_call_wrapper,
61 gdb_get_blocks, NULL);
62 Tcl_CreateObjCommand (interp, "gdb_get_args", gdbtk_call_wrapper,
63 gdb_get_args_command, NULL);
64 Tcl_CreateObjCommand (interp, "gdb_get_locals", gdbtk_call_wrapper,
65 gdb_get_locals_command, NULL);
66 Tcl_CreateObjCommand (interp, "gdb_selected_block", gdbtk_call_wrapper,
67 gdb_selected_block, NULL);
68 Tcl_CreateObjCommand (interp, "gdb_selected_frame", gdbtk_call_wrapper,
69 gdb_selected_frame, NULL);
70 Tcl_CreateObjCommand (interp, "gdb_stack", gdbtk_call_wrapper, gdb_stack, NULL);
75 /* This implements the tcl command gdb_block_vars.
77 * Returns all variables valid in the specified block.
80 * The start and end addresses which identify the block.
82 * All variables defined in the given block.
85 gdb_block_vars (ClientData clientData, Tcl_Interp *interp,
86 int objc, Tcl_Obj *CONST objv[])
89 struct dict_iterator iter;
95 Tcl_WrongNumArgs (interp, 1, objv, "startAddr endAddr");
99 Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
100 if (!target_has_registers)
103 start = string_to_core_addr (Tcl_GetStringFromObj (objv[1], NULL));
104 end = string_to_core_addr (Tcl_GetStringFromObj (objv[2], NULL));
106 block = get_frame_block (get_selected_frame (NULL), 0);
110 if (BLOCK_START (block) == start && BLOCK_END (block) == end)
112 ALL_BLOCK_SYMBOLS (block, iter, sym)
114 switch (SYMBOL_CLASS (sym))
116 case LOC_ARG: /* argument */
117 case LOC_REF_ARG: /* reference arg */
118 case LOC_REGPARM: /* register arg */
119 case LOC_REGPARM_ADDR: /* indirect register arg */
120 case LOC_LOCAL_ARG: /* stack arg */
121 case LOC_BASEREG_ARG: /* basereg arg */
122 case LOC_LOCAL: /* stack local */
123 case LOC_BASEREG: /* basereg local */
124 case LOC_STATIC: /* static */
125 case LOC_REGISTER: /* register */
126 case LOC_COMPUTED: /* computed location */
127 case LOC_COMPUTED_ARG: /* computed location arg */
128 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
129 Tcl_NewStringObj (DEPRECATED_SYMBOL_NAME (sym),
140 else if (BLOCK_FUNCTION (block))
143 block = BLOCK_SUPERBLOCK (block);
149 /* This implements the tcl command gdb_get_blocks
151 * Returns the start and end addresses for all blocks in
152 * the selected frame.
157 * A list of all valid blocks in the selected_frame.
160 gdb_get_blocks (ClientData clientData, Tcl_Interp *interp,
161 int objc, Tcl_Obj *CONST objv[])
164 struct dict_iterator iter;
169 Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
171 if (target_has_registers)
173 struct frame_info *frame = get_selected_frame (NULL);
175 block = get_frame_block (frame, 0);
176 pc = get_frame_pc (frame);
180 ALL_BLOCK_SYMBOLS (block, iter, sym)
182 switch (SYMBOL_CLASS (sym))
185 case LOC_UNDEF: /* catches errors */
186 case LOC_CONST: /* constant */
187 case LOC_TYPEDEF: /* local typedef */
188 case LOC_LABEL: /* local label */
189 case LOC_BLOCK: /* local function */
190 case LOC_CONST_BYTES: /* loc. byte seq. */
191 case LOC_UNRESOLVED: /* unresolved static */
192 case LOC_OPTIMIZED_OUT: /* optimized out */
196 case LOC_ARG: /* argument */
197 case LOC_REF_ARG: /* reference arg */
198 case LOC_REGPARM: /* register arg */
199 case LOC_REGPARM_ADDR: /* indirect register arg */
200 case LOC_LOCAL_ARG: /* stack arg */
201 case LOC_BASEREG_ARG: /* basereg arg */
202 case LOC_COMPUTED_ARG: /* computed location arg */
204 case LOC_LOCAL: /* stack local */
205 case LOC_BASEREG: /* basereg local */
206 case LOC_STATIC: /* static */
207 case LOC_REGISTER: /* register */
208 case LOC_COMPUTED: /* computed location */
214 /* If we found a block with locals in it, add it to the list.
215 Note that the ranges of start and end address for blocks
216 are exclusive, so double-check against the PC */
218 if (!junk && pc < BLOCK_END (block))
222 Tcl_Obj *elt = Tcl_NewListObj (0, NULL);
223 xasprintf (&addr, "0x%s", paddr_nz (BLOCK_START (block)));
224 Tcl_ListObjAppendElement (interp, elt,
225 Tcl_NewStringObj (addr, -1));
227 xasprintf (&addr, "0x%s", paddr_nz (BLOCK_END (block)));
228 Tcl_ListObjAppendElement (interp, elt,
229 Tcl_NewStringObj (addr, -1));
230 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, elt);
234 if (BLOCK_FUNCTION (block))
237 block = BLOCK_SUPERBLOCK (block);
245 * This and gdb_get_locals just call gdb_get_vars_command with the right
246 * value of clientData. We can't use the client data in the definition
247 * of the command, because the call wrapper uses this instead...
250 gdb_get_args_command (ClientData clientData, Tcl_Interp *interp,
251 int objc, Tcl_Obj *CONST objv[])
253 return gdb_get_vars_command ((ClientData) 1, interp, objc, objv);
258 gdb_get_locals_command (ClientData clientData, Tcl_Interp *interp,
259 int objc, Tcl_Obj *CONST objv[])
261 return gdb_get_vars_command ((ClientData) 0, interp, objc, objv);
264 /* This implements the tcl commands "gdb_get_locals" and "gdb_get_args"
266 * This function sets the Tcl interpreter's result to a list of variable names
267 * depending on clientData. If clientData is one, the result is a list of
268 * arguments; zero returns a list of locals -- all relative to the block
269 * specified as an argument to the command. Valid commands include
270 * anything decode_line_1 can handle (like "main.c:2", "*0x02020202",
274 * linespec - the linespec defining the scope of the lookup. Empty string
275 * to use the current block in the innermost frame.
277 * A list of the locals or args
280 gdb_get_vars_command (ClientData clientData, Tcl_Interp *interp,
281 int objc, Tcl_Obj *CONST objv[])
283 struct symtabs_and_lines sals;
286 char **canonical, *args;
287 struct dict_iterator iter;
292 Tcl_WrongNumArgs (interp, 1, objv,
293 "[function:line|function|line|*addr]");
297 arguments = (int) clientData;
299 /* Initialize the result pointer to an empty list. */
301 Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
305 args = Tcl_GetStringFromObj (objv[1], NULL);
306 sals = decode_line_1 (&args, 1, NULL, 0, &canonical, NULL);
309 gdbtk_set_result (interp, "error decoding line");
313 /* Resolve all line numbers to PC's */
314 for (i = 0; i < sals.nelts; i++)
315 resolve_sal_pc (&sals.sals[i]);
317 block = block_for_pc (sals.sals[0].pc);
321 /* Specified currently selected frame */
322 if (!target_has_registers)
325 block = get_frame_block (get_selected_frame (NULL), 0);
330 ALL_BLOCK_SYMBOLS (block, iter, sym)
332 switch (SYMBOL_CLASS (sym))
335 case LOC_UNDEF: /* catches errors */
336 case LOC_CONST: /* constant */
337 case LOC_TYPEDEF: /* local typedef */
338 case LOC_LABEL: /* local label */
339 case LOC_BLOCK: /* local function */
340 case LOC_CONST_BYTES: /* loc. byte seq. */
341 case LOC_UNRESOLVED: /* unresolved static */
342 case LOC_OPTIMIZED_OUT: /* optimized out */
344 case LOC_ARG: /* argument */
345 case LOC_REF_ARG: /* reference arg */
346 case LOC_REGPARM: /* register arg */
347 case LOC_REGPARM_ADDR: /* indirect register arg */
348 case LOC_LOCAL_ARG: /* stack arg */
349 case LOC_BASEREG_ARG: /* basereg arg */
350 case LOC_COMPUTED_ARG: /* computed location arg */
352 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
353 Tcl_NewStringObj (DEPRECATED_SYMBOL_NAME (sym), -1));
355 case LOC_LOCAL: /* stack local */
356 case LOC_BASEREG: /* basereg local */
357 case LOC_STATIC: /* static */
358 case LOC_REGISTER: /* register */
359 case LOC_COMPUTED: /* computed location */
361 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
362 Tcl_NewStringObj (DEPRECATED_SYMBOL_NAME (sym), -1));
366 if (BLOCK_FUNCTION (block))
369 block = BLOCK_SUPERBLOCK (block);
375 /* This implements the tcl command gdb_selected_block
377 * Returns the start and end addresses of the innermost
378 * block in the selected frame.
383 * The currently selected block's start and end addresses
386 gdb_selected_block (ClientData clientData, Tcl_Interp *interp,
387 int objc, Tcl_Obj *CONST objv[])
392 if (!target_has_registers)
394 xasprintf (&start, "%s", "");
395 xasprintf (&end, "%s", "");
400 block = get_frame_block (get_selected_frame (NULL), 0);
401 xasprintf (&start, "0x%s", paddr_nz (BLOCK_START (block)));
402 xasprintf (&end, "0x%s", paddr_nz (BLOCK_END (block)));
405 Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
406 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
407 Tcl_NewStringObj (start, -1));
408 Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
409 Tcl_NewStringObj (end, -1));
416 /* This implements the tcl command gdb_selected_frame
418 * Returns the address of the selected frame
424 * The currently selected frame's address
427 gdb_selected_frame (ClientData clientData, Tcl_Interp *interp,
428 int objc, Tcl_Obj *CONST objv[])
432 if (!target_has_registers)
433 xasprintf (&frame, "%s","");
435 /* FIXME: cagney/2002-11-19: This should be using get_frame_id()
436 to identify the frame and *NOT* get_frame_base(). */
437 xasprintf (&frame, "0x%s",
438 paddr_nz (get_frame_base (get_selected_frame (NULL))));
440 Tcl_SetStringObj (result_ptr->obj_ptr, frame, -1);
446 /* This implements the tcl command gdb_stack.
447 * It builds up a list of stack frames.
450 * start - starting stack frame
451 * count - number of frames to inspect
453 * A list of function names
456 gdb_stack (ClientData clientData, Tcl_Interp *interp,
457 int objc, Tcl_Obj *CONST objv[])
463 Tcl_WrongNumArgs (interp, 1, objv, "start count");
467 if (Tcl_GetIntFromObj (NULL, objv[1], &start))
469 result_ptr->flags |= GDBTK_IN_TCL_RESULT;
472 if (Tcl_GetIntFromObj (NULL, objv[2], &count))
474 result_ptr->flags |= GDBTK_IN_TCL_RESULT;
478 if (target_has_stack)
481 struct frame_info *top;
482 struct frame_info *fi;
484 /* Find the outermost frame */
485 r = GDB_get_current_frame (&fi);
492 r = GDB_get_prev_frame (fi, &fi);
497 /* top now points to the top (outermost frame) of the
498 stack, so point it to the requested start */
500 r = GDB_find_relative_frame (top, &start, &top);
502 result_ptr->obj_ptr = Tcl_NewListObj (0, NULL);
506 /* If start != 0, then we have asked to start outputting
507 frames beyond the innermost stack frame */
511 while (fi && count--)
513 get_frame_name (interp, result_ptr->obj_ptr, fi);
514 r = GDB_get_next_frame (fi, &fi);
524 /* A helper function for get_stack which adds information about
525 * the stack frame FI to the caller's LIST.
527 * This is stolen from print_frame_info in stack.c.
530 get_frame_name (Tcl_Interp *interp, Tcl_Obj *list, struct frame_info *fi)
532 struct symtab_and_line sal;
533 struct symbol *func = NULL;
534 register char *funname = 0;
535 enum language funlang = language_unknown;
538 if (get_frame_type (fi) == DUMMY_FRAME)
540 objv[0] = Tcl_NewStringObj ("<function called from gdb>\n", -1);
541 Tcl_ListObjAppendElement (interp, list, objv[0]);
544 if ((get_frame_type (fi) == SIGTRAMP_FRAME))
546 objv[0] = Tcl_NewStringObj ("<signal handler called>\n", -1);
547 Tcl_ListObjAppendElement (interp, list, objv[0]);
552 find_pc_line (get_frame_pc (fi),
553 get_next_frame (fi) != NULL
554 && !(get_frame_type (fi) == SIGTRAMP_FRAME)
555 && !(get_frame_type (fi) == DUMMY_FRAME));
557 func = find_pc_function (get_frame_pc (fi));
560 struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (get_frame_pc (fi));
562 && (SYMBOL_VALUE_ADDRESS (msymbol)
563 > BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
566 funname = GDBTK_SYMBOL_SOURCE_NAME (msymbol);
567 funlang = SYMBOL_LANGUAGE (msymbol);
571 funname = GDBTK_SYMBOL_SOURCE_NAME (func);
572 funlang = SYMBOL_LANGUAGE (func);
577 struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (get_frame_pc (fi));
580 funname = GDBTK_SYMBOL_SOURCE_NAME (msymbol);
581 funlang = SYMBOL_LANGUAGE (msymbol);
587 objv[0] = Tcl_NewStringObj (funname, -1);
588 Tcl_ListObjAppendElement (interp, list, objv[0]);
593 /* we have no convenient way to deal with this yet... */
594 if (fi->pc != sal.pc || !sal.symtab)
596 deprecated_print_address_numeric (fi->pc, 1, gdb_stdout);
597 printf_filtered (" in ");
599 printf_symbol_filtered (gdb_stdout, funname ? funname : "??", funlang,
602 objv[0] = Tcl_NewStringObj (funname != NULL ? funname : "??", -1);
603 #ifdef PC_LOAD_SEGMENT
604 /* If we couldn't print out function name but if can figure out what
605 load segment this pc value is from, at least print out some info
606 about its load segment. */
609 Tcl_AppendStringsToObj (objv[0], " from ", PC_LOAD_SEGMENT (fi->pc),
616 char *lib = PC_SOLIB (get_frame_pc (fi));
619 Tcl_AppendStringsToObj (objv[0], " from ", lib, (char *) NULL);
623 Tcl_ListObjAppendElement (interp, list, objv[0]);