static CORE_ADDR i386syl_sigcontext_addr (struct frame_info *next_frame) { CORE_ADDR pc; CORE_ADDR sp; char buf[4]; frame_unwind_register (next_frame, I386_ESP_REGNUM, buf); sp = extract_unsigned_integer (buf, 4); pc = i386syl_sigtramp_start (next_frame); if (pc) { /* The sigcontext structure lives on the stack, right after the signum argument. We determine the address of the sigcontext structure by looking at the frame's stack pointer. Keep in mind that the first instruction of the sigtramp code is "pop %eax". If the PC is after this instruction, adjust the returned value accordingly. */ if (pc == frame_pc_unwind (next_frame)) return sp + 4; return sp; } error ("Couldn't recognize signal trampoline."); return 0; }
static const struct frame_unwind * amd64_sigtramp_frame_sniffer (struct frame_info *next_frame) { struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame)); /* We shouldn't even bother if we don't have a sigcontext_addr handler. */ if (tdep->sigcontext_addr == NULL) return NULL; if (tdep->sigtramp_p != NULL) { if (tdep->sigtramp_p (next_frame)) return &amd64_sigtramp_frame_unwind; } if (tdep->sigtramp_start != 0) { CORE_ADDR pc = frame_pc_unwind (next_frame); gdb_assert (tdep->sigtramp_end != 0); if (pc >= tdep->sigtramp_start && pc < tdep->sigtramp_end) return &amd64_sigtramp_frame_unwind; } return NULL; }
static CORE_ADDR amd64_linux_sigtramp_start (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); gdb_byte buf[LINUX_SIGTRAMP_LEN]; /* We only recognize a signal trampoline if PC is at the start of one of the two instructions. We optimize for finding the PC at the start, as will be the case when the trampoline is not the first frame on the stack. We assume that in the case where the PC is not at the start of the instruction sequence, there will be a few trailing readable bytes on the stack. */ if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf)) return 0; if (buf[0] != LINUX_SIGTRAMP_INSN0) { if (buf[0] != LINUX_SIGTRAMP_INSN1) return 0; pc -= LINUX_SIGTRAMP_OFFSET1; if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf)) return 0; } if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0) return 0; return pc; }
static struct sparc_frame_cache * sparc64obsd_frame_cache (struct frame_info *next_frame, void **this_cache) { struct sparc_frame_cache *cache; CORE_ADDR addr; if (*this_cache) return *this_cache; cache = sparc_frame_cache (next_frame, this_cache); gdb_assert (cache == *this_cache); /* If we couldn't find the frame's function, we're probably dealing with an on-stack signal trampoline. */ if (cache->pc == 0) { cache->pc = frame_pc_unwind (next_frame); cache->pc &= ~(sparc64obsd_page_size - 1); /* Since we couldn't find the frame's function, the cache was initialized under the assumption that we're frameless. */ cache->frameless_p = 0; addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM); cache->base = addr; } /* We find the appropriate instance of `struct sigcontext' at a fixed offset in the signal frame. */ addr = cache->base + BIAS + 128 + 16; cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, next_frame); return cache; }
static CORE_ADDR alpha_linux_sigcontext_addr (struct frame_info *next_frame) { CORE_ADDR pc; ULONGEST sp; long off; pc = frame_pc_unwind (next_frame); frame_unwind_unsigned_register (next_frame, ALPHA_SP_REGNUM, &sp); off = alpha_linux_sigtramp_offset (pc); gdb_assert (off >= 0); /* __NR_rt_sigreturn has a couple of structures on the stack. This is: struct rt_sigframe { struct siginfo info; struct ucontext uc; }; offsetof (struct rt_sigframe, uc.uc_mcontext); */ if (alpha_read_insn (pc - off + 4) == 0x201f015f) return sp + 176; /* __NR_sigreturn has the sigcontext structure at the top of the stack. */ return sp; }
static struct trad_frame_cache * vaxobsd_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache) { struct trad_frame_cache *cache; CORE_ADDR addr, base, func; if (*this_cache) return *this_cache; cache = trad_frame_cache_zalloc (next_frame); *this_cache = cache; func = frame_pc_unwind (next_frame); func &= ~(vaxobsd_page_size - 1); base = frame_unwind_register_unsigned (next_frame, VAX_SP_REGNUM); addr = get_frame_memory_unsigned (next_frame, base - 4, 4); trad_frame_set_reg_addr (cache, VAX_SP_REGNUM, addr + 8); trad_frame_set_reg_addr (cache, VAX_FP_REGNUM, addr + 12); trad_frame_set_reg_addr (cache, VAX_AP_REGNUM, addr + 16); trad_frame_set_reg_addr (cache, VAX_PC_REGNUM, addr + 20); trad_frame_set_reg_addr (cache, VAX_PS_REGNUM, addr + 24); /* Construct the frame ID using the function start. */ trad_frame_set_id (cache, frame_id_build (base, func)); return cache; }
static LONGEST mipsnbsd_sigtramp_offset (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); const char *retcode = gdbarch_byte_order (get_frame_arch (next_frame)) == BFD_ENDIAN_BIG ? sigtramp_retcode_mipseb : sigtramp_retcode_mipsel; unsigned char ret[RETCODE_SIZE], w[4]; LONGEST off; int i; if (!safe_frame_unwind_memory (next_frame, pc, w, sizeof (w))) return -1; for (i = 0; i < RETCODE_NWORDS; i++) { if (memcmp (w, retcode + (i * 4), 4) == 0) break; } if (i == RETCODE_NWORDS) return -1; off = i * 4; pc -= off; if (!safe_frame_unwind_memory (next_frame, pc, ret, sizeof (ret))) return -1; if (memcmp (ret, retcode, RETCODE_SIZE) == 0) return off; return -1; }
static int tramp_frame_sniffer (const struct frame_unwind *self, struct frame_info *next_frame, void **this_cache) { const struct tramp_frame *tramp = self->unwind_data->tramp_frame; CORE_ADDR pc = frame_pc_unwind (next_frame); CORE_ADDR func; char *name; struct tramp_frame_cache *tramp_cache; /* If the function has a valid symbol name, it isn't a trampoline. */ find_pc_partial_function (pc, &name, NULL, NULL); if (name != NULL) return 0; /* If the function lives in a valid section (even without a starting point) it isn't a trampoline. */ if (find_pc_section (pc) != NULL) return 0; /* Finally, check that the trampoline matches at PC. */ func = tramp_frame_start (tramp, next_frame, pc); if (func == 0) return 0; tramp_cache = FRAME_OBSTACK_ZALLOC (struct tramp_frame_cache); tramp_cache->func = func; tramp_cache->tramp_frame = tramp; (*this_cache) = tramp_cache; return 1; }
static void ppc_linux_sigtramp_cache (struct frame_info *next_frame, struct trad_frame_cache *this_cache, CORE_ADDR func, LONGEST offset, int bias) { CORE_ADDR base; CORE_ADDR regs; CORE_ADDR gpregs; CORE_ADDR fpregs; int i; struct gdbarch *gdbarch = get_frame_arch (next_frame); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); base = frame_unwind_register_unsigned (next_frame, gdbarch_sp_regnum (current_gdbarch)); if (bias > 0 && frame_pc_unwind (next_frame) != func) /* See below, some signal trampolines increment the stack as their first instruction, need to compensate for that. */ base -= bias; /* Find the address of the register buffer pointer. */ regs = base + offset; /* Use that to find the address of the corresponding register buffers. */ gpregs = read_memory_unsigned_integer (regs, tdep->wordsize); fpregs = gpregs + 48 * tdep->wordsize; /* General purpose. */ for (i = 0; i < 32; i++) { int regnum = i + tdep->ppc_gp0_regnum; trad_frame_set_reg_addr (this_cache, regnum, gpregs + i * tdep->wordsize); } trad_frame_set_reg_addr (this_cache, gdbarch_pc_regnum (current_gdbarch), gpregs + 32 * tdep->wordsize); trad_frame_set_reg_addr (this_cache, tdep->ppc_ctr_regnum, gpregs + 35 * tdep->wordsize); trad_frame_set_reg_addr (this_cache, tdep->ppc_lr_regnum, gpregs + 36 * tdep->wordsize); trad_frame_set_reg_addr (this_cache, tdep->ppc_xer_regnum, gpregs + 37 * tdep->wordsize); trad_frame_set_reg_addr (this_cache, tdep->ppc_cr_regnum, gpregs + 38 * tdep->wordsize); if (ppc_floating_point_unit_p (gdbarch)) { /* Floating point registers. */ for (i = 0; i < 32; i++) { int regnum = i + gdbarch_fp0_regnum (current_gdbarch); trad_frame_set_reg_addr (this_cache, regnum, fpregs + i * tdep->wordsize); } trad_frame_set_reg_addr (this_cache, tdep->ppc_fpscr_regnum, fpregs + 32 * tdep->wordsize); } trad_frame_set_id (this_cache, frame_id_build (base, func)); }
/* Here is a dummy implementation. */ static struct frame_id mn10300_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) { return frame_id_build (frame_sp_unwind (next_frame), frame_pc_unwind (next_frame)); }
CORE_ADDR glibc_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) { /* The GNU dynamic linker is part of the GNU C library, and is used by all GNU systems (GNU/Hurd, GNU/Linux). An unresolved PLT entry points to "_dl_runtime_resolve", which calls "fixup" to patch the PLT, and then passes control to the function. We look for the symbol `_dl_runtime_resolve', and find `fixup' in the same objfile. If we are at the entry point of `fixup', then we set a breakpoint at the return address (at the top of the stack), and continue. It's kind of gross to do all these checks every time we're called, since they don't change once the executable has gotten started. But this is only a temporary hack --- upcoming versions of GNU/Linux will provide a portable, efficient interface for debugging programs that use shared libraries. */ struct objfile *objfile; struct minimal_symbol *resolver = find_minsym_and_objfile ("_dl_runtime_resolve", &objfile); if (resolver) { struct minimal_symbol *fixup = lookup_minimal_symbol ("fixup", NULL, objfile); if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc) return frame_pc_unwind (get_current_frame ()); } return 0; }
static struct frame_id m88k_unwind_dummy_id (struct gdbarch *arch, struct frame_info *next_frame) { CORE_ADDR sp; sp = frame_unwind_register_unsigned (next_frame, M88K_R31_REGNUM); return frame_id_build (sp, frame_pc_unwind (next_frame)); }
static struct frame_id sparc_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) { CORE_ADDR sp; sp = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM); return frame_id_build (sp, frame_pc_unwind (next_frame)); }
static void amd64_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache, struct frame_id *this_id) { struct x86_frame_cache *cache = amd64_sigtramp_frame_cache (next_frame, this_cache); (*this_id) = frame_id_build (cache->frame_base + 8, frame_pc_unwind (next_frame)); }
static int i386nto_sigtramp_p (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); char *name; find_pc_partial_function (pc, &name, NULL, NULL); return name && strcmp ("__signalstub", name) == 0; }
static int amd64_sol2_sigtramp_p (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); char *name; find_pc_partial_function (pc, &name, NULL, NULL); return (name && (strcmp ("sigacthandler", name) == 0 || strcmp (name, "ucbsigvechandler") == 0)); }
static int i386nbsd_sigtramp_p (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); char *name; find_pc_partial_function (pc, &name, NULL, NULL); return (nbsd_pc_in_sigtramp (pc, name) || i386nbsd_sigtramp_offset (next_frame) >= 0); }
struct m88k_frame_cache * m88k_frame_cache (struct frame_info *next_frame, void **this_cache) { struct m88k_frame_cache *cache; CORE_ADDR frame_sp; if (*this_cache) return *this_cache; cache = FRAME_OBSTACK_ZALLOC (struct m88k_frame_cache); cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); cache->fp_offset = -1; cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME); if (cache->pc != 0) m88k_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache); /* Calculate the stack pointer used in the prologue. */ if (cache->fp_offset != -1) { CORE_ADDR fp; fp = frame_unwind_register_unsigned (next_frame, M88K_R30_REGNUM); frame_sp = fp - cache->fp_offset; } else { /* If we know where the return address is saved, we can take a solid guess at what the frame pointer should be. */ if (cache->saved_regs[M88K_R1_REGNUM].addr != -1) cache->fp_offset = cache->saved_regs[M88K_R1_REGNUM].addr - 4; frame_sp = frame_unwind_register_unsigned (next_frame, M88K_R31_REGNUM); } /* Now that we know the stack pointer, adjust the location of the saved registers. */ { int regnum; for (regnum = M88K_R0_REGNUM; regnum < M88K_R31_REGNUM; regnum ++) if (cache->saved_regs[regnum].addr != -1) cache->saved_regs[regnum].addr += frame_sp; } /* Calculate the frame's base. */ cache->base = frame_sp - cache->sp_offset; trad_frame_set_value (cache->saved_regs, M88K_R31_REGNUM, cache->base); /* Identify SXIP with the return address in R1. */ cache->saved_regs[M88K_SXIP_REGNUM] = cache->saved_regs[M88K_R1_REGNUM]; *this_cache = cache; return cache; }
static struct frame_id amd64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) { gdb_byte buf[8]; CORE_ADDR fp; frame_unwind_register (next_frame, AMD64_RBP_REGNUM, buf); fp = extract_unsigned_integer (buf, 8); return frame_id_build (fp + 16, frame_pc_unwind (next_frame)); }
CORE_ADDR obsd_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) { struct minimal_symbol *msym; msym = lookup_minimal_symbol("_dl_bind", NULL, NULL); if (msym && SYMBOL_VALUE_ADDRESS (msym) == pc) return frame_pc_unwind (get_current_frame ()); else return find_solib_trampoline_target (get_current_frame (), pc); }
static const struct frame_unwind * sparc64_sol2_sigtramp_frame_sniffer (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); char *name; find_pc_partial_function (pc, &name, NULL, NULL); if (sparc_sol2_pc_in_sigtramp (pc, name)) return &sparc64_sol2_sigtramp_frame_unwind; return NULL; }
static struct trad_frame_cache * ppcobsd_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache) { struct gdbarch *gdbarch = get_frame_arch (next_frame); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); struct trad_frame_cache *cache; CORE_ADDR addr, base, func; gdb_byte buf[PPC_INSN_SIZE]; unsigned long insn, sigcontext_offset; int i; if (*this_cache) return *this_cache; cache = trad_frame_cache_zalloc (next_frame); *this_cache = cache; func = frame_pc_unwind (next_frame); func &= ~(ppcobsd_page_size - 1); if (!safe_frame_unwind_memory (next_frame, func, buf, sizeof buf)) return cache; /* Calculate the offset where we can find `struct sigcontext'. We base our calculation on the amount of stack space reserved by the first instruction of the signal trampoline. */ insn = extract_unsigned_integer (buf, PPC_INSN_SIZE); sigcontext_offset = (0x10000 - (insn & 0x0000ffff)) + 8; base = frame_unwind_register_unsigned (next_frame, gdbarch_sp_regnum (gdbarch)); addr = base + sigcontext_offset + 2 * tdep->wordsize; for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize) { int regnum = i + tdep->ppc_gp0_regnum; trad_frame_set_reg_addr (cache, regnum, addr); } trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr); addr += tdep->wordsize; trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr); addr += tdep->wordsize; trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr); addr += tdep->wordsize; trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr); addr += tdep->wordsize; trad_frame_set_reg_addr (cache, gdbarch_pc_regnum (gdbarch), addr); /* SRR0? */ addr += tdep->wordsize; /* Construct the frame ID using the function start. */ trad_frame_set_id (cache, frame_id_build (base, func)); return cache; }
static CORE_ADDR mips_linux_skip_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) { struct minimal_symbol *resolver; resolver = lookup_minimal_symbol ("__dl_runtime_resolve", NULL, NULL); if (resolver && SYMBOL_VALUE_ADDRESS (resolver) == pc) return frame_pc_unwind (get_current_frame ()); return 0; }
static LONGEST i386nbsd_sigtramp_offset (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); unsigned char ret[sizeof(sigtramp_retcode)], insn; LONGEST off; int i; if (!safe_frame_unwind_memory (next_frame, pc, &insn, 1)) return -1; switch (insn) { case RETCODE_INSN1: off = 0; break; case RETCODE_INSN2: /* INSN2 and INSN3 are the same. Read at the location of PC+1 to determine if we're actually looking at INSN2 or INSN3. */ if (!safe_frame_unwind_memory (next_frame, pc + 1, &insn, 1)) return -1; if (insn == RETCODE_INSN3) off = RETCODE_INSN2_OFF; else off = RETCODE_INSN3_OFF; break; case RETCODE_INSN4: off = RETCODE_INSN4_OFF; break; case RETCODE_INSN5: off = RETCODE_INSN5_OFF; break; default: return -1; } pc -= off; if (!safe_frame_unwind_memory (next_frame, pc, ret, sizeof (ret))) return -1; if (memcmp (ret, sigtramp_retcode, sizeof (ret)) == 0) return off; return -1; }
static const struct frame_unwind * sparc64nbsd_sigtramp_frame_sniffer (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); char *name; find_pc_partial_function (pc, &name, NULL, NULL); if (sparc64nbsd_pc_in_sigtramp (pc, name)) { if (name == NULL || strncmp (name, "__sigtramp_sigcontext", 21)) return &sparc64nbsd_sigcontext_frame_unwind; } return NULL; }
static struct trad_frame_cache * tramp_frame_cache (struct frame_info *next_frame, void **this_cache) { CORE_ADDR pc = frame_pc_unwind (next_frame); struct tramp_frame_cache *tramp_cache = (*this_cache); if (tramp_cache->trad_cache == NULL) { tramp_cache->trad_cache = trad_frame_cache_zalloc (next_frame); tramp_cache->tramp_frame->init (tramp_cache->tramp_frame, next_frame, tramp_cache->trad_cache, tramp_cache->func); } return tramp_cache->trad_cache; }
static int i386obsd_sigtramp_p (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1)); const char sigreturn[] = { 0xb8, 0x67, 0x00, 0x00, 0x00, /* movl $SYS_sigreturn, %eax */ 0xcd, 0x80 /* int $0x80 */ }; size_t buflen = sizeof sigreturn; char *name, *buf; /* If the function has a valid symbol name, it isn't a trampoline. */ find_pc_partial_function (pc, &name, NULL, NULL); if (name != NULL) return 0; /* If the function lives in a valid section (even without a starting point) it isn't a trampoline. */ if (find_pc_section (pc) != NULL) return 0; /* Allocate buffer. */ buf = alloca (buflen); /* If we can't read the instructions at START_PC, return zero. */ if (!safe_frame_unwind_memory (next_frame, start_pc + 0x0a, buf, buflen)) return 0; /* Check for sigreturn(2). */ if (memcmp (buf, sigreturn, buflen) == 0) return 1; /* If we can't read the instructions at START_PC, return zero. */ if (!safe_frame_unwind_memory (next_frame, start_pc + 0x14, buf, buflen)) return 0; /* Check for sigreturn(2) (again). */ if (memcmp (buf, sigreturn, buflen) == 0) return 1; return 0; }
static CORE_ADDR i386syl_sigtramp_start (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); unsigned char buf[SYL_SIGTRAMP_LEN]; /* We only recognize a signal trampoline if PC is at the start of one of the three instructions. We optimize for finding the PC at the start, as will be the case when the trampoline is not the first frame on the stack. We assume that in the case where the PC is not at the start of the instruction sequence, there will be a few trailing readable bytes on the stack. */ if (!safe_frame_unwind_memory (next_frame, pc, buf, SYL_SIGTRAMP_LEN)) return 0; if (buf[0] != SYL_SIGTRAMP_INSN0) { int adjust; switch (buf[0]) { case SYL_SIGTRAMP_INSN1: adjust = SYL_SIGTRAMP_OFFSET1; break; case SYL_SIGTRAMP_INSN2: adjust = SYL_SIGTRAMP_OFFSET2; break; default: return 0; } pc -= adjust; if (!safe_frame_unwind_memory (next_frame, pc, buf, SYL_SIGTRAMP_LEN)) return 0; } if (memcmp (buf, syllable_sigtramp_code, SYL_SIGTRAMP_LEN) != 0) return 0; return pc; }
static int amd64_linux_sigtramp_p (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); char *name; find_pc_partial_function (pc, &name, NULL, NULL); /* If we have NAME, we can optimize the search. The trampoline is named __restore_rt. However, it isn't dynamically exported from the shared C library, so the trampoline may appear to be part of the preceding function. This should always be sigaction, __sigaction, or __libc_sigaction (all aliases to the same function). */ if (name == NULL || strstr (name, "sigaction") != NULL) return (amd64_linux_sigtramp_start (next_frame) != 0); return (strcmp ("__restore_rt", name) == 0); }
static int amd64obsd_trapframe_sniffer (const struct frame_unwind *self, struct frame_info *next_frame, void **this_prologue_cache) { ULONGEST cs; char *name; /* Check Current Privilege Level and bail out if we're not executing in kernel space. */ cs = frame_unwind_register_unsigned (next_frame, AMD64_CS_REGNUM); if ((cs & I386_SEL_RPL) == I386_SEL_UPL) return 0; find_pc_partial_function (frame_pc_unwind (next_frame), &name, NULL, NULL); return (name && ((strcmp (name, "calltrap") == 0) || (strcmp (name, "osyscall1") == 0) || (strcmp (name, "Xsyscall") == 0) || (strncmp (name, "Xintr", 5) == 0))); }