From ee967b5f616f692f59f48cac5ffcb7b0ecd79d70 Mon Sep 17 00:00:00 2001 From: Maxim Grigoriev Date: Wed, 23 Apr 2008 21:17:05 +0000 Subject: [PATCH] 2008-04-23 Maxim Grigoriev * Makefile.in (xtensa-tdep.o): Update dependencies. * configure.tgt (xtensa*): Update dependencies. * xtensa-tdep.c (arreg_number): Renamed from areg_number. Local variable areg renamed to arreg. (areg_number): New function. (xtensa_pseudo_register_read, xtensa_pseudo_register_write) (xtensa_extract_return_value, xtensa_store_return_value): areg_number replaced by arreg_number. (xtensa_windowed_frame_cache, struct xtensa_frame_cache): New comments. (xtensa_alloc_frame_cache): Initialize cache->wd.ws. (xtensa_scan_prologue): New function. (xtensa_frame_cache): New local fp_regnum. Handle separately the case, when ENTRY instraction hasn't been executed yet. Get the frame pointer value based on prologue analysis. Fix the bugs preventing WS and AR4-AR7/A11 registers from getting right values for intermediate frames, whose registers have been already spilled. (xtensa_frame_prev_register): Fix WS register value. Use are_number and arreg_number appropriately. (xtensa_gdbarch_init): Set solib_svr4_fetch_link_map_offsets to svr4_ilp32_fetch_link_map_offsets. --- gdb/ChangeLog | 23 +++++ gdb/Makefile.in | 2 +- gdb/configure.tgt | 2 +- gdb/xtensa-tdep.c | 247 +++++++++++++++++++++++++++++++++++++--------- 4 files changed, 226 insertions(+), 48 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ed16e4729f3..5d03f7f7b55 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,26 @@ +2008-04-23 Maxim Grigoriev + + * Makefile.in (xtensa-tdep.o): Update dependencies. + * configure.tgt (xtensa*): Update dependencies. + * xtensa-tdep.c (arreg_number): Renamed from areg_number. + Local variable areg renamed to arreg. + (areg_number): New function. + (xtensa_pseudo_register_read, xtensa_pseudo_register_write) + (xtensa_extract_return_value, xtensa_store_return_value): areg_number + replaced by arreg_number. + (xtensa_windowed_frame_cache, struct xtensa_frame_cache): New comments. + (xtensa_alloc_frame_cache): Initialize cache->wd.ws. + (xtensa_scan_prologue): New function. + (xtensa_frame_cache): New local fp_regnum. Handle separately the case, + when ENTRY instraction hasn't been executed yet. Get the frame pointer + value based on prologue analysis. Fix the bugs preventing WS and + AR4-AR7/A11 registers from getting right values for intermediate frames, + whose registers have been already spilled. + (xtensa_frame_prev_register): Fix WS register value. Use are_number + and arreg_number appropriately. + (xtensa_gdbarch_init): Set solib_svr4_fetch_link_map_offsets to + svr4_ilp32_fetch_link_map_offsets. + 2008-04-23 Andrew Stubbs * printcmd.c: Define USE_PRINTF_I64 and PRINTF_HAS_LONG_LONG on MinGW. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 86c4423601b..ba5f6aca907 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -3016,7 +3016,7 @@ xtensa-tdep.o: xtensa-tdep.c $(defs_h) $(doublest_h) $(frame_h) \ $(value_h) $(gdbcmd_h) $(gdbcore_h) $(dis_asm_h) $(symfile_h) \ $(objfiles_h) $(gdb_string_h) $(linespec_h) $(regcache_h) \ $(reggroups_h) $(arch_utils_h) $(osabi_h) $(block_h) $(gdb_assert_h) \ - $(elf_bfd_h) $(xtensa_tdep_h) $(dwarf2_frame_h) + $(elf_bfd_h) $(xtensa_tdep_h) $(dwarf2_frame_h) $(solib_svr4_h) xtensa-config.o: $(defs_h) $(xtensa_tdep_h) # diff --git a/gdb/configure.tgt b/gdb/configure.tgt index b4e91f4a437..36ac71e4118 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -523,7 +523,7 @@ xtensa*-*-linux*) gdb_target=linux ;; xtensa*) # Target: Tensilica Xtensa processors - gdb_target_obs="xtensa-tdep.o xtensa-config.o" + gdb_target_obs="xtensa-tdep.o xtensa-config.o solib.o solib-svr4.o" ;; esac diff --git a/gdb/xtensa-tdep.c b/gdb/xtensa-tdep.c index 0ed254f7c54..200ad2665a3 100644 --- a/gdb/xtensa-tdep.c +++ b/gdb/xtensa-tdep.c @@ -19,6 +19,7 @@ #include "defs.h" #include "frame.h" +#include "solib-svr4.h" #include "symtab.h" #include "symfile.h" #include "objfiles.h" @@ -114,18 +115,33 @@ static int xtensa_debug_level = 0; #define PS_WOE (1<<18) #define PS_EXC (1<<4) -/* Convert a live Ax register number to the corresponding Areg number. */ +/* Convert a live A-register number to the corresponding AR-register number. */ static int -areg_number (struct gdbarch *gdbarch, int regnum, ULONGEST wb) +arreg_number (struct gdbarch *gdbarch, int a_regnum, ULONGEST wb) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - int areg; + int arreg; - areg = regnum - tdep->a0_base; - areg += (wb & ((tdep->num_aregs - 1) >> 2)) << WB_SHIFT; - areg &= tdep->num_aregs - 1; + arreg = a_regnum - tdep->a0_base; + arreg += (wb & ((tdep->num_aregs - 1) >> 2)) << WB_SHIFT; + arreg &= tdep->num_aregs - 1; - return areg + tdep->ar_base; + return arreg + tdep->ar_base; +} + +/* Convert a live AR-register number to the corresponding A-register order + number in a range [0..15]. Return -1, if AR_REGNUM is out of WB window. */ +static int +areg_number (struct gdbarch *gdbarch, int ar_regnum, unsigned int wb) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int areg; + + areg = ar_regnum - tdep->ar_base; + if (areg < 0 || areg >= tdep->num_aregs) + return -1; + areg = (areg - wb * 4) & (tdep->num_aregs - 1); + return (areg > 15) ? -1 : areg; } static inline int @@ -516,7 +532,8 @@ xtensa_pseudo_register_read (struct gdbarch *gdbarch, gdb_byte *buf = (gdb_byte *) alloca (MAX_REGISTER_SIZE); regcache_raw_read (regcache, gdbarch_tdep (gdbarch)->wb_regnum, buf); - regnum = areg_number (gdbarch, regnum, extract_unsigned_integer (buf, 4)); + regnum = arreg_number (gdbarch, regnum, + extract_unsigned_integer (buf, 4)); } /* We can always read non-pseudo registers. */ @@ -613,7 +630,8 @@ xtensa_pseudo_register_write (struct gdbarch *gdbarch, regcache_raw_read (regcache, gdbarch_tdep (gdbarch)->wb_regnum, buf); - regnum = areg_number (gdbarch, regnum, extract_unsigned_integer (buf, 4)); + regnum = arreg_number (gdbarch, regnum, + extract_unsigned_integer (buf, 4)); } /* We can always write 'core' registers. @@ -880,9 +898,15 @@ xtensa_regset_from_core_section (struct gdbarch *core_arch, /* Frame cache part for Windowed ABI. */ typedef struct xtensa_windowed_frame_cache { - int wb; /* Base for this frame; -1 if not in regfile. */ - int callsize; /* Call size to next frame. */ - int ws; + int wb; /* WINDOWBASE of the previous frame. */ + int callsize; /* Call size of this frame. */ + int ws; /* WINDOWSTART of the previous frame. It keeps track of + life windows only. If there is no bit set for the + window, that means it had been already spilled + because of window overflow. */ + + /* Spilled A-registers from the previous frame. + AREGS[i] == -1, if corresponding AR is alive. */ CORE_ADDR aregs[XTENSA_NUM_SAVED_AREGS]; } xtensa_windowed_frame_cache_t; @@ -932,11 +956,11 @@ typedef struct xtensa_call0_frame_cache typedef struct xtensa_frame_cache { - CORE_ADDR base; /* Stack pointer of the next frame. */ + CORE_ADDR base; /* Stack pointer of this frame. */ CORE_ADDR pc; /* PC at the entry point to the function. */ - CORE_ADDR ra; /* The raw return address. */ - CORE_ADDR ps; /* The PS register of the frame. */ - CORE_ADDR prev_sp; /* Stack Pointer of the frame. */ + CORE_ADDR ra; /* The raw return address (without CALLINC). */ + CORE_ADDR ps; /* The PS register of the previous frame. */ + CORE_ADDR prev_sp; /* Stack Pointer of the previous frame. */ int call0; /* It's a call0 framework (else windowed). */ union { @@ -979,6 +1003,7 @@ xtensa_alloc_frame_cache (int windowed) else { cache->wd.wb = 0; + cache->wd.ws = 0; cache->wd.callsize = -1; for (i = 0; i < XTENSA_NUM_SAVED_AREGS; i++) @@ -1028,9 +1053,126 @@ xtensa_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) return frame_id_build (fp + SP_ALIGNMENT, pc); } +/* Returns the best guess about which register is a frame pointer + for the function containing CURRENT_PC. */ + +#define XTENSA_ISA_BSZ 32 /* Instruction buffer size. */ + +static unsigned int +xtensa_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR current_pc) +{ +#define RETURN_FP goto done + + unsigned int fp_regnum = gdbarch_tdep (gdbarch)->a0_base + 1; + CORE_ADDR start_addr; + xtensa_isa isa; + xtensa_insnbuf ins, slot; + char ibuf[XTENSA_ISA_BSZ]; + CORE_ADDR ia, bt, ba; + xtensa_format ifmt; + int ilen, islots, is; + xtensa_opcode opc; + const char *opcname; + + find_pc_partial_function (current_pc, NULL, &start_addr, NULL); + if (start_addr == 0) + return fp_regnum; + + if (!xtensa_default_isa) + xtensa_default_isa = xtensa_isa_init (0, 0); + isa = xtensa_default_isa; + gdb_assert (XTENSA_ISA_BSZ >= xtensa_isa_maxlength (isa)); + ins = xtensa_insnbuf_alloc (isa); + slot = xtensa_insnbuf_alloc (isa); + ba = 0; + + for (ia = start_addr, bt = ia; ia < current_pc ; ia += ilen) + { + if (ia + xtensa_isa_maxlength (isa) > bt) + { + ba = ia; + bt = (ba + XTENSA_ISA_BSZ) < current_pc + ? ba + XTENSA_ISA_BSZ : current_pc; + read_memory (ba, ibuf, bt - ba); + } + + xtensa_insnbuf_from_chars (isa, ins, &ibuf[ia-ba], 0); + ifmt = xtensa_format_decode (isa, ins); + if (ifmt == XTENSA_UNDEFINED) + RETURN_FP; + ilen = xtensa_format_length (isa, ifmt); + if (ilen == XTENSA_UNDEFINED) + RETURN_FP; + islots = xtensa_format_num_slots (isa, ifmt); + if (islots == XTENSA_UNDEFINED) + RETURN_FP; + + for (is = 0; is < islots; ++is) + { + if (xtensa_format_get_slot (isa, ifmt, is, ins, slot)) + RETURN_FP; + + opc = xtensa_opcode_decode (isa, ifmt, is, slot); + if (opc == XTENSA_UNDEFINED) + RETURN_FP; + + opcname = xtensa_opcode_name (isa, opc); + + if (strcasecmp (opcname, "mov.n") == 0 + || strcasecmp (opcname, "or") == 0) + { + unsigned int register_operand; + + /* Possible candidate for setting frame pointer + from A1. This is what we are looking for. */ + + if (xtensa_operand_get_field (isa, opc, 1, ifmt, + is, slot, ®ister_operand) != 0) + RETURN_FP; + if (xtensa_operand_decode (isa, opc, 1, ®ister_operand) != 0) + RETURN_FP; + if (register_operand == 1) /* Mov{.n} FP A1. */ + { + if (xtensa_operand_get_field (isa, opc, 0, ifmt, is, slot, + ®ister_operand) != 0) + RETURN_FP; + if (xtensa_operand_decode (isa, opc, 0, + ®ister_operand) != 0) + RETURN_FP; + + fp_regnum = gdbarch_tdep (gdbarch)->a0_base + register_operand; + RETURN_FP; + } + } + + if ( + /* We have problems decoding the memory. */ + opcname == NULL + || strcasecmp (opcname, "ill") == 0 + || strcasecmp (opcname, "ill.n") == 0 + /* Hit planted breakpoint. */ + || strcasecmp (opcname, "break") == 0 + || strcasecmp (opcname, "break.n") == 0 + /* Flow control instructions finish prologue. */ + || xtensa_opcode_is_branch (isa, opc) > 0 + || xtensa_opcode_is_jump (isa, opc) > 0 + || xtensa_opcode_is_loop (isa, opc) > 0 + || xtensa_opcode_is_call (isa, opc) > 0 + || strcasecmp (opcname, "simcall") == 0 + || strcasecmp (opcname, "syscall") == 0) + /* Can not continue analysis. */ + RETURN_FP; + } + } +done: + xtensa_insnbuf_free(isa, slot); + xtensa_insnbuf_free(isa, ins); + return fp_regnum; +} + /* The key values to identify the frame using "cache" are - cache->base = SP of this frame; + cache->base = SP (or best guess about FP) of this frame; cache->pc = entry-PC (entry point of the frame function); cache->prev_sp = SP of the previous frame. */ @@ -1047,6 +1189,7 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache) CORE_ADDR ra, wb, ws, pc, sp, ps; struct gdbarch *gdbarch = get_frame_arch (next_frame); unsigned int ps_regnum = gdbarch_ps_regnum (gdbarch); + unsigned int fp_regnum; char op1; int windowed; @@ -1090,21 +1233,35 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache) cache->wd.ws = ws; cache->prev_sp = frame_unwind_register_unsigned (next_frame, gdbarch_tdep (gdbarch)->a0_base + 1); + + /* This only can be the outermost frame since we are + just about to execute ENTRY. SP hasn't been set yet. + We can assume any frame size, because it does not + matter, and, let's fake frame base in cache. */ + cache->base = cache->prev_sp + 16; + + cache->pc = pc; + cache->ra = (cache->pc & 0xc0000000) | (ra & 0x3fffffff); + cache->ps = (ps & ~PS_CALLINC_MASK) + | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT); + + return cache; } else { + fp_regnum = xtensa_scan_prologue (gdbarch, pc); ra = frame_unwind_register_unsigned (next_frame, gdbarch_tdep (gdbarch)->a0_base); cache->wd.callsize = WINSIZE (ra); cache->wd.wb = (wb - cache->wd.callsize / 4) & (gdbarch_tdep (gdbarch)->num_aregs / 4 - 1); cache->wd.ws = ws & ~(1 << wb); - } - cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME); - cache->ra = (cache->pc & 0xc0000000) | (ra & 0x3fffffff); - cache->ps = (ps & ~PS_CALLINC_MASK) - | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT); + cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME); + cache->ra = (cache->pc & 0xc0000000) | (ra & 0x3fffffff); + cache->ps = (ps & ~PS_CALLINC_MASK) + | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT); + } if (cache->wd.ws == 0) { @@ -1122,12 +1279,13 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache) if (cache->wd.callsize > 4) { /* Set A4...A7/A11. */ - /* Read an SP of the previous frame. */ + /* Get the SP of the frame previous to the previous one. + To achieve this, we have to dereference SP twice. */ sp = (CORE_ADDR) read_memory_integer (sp - 12, 4); sp = (CORE_ADDR) read_memory_integer (sp - 12, 4); sp -= cache->wd.callsize * 4; - for ( /* i=4 */ ; i < cache->wd.callsize; i++, sp += 4) + for ( i = 4; i < cache->wd.callsize; i++, sp += 4) { cache->wd.aregs[i] = sp; } @@ -1138,19 +1296,18 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache) /* If RA is equal to 0 this frame is an outermost frame. Leave cache->prev_sp unchanged marking the boundary of the frame stack. */ { - if (cache->wd.ws == 0) + if ((cache->wd.ws & (1 << cache->wd.wb)) == 0) { /* Register window overflow already happened. We can read caller's SP from the proper spill loction. */ - cache->prev_sp = - read_memory_integer (cache->wd.aregs[1], - register_size (gdbarch, - gdbarch_tdep (gdbarch)->a0_base + 1)); + sp = frame_unwind_register_unsigned (next_frame, + gdbarch_tdep (gdbarch)->a0_base + 1); + cache->prev_sp = read_memory_integer (sp - 12, 4); } else { /* Read caller's frame SP directly from the previous window. */ - int regnum = areg_number + int regnum = arreg_number (gdbarch, gdbarch_tdep (gdbarch)->a0_base + 1, cache->wd.wb); @@ -1161,10 +1318,10 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache) else /* Call0 framework. */ { call0_frame_cache (next_frame, cache, pc); + fp_regnum = cache->c0.fp_regnum; } - cache->base = frame_unwind_register_unsigned - (next_frame, gdbarch_tdep (gdbarch)->a0_base + 1); + cache->base = frame_unwind_register_unsigned (next_frame, fp_regnum); return cache; } @@ -1272,12 +1429,7 @@ xtensa_frame_prev_register (struct frame_info *next_frame, else if (!cache->call0) { if (regnum == gdbarch_tdep (gdbarch)->ws_regnum) - { - if (cache->wd.ws != 0) - saved_reg = cache->wd.ws; - else - saved_reg = 1 << cache->wd.wb; - } + saved_reg = cache->wd.ws; else if (regnum == gdbarch_tdep (gdbarch)->wb_regnum) saved_reg = cache->wd.wb; else if (regnum == gdbarch_ps_regnum (gdbarch)) @@ -1302,18 +1454,18 @@ xtensa_frame_prev_register (struct frame_info *next_frame, if (!cache->call0) /* Windowed ABI. */ { - /* Convert A-register numbers to AR-register numbers. */ + /* Convert A-register numbers to AR-register numbers, + if we deal with A-register. */ if (regnum >= gdbarch_tdep (gdbarch)->a0_base && regnum <= gdbarch_tdep (gdbarch)->a0_base + 15) - regnum = areg_number (gdbarch, regnum, cache->wd.wb); + regnum = arreg_number (gdbarch, regnum, cache->wd.wb); - /* Check if AR-register has been saved to stack. */ + /* Check, if we deal with AR-register saved on stack. */ if (regnum >= gdbarch_tdep (gdbarch)->ar_base && regnum <= (gdbarch_tdep (gdbarch)->ar_base + gdbarch_tdep (gdbarch)->num_aregs)) { - int areg = regnum - gdbarch_tdep (gdbarch)->ar_base - - (cache->wd.wb * 4); + int areg = areg_number (gdbarch, regnum, cache->wd.wb); if (areg >= 0 && areg < XTENSA_NUM_SAVED_AREGS @@ -1443,7 +1595,7 @@ xtensa_extract_return_value (struct type *type, register (A2) in the caller window. */ regcache_raw_read_unsigned (regcache, gdbarch_tdep (gdbarch)->wb_regnum, &wb); - areg = areg_number (gdbarch, + areg = arreg_number (gdbarch, gdbarch_tdep (gdbarch)->a0_base + 2 + callsize, wb); } else @@ -1493,8 +1645,8 @@ xtensa_store_return_value (struct type *type, internal_error (__FILE__, __LINE__, _("unimplemented for this length: %d"), TYPE_LENGTH (type)); - areg = areg_number (gdbarch, - gdbarch_tdep (gdbarch)->a0_base + 2 + callsize, wb); + areg = arreg_number (gdbarch, + gdbarch_tdep (gdbarch)->a0_base + 2 + callsize, wb); DEBUGTRACE ("[xtensa_store_return_value] callsize %d wb %d\n", callsize, (int) wb); @@ -2666,6 +2818,9 @@ xtensa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_regset_from_core_section (gdbarch, xtensa_regset_from_core_section); + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_ilp32_fetch_link_map_offsets); + return gdbarch; } -- 2.30.2