static CORE_ADDR rs6000_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr, struct target_ops *targ) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); struct obj_section *s; s = find_pc_section (addr); /* Normally, functions live inside a section that is executable. So, if ADDR points to a non-executable section, then treat it as a function descriptor and return the target address iff the target address itself points to a section that is executable. */ if (s && (s->the_bfd_section->flags & SEC_CODE) == 0) { CORE_ADDR pc = 0; struct obj_section *pc_section; volatile struct gdb_exception e; TRY_CATCH (e, RETURN_MASK_ERROR) { pc = read_memory_unsigned_integer (addr, tdep->wordsize, byte_order); }
static CORE_ADDR tilegx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc) { CORE_ADDR func_start, end_pc; struct obj_section *s; /* This is the preferred method, find the end of the prologue by using the debugging information. */ if (find_pc_partial_function (start_pc, NULL, &func_start, NULL)) { CORE_ADDR post_prologue_pc = skip_prologue_using_sal (gdbarch, func_start); if (post_prologue_pc != 0) return max (start_pc, post_prologue_pc); } /* Don't straddle a section boundary. */ s = find_pc_section (start_pc); end_pc = start_pc + 8 * TILEGX_BUNDLE_SIZE_IN_BYTES; if (s != NULL) end_pc = min (end_pc, obj_section_endaddr (s)); /* Otherwise, try to skip prologue the hard way. */ return tilegx_analyze_prologue (gdbarch, start_pc, end_pc, NULL, NULL); }
CORE_ADDR get_pc_function_start (CORE_ADDR pc) { struct block *bl; struct minimal_symbol *msymbol; bl = block_for_pc (pc); if (bl) { struct symbol *symbol = block_linkage_function (bl); if (symbol) { bl = SYMBOL_BLOCK_VALUE (symbol); return BLOCK_START (bl); } } msymbol = lookup_minimal_symbol_by_pc (pc); if (msymbol) { CORE_ADDR fstart = SYMBOL_VALUE_ADDRESS (msymbol); if (find_pc_section (fstart)) return fstart; } return 0; }
static int convert_code_addr_to_desc_addr (CORE_ADDR code_addr, CORE_ADDR *desc_addr) { struct obj_section *dot_fn_section; struct minimal_symbol *dot_fn; struct minimal_symbol *fn; CORE_ADDR toc; /* Find the minimal symbol that corresponds to CODE_ADDR (should have a name of the form ".FN"). */ dot_fn = lookup_minimal_symbol_by_pc (code_addr); if (dot_fn == NULL || SYMBOL_LINKAGE_NAME (dot_fn)[0] != '.') return 0; /* Get the section that contains CODE_ADDR. Need this for the "objfile" that it contains. */ dot_fn_section = find_pc_section (code_addr); if (dot_fn_section == NULL || dot_fn_section->objfile == NULL) return 0; /* Now find the corresponding "FN" (dropping ".") minimal symbol's address. Only look for the minimal symbol in ".FN"'s object file - avoids problems when two object files (i.e., shared libraries) contain a minimal symbol with the same name. */ fn = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL, dot_fn_section->objfile); if (fn == NULL) return 0; /* Found a descriptor. */ (*desc_addr) = SYMBOL_VALUE_ADDRESS (fn); 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; }
CORE_ADDR get_pc_function_start (CORE_ADDR pc) { struct block *bl; struct minimal_symbol *msymbol; bl = block_for_pc (pc); if (bl) { struct symbol *symbol = block_function (bl); if (symbol) { bl = SYMBOL_BLOCK_VALUE (symbol); /* APPLE LOCAL begin address ranges */ return BLOCK_LOWEST_PC (bl); /* APPLE LOCAL end address ranges */ } } msymbol = lookup_minimal_symbol_by_pc (pc); if (msymbol) { CORE_ADDR fstart = SYMBOL_VALUE_ADDRESS (msymbol); if (find_pc_section (fstart)) return fstart; } return 0; }
static int in_opd_section (CORE_ADDR pc) { struct obj_section *s; int retval = 0; s = find_pc_section (pc); retval = (s != NULL && s->the_bfd_section->name != NULL && strcmp (s->the_bfd_section->name, ".opd") == 0); return (retval); }
static CORE_ADDR rs6000_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr, struct target_ops *targ) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); struct obj_section *s; s = find_pc_section (addr); /* Normally, functions live inside a section that is executable. So, if ADDR points to a non-executable section, then treat it as a function descriptor and return the target address iff the target address itself points to a section that is executable. */ if (s && (s->the_bfd_section->flags & SEC_CODE) == 0) { CORE_ADDR pc = 0; struct obj_section *pc_section; TRY { pc = read_memory_unsigned_integer (addr, tdep->wordsize, byte_order); } CATCH (e, RETURN_MASK_ERROR) { /* An error occured during reading. Probably a memory error due to the section not being loaded yet. This address cannot be a function descriptor. */ return addr; } END_CATCH pc_section = find_pc_section (pc); if (pc_section && (pc_section->the_bfd_section->flags & SEC_CODE)) return pc; }
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 *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 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 CORE_ADDR gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc) { CORE_ADDR real_stop_pc, method_stop_pc; struct gdbarch *gdbarch = get_frame_arch (frame); struct minimal_symbol *thunk_sym, *fn_sym; struct obj_section *section; char *thunk_name, *fn_name; real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc); if (real_stop_pc == 0) real_stop_pc = stop_pc; /* Find the linker symbol for this potential thunk. */ thunk_sym = lookup_minimal_symbol_by_pc (real_stop_pc); section = find_pc_section (real_stop_pc); if (thunk_sym == NULL || section == NULL) return 0; /* The symbol's demangled name should be something like "virtual thunk to FUNCTION", where FUNCTION is the name of the function being thunked to. */ thunk_name = SYMBOL_DEMANGLED_NAME (thunk_sym); if (thunk_name == NULL || strstr (thunk_name, " thunk to ") == NULL) return 0; fn_name = strstr (thunk_name, " thunk to ") + strlen (" thunk to "); fn_sym = lookup_minimal_symbol (fn_name, NULL, section->objfile); if (fn_sym == NULL) return 0; method_stop_pc = SYMBOL_VALUE_ADDRESS (fn_sym); real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, method_stop_pc); if (real_stop_pc == 0) real_stop_pc = method_stop_pc; return real_stop_pc; }
static void mi_memory_changed (struct inferior *inferior, CORE_ADDR memaddr, ssize_t len, const bfd_byte *myaddr) { struct mi_interp *mi = top_level_interpreter_data (); struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); struct obj_section *sec; if (mi_suppress_notification.memory) return; target_terminal_ours (); fprintf_unfiltered (mi->event_channel, "memory-changed"); ui_out_redirect (mi_uiout, mi->event_channel); ui_out_field_fmt (mi_uiout, "thread-group", "i%d", inferior->num); ui_out_field_core_addr (mi_uiout, "addr", target_gdbarch (), memaddr); ui_out_field_fmt (mi_uiout, "len", "%s", hex_string (len)); /* Append 'type=code' into notification if MEMADDR falls in the range of sections contain code. */ sec = find_pc_section (memaddr); if (sec != NULL && sec->objfile != NULL) { flagword flags = bfd_get_section_flags (sec->objfile->obfd, sec->the_bfd_section); if (flags & SEC_CODE) ui_out_field_string (mi_uiout, "type", "code"); } ui_out_redirect (mi_uiout, NULL); gdb_flush (mi->event_channel); }
int find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address, CORE_ADDR *endaddr) { struct bfd_section *bfd_section; /* To ensure that the symbol returned belongs to the correct setion (and that the last [random] symbol from the previous section isn't returned) try to find the section containing PC. First try the overlay code (which by default returns NULL); and second try the normal section code (which almost always succeeds). */ bfd_section = find_pc_overlay (pc); if (bfd_section == NULL) { struct obj_section *obj_section = find_pc_section (pc); if (obj_section == NULL) bfd_section = NULL; else bfd_section = obj_section->the_bfd_section; } return find_pc_sect_partial_function (pc, bfd_section, name, address, endaddr); }
static int amd64_windows_find_unwind_info (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR *unwind_info, CORE_ADDR *image_base, CORE_ADDR *start_rva, CORE_ADDR *end_rva) { struct obj_section *sec; pe_data_type *pe; IMAGE_DATA_DIRECTORY *dir; struct objfile *objfile; unsigned long lo, hi; CORE_ADDR base; enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); /* Get the corresponding exception directory. */ sec = find_pc_section (pc); if (sec == NULL) return -1; objfile = sec->objfile; pe = pe_data (sec->objfile->obfd); dir = &pe->pe_opthdr.DataDirectory[PE_EXCEPTION_TABLE]; base = pe->pe_opthdr.ImageBase + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); *image_base = base; /* Find the entry. Note: This does not handle dynamically added entries (for JIT engines). For this, we would need to ask the kernel directly, which means getting some info from the native layer. For the rest of the code, however, it's probably faster to search the entry ourselves. */ lo = 0; hi = dir->Size / sizeof (struct external_pex64_runtime_function); *unwind_info = 0; while (lo <= hi) { unsigned long mid = lo + (hi - lo) / 2; struct external_pex64_runtime_function d; CORE_ADDR sa, ea; if (target_read_memory (base + dir->VirtualAddress + mid * sizeof (d), (gdb_byte *) &d, sizeof (d)) != 0) return -1; sa = extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order); ea = extract_unsigned_integer (d.rva_EndAddress, 4, byte_order); if (pc < base + sa) hi = mid - 1; else if (pc >= base + ea) lo = mid + 1; else if (pc >= base + sa && pc < base + ea) { /* Got it. */ *start_rva = sa; *end_rva = ea; *unwind_info = extract_unsigned_integer (d.rva_UnwindData, 4, byte_order); break; } else break; } if (frame_debug) fprintf_unfiltered (gdb_stdlog, "amd64_windows_find_unwind_data: image_base=%s, unwind_data=%s\n", paddress (gdbarch, base), paddress (gdbarch, *unwind_info)); if (*unwind_info & 1) { /* Unofficially documented unwind info redirection, when UNWIND_INFO address is odd (http://www.codemachine.com/article_x64deepdive.html). */ struct external_pex64_runtime_function d; CORE_ADDR sa, ea; if (target_read_memory (base + (*unwind_info & ~1), (gdb_byte *) &d, sizeof (d)) != 0) return -1; *start_rva = extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order); *end_rva = extract_unsigned_integer (d.rva_EndAddress, 4, byte_order); *unwind_info = extract_unsigned_integer (d.rva_UnwindData, 4, byte_order); } return 0; }
CORE_ADDR ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr) { CORE_ADDR func_addr = find_function_addr (function, NULL); struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); /* By this stage in the proceedings, SP has been decremented by "red zone size" + "struct return size". Fetch the stack-pointer from before this and use that as the BACK_CHAIN. */ const CORE_ADDR back_chain = read_sp (); /* See for-loop comment below. */ int write_pass; /* Size of the Altivec's vector parameter region, the final value is computed in the for-loop below. */ LONGEST vparam_size = 0; /* Size of the general parameter region, the final value is computed in the for-loop below. */ LONGEST gparam_size = 0; /* Kevin writes ... I don't mind seeing tdep->wordsize used in the calls to align_up(), align_down(), etc. because this makes it easier to reuse this code (in a copy/paste sense) in the future, but it is a 64-bit ABI and asserting that the wordsize is 8 bytes at some point makes it easier to verify that this function is correct without having to do a non-local analysis to figure out the possible values of tdep->wordsize. */ gdb_assert (tdep->wordsize == 8); /* Go through the argument list twice. Pass 1: Compute the function call's stack space and register requirements. Pass 2: Replay the same computation but this time also write the values out to the target. */ for (write_pass = 0; write_pass < 2; write_pass++) { int argno; /* Next available floating point register for float and double arguments. */ int freg = 1; /* Next available general register for non-vector (but possibly float) arguments. */ int greg = 3; /* Next available vector register for vector arguments. */ int vreg = 2; /* The address, at which the next general purpose parameter (integer, struct, float, ...) should be saved. */ CORE_ADDR gparam; /* Address, at which the next Altivec vector parameter should be saved. */ CORE_ADDR vparam; if (!write_pass) { /* During the first pass, GPARAM and VPARAM are more like offsets (start address zero) than addresses. That way the accumulate the total stack space each region requires. */ gparam = 0; vparam = 0; } else { /* Decrement the stack pointer making space for the Altivec and general on-stack parameters. Set vparam and gparam to their corresponding regions. */ vparam = align_down (sp - vparam_size, 16); gparam = align_down (vparam - gparam_size, 16); /* Add in space for the TOC, link editor double word, compiler double word, LR save area, CR save area. */ sp = align_down (gparam - 48, 16); } /* If the function is returning a `struct', then there is an extra hidden parameter (which will be passed in r3) containing the address of that struct.. In that case we should advance one word and start from r4 register to copy parameters. This also consumes one on-stack parameter slot. */ if (struct_return) { if (write_pass) regcache_cooked_write_signed (regcache, tdep->ppc_gp0_regnum + greg, struct_addr); greg++; gparam = align_up (gparam + tdep->wordsize, tdep->wordsize); } for (argno = 0; argno < nargs; argno++) { struct value *arg = args[argno]; struct type *type = check_typedef (VALUE_TYPE (arg)); char *val = VALUE_CONTENTS (arg); if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8) { /* Floats and Doubles go in f1 .. f13. They also consume a left aligned GREG,, and can end up in memory. */ if (write_pass) { if (ppc_floating_point_unit_p (current_gdbarch) && freg <= 13) { char regval[MAX_REGISTER_SIZE]; struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum); convert_typed_floating (val, type, regval, regtype); regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, regval); } if (greg <= 10) { /* The ABI states "Single precision floating point values are mapped to the first word in a single doubleword" and "... floating point values mapped to the first eight doublewords of the parameter save area are also passed in general registers"). This code interprets that to mean: store it, left aligned, in the general register. */ char regval[MAX_REGISTER_SIZE]; memset (regval, 0, sizeof regval); memcpy (regval, val, TYPE_LENGTH (type)); regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, regval); } write_memory (gparam, val, TYPE_LENGTH (type)); } /* Always consume parameter stack space. */ freg++; greg++; gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); } else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type) && TYPE_CODE (type) == TYPE_CODE_ARRAY && tdep->ppc_vr0_regnum >= 0) { /* In the Altivec ABI, vectors go in the vector registers v2 .. v13, or when that runs out, a vector annex which goes above all the normal parameters. NOTE: cagney/2003-09-21: This is a guess based on the PowerOpen Altivec ABI. */ if (vreg <= 13) { if (write_pass) regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + vreg, val); vreg++; } else { if (write_pass) write_memory (vparam, val, TYPE_LENGTH (type)); vparam = align_up (vparam + TYPE_LENGTH (type), 16); } } else if ((TYPE_CODE (type) == TYPE_CODE_INT || TYPE_CODE (type) == TYPE_CODE_ENUM) && TYPE_LENGTH (type) <= 8) { /* Scalars get sign[un]extended and go in gpr3 .. gpr10. They can also end up in memory. */ if (write_pass) { /* Sign extend the value, then store it unsigned. */ ULONGEST word = unpack_long (type, val); if (greg <= 10) regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + greg, word); write_memory_unsigned_integer (gparam, tdep->wordsize, word); } greg++; gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); } else { int byte; for (byte = 0; byte < TYPE_LENGTH (type); byte += tdep->wordsize) { if (write_pass && greg <= 10) { char regval[MAX_REGISTER_SIZE]; int len = TYPE_LENGTH (type) - byte; if (len > tdep->wordsize) len = tdep->wordsize; memset (regval, 0, sizeof regval); /* WARNING: cagney/2003-09-21: As best I can tell, the ABI specifies that the value should be left aligned. Unfortunately, GCC doesn't do this - it instead right aligns even sized values and puts odd sized values on the stack. Work around that by putting both a left and right aligned value into the register (hopefully no one notices :-^). Arrrgh! */ /* Left aligned (8 byte values such as pointers fill the buffer). */ memcpy (regval, val + byte, len); /* Right aligned (but only if even). */ if (len == 1 || len == 2 || len == 4) memcpy (regval + tdep->wordsize - len, val + byte, len); regcache_cooked_write (regcache, greg, regval); } greg++; } if (write_pass) /* WARNING: cagney/2003-09-21: Strictly speaking, this isn't necessary, unfortunately, GCC appears to get "struct convention" parameter passing wrong putting odd sized structures in memory instead of in a register. Work around this by always writing the value to memory. Fortunately, doing this simplifies the code. */ write_memory (gparam, val, TYPE_LENGTH (type)); /* Always consume parameter stack space. */ gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); } } if (!write_pass) { /* Save the true region sizes ready for the second pass. */ vparam_size = vparam; /* Make certain that the general parameter save area is at least the minimum 8 registers (or doublewords) in size. */ if (greg < 8) gparam_size = 8 * tdep->wordsize; else gparam_size = gparam; } } /* Update %sp. */ regcache_cooked_write_signed (regcache, SP_REGNUM, sp); /* Write the backchain (it occupies WORDSIZED bytes). */ write_memory_signed_integer (sp, tdep->wordsize, back_chain); /* Point the inferior function call's return address at the dummy's breakpoint. */ regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr); /* Find a value for the TOC register. Every symbol should have both ".FN" and "FN" in the minimal symbol table. "FN" points at the FN's descriptor, while ".FN" points at the entry point (which matches FUNC_ADDR). Need to reverse from FUNC_ADDR back to the FN's descriptor address (while at the same time being careful to find "FN" in the same object file as ".FN"). */ { /* Find the minimal symbol that corresponds to FUNC_ADDR (should have the name ".FN"). */ struct minimal_symbol *dot_fn = lookup_minimal_symbol_by_pc (func_addr); if (dot_fn != NULL && SYMBOL_LINKAGE_NAME (dot_fn)[0] == '.') { /* Get the section that contains FUNC_ADR. Need this for the "objfile" that it contains. */ struct obj_section *dot_fn_section = find_pc_section (func_addr); if (dot_fn_section != NULL && dot_fn_section->objfile != NULL) { /* Now find the corresponding "FN" (dropping ".") minimal symbol's address. Only look for the minimal symbol in ".FN"'s object file - avoids problems when two object files (i.e., shared libraries) contain a minimal symbol with the same name. */ struct minimal_symbol *fn = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL, dot_fn_section->objfile); if (fn != NULL) { /* Got the address of that descriptor. The TOC is the second double word. */ CORE_ADDR toc = read_memory_unsigned_integer (SYMBOL_VALUE_ADDRESS (fn) + tdep->wordsize, tdep->wordsize); regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 2, toc); } } } } return sp; }
bound_minimal_symbol lookup_minimal_symbol_by_pc_section (CORE_ADDR pc_in, struct obj_section *section, lookup_msym_prefer prefer) { int lo; int hi; int newobj; struct objfile *objfile; struct minimal_symbol *msymbol; struct minimal_symbol *best_symbol = NULL; struct objfile *best_objfile = NULL; struct bound_minimal_symbol result; if (section == NULL) { section = find_pc_section (pc_in); if (section == NULL) return {}; } minimal_symbol_type want_type = msym_prefer_to_msym_type (prefer); /* We can not require the symbol found to be in section, because e.g. IRIX 6.5 mdebug relies on this code returning an absolute symbol - but find_pc_section won't return an absolute section and hence the code below would skip over absolute symbols. We can still take advantage of the call to find_pc_section, though - the object file still must match. In case we have separate debug files, search both the file and its separate debug file. There's no telling which one will have the minimal symbols. */ gdb_assert (section != NULL); for (objfile = section->objfile; objfile != NULL; objfile = objfile_separate_debug_iterate (section->objfile, objfile)) { CORE_ADDR pc = pc_in; /* If this objfile has a minimal symbol table, go search it using a binary search. Note that a minimal symbol table always consists of at least two symbols, a "real" symbol and the terminating "null symbol". If there are no real symbols, then there is no minimal symbol table at all. */ if (objfile->per_bfd->minimal_symbol_count > 0) { int best_zero_sized = -1; msymbol = objfile->per_bfd->msymbols; lo = 0; hi = objfile->per_bfd->minimal_symbol_count - 1; /* This code assumes that the minimal symbols are sorted by ascending address values. If the pc value is greater than or equal to the first symbol's address, then some symbol in this minimal symbol table is a suitable candidate for being the "best" symbol. This includes the last real symbol, for cases where the pc value is larger than any address in this vector. By iterating until the address associated with the current hi index (the endpoint of the test interval) is less than or equal to the desired pc value, we accomplish two things: (1) the case where the pc value is larger than any minimal symbol address is trivially solved, (2) the address associated with the hi index is always the one we want when the interation terminates. In essence, we are iterating the test interval down until the pc value is pushed out of it from the high end. Warning: this code is trickier than it would appear at first. */ if (frob_address (objfile, &pc) && pc >= MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[lo])) { while (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi]) > pc) { /* pc is still strictly less than highest address. */ /* Note "new" will always be >= lo. */ newobj = (lo + hi) / 2; if ((MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[newobj]) >= pc) || (lo == newobj)) { hi = newobj; } else { lo = newobj; } } /* If we have multiple symbols at the same address, we want hi to point to the last one. That way we can find the right symbol if it has an index greater than hi. */ while (hi < objfile->per_bfd->minimal_symbol_count - 1 && (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi]) == MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi + 1]))) hi++; /* Skip various undesirable symbols. */ while (hi >= 0) { /* Skip any absolute symbols. This is apparently what adb and dbx do, and is needed for the CM-5. There are two known possible problems: (1) on ELF, apparently end, edata, etc. are absolute. Not sure ignoring them here is a big deal, but if we want to use them, the fix would go in elfread.c. (2) I think shared library entry points on the NeXT are absolute. If we want special handling for this it probably should be triggered by a special mst_abs_or_lib or some such. */ if (MSYMBOL_TYPE (&msymbol[hi]) == mst_abs) { hi--; continue; } /* If SECTION was specified, skip any symbol from wrong section. */ if (section /* Some types of debug info, such as COFF, don't fill the bfd_section member, so don't throw away symbols on those platforms. */ && MSYMBOL_OBJ_SECTION (objfile, &msymbol[hi]) != NULL && (!matching_obj_sections (MSYMBOL_OBJ_SECTION (objfile, &msymbol[hi]), section))) { hi--; continue; } /* If we are looking for a trampoline and this is a text symbol, or the other way around, check the preceding symbol too. If they are otherwise identical prefer that one. */ if (hi > 0 && MSYMBOL_TYPE (&msymbol[hi]) != want_type && MSYMBOL_TYPE (&msymbol[hi - 1]) == want_type && (MSYMBOL_SIZE (&msymbol[hi]) == MSYMBOL_SIZE (&msymbol[hi - 1])) && (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi]) == MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi - 1])) && (MSYMBOL_OBJ_SECTION (objfile, &msymbol[hi]) == MSYMBOL_OBJ_SECTION (objfile, &msymbol[hi - 1]))) { hi--; continue; } /* If the minimal symbol has a zero size, save it but keep scanning backwards looking for one with a non-zero size. A zero size may mean that the symbol isn't an object or function (e.g. a label), or it may just mean that the size was not specified. */ if (MSYMBOL_SIZE (&msymbol[hi]) == 0) { if (best_zero_sized == -1) best_zero_sized = hi; hi--; continue; } /* If we are past the end of the current symbol, try the previous symbol if it has a larger overlapping size. This happens on i686-pc-linux-gnu with glibc; the nocancel variants of system calls are inside the cancellable variants, but both have sizes. */ if (hi > 0 && MSYMBOL_SIZE (&msymbol[hi]) != 0 && pc >= (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi]) + MSYMBOL_SIZE (&msymbol[hi])) && pc < (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi - 1]) + MSYMBOL_SIZE (&msymbol[hi - 1]))) { hi--; continue; } /* Otherwise, this symbol must be as good as we're going to get. */ break; } /* If HI has a zero size, and best_zero_sized is set, then we had two or more zero-sized symbols; prefer the first one we found (which may have a higher address). Also, if we ran off the end, be sure to back up. */ if (best_zero_sized != -1 && (hi < 0 || MSYMBOL_SIZE (&msymbol[hi]) == 0)) hi = best_zero_sized; /* If the minimal symbol has a non-zero size, and this PC appears to be outside the symbol's contents, then refuse to use this symbol. If we found a zero-sized symbol with an address greater than this symbol's, use that instead. We assume that if symbols have specified sizes, they do not overlap. */ if (hi >= 0 && MSYMBOL_SIZE (&msymbol[hi]) != 0 && pc >= (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi]) + MSYMBOL_SIZE (&msymbol[hi]))) { if (best_zero_sized != -1) hi = best_zero_sized; else /* Go on to the next object file. */ continue; } /* The minimal symbol indexed by hi now is the best one in this objfile's minimal symbol table. See if it is the best one overall. */ if (hi >= 0 && ((best_symbol == NULL) || (MSYMBOL_VALUE_RAW_ADDRESS (best_symbol) < MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi])))) { best_symbol = &msymbol[hi]; best_objfile = objfile; } } } } result.minsym = best_symbol; result.objfile = best_objfile; return result; }
static struct mdebug_extra_func_info * non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr) { CORE_ADDR startaddr; struct mdebug_extra_func_info *proc_desc; struct block *b = block_for_pc (pc); struct symbol *sym; struct obj_section *sec; struct mips_objfile_private *priv; find_pc_partial_function (pc, NULL, &startaddr, NULL); if (addrptr) *addrptr = startaddr; priv = NULL; sec = find_pc_section (pc); if (sec != NULL) { priv = (struct mips_objfile_private *) objfile_data (sec->objfile, mips_pdr_data); /* Search the ".pdr" section generated by GAS. This includes most of the information normally found in ECOFF PDRs. */ the_bfd = sec->objfile->obfd; if (priv == NULL && (the_bfd->format == bfd_object && bfd_get_flavour (the_bfd) == bfd_target_elf_flavour && elf_elfheader (the_bfd)->e_ident[EI_CLASS] == ELFCLASS64)) { /* Right now GAS only outputs the address as a four-byte sequence. This means that we should not bother with this method on 64-bit targets (until that is fixed). */ priv = obstack_alloc (&sec->objfile->objfile_obstack, sizeof (struct mips_objfile_private)); priv->size = 0; set_objfile_data (sec->objfile, mips_pdr_data, priv); } else if (priv == NULL) { asection *bfdsec; priv = obstack_alloc (&sec->objfile->objfile_obstack, sizeof (struct mips_objfile_private)); bfdsec = bfd_get_section_by_name (sec->objfile->obfd, ".pdr"); if (bfdsec != NULL) { priv->size = bfd_section_size (sec->objfile->obfd, bfdsec); priv->contents = obstack_alloc (&sec->objfile->objfile_obstack, priv->size); bfd_get_section_contents (sec->objfile->obfd, bfdsec, priv->contents, 0, priv->size); /* In general, the .pdr section is sorted. However, in the presence of multiple code sections (and other corner cases) it can become unsorted. Sort it so that we can use a faster binary search. */ qsort (priv->contents, priv->size / 32, 32, compare_pdr_entries); } else priv->size = 0; set_objfile_data (sec->objfile, mips_pdr_data, priv); } the_bfd = NULL; if (priv->size != 0) { int low, mid, high; char *ptr; CORE_ADDR pdr_pc; low = 0; high = priv->size / 32; /* We've found a .pdr section describing this objfile. We want to find the entry which describes this code address. The .pdr information is not very descriptive; we have only a function start address. We have to look for the closest entry, because the local symbol at the beginning of this function may have been stripped - so if we ask the symbol table for the start address we may get a preceding global function. */ /* First, find the last .pdr entry starting at or before PC. */ do { mid = (low + high) / 2; ptr = priv->contents + mid * 32; pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr); pdr_pc += ANOFFSET (sec->objfile->section_offsets, SECT_OFF_TEXT (sec->objfile)); if (pdr_pc > pc) high = mid; else low = mid + 1; } while (low != high); /* Both low and high point one past the PDR of interest. If both are zero, that means this PC is before any region covered by a PDR, i.e. pdr_pc for the first PDR entry is greater than PC. */ if (low > 0) { ptr = priv->contents + (low - 1) * 32; pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr); pdr_pc += ANOFFSET (sec->objfile->section_offsets, SECT_OFF_TEXT (sec->objfile)); } /* We don't have a range, so we have no way to know for sure whether we're in the correct PDR or a PDR for a preceding function and the current function was a stripped local symbol. But if the PDR's PC is at least as great as the best guess from the symbol table, assume that it does cover the right area; if a .pdr section is present at all then nearly every function will have an entry. The biggest exception will be the dynamic linker stubs; conveniently these are placed before .text instead of after. */ if (pc >= pdr_pc && pdr_pc >= startaddr) { struct symbol *sym = find_pc_function (pc); if (addrptr) *addrptr = pdr_pc; /* Fill in what we need of the proc_desc. */ proc_desc = (struct mdebug_extra_func_info *) obstack_alloc (&sec->objfile->objfile_obstack, sizeof (struct mdebug_extra_func_info)); PROC_LOW_ADDR (proc_desc) = pdr_pc; PROC_FRAME_OFFSET (proc_desc) = bfd_get_signed_32 (sec->objfile->obfd, ptr + 20); PROC_FRAME_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd, ptr + 24); PROC_REG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd, ptr + 4); PROC_FREG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd, ptr + 12); PROC_REG_OFFSET (proc_desc) = bfd_get_signed_32 (sec->objfile->obfd, ptr + 8); PROC_FREG_OFFSET (proc_desc) = bfd_get_signed_32 (sec->objfile->obfd, ptr + 16); PROC_PC_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd, ptr + 28); proc_desc->pdr.isym = (long) sym; return proc_desc; } } } if (b == NULL) return NULL; if (startaddr > BLOCK_START (b)) { /* This is the "pathological" case referred to in a comment in print_frame_info. It might be better to move this check into symbol reading. */ return NULL; } sym = lookup_symbol (MDEBUG_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, 0); /* If we never found a PDR for this function in symbol reading, then examine prologues to find the information. */ if (sym) { proc_desc = (struct mdebug_extra_func_info *) SYMBOL_VALUE (sym); if (PROC_FRAME_REG (proc_desc) == -1) return NULL; else return proc_desc; } else return NULL; }
int find_pc_partial_function_gnu_ifunc (CORE_ADDR pc, const char **name, CORE_ADDR *address, CORE_ADDR *endaddr, int *is_gnu_ifunc_p) { struct obj_section *section; struct symbol *f; struct minimal_symbol *msymbol; struct symtab *symtab = NULL; struct objfile *objfile; int i; CORE_ADDR mapped_pc; /* To ensure that the symbol returned belongs to the correct setion (and that the last [random] symbol from the previous section isn't returned) try to find the section containing PC. First try the overlay code (which by default returns NULL); and second try the normal section code (which almost always succeeds). */ section = find_pc_overlay (pc); if (section == NULL) section = find_pc_section (pc); mapped_pc = overlay_mapped_address (pc, section); if (mapped_pc >= cache_pc_function_low && mapped_pc < cache_pc_function_high && section == cache_pc_function_section) goto return_cached_value; msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section); ALL_OBJFILES (objfile) { if (objfile->sf) symtab = objfile->sf->qf->find_pc_sect_symtab (objfile, msymbol, mapped_pc, section, 0); if (symtab) break; } if (symtab) { /* Checking whether the msymbol has a larger value is for the "pathological" case mentioned in print_frame_info. */ f = find_pc_sect_function (mapped_pc, section); if (f != NULL && (msymbol == NULL || (BLOCK_START (SYMBOL_BLOCK_VALUE (f)) >= SYMBOL_VALUE_ADDRESS (msymbol)))) { cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f)); cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f)); cache_pc_function_name = SYMBOL_LINKAGE_NAME (f); cache_pc_function_section = section; cache_pc_function_is_gnu_ifunc = TYPE_GNU_IFUNC (SYMBOL_TYPE (f)); goto return_cached_value; } } /* Not in the normal symbol tables, see if the pc is in a known section. If it's not, then give up. This ensures that anything beyond the end of the text seg doesn't appear to be part of the last function in the text segment. */ if (!section) msymbol = NULL; /* Must be in the minimal symbol table. */ if (msymbol == NULL) { /* No available symbol. */ if (name != NULL) *name = 0; if (address != NULL) *address = 0; if (endaddr != NULL) *endaddr = 0; if (is_gnu_ifunc_p != NULL) *is_gnu_ifunc_p = 0; return 0; } cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol); cache_pc_function_name = SYMBOL_LINKAGE_NAME (msymbol); cache_pc_function_section = section; cache_pc_function_is_gnu_ifunc = MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc; /* If the minimal symbol has a size, use it for the cache. Otherwise use the lesser of the next minimal symbol in the same section, or the end of the section, as the end of the function. */ if (MSYMBOL_SIZE (msymbol) != 0) cache_pc_function_high = cache_pc_function_low + MSYMBOL_SIZE (msymbol); else { /* Step over other symbols at this same address, and symbols in other sections, to find the next symbol in this section with a different address. */ for (i = 1; SYMBOL_LINKAGE_NAME (msymbol + i) != NULL; i++) { if (SYMBOL_VALUE_ADDRESS (msymbol + i) != SYMBOL_VALUE_ADDRESS (msymbol) && SYMBOL_OBJ_SECTION (msymbol + i) == SYMBOL_OBJ_SECTION (msymbol)) break; } if (SYMBOL_LINKAGE_NAME (msymbol + i) != NULL && SYMBOL_VALUE_ADDRESS (msymbol + i) < obj_section_endaddr (section)) cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + i); else /* We got the start address from the last msymbol in the objfile. So the end address is the end of the section. */ cache_pc_function_high = obj_section_endaddr (section); } return_cached_value: if (address) { if (pc_in_unmapped_range (pc, section)) *address = overlay_unmapped_address (cache_pc_function_low, section); else *address = cache_pc_function_low; } if (name) *name = cache_pc_function_name; if (endaddr) { if (pc_in_unmapped_range (pc, section)) { /* Because the high address is actually beyond the end of the function (and therefore possibly beyond the end of the overlay), we must actually convert (high - 1) and then add one to that. */ *endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1, section); } else *endaddr = cache_pc_function_high; } if (is_gnu_ifunc_p) *is_gnu_ifunc_p = cache_pc_function_is_gnu_ifunc; return 1; }
static CORE_ADDR ppc_linux_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) { gdb_byte buf[4]; struct obj_section *sect; struct objfile *objfile; unsigned long insn; CORE_ADDR plt_start = 0; CORE_ADDR symtab = 0; CORE_ADDR strtab = 0; int num_slots = -1; int reloc_index = -1; CORE_ADDR plt_table; CORE_ADDR reloc; CORE_ADDR sym; long symidx; char symname[1024]; struct minimal_symbol *msymbol; /* Find the section pc is in; return if not in .plt */ sect = find_pc_section (pc); if (!sect || strcmp (sect->the_bfd_section->name, ".plt") != 0) return 0; objfile = sect->objfile; /* Pick up the instruction at pc. It had better be of the form li r11, IDX where IDX is an index into the plt_table. */ if (target_read_memory (pc, buf, 4) != 0) return 0; insn = extract_unsigned_integer (buf, 4); if ((insn & 0xffff0000) != 0x39600000 /* li r11, VAL */ ) return 0; reloc_index = (insn << 16) >> 16; /* Find the objfile that pc is in and obtain the information necessary for finding the symbol name. */ for (sect = objfile->sections; sect < objfile->sections_end; ++sect) { const char *secname = sect->the_bfd_section->name; if (strcmp (secname, ".plt") == 0) plt_start = sect->addr; else if (strcmp (secname, ".rela.plt") == 0) num_slots = ((int) sect->endaddr - (int) sect->addr) / 12; else if (strcmp (secname, ".dynsym") == 0) symtab = sect->addr; else if (strcmp (secname, ".dynstr") == 0) strtab = sect->addr; } /* Make sure we have all the information we need. */ if (plt_start == 0 || num_slots == -1 || symtab == 0 || strtab == 0) return 0; /* Compute the value of the plt table */ plt_table = plt_start + 72 + 8 * num_slots; /* Get address of the relocation entry (Elf32_Rela) */ if (target_read_memory (plt_table + reloc_index, buf, 4) != 0) return 0; reloc = extract_unsigned_integer (buf, 4); sect = find_pc_section (reloc); if (!sect) return 0; if (strcmp (sect->the_bfd_section->name, ".text") == 0) return reloc; /* Now get the r_info field which is the relocation type and symbol index. */ if (target_read_memory (reloc + 4, buf, 4) != 0) return 0; symidx = extract_unsigned_integer (buf, 4); /* Shift out the relocation type leaving just the symbol index */ /* symidx = ELF32_R_SYM(symidx); */ symidx = symidx >> 8; /* compute the address of the symbol */ sym = symtab + symidx * 4; /* Fetch the string table index */ if (target_read_memory (sym, buf, 4) != 0) return 0; symidx = extract_unsigned_integer (buf, 4); /* Fetch the string; we don't know how long it is. Is it possible that the following will fail because we're trying to fetch too much? */ if (target_read_memory (strtab + symidx, (gdb_byte *) symname, sizeof (symname)) != 0) return 0; /* This might not work right if we have multiple symbols with the same name; the only way to really get it right is to perform the same sort of lookup as the dynamic linker. */ msymbol = lookup_minimal_symbol_text (symname, NULL); if (!msymbol) return 0; return SYMBOL_VALUE_ADDRESS (msymbol); }
int find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address, CORE_ADDR *endaddr, const struct block **block) { struct obj_section *section; struct symbol *f; struct bound_minimal_symbol msymbol; struct compunit_symtab *compunit_symtab = NULL; CORE_ADDR mapped_pc; /* To ensure that the symbol returned belongs to the correct setion (and that the last [random] symbol from the previous section isn't returned) try to find the section containing PC. First try the overlay code (which by default returns NULL); and second try the normal section code (which almost always succeeds). */ section = find_pc_overlay (pc); if (section == NULL) section = find_pc_section (pc); mapped_pc = overlay_mapped_address (pc, section); if (mapped_pc >= cache_pc_function_low && mapped_pc < cache_pc_function_high && section == cache_pc_function_section) goto return_cached_value; msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section); for (objfile *objfile : current_program_space->objfiles ()) { if (objfile->sf) { compunit_symtab = objfile->sf->qf->find_pc_sect_compunit_symtab (objfile, msymbol, mapped_pc, section, 0); } if (compunit_symtab != NULL) break; } if (compunit_symtab != NULL) { /* Checking whether the msymbol has a larger value is for the "pathological" case mentioned in stack.c:find_frame_funname. We use BLOCK_ENTRY_PC instead of BLOCK_START_PC for this comparison because the minimal symbol should refer to the function's entry pc which is not necessarily the lowest address of the function. This will happen when the function has more than one range and the entry pc is not within the lowest range of addresses. */ f = find_pc_sect_function (mapped_pc, section); if (f != NULL && (msymbol.minsym == NULL || (BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (f)) >= BMSYMBOL_VALUE_ADDRESS (msymbol)))) { const struct block *b = SYMBOL_BLOCK_VALUE (f); cache_pc_function_name = SYMBOL_LINKAGE_NAME (f); cache_pc_function_section = section; cache_pc_function_block = b; /* For blocks occupying contiguous addresses (i.e. no gaps), the low and high cache addresses are simply the start and end of the block. For blocks with non-contiguous ranges, we have to search for the range containing mapped_pc and then use the start and end of that range. This causes the returned *ADDRESS and *ENDADDR values to be limited to the range in which mapped_pc is found. See comment preceding declaration of find_pc_partial_function in symtab.h for more information. */ if (BLOCK_CONTIGUOUS_P (b)) { cache_pc_function_low = BLOCK_START (b); cache_pc_function_high = BLOCK_END (b); } else { int i; for (i = 0; i < BLOCK_NRANGES (b); i++) { if (BLOCK_RANGE_START (b, i) <= mapped_pc && mapped_pc < BLOCK_RANGE_END (b, i)) { cache_pc_function_low = BLOCK_RANGE_START (b, i); cache_pc_function_high = BLOCK_RANGE_END (b, i); break; } } /* Above loop should exit via the break. */ gdb_assert (i < BLOCK_NRANGES (b)); } goto return_cached_value; } } /* Not in the normal symbol tables, see if the pc is in a known section. If it's not, then give up. This ensures that anything beyond the end of the text seg doesn't appear to be part of the last function in the text segment. */ if (!section) msymbol.minsym = NULL; /* Must be in the minimal symbol table. */ if (msymbol.minsym == NULL) { /* No available symbol. */ if (name != NULL) *name = 0; if (address != NULL) *address = 0; if (endaddr != NULL) *endaddr = 0; return 0; } cache_pc_function_low = BMSYMBOL_VALUE_ADDRESS (msymbol); cache_pc_function_name = MSYMBOL_LINKAGE_NAME (msymbol.minsym); cache_pc_function_section = section; cache_pc_function_high = minimal_symbol_upper_bound (msymbol); cache_pc_function_block = nullptr; return_cached_value: if (address) { if (pc_in_unmapped_range (pc, section)) *address = overlay_unmapped_address (cache_pc_function_low, section); else *address = cache_pc_function_low; } if (name) *name = cache_pc_function_name; if (endaddr) { if (pc_in_unmapped_range (pc, section)) { /* Because the high address is actually beyond the end of the function (and therefore possibly beyond the end of the overlay), we must actually convert (high - 1) and then add one to that. */ *endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1, section); } else *endaddr = cache_pc_function_high; } if (block != nullptr) *block = cache_pc_function_block; return 1; }
static int find_pc_partial_function_impl (CORE_ADDR pc, char **name, CORE_ADDR *address, CORE_ADDR *endaddr, int inlining_flag) { struct bfd_section *section; struct partial_symtab *pst; struct symbol *f; struct minimal_symbol *msymbol; struct partial_symbol *psb; struct obj_section *osect; int i; CORE_ADDR mapped_pc; /* To ensure that the symbol returned belongs to the correct setion (and that the last [random] symbol from the previous section isn't returned) try to find the section containing PC. First try the overlay code (which by default returns NULL); and second try the normal section code (which almost always succeeds). */ section = find_pc_overlay (pc); if (section == NULL) { struct obj_section *obj_section = find_pc_section (pc); if (obj_section == NULL) section = NULL; else section = obj_section->the_bfd_section; } mapped_pc = overlay_mapped_address (pc, section); if (mapped_pc >= cache_pc_function_low && mapped_pc < cache_pc_function_high && section == cache_pc_function_section && inlining_flag == cache_pc_function_inlining) goto return_cached_value; cache_pc_function_inlining = inlining_flag; msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section); pst = find_pc_sect_psymtab (mapped_pc, section); if (pst) { /* Need to read the symbols to get a good value for the end address. */ if (endaddr != NULL && !pst->readin) { /* Need to get the terminal in case symbol-reading produces output. */ target_terminal_ours_for_output (); PSYMTAB_TO_SYMTAB (pst); } if (pst->readin) { /* Checking whether the msymbol has a larger value is for the "pathological" case mentioned in print_frame_info. */ if (inlining_flag) f = find_pc_sect_function (mapped_pc, section); else f = find_pc_sect_function_no_inlined (mapped_pc, section); /* APPLE LOCAL begin address ranges */ if (f != NULL && (msymbol == NULL || (BLOCK_LOWEST_PC (SYMBOL_BLOCK_VALUE (f)) >= SYMBOL_VALUE_ADDRESS (msymbol)))) { cache_pc_function_low = BLOCK_LOWEST_PC (SYMBOL_BLOCK_VALUE (f)); if (BLOCK_RANGES (SYMBOL_BLOCK_VALUE (f))) cache_pc_function_high = BLOCK_HIGHEST_PC (SYMBOL_BLOCK_VALUE (f)); else cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f)); /* APPLE LOCAL end address ranges */ cache_pc_function_name = DEPRECATED_SYMBOL_NAME (f); cache_pc_function_section = section; goto return_cached_value; } } else { /* Now that static symbols go in the minimal symbol table, perhaps we could just ignore the partial symbols. But at least for now we use the partial or minimal symbol, whichever is larger. */ psb = find_pc_sect_psymbol (pst, mapped_pc, section); if (psb && (msymbol == NULL || (SYMBOL_VALUE_ADDRESS (psb) >= SYMBOL_VALUE_ADDRESS (msymbol)))) { /* This case isn't being cached currently. */ if (address) *address = SYMBOL_VALUE_ADDRESS (psb); if (name) *name = DEPRECATED_SYMBOL_NAME (psb); /* endaddr non-NULL can't happen here. */ return 1; } } } /* Not in the normal symbol tables, see if the pc is in a known section. If it's not, then give up. This ensures that anything beyond the end of the text seg doesn't appear to be part of the last function in the text segment. */ osect = find_pc_sect_section (mapped_pc, section); if (!osect) msymbol = NULL; /* Must be in the minimal symbol table. */ if (msymbol == NULL) { /* No available symbol. */ if (name != NULL) *name = 0; if (address != NULL) *address = 0; if (endaddr != NULL) *endaddr = 0; return 0; } cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol); cache_pc_function_name = DEPRECATED_SYMBOL_NAME (msymbol); cache_pc_function_section = section; /* Use the lesser of the next minimal symbol in the same section, or the end of the section, as the end of the function. */ /* Step over other symbols at this same address, and symbols in other sections, to find the next symbol in this section with a different address. */ for (i = 1; DEPRECATED_SYMBOL_NAME (msymbol + i) != NULL; i++) { if (SYMBOL_VALUE_ADDRESS (msymbol + i) != SYMBOL_VALUE_ADDRESS (msymbol) && SYMBOL_BFD_SECTION (msymbol + i) == SYMBOL_BFD_SECTION (msymbol)) break; } if (DEPRECATED_SYMBOL_NAME (msymbol + i) != NULL && SYMBOL_VALUE_ADDRESS (msymbol + i) < osect->endaddr) cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + i); else /* We got the start address from the last msymbol in the objfile. So the end address is the end of the section. */ cache_pc_function_high = osect->endaddr; return_cached_value: if (address) { if (pc_in_unmapped_range (pc, section)) *address = overlay_unmapped_address (cache_pc_function_low, section); else *address = cache_pc_function_low; } if (name) *name = cache_pc_function_name; if (endaddr) { if (pc_in_unmapped_range (pc, section)) { /* Because the high address is actually beyond the end of the function (and therefore possibly beyond the end of the overlay), we must actually convert (high - 1) and then add one to that. */ *endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1, section); } else *endaddr = cache_pc_function_high; } return 1; }