2003-03-12 Michal Ludvig * frame.c (get_prev_frame): Link prev_frame to this_frame as soon as possible. * i386-tdep.c (i386_frameless_signal_p, i386_frame_chain) (i386_sigtramp_saved_pc, i386_sigtramp_saved_sp) (i386_frame_saved_pc, i386_frame_init_saved_regs): Removed. (i386_frame_cache): New structure. (i386_unwind_pc): New method. (i386_frame_cache, i386_frame_pc_unwind, i386_frame_unwind) (i386_frame_id_unwind, i386_frame_register_unwind): New stuff for unwinding normal frames. (i386_sigtramp_cache, i386_sigtramp_pc_unwind) (i386_sigtramp_id_unwind, i386_sigtramp_register_unwind) (i386_sigtramp_unwind): New stuff for unwinding sigtramp frames. (i386_frame_p): New. (i386_unwind_dummy_id, i386_save_dummy_frame_tos): New. (i386_pc_in_sigtramp): Doesn't need name anymore. (i386_gdbarch_init): Updated to use new unwinding methods. Index: frame.c =================================================================== RCS file: /cvs/src/src/gdb/frame.c,v retrieving revision 1.71.2.7 diff -u -p -r1.71.2.7 frame.c --- frame.c 11 Mar 2003 23:00:26 -0000 1.71.2.7 +++ frame.c 12 Mar 2003 16:28:15 -0000 @@ -1282,7 +1282,6 @@ get_prev_frame (struct frame_info *this_ /* Only try to do the unwind once. */ if (this_frame->prev_p) return this_frame->prev; - this_frame->prev_p = 1; /* If we're inside the entry file, it isn't valid. Don't apply this test to a dummy frame - dummy frame PC's typically land in the @@ -1351,6 +1350,11 @@ get_prev_frame (struct frame_info *this_ prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info); prev_frame->level = this_frame->level + 1; + /* Link it in. */ + this_frame->prev = prev_frame; + prev_frame->next = this_frame; + this_frame->prev_p = 1; + /* Try to unwind the PC. If that doesn't work, assume we've reached the oldest frame and simply return. Is there a better sentinal value? The unwound PC value is then used to initialize the new @@ -1466,10 +1470,6 @@ get_prev_frame (struct frame_info *this_ (HP/UX) still reply on EXTRA_FRAME_INFO and, hence, still poke at the "struct frame_info" object directly. */ prev_frame->frame = prev_frame->id.base; - - /* Link it in. */ - this_frame->prev = prev_frame; - prev_frame->next = this_frame; /* FIXME: cagney/2002-01-19: This call will go away. Instead of initializing extra info, all frames will use the frame_cache Index: i386-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/i386-tdep.c,v retrieving revision 1.116 diff -u -p -r1.116 i386-tdep.c --- i386-tdep.c 3 Mar 2003 20:50:18 -0000 1.116 +++ i386-tdep.c 12 Mar 2003 16:28:15 -0000 @@ -469,64 +476,8 @@ i386_get_frame_setup (CORE_ADDR pc) return (-1); } -/* Signal trampolines don't have a meaningful frame. The frame - pointer value we use is actually the frame pointer of the calling - frame -- that is, the frame which was in progress when the signal - trampoline was entered. GDB mostly treats this frame pointer value - as a magic cookie. We detect the case of a signal trampoline by - testing for get_frame_type() == SIGTRAMP_FRAME, which is set based - on PC_IN_SIGTRAMP. - - When a signal trampoline is invoked from a frameless function, we - essentially have two frameless functions in a row. In this case, - we use the same magic cookie for three frames in a row. We detect - this case by seeing whether the next frame is a SIGTRAMP_FRAME, - and, if it does, checking whether the current frame is actually - frameless. In this case, we need to get the PC by looking at the - SP register value stored in the signal context. - - This should work in most cases except in horrible situations where - a signal occurs just as we enter a function but before the frame - has been set up. Incidentally, that's just what happens when we - call a function from GDB with a signal pending (there's a test in - the testsuite that makes this happen). Therefore we pretend that - we have a frameless function if we're stopped at the start of a - function. */ - -/* Return non-zero if we're dealing with a frameless signal, that is, - a signal trampoline invoked from a frameless function. */ - -int -i386_frameless_signal_p (struct frame_info *frame) -{ - return (get_next_frame (frame) - && get_frame_type (get_next_frame (frame)) == SIGTRAMP_FRAME - && (frameless_look_for_prologue (frame) - || get_frame_pc (frame) == get_pc_function_start (get_frame_pc (frame)))); -} - -/* Return the chain-pointer for FRAME. In the case of the i386, the - frame's nominal address is the address of a 4-byte word containing - the calling frame's address. */ - -static CORE_ADDR -i386_frame_chain (struct frame_info *frame) -{ - if (pc_in_dummy_frame (get_frame_pc (frame))) - return get_frame_base (frame); - - if (get_frame_type (frame) == SIGTRAMP_FRAME - || i386_frameless_signal_p (frame)) - return get_frame_base (frame); - - if (! inside_entry_file (get_frame_pc (frame))) - return read_memory_unsigned_integer (get_frame_base (frame), 4); - - return 0; -} - /* Determine whether the function invocation represented by FRAME does - not have a from on the stack associated with it. If it does not, + not have a frame on the stack associated with it. If it does not, return non-zero, otherwise return zero. */ static int @@ -538,66 +489,16 @@ i386_frameless_function_invocation (stru return frameless_look_for_prologue (frame); } -/* Assuming FRAME is for a sigtramp routine, return the saved program - counter. */ - -static CORE_ADDR -i386_sigtramp_saved_pc (struct frame_info *frame) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - CORE_ADDR addr; - - addr = tdep->sigcontext_addr (frame); - return read_memory_unsigned_integer (addr + tdep->sc_pc_offset, 4); -} - -/* Assuming FRAME is for a sigtramp routine, return the saved stack - pointer. */ - -static CORE_ADDR -i386_sigtramp_saved_sp (struct frame_info *frame) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - CORE_ADDR addr; - - addr = tdep->sigcontext_addr (frame); - return read_memory_unsigned_integer (addr + tdep->sc_sp_offset, 4); -} - -/* Return the saved program counter for FRAME. */ - -static CORE_ADDR -i386_frame_saved_pc (struct frame_info *frame) -{ - if (pc_in_dummy_frame (get_frame_pc (frame))) - { - ULONGEST pc; - - frame_unwind_unsigned_register (frame, PC_REGNUM, &pc); - return pc; - } - - if (get_frame_type (frame) == SIGTRAMP_FRAME) - return i386_sigtramp_saved_pc (frame); - - if (i386_frameless_signal_p (frame)) - { - CORE_ADDR sp = i386_sigtramp_saved_sp (get_next_frame (frame)); - return read_memory_unsigned_integer (sp, 4); - } - - return read_memory_unsigned_integer (get_frame_base (frame) + 4, 4); -} - /* Immediately after a function call, return the saved pc. */ static CORE_ADDR i386_saved_pc_after_call (struct frame_info *frame) { - if (get_frame_type (frame) == SIGTRAMP_FRAME) - return i386_sigtramp_saved_pc (frame); + char buf[4]; - return read_memory_unsigned_integer (read_register (SP_REGNUM), 4); + /* Our frame unwinder handles this just fine. */ + frame_unwind_register (frame, PC_REGNUM, buf); + return extract_address (buf, 4); } /* Return number of args passed to a frame. @@ -674,72 +575,6 @@ i386_frame_num_args (struct frame_info * #endif } -/* Parse the first few instructions the function to see what registers - were stored. - - We handle these cases: - - The startup sequence can be at the start of the function, or the - function can start with a branch to startup code at the end. - - %ebp can be set up with either the 'enter' instruction, or "pushl - %ebp, movl %esp, %ebp" (`enter' is too slow to be useful, but was - once used in the System V compiler). - - Local space is allocated just below the saved %ebp by either the - 'enter' instruction, or by "subl $, %esp". 'enter' has a 16 - bit unsigned argument for space to allocate, and the 'addl' - instruction could have either a signed byte, or 32 bit immediate. - - Next, the registers used by this function are pushed. With the - System V compiler they will always be in the order: %edi, %esi, - %ebx (and sometimes a harmless bug causes it to also save but not - restore %eax); however, the code below is willing to see the pushes - in any order, and will handle up to 8 of them. - - If the setup sequence is at the end of the function, then the next - instruction will be a branch back to the start. */ - -static void -i386_frame_init_saved_regs (struct frame_info *fip) -{ - long locals = -1; - unsigned char op; - CORE_ADDR addr; - CORE_ADDR pc; - int i; - - if (get_frame_saved_regs (fip)) - return; - - frame_saved_regs_zalloc (fip); - - pc = get_pc_function_start (get_frame_pc (fip)); - if (pc != 0) - locals = i386_get_frame_setup (pc); - - if (locals >= 0) - { - addr = get_frame_base (fip) - 4 - locals; - for (i = 0; i < 8; i++) - { - op = codestream_get (); - if (op < 0x50 || op > 0x57) - break; -#ifdef I386_REGNO_TO_SYMMETRY - /* Dynix uses different internal numbering. Ick. */ - get_frame_saved_regs (fip)[I386_REGNO_TO_SYMMETRY (op - 0x50)] = addr; -#else - get_frame_saved_regs (fip)[op - 0x50] = addr; -#endif - addr -= 4; - } - } - - get_frame_saved_regs (fip)[PC_REGNUM] = get_frame_base (fip) + 4; - get_frame_saved_regs (fip)[FP_REGNUM] = get_frame_base (fip); -} - /* Return PC of first real instruction. */ static CORE_ADDR @@ -855,37 +690,423 @@ i386_push_return_address (CORE_ADDR pc, write_memory (sp - 4, buf, 4); return sp - 4; } + +#include "frame-unwind.h" + +#define regcache_cooked_write_unsigned regcache_raw_write_unsigned + +#ifdef I386_REGNO_TO_SYMMETRY +#error "The Sequent Symmetry is no longer supported." +#endif + +/* According to the System V ABI, the registers %ebp, %ebx, %edi, %esi + and %esp "belong" to the calling function. */ + +/* The maximum number of saved registers. This should include all + registers mentioned above, and %eip. */ +#define I386_NUM_SAVED_REGISTERS 9 + +struct i386_frame_cache +{ + CORE_ADDR saved_regs[I386_NUM_SAVED_REGISTERS]; + CORE_ADDR saved_sp; + CORE_ADDR return_pc; + CORE_ADDR base; + int frameless; +}; + +/* Parse the first few instructions the function to see what registers + were stored. + + We handle these cases: + + The startup sequence can be at the start of the function, or the + function can start with a branch to startup code at the end. + + %ebp can be set up with either the 'enter' instruction, or "pushl + %ebp, movl %esp, %ebp" (`enter' is too slow to be useful, but was + once used in the System V compiler). + + Local space is allocated just below the saved %ebp by either the + 'enter' instruction, or by "subl $, %esp". 'enter' has a 16 + bit unsigned argument for space to allocate, and the 'addl' + instruction could have either a signed byte, or 32 bit immediate. + + Next, the registers used by this function are pushed. With the + System V compiler they will always be in the order: %edi, %esi, + %ebx (and sometimes a harmless bug causes it to also save but not + restore %eax); however, the code below is willing to see the pushes + in any order, and will handle up to 8 of them. + + If the setup sequence is at the end of the function, then the next + instruction will be a branch back to the start. */ + +static struct i386_frame_cache * +i386_frame_cache (struct frame_info *frame, void **cachep) +{ + struct i386_frame_cache *cache; + CORE_ADDR pc, start_pc; + + if (*cachep) + return *cachep; + + cache = FRAME_OBSTACK_ZALLOC (struct i386_frame_cache); + + pc = frame_pc_unwind (frame); + start_pc = get_pc_function_start (pc); + + long locals = -1; + + if (start_pc != 0) + locals = i386_get_frame_setup (start_pc); + + if (locals >= 0 && pc > start_pc) + { + ULONGEST fp; + CORE_ADDR addr; + unsigned char op; + int i; + + frame_unwind_unsigned_register (frame, FP_REGNUM, &fp); + cache->base = fp; + + addr = fp - 4 - locals; + for (i = 0; i < I386_NUM_SAVED_REGISTERS; i++) + { + op = codestream_get (); + if (op < 0x50 || op > 0x57) + break; + + cache->saved_regs[op - 0x50] = addr; + addr -= 4; + } + + cache->saved_regs[PC_REGNUM] = fp + 4; + cache->saved_regs[FP_REGNUM] = fp; + cache->saved_sp = fp + 8; + } + else + { + ULONGEST sp; + + /* This function is either frameless or we're at the start + of the function and this function's frame hasn't been + setup yet. In the latter case only %eip and %esp have + changed, and we can determine their previous values. We + pretend we can do the same in the former case. */ + cache->frameless = 1; + + frame_unwind_unsigned_register (frame, SP_REGNUM, &sp); + cache->saved_regs[PC_REGNUM] = sp; + cache->saved_sp = cache->saved_regs[PC_REGNUM] + 4; + cache->base = sp; + } + + *cachep = cache; + return cache; +} static void -i386_do_pop_frame (struct frame_info *frame) +i386_frame_pop (struct frame_info *frame, void **cachep, + struct regcache *regcache) { - CORE_ADDR fp; + CORE_ADDR fp = get_frame_base (frame); int regnum; - char regbuf[I386_MAX_REGISTER_SIZE]; + char buf[4]; + ULONGEST val; - fp = get_frame_base (frame); - i386_frame_init_saved_regs (frame); + gdb_assert (get_frame_type (frame) != DUMMY_FRAME); - for (regnum = 0; regnum < NUM_REGS; regnum++) + for (regnum = 0; regnum < I386_NUM_SAVED_REGISTERS; regnum++) { - CORE_ADDR addr; - addr = get_frame_saved_regs (frame)[regnum]; - if (addr) + frame_unwind_register (frame, regnum, buf); + regcache_cooked_write (regcache, regnum, buf); + } + + /* Reset the direction flag. */ + regcache_cooked_read_unsigned (regcache, PS_REGNUM, &val); + val &= ~(1 << 10); + regcache_cooked_write_unsigned (regcache, PS_REGNUM, val); + + /* The following sequence restores %ebp, %eip and %esp. */ + read_memory (fp, buf, 4); + regcache_cooked_write (regcache, FP_REGNUM, buf); + read_memory (fp + 4, buf, 4); + regcache_cooked_write (regcache, PC_REGNUM, buf); + regcache_cooked_write_unsigned (regcache, SP_REGNUM, fp + 8); + + flush_cached_frames (); +} + +static CORE_ADDR +i386_frame_pc_unwind (struct frame_info *frame, void **cachep) +{ + struct i386_frame_cache *cache = i386_frame_cache (frame, cachep); + + gdb_assert (get_frame_type (frame) != DUMMY_FRAME); + + if (cache->return_pc == 0) + { + char buf[4]; + + frame_unwind_register (frame, PC_REGNUM, buf); + cache->return_pc = extract_address (buf, 4); + } + + return cache->return_pc; +} + +static CORE_ADDR +i386_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + ULONGEST pc; + frame_unwind_unsigned_register (next_frame, PC_REGNUM, &pc); + return (CORE_ADDR) pc; +} + +static void +i386_frame_id_unwind (struct frame_info *next_frame, void **cachep, + struct frame_id *id) +{ + struct i386_frame_cache *cache = i386_frame_cache (next_frame, cachep); + + gdb_assert (cache); + gdb_assert (get_frame_type (next_frame) != DUMMY_FRAME); + + /* Start with a NULL next_frame ID. */ + *id = null_frame_id; + + /* Unwind PC first */ + id->pc = frame_pc_unwind (next_frame); + cache->return_pc = id->pc; + + /* The next_frame's base is the address of a 4-byte word containing the + calling next_frame's address. + + Signal trampolines don't have a meaningful next_frame. The frame + pointer value we use is actually the next_frame pointer of the calling + next_frame -- that is, the frame which was in progress when the signal + trampoline was entered. GDB mostly treats this next_frame pointer + value as a magic cookie. We detect the case of a signal + trampoline by testing for get_frame_type() == SIGTRAMP_FRAME, + which is set based on PC_IN_SIGTRAMP. */ + + if (get_frame_type (next_frame) == SIGTRAMP_FRAME || cache->frameless) + id->base = get_frame_base (next_frame); + else + if (!inside_entry_file (get_frame_pc (next_frame))) + id->base = cache->base; +} + +static void +i386_frame_register_unwind (struct frame_info *frame, void **cachep, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + /* FIXME: kettenis/20030302: I don't understand why the cache isn't + already initialized. */ + struct i386_frame_cache *cache = i386_frame_cache (frame, cachep); + + gdb_assert (cache); + gdb_assert (get_frame_type (frame) != DUMMY_FRAME); + gdb_assert (regnum >= 0); + + if (regnum == SP_REGNUM && cache->saved_sp) + { + *optimizedp = 0; + *lvalp = not_lval; + *addrp = 0; + *realnump = -1; + if (valuep) { - read_memory (addr, regbuf, REGISTER_RAW_SIZE (regnum)); - deprecated_write_register_gen (regnum, regbuf); + /* Store the value. */ + store_address (valuep, 4, cache->saved_regs[SP_REGNUM]); } + return; } - write_register (FP_REGNUM, read_memory_integer (fp, 4)); - write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); - write_register (SP_REGNUM, fp + 8); - flush_cached_frames (); + + if (regnum == PC_REGNUM) + { + CORE_ADDR pc; + *optimizedp = 0; + *lvalp = not_lval; + *addrp = 0; + *realnump = -1; + pc = i386_frame_pc_unwind (frame, cachep); + if (valuep) + store_address (valuep, 4, pc); + } + + if (regnum < I386_NUM_SAVED_REGISTERS && cache->saved_regs[regnum] != 0) + { + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = cache->saved_regs[regnum]; + *realnump = -1; + if (valuep) + { + /* Read the value in from memory. */ + read_memory (*addrp, valuep, + register_size (current_gdbarch, regnum)); + } + return; + } + + frame_register (frame, regnum, optimizedp, lvalp, addrp, realnump, valuep); +} + +static struct i386_frame_cache * +i386_sigtramp_cache (struct frame_info *frame, void **cachep) +{ + struct i386_frame_cache *cache; + CORE_ADDR pc, start_pc, addr; + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + int sc_offset, regnum; + + if (*cachep) + return *cachep; + + cache = FRAME_OBSTACK_ZALLOC (struct i386_frame_cache); + + pc = frame_pc_unwind (frame); + start_pc = get_pc_function_start (pc); + addr = tdep->sigcontext_addr (frame->prev); + + for (regnum=0; regnum<=PS_REGNUM; regnum++) + { + /* See for details on how registers are stored + in the sigcontext. */ + if (regnum < PC_REGNUM) + sc_offset = (11 - regnum); + else if (regnum == PC_REGNUM) + sc_offset = 14; + else if (regnum == PS_REGNUM) + sc_offset = 16; + else + break; + + sc_offset *= 4; + + if (regnum < sizeof (cache->saved_regs)) + cache->saved_regs[regnum] = addr + sc_offset; + } + + cache->base = addr; + + *cachep = cache; + return cache; +} + +static void +i386_sigtramp_register_unwind (struct frame_info *frame, void **cachep, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + printf_debug ("## %s(%p, %p, %s(%d))\n", __func__, (void*)frame->frame, + (void*)frame->pc, i386_register_name(regnum), regnum); + + struct i386_frame_cache *cache = i386_sigtramp_cache (frame, cachep); + char buf[4]; + CORE_ADDR addr; + + gdb_assert (cache); + gdb_assert (regnum >= 0); + + if (regnum < I386_NUM_SAVED_REGISTERS && cache->saved_regs[regnum] != 0) + { + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = cache->saved_regs[regnum]; + *realnump = -1; + if (valuep) + read_memory (*addrp, valuep, + register_size (current_gdbarch, regnum)); + return; + } + + /* Fall back for non-saved registers. */ + frame_register (frame, regnum, optimizedp, lvalp, addrp, realnump, valuep); } static void -i386_pop_frame (void) +i386_sigtramp_id_unwind (struct frame_info *next_frame, void **cachep, + struct frame_id *id) +{ + printf_debug ("## %s(%p, %p)\n", __func__, (void*)next_frame->frame, + (void*)next_frame->pc); + struct i386_frame_cache *cache = i386_sigtramp_cache (next_frame, cachep); + + gdb_assert (cache); + gdb_assert (get_frame_type (next_frame) != DUMMY_FRAME); + + /* Start with a NULL next_frame ID. */ + *id = null_frame_id; + + /* Unwind PC first */ + id->pc = frame_pc_unwind (next_frame); + cache->return_pc = id->pc; + + /* The next_frame's base is the address of a 4-byte word containing the + calling next_frame's address. + + Signal trampolines don't have a meaningful next_frame. The frame + pointer value we use is actually the next_frame pointer of the calling + next_frame -- that is, the frame which was in progress when the signal + trampoline was entered. GDB mostly treats this next_frame pointer + value as a magic cookie. We detect the case of a signal + trampoline by testing for get_frame_type() == SIGTRAMP_FRAME, + which is set based on PC_IN_SIGTRAMP. */ + + if (get_frame_type (next_frame) == SIGTRAMP_FRAME || cache->frameless) + id->base = get_frame_base (next_frame); + else + if (!inside_entry_file (get_frame_pc (next_frame))) + id->base = cache->base; +} + +static struct frame_unwind i386_sigtramp_unwind = { + i386_sigtramp_id_unwind, + i386_sigtramp_register_unwind +}; + +static struct frame_unwind i386_frame_unwind = { + i386_frame_id_unwind, + i386_frame_register_unwind +}; + +const struct frame_unwind * +i386_frame_p (CORE_ADDR pc) { - generic_pop_current_frame (i386_do_pop_frame); + if (gdbarch_pc_in_sigtramp (current_gdbarch, pc, NULL)) + return &i386_sigtramp_unwind; + else + return &i386_frame_unwind; +} + +static struct frame_id +i386_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + struct frame_id id; + ULONGEST base; + + id.pc = frame_pc_unwind (next_frame); + frame_unwind_unsigned_register (next_frame, FP_REGNUM, &base); + id.base = base; + return id; +} + +static void +i386_save_dummy_frame_tos (CORE_ADDR sp) +{ + /* We can't use the saved top-of-stack to find the right dummy frame + when unwinding, since we can't reconstruct it properly if the + dummy frame is the innermost frame. To circumvent this, we fake + a frame pointer here. */ + + regcache_cooked_write_unsigned (current_regcache, FP_REGNUM, sp); + generic_save_dummy_frame_tos (sp); } @@ -1312,7 +1533,13 @@ i386_pe_skip_trampoline_code (CORE_ADDR static int i386_pc_in_sigtramp (CORE_ADDR pc, char *name) { - return (name && strcmp ("_sigtramp", name) == 0); + char *pname; + if (name) + pname = name; + else + find_pc_partial_function (pc, &pname, NULL, NULL); + + return (name && strcmp ("_sigtramp", pname) == 0); } @@ -1506,10 +1733,6 @@ i386_gdbarch_init (struct gdbarch_info i tdep = XMALLOC (struct gdbarch_tdep); gdbarch = gdbarch_alloc (&info, tdep); - /* NOTE: cagney/2002-12-06: This can be deleted when this arch is - ready to unwind the PC first (see frame.c:get_prev_frame()). */ - set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default); - /* The i386 default settings don't include the SSE registers. FIXME: kettenis/20020614: They do include the FPU registers for now, which probably is not quite right. */ @@ -1591,14 +1814,12 @@ i386_gdbarch_init (struct gdbarch_info i set_gdbarch_extract_return_value (gdbarch, i386_extract_return_value); set_gdbarch_push_arguments (gdbarch, i386_push_arguments); set_gdbarch_push_return_address (gdbarch, i386_push_return_address); - set_gdbarch_pop_frame (gdbarch, i386_pop_frame); set_gdbarch_store_struct_return (gdbarch, i386_store_struct_return); set_gdbarch_store_return_value (gdbarch, i386_store_return_value); set_gdbarch_extract_struct_value_address (gdbarch, i386_extract_struct_value_address); set_gdbarch_use_struct_convention (gdbarch, i386_use_struct_convention); - set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, i386_frame_init_saved_regs); set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue); /* Stack grows downward. */ @@ -1608,16 +1829,9 @@ i386_gdbarch_init (struct gdbarch_info i set_gdbarch_decr_pc_after_break (gdbarch, 1); set_gdbarch_function_start_offset (gdbarch, 0); - /* The following redefines make backtracing through sigtramp work. - They manufacture a fake sigtramp frame and obtain the saved pc in - sigtramp from the sigcontext structure which is pushed by the - kernel on the user stack, along with a pointer to it. */ - set_gdbarch_frame_args_skip (gdbarch, 8); set_gdbarch_frameless_function_invocation (gdbarch, i386_frameless_function_invocation); - set_gdbarch_frame_chain (gdbarch, i386_frame_chain); - set_gdbarch_frame_saved_pc (gdbarch, i386_frame_saved_pc); set_gdbarch_saved_pc_after_call (gdbarch, i386_saved_pc_after_call); set_gdbarch_frame_num_args (gdbarch, i386_frame_num_args); set_gdbarch_pc_in_sigtramp (gdbarch, i386_pc_in_sigtramp); @@ -1629,12 +1843,19 @@ i386_gdbarch_init (struct gdbarch_info i set_gdbarch_print_insn (gdbarch, i386_print_insn); + set_gdbarch_unwind_dummy_id (gdbarch, i386_unwind_dummy_id); + set_gdbarch_save_dummy_frame_tos (gdbarch, i386_save_dummy_frame_tos); + + set_gdbarch_unwind_pc (gdbarch, i386_unwind_pc); + /* Add the i386 register groups. */ i386_add_reggroups (gdbarch); set_gdbarch_register_reggroup_p (gdbarch, i386_register_reggroup_p); /* Hook in ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); + + frame_unwind_append_predicate (gdbarch, i386_frame_p); return gdbarch; }