diff options
Diffstat (limited to 'gdb/rs6000-tdep.c')
-rw-r--r-- | gdb/rs6000-tdep.c | 61 |
1 files changed, 56 insertions, 5 deletions
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index 3b4aeb9..3c0a7b9 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -1132,19 +1132,55 @@ rs6000_extract_return_value (struct type *valtype, char *regbuf, char *valbuf) static CORE_ADDR rs6000_struct_return_address; -/* Indirect function calls use a piece of trampoline code to do context - switching, i.e. to set the new TOC table. Skip such code if we are on - its first instruction (as when we have single-stepped to here). - Also skip shared library trampoline code (which is different from +/* Return whether handle_inferior_event() should proceed through code + starting at PC in function NAME when stepping. + + The AIX -bbigtoc linker option generates functions @FIX0, @FIX1, etc. to + handle memory references that are too distant to fit in instructions + generated by the compiler. For example, if 'foo' in the following + instruction: + + lwz r9,foo(r2) + + is greater than 32767, the linker might replace the lwz with a branch to + somewhere in @FIX1 that does the load in 2 instructions and then branches + back to where execution should continue. + + GDB should silently step over @FIX code, just like AIX dbx does. + Unfortunately, the linker uses the "b" instruction for the branches, + meaning that the link register doesn't get set. Therefore, GDB's usual + step_over_function() mechanism won't work. + + Instead, use the IN_SOLIB_RETURN_TRAMPOLINE and SKIP_TRAMPOLINE_CODE hooks + in handle_inferior_event() to skip past @FIX code. */ + +int +rs6000_in_solib_return_trampoline (CORE_ADDR pc, char *name) +{ + return name && !strncmp (name, "@FIX", 4); +} + +/* Skip code that the user doesn't want to see when stepping: + + 1. Indirect function calls use a piece of trampoline code to do context + switching, i.e. to set the new TOC table. Skip such code if we are on + its first instruction (as when we have single-stepped to here). + + 2. Skip shared library trampoline code (which is different from indirect function call trampolines). + + 3. Skip bigtoc fixup code. + Result is desired PC to step until, or NULL if we are not in - trampoline code. */ + code that should be skipped. */ CORE_ADDR rs6000_skip_trampoline_code (CORE_ADDR pc) { register unsigned int ii, op; + int rel; CORE_ADDR solib_target_pc; + struct minimal_symbol *msymbol; static unsigned trampoline_code[] = { @@ -1158,6 +1194,21 @@ rs6000_skip_trampoline_code (CORE_ADDR pc) 0 }; + /* Check for bigtoc fixup code. */ + msymbol = lookup_minimal_symbol_by_pc (pc); + if (msymbol && rs6000_in_solib_return_trampoline (pc, SYMBOL_NAME (msymbol))) + { + /* Double-check that the third instruction from PC is relative "b". */ + op = read_memory_integer (pc + 8, 4); + if ((op & 0xfc000003) == 0x48000000) + { + /* Extract bits 6-29 as a signed 24-bit relative word address and + add it to the containing PC. */ + rel = ((int)(op << 6) >> 6); + return pc + 8 + rel; + } + } + /* If pc is in a shared library trampoline, return its target. */ solib_target_pc = find_solib_trampoline_target (pc); if (solib_target_pc) |