X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Ftrad-frame.c;h=a33fa89e3354c754dc44bbc7a9024eabd7f2d164;hb=09b0d8a75fa379eacf0d9d6b27320d025475b14d;hp=b38409e0911c94f47ddb93b374ca5fde2e627e3d;hpb=5d5021647dbce1a933576243b9d54281a88eb3b5;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/trad-frame.c b/gdb/trad-frame.c index b38409e091..a33fa89e33 100644 --- a/gdb/trad-frame.c +++ b/gdb/trad-frame.c @@ -1,7 +1,6 @@ /* Traditional frame unwind support, for GDB the GNU Debugger. - Copyright (C) 2003, 2004, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 2003-2019 Free Software Foundation, Inc. This file is part of GDB. @@ -23,7 +22,9 @@ #include "trad-frame.h" #include "regcache.h" #include "frame-unwind.h" +#include "target.h" #include "value.h" +#include "gdbarch.h" struct trad_frame_cache { @@ -44,6 +45,31 @@ trad_frame_cache_zalloc (struct frame_info *this_frame) return this_trad_cache; } +/* See trad-frame.h. */ + +void +trad_frame_reset_saved_regs (struct gdbarch *gdbarch, + struct trad_frame_saved_reg *regs) +{ + int numregs = gdbarch_num_cooked_regs (gdbarch); + for (int regnum = 0; regnum < numregs; regnum++) + { + regs[regnum].realreg = regnum; + regs[regnum].addr = -1; + } +} + +struct trad_frame_saved_reg * +trad_frame_alloc_saved_regs (struct gdbarch *gdbarch) +{ + int numregs = gdbarch_num_cooked_regs (gdbarch); + struct trad_frame_saved_reg *this_saved_regs + = FRAME_OBSTACK_CALLOC (numregs, struct trad_frame_saved_reg); + + trad_frame_reset_saved_regs (gdbarch, this_saved_regs); + return this_saved_regs; +} + /* A traditional frame is unwound by analysing the function prologue and using the information gathered to track registers. For non-optimized frames, the technique is reliable (just need to check @@ -52,26 +78,17 @@ trad_frame_cache_zalloc (struct frame_info *this_frame) struct trad_frame_saved_reg * trad_frame_alloc_saved_regs (struct frame_info *this_frame) { - int regnum; struct gdbarch *gdbarch = get_frame_arch (this_frame); - int numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); - struct trad_frame_saved_reg *this_saved_regs - = FRAME_OBSTACK_CALLOC (numregs, struct trad_frame_saved_reg); - for (regnum = 0; regnum < numregs; regnum++) - { - this_saved_regs[regnum].realreg = regnum; - this_saved_regs[regnum].addr = -1; - } - return this_saved_regs; + return trad_frame_alloc_saved_regs (gdbarch); } -enum { REG_VALUE = -1, REG_UNKNOWN = -2 }; +enum { TF_REG_VALUE = -1, TF_REG_UNKNOWN = -2 }; int trad_frame_value_p (struct trad_frame_saved_reg this_saved_regs[], int regnum) { - return (this_saved_regs[regnum].realreg == REG_VALUE); + return (this_saved_regs[regnum].realreg == TF_REG_VALUE); } int @@ -95,10 +112,30 @@ trad_frame_set_value (struct trad_frame_saved_reg this_saved_regs[], { /* Make the REALREG invalid, indicating that the ADDR contains the register's value. */ - this_saved_regs[regnum].realreg = REG_VALUE; + this_saved_regs[regnum].realreg = TF_REG_VALUE; this_saved_regs[regnum].addr = val; } +/* See trad-frame.h. */ + +void +trad_frame_set_realreg (struct trad_frame_saved_reg this_saved_regs[], + int regnum, int realreg) +{ + this_saved_regs[regnum].realreg = realreg; + this_saved_regs[regnum].addr = -1; +} + +/* See trad-frame.h. */ + +void +trad_frame_set_addr (struct trad_frame_saved_reg this_saved_regs[], + int regnum, CORE_ADDR addr) +{ + this_saved_regs[regnum].realreg = regnum; + this_saved_regs[regnum].addr = addr; +} + void trad_frame_set_reg_value (struct trad_frame_cache *this_trad_cache, int regnum, LONGEST val) @@ -112,15 +149,70 @@ void trad_frame_set_reg_realreg (struct trad_frame_cache *this_trad_cache, int regnum, int realreg) { - this_trad_cache->prev_regs[regnum].realreg = realreg; - this_trad_cache->prev_regs[regnum].addr = -1; + trad_frame_set_realreg (this_trad_cache->prev_regs, regnum, realreg); } void trad_frame_set_reg_addr (struct trad_frame_cache *this_trad_cache, int regnum, CORE_ADDR addr) { - this_trad_cache->prev_regs[regnum].addr = addr; + trad_frame_set_addr (this_trad_cache->prev_regs, regnum, addr); +} + +void +trad_frame_set_reg_regmap (struct trad_frame_cache *this_trad_cache, + const struct regcache_map_entry *regmap, + CORE_ADDR addr, size_t size) +{ + struct gdbarch *gdbarch = get_frame_arch (this_trad_cache->this_frame); + int offs = 0, count; + + for (; (count = regmap->count) != 0; regmap++) + { + int regno = regmap->regno; + int slot_size = regmap->size; + + if (slot_size == 0 && regno != REGCACHE_MAP_SKIP) + slot_size = register_size (gdbarch, regno); + + if (offs + slot_size > size) + break; + + if (regno == REGCACHE_MAP_SKIP) + offs += count * slot_size; + else + for (; count--; regno++, offs += slot_size) + { + /* Mimic the semantics of regcache::transfer_regset if a + register slot's size does not match the size of a + register. + + If a register slot is larger than a register, assume + the register's value is stored in the first N bytes of + the slot and ignore the remaining bytes. + + If the register slot is smaller than the register, + assume that the slot contains the low N bytes of the + register's value. Since trad_frame assumes that + registers stored by address are sized according to the + register, read the low N bytes and zero-extend them to + generate a register value. */ + if (slot_size >= register_size (gdbarch, regno)) + trad_frame_set_reg_addr (this_trad_cache, regno, addr + offs); + else + { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte buf[slot_size]; + + if (target_read_memory (addr + offs, buf, sizeof buf) == 0) + { + LONGEST val + = extract_unsigned_integer (buf, sizeof buf, byte_order); + trad_frame_set_reg_value (this_trad_cache, regno, val); + } + } + } + } } void @@ -128,7 +220,7 @@ trad_frame_set_unknown (struct trad_frame_saved_reg this_saved_regs[], int regnum) { /* Make the REALREG invalid, indicating that the value is not known. */ - this_saved_regs[regnum].realreg = REG_UNKNOWN; + this_saved_regs[regnum].realreg = TF_REG_UNKNOWN; this_saved_regs[regnum].addr = -1; }