#include <ctype.h>
#include "defs.h"
#include "gdb_string.h"
#include "value.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "expression.h"
#include "language.h"
#include "frame.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "target.h"
#include "source.h"
#include "breakpoint.h"
#include "demangle.h"
#include "inferior.h"
#include "annotate.h"
#include "symfile.h"
#include "objfiles.h"
#include "ui-out.h"
void args_info (char *, int);
void locals_info (char *, int);
void (*selected_frame_level_changed_hook) (int);
void _initialize_stack (void);
void return_command (char *, int);
static void down_command (char *, int);
static void down_silently_base (char *);
static void down_silently_command (char *, int);
static void up_command (char *, int);
static void up_silently_base (char *);
static void up_silently_command (char *, int);
void frame_command (char *, int);
static void current_frame_command (char *, int);
static void select_frame_command (char *, int);
static void print_frame_arg_vars (struct frame_info *, struct ui_file *);
static void catch_info (char *, int);
static void args_plus_locals_info (char *, int);
static void print_frame_label_vars (struct frame_info *, int,
struct ui_file *);
static void print_frame_local_vars (struct frame_info *, int,
struct ui_file *);
static int print_block_frame_labels (struct block *, int *,
struct ui_file *);
static int print_block_frame_locals (struct block *,
struct frame_info *,
int,
struct ui_file *);
static void print_frame (struct frame_info *fi,
int level,
int source,
int args,
struct symtab_and_line sal);
static void print_frame_info_base (struct frame_info *, int, int, int);
static void print_stack_frame_base (struct frame_info *, int, int);
static void backtrace_command (char *, int);
struct frame_info *parse_frame_specification (char *);
static void frame_info (char *, int);
extern int addressprint;
struct frame_info *selected_frame;
int selected_frame_level;
int
frame_relative_level (struct frame_info *fi)
{
if (fi == NULL)
return -1;
else
return fi->level;
}
int annotation_level = 0;
struct print_stack_frame_args
{
struct frame_info *fi;
int level;
int source;
int args;
};
static int print_stack_frame_base_stub (char *);
static int show_and_print_stack_frame_stub (void *args);
static int
show_and_print_stack_frame_stub (void *args)
{
struct print_stack_frame_args *p = (struct print_stack_frame_args *) args;
print_frame_info (p->fi, p->level, p->source, p->args);
return 0;
}
static int print_stack_frame_stub (void *args);
static int
print_stack_frame_stub (void *args)
{
struct print_stack_frame_args *p = (struct print_stack_frame_args *) args;
print_frame_info_base (p->fi, p->level, p->source, p->args);
return 0;
}
static int
print_stack_frame_base_stub (char *args)
{
struct print_stack_frame_args *p = (struct print_stack_frame_args *) args;
print_frame_info_base (p->fi, p->level, p->source, p->args);
return 0;
}
static int print_only_stack_frame_stub (void *);
static int
print_only_stack_frame_stub (void *args)
{
struct print_stack_frame_args *p = (struct print_stack_frame_args *) args;
print_frame_info_base (p->fi, p->level, p->source, p->args);
return 0;
}
static void
print_stack_frame_base (struct frame_info *fi, int level, int source)
{
struct print_stack_frame_args args;
args.fi = fi;
args.level = level;
args.source = source;
args.args = 1;
catch_errors (print_stack_frame_stub, &args, "", RETURN_MASK_ALL);
}
void
show_and_print_stack_frame (struct frame_info *fi, int level, int source)
{
struct print_stack_frame_args args;
args.fi = fi;
args.level = level;
args.source = source;
args.args = 1;
catch_errors (show_and_print_stack_frame_stub, &args, "", RETURN_MASK_ALL);
}
void
print_stack_frame (struct frame_info *fi, int level, int source)
{
struct print_stack_frame_args args;
args.fi = fi;
args.level = level;
args.source = source;
args.args = 1;
catch_errors (print_stack_frame_stub, (char *) &args, "", RETURN_MASK_ALL);
}
void
print_only_stack_frame (struct frame_info *fi, int level, int source)
{
struct print_stack_frame_args args;
args.fi = fi;
args.level = level;
args.source = source;
args.args = 1;
catch_errors (print_only_stack_frame_stub, &args, "", RETURN_MASK_ALL);
}
struct print_args_args
{
struct symbol *func;
struct frame_info *fi;
struct ui_file *stream;
};
static int print_args_stub (PTR);
static int
print_args_stub (PTR args)
{
int numargs;
struct print_args_args *p = (struct print_args_args *) args;
numargs = FRAME_NUM_ARGS (p->fi);
print_frame_args (p->func, p->fi, numargs, p->stream);
return 0;
}
static void
print_frame_info_base (struct frame_info *fi, int level, int source, int args)
{
struct symtab_and_line sal;
int source_print;
int location_print;
#if 0
char buf[MAX_REGISTER_RAW_SIZE];
CORE_ADDR sp;
get_saved_register (buf, (int *) NULL, (CORE_ADDR *) NULL,
FRAME_INFO_ID (fi), SP_REGNUM, (enum lval_type *) NULL);
sp = extract_address (buf, REGISTER_RAW_SIZE (SP_REGNUM));
if (PC_IN_CALL_DUMMY (fi->pc, sp, fi->frame))
#else
if (frame_in_dummy (fi))
#endif
{
struct cleanup *uiout_cleanup;
annotate_frame_begin (level == -1 ? 0 : level, fi->pc);
uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
if (level >= 0)
{
ui_out_text (uiout, "#");
ui_out_field_fmt_int (uiout, 2, ui_left, "level", level);
}
if (ui_out_is_mi_like_p (uiout))
{
annotate_frame_address ();
ui_out_field_core_addr (uiout, "addr", fi->pc);
annotate_frame_address_end ();
ui_out_field_core_addr (uiout, "fp", FRAME_FP(fi));
}
annotate_function_call ();
ui_out_field_string (uiout, "func", "<function called from gdb>");
ui_out_text (uiout, "\n");
annotate_frame_end ();
do_cleanups (uiout_cleanup);
return;
}
if (fi->signal_handler_caller)
{
struct cleanup *uiout_cleanup;
annotate_frame_begin (level == -1 ? 0 : level, fi->pc);
uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
if (level >= 0)
{
ui_out_text (uiout, "#");
ui_out_field_fmt_int (uiout, 2, ui_left, "level", level);
}
if (ui_out_is_mi_like_p (uiout))
{
annotate_frame_address ();
ui_out_field_core_addr (uiout, "addr", fi->pc);
annotate_frame_address_end ();
ui_out_field_core_addr (uiout, "fp", FRAME_FP(fi));
}
annotate_signal_handler_caller ();
ui_out_field_string (uiout, "func", "<signal handler called>");
ui_out_text (uiout, "\n");
annotate_frame_end ();
do_cleanups (uiout_cleanup);
return;
}
sal =
find_pc_line (fi->pc,
fi->next != NULL
&& !fi->next->signal_handler_caller
&& !frame_in_dummy (fi->next));
location_print = (source == LOCATION
|| source == LOC_AND_ADDRESS
|| source == SRC_AND_LOC);
if (location_print || !sal.symtab)
print_frame (fi, level, source, args, sal);
source_print = (source == SRC_LINE || source == SRC_AND_LOC);
if (sal.symtab)
set_current_source_symtab_and_line (&sal);
if (source_print && sal.symtab)
{
struct symtab_and_line cursal;
int done = 0;
int mid_statement = (source == SRC_LINE) && (fi->pc != sal.pc);
if (annotation_level)
done = identify_source_line (sal.symtab, sal.line, mid_statement,
fi->pc);
if (!done)
{
if (print_frame_info_listing_hook)
print_frame_info_listing_hook (sal.symtab, sal.line, sal.line + 1, 0);
else
{
if (addressprint && mid_statement)
{
ui_out_field_core_addr (uiout, "addr", fi->pc);
ui_out_text (uiout, "\t");
}
if (print_frame_info_listing_hook)
print_frame_info_listing_hook (sal.symtab, sal.line, 1, 0);
else
print_source_lines (sal.symtab, sal.line, 1, 0);
}
}
set_default_source_symtab_and_line ();
cursal = get_current_source_symtab_and_line ();
cursal.line = max (sal.line - get_lines_to_list () / 2, 1);
set_current_source_symtab_and_line (&cursal);
}
if (source != 0)
set_default_breakpoint (1, fi->pc, sal.symtab, sal.line);
annotate_frame_end ();
gdb_flush (gdb_stdout);
}
static void
print_frame (struct frame_info *fi,
int level,
int source,
int args,
struct symtab_and_line sal)
{
struct symbol *func;
register char *funname = 0;
enum language funlang = language_unknown;
struct ui_stream *stb;
struct cleanup *old_chain;
struct cleanup *list_chain;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
func = find_pc_function (frame_address_in_block (fi));
if (func)
{
struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (frame_address_in_block (fi));
if (msymbol != NULL
&& (SYMBOL_VALUE_ADDRESS (msymbol)
> BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
{
#if 0
sal.symtab = 0;
#endif
func = 0;
funname = SYMBOL_NAME (msymbol);
funlang = SYMBOL_LANGUAGE (msymbol);
}
else
{
char *demangled;
funname = SYMBOL_NAME (func);
funlang = SYMBOL_LANGUAGE (func);
if (funlang == language_cplus)
{
demangled = cplus_demangle (funname, DMGL_ANSI);
if (demangled == NULL)
funname = SYMBOL_SOURCE_NAME (func);
}
}
}
else
{
struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (frame_address_in_block (fi));
if (msymbol != NULL)
{
funname = SYMBOL_NAME (msymbol);
funlang = SYMBOL_LANGUAGE (msymbol);
}
}
#ifdef TARGET_HAS_EMBEDDED_SYMBOLS
if (funname == NULL)
{
embedded_symbol *esymbol = search_for_embedded_symbol (fi->pc);
if (NULL != esymbol)
{
funname = esymbol->name;
funlang = esymbol->language;
func = NULL;
args = 0;
}
}
#endif
annotate_frame_begin (level == -1 ? 0 : level, fi->pc);
list_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
if (level >= 0)
{
ui_out_text (uiout, "#");
ui_out_field_fmt_int (uiout, 2, ui_left, "level", level);
}
if (addressprint)
if (fi->pc != sal.pc || !sal.symtab || source == LOC_AND_ADDRESS)
{
annotate_frame_address ();
ui_out_field_core_addr (uiout, "addr", fi->pc);
annotate_frame_address_end ();
ui_out_text (uiout, " in ");
if (ui_out_is_mi_like_p (uiout))
{
ui_out_field_core_addr (uiout, "fp", FRAME_FP(fi));
}
}
annotate_frame_function_name ();
fprintf_symbol_filtered (stb->stream, funname ? funname : "??", funlang,
DMGL_ANSI);
ui_out_field_stream (uiout, "func", stb);
ui_out_wrap_hint (uiout, " ");
annotate_frame_args ();
ui_out_text (uiout, " (");
if (args)
{
struct print_args_args args;
struct cleanup *args_list_chain;
args.fi = fi;
args.func = func;
args.stream = gdb_stdout;
args_list_chain = make_cleanup_ui_out_list_begin_end (uiout, "args");
catch_errors (print_args_stub, &args, "", RETURN_MASK_ALL);
do_cleanups (args_list_chain);
QUIT;
}
ui_out_text (uiout, ")");
if (sal.symtab && sal.symtab->filename)
{
annotate_frame_source_begin ();
ui_out_wrap_hint (uiout, " ");
ui_out_text (uiout, " at ");
annotate_frame_source_file ();
ui_out_field_string (uiout, "file", sal.symtab->filename);
annotate_frame_source_file_end ();
ui_out_text (uiout, ":");
annotate_frame_source_line ();
ui_out_field_int (uiout, "line", sal.line);
annotate_frame_source_end ();
}
if (print_frame_more_info_hook)
print_frame_more_info_hook (uiout, &sal, fi);
#ifdef PC_SOLIB
if (!funname || (!sal.symtab || !sal.symtab->filename))
{
char *lib = PC_SOLIB (fi->pc);
if (lib)
{
annotate_frame_where ();
ui_out_wrap_hint (uiout, " ");
ui_out_text (uiout, " from ");
ui_out_field_string (uiout, "from", lib);
}
}
#endif
do_cleanups (list_chain);
ui_out_text (uiout, "\n");
do_cleanups (old_chain);
}
void
print_frame_info (struct frame_info *fi, register int level, int source,
int args)
{
print_frame_info_base (fi, level, source, args);
}
void
show_stack_frame (struct frame_info *fi)
{
}
struct frame_info *
parse_frame_specification (char *frame_exp)
{
int numargs = 0;
#define MAXARGS 4
CORE_ADDR args[MAXARGS];
int level;
if (frame_exp)
{
char *addr_string, *p;
struct cleanup *tmp_cleanup;
while (*frame_exp == ' ')
frame_exp++;
while (*frame_exp)
{
if (numargs > MAXARGS)
error ("Too many args in frame specification");
for (p = frame_exp; *p && *p != ' '; p++)
;
addr_string = savestring (frame_exp, p - frame_exp);
{
struct value *vp;
tmp_cleanup = make_cleanup (xfree, addr_string);
vp = parse_and_eval (addr_string);
if (numargs == 0)
level = value_as_long (vp);
args[numargs++] = value_as_address (vp);
do_cleanups (tmp_cleanup);
}
while (*p == ' ')
p++;
frame_exp = p;
}
}
switch (numargs)
{
case 0:
if (selected_frame == NULL)
error ("No selected frame.");
return selected_frame;
case 1:
{
struct frame_info *fid =
find_relative_frame (get_current_frame (), &level);
struct frame_info *tfid;
if (level == 0)
return fid;
#ifdef SETUP_ARBITRARY_FRAME
error ("No frame %s", paddr_d (args[0]));
#endif
for (fid = get_current_frame ();
fid && fid->frame != args[0];
fid = get_prev_frame (fid))
;
if (fid)
while ((tfid = get_prev_frame (fid)) &&
(tfid->frame == args[0]))
fid = tfid;
}
default:
#ifdef SETUP_ARBITRARY_FRAME
return SETUP_ARBITRARY_FRAME (numargs, args);
#else
if (numargs == 1)
return create_new_frame (args[0], 0);
error ("Too many args in frame specification");
#endif
}
}
#if !defined (FRAME_ARGS_ADDRESS_CORRECT)
#define FRAME_ARGS_ADDRESS_CORRECT FRAME_ARGS_ADDRESS
#endif
static void
frame_info (char *addr_exp, int from_tty)
{
struct frame_info *fi;
struct symtab_and_line sal;
struct symbol *func;
struct symtab *s;
struct frame_info *calling_frame_info;
int i, count, numregs;
char *funname = 0;
enum language funlang = language_unknown;
if (!target_has_stack)
error ("No stack.");
fi = parse_frame_specification (addr_exp);
if (fi == NULL)
error ("Invalid frame specified.");
sal = find_pc_line (fi->pc,
fi->next != NULL
&& !fi->next->signal_handler_caller
&& !frame_in_dummy (fi->next));
func = get_frame_function (fi);
s = find_pc_symtab (fi->pc);
if (func)
{
char *demangled;
funname = SYMBOL_NAME (func);
funlang = SYMBOL_LANGUAGE (func);
if (funlang == language_cplus)
{
demangled = cplus_demangle (funname, DMGL_ANSI);
if (demangled == NULL)
funname = SYMBOL_SOURCE_NAME (func);
}
}
else
{
register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc);
if (msymbol != NULL)
{
funname = SYMBOL_NAME (msymbol);
funlang = SYMBOL_LANGUAGE (msymbol);
}
}
calling_frame_info = get_prev_frame (fi);
if (!addr_exp && frame_relative_level (selected_frame) >= 0)
{
printf_filtered ("Stack level %d, frame at ",
frame_relative_level (selected_frame));
print_address_numeric (fi->frame, 1, gdb_stdout);
printf_filtered (":\n");
}
else
{
printf_filtered ("Stack frame at ");
print_address_numeric (fi->frame, 1, gdb_stdout);
printf_filtered (":\n");
}
printf_filtered (" %s = ", REGISTER_NAME (PC_REGNUM));
print_address_numeric (fi->pc, 1, gdb_stdout);
wrap_here (" ");
if (funname)
{
printf_filtered (" in ");
fprintf_symbol_filtered (gdb_stdout, funname, funlang,
DMGL_ANSI | DMGL_PARAMS);
}
wrap_here (" ");
if (sal.symtab)
printf_filtered (" (%s:%d)", sal.symtab->filename, sal.line);
puts_filtered ("; ");
wrap_here (" ");
printf_filtered ("saved %s ", REGISTER_NAME (PC_REGNUM));
print_address_numeric (FRAME_SAVED_PC (fi), 1, gdb_stdout);
printf_filtered ("\n");
{
int frameless;
frameless = FRAMELESS_FUNCTION_INVOCATION (fi);
if (frameless)
printf_filtered (" (FRAMELESS),");
}
if (calling_frame_info)
{
printf_filtered (" called by frame at ");
print_address_numeric (calling_frame_info->frame, 1, gdb_stdout);
}
if (fi->next && calling_frame_info)
puts_filtered (",");
wrap_here (" ");
if (fi->next)
{
printf_filtered (" caller of frame at ");
print_address_numeric (fi->next->frame, 1, gdb_stdout);
}
if (fi->next || calling_frame_info)
puts_filtered ("\n");
if (s)
printf_filtered (" source language %s.\n", language_str (s->language));
#ifdef PRINT_EXTRA_FRAME_INFO
PRINT_EXTRA_FRAME_INFO (fi);
#endif
{
CORE_ADDR arg_list = FRAME_ARGS_ADDRESS_CORRECT (fi);
int numargs;
if (arg_list == 0)
printf_filtered (" Arglist at unknown address.\n");
else
{
printf_filtered (" Arglist at ");
print_address_numeric (arg_list, 1, gdb_stdout);
printf_filtered (",");
numargs = FRAME_NUM_ARGS (fi);
if (numargs < 0)
puts_filtered (" args: ");
else if (numargs == 0)
puts_filtered (" no args.");
else if (numargs == 1)
puts_filtered (" 1 arg: ");
else
printf_filtered (" %d args: ", numargs);
print_frame_args (func, fi, numargs, gdb_stdout);
puts_filtered ("\n");
}
}
{
CORE_ADDR arg_list = FRAME_LOCALS_ADDRESS (fi);
if (arg_list == 0)
printf_filtered (" Locals at unknown address,");
else
{
printf_filtered (" Locals at ");
print_address_numeric (arg_list, 1, gdb_stdout);
printf_filtered (",");
}
}
if (fi->saved_regs == NULL)
FRAME_INIT_SAVED_REGS (fi);
if (fi->saved_regs != NULL)
{
enum lval_type lval;
int optimized;
CORE_ADDR addr;
int realnum;
int count;
int i;
int need_nl = 1;
if (SP_REGNUM >= 0)
{
frame_register_unwind (fi, SP_REGNUM, &optimized, &lval, &addr,
&realnum, NULL);
if (!optimized && lval == not_lval)
{
void *value = alloca (MAX_REGISTER_RAW_SIZE);
CORE_ADDR sp;
frame_register_unwind (fi, SP_REGNUM, &optimized, &lval, &addr,
&realnum, value);
sp = extract_address (value, REGISTER_RAW_SIZE (SP_REGNUM));
printf_filtered (" Previous frame's sp is ");
print_address_numeric (sp, 1, gdb_stdout);
printf_filtered ("\n");
need_nl = 0;
}
else if (!optimized && lval == lval_memory)
{
printf_filtered (" Previous frame's sp at ");
print_address_numeric (addr, 1, gdb_stdout);
printf_filtered ("\n");
need_nl = 0;
}
else if (!optimized && lval == lval_register)
{
printf_filtered (" Previous frame's sp in %s\n",
REGISTER_NAME (realnum));
need_nl = 0;
}
}
count = 0;
numregs = NUM_REGS + NUM_PSEUDO_REGS;
for (i = 0; i < numregs; i++)
if (i != SP_REGNUM)
{
frame_register_unwind (fi, i, &optimized, &lval, &addr, &realnum,
NULL);
if (!optimized && lval == lval_memory)
{
if (count == 0)
puts_filtered (" Saved registers:\n ");
else
puts_filtered (",");
wrap_here (" ");
printf_filtered (" %s at ", REGISTER_NAME (i));
print_address_numeric (addr, 1, gdb_stdout);
count++;
}
}
if (count || need_nl)
puts_filtered ("\n");
}
}
#if 0
static int backtrace_limit;
static void
set_backtrace_limit_command (char *count_exp, int from_tty)
{
int count = parse_and_eval_long (count_exp);
if (count < 0)
error ("Negative argument not meaningful as backtrace limit.");
backtrace_limit = count;
}
static void
backtrace_limit_info (char *arg, int from_tty)
{
if (arg)
error ("\"Info backtrace-limit\" takes no arguments.");
printf_unfiltered ("Backtrace limit: %d.\n", backtrace_limit);
}
#endif
static void backtrace_command_1 (char *count_exp, int show_locals,
int from_tty);
static void
backtrace_command_1 (char *count_exp, int show_locals, int from_tty)
{
struct frame_info *fi;
register int count;
register int i;
register struct frame_info *trailing;
register int trailing_level;
if (!target_has_stack)
error ("No stack.");
trailing = get_current_frame ();
if (trailing == NULL)
error ("No stack.");
trailing_level = 0;
if (count_exp)
{
count = parse_and_eval_long (count_exp);
if (count < 0)
{
struct frame_info *current;
count = -count;
current = trailing;
while (current && count--)
{
QUIT;
current = get_prev_frame (current);
}
while (current)
{
QUIT;
trailing = get_prev_frame (trailing);
current = get_prev_frame (current);
trailing_level++;
}
count = -1;
}
}
else
count = -1;
if (info_verbose)
{
struct partial_symtab *ps;
i = count;
for (fi = trailing;
fi != NULL && i--;
fi = get_prev_frame (fi))
{
QUIT;
ps = find_pc_psymtab (frame_address_in_block (fi));
if (ps)
PSYMTAB_TO_SYMTAB (ps);
}
}
for (i = 0, fi = trailing;
fi && count--;
i++, fi = get_prev_frame (fi))
{
QUIT;
print_frame_info_base (fi, trailing_level + i, 0, 1);
if (show_locals)
print_frame_local_vars (fi, 1, gdb_stdout);
}
if (fi && from_tty)
printf_filtered ("(More stack frames follow...)\n");
}
static void
backtrace_command (char *arg, int from_tty)
{
struct cleanup *old_chain = (struct cleanup *) NULL;
char **argv = (char **) NULL;
int argIndicatingFullTrace = (-1), totArgLen = 0, argc = 0;
char *argPtr = arg;
if (arg != (char *) NULL)
{
int i;
argv = buildargv (arg);
old_chain = make_cleanup_freeargv (argv);
argc = 0;
for (i = 0; (argv[i] != (char *) NULL); i++)
{
unsigned int j;
for (j = 0; (j < strlen (argv[i])); j++)
argv[i][j] = tolower (argv[i][j]);
if (argIndicatingFullTrace < 0 && subset_compare (argv[i], "full"))
argIndicatingFullTrace = argc;
else
{
argc++;
totArgLen += strlen (argv[i]);
}
}
totArgLen += argc;
if (argIndicatingFullTrace >= 0)
{
if (totArgLen > 0)
{
argPtr = (char *) xmalloc (totArgLen + 1);
if (!argPtr)
nomem (0);
else
{
memset (argPtr, 0, totArgLen + 1);
for (i = 0; (i < (argc + 1)); i++)
{
if (i != argIndicatingFullTrace)
{
strcat (argPtr, argv[i]);
strcat (argPtr, " ");
}
}
}
}
else
argPtr = (char *) NULL;
}
}
backtrace_command_1 (argPtr, (argIndicatingFullTrace >= 0), from_tty);
if (argIndicatingFullTrace >= 0 && totArgLen > 0)
xfree (argPtr);
if (old_chain)
do_cleanups (old_chain);
}
static void backtrace_full_command (char *arg, int from_tty);
static void
backtrace_full_command (char *arg, int from_tty)
{
backtrace_command_1 (arg, 1, from_tty);
}
static int
print_block_frame_locals (struct block *b, register struct frame_info *fi,
int num_tabs, register struct ui_file *stream)
{
register int i, j;
register struct symbol *sym;
register int values_printed = 0;
ALL_BLOCK_SYMBOLS (b, i, sym)
{
switch (SYMBOL_CLASS (sym))
{
case LOC_LOCAL:
case LOC_REGISTER:
case LOC_STATIC:
case LOC_BASEREG:
values_printed = 1;
for (j = 0; j < num_tabs; j++)
fputs_filtered ("\t", stream);
fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
fputs_filtered (" = ", stream);
print_variable_value (sym, fi, stream);
fprintf_filtered (stream, "\n");
break;
default:
break;
}
}
return values_printed;
}
static int
print_block_frame_labels (struct block *b, int *have_default,
register struct ui_file *stream)
{
register int i;
register struct symbol *sym;
register int values_printed = 0;
ALL_BLOCK_SYMBOLS (b, i, sym)
{
if (STREQ (SYMBOL_NAME (sym), "default"))
{
if (*have_default)
continue;
*have_default = 1;
}
if (SYMBOL_CLASS (sym) == LOC_LABEL)
{
struct symtab_and_line sal;
sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0);
values_printed = 1;
fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
if (addressprint)
{
fprintf_filtered (stream, " ");
print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, stream);
}
fprintf_filtered (stream, " in file %s, line %d\n",
sal.symtab->filename, sal.line);
}
}
return values_printed;
}
static void
print_frame_local_vars (register struct frame_info *fi, register int num_tabs,
register struct ui_file *stream)
{
register struct block *block = get_frame_block (fi, 0);
register int values_printed = 0;
if (block == 0)
{
fprintf_filtered (stream, "No symbol table info available.\n");
return;
}
while (block != 0)
{
if (print_block_frame_locals (block, fi, num_tabs, stream))
values_printed = 1;
if (BLOCK_FUNCTION (block))
break;
block = BLOCK_SUPERBLOCK (block);
}
if (!values_printed)
{
fprintf_filtered (stream, "No locals.\n");
}
}
static void
print_frame_label_vars (register struct frame_info *fi, int this_level_only,
register struct ui_file *stream)
{
register struct blockvector *bl;
register struct block *block = get_frame_block (fi, 0);
register int values_printed = 0;
int index, have_default = 0;
char *blocks_printed;
CORE_ADDR pc = fi->pc;
if (block == 0)
{
fprintf_filtered (stream, "No symbol table info available.\n");
return;
}
bl = blockvector_for_pc (BLOCK_END (block) - 4, &index);
blocks_printed = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
memset (blocks_printed, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
while (block != 0)
{
CORE_ADDR end = BLOCK_END (block) - 4;
int last_index;
if (bl != blockvector_for_pc (end, &index))
error ("blockvector blotch");
if (BLOCKVECTOR_BLOCK (bl, index) != block)
error ("blockvector botch");
last_index = BLOCKVECTOR_NBLOCKS (bl);
index += 1;
while (index < last_index
&& BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc)
index++;
while (index < last_index
&& BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end)
{
if (blocks_printed[index] == 0)
{
if (print_block_frame_labels (BLOCKVECTOR_BLOCK (bl, index), &have_default, stream))
values_printed = 1;
blocks_printed[index] = 1;
}
index++;
}
if (have_default)
return;
if (values_printed && this_level_only)
return;
if (BLOCK_FUNCTION (block))
break;
block = BLOCK_SUPERBLOCK (block);
}
if (!values_printed && !this_level_only)
{
fprintf_filtered (stream, "No catches.\n");
}
}
void
locals_info (char *args, int from_tty)
{
if (!selected_frame)
error ("No frame selected.");
print_frame_local_vars (selected_frame, 0, gdb_stdout);
}
static void
catch_info (char *ignore, int from_tty)
{
struct symtab_and_line *sal;
sal = target_enable_exception_callback (EX_EVENT_CATCH, 1);
if (sal)
{
fprintf_filtered (gdb_stdout, "Info catch not supported with this target/compiler combination.\n");
#if 0
if (!selected_frame)
error ("No frame selected.");
#endif
}
else
{
if (!selected_frame)
error ("No frame selected.");
print_frame_label_vars (selected_frame, 0, gdb_stdout);
}
}
static void
print_frame_arg_vars (register struct frame_info *fi,
register struct ui_file *stream)
{
struct symbol *func = get_frame_function (fi);
register struct block *b;
register int i;
register struct symbol *sym, *sym2;
register int values_printed = 0;
if (func == 0)
{
fprintf_filtered (stream, "No symbol table info available.\n");
return;
}
b = SYMBOL_BLOCK_VALUE (func);
ALL_BLOCK_SYMBOLS (b, i, sym)
{
switch (SYMBOL_CLASS (sym))
{
case LOC_ARG:
case LOC_LOCAL_ARG:
case LOC_REF_ARG:
case LOC_REGPARM:
case LOC_REGPARM_ADDR:
case LOC_BASEREG_ARG:
values_printed = 1;
fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
fputs_filtered (" = ", stream);
sym2 = lookup_symbol (SYMBOL_NAME (sym),
b, VAR_NAMESPACE, (int *) NULL, (struct symtab **) NULL);
print_variable_value (sym2, fi, stream);
fprintf_filtered (stream, "\n");
break;
default:
break;
}
}
if (!values_printed)
{
fprintf_filtered (stream, "No arguments.\n");
}
}
void
args_info (char *ignore, int from_tty)
{
if (!selected_frame)
error ("No frame selected.");
print_frame_arg_vars (selected_frame, gdb_stdout);
}
static void
args_plus_locals_info (char *ignore, int from_tty)
{
args_info (ignore, from_tty);
locals_info (ignore, from_tty);
}
void
select_frame (struct frame_info *fi)
{
register struct symtab *s;
selected_frame = fi;
if (selected_frame_level_changed_hook)
selected_frame_level_changed_hook (frame_relative_level (fi));
if (frame_changed_hook)
frame_changed_hook (frame_relative_level (fi));
if (fi)
{
s = find_pc_symtab (fi->pc);
if (s
&& s->language != current_language->la_language
&& s->language != language_unknown
&& language_mode == language_mode_auto)
{
set_language (s->language);
}
}
}
static void
select_and_print_frame (struct frame_info *fi)
{
select_frame (fi);
if (fi)
{
print_stack_frame (fi, frame_relative_level (fi), 1);
}
}
struct block *
get_selected_block (CORE_ADDR *addr_in_block)
{
if (!target_has_stack)
return 0;
if (!selected_frame)
return get_current_block (addr_in_block);
return get_frame_block (selected_frame, addr_in_block);
}
struct frame_info *
find_relative_frame (register struct frame_info *frame,
register int *level_offset_ptr)
{
register struct frame_info *prev;
register struct frame_info *frame1;
while (*level_offset_ptr > 0)
{
prev = get_prev_frame (frame);
if (prev == 0)
break;
(*level_offset_ptr)--;
frame = prev;
}
if (*level_offset_ptr < 0)
{
while (*level_offset_ptr < 0)
{
frame1 = get_next_frame (frame);
if (!frame1)
break;
frame = frame1;
(*level_offset_ptr)++;
}
}
return frame;
}
void
select_frame_command_wrapper (char *level_exp, int from_tty)
{
select_frame_command (level_exp, from_tty);
}
static void
select_frame_command (char *level_exp, int from_tty)
{
struct frame_info *frame;
int level = frame_relative_level (selected_frame);
if (!target_has_stack)
error ("No stack.");
frame = parse_frame_specification (level_exp);
select_frame (frame);
if (level != frame_relative_level (selected_frame))
selected_frame_level_changed_event (frame_relative_level (selected_frame));
}
void
frame_command (char *level_exp, int from_tty)
{
select_frame_command (level_exp, from_tty);
show_and_print_stack_frame (selected_frame,
frame_relative_level (selected_frame), 1);
}
static void
current_frame_command (char *level_exp, int from_tty)
{
if (target_has_stack == 0 || selected_frame == 0)
error ("No stack.");
print_only_stack_frame (selected_frame,
frame_relative_level (selected_frame), 1);
}
static void
up_silently_base (char *count_exp)
{
register struct frame_info *fi;
int count = 1, count1;
if (count_exp)
count = parse_and_eval_long (count_exp);
count1 = count;
if (target_has_stack == 0 || selected_frame == 0)
error ("No stack.");
fi = find_relative_frame (selected_frame, &count1);
if (count1 != 0 && count_exp == 0)
error ("Initial frame selected; you cannot go up.");
select_frame (fi);
selected_frame_level_changed_event (frame_relative_level (selected_frame));
}
static void
up_silently_command (char *count_exp, int from_tty)
{
up_silently_base (count_exp);
}
static void
up_command (char *count_exp, int from_tty)
{
up_silently_base (count_exp);
show_and_print_stack_frame (selected_frame,
frame_relative_level (selected_frame), 1);
}
static void
down_silently_base (char *count_exp)
{
register struct frame_info *frame;
int count = -1, count1;
if (count_exp)
count = -parse_and_eval_long (count_exp);
count1 = count;
if (target_has_stack == 0 || selected_frame == 0)
error ("No stack.");
frame = find_relative_frame (selected_frame, &count1);
if (count1 != 0 && count_exp == 0)
{
error ("Bottom (i.e., innermost) frame selected; you cannot go down.");
}
select_frame (frame);
selected_frame_level_changed_event (frame_relative_level (selected_frame));
}
static void
down_silently_command (char *count_exp, int from_tty)
{
down_silently_base (count_exp);
}
static void
down_command (char *count_exp, int from_tty)
{
down_silently_base (count_exp);
show_and_print_stack_frame (selected_frame,
frame_relative_level (selected_frame), 1);
}
void
return_command (char *retval_exp, int from_tty)
{
struct symbol *thisfun;
CORE_ADDR selected_frame_addr;
CORE_ADDR selected_frame_pc;
struct frame_info *frame;
struct value *return_value = NULL;
if (selected_frame == NULL)
error ("No selected frame.");
thisfun = get_frame_function (selected_frame);
selected_frame_addr = FRAME_FP (selected_frame);
selected_frame_pc = selected_frame->pc;
if (retval_exp)
{
struct type *return_type = NULL;
return_value = parse_and_eval (retval_exp);
if (thisfun != NULL)
return_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (thisfun));
if (return_type == NULL)
return_type = builtin_type_int;
return_value = value_cast (return_type, return_value);
if (VALUE_LAZY (return_value))
value_fetch_lazy (return_value);
}
if (from_tty)
{
if (thisfun != 0)
{
if (!query ("Make %s return now? ", SYMBOL_SOURCE_NAME (thisfun)))
{
error ("Not confirmed.");
}
}
else if (!query ("Make selected stack frame return now? "))
error ("Not confirmed.");
}
while (selected_frame_addr != (frame = get_current_frame ())->frame
|| selected_frame_pc != frame->pc)
POP_FRAME;
POP_FRAME;
if (retval_exp)
set_return_value (return_value);
if (CALL_DUMMY_HAS_COMPLETED (read_pc(), read_sp (),
FRAME_FP (get_current_frame ())))
POP_FRAME;
if (from_tty)
frame_command ("0", 1);
else
select_frame_command ("0", 0);
}
struct function_bounds
{
CORE_ADDR low, high;
};
static void func_command (char *arg, int from_tty);
static void
func_command (char *arg, int from_tty)
{
struct frame_info *fp;
int found = 0;
struct symtabs_and_lines sals;
int i;
int level = 1;
struct function_bounds *func_bounds = (struct function_bounds *) NULL;
if (arg != (char *) NULL)
return;
fp = parse_frame_specification ("0");
sals = decode_line_spec (arg, 1);
func_bounds = (struct function_bounds *) xmalloc (
sizeof (struct function_bounds) * sals.nelts);
for (i = 0; (i < sals.nelts && !found); i++)
{
if (sals.sals[i].pc == (CORE_ADDR) 0 ||
find_pc_partial_function (sals.sals[i].pc,
(char **) NULL,
&func_bounds[i].low,
&func_bounds[i].high) == 0)
{
func_bounds[i].low =
func_bounds[i].high = (CORE_ADDR) NULL;
}
}
do
{
for (i = 0; (i < sals.nelts && !found); i++)
found = (fp->pc >= func_bounds[i].low &&
fp->pc < func_bounds[i].high);
if (!found)
{
level = 1;
fp = find_relative_frame (fp, &level);
}
}
while (!found && level == 0);
if (func_bounds)
xfree (func_bounds);
if (!found)
printf_filtered ("'%s' not within current stack frame.\n", arg);
else if (fp != selected_frame)
select_and_print_frame (fp);
}
enum language
get_frame_language (void)
{
register struct symtab *s;
enum language flang;
if (selected_frame)
{
s = find_pc_symtab (selected_frame->pc);
if (s)
flang = s->language;
else
flang = language_unknown;
}
else
flang = language_unknown;
return flang;
}
void
_initialize_stack (void)
{
#if 0
backtrace_limit = 30;
#endif
add_com ("return", class_stack, return_command,
"Make selected stack frame return to its caller.\n\
Control remains in the debugger, but when you continue\n\
execution will resume in the frame above the one now selected.\n\
If an argument is given, it is an expression for the value to return.");
add_com ("up", class_stack, up_command,
"Select and print stack frame that called this one.\n\
An argument says how many frames up to go.");
add_com ("up-silently", class_support, up_silently_command,
"Same as the `up' command, but does not print anything.\n\
This is useful in command scripts.");
add_com ("down", class_stack, down_command,
"Select and print stack frame called by this one.\n\
An argument says how many frames down to go.");
add_com_alias ("do", "down", class_stack, 1);
add_com_alias ("dow", "down", class_stack, 1);
add_com ("down-silently", class_support, down_silently_command,
"Same as the `down' command, but does not print anything.\n\
This is useful in command scripts.");
add_com ("frame", class_stack, frame_command,
"Select and print a stack frame.\n\
With no argument, print the selected stack frame. (See also \"info frame\").\n\
An argument specifies the frame to select.\n\
It can be a stack frame number or the address of the frame.\n\
With argument, nothing is printed if input is coming from\n\
a command file or a user-defined command.");
add_com_alias ("f", "frame", class_stack, 1);
if (xdb_commands)
{
add_com ("L", class_stack, current_frame_command,
"Print the current stack frame.\n");
add_com_alias ("V", "frame", class_stack, 1);
}
add_com ("select-frame", class_stack, select_frame_command,
"Select a stack frame without printing anything.\n\
An argument specifies the frame to select.\n\
It can be a stack frame number or the address of the frame.\n");
add_com ("backtrace", class_stack, backtrace_command,
"Print backtrace of all stack frames, or innermost COUNT frames.\n\
With a negative argument, print outermost -COUNT frames.\n\
Use of the 'full' qualifier also prints the values of the local variables.\n");
add_com_alias ("bt", "backtrace", class_stack, 0);
if (xdb_commands)
{
add_com_alias ("t", "backtrace", class_stack, 0);
add_com ("T", class_stack, backtrace_full_command,
"Print backtrace of all stack frames, or innermost COUNT frames \n\
and the values of the local variables.\n\
With a negative argument, print outermost -COUNT frames.\n\
Usage: T <count>\n");
}
add_com_alias ("where", "backtrace", class_alias, 0);
add_info ("stack", backtrace_command,
"Backtrace of the stack, or innermost COUNT frames.");
add_info_alias ("s", "stack", 1);
add_info ("frame", frame_info,
"All about selected stack frame, or frame at ADDR.");
add_info_alias ("f", "frame", 1);
add_info ("locals", locals_info,
"Local variables of current stack frame.");
add_info ("args", args_info,
"Argument variables of current stack frame.");
if (xdb_commands)
add_com ("l", class_info, args_plus_locals_info,
"Argument and local variables of current stack frame.");
if (dbx_commands)
add_com ("func", class_stack, func_command,
"Select the stack frame that contains <func>.\nUsage: func <name>\n");
add_info ("catch", catch_info,
"Exceptions that can be caught in the current stack frame.");
#if 0
add_cmd ("backtrace-limit", class_stack, set_backtrace_limit_command,
"Specify maximum number of frames for \"backtrace\" to print by default.",
&setlist);
add_info ("backtrace-limit", backtrace_limit_info,
"The maximum number of frames for \"backtrace\" to print by default.");
#endif
}