aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbtk-cmds.c
diff options
context:
space:
mode:
authorKeith Seitz <keiths@cygnus>1998-08-19 02:25:21 +0000
committerKeith Seitz <keiths@cygnus>1998-08-19 02:25:21 +0000
commit3d64f1e0503e6d627d5e280976fb7156eb756976 (patch)
tree243c08594e0916e60eed7734421b53e78204eafe /gdb/gdbtk-cmds.c
parenta36035532fee85b822ec77d70cc5523b5ad83829 (diff)
downloadgdb-3d64f1e0503e6d627d5e280976fb7156eb756976.zip
gdb-3d64f1e0503e6d627d5e280976fb7156eb756976.tar.gz
gdb-3d64f1e0503e6d627d5e280976fb7156eb756976.tar.bz2
* gdbtk-hooks.c (gdbtk_add_hooks): Set selected_frame_level_changed_hook
. (gdbtk_selected_frame_changed): New function. * gdbtk-cmds.c (Gdbtk_Init): Add command gdb_stack into interpreter. Link gdb's global selected_frame_level with interpreter global gdb_selected_frame_level. (gdb_stack): New function to faciltate speedier backtraces from gdbtk. (get_frame_name): New helper function for gdb_stack.
Diffstat (limited to 'gdb/gdbtk-cmds.c')
-rw-r--r--gdb/gdbtk-cmds.c195
1 files changed, 194 insertions, 1 deletions
diff --git a/gdb/gdbtk-cmds.c b/gdb/gdbtk-cmds.c
index 9cefd82..f7dda53 100644
--- a/gdb/gdbtk-cmds.c
+++ b/gdb/gdbtk-cmds.c
@@ -142,10 +142,15 @@ extern int breakpoint_count;
/*
- * Declarations for routines used only in this file.
+ * Declarations for routines exported from this file
*/
int Gdbtk_Init (Tcl_Interp *interp);
+
+/*
+ * Declarations for routines used only in this file.
+ */
+
static int compare_lines PARAMS ((const PTR, const PTR));
static int comp_files PARAMS ((const void *, const void *));
static int call_wrapper PARAMS ((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []));
@@ -206,6 +211,8 @@ static int gdb_get_tracepoint_info PARAMS ((ClientData, Tcl_Interp *, int,
Tcl_Obj *CONST objv[]));
static int gdbtk_dis_asm_read_memory PARAMS ((bfd_vma, bfd_byte *, int, disassemble_info *));
static int get_pc_register PARAMS ((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []));
+static int gdb_stack PARAMS ((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []));
+
char * get_prompt PARAMS ((void));
static void get_register PARAMS ((int, void *));
static void get_register_name PARAMS ((int, void *));
@@ -214,6 +221,7 @@ static int perror_with_name_wrapper PARAMS ((char *args));
static void register_changed_p PARAMS ((int, void *));
void TclDebug PARAMS ((const char *fmt, ...));
static int wrapped_call (char *opaque_args);
+static void get_frame_name PARAMS ((Tcl_Interp *interp, Tcl_Obj *list, struct frame_info *fi));
/* Gdbtk_Init
* This loads all the Tcl commands into the Tcl interpreter.
@@ -294,6 +302,11 @@ Gdbtk_Init (interp)
Tcl_CreateObjCommand (interp, "gdb_set_bp", call_wrapper, gdb_set_bp, NULL);
Tcl_CreateObjCommand (interp, "gdb_get_trace_frame_num",
call_wrapper, gdb_get_trace_frame_num, NULL);
+ Tcl_CreateObjCommand (interp, "gdb_stack", call_wrapper, gdb_stack, NULL);
+
+ Tcl_LinkVar (interp, "gdb_selected_frame_level",
+ (char *) &selected_frame_level,
+ TCL_LINK_INT | TCL_LINK_READ_ONLY);
Tcl_PkgProvide(interp, "Gdbtk", GDBTK_VERSION);
return TCL_OK;
@@ -2959,6 +2972,186 @@ gdb_get_breakpoint_list (clientData, interp, objc, objv)
return TCL_OK;
}
+
+/* The functions in this section deal with stacks and backtraces. */
+
+/* This implements the tcl command gdb_stack.
+ * It builds up a list of stack frames.
+ *
+ * Tcl Arguments:
+ * start - starting stack frame
+ * count - number of frames to inspect
+ * Tcl Result:
+ * A list of function names
+ */
+
+static int
+gdb_stack (clientData, interp, objc, objv) ClientData clientData;
+ Tcl_Interp *interp;
+ int objc;
+ Tcl_Obj *CONST objv[];
+{
+ int start, count;
+
+ if (objc < 3)
+ {
+ Tcl_WrongNumArgs (interp, 1, objv, "start count");
+ result_ptr->flags |= GDBTK_IN_TCL_RESULT;
+ return TCL_ERROR;
+ }
+
+ if (Tcl_GetIntFromObj (NULL, objv[1], &start))
+ {
+ result_ptr->flags |= GDBTK_IN_TCL_RESULT;
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIntFromObj (NULL, objv[2], &count))
+ {
+ result_ptr->flags |= GDBTK_IN_TCL_RESULT;
+ return TCL_ERROR;
+ }
+
+ Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
+
+ if (target_has_stack)
+ {
+ struct frame_info *top;
+ struct frame_info *fi;
+
+ /* Find the outermost frame */
+ fi = get_current_frame ();
+ while (fi != NULL)
+ {
+ top = fi;
+ fi = get_prev_frame (fi);
+ }
+
+ /* top now points to the top (outermost frame) of the
+ stack, so point it to the requested start */
+ start = -start;
+ top = find_relative_frame (top, &start);
+
+ /* If start != 0, then we have asked to start outputting
+ frames beyond the innermost stack frame */
+ if (start == 0)
+ {
+ fi = top;
+ while (fi && count--)
+ {
+ get_frame_name (interp, result_ptr->obj_ptr, fi);
+ fi = get_next_frame (fi);
+ }
+ }
+ }
+
+ return TCL_OK;
+}
+
+/* A helper function for get_stack which adds information about
+ * the stack frame FI to the caller's LIST.
+ *
+ * This is stolen from print_frame_info in stack.c.
+ */
+static void
+get_frame_name (interp, list, fi)
+ Tcl_Interp *interp;
+ Tcl_Obj *list;
+ struct frame_info *fi;
+{
+ struct symtab_and_line sal;
+ struct symbol *func = NULL;
+ register char *funname = 0;
+ enum language funlang = language_unknown;
+ Tcl_Obj *objv[1];
+
+ if (frame_in_dummy (fi))
+ {
+ objv[0] = Tcl_NewStringObj ("<function called from gdb>\n", -1);
+ Tcl_ListObjAppendElement (interp, list, objv[0]);
+ return;
+ }
+ if (fi->signal_handler_caller)
+ {
+ objv[0] = Tcl_NewStringObj ("<signal handler called>\n", -1);
+ Tcl_ListObjAppendElement (interp, list, objv[0]);
+ return;
+ }
+
+ sal =
+ find_pc_line (fi->pc,
+ fi->next != NULL
+ && !fi->next->signal_handler_caller
+ && !frame_in_dummy (fi->next));
+
+ func = find_pc_function (fi->pc);
+ if (func)
+ {
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc);
+ if (msymbol != NULL
+ && (SYMBOL_VALUE_ADDRESS (msymbol)
+ > BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
+ {
+ func = 0;
+ funname = SYMBOL_NAME (msymbol);
+ funlang = SYMBOL_LANGUAGE (msymbol);
+ }
+ else
+ {
+ funname = SYMBOL_NAME (func);
+ funlang = SYMBOL_LANGUAGE (func);
+ }
+ }
+ else
+ {
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc);
+ if (msymbol != NULL)
+ {
+ funname = SYMBOL_NAME (msymbol);
+ funlang = SYMBOL_LANGUAGE (msymbol);
+ }
+ }
+
+ if (sal.symtab)
+ {
+ objv[0] = Tcl_NewStringObj (funname, -1);
+ Tcl_ListObjAppendElement (interp, list, objv[0]);
+ }
+ else
+ {
+#if 0
+ /* we have no convenient way to deal with this yet... */
+ if (fi->pc != sal.pc || !sal.symtab)
+ {
+ print_address_numeric (fi->pc, 1, gdb_stdout);
+ printf_filtered (" in ");
+ }
+ printf_symbol_filtered (gdb_stdout, funname ? funname : "??", funlang,
+ DMGL_ANSI);
+#endif
+ objv[0] = Tcl_NewStringObj (funname != NULL ? funname : "??", -1);
+#ifdef PC_LOAD_SEGMENT
+ /* If we couldn't print out function name but if can figure out what
+ load segment this pc value is from, at least print out some info
+ about its load segment. */
+ if (!funname)
+ {
+ Tcl_AppendStringsToObj (objv[0], " from ", PC_LOAD_SEGMENT (fi->pc),
+ (char *) NULL);
+ }
+#endif
+#ifdef PC_SOLIB
+ if (!funname)
+ {
+ char *lib = PC_SOLIB (fi->pc);
+ if (lib)
+ {
+ Tcl_AppendStringsToObj (objv[0], " from ", lib, (char *) NULL);
+ }
+ }
+#endif
+ Tcl_ListObjAppendElement (interp, list, objv[0]);
+ }
+}
/*