X-Git-Url: http://drtracing.org/?a=blobdiff_plain;ds=sidebyside;f=gdb%2Ftrad-frame.c;h=a6a84790a99208f2d20939c25b186267e07307a8;hb=746ebfe8dd7aa7d9ec8e9651871f6e11fbf14537;hp=b0129da906d2c596bea5c143d4629ed5c073c902;hpb=8acc9f485bba28b65935dcc3498d9f3b712ddac7;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/trad-frame.c b/gdb/trad-frame.c index b0129da906..a6a84790a9 100644 --- a/gdb/trad-frame.c +++ b/gdb/trad-frame.c @@ -1,6 +1,6 @@ /* Traditional frame unwind support, for GDB the GNU Debugger. - Copyright (C) 2003-2013 Free Software Foundation, Inc. + Copyright (C) 2003-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -22,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 { @@ -43,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 @@ -51,18 +78,9 @@ 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 { TF_REG_VALUE = -1, TF_REG_UNKNOWN = -2 }; @@ -98,6 +116,26 @@ trad_frame_set_value (struct trad_frame_saved_reg this_saved_regs[], 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) @@ -111,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