#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 "reggroups.h"
#include "regcache.h"
#include "symfile.h"
#include "objfiles.h"
void args_info (char *, int);
void locals_info (char *, int);
void (*selected_frame_level_changed_hook) (int);
void _initialize_stack (void);
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 level,
int source,
int args,
struct symtab_and_line sal);
static void backtrace_command (char *, int);
struct frame_info *parse_frame_specification (char *);
static void frame_info (char *, int);
extern int addressprint;
int annotation_level = 0;
struct print_stack_frame_args
{
struct frame_info *fi;
int level;
int source;
int args;
};
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 (p->fi, p->level, p->source, p->args);
return 0;
}
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);
}
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)
{
val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), 0,
VALUE_ADDRESS (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;
}
void
print_frame_info (struct frame_info *fi, int level, int source, int 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 (level == -1 ? 0 : level, get_frame_pc (fi));
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", 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);
find_frame_sal (fi, &sal);
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) && (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 (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", get_frame_pc (fi));
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, get_frame_pc (fi), 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;
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))))
{
#if 0
sal.symtab = 0;
#endif
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 (level == -1 ? 0 : level, get_frame_pc (fi));
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 (get_frame_pc (fi) != sal.pc
|| !sal.symtab
|| source == 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 (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 (get_frame_pc (fi));
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
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 (deprecated_selected_frame == NULL)
error ("No selected frame.");
return deprecated_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 && get_frame_base (fid) != args[0];
fid = get_prev_frame (fid))
;
if (fid)
while ((tfid = get_prev_frame (fid)) &&
(get_frame_base (tfid) == 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
}
}
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;
if (!target_has_stack)
error ("No stack.");
if (PC_REGNUM >= 0)
pc_regname = REGISTER_NAME (PC_REGNUM);
else
pc_regname = "pc";
fi = parse_frame_specification (addr_exp);
if (fi == NULL)
error ("Invalid frame specified.");
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 (!addr_exp && frame_relative_level (deprecated_selected_frame) >= 0)
{
printf_filtered ("Stack level %d, frame at ",
frame_relative_level (deprecated_selected_frame));
print_address_numeric (get_frame_base (fi), 1, gdb_stdout);
printf_filtered (":\n");
}
else
{
printf_filtered ("Stack frame at ");
print_address_numeric (get_frame_base (fi), 1, gdb_stdout);
printf_filtered (":\n");
}
printf_filtered (" %s = ", pc_regname);
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);
print_address_numeric (frame_pc_unwind (fi), 1, gdb_stdout);
printf_filtered ("\n");
{
int frameless;
frameless = (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P ()
&& DEPRECATED_FRAMELESS_FUNCTION_INVOCATION (fi));
if (frameless)
printf_filtered (" (FRAMELESS),");
}
if (calling_frame_info)
{
printf_filtered (" called by frame at ");
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 ");
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 ");
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 ");
print_address_numeric (arg_list, 1, gdb_stdout);
printf_filtered (",");
}
}
if (DEPRECATED_FRAME_INIT_SAVED_REGS_P ()
&& deprecated_get_frame_saved_regs (fi) == NULL)
DEPRECATED_FRAME_INIT_SAVED_REGS (fi);
{
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)
{
char value[MAX_REGISTER_SIZE];
CORE_ADDR sp;
frame_register_unwind (fi, SP_REGNUM, &optimized, &lval, &addr,
&realnum, value);
sp = extract_unsigned_integer (value, DEPRECATED_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
&& 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));
print_address_numeric (addr, 1, gdb_stdout);
count++;
}
}
if (count || need_nl)
puts_filtered ("\n");
}
gdbarch_deprecated_print_extra_frame_info (current_gdbarch, deprecated_frame_next_hack (fi), deprecated_frame_cache_hack (fi));
}
#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;
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, 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");
set_current_source_symtab_and_line (&original_sal);
}
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, 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 (DEPRECATED_STREQ (DEPRECATED_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_PRINT_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 (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)
{
if (!deprecated_selected_frame)
error ("No frame selected.");
print_frame_local_vars (deprecated_selected_frame, 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);
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
{
if (!deprecated_selected_frame)
error ("No frame selected.");
print_frame_label_vars (deprecated_selected_frame, 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)
{
if (!deprecated_selected_frame)
error ("No frame selected.");
print_frame_arg_vars (deprecated_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);
}
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 (!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)
{
struct frame_info *frame;
int level = frame_relative_level (deprecated_selected_frame);
if (!target_has_stack)
error ("No stack.");
frame = parse_frame_specification (level_exp);
select_frame (frame);
if (level != frame_relative_level (deprecated_selected_frame))
selected_frame_level_changed_event (frame_relative_level (deprecated_selected_frame));
}
void
frame_command (char *level_exp, int from_tty)
{
select_frame_command (level_exp, from_tty);
print_stack_frame (deprecated_selected_frame,
frame_relative_level (deprecated_selected_frame), 1);
}
static void
current_frame_command (char *level_exp, int from_tty)
{
if (target_has_stack == 0 || deprecated_selected_frame == 0)
error ("No stack.");
print_stack_frame (deprecated_selected_frame,
frame_relative_level (deprecated_selected_frame), 1);
}
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;
if (target_has_stack == 0 || deprecated_selected_frame == 0)
error ("No stack.");
fi = find_relative_frame (deprecated_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 (deprecated_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);
print_stack_frame (deprecated_selected_frame,
frame_relative_level (deprecated_selected_frame), 1);
}
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;
if (target_has_stack == 0 || deprecated_selected_frame == 0)
error ("No stack.");
frame = find_relative_frame (deprecated_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 (deprecated_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);
print_stack_frame (deprecated_selected_frame,
frame_relative_level (deprecated_selected_frame), 1);
}
void
return_command (char *retval_exp, int from_tty)
{
struct symbol *thisfun;
struct value *return_value = NULL;
const char *query_prefix = "";
if (!target_has_registers)
error ("No selected frame.");
thisfun = get_frame_function (get_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;
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 ());
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);
if (!gdbarch_return_value_p (current_gdbarch))
{
STORE_RETURN_VALUE (return_type, current_regcache,
VALUE_CONTENTS (return_value));
}
else
{
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) );
}
}
#ifdef DEPRECATED_CALL_DUMMY_HAS_COMPLETED
if (DEPRECATED_CALL_DUMMY_HAS_COMPLETED (read_pc(), read_sp (),
get_frame_base (get_current_frame ())))
frame_pop (get_current_frame ());
#else
if (get_frame_type (get_current_frame ()) == DUMMY_FRAME)
frame_pop (get_current_frame ());
#endif
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>.\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
}