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 CORE_ADDR i386_linux_rt_sigtramp_start (struct frame_info *this_frame) { CORE_ADDR pc = get_frame_pc (this_frame); gdb_byte buf[LINUX_RT_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 (this_frame, pc, buf, LINUX_RT_SIGTRAMP_LEN)) return 0; if (buf[0] != LINUX_RT_SIGTRAMP_INSN0) { if (buf[0] != LINUX_RT_SIGTRAMP_INSN1) return 0; pc -= LINUX_RT_SIGTRAMP_OFFSET1; if (!safe_frame_unwind_memory (this_frame, pc, buf, LINUX_RT_SIGTRAMP_LEN)) return 0; } if (memcmp (buf, linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN) != 0) return 0; return pc; }
static CORE_ADDR m32r_linux_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame) { gdb_byte buf[4]; /* We only recognize a signal trampoline if PC is at the start of one of the instructions. We optimize for finding the PC at the start of the instruction sequence, 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 (pc % 2 != 0) { if (!safe_frame_unwind_memory (next_frame, pc, buf, 2)) return 0; if (memcmp (buf, linux_sigtramp_code, 2) == 0) pc -= 2; else return 0; } if (!safe_frame_unwind_memory (next_frame, pc, buf, 4)) return 0; if (memcmp (buf, linux_sigtramp_code, 4) != 0) return 0; return pc; }
static int i386fbsd_sigtramp_p (struct frame_info *this_frame) { CORE_ADDR pc = get_frame_pc (this_frame); gdb_byte buf[sizeof i386fbsd_sigtramp_middle]; const gdb_byte *middle, *end; /* Look for a matching start. */ if (!safe_frame_unwind_memory (this_frame, pc, buf, sizeof i386fbsd_sigtramp_start)) return 0; if (memcmp (buf, i386fbsd_sigtramp_start, sizeof i386fbsd_sigtramp_start) == 0) { middle = i386fbsd_sigtramp_middle; end = i386fbsd_sigtramp_end; } else if (memcmp (buf, i386fbsd_freebsd4_sigtramp_start, sizeof i386fbsd_freebsd4_sigtramp_start) == 0) { middle = i386fbsd_freebsd4_sigtramp_middle; end = i386fbsd_freebsd4_sigtramp_end; } else if (memcmp (buf, i386fbsd_osigtramp_start, sizeof i386fbsd_osigtramp_start) == 0) { middle = i386fbsd_osigtramp_middle; end = i386fbsd_osigtramp_end; } else return 0; /* Since the end is shorter than the middle, check for a matching end next. */ pc += sizeof i386fbsd_sigtramp_start; if (!safe_frame_unwind_memory (this_frame, pc, buf, sizeof i386fbsd_sigtramp_end)) return 0; if (memcmp (buf, end, sizeof i386fbsd_sigtramp_end) == 0) return 1; /* If the end didn't match, check for a matching middle. */ if (!safe_frame_unwind_memory (this_frame, pc, buf, sizeof i386fbsd_sigtramp_middle)) return 0; if (memcmp (buf, middle, sizeof i386fbsd_sigtramp_middle) != 0) return 0; /* The middle matched, check for a matching end. */ pc += sizeof i386fbsd_sigtramp_middle; if (!safe_frame_unwind_memory (this_frame, pc, buf, sizeof i386fbsd_sigtramp_end)) return 0; if (memcmp (buf, end, sizeof i386fbsd_sigtramp_end) != 0) return 0; return 1; }
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 CORE_ADDR tramp_frame_start (const struct tramp_frame *tramp, struct frame_info *this_frame, CORE_ADDR pc) { int ti; /* Search through the trampoline for one that matches the instruction sequence around PC. */ for (ti = 0; tramp->insn[ti].bytes != TRAMP_SENTINEL_INSN; ti++) { CORE_ADDR func = pc - tramp->insn_size * ti; int i; for (i = 0; 1; i++) { gdb_byte buf[sizeof (tramp->insn[0])]; ULONGEST insn; if (tramp->insn[i].bytes == TRAMP_SENTINEL_INSN) return func; if (!safe_frame_unwind_memory (this_frame, func + i * tramp->insn_size, buf, tramp->insn_size)) break; insn = extract_unsigned_integer (buf, tramp->insn_size); if (tramp->insn[i].bytes != (insn & tramp->insn[i].mask)) break; } } /* Trampoline doesn't match. */ return 0; }
static int vaxobsd_sigtramp_sniffer (const struct frame_unwind *self, struct frame_info *this_frame, void **this_cache) { CORE_ADDR pc = get_frame_pc (this_frame); CORE_ADDR start_pc = (pc & ~(vaxobsd_page_size - 1)); CORE_ADDR sigreturn_addr = start_pc + vaxobsd_sigreturn_offset; gdb_byte *buf; const char *name; find_pc_partial_function (pc, &name, NULL, NULL); if (name) return 0; buf = alloca(sizeof vaxobsd_sigreturn); if (!safe_frame_unwind_memory (this_frame, sigreturn_addr, buf, sizeof vaxobsd_sigreturn)) return 0; if (memcmp(buf, vaxobsd_sigreturn, sizeof vaxobsd_sigreturn) == 0) return 1; return 0; }
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 struct trad_frame_cache * ppcobsd_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache) { struct gdbarch *gdbarch = get_frame_arch (this_frame); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order = gdbarch_byte_order (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 (struct trad_frame_cache *) *this_cache; cache = trad_frame_cache_zalloc (this_frame); *this_cache = cache; func = get_frame_pc (this_frame); func &= ~(ppcobsd_page_size - 1); if (!safe_frame_unwind_memory (this_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, byte_order); sigcontext_offset = (0x10000 - (insn & 0x0000ffff)) + 8; base = get_frame_register_unsigned (this_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 int ppcfbsd_sigtramp_frame_sniffer (const struct frame_unwind *self, struct frame_info *this_frame, void **this_cache) { struct gdbarch *gdbarch = get_frame_arch(this_frame); enum bfd_endian byte_order = (enum bfd_endian)gdbarch_byte_order(gdbarch); CORE_ADDR pc = get_frame_pc(this_frame); CORE_ADDR start_pc = (pc & ~(ppcfbsd_page_size - 1)); const int *offset; const char *name; /* A stack trampoline is detected if no name is associated to the current pc and if it points inside a trampoline sequence. */ find_pc_partial_function (pc, &name, NULL, NULL); /* If we have a name, we have no trampoline, return. */ if (name) return 0; for (offset = ppcfbsd_sigreturn_offset; *offset != -1; offset++) { #ifdef PPC_INSN_SIZE gdb_byte buf[2 * PPC_INSN_SIZE]; #else gdb_byte buf[2 * sizeof(unsigned long)]; #endif /* PPC_INSN_SIZE */ unsigned long insn; if (!safe_frame_unwind_memory (this_frame, start_pc + *offset, buf, sizeof buf)) continue; /* Check for "li r0,SYS_sigreturn". */ insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order); if (insn != 0x380001a1) continue; /* Check for "sc". */ insn = extract_unsigned_integer (buf + PPC_INSN_SIZE, PPC_INSN_SIZE, byte_order); if (insn != 0x44000002) continue; return 1; } return 0; }
static int amd64obsd_sigtramp_p (struct frame_info *this_frame) { CORE_ADDR pc = get_frame_pc (this_frame); CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1)); const gdb_byte osigreturn[] = { 0x48, 0xc7, 0xc0, 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ 0xcd, 0x80 /* int $0x80 */ }; const gdb_byte sigreturn[] = { 0x48, 0xc7, 0xc0, 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ 0x0f, 0x05 /* syscall */ }; size_t buflen = (sizeof sigreturn) + 1; gdb_byte *buf; const char *name; /* 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; /* If we can't read the instructions at START_PC, return zero. */ buf = (gdb_byte *) alloca ((sizeof sigreturn) + 1); if (!safe_frame_unwind_memory (this_frame, start_pc + 6, buf, buflen)) return 0; /* Check for sigreturn(2). Depending on how the assembler encoded the `movq %rsp, %rdi' instruction, the code starts at offset 6 or 7. OpenBSD 5.0 and later use the `syscall' instruction. Older versions use `int $0x80'. Check for both. */ if (memcmp (buf, sigreturn, sizeof sigreturn) && memcmp (buf + 1, sigreturn, sizeof sigreturn) && memcmp (buf, osigreturn, sizeof osigreturn) && memcmp (buf + 1, osigreturn, sizeof osigreturn)) return 0; return 1; }
static int i386obsd_sigtramp_p (struct frame_info *this_frame) { CORE_ADDR pc = get_frame_pc (this_frame); CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1)); /* The call sequence invoking sigreturn(2). */ const gdb_byte sigreturn[] = { 0xb8, 0x67, 0x00, 0x00, 0x00, /* movl $SYS_sigreturn, %eax */ 0xcd, 0x80 /* int $0x80 */ }; size_t buflen = sizeof sigreturn; const int *offset; gdb_byte *buf; const char *name; /* 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); /* Loop over all offsets. */ for (offset = i386obsd_sigreturn_offset; *offset != -1; offset++) { /* If we can't read the instructions, return zero. */ if (!safe_frame_unwind_memory (this_frame, start_pc + *offset, buf, buflen)) return 0; /* Check for sigreturn(2). */ if (memcmp (buf, sigreturn, buflen) == 0) return 1; } return 0; }
static struct trad_frame_cache * ppcfbsd_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache) { struct gdbarch *gdbarch = get_frame_arch (this_frame); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); struct trad_frame_cache *cache; CORE_ADDR addr, base, func; gdb_byte buf[PPC_INSN_SIZE]; int i; if (*this_cache) return *this_cache; cache = trad_frame_cache_zalloc (this_frame); *this_cache = cache; func = get_frame_pc (this_frame); func &= ~(ppcfbsd_page_size - 1); if (!safe_frame_unwind_memory (this_frame, func, buf, sizeof buf)) return cache; base = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch)); addr = base + 0x10 + 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 int ppcobsd_sigtramp_frame_sniffer (const struct frame_unwind *self, struct frame_info *this_frame, void **this_cache) { struct gdbarch *gdbarch = get_frame_arch (this_frame); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR pc = get_frame_pc (this_frame); CORE_ADDR start_pc = (pc & ~(ppcobsd_page_size - 1)); const int *offset; const char *name; find_pc_partial_function (pc, &name, NULL, NULL); if (name) return 0; for (offset = ppcobsd_sigreturn_offset; *offset != -1; offset++) { gdb_byte buf[2 * PPC_INSN_SIZE]; unsigned long insn; if (!safe_frame_unwind_memory (this_frame, start_pc + *offset, buf, sizeof buf)) continue; /* Check for "li r0,SYS_sigreturn". */ insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order); if (insn != 0x38000067) continue; /* Check for "sc". */ insn = extract_unsigned_integer (buf + PPC_INSN_SIZE, PPC_INSN_SIZE, byte_order); if (insn != 0x44000002) continue; return 1; } return 0; }
static CORE_ADDR tramp_frame_start (const struct tramp_frame *tramp, struct frame_info *this_frame, CORE_ADDR pc) { struct gdbarch *gdbarch = get_frame_arch (this_frame); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int ti; /* Check if we can use this trampoline. */ if (tramp->validate && !tramp->validate (tramp, this_frame, &pc)) return 0; /* Search through the trampoline for one that matches the instruction sequence around PC. */ for (ti = 0; tramp->insn[ti].bytes != TRAMP_SENTINEL_INSN; ti++) { CORE_ADDR func = pc - tramp->insn_size * ti; int i; for (i = 0; 1; i++) { gdb_byte buf[sizeof (tramp->insn[0])]; ULONGEST insn; if (tramp->insn[i].bytes == TRAMP_SENTINEL_INSN) return func; if (!safe_frame_unwind_memory (this_frame, func + i * tramp->insn_size, buf, tramp->insn_size)) break; insn = extract_unsigned_integer (buf, tramp->insn_size, byte_order); if (tramp->insn[i].bytes != (insn & tramp->insn[i].mask)) break; } } /* Trampoline doesn't match. */ return 0; }
static int vaxobsd_sigtramp_p (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); CORE_ADDR start_pc = (pc & ~(vaxobsd_page_size - 1)); CORE_ADDR sigreturn_addr = start_pc + vaxobsd_sigreturn_offset; gdb_byte *buf; char *name; find_pc_partial_function (pc, &name, NULL, NULL); if (name) return 0; buf = alloca(sizeof vaxobsd_sigreturn); if (!safe_frame_unwind_memory (next_frame, sigreturn_addr, buf, sizeof vaxobsd_sigreturn)) return 0; if (memcmp(buf, vaxobsd_sigreturn, sizeof vaxobsd_sigreturn) == 0) return 1; return 0; }
static int ppcobsd_sigtramp_p (struct frame_info *next_frame) { CORE_ADDR pc = frame_pc_unwind (next_frame); CORE_ADDR start_pc = (pc & ~(ppcobsd_page_size - 1)); const int *offset; char *name; find_pc_partial_function (pc, &name, NULL, NULL); if (name) return 0; for (offset = ppcobsd_sigreturn_offset; *offset != -1; offset++) { gdb_byte buf[2 * PPC_INSN_SIZE]; unsigned long insn; if (!safe_frame_unwind_memory (next_frame, start_pc + *offset, buf, sizeof buf)) continue; /* Check for "li r0,SYS_sigreturn". */ insn = extract_unsigned_integer (buf, PPC_INSN_SIZE); if (insn != 0x38000067) continue; /* Check for "sc". */ insn = extract_unsigned_integer (buf + PPC_INSN_SIZE, PPC_INSN_SIZE); if (insn != 0x44000002) continue; return 1; } return 0; }
static CORE_ADDR mn10300_analyze_prologue (struct frame_info *fi, void **this_cache, CORE_ADDR pc) { CORE_ADDR func_addr, func_end, addr, stop; long stack_extra_size = 0; int imm_size; unsigned char buf[4]; int status; int movm_args = 0; int fpregmask = 0; char *name; int frame_in_fp = 0; /* Use the PC in the frame if it's provided to look up the start of this function. Note: kevinb/2003-07-16: We used to do the following here: pc = (fi ? get_frame_pc (fi) : pc); But this is (now) badly broken when called from analyze_dummy_frame(). */ if (fi) { pc = (pc ? pc : get_frame_pc (fi)); } /* Find the start of this function. */ status = find_pc_partial_function (pc, &name, &func_addr, &func_end); /* Do nothing if we couldn't find the start of this function MVS: comment went on to say "or if we're stopped at the first instruction in the prologue" -- but code doesn't reflect that, and I don't want to do that anyway. */ if (status == 0) { addr = pc; goto finish_prologue; } /* If we're in start, then give up. */ if (strcmp (name, "start") == 0) { addr = pc; goto finish_prologue; } /* Figure out where to stop scanning. */ stop = fi ? pc : func_end; /* Don't walk off the end of the function. */ stop = stop > func_end ? func_end : stop; /* Start scanning on the first instruction of this function. */ addr = func_addr; /* Suck in two bytes. */ if (addr + 2 > stop || !safe_frame_unwind_memory (fi, addr, buf, 2)) goto finish_prologue; /* First see if this insn sets the stack pointer from a register; if so, it's probably the initialization of the stack pointer in _start, so mark this as the bottom-most frame. */ if (buf[0] == 0xf2 && (buf[1] & 0xf3) == 0xf0) { goto finish_prologue; } /* Now look for movm [regs],sp, which saves the callee saved registers. At this time we don't know if fi->frame is valid, so we only note that we encountered a movm instruction. Later, we'll set the entries in fsr.regs as needed. */ if (buf[0] == 0xcf) { /* Extract the register list for the movm instruction. */ movm_args = buf[1]; addr += 2; /* Quit now if we're beyond the stop point. */ if (addr >= stop) goto finish_prologue; /* Get the next two bytes so the prologue scan can continue. */ if (!safe_frame_unwind_memory (fi, addr, buf, 2)) goto finish_prologue; } if (AM33_MODE == 2) { /* Determine if any floating point registers are to be saved. Look for one of the following three prologue formats: [movm [regs],(sp)] [movm [regs],(sp)] [movm [regs],(sp)] add -SIZE,sp add -SIZE,sp add -SIZE,sp fmov fs#,(sp) mov sp,a0/a1 mov sp,a0/a1 fmov fs#,(#,sp) fmov fs#,(a0/a1+) add SIZE2,a0/a1 ... ... fmov fs#,(a0/a1+) ... ... ... fmov fs#,(#,sp) fmov fs#,(a0/a1+) fmov fs#,(a0/a1+) [mov sp,a3] [mov sp,a3] [add -SIZE2,sp] [add -SIZE2,sp] */ /* First, look for add -SIZE,sp (i.e. add imm8,sp (0xf8feXX) or add imm16,sp (0xfafeXXXX) or add imm32,sp (0xfcfeXXXXXXXX)) */ imm_size = 0; if (buf[0] == 0xf8 && buf[1] == 0xfe) imm_size = 1; else if (buf[0] == 0xfa && buf[1] == 0xfe) imm_size = 2; else if (buf[0] == 0xfc && buf[1] == 0xfe) imm_size = 4; if (imm_size != 0) { /* An "add -#,sp" instruction has been found. "addr + 2 + imm_size" is the address of the next instruction. Don't modify "addr" until the next "floating point prologue" instruction is found. If this is not a prologue that saves floating point registers we need to be able to back out of this bit of code and continue with the prologue analysis. */ if (addr + 2 + imm_size < stop) { if (!safe_frame_unwind_memory (fi, addr + 2 + imm_size, buf, 3)) goto finish_prologue; if ((buf[0] & 0xfc) == 0x3c) { /* Occasionally, especially with C++ code, the "fmov" instructions will be preceded by "mov sp,aN" (aN => a0, a1, a2, or a3). This is a one byte instruction: mov sp,aN = 0011 11XX where XX is the register number. Skip this instruction by incrementing addr. (We're committed now.) The "fmov" instructions will have the form "fmov fs#,(aN+)" in this case, but that will not necessitate a change in the "fmov" parsing logic below. */ addr++; if ((buf[1] & 0xfc) == 0x20) { /* Occasionally, especially with C++ code compiled with the -fomit-frame-pointer or -O3 options, the "mov sp,aN" instruction will be followed by an "add #,aN" instruction. This indicates the "stack_size", the size of the portion of the stack containing the arguments. This instruction format is: add #,aN = 0010 00XX YYYY YYYY where XX is the register number YYYY YYYY is the constant. Note the size of the stack (as a negative number) in the frame info structure. */ if (fi) stack_extra_size += -buf[2]; addr += 2; } } if ((buf[0] & 0xfc) == 0x3c || buf[0] == 0xf9 || buf[0] == 0xfb) { /* An "fmov" instruction has been found indicating that this prologue saves floating point registers (or, as described above, a "mov sp,aN" and possible "add #,aN" have been found and we will assume an "fmov" follows). Process the consecutive "fmov" instructions. */ for (addr += 2 + imm_size;;addr += imm_size) { int regnum; /* Read the "fmov" instruction. */ if (addr >= stop || !safe_frame_unwind_memory (fi, addr, buf, 4)) goto finish_prologue; if (buf[0] != 0xf9 && buf[0] != 0xfb) break; /* Get the floating point register number from the 2nd and 3rd bytes of the "fmov" instruction: Machine Code: 0000 00X0 YYYY 0000 => Regnum: 000X YYYY */ regnum = (buf[1] & 0x02) << 3; regnum |= ((buf[2] & 0xf0) >> 4) & 0x0f; /* Add this register number to the bit mask of floating point registers that have been saved. */ fpregmask |= 1 << regnum; /* Determine the length of this "fmov" instruction. fmov fs#,(sp) => 3 byte instruction fmov fs#,(#,sp) => 4 byte instruction */ imm_size = (buf[0] == 0xf9) ? 3 : 4; } } else { /* No "fmov" was found. Reread the two bytes at the original "addr" to reset the state. */ if (!safe_frame_unwind_memory (fi, addr, buf, 2)) goto finish_prologue; } } /* else the prologue consists entirely of an "add -SIZE,sp" instruction. Handle this below. */ }
static CORE_ADDR tilegx_analyze_prologue (struct gdbarch* gdbarch, CORE_ADDR start_addr, CORE_ADDR end_addr, struct tilegx_frame_cache *cache, struct frame_info *next_frame) { enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR next_addr; CORE_ADDR prolog_end = end_addr; gdb_byte instbuf[32 * TILEGX_BUNDLE_SIZE_IN_BYTES]; CORE_ADDR instbuf_start; unsigned int instbuf_size; int status; bfd_uint64_t bundle; struct tilegx_decoded_instruction decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]; int num_insns; struct tilegx_reverse_regs reverse_frame[TILEGX_NUM_PHYS_REGS]; struct tilegx_reverse_regs new_reverse_frame[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]; int dest_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]; int reverse_frame_valid, prolog_done, branch_seen, lr_saved_on_stack_p; LONGEST prev_sp_value; int i, j; if (start_addr >= end_addr || (start_addr % TILEGX_BUNDLE_ALIGNMENT_IN_BYTES) != 0) return end_addr; /* Initialize the reverse frame. This maps the CURRENT frame's registers to the outer frame's registers (the frame on the stack goes the other way). */ memcpy (&reverse_frame, &template_reverse_regs, sizeof (reverse_frame)); prolog_done = 0; branch_seen = 0; prev_sp_value = 0; lr_saved_on_stack_p = 0; /* To cut down on round-trip overhead, we fetch multiple bundles at once. These variables describe the range of memory we have prefetched. */ instbuf_start = 0; instbuf_size = 0; for (next_addr = start_addr; next_addr < end_addr; next_addr += TILEGX_BUNDLE_SIZE_IN_BYTES) { /* Retrieve the next instruction. */ if (next_addr - instbuf_start >= instbuf_size) { /* Figure out how many bytes to fetch. Don't span a page boundary since that might cause an unnecessary memory error. */ unsigned int size_on_same_page = 4096 - (next_addr & 4095); instbuf_size = sizeof instbuf; if (instbuf_size > size_on_same_page) instbuf_size = size_on_same_page; instbuf_size = min (instbuf_size, (end_addr - next_addr)); instbuf_start = next_addr; status = safe_frame_unwind_memory (next_frame, instbuf_start, instbuf, instbuf_size); if (status == 0) memory_error (TARGET_XFER_E_IO, next_addr); } reverse_frame_valid = 0; bundle = extract_unsigned_integer (&instbuf[next_addr - instbuf_start], 8, byte_order); num_insns = parse_insn_tilegx (bundle, next_addr, decoded); for (i = 0; i < num_insns; i++) { struct tilegx_decoded_instruction *this_insn = &decoded[i]; int64_t *operands = (int64_t *) this_insn->operand_values; const struct tilegx_opcode *opcode = this_insn->opcode; switch (opcode->mnemonic) { case TILEGX_OPC_ST: if (cache && reverse_frame[operands[0]].state == REVERSE_STATE_VALUE && reverse_frame[operands[1]].state == REVERSE_STATE_REGISTER) { LONGEST saved_address = reverse_frame[operands[0]].value; unsigned saved_register = (unsigned) reverse_frame[operands[1]].value; /* realreg >= 0 and addr != -1 indicates that the value of saved_register is in memory location saved_address. The value of realreg is not meaningful in this case but it must be >= 0. See trad-frame.h. */ cache->saved_regs[saved_register].realreg = saved_register; cache->saved_regs[saved_register].addr = saved_address; } else if (cache && (operands[0] == TILEGX_SP_REGNUM) && (operands[1] == TILEGX_LR_REGNUM)) lr_saved_on_stack_p = 1; break; case TILEGX_OPC_ADDI: case TILEGX_OPC_ADDLI: if (cache && operands[0] == TILEGX_SP_REGNUM && operands[1] == TILEGX_SP_REGNUM && reverse_frame[operands[1]].state == REVERSE_STATE_REGISTER) { /* Special case. We're fixing up the stack frame. */ uint64_t hopefully_sp = (unsigned) reverse_frame[operands[1]].value; short op2_as_short = (short) operands[2]; signed char op2_as_char = (signed char) operands[2]; /* Fix up the sign-extension. */ if (opcode->mnemonic == TILEGX_OPC_ADDI) op2_as_short = op2_as_char; prev_sp_value = (cache->saved_regs[hopefully_sp].addr - op2_as_short); new_reverse_frame[i].state = REVERSE_STATE_VALUE; new_reverse_frame[i].value = cache->saved_regs[hopefully_sp].addr; trad_frame_set_value (cache->saved_regs, hopefully_sp, prev_sp_value); } else { short op2_as_short = (short) operands[2]; signed char op2_as_char = (signed char) operands[2]; /* Fix up the sign-extension. */ if (opcode->mnemonic == TILEGX_OPC_ADDI) op2_as_short = op2_as_char; new_reverse_frame[i] = reverse_frame[operands[1]]; if (new_reverse_frame[i].state == REVERSE_STATE_VALUE) new_reverse_frame[i].value += op2_as_short; else new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN; } reverse_frame_valid |= 1 << i; dest_regs[i] = operands[0]; break; case TILEGX_OPC_ADD: if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE) { /* We have values -- we can do this. */ new_reverse_frame[i] = reverse_frame[operands[2]]; new_reverse_frame[i].value += reverse_frame[operands[i]].value; } else { /* We don't know anything about the values. Punt. */ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN; } reverse_frame_valid |= 1 << i; dest_regs[i] = operands[0]; break; case TILEGX_OPC_MOVE: new_reverse_frame[i] = reverse_frame[operands[1]]; reverse_frame_valid |= 1 << i; dest_regs[i] = operands[0]; break; case TILEGX_OPC_MOVEI: case TILEGX_OPC_MOVELI: new_reverse_frame[i].state = REVERSE_STATE_VALUE; new_reverse_frame[i].value = operands[1]; reverse_frame_valid |= 1 << i; dest_regs[i] = operands[0]; break; case TILEGX_OPC_ORI: if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE) { /* We have a value in A -- we can do this. */ new_reverse_frame[i] = reverse_frame[operands[1]]; new_reverse_frame[i].value = reverse_frame[operands[1]].value | operands[2]; } else if (operands[2] == 0) { /* This is a move. */ new_reverse_frame[i] = reverse_frame[operands[1]]; } else { /* We don't know anything about the values. Punt. */ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN; } reverse_frame_valid |= 1 << i; dest_regs[i] = operands[0]; break; case TILEGX_OPC_OR: if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE && reverse_frame[operands[1]].value == 0) { /* This is a move. */ new_reverse_frame[i] = reverse_frame[operands[2]]; } else if (reverse_frame[operands[2]].state == REVERSE_STATE_VALUE && reverse_frame[operands[2]].value == 0) { /* This is a move. */ new_reverse_frame[i] = reverse_frame[operands[1]]; } else { /* We don't know anything about the values. Punt. */ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN; } reverse_frame_valid |= 1 << i; dest_regs[i] = operands[0]; break; case TILEGX_OPC_SUB: if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE) { /* We have values -- we can do this. */ new_reverse_frame[i] = reverse_frame[operands[1]]; new_reverse_frame[i].value -= reverse_frame[operands[2]].value; } else { /* We don't know anything about the values. Punt. */ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN; } reverse_frame_valid |= 1 << i; dest_regs[i] = operands[0]; break; case TILEGX_OPC_FNOP: case TILEGX_OPC_INFO: case TILEGX_OPC_INFOL: /* Nothing to see here, move on. Note that real NOP is treated as a 'real' instruction because someone must have intended that it be there. It therefore terminates the prolog. */ break; case TILEGX_OPC_J: case TILEGX_OPC_JAL: case TILEGX_OPC_BEQZ: case TILEGX_OPC_BEQZT: case TILEGX_OPC_BGEZ: case TILEGX_OPC_BGEZT: case TILEGX_OPC_BGTZ: case TILEGX_OPC_BGTZT: case TILEGX_OPC_BLBC: case TILEGX_OPC_BLBCT: case TILEGX_OPC_BLBS: case TILEGX_OPC_BLBST: case TILEGX_OPC_BLEZ: case TILEGX_OPC_BLEZT: case TILEGX_OPC_BLTZ: case TILEGX_OPC_BLTZT: case TILEGX_OPC_BNEZ: case TILEGX_OPC_BNEZT: case TILEGX_OPC_IRET: case TILEGX_OPC_JALR: case TILEGX_OPC_JALRP: case TILEGX_OPC_JR: case TILEGX_OPC_JRP: case TILEGX_OPC_SWINT0: case TILEGX_OPC_SWINT1: case TILEGX_OPC_SWINT2: case TILEGX_OPC_SWINT3: /* We're really done -- this is a branch. */ branch_seen = 1; prolog_done = 1; break; default: /* We don't know or care what this instruction is. All we know is that it isn't part of a prolog, and if there's a destination register, we're trashing it. */ prolog_done = 1; for (j = 0; j < opcode->num_operands; j++) { if (this_insn->operands[j]->is_dest_reg) { dest_regs[i] = operands[j]; new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN; reverse_frame_valid |= 1 << i; break; } } break; } } /* Now update the reverse frames. */ for (i = 0; i < num_insns; i++) { /* ISSUE: Does this properly handle "network" registers? */ if ((reverse_frame_valid & (1 << i)) && dest_regs[i] != TILEGX_ZERO_REGNUM) reverse_frame[dest_regs[i]] = new_reverse_frame[i]; } if (prev_sp_value != 0) { /* GCC uses R52 as a frame pointer. Have we seen "move r52, sp"? */ if (reverse_frame[TILEGX_R52_REGNUM].state == REVERSE_STATE_REGISTER && reverse_frame[TILEGX_R52_REGNUM].value == TILEGX_SP_REGNUM) { reverse_frame[TILEGX_R52_REGNUM].state = REVERSE_STATE_VALUE; reverse_frame[TILEGX_R52_REGNUM].value = prev_sp_value; } prev_sp_value = 0; } if (prolog_done && prolog_end == end_addr) { /* We found non-prolog code. As such, _this_ instruction is the one after the prolog. We keep processing, because there may be more prolog code in there, but this is what we'll return. */ /* ISSUE: There may not have actually been a prologue, and we may have simply skipped some random instructions. */ prolog_end = next_addr; } if (branch_seen) { /* We saw a branch. The prolog absolutely must be over. */ break; } } if (prolog_end == end_addr && cache) { /* We may have terminated the prolog early, and we're certainly at THIS point right now. It's possible that the values of registers we need are currently actually in other registers (and haven't been written to memory yet). Go find them. */ for (i = 0; i < TILEGX_NUM_PHYS_REGS; i++) { if (reverse_frame[i].state == REVERSE_STATE_REGISTER && reverse_frame[i].value != i) { unsigned saved_register = (unsigned) reverse_frame[i].value; cache->saved_regs[saved_register].realreg = i; cache->saved_regs[saved_register].addr = (LONGEST) -1; } } } if (lr_saved_on_stack_p) { cache->saved_regs[TILEGX_LR_REGNUM].realreg = TILEGX_LR_REGNUM; cache->saved_regs[TILEGX_LR_REGNUM].addr = cache->saved_regs[TILEGX_SP_REGNUM].addr; } return prolog_end; }