aboutsummaryrefslogtreecommitdiff
path: root/gdb/ft32-tdep.c
diff options
context:
space:
mode:
authorjamesbowman <jamesb@excamera.com>2015-10-02 17:32:47 -0700
committerjamesbowman <jamesb@excamera.com>2015-10-02 17:32:47 -0700
commitae4e25019d53d38b2ad50475c80fa99ecab94c5c (patch)
treedb590291fcd1df1983d071aa01988bd8844e24af /gdb/ft32-tdep.c
parent604763ceaa318df58f706c92eb563a7ba98ebe6e (diff)
[FT32] gdb: Correctly interpret function prologs
The stack unwinder did not understand the function prologs generated by gcc with -Os. Add code to recognize and interpret the prolog calls. [gdb] 2015-10-02 James Bowman <james.bowman@ftdichip.com> * ft32-tdep.c (ft32_analyze_prologue): Add function prolog subroutine handling.
Diffstat (limited to 'gdb/ft32-tdep.c')
-rw-r--r--gdb/ft32-tdep.c55
1 files changed, 49 insertions, 6 deletions
diff --git a/gdb/ft32-tdep.c b/gdb/ft32-tdep.c
index 00cf847f76..e9da23ec9d 100644
--- a/gdb/ft32-tdep.c
+++ b/gdb/ft32-tdep.c
@@ -164,33 +164,76 @@ ft32_analyze_prologue (CORE_ADDR start_addr, CORE_ADDR end_addr,
CORE_ADDR next_addr;
ULONGEST inst, inst2;
LONGEST offset;
- int regnum;
+ int regnum, pushreg;
+ struct bound_minimal_symbol msymbol;
+ const int first_saved_reg = 13; /* The first saved register. */
+ /* PROLOGS are addresses of the subroutine prologs, PROLOGS[n]
+ is the address of __prolog_$rN.
+ __prolog_$rN pushes registers from 13 through n inclusive.
+ So for example CALL __prolog_$r15 is equivalent to:
+ PUSH $r13
+ PUSH $r14
+ PUSH $r15
+ Note that PROLOGS[0] through PROLOGS[12] are unused. */
+ CORE_ADDR prologs[32];
cache->saved_regs[FT32_PC_REGNUM] = 0;
cache->framesize = 0;
+ for (regnum = first_saved_reg; regnum < 32; regnum++)
+ {
+ char prolog_symbol[32];
+
+ snprintf (prolog_symbol, sizeof (prolog_symbol), "__prolog_$r%02d",
+ regnum);
+ msymbol = lookup_minimal_symbol (prolog_symbol, NULL, NULL);
+ if (msymbol.minsym)
+ prologs[regnum] = BMSYMBOL_VALUE_ADDRESS (msymbol);
+ else
+ prologs[regnum] = 0;
+ }
+
if (start_addr >= end_addr)
- return end_addr;
+ return end_addr;
cache->established = 0;
- for (next_addr = start_addr; next_addr < end_addr; )
+ for (next_addr = start_addr; next_addr < end_addr;)
{
inst = read_memory_unsigned_integer (next_addr, 4, byte_order);
if (FT32_IS_PUSH (inst))
{
- regnum = FT32_R0_REGNUM + FT32_PUSH_REG (inst);
+ pushreg = FT32_PUSH_REG (inst);
cache->framesize += 4;
- cache->saved_regs[regnum] = cache->framesize;
+ cache->saved_regs[FT32_R0_REGNUM + pushreg] = cache->framesize;
next_addr += 4;
}
+ else if (FT32_IS_CALL (inst))
+ {
+ for (regnum = first_saved_reg; regnum < 32; regnum++)
+ {
+ if ((4 * (inst & 0x3ffff)) == prologs[regnum])
+ {
+ for (pushreg = first_saved_reg; pushreg <= regnum;
+ pushreg++)
+ {
+ cache->framesize += 4;
+ cache->saved_regs[FT32_R0_REGNUM + pushreg] =
+ cache->framesize;
+ }
+ next_addr += 4;
+ }
+ }
+ break;
+ }
else
break;
}
for (regnum = FT32_R0_REGNUM; regnum < FT32_PC_REGNUM; regnum++)
{
if (cache->saved_regs[regnum] != REG_UNAVAIL)
- cache->saved_regs[regnum] = cache->framesize - cache->saved_regs[regnum];
+ cache->saved_regs[regnum] =
+ cache->framesize - cache->saved_regs[regnum];
}
cache->saved_regs[FT32_PC_REGNUM] = cache->framesize;