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 int hppa64_hpux_in_solib_call_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc, char *name) { enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); /* PA64 has a completely different stub/trampoline scheme. Is it better? Maybe. It's certainly harder to determine with any certainty that we are in a stub because we can not refer to the unwinders to help. The heuristic is simple. Try to lookup the current PC value in th minimal symbol table. If that fails, then assume we are not in a stub and return. Then see if the PC value falls within the section bounds for the section containing the minimal symbol we found in the first step. If it does, then assume we are not in a stub and return. Finally peek at the instructions to see if they look like a stub. */ struct minimal_symbol *minsym; asection *sec; CORE_ADDR addr; int insn, i; minsym = lookup_minimal_symbol_by_pc (pc); if (! minsym) return 0; sec = SYMBOL_OBJ_SECTION (minsym)->the_bfd_section; if (bfd_get_section_vma (sec->owner, sec) <= pc && pc < (bfd_get_section_vma (sec->owner, sec) + bfd_section_size (sec->owner, sec))) return 0; /* We might be in a stub. Peek at the instructions. Stubs are 3 instructions long. */ insn = read_memory_integer (pc, 4, byte_order); /* Find out where we think we are within the stub. */ if ((insn & 0xffffc00e) == 0x53610000) addr = pc; else if ((insn & 0xffffffff) == 0xe820d000) addr = pc - 4; else if ((insn & 0xffffc00e) == 0x537b0000) addr = pc - 8; else return 0; /* Now verify each insn in the range looks like a stub instruction. */ insn = read_memory_integer (addr, 4, byte_order); if ((insn & 0xffffc00e) != 0x53610000) return 0; /* Now verify each insn in the range looks like a stub instruction. */ insn = read_memory_integer (addr + 4, 4, byte_order); if ((insn & 0xffffffff) != 0xe820d000) return 0; /* Now verify each insn in the range looks like a stub instruction. */ insn = read_memory_integer (addr + 8, 4, byte_order); if ((insn & 0xffffc00e) != 0x537b0000) return 0; /* Looks like a stub. */ return 1; }
int find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address, CORE_ADDR *endaddr) { struct obj_section *section; struct partial_symtab *pst; struct symbol *f; struct minimal_symbol *msymbol; struct partial_symbol *psb; 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); 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. */ 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; 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 = SYMBOL_LINKAGE_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. */ 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; return 0; } cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol); cache_pc_function_name = SYMBOL_LINKAGE_NAME (msymbol); cache_pc_function_section = section; /* 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; } return 1; }