#include "defs.h"
#include "frame.h"
#include "target.h"
#include "value.h"
#include "inferior.h"
#include "regcache.h"
#include "gdb_assert.h"
#include "gdb_string.h"
#include "user-regs.h"
#include "gdb_obstack.h"
#include "dummy-frame.h"
#include "sentinel-frame.h"
#include "gdbcore.h"
#include "annotate.h"
#include "language.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "command.h"
#include "gdbcmd.h"
#include "observer.h"
#include "objfiles.h"
#include "exceptions.h"
static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
struct frame_info
{
int level;
void *prologue_cache;
const struct frame_unwind *unwind;
struct {
int p;
CORE_ADDR value;
} prev_pc;
struct
{
CORE_ADDR addr;
int p;
} prev_func;
struct
{
int p;
struct frame_id value;
} this_id;
const struct frame_base *base;
void *base_cache;
struct frame_info *next;
int prev_p;
struct frame_info *prev;
};
int frame_debug;
static void
show_frame_debug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Frame debugging is %s.\n"), value);
}
struct frame_info *frame_next_hack (struct frame_info *frame)
{
return frame->next;
}
void *frame_cache_hack (struct frame_info *frame)
{
return & (frame->prologue_cache);
}
int backtrace_past_main;
static void
show_backtrace_past_main (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
Whether backtraces should continue past \"main\" is %s.\n"),
value);
}
static int backtrace_past_entry;
static void
show_backtrace_past_entry (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
Whether backtraces should continue past the entry point of a program is %s.\n"),
value);
}
static int backtrace_limit = INT_MAX;
static void
show_backtrace_limit (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
An upper bound on the number of backtrace levels is %s.\n"),
value);
}
static void
fprint_field (struct ui_file *file, const char *name, int p, CORE_ADDR addr)
{
if (p)
fprintf_unfiltered (file, "%s=0x%s", name, paddr_nz (addr));
else
fprintf_unfiltered (file, "!%s", name);
}
void
fprint_frame_id (struct ui_file *file, struct frame_id id)
{
fprintf_unfiltered (file, "{");
fprint_field (file, "stack", id.stack_addr_p, id.stack_addr);
fprintf_unfiltered (file, ",");
fprint_field (file, "code", id.code_addr_p, id.code_addr);
fprintf_unfiltered (file, ",");
fprint_field (file, "special", id.special_addr_p, id.special_addr);
fprintf_unfiltered (file, "}");
}
static void
fprint_frame_type (struct ui_file *file, enum frame_type type)
{
switch (type)
{
case NORMAL_FRAME:
fprintf_unfiltered (file, "NORMAL_FRAME");
return;
case DUMMY_FRAME:
fprintf_unfiltered (file, "DUMMY_FRAME");
return;
case SIGTRAMP_FRAME:
fprintf_unfiltered (file, "SIGTRAMP_FRAME");
return;
default:
fprintf_unfiltered (file, "<unknown type>");
return;
};
}
static void
fprint_frame (struct ui_file *file, struct frame_info *fi)
{
if (fi == NULL)
{
fprintf_unfiltered (file, "<NULL frame>");
return;
}
fprintf_unfiltered (file, "{");
fprintf_unfiltered (file, "level=%d", fi->level);
fprintf_unfiltered (file, ",");
fprintf_unfiltered (file, "type=");
if (fi->unwind != NULL)
fprint_frame_type (file, fi->unwind->type);
else
fprintf_unfiltered (file, "<unknown>");
fprintf_unfiltered (file, ",");
fprintf_unfiltered (file, "unwind=");
if (fi->unwind != NULL)
gdb_print_host_address (fi->unwind, file);
else
fprintf_unfiltered (file, "<unknown>");
fprintf_unfiltered (file, ",");
fprintf_unfiltered (file, "pc=");
if (fi->next != NULL && fi->next->prev_pc.p)
fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_pc.value));
else
fprintf_unfiltered (file, "<unknown>");
fprintf_unfiltered (file, ",");
fprintf_unfiltered (file, "id=");
if (fi->this_id.p)
fprint_frame_id (file, fi->this_id.value);
else
fprintf_unfiltered (file, "<unknown>");
fprintf_unfiltered (file, ",");
fprintf_unfiltered (file, "func=");
if (fi->next != NULL && fi->next->prev_func.p)
fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_func.addr));
else
fprintf_unfiltered (file, "<unknown>");
fprintf_unfiltered (file, "}");
}
struct frame_id
get_frame_id (struct frame_info *fi)
{
if (fi == NULL)
{
return null_frame_id;
}
if (!fi->this_id.p)
{
if (frame_debug)
fprintf_unfiltered (gdb_stdlog, "{ get_frame_id (fi=%d) ",
fi->level);
if (fi->unwind == NULL)
fi->unwind = frame_unwind_find_by_frame (fi->next,
&fi->prologue_cache);
fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->this_id.value);
fi->this_id.p = 1;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "-> ");
fprint_frame_id (gdb_stdlog, fi->this_id.value);
fprintf_unfiltered (gdb_stdlog, " }\n");
}
}
return fi->this_id.value;
}
struct frame_id
frame_unwind_id (struct frame_info *next_frame)
{
return get_frame_id (get_prev_frame_1 (next_frame));
}
const struct frame_id null_frame_id;
struct frame_id
frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
CORE_ADDR special_addr)
{
struct frame_id id = null_frame_id;
id.stack_addr = stack_addr;
id.stack_addr_p = 1;
id.code_addr = code_addr;
id.code_addr_p = 1;
id.special_addr = special_addr;
id.special_addr_p = 1;
return id;
}
struct frame_id
frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
{
struct frame_id id = null_frame_id;
id.stack_addr = stack_addr;
id.stack_addr_p = 1;
id.code_addr = code_addr;
id.code_addr_p = 1;
return id;
}
struct frame_id
frame_id_build_wild (CORE_ADDR stack_addr)
{
struct frame_id id = null_frame_id;
id.stack_addr = stack_addr;
id.stack_addr_p = 1;
return id;
}
int
frame_id_p (struct frame_id l)
{
int p;
p = l.stack_addr_p;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l=");
fprint_frame_id (gdb_stdlog, l);
fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", p);
}
return p;
}
int
frame_id_eq (struct frame_id l, struct frame_id r)
{
int eq;
if (!l.stack_addr_p || !r.stack_addr_p)
eq = 0;
else if (l.stack_addr != r.stack_addr)
eq = 0;
else if (l.code_addr != r.code_addr)
eq = 0;
else if (!l.special_addr_p || !r.special_addr_p)
eq = 1;
else if (l.special_addr == r.special_addr)
eq = 1;
else
eq = 0;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ frame_id_eq (l=");
fprint_frame_id (gdb_stdlog, l);
fprintf_unfiltered (gdb_stdlog, ",r=");
fprint_frame_id (gdb_stdlog, r);
fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", eq);
}
return eq;
}
int
frame_id_inner (struct frame_id l, struct frame_id r)
{
int inner;
if (!l.stack_addr_p || !r.stack_addr_p)
inner = 0;
else
inner = INNER_THAN (l.stack_addr, r.stack_addr);
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ frame_id_inner (l=");
fprint_frame_id (gdb_stdlog, l);
fprintf_unfiltered (gdb_stdlog, ",r=");
fprint_frame_id (gdb_stdlog, r);
fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", inner);
}
return inner;
}
struct frame_info *
frame_find_by_id (struct frame_id id)
{
struct frame_info *frame;
if (!frame_id_p (id))
return NULL;
for (frame = get_current_frame ();
frame != NULL;
frame = get_prev_frame (frame))
{
struct frame_id this = get_frame_id (frame);
if (frame_id_eq (id, this))
return frame;
if (frame_id_inner (id, this))
return NULL;
}
return NULL;
}
CORE_ADDR
frame_pc_unwind (struct frame_info *this_frame)
{
if (!this_frame->prev_pc.p)
{
CORE_ADDR pc;
if (this_frame->unwind == NULL)
this_frame->unwind
= frame_unwind_find_by_frame (this_frame->next,
&this_frame->prologue_cache);
if (this_frame->unwind->prev_pc != NULL)
pc = this_frame->unwind->prev_pc (this_frame->next,
&this_frame->prologue_cache);
else if (gdbarch_unwind_pc_p (current_gdbarch))
{
pc = gdbarch_unwind_pc (current_gdbarch, this_frame);
}
else
internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
this_frame->prev_pc.value = pc;
this_frame->prev_pc.p = 1;
if (frame_debug)
fprintf_unfiltered (gdb_stdlog,
"{ frame_pc_unwind (this_frame=%d) -> 0x%s }\n",
this_frame->level,
paddr_nz (this_frame->prev_pc.value));
}
return this_frame->prev_pc.value;
}
CORE_ADDR
frame_func_unwind (struct frame_info *fi)
{
if (!fi->prev_func.p)
{
CORE_ADDR addr_in_block = frame_unwind_address_in_block (fi);
fi->prev_func.p = 1;
fi->prev_func.addr = get_pc_function_start (addr_in_block);
if (frame_debug)
fprintf_unfiltered (gdb_stdlog,
"{ frame_func_unwind (fi=%d) -> 0x%s }\n",
fi->level, paddr_nz (fi->prev_func.addr));
}
return fi->prev_func.addr;
}
CORE_ADDR
get_frame_func (struct frame_info *fi)
{
return frame_func_unwind (fi->next);
}
static int
do_frame_register_read (void *src, int regnum, gdb_byte *buf)
{
frame_register_read (src, regnum, buf);
return 1;
}
struct regcache *
frame_save_as_regcache (struct frame_info *this_frame)
{
struct regcache *regcache = regcache_xmalloc (current_gdbarch);
struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache);
regcache_save (regcache, do_frame_register_read, this_frame);
discard_cleanups (cleanups);
return regcache;
}
void
frame_pop (struct frame_info *this_frame)
{
struct regcache *scratch
= frame_save_as_regcache (get_prev_frame_1 (this_frame));
struct cleanup *cleanups = make_cleanup_regcache_xfree (scratch);
regcache_cpy (current_regcache, scratch);
do_cleanups (cleanups);
flush_cached_frames ();
}
void
frame_register_unwind (struct frame_info *frame, int regnum,
int *optimizedp, enum lval_type *lvalp,
CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
{
struct frame_unwind_cache *cache;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "\
{ frame_register_unwind (frame=%d,regnum=%d(%s),...) ",
frame->level, regnum,
frame_map_regnum_to_name (frame, regnum));
}
gdb_assert (optimizedp != NULL);
gdb_assert (lvalp != NULL);
gdb_assert (addrp != NULL);
gdb_assert (realnump != NULL);
gdb_assert (frame != NULL);
if (frame->unwind == NULL)
frame->unwind = frame_unwind_find_by_frame (frame->next,
&frame->prologue_cache);
frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum,
optimizedp, lvalp, addrp, realnump, bufferp);
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "->");
fprintf_unfiltered (gdb_stdlog, " *optimizedp=%d", (*optimizedp));
fprintf_unfiltered (gdb_stdlog, " *lvalp=%d", (int) (*lvalp));
fprintf_unfiltered (gdb_stdlog, " *addrp=0x%s", paddr_nz ((*addrp)));
fprintf_unfiltered (gdb_stdlog, " *bufferp=");
if (bufferp == NULL)
fprintf_unfiltered (gdb_stdlog, "<NULL>");
else
{
int i;
const unsigned char *buf = bufferp;
fprintf_unfiltered (gdb_stdlog, "[");
for (i = 0; i < register_size (current_gdbarch, regnum); i++)
fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
fprintf_unfiltered (gdb_stdlog, "]");
}
fprintf_unfiltered (gdb_stdlog, " }\n");
}
}
void
frame_register (struct frame_info *frame, int regnum,
int *optimizedp, enum lval_type *lvalp,
CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
{
gdb_assert (optimizedp != NULL);
gdb_assert (lvalp != NULL);
gdb_assert (addrp != NULL);
gdb_assert (realnump != NULL);
gdb_assert (frame != NULL && frame->next != NULL);
frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
realnump, bufferp);
}
void
frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf)
{
int optimized;
CORE_ADDR addr;
int realnum;
enum lval_type lval;
frame_register_unwind (frame, regnum, &optimized, &lval, &addr,
&realnum, buf);
}
void
get_frame_register (struct frame_info *frame,
int regnum, gdb_byte *buf)
{
frame_unwind_register (frame->next, regnum, buf);
}
LONGEST
frame_unwind_register_signed (struct frame_info *frame, int regnum)
{
gdb_byte buf[MAX_REGISTER_SIZE];
frame_unwind_register (frame, regnum, buf);
return extract_signed_integer (buf, register_size (get_frame_arch (frame),
regnum));
}
LONGEST
get_frame_register_signed (struct frame_info *frame, int regnum)
{
return frame_unwind_register_signed (frame->next, regnum);
}
ULONGEST
frame_unwind_register_unsigned (struct frame_info *frame, int regnum)
{
gdb_byte buf[MAX_REGISTER_SIZE];
frame_unwind_register (frame, regnum, buf);
return extract_unsigned_integer (buf, register_size (get_frame_arch (frame),
regnum));
}
ULONGEST
get_frame_register_unsigned (struct frame_info *frame, int regnum)
{
return frame_unwind_register_unsigned (frame->next, regnum);
}
void
frame_unwind_unsigned_register (struct frame_info *frame, int regnum,
ULONGEST *val)
{
gdb_byte buf[MAX_REGISTER_SIZE];
frame_unwind_register (frame, regnum, buf);
(*val) = extract_unsigned_integer (buf,
register_size (get_frame_arch (frame),
regnum));
}
void
put_frame_register (struct frame_info *frame, int regnum,
const gdb_byte *buf)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
int realnum;
int optim;
enum lval_type lval;
CORE_ADDR addr;
frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL);
if (optim)
error (_("Attempt to assign to a value that was optimized out."));
switch (lval)
{
case lval_memory:
{
gdb_byte tmp[MAX_REGISTER_SIZE];
memcpy (tmp, buf, register_size (gdbarch, regnum));
write_memory (addr, tmp, register_size (gdbarch, regnum));
break;
}
case lval_register:
case lval_register_literal:
regcache_cooked_write (current_regcache, realnum, buf);
break;
default:
error (_("Attempt to assign to an unmodifiable value."));
}
}
int
frame_register_read (struct frame_info *frame, int regnum,
gdb_byte *myaddr)
{
int optimized;
enum lval_type lval;
CORE_ADDR addr;
int realnum;
frame_register (frame, regnum, &optimized, &lval, &addr, &realnum, myaddr);
if (register_cached (regnum) < 0)
return 0;
return !optimized;
}
int
frame_map_name_to_regnum (struct frame_info *frame, const char *name, int len)
{
return user_reg_map_name_to_regnum (get_frame_arch (frame), name, len);
}
const char *
frame_map_regnum_to_name (struct frame_info *frame, int regnum)
{
return user_reg_map_regnum_to_name (get_frame_arch (frame), regnum);
}
static struct frame_info *
create_sentinel_frame (struct regcache *regcache)
{
struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
frame->level = -1;
frame->prologue_cache = sentinel_frame_cache (regcache);
frame->unwind = sentinel_frame_unwind;
frame->next = frame;
frame->this_id.p = 1;
frame->this_id.value = null_frame_id;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ create_sentinel_frame (...) -> ");
fprint_frame (gdb_stdlog, frame);
fprintf_unfiltered (gdb_stdlog, " }\n");
}
return frame;
}
static struct frame_info *current_frame;
static struct obstack frame_cache_obstack;
void *
frame_obstack_zalloc (unsigned long size)
{
void *data = obstack_alloc (&frame_cache_obstack, size);
memset (data, 0, size);
return data;
}
static int
unwind_to_current_frame (struct ui_out *ui_out, void *args)
{
struct frame_info *frame = get_prev_frame (args);
if (frame == NULL)
return 1;
current_frame = frame;
return 0;
}
struct frame_info *
get_current_frame (void)
{
if (!target_has_registers)
error (_("No registers."));
if (!target_has_stack)
error (_("No stack."));
if (!target_has_memory)
error (_("No memory."));
if (current_frame == NULL)
{
struct frame_info *sentinel_frame =
create_sentinel_frame (current_regcache);
if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
RETURN_MASK_ERROR) != 0)
{
current_frame = sentinel_frame;
}
}
return current_frame;
}
struct frame_info *deprecated_selected_frame;
struct frame_info *
get_selected_frame (const char *message)
{
if (deprecated_selected_frame == NULL)
{
if (message != NULL && (!target_has_registers
|| !target_has_stack
|| !target_has_memory))
error (("%s"), message);
select_frame (get_current_frame ());
}
gdb_assert (deprecated_selected_frame != NULL);
return deprecated_selected_frame;
}
struct frame_info *
deprecated_safe_get_selected_frame (void)
{
if (!target_has_registers || !target_has_stack || !target_has_memory)
return NULL;
return get_selected_frame (NULL);
}
void
select_frame (struct frame_info *fi)
{
struct symtab *s;
deprecated_selected_frame = fi;
if (deprecated_selected_frame_level_changed_hook)
deprecated_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 (get_frame_address_in_block (fi));
if (s
&& s->language != current_language->la_language
&& s->language != language_unknown
&& language_mode == language_mode_auto)
{
set_language (s->language);
}
}
}
struct frame_info *
create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
{
struct frame_info *fi;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog,
"{ create_new_frame (addr=0x%s, pc=0x%s) ",
paddr_nz (addr), paddr_nz (pc));
}
fi = frame_obstack_zalloc (sizeof (struct frame_info));
fi->next = create_sentinel_frame (current_regcache);
fi->unwind = frame_unwind_find_by_frame (fi->next, &fi->prologue_cache);
fi->this_id.p = 1;
deprecated_update_frame_base_hack (fi, addr);
deprecated_update_frame_pc_hack (fi, pc);
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "-> ");
fprint_frame (gdb_stdlog, fi);
fprintf_unfiltered (gdb_stdlog, " }\n");
}
return fi;
}
struct frame_info *
get_next_frame (struct frame_info *this_frame)
{
if (this_frame->level > 0)
return this_frame->next;
else
return NULL;
}
void
frame_observer_target_changed (struct target_ops *target)
{
flush_cached_frames ();
}
void
flush_cached_frames (void)
{
obstack_free (&frame_cache_obstack, 0);
obstack_init (&frame_cache_obstack);
current_frame = NULL;
select_frame (NULL);
annotate_frames_invalid ();
if (frame_debug)
fprintf_unfiltered (gdb_stdlog, "{ flush_cached_frames () }\n");
}
void
reinit_frame_cache (void)
{
flush_cached_frames ();
if (PIDGET (inferior_ptid) != 0)
{
select_frame (get_current_frame ());
}
}
static struct frame_info *
get_prev_frame_1 (struct frame_info *this_frame)
{
struct frame_info *prev_frame;
struct frame_id this_id;
gdb_assert (this_frame != NULL);
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame_1 (this_frame=");
if (this_frame != NULL)
fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
else
fprintf_unfiltered (gdb_stdlog, "<NULL>");
fprintf_unfiltered (gdb_stdlog, ") ");
}
if (this_frame->prev_p)
{
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "-> ");
fprint_frame (gdb_stdlog, this_frame->prev);
fprintf_unfiltered (gdb_stdlog, " // cached \n");
}
return this_frame->prev;
}
this_frame->prev_p = 1;
this_id = get_frame_id (this_frame);
if (this_frame->level >= 0 && !frame_id_p (this_id))
{
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "-> ");
fprint_frame (gdb_stdlog, NULL);
fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
}
return NULL;
}
if (this_frame->next->level >= 0
&& this_frame->next->unwind->type != SIGTRAMP_FRAME
&& frame_id_inner (this_id, get_frame_id (this_frame->next)))
error (_("Previous frame inner to this frame (corrupt stack?)"));
if (this_frame->level > 0
&& frame_id_eq (this_id, get_frame_id (this_frame->next)))
error (_("Previous frame identical to this frame (corrupt stack?)"));
prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
prev_frame->level = this_frame->level + 1;
this_frame->prev = prev_frame;
prev_frame->next = this_frame;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "-> ");
fprint_frame (gdb_stdlog, prev_frame);
fprintf_unfiltered (gdb_stdlog, " }\n");
}
return prev_frame;
}
static void
frame_debug_got_null_frame (struct ui_file *file,
struct frame_info *this_frame,
const char *reason)
{
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame (this_frame=");
if (this_frame != NULL)
fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
else
fprintf_unfiltered (gdb_stdlog, "<NULL>");
fprintf_unfiltered (gdb_stdlog, ") -> // %s}\n", reason);
}
}
int
inside_main_func (struct frame_info *this_frame)
{
struct minimal_symbol *msymbol;
CORE_ADDR maddr;
msymbol = lookup_minimal_symbol (main_name (), NULL, NULL);
if (msymbol == NULL)
return 0;
maddr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
SYMBOL_VALUE_ADDRESS (msymbol),
¤t_target);
return maddr == get_frame_func (this_frame);
}
static int
inside_entry_func (struct frame_info *this_frame)
{
return (get_frame_func (this_frame) == entry_point_address ());
}
struct frame_info *
get_prev_frame (struct frame_info *this_frame)
{
struct frame_info *prev_frame;
if (this_frame == NULL)
{
frame_debug_got_null_frame (gdb_stdlog, this_frame, "this_frame NULL");
return current_frame;
}
gdb_assert (this_frame != NULL);
if (this_frame->level >= 0
&& get_frame_type (this_frame) != DUMMY_FRAME
&& !backtrace_past_main
&& inside_main_func (this_frame))
{
frame_debug_got_null_frame (gdb_stdlog, this_frame, "inside main func");
return NULL;
}
if (this_frame->level + 2 > backtrace_limit)
{
frame_debug_got_null_frame (gdb_stdlog, this_frame,
"backtrace limit exceeded");
return NULL;
}
if (!backtrace_past_entry
&& get_frame_type (this_frame) != DUMMY_FRAME && this_frame->level >= 0
&& inside_entry_func (this_frame))
{
frame_debug_got_null_frame (gdb_stdlog, this_frame, "inside entry func");
return NULL;
}
if (this_frame->level > 0
&& get_frame_type (this_frame) == NORMAL_FRAME
&& get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME
&& get_frame_pc (this_frame) == 0)
{
frame_debug_got_null_frame (gdb_stdlog, this_frame, "zero PC");
return NULL;
}
return get_prev_frame_1 (this_frame);
}
CORE_ADDR
get_frame_pc (struct frame_info *frame)
{
gdb_assert (frame->next != NULL);
return frame_pc_unwind (frame->next);
}
CORE_ADDR
frame_unwind_address_in_block (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
if (pc == 0)
return 0;
if (next_frame->level >= 0
&& get_frame_type (next_frame) == NORMAL_FRAME)
--pc;
return pc;
}
CORE_ADDR
get_frame_address_in_block (struct frame_info *this_frame)
{
return frame_unwind_address_in_block (this_frame->next);
}
static int
pc_notcurrent (struct frame_info *frame)
{
struct frame_info *next = get_next_frame (frame);
int notcurrent = (next != NULL && get_frame_type (next) == NORMAL_FRAME);
return notcurrent;
}
void
find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
{
(*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame));
}
CORE_ADDR
get_frame_base (struct frame_info *fi)
{
return get_frame_id (fi).stack_addr;
}
CORE_ADDR
get_frame_base_address (struct frame_info *fi)
{
if (get_frame_type (fi) != NORMAL_FRAME)
return 0;
if (fi->base == NULL)
fi->base = frame_base_find_by_frame (fi->next);
if (fi->base->unwind == fi->unwind)
return fi->base->this_base (fi->next, &fi->prologue_cache);
return fi->base->this_base (fi->next, &fi->base_cache);
}
CORE_ADDR
get_frame_locals_address (struct frame_info *fi)
{
void **cache;
if (get_frame_type (fi) != NORMAL_FRAME)
return 0;
if (fi->base == NULL)
fi->base = frame_base_find_by_frame (fi->next);
if (fi->base->unwind == fi->unwind)
cache = &fi->prologue_cache;
else
cache = &fi->base_cache;
return fi->base->this_locals (fi->next, cache);
}
CORE_ADDR
get_frame_args_address (struct frame_info *fi)
{
void **cache;
if (get_frame_type (fi) != NORMAL_FRAME)
return 0;
if (fi->base == NULL)
fi->base = frame_base_find_by_frame (fi->next);
if (fi->base->unwind == fi->unwind)
cache = &fi->prologue_cache;
else
cache = &fi->base_cache;
return fi->base->this_args (fi->next, cache);
}
int
frame_relative_level (struct frame_info *fi)
{
if (fi == NULL)
return -1;
else
return fi->level;
}
enum frame_type
get_frame_type (struct frame_info *frame)
{
if (frame->unwind == NULL)
frame->unwind = frame_unwind_find_by_frame (frame->next,
&frame->prologue_cache);
return frame->unwind->type;
}
CORE_ADDR
refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc, int max_skip_non_prologue_insns)
{
struct symtab_and_line prologue_sal;
prologue_sal = find_pc_line (pc, 0);
if (prologue_sal.line != 0)
{
int i;
CORE_ADDR addr = prologue_sal.end;
int prev_line = prologue_sal.line;
for (i = 2 * max_skip_non_prologue_insns;
i > 0 && (lim_pc == 0 || addr < lim_pc);
i--)
{
struct symtab_and_line sal;
sal = find_pc_line (addr, 0);
if (sal.line == 0)
break;
if (sal.line <= prologue_sal.line
&& prev_line != sal.line
&& sal.symtab == prologue_sal.symtab)
{
prologue_sal = sal;
}
prev_line = sal.line;
addr = sal.end;
}
if (lim_pc == 0 || prologue_sal.end < lim_pc)
lim_pc = prologue_sal.end;
}
return lim_pc;
}
void
deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
{
if (frame_debug)
fprintf_unfiltered (gdb_stdlog,
"{ deprecated_update_frame_pc_hack (frame=%d,pc=0x%s) }\n",
frame->level, paddr_nz (pc));
if (frame->next != NULL)
{
frame->next->prev_pc.value = pc;
frame->next->prev_pc.p = 1;
}
}
void
deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base)
{
if (frame_debug)
fprintf_unfiltered (gdb_stdlog,
"{ deprecated_update_frame_base_hack (frame=%d,base=0x%s) }\n",
frame->level, paddr_nz (base));
frame->this_id.value.stack_addr = base;
}
void
get_frame_memory (struct frame_info *this_frame, CORE_ADDR addr,
gdb_byte *buf, int len)
{
read_memory (addr, buf, len);
}
LONGEST
get_frame_memory_signed (struct frame_info *this_frame, CORE_ADDR addr,
int len)
{
return read_memory_integer (addr, len);
}
ULONGEST
get_frame_memory_unsigned (struct frame_info *this_frame, CORE_ADDR addr,
int len)
{
return read_memory_unsigned_integer (addr, len);
}
int
safe_frame_unwind_memory (struct frame_info *this_frame,
CORE_ADDR addr, gdb_byte *buf, int len)
{
return !deprecated_read_memory_nobpt (addr, buf, len);
}
struct gdbarch *
get_frame_arch (struct frame_info *this_frame)
{
return current_gdbarch;
}
CORE_ADDR
get_frame_sp (struct frame_info *this_frame)
{
return frame_sp_unwind (this_frame->next);
}
CORE_ADDR
frame_sp_unwind (struct frame_info *next_frame)
{
if (gdbarch_unwind_sp_p (current_gdbarch))
return gdbarch_unwind_sp (current_gdbarch, next_frame);
if (next_frame->level < 0 && TARGET_READ_SP_P ())
return TARGET_READ_SP ();
if (SP_REGNUM >= 0)
{
ULONGEST sp;
frame_unwind_unsigned_register (next_frame, SP_REGNUM, &sp);
return sp;
}
internal_error (__FILE__, __LINE__, _("Missing unwind SP method"));
}
extern initialize_file_ftype _initialize_frame;
static struct cmd_list_element *set_backtrace_cmdlist;
static struct cmd_list_element *show_backtrace_cmdlist;
static void
set_backtrace_cmd (char *args, int from_tty)
{
help_list (set_backtrace_cmdlist, "set backtrace ", -1, gdb_stdout);
}
static void
show_backtrace_cmd (char *args, int from_tty)
{
cmd_show_list (show_backtrace_cmdlist, from_tty, "");
}
void
_initialize_frame (void)
{
obstack_init (&frame_cache_obstack);
observer_attach_target_changed (frame_observer_target_changed);
add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\
Set backtrace specific variables.\n\
Configure backtrace variables such as the backtrace limit"),
&set_backtrace_cmdlist, "set backtrace ",
0, &setlist);
add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, _("\
Show backtrace specific variables\n\
Show backtrace variables such as the backtrace limit"),
&show_backtrace_cmdlist, "show backtrace ",
0, &showlist);
add_setshow_boolean_cmd ("past-main", class_obscure,
&backtrace_past_main, _("\
Set whether backtraces should continue past \"main\"."), _("\
Show whether backtraces should continue past \"main\"."), _("\
Normally the caller of \"main\" is not of interest, so GDB will terminate\n\
the backtrace at \"main\". Set this variable if you need to see the rest\n\
of the stack trace."),
NULL,
show_backtrace_past_main,
&set_backtrace_cmdlist,
&show_backtrace_cmdlist);
add_setshow_boolean_cmd ("past-entry", class_obscure,
&backtrace_past_entry, _("\
Set whether backtraces should continue past the entry point of a program."),
_("\
Show whether backtraces should continue past the entry point of a program."),
_("\
Normally there are no callers beyond the entry point of a program, so GDB\n\
will terminate the backtrace there. Set this variable if you need to see \n\
the rest of the stack trace."),
NULL,
show_backtrace_past_entry,
&set_backtrace_cmdlist,
&show_backtrace_cmdlist);
add_setshow_integer_cmd ("limit", class_obscure,
&backtrace_limit, _("\
Set an upper bound on the number of backtrace levels."), _("\
Show the upper bound on the number of backtrace levels."), _("\
No more than the specified number of frames can be displayed or examined.\n\
Zero is unlimited."),
NULL,
show_backtrace_limit,
&set_backtrace_cmdlist,
&show_backtrace_cmdlist);
add_setshow_zinteger_cmd ("frame", class_maintenance, &frame_debug, _("\
Set frame debugging."), _("\
Show frame debugging."), _("\
When non-zero, frame specific internal debugging is enabled."),
NULL,
show_frame_debug,
&setdebuglist, &showdebuglist);
}