/* Adjust a breakpoint's address to account for the FR-V architecture's constraint that a break instruction must not appear as any but the first instruction in the bundle. */ static CORE_ADDR frv_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr) { int count = max_instrs_per_bundle; CORE_ADDR addr = bpaddr - frv_instr_size; CORE_ADDR func_start = get_pc_function_start (bpaddr); /* Find the end of the previous packing sequence. This will be indicated by either attempting to access some inaccessible memory or by finding an instruction word whose packing bit is set to one. */ while (count-- > 0 && addr >= func_start) { gdb_byte instr[frv_instr_size]; int status; status = target_read_memory (addr, instr, sizeof instr); if (status != 0) break; /* This is a big endian architecture, so byte zero will have most significant byte. The most significant bit of this byte is the packing bit. */ if (instr[0] & 0x80) break; addr -= frv_instr_size; } if (count > 0) bpaddr = addr + frv_instr_size; return bpaddr; }
int frameless_look_for_prologue (struct frame_info *frame) { CORE_ADDR func_start, after_prologue; func_start = get_pc_function_start (frame->pc); if (func_start) { func_start += FUNCTION_START_OFFSET; /* This is faster, since only care whether there *is* a prologue, not how long it is. */ return PROLOGUE_FRAMELESS_P (func_start); } else if (frame->pc == 0) /* A frame with a zero PC is usually created by dereferencing a NULL function pointer, normally causing an immediate core dump of the inferior. Mark function as frameless, as the inferior has no chance of setting up a stack frame. */ return 1; else /* If we can't find the start of the function, we don't really know whether the function is frameless, but we should be able to get a reasonable (i.e. best we can do under the circumstances) backtrace by saying that it isn't. */ return 0; }
void frame_find_saved_regs (struct frame_info *frame_info, struct frame_saved_regs *frame_saved_regs) { register int regnum; register int regmask; register CORE_ADDR next_addr; register CORE_ADDR pc; unsigned char thebyte; memset (frame_saved_regs, '\0', sizeof *frame_saved_regs); if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 4 && (frame_info)->pc <= (frame_info)->frame) { next_addr = (frame_info)->frame; pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 4; } else { pc = get_pc_function_start ((frame_info)->pc); /* Verify we have a link a6 instruction next; if not we lose. If we win, find the address above the saved regs using the amount of storage from the link instruction. */ thebyte = read_memory_integer (pc, 1); if (0x1f == thebyte) next_addr = (frame_info)->frame + read_memory_integer (pc += 1, 2), pc += 2; else if (0x17 == thebyte) next_addr = (frame_info)->frame + read_memory_integer (pc += 1, 1), pc += 1; else goto lose; #if 0 /* FIXME steve */ /* If have an add:g.waddal #-n, sp next, adjust next_addr. */ if ((0x0c0177777 & read_memory_integer (pc, 2)) == 0157774) next_addr += read_memory_integer (pc += 2, 4), pc += 4; #endif } thebyte = read_memory_integer (pc, 1); if (thebyte == 0x12) { /* Got stm */ pc++; regmask = read_memory_integer (pc, 1); pc++; for (regnum = 0; regnum < 8; regnum++, regmask >>= 1) { if (regmask & 1) { (frame_saved_regs)->regs[regnum] = (next_addr += 2) - 2; } } thebyte = read_memory_integer (pc, 1); }
static struct btrace_function * ftrace_update_function (struct btrace_function *bfun, CORE_ADDR pc) { struct bound_minimal_symbol bmfun; struct minimal_symbol *mfun; struct symbol *fun; struct btrace_insn *last; /* Try to determine the function we're in. We use both types of symbols to avoid surprises when we sometimes get a full symbol and sometimes only a minimal symbol. */ fun = find_pc_function (pc); bmfun = lookup_minimal_symbol_by_pc (pc); mfun = bmfun.minsym; if (fun == NULL && mfun == NULL) DEBUG_FTRACE ("no symbol at %s", core_addr_to_string_nz (pc)); /* If we didn't have a function or if we had a gap before, we create one. */ if (bfun == NULL || bfun->errcode != 0) return ftrace_new_function (bfun, mfun, fun); /* Check the last instruction, if we have one. We do this check first, since it allows us to fill in the call stack links in addition to the normal flow links. */ last = NULL; if (!VEC_empty (btrace_insn_s, bfun->insn)) last = VEC_last (btrace_insn_s, bfun->insn); if (last != NULL) { switch (last->iclass) { case BTRACE_INSN_RETURN: { const char *fname; /* On some systems, _dl_runtime_resolve returns to the resolved function instead of jumping to it. From our perspective, however, this is a tailcall. If we treated it as return, we wouldn't be able to find the resolved function in our stack back trace. Hence, we would lose the current stack back trace and start anew with an empty back trace. When the resolved function returns, we would then create a stack back trace with the same function names but different frame id's. This will confuse stepping. */ fname = ftrace_print_function_name (bfun); if (strcmp (fname, "_dl_runtime_resolve") == 0) return ftrace_new_tailcall (bfun, mfun, fun); return ftrace_new_return (bfun, mfun, fun); } case BTRACE_INSN_CALL: /* Ignore calls to the next instruction. They are used for PIC. */ if (last->pc + last->size == pc) break; return ftrace_new_call (bfun, mfun, fun); case BTRACE_INSN_JUMP: { CORE_ADDR start; start = get_pc_function_start (pc); /* If we can't determine the function for PC, we treat a jump at the end of the block as tail call. */ if (start == 0 || start == pc) return ftrace_new_tailcall (bfun, mfun, fun); } } } /* Check if we're switching functions for some other reason. */ if (ftrace_function_switched (bfun, mfun, fun)) { DEBUG_FTRACE ("switching from %s in %s at %s", ftrace_print_insn_addr (last), ftrace_print_function_name (bfun), ftrace_print_filename (bfun)); return ftrace_new_switch (bfun, mfun, fun); } return bfun; }
static struct btrace_function * ftrace_update_function (struct gdbarch *gdbarch, struct btrace_function *bfun, CORE_ADDR pc) { struct bound_minimal_symbol bmfun; struct minimal_symbol *mfun; struct symbol *fun; struct btrace_insn *last; /* Try to determine the function we're in. We use both types of symbols to avoid surprises when we sometimes get a full symbol and sometimes only a minimal symbol. */ fun = find_pc_function (pc); bmfun = lookup_minimal_symbol_by_pc (pc); mfun = bmfun.minsym; if (fun == NULL && mfun == NULL) DEBUG_FTRACE ("no symbol at %s", core_addr_to_string_nz (pc)); /* If we didn't have a function before, we create one. */ if (bfun == NULL) return ftrace_new_function (bfun, mfun, fun); /* Check the last instruction, if we have one. We do this check first, since it allows us to fill in the call stack links in addition to the normal flow links. */ last = NULL; if (!VEC_empty (btrace_insn_s, bfun->insn)) last = VEC_last (btrace_insn_s, bfun->insn); if (last != NULL) { CORE_ADDR lpc; lpc = last->pc; /* Check for returns. */ if (gdbarch_insn_is_ret (gdbarch, lpc)) return ftrace_new_return (gdbarch, bfun, mfun, fun); /* Check for calls. */ if (gdbarch_insn_is_call (gdbarch, lpc)) { int size; size = gdb_insn_length (gdbarch, lpc); /* Ignore calls to the next instruction. They are used for PIC. */ if (lpc + size != pc) return ftrace_new_call (bfun, mfun, fun); } } /* Check if we're switching functions for some other reason. */ if (ftrace_function_switched (bfun, mfun, fun)) { DEBUG_FTRACE ("switching from %s in %s at %s", ftrace_print_insn_addr (last), ftrace_print_function_name (bfun), ftrace_print_filename (bfun)); if (last != NULL) { CORE_ADDR start, lpc; start = get_pc_function_start (pc); /* If we can't determine the function for PC, we treat a jump at the end of the block as tail call. */ if (start == 0) start = pc; lpc = last->pc; /* Jumps indicate optimized tail calls. */ if (start == pc && gdbarch_insn_is_jump (gdbarch, lpc)) return ftrace_new_tailcall (bfun, mfun, fun); } return ftrace_new_switch (bfun, mfun, fun); } return bfun; }