#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 "ui-out.h"
#include "block.h"
#include "stack.h"
#include "gdb_assert.h"
#include "dictionary.h"
#include "exceptions.h"
#include "reggroups.h"
#include "regcache.h"
#include "symfile.h"
#include "objfiles.h"
#include "solib.h"
void args_info (char *, int);
void locals_info (char *, int);
void (*deprecated_selected_frame_level_changed_hook) (int);
void _initialize_stack (void);
static struct frame_info *parse_frame_specification (char *frame_exp);
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 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 print_level,
enum print_what print_what,
int print_args,
struct symtab_and_line sal);
static void set_current_sal_from_frame (struct frame_info *, int);
static void backtrace_command (char *, int);
static void frame_info (char *, int);
extern int addressprint;
int annotation_level = 0;
struct print_stack_frame_args
{
struct frame_info *fi;
int print_level;
enum print_what print_what;
int print_args;
};
static int
print_stack_frame_stub (void *args)
{
struct print_stack_frame_args *p = args;
int center = (p->print_what == SRC_LINE
|| p->print_what == SRC_AND_LOC);
print_frame_info (p->fi, p->print_level, p->print_what, p->print_args);
set_current_sal_from_frame (p->fi, center);
return 0;
}
void
print_stack_frame (struct frame_info *fi, int print_level,
enum print_what print_what)
{
struct print_stack_frame_args args;
args.fi = fi;
args.print_level = print_level;
args.print_what = print_what;
args.print_args = 1;
catch_errors (print_stack_frame_stub, (char *) &args, "", RETURN_MASK_ALL);
}
struct print_args_args
{
struct symbol *func;
struct frame_info *fi;
struct ui_file *stream;
};
static int print_args_stub (void *);
static void
print_frame_nameless_args (struct frame_info *fi, long start, int num,
int first, struct ui_file *stream)
{
int i;
CORE_ADDR argsaddr;
long arg_value;
for (i = 0; i < num; i++)
{
QUIT;
argsaddr = get_frame_args_address (fi);
if (!argsaddr)
return;
arg_value = read_memory_integer (argsaddr + start, sizeof (int));
if (!first)
fprintf_filtered (stream, ", ");
fprintf_filtered (stream, "%ld", arg_value);
first = 0;
start += sizeof (int);
}
}
static void
print_frame_args (struct symbol *func, struct frame_info *fi, int num,
struct ui_file *stream)
{
struct block *b = NULL;
int first = 1;
struct dict_iterator iter;
struct symbol *sym;
struct value *val;
long highest_offset = -1;
int arg_size;
int args_printed = 0;
struct cleanup *old_chain, *list_chain;
struct ui_stream *stb;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
if (func)
{
b = SYMBOL_BLOCK_VALUE (func);
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
QUIT;
switch (SYMBOL_CLASS (sym))
{
case LOC_ARG:
case LOC_REF_ARG:
{
long current_offset = SYMBOL_VALUE (sym);
arg_size = TYPE_LENGTH (SYMBOL_TYPE (sym));
current_offset =
((current_offset + arg_size + sizeof (int) - 1)
& ~(sizeof (int) - 1));
if (highest_offset == -1
|| (current_offset > highest_offset))
highest_offset = current_offset;
args_printed += (arg_size + sizeof (int) - 1) / sizeof (int);
}
case LOC_REGPARM:
case LOC_REGPARM_ADDR:
case LOC_LOCAL_ARG:
case LOC_BASEREG_ARG:
case LOC_COMPUTED_ARG:
break;
default:
continue;
}
if (*DEPRECATED_SYMBOL_NAME (sym))
{
struct symbol *nsym;
nsym = lookup_symbol
(DEPRECATED_SYMBOL_NAME (sym),
b, VAR_DOMAIN, (int *) NULL, (struct symtab **) NULL);
if (SYMBOL_CLASS (nsym) == LOC_REGISTER)
{
;
}
else
sym = nsym;
}
if (!first)
ui_out_text (uiout, ", ");
ui_out_wrap_hint (uiout, " ");
annotate_arg_begin ();
list_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
fprintf_symbol_filtered (stb->stream, SYMBOL_PRINT_NAME (sym),
SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI);
ui_out_field_stream (uiout, "name", stb);
annotate_arg_name_end ();
ui_out_text (uiout, "=");
val = read_var_value (sym, fi);
annotate_arg_value (val == NULL ? NULL : value_type (val));
if (val)
{
common_val_print (val, stb->stream, 0, 0, 2, Val_no_prettyprint);
ui_out_field_stream (uiout, "value", stb);
}
else
ui_out_text (uiout, "???");
do_cleanups (list_chain);
annotate_arg_end ();
first = 0;
}
}
if (num != -1)
{
long start;
if (highest_offset == -1)
start = FRAME_ARGS_SKIP;
else
start = highest_offset;
print_frame_nameless_args (fi, start, num - args_printed,
first, stream);
}
do_cleanups (old_chain);
}
static int
print_args_stub (void *args)
{
int numargs;
struct print_args_args *p = (struct print_args_args *) args;
if (FRAME_NUM_ARGS_P ())
{
numargs = FRAME_NUM_ARGS (p->fi);
gdb_assert (numargs >= 0);
}
else
numargs = -1;
print_frame_args (p->func, p->fi, numargs, p->stream);
return 0;
}
static void
set_current_sal_from_frame (struct frame_info *fi, int center)
{
struct symtab_and_line sal;
find_frame_sal (fi, &sal);
if (sal.symtab)
{
if (center)
sal.line = max (sal.line - get_lines_to_list () / 2, 1);
set_current_source_symtab_and_line (&sal);
}
}
void
print_frame_info (struct frame_info *fi, int print_level,
enum print_what print_what, int print_args)
{
struct symtab_and_line sal;
int source_print;
int location_print;
if (get_frame_type (fi) == DUMMY_FRAME
|| get_frame_type (fi) == SIGTRAMP_FRAME)
{
struct cleanup *uiout_cleanup
= make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
annotate_frame_begin (print_level ? frame_relative_level (fi) : 0,
get_frame_pc (fi));
if (print_level)
{
ui_out_text (uiout, "#");
ui_out_field_fmt_int (uiout, 2, ui_left, "level",
frame_relative_level (fi));
}
if (ui_out_is_mi_like_p (uiout))
{
annotate_frame_address ();
ui_out_field_core_addr (uiout, "addr", get_frame_pc (fi));
annotate_frame_address_end ();
ui_out_field_core_addr (uiout, "fp", get_frame_base (fi));
}
if (get_frame_type (fi) == DUMMY_FRAME)
{
annotate_function_call ();
ui_out_field_string (uiout, "func", "<function called from gdb>");
}
else if (get_frame_type (fi) == SIGTRAMP_FRAME)
{
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;
}
pc_set_load_state (get_frame_pc (fi), OBJF_SYM_ALL, 0);
find_frame_sal (fi, &sal);
location_print = (print_what == LOCATION
|| print_what == LOC_AND_ADDRESS
|| print_what == SRC_AND_LOC);
if (location_print || !sal.symtab)
print_frame (fi, print_level, print_what, print_args, sal);
source_print = (print_what == SRC_LINE || print_what == SRC_AND_LOC);
if (source_print && sal.symtab)
{
int done = 0;
int mid_statement = ((print_what == SRC_LINE)
&& (get_frame_pc (fi) != sal.pc));
if (annotation_level)
done = identify_source_line (sal.symtab, sal.line, mid_statement,
get_frame_pc (fi));
if (!done)
{
if (deprecated_print_frame_info_listing_hook)
deprecated_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", get_frame_pc (fi));
ui_out_text (uiout, "\t");
}
if (deprecated_print_frame_info_listing_hook)
deprecated_print_frame_info_listing_hook (sal.symtab, sal.line, 1, 0);
else
print_source_lines (sal.symtab, sal.line, 1, 0);
}
}
}
if (print_what != LOCATION)
set_default_breakpoint (1, get_frame_pc (fi), sal.symtab, sal.line);
annotate_frame_end ();
gdb_flush (gdb_stdout);
}
static void
print_frame (struct frame_info *fi,
int print_level,
enum print_what print_what,
int print_args,
struct symtab_and_line sal)
{
struct symbol *func;
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 (get_frame_address_in_block (fi));
if (func)
{
struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (get_frame_address_in_block (fi));
if (msymbol != NULL
&& (SYMBOL_VALUE_ADDRESS (msymbol)
> BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
{
func = 0;
funname = DEPRECATED_SYMBOL_NAME (msymbol);
funlang = SYMBOL_LANGUAGE (msymbol);
}
else
{
char *demangled;
funname = DEPRECATED_SYMBOL_NAME (func);
funlang = SYMBOL_LANGUAGE (func);
if (funlang == language_cplus || funlang == language_objcplus)
{
demangled = cplus_demangle (funname, DMGL_ANSI);
if (demangled == NULL)
funname = SYMBOL_PRINT_NAME (func);
}
}
}
else
{
struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (get_frame_address_in_block (fi));
if (msymbol != NULL)
{
funname = DEPRECATED_SYMBOL_NAME (msymbol);
funlang = SYMBOL_LANGUAGE (msymbol);
}
}
annotate_frame_begin (print_level ? frame_relative_level (fi) : 0,
get_frame_pc (fi));
list_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
if (print_level)
{
ui_out_text (uiout, "#");
ui_out_field_fmt_int (uiout, 2, ui_left, "level",
frame_relative_level (fi));
}
if (addressprint)
if (get_frame_pc (fi) != sal.pc
|| !sal.symtab
|| print_what == LOC_AND_ADDRESS)
{
annotate_frame_address ();
ui_out_field_core_addr (uiout, "addr", get_frame_pc (fi));
annotate_frame_address_end ();
ui_out_text (uiout, " in ");
if (ui_out_is_mi_like_p (uiout))
{
ui_out_field_core_addr (uiout, "fp", get_frame_base (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 (print_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);
if (ui_out_is_mi_like_p (uiout))
{
const char *fullname = symtab_to_fullname (sal.symtab);
if (fullname != NULL)
ui_out_field_string (uiout, "fullname", fullname);
}
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);
if (!funname || (!sal.symtab || !sal.symtab->filename))
{
#ifdef PC_SOLIB
char *lib = PC_SOLIB (get_frame_pc (fi));
#else
char *lib = solib_address (get_frame_pc (fi));
#endif
if (lib)
{
annotate_frame_where ();
ui_out_wrap_hint (uiout, " ");
ui_out_text (uiout, " from ");
ui_out_field_string (uiout, "from", lib);
}
}
do_cleanups (list_chain);
ui_out_text (uiout, "\n");
do_cleanups (old_chain);
}
void
show_stack_frame (struct frame_info *fi)
{
}
struct frame_info *
parse_frame_specification_1 (const char *frame_exp, const char *message,
int *selected_frame_p)
{
int numargs;
struct value *args[4];
CORE_ADDR addrs[ARRAY_SIZE (args)];
if (frame_exp == NULL)
numargs = 0;
else
{
char *addr_string;
struct cleanup *tmp_cleanup;
numargs = 0;
while (1)
{
char *addr_string;
struct cleanup *cleanup;
const char *p;
while (isspace (*frame_exp))
frame_exp++;
if (!*frame_exp)
break;
for (p = frame_exp;
*p && !isspace (*p);
p++);
addr_string = savestring (frame_exp, p - frame_exp);
frame_exp = p;
cleanup = make_cleanup (xfree, addr_string);
if (numargs >= ARRAY_SIZE (args))
error (_("Too many args in frame specification"));
args[numargs++] = parse_and_eval (addr_string);
do_cleanups (cleanup);
}
}
if (numargs == 0)
{
if (selected_frame_p != NULL)
(*selected_frame_p) = 1;
return get_selected_frame (message);
}
if (selected_frame_p != NULL)
(*selected_frame_p) = 0;
if (numargs == 1)
{
struct frame_info *fid;
int level = value_as_long (args[0]);
fid = find_relative_frame (get_current_frame (), &level);
if (level == 0)
return fid;
}
{
int i;
for (i = 0; i < numargs; i++)
addrs[i] = value_as_address (args[0]);
}
if (numargs == 1)
{
struct frame_id id = frame_id_build_wild (addrs[0]);
struct frame_info *fid;
for (fid = get_current_frame ();
fid != NULL;
fid = get_prev_frame (fid))
{
if (frame_id_eq (id, get_frame_id (fid)))
{
while (frame_id_eq (id, frame_unwind_id (fid)))
fid = get_prev_frame (fid);
return fid;
}
}
}
if (numargs == 1)
return create_new_frame (addrs[0], 0);
else if (numargs == 2)
return create_new_frame (addrs[0], addrs[1]);
else
error (_("Too many args in frame specification"));
}
struct frame_info *
parse_frame_specification (char *frame_exp)
{
return parse_frame_specification_1 (frame_exp, NULL, NULL);
}
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;
const char *pc_regname;
int selected_frame_p;
fi = parse_frame_specification_1 (addr_exp, "No stack.", &selected_frame_p);
if (PC_REGNUM >= 0)
pc_regname = REGISTER_NAME (PC_REGNUM);
else
pc_regname = "pc";
find_frame_sal (fi, &sal);
func = get_frame_function (fi);
s = find_pc_symtab (get_frame_pc (fi));
if (func)
{
char *demangled;
funname = DEPRECATED_SYMBOL_NAME (func);
funlang = SYMBOL_LANGUAGE (func);
if (funlang == language_cplus || funlang == language_objcplus)
{
demangled = cplus_demangle (funname, DMGL_ANSI);
if (demangled == NULL)
funname = SYMBOL_PRINT_NAME (func);
}
}
else
{
struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (get_frame_pc (fi));
if (msymbol != NULL)
{
funname = DEPRECATED_SYMBOL_NAME (msymbol);
funlang = SYMBOL_LANGUAGE (msymbol);
}
}
calling_frame_info = get_prev_frame (fi);
if (selected_frame_p && frame_relative_level (fi) >= 0)
{
printf_filtered (_("Stack level %d, frame at "),
frame_relative_level (fi));
}
else
{
printf_filtered (_("Stack frame at "));
}
deprecated_print_address_numeric (get_frame_base (fi), 1, gdb_stdout);
printf_filtered (":\n");
printf_filtered (" %s = ", pc_regname);
deprecated_print_address_numeric (get_frame_pc (fi), 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 ", pc_regname);
deprecated_print_address_numeric (frame_pc_unwind (fi), 1, gdb_stdout);
printf_filtered ("\n");
if (calling_frame_info)
{
printf_filtered (" called by frame at ");
deprecated_print_address_numeric (get_frame_base (calling_frame_info),
1, gdb_stdout);
}
if (get_next_frame (fi) && calling_frame_info)
puts_filtered (",");
wrap_here (" ");
if (get_next_frame (fi))
{
printf_filtered (" caller of frame at ");
deprecated_print_address_numeric (get_frame_base (get_next_frame (fi)), 1,
gdb_stdout);
}
if (get_next_frame (fi) || calling_frame_info)
puts_filtered ("\n");
if (s)
printf_filtered (" source language %s.\n",
language_str (s->language));
{
CORE_ADDR arg_list = get_frame_args_address (fi);
int numargs;
if (arg_list == 0)
printf_filtered (" Arglist at unknown address.\n");
else
{
printf_filtered (" Arglist at ");
deprecated_print_address_numeric (arg_list, 1, gdb_stdout);
printf_filtered (",");
if (!FRAME_NUM_ARGS_P ())
{
numargs = -1;
puts_filtered (" args: ");
}
else
{
numargs = FRAME_NUM_ARGS (fi);
gdb_assert (numargs >= 0);
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 = get_frame_locals_address (fi);
if (arg_list == 0)
printf_filtered (" Locals at unknown address,");
else
{
printf_filtered (" Locals at ");
deprecated_print_address_numeric (arg_list, 1, gdb_stdout);
printf_filtered (",");
}
}
{
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)
{
gdb_byte value[MAX_REGISTER_SIZE];
CORE_ADDR sp;
frame_register_unwind (fi, SP_REGNUM, &optimized, &lval, &addr,
&realnum, value);
sp = extract_unsigned_integer (value, register_size (current_gdbarch, SP_REGNUM));
printf_filtered (" Previous frame's sp is ");
deprecated_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 ");
deprecated_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
&& gdbarch_register_reggroup_p (current_gdbarch, i, all_reggroup))
{
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));
deprecated_print_address_numeric (addr, 1, gdb_stdout);
count++;
}
}
if (count || need_nl)
puts_filtered ("\n");
}
#ifdef PRINT_EXTRA_FRAME_INFO
PRINT_EXTRA_FRAME_INFO (frame_next_hack (fi), frame_cache_hack (fi));
#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;
int count;
int i;
struct frame_info *trailing;
int trailing_level;
struct symtab_and_line original_sal;
if (!target_has_stack)
error (_("No stack."));
trailing = get_current_frame ();
original_sal = get_current_source_symtab_and_line ();
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 (get_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 (fi, 1, LOCATION, 1);
if (show_locals)
print_frame_local_vars (fi, 1, gdb_stdout);
}
if (fi && from_tty)
printf_filtered (_("(More stack frames follow...)\n"));
set_current_source_symtab_and_line (&original_sal);
}
struct backtrace_command_args
{
char *count_exp;
int show_locals;
int from_tty;
};
static int
backtrace_command_stub (void *data)
{
struct backtrace_command_args *args = (struct backtrace_command_args *)data;
backtrace_command_1 (args->count_exp, args->show_locals, args->from_tty);
return 0;
}
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;
struct backtrace_command_args btargs;
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;
}
}
btargs.count_exp = argPtr;
btargs.show_locals = (argIndicatingFullTrace >= 0);
btargs.from_tty = from_tty;
catch_errors (backtrace_command_stub, (char *)&btargs, "", RETURN_MASK_ERROR);
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)
{
struct backtrace_command_args btargs;
btargs.count_exp = arg;
btargs.show_locals = 1;
btargs.from_tty = from_tty;
catch_errors (backtrace_command_stub, (char *)&btargs, "", RETURN_MASK_ERROR);
}
static int
print_block_frame_locals (struct block *b, struct frame_info *fi,
int num_tabs, struct ui_file *stream)
{
struct dict_iterator iter;
int j;
struct symbol *sym;
int values_printed = 0;
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
switch (SYMBOL_CLASS (sym))
{
case LOC_LOCAL:
case LOC_REGISTER:
case LOC_STATIC:
case LOC_BASEREG:
case LOC_COMPUTED:
values_printed = 1;
for (j = 0; j < num_tabs; j++)
fputs_filtered ("\t", stream);
fputs_filtered (SYMBOL_PRINT_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,
struct ui_file *stream)
{
struct dict_iterator iter;
struct symbol *sym;
int values_printed = 0;
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
if (strcmp (DEPRECATED_SYMBOL_NAME (sym), "default") == 0)
{
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_PRINT_NAME (sym), stream);
if (addressprint)
{
fprintf_filtered (stream, " ");
deprecated_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 (struct frame_info *fi, int num_tabs,
struct ui_file *stream)
{
struct block *block = get_frame_block (fi, 0);
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 (struct frame_info *fi, int this_level_only,
struct ui_file *stream)
{
struct blockvector *bl;
struct block *block = get_frame_block (fi, 0);
int values_printed = 0;
int index, have_default = 0;
char *blocks_printed;
CORE_ADDR pc = get_frame_pc (fi);
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)
{
print_frame_local_vars (get_selected_frame ("No frame selected."),
0, gdb_stdout);
}
static void
catch_info (char *ignore, int from_tty)
{
struct symtabs_and_lines *sals;
if (target_enable_exception_callback (EX_EVENT_CATCH, 1))
{
sals = target_find_exception_catchpoints (EX_EVENT_CATCH, NULL);
if (sals)
{
fprintf_filtered (gdb_stdout, "Info catch not supported with this"
" target/compiler combination.\n");
if (sals != (struct symtabs_and_lines *) -1)
{
if (sals->nelts > 0)
xfree (sals->sals);
xfree (sals);
}
}
#if 0
if (!deprecated_selected_frame)
error ("No frame selected.");
#endif
}
else
{
print_frame_label_vars (get_selected_frame ("No frame selected."),
0, gdb_stdout);
}
}
static void
print_frame_arg_vars (struct frame_info *fi,
struct ui_file *stream)
{
struct symbol *func = get_frame_function (fi);
struct block *b;
struct dict_iterator iter;
struct symbol *sym, *sym2;
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, iter, 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:
case LOC_COMPUTED_ARG:
values_printed = 1;
fputs_filtered (SYMBOL_PRINT_NAME (sym), stream);
fputs_filtered (" = ", stream);
sym2 = lookup_symbol (DEPRECATED_SYMBOL_NAME (sym),
b, VAR_DOMAIN, (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)
{
print_frame_arg_vars (get_selected_frame ("No frame selected."),
gdb_stdout);
}
static void
args_plus_locals_info (char *ignore, int from_tty)
{
args_info (ignore, from_tty);
locals_info (ignore, from_tty);
}
static void
select_and_print_frame (struct frame_info *fi)
{
select_frame (fi);
if (fi)
print_stack_frame (fi, 1, SRC_AND_LOC);
}
struct block *
get_selected_block (CORE_ADDR *addr_in_block)
{
if (!target_has_stack)
return 0;
if (!deprecated_selected_frame)
{
CORE_ADDR pc = read_pc ();
if (addr_in_block != NULL)
*addr_in_block = pc;
return block_for_pc (pc);
}
return get_frame_block (deprecated_selected_frame, addr_in_block);
}
struct frame_info *
find_relative_frame (struct frame_info *frame,
int *level_offset_ptr)
{
struct frame_info *prev;
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 (char *level_exp, int from_tty)
{
select_frame (parse_frame_specification_1 (level_exp, "No stack.", NULL));
}
void
frame_command (char *level_exp, int from_tty)
{
select_frame_command (level_exp, from_tty);
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
}
static void
current_frame_command (char *level_exp, int from_tty)
{
print_stack_frame (get_selected_frame ("No stack."), 1, SRC_AND_LOC);
}
static void
up_silently_base (char *count_exp)
{
struct frame_info *fi;
int count = 1, count1;
if (count_exp)
count = parse_and_eval_long (count_exp);
count1 = count;
fi = find_relative_frame (get_selected_frame ("No stack."), &count1);
if (count1 != 0 && count_exp == 0)
error (_("Initial frame selected; you cannot go up."));
select_frame (fi);
}
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);
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
}
static void
down_silently_base (char *count_exp)
{
struct frame_info *frame;
int count = -1, count1;
if (count_exp)
count = -parse_and_eval_long (count_exp);
count1 = count;
frame = find_relative_frame (get_selected_frame ("No stack."), &count1);
if (count1 != 0 && count_exp == 0)
{
error (_("Bottom (i.e., innermost) frame selected; you cannot go down."));
}
select_frame (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);
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
}
void
return_command (char *retval_exp, int from_tty)
{
struct symbol *thisfun;
struct value *return_value = NULL;
const char *query_prefix = "";
thisfun = get_frame_function (get_selected_frame ("No selected frame."));
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;
CHECK_TYPEDEF (return_type);
return_value = value_cast (return_type, return_value);
if (value_lazy (return_value))
value_fetch_lazy (return_value);
if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
return_value = NULL;
else if (!gdbarch_return_value_p (current_gdbarch)
&& (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
|| TYPE_CODE (return_type) == TYPE_CODE_UNION))
{
query_prefix = "\
A structure or union return type is not supported by this architecture.\n\
If you continue, the return value that you specified will be ignored.\n";
return_value = NULL;
}
else if (using_struct_return (return_type, 0))
{
query_prefix = "\
The location at which to store the function's return value is unknown.\n\
If you continue, the return value that you specified will be ignored.\n";
return_value = NULL;
}
}
if (from_tty)
{
int confirmed;
if (thisfun == NULL)
confirmed = query (_("%sMake selected stack frame return now? "),
query_prefix);
else
confirmed = query (_("%sMake %s return now? "), query_prefix,
SYMBOL_PRINT_NAME (thisfun));
if (!confirmed)
error (_("Not confirmed"));
}
{
struct frame_id selected_id = get_frame_id (get_selected_frame (NULL));
while (!frame_id_eq (selected_id, get_frame_id (get_current_frame ())))
{
if (frame_id_inner (selected_id, get_frame_id (get_current_frame ())))
error (_("Problem while popping stack frames (corrupt stack?)"));
frame_pop (get_current_frame ());
}
}
frame_pop (get_current_frame ());
if (return_value != NULL)
{
struct type *return_type = value_type (return_value);
gdb_assert (gdbarch_return_value (current_gdbarch, return_type,
NULL, NULL, NULL)
== RETURN_VALUE_REGISTER_CONVENTION);
gdbarch_return_value (current_gdbarch, return_type,
current_regcache, NULL ,
value_contents (return_value) );
}
if (get_frame_type (get_current_frame ()) == DUMMY_FRAME)
frame_pop (get_current_frame ());
if (stack_changed_hook != NULL)
stack_changed_hook ();
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 = (get_frame_pc (fp) >= func_bounds[i].low &&
get_frame_pc (fp) < 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 != deprecated_selected_frame)
select_and_print_frame (fp);
}
enum language
get_frame_language (void)
{
struct symtab *s;
enum language flang;
if (deprecated_selected_frame)
{
s = find_pc_symtab (get_frame_address_in_block (deprecated_selected_frame));
if (s)
{
flang = s->language;
if (flang == language_objcplus)
{
struct symbol *sym =
find_pc_function (get_frame_pc (deprecated_selected_frame));
if (sym && (SYMBOL_LANGUAGE (sym) == language_cplus))
flang = language_cplus;
}
}
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>.\n\
Usage: 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
}