* m68hc11-tdep.c (struct m68hc11_unwind_cache): New struct to hold

frame unwind information.
	(m68hc11_scan_prologue): New function from m68hc11_guess_from_prologue
	and adapted for frame unwinding.
	(m68hc11_skip_prologue): Update to scan prologue in temporary object.
	(m68hc11_unwind_pc): New function.
	(m68hc11_frame_unwind_cache): New function to analyze frames.
	(m68hc11_frame_this_id): New function to create new frame struct.
	(m68hc11_frame_prev_register): New function to unwind a register from
	the frame.
	(m68hc11_frame_unwind): Default 68hc11/68hc12 unwinder.
	(m68hc11_frame_p): New function for the above.
	(m68hc11_frame_base_address): New function to return fp of frame.
	(m68hc11_frame_args_address): Update for frame.
	(m68hc11_frame_base): Default 68hc11/68hc12 frame.
	(m68hc11_unwind_sp): New function.
	(m68hc11_unwind_dummy_id): New function.
	(m68hc11_gdbarch_init): Install the above frames; remove deprecated
	calls.
This commit is contained in:
Stephane Carrez 2003-07-27 21:24:41 +00:00
parent 225f2bf663
commit 1ea653ae0a
2 changed files with 344 additions and 57 deletions

View File

@ -1,3 +1,25 @@
2003-07-27 Stephane Carrez <stcarrez@nerim.fr>
* m68hc11-tdep.c (struct m68hc11_unwind_cache): New struct to hold
frame unwind information.
(m68hc11_scan_prologue): New function from m68hc11_guess_from_prologue
and adapted for frame unwinding.
(m68hc11_skip_prologue): Update to scan prologue in temporary object.
(m68hc11_unwind_pc): New function.
(m68hc11_frame_unwind_cache): New function to analyze frames.
(m68hc11_frame_this_id): New function to create new frame struct.
(m68hc11_frame_prev_register): New function to unwind a register from
the frame.
(m68hc11_frame_unwind): Default 68hc11/68hc12 unwinder.
(m68hc11_frame_p): New function for the above.
(m68hc11_frame_base_address): New function to return fp of frame.
(m68hc11_frame_args_address): Update for frame.
(m68hc11_frame_base): Default 68hc11/68hc12 frame.
(m68hc11_unwind_sp): New function.
(m68hc11_unwind_dummy_id): New function.
(m68hc11_gdbarch_init): Install the above frames; remove deprecated
calls.
2003-07-27 Stephane Carrez <stcarrez@nerim.fr>
* m68hc11-tdep.c (m68hc11_analyze_instruction): Don't advance the pc.

View File

@ -21,6 +21,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "dwarf2-frame.h"
#include "trad-frame.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "gdbcmd.h"
@ -157,6 +161,25 @@ struct gdbarch_tdep
#define STACK_CORRECTION (M6811_TDEP->stack_correction)
#define USE_PAGE_REGISTER (M6811_TDEP->use_page_register)
struct m68hc11_unwind_cache
{
/* The previous frame's inner most stack address. Used as this
frame ID's stack_addr. */
CORE_ADDR prev_sp;
/* The frame's base, optionally used by the high-level debug info. */
CORE_ADDR base;
CORE_ADDR pc;
int size;
int prologue_type;
CORE_ADDR return_pc;
CORE_ADDR sp_offset;
int frameless;
enum insn_return_kind return_kind;
/* Table indicating the location of each and every register. */
struct trad_frame_saved_reg *saved_regs;
};
struct frame_extra_info
{
CORE_ADDR return_pc;
@ -412,20 +435,6 @@ m68hc11_frame_saved_pc (struct frame_info *frame)
return get_frame_extra_info (frame)->return_pc;
}
static CORE_ADDR
m68hc11_frame_args_address (struct frame_info *frame)
{
CORE_ADDR addr;
addr = get_frame_base (frame) + get_frame_extra_info (frame)->size + STACK_CORRECTION + 2;
if (get_frame_extra_info (frame)->return_kind == RETURN_RTC)
addr += 1;
else if (get_frame_extra_info (frame)->return_kind == RETURN_RTI)
addr += 7;
return addr;
}
/* Discard from the stack the innermost frame, restoring all saved
registers. */
@ -660,35 +669,35 @@ m68hc11_get_return_insn (CORE_ADDR pc)
return RETURN_RTS;
}
/* Analyze the function prologue to find some information
about the function:
- the PC of the first line (for m68hc11_skip_prologue)
- the offset of the previous frame saved address (from current frame)
- the soft registers which are pushed. */
static void
m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR current_pc, CORE_ADDR fp,
CORE_ADDR *first_line,
int *frame_offset, CORE_ADDR *pushed_regs)
static CORE_ADDR
m68hc11_scan_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
struct m68hc11_unwind_cache *info)
{
CORE_ADDR save_addr;
LONGEST save_addr;
CORE_ADDR func_end;
int size;
int found_frame_point;
int saved_reg;
CORE_ADDR first_pc;
int done = 0;
struct insn_sequence *seq_table;
first_pc = get_pc_function_start (pc);
info->size = 0;
info->sp_offset = 0;
if (pc >= current_pc)
return current_pc;
size = 0;
m68hc11_initialize_register_info ();
if (first_pc == 0)
if (pc == 0)
{
*frame_offset = 0;
*first_line = pc;
return;
info->size = 0;
return pc;
}
seq_table = gdbarch_tdep (current_gdbarch)->prologue;
@ -734,16 +743,15 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR current_pc, CORE_ADDR fp,
we find an instruction which is not supposed to appear in the
prologue (as generated by gcc 2.95, 2.96).
*/
pc = first_pc;
func_end = pc + 128;
found_frame_point = 0;
*frame_offset = 0;
save_addr = fp + STACK_CORRECTION;
info->size = 0;
save_addr = 0;
while (!done && pc + 2 < func_end)
{
struct insn_sequence *seq;
CORE_ADDR val;
seq = m68hc11_analyze_instruction (seq_table, pc, &val);
if (seq == 0)
break;
@ -764,8 +772,7 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR current_pc, CORE_ADDR fp,
break;
save_addr -= 2;
if (pushed_regs)
pushed_regs[saved_reg] = save_addr;
info->saved_regs[saved_reg].addr = save_addr;
}
else
{
@ -775,7 +782,7 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR current_pc, CORE_ADDR fp,
else if (seq->type == P_SET_FRAME)
{
found_frame_point = 1;
*frame_offset = size;
info->size = size;
}
else if (seq->type == P_LOCAL_1)
{
@ -794,7 +801,11 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR current_pc, CORE_ADDR fp,
size -= val;
}
}
*first_line = pc;
if (found_frame_point == 0)
info->sp_offset = size;
else
info->sp_offset = -1;
return pc;
}
static CORE_ADDR
@ -802,7 +813,7 @@ m68hc11_skip_prologue (CORE_ADDR pc)
{
CORE_ADDR func_addr, func_end;
struct symtab_and_line sal;
int frame_offset;
struct m68hc11_unwind_cache tmp_cache = { 0 };
/* If we have line debugging information, then the end of the
prologue should be the first assembly instruction of the
@ -814,7 +825,7 @@ m68hc11_skip_prologue (CORE_ADDR pc)
return sal.end;
}
m68hc11_guess_from_prologue (pc, pc, 0, &pc, &frame_offset, 0);
pc = m68hc11_scan_prologue (pc, (CORE_ADDR) -1, &tmp_cache);
return pc;
}
@ -846,7 +857,7 @@ m68hc11_frame_chain (struct frame_info *frame)
addr = read_memory_unsigned_integer (addr, 2) & 0x0FFFF;
return addr;
}
#if 0
/* Put here the code to store, into a struct frame_saved_regs, the
addresses of the saved registers of frame described by FRAME_INFO.
This includes special registers such as pc and fp saved in special
@ -928,6 +939,261 @@ m68hc11_init_extra_frame_info (int fromleaf, struct frame_info *fi)
get_frame_extra_info (fi)->return_pc = addr;
}
}
#endif
static CORE_ADDR
m68hc11_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST pc;
frame_unwind_unsigned_register (next_frame, gdbarch_pc_regnum (gdbarch),
&pc);
return pc;
}
/* Put here the code to store, into fi->saved_regs, the addresses of
the saved registers of frame described by FRAME_INFO. This
includes special registers such as pc and fp saved in special ways
in the stack frame. sp is even more special: the address we return
for it IS the sp for the next frame. */
struct m68hc11_unwind_cache *
m68hc11_frame_unwind_cache (struct frame_info *next_frame,
void **this_prologue_cache)
{
ULONGEST prev_sp;
ULONGEST this_base;
struct m68hc11_unwind_cache *info;
CORE_ADDR current_pc;
int i;
if ((*this_prologue_cache))
return (*this_prologue_cache);
info = FRAME_OBSTACK_ZALLOC (struct m68hc11_unwind_cache);
(*this_prologue_cache) = info;
info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
info->pc = frame_func_unwind (next_frame);
info->size = 0;
info->return_kind = m68hc11_get_return_insn (info->pc);
/* The SP was moved to the FP. This indicates that a new frame
was created. Get THIS frame's FP value by unwinding it from
the next frame. */
frame_unwind_unsigned_register (next_frame, SOFT_FP_REGNUM, &this_base);
if (this_base == 0)
{
info->base = 0;
return info;
}
current_pc = frame_pc_unwind (next_frame);
if (info->pc != 0)
m68hc11_scan_prologue (info->pc, current_pc, info);
info->saved_regs[HARD_PC_REGNUM].addr = info->size;
if (info->sp_offset != (CORE_ADDR) -1)
{
info->saved_regs[HARD_PC_REGNUM].addr = info->sp_offset;
frame_unwind_unsigned_register (next_frame, HARD_SP_REGNUM, &this_base);
prev_sp = this_base + info->sp_offset + 2;
this_base += STACK_CORRECTION;
}
else
{
/* The FP points at the last saved register. Adjust the FP back
to before the first saved register giving the SP. */
prev_sp = this_base + info->size + 2;
this_base += STACK_CORRECTION;
if (soft_regs[SOFT_FP_REGNUM].name)
info->saved_regs[SOFT_FP_REGNUM].addr = info->size - 2;
}
if (info->return_kind == RETURN_RTC)
{
prev_sp += 1;
info->saved_regs[HARD_PAGE_REGNUM].addr = info->size;
info->saved_regs[HARD_PC_REGNUM].addr = info->size + 1;
}
else if (info->return_kind == RETURN_RTI)
{
prev_sp += 7;
info->saved_regs[HARD_CCR_REGNUM].addr = info->size;
info->saved_regs[HARD_D_REGNUM].addr = info->size + 1;
info->saved_regs[HARD_X_REGNUM].addr = info->size + 3;
info->saved_regs[HARD_Y_REGNUM].addr = info->size + 5;
info->saved_regs[HARD_PC_REGNUM].addr = info->size + 7;
}
/* Add 1 here to adjust for the post-decrement nature of the push
instruction.*/
info->prev_sp = prev_sp;
info->base = this_base;
/* Adjust all the saved registers so that they contain addresses and not
offsets. */
for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS - 1; i++)
if (trad_frame_addr_p (info->saved_regs, i))
{
info->saved_regs[i].addr += this_base;
}
/* The previous frame's SP needed to be computed. Save the computed
value. */
trad_frame_set_value (info->saved_regs, HARD_SP_REGNUM, info->prev_sp);
return info;
}
/* Given a GDB frame, determine the address of the calling function's
frame. This will be used to create a new GDB frame struct. */
static void
m68hc11_frame_this_id (struct frame_info *next_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
struct m68hc11_unwind_cache *info
= m68hc11_frame_unwind_cache (next_frame, this_prologue_cache);
CORE_ADDR base;
CORE_ADDR func;
struct frame_id id;
/* The FUNC is easy. */
func = frame_func_unwind (next_frame);
/* This is meant to halt the backtrace at "_start". Make sure we
don't halt it at a generic dummy frame. */
if (inside_entry_file (func))
return;
/* Hopefully the prologue analysis either correctly determined the
frame's base (which is the SP from the previous frame), or set
that base to "NULL". */
base = info->prev_sp;
if (base == 0)
return;
id = frame_id_build (base, func);
#if 0
/* Check that we're not going round in circles with the same frame
ID (but avoid applying the test to sentinel frames which do go
round in circles). Can't use frame_id_eq() as that doesn't yet
compare the frame's PC value. */
if (frame_relative_level (next_frame) >= 0
&& get_frame_type (next_frame) != DUMMY_FRAME
&& frame_id_eq (get_frame_id (next_frame), id))
return;
#endif
(*this_id) = id;
}
static void
m68hc11_frame_prev_register (struct frame_info *next_frame,
void **this_prologue_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *bufferp)
{
struct m68hc11_unwind_cache *info
= m68hc11_frame_unwind_cache (next_frame, this_prologue_cache);
trad_frame_prev_register (next_frame, info->saved_regs, regnum,
optimizedp, lvalp, addrp, realnump, bufferp);
if (regnum == HARD_PC_REGNUM)
{
/* Take into account the 68HC12 specific call (PC + page). */
if (info->return_kind == RETURN_RTC
&& *addrp >= 0x08000 && *addrp < 0x0c000
&& USE_PAGE_REGISTER)
{
int page_optimized;
CORE_ADDR page;
trad_frame_prev_register (next_frame, info->saved_regs,
HARD_PAGE_REGNUM, &page_optimized,
0, &page, 0, 0);
*addrp -= 0x08000;
*addrp += ((page & 0x0ff) << 14);
*addrp += 0x1000000;
}
}
}
static const struct frame_unwind m68hc11_frame_unwind = {
NORMAL_FRAME,
m68hc11_frame_this_id,
m68hc11_frame_prev_register
};
const struct frame_unwind *
m68hc11_frame_p (CORE_ADDR pc)
{
return &m68hc11_frame_unwind;
}
static CORE_ADDR
m68hc11_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
struct m68hc11_unwind_cache *info
= m68hc11_frame_unwind_cache (next_frame, this_cache);
return info->base;
}
static CORE_ADDR
m68hc11_frame_args_address (struct frame_info *next_frame, void **this_cache)
{
CORE_ADDR addr;
struct m68hc11_unwind_cache *info
= m68hc11_frame_unwind_cache (next_frame, this_cache);
addr = info->base + info->size;
if (info->return_kind == RETURN_RTC)
addr += 1;
else if (info->return_kind == RETURN_RTI)
addr += 7;
return addr;
}
static const struct frame_base m68hc11_frame_base = {
&m68hc11_frame_unwind,
m68hc11_frame_base_address,
m68hc11_frame_base_address,
m68hc11_frame_args_address
};
static CORE_ADDR
m68hc11_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST sp;
frame_unwind_unsigned_register (next_frame, HARD_SP_REGNUM, &sp);
return sp;
}
/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
dummy frame. The frame ID's base needs to match the TOS value
saved by save_dummy_frame_tos(), and the PC match the dummy frame's
breakpoint. */
static struct frame_id
m68hc11_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST tos;
CORE_ADDR pc = frame_pc_unwind (next_frame);
frame_unwind_unsigned_register (next_frame, SOFT_FP_REGNUM, &tos);
tos += 2;
return frame_id_build (tos, pc);
}
/* Get and print the register from the given frame. */
@ -1410,10 +1676,6 @@ m68hc11_gdbarch_init (struct gdbarch_info info,
gdbarch = gdbarch_alloc (&info, tdep);
tdep->elf_flags = elf_flags;
/* NOTE: cagney/2002-12-06: This can be deleted when this arch is
ready to unwind the PC first (see frame.c:get_prev_frame()). */
set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default);
switch (info.bfd_arch_info->arch)
{
case bfd_arch_m68hc11:
@ -1461,16 +1723,16 @@ m68hc11_gdbarch_init (struct gdbarch_info info,
/* Characters are unsigned. */
set_gdbarch_char_signed (gdbarch, 0);
set_gdbarch_unwind_pc (gdbarch, m68hc11_unwind_pc);
set_gdbarch_unwind_sp (gdbarch, m68hc11_unwind_sp);
/* Set register info. */
set_gdbarch_fp0_regnum (gdbarch, -1);
set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, m68hc11_frame_init_saved_regs);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_write_pc (gdbarch, generic_target_write_pc);
set_gdbarch_deprecated_dummy_write_sp (gdbarch, deprecated_write_sp);
set_gdbarch_sp_regnum (gdbarch, HARD_SP_REGNUM);
set_gdbarch_deprecated_fp_regnum (gdbarch, SOFT_FP_REGNUM);
set_gdbarch_register_name (gdbarch, m68hc11_register_name);
set_gdbarch_register_type (gdbarch, m68hc11_register_type);
set_gdbarch_pseudo_register_read (gdbarch, m68hc11_pseudo_register_read);
@ -1478,27 +1740,15 @@ m68hc11_gdbarch_init (struct gdbarch_info info,
set_gdbarch_push_dummy_call (gdbarch, m68hc11_push_dummy_call);
set_gdbarch_deprecated_get_saved_register (gdbarch, deprecated_generic_get_saved_register);
set_gdbarch_extract_return_value (gdbarch, m68hc11_extract_return_value);
set_gdbarch_return_value_on_stack (gdbarch, m68hc11_return_value_on_stack);
set_gdbarch_deprecated_store_struct_return (gdbarch, m68hc11_store_struct_return);
set_gdbarch_store_return_value (gdbarch, m68hc11_store_return_value);
set_gdbarch_extract_struct_value_address (gdbarch, m68hc11_extract_struct_value_address);
set_gdbarch_deprecated_frame_chain (gdbarch, m68hc11_frame_chain);
set_gdbarch_deprecated_frame_saved_pc (gdbarch, m68hc11_frame_saved_pc);
set_gdbarch_deprecated_frame_args_address (gdbarch, m68hc11_frame_args_address);
set_gdbarch_deprecated_saved_pc_after_call (gdbarch, m68hc11_saved_pc_after_call);
set_gdbarch_deprecated_get_saved_register (gdbarch, deprecated_generic_get_saved_register);
set_gdbarch_deprecated_store_struct_return (gdbarch, m68hc11_store_struct_return);
set_gdbarch_store_return_value (gdbarch, m68hc11_store_return_value);
set_gdbarch_extract_struct_value_address (gdbarch, m68hc11_extract_struct_value_address);
set_gdbarch_use_struct_convention (gdbarch, m68hc11_use_struct_convention);
set_gdbarch_deprecated_init_extra_frame_info (gdbarch, m68hc11_init_extra_frame_info);
set_gdbarch_deprecated_pop_frame (gdbarch, m68hc11_pop_frame);
set_gdbarch_skip_prologue (gdbarch, m68hc11_skip_prologue);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_decr_pc_after_break (gdbarch, 0);
@ -1511,6 +1761,21 @@ m68hc11_gdbarch_init (struct gdbarch_info info,
set_gdbarch_register_reggroup_p (gdbarch, m68hc11_register_reggroup_p);
set_gdbarch_print_registers_info (gdbarch, m68hc11_print_registers_info);
/* Hook in the DWARF CFI frame unwinder. */
frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
set_gdbarch_dwarf2_build_frame_info (gdbarch, dwarf2_build_frame_info);
frame_unwind_append_predicate (gdbarch, m68hc11_frame_p);
frame_base_set_default (gdbarch, &m68hc11_frame_base);
/* Methods for saving / extracting a dummy frame's ID. The ID's
stack address must match the SP value returned by
PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos. */
set_gdbarch_unwind_dummy_id (gdbarch, m68hc11_unwind_dummy_id);
/* Return the unwound PC value. */
set_gdbarch_unwind_pc (gdbarch, m68hc11_unwind_pc);
/* Minsymbol frobbing. */
set_gdbarch_elf_make_msymbol_special (gdbarch,
m68hc11_elf_make_msymbol_special);