void minimal_symbol_reader::record (const char *name, CORE_ADDR address, enum minimal_symbol_type ms_type) { int section; switch (ms_type) { case mst_text: case mst_text_gnu_ifunc: case mst_file_text: case mst_solib_trampoline: section = SECT_OFF_TEXT (m_objfile); break; case mst_data: case mst_data_gnu_ifunc: case mst_file_data: section = SECT_OFF_DATA (m_objfile); break; case mst_bss: case mst_file_bss: section = SECT_OFF_BSS (m_objfile); break; default: section = -1; } record_with_info (name, address, ms_type, section); }
static gdb_byte * find_location_expression (struct dwarf2_loclist_baton *baton, size_t *locexpr_length, CORE_ADDR pc) { CORE_ADDR low, high; gdb_byte *loc_ptr, *buf_end; int length; struct objfile *objfile = dwarf2_per_cu_objfile (baton->per_cu); struct gdbarch *gdbarch = get_objfile_arch (objfile); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); unsigned int addr_size = dwarf2_per_cu_addr_size (baton->per_cu); CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); /* Adjust base_address for relocatable objects. */ CORE_ADDR base_offset = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); CORE_ADDR base_address = baton->base_address + base_offset; loc_ptr = baton->data; buf_end = baton->data + baton->size; while (1) { if (buf_end - loc_ptr < 2 * addr_size) error (_("find_location_expression: Corrupted DWARF expression.")); low = extract_unsigned_integer (loc_ptr, addr_size, byte_order); loc_ptr += addr_size; /* A base-address-selection entry. */ if (low == base_mask) { base_address = dwarf2_read_address (gdbarch, loc_ptr, buf_end, addr_size); loc_ptr += addr_size; continue; } high = extract_unsigned_integer (loc_ptr, addr_size, byte_order); loc_ptr += addr_size; /* An end-of-list entry. */ if (low == 0 && high == 0) return NULL; /* Otherwise, a location expression entry. */ low += base_address; high += base_address; length = extract_unsigned_integer (loc_ptr, 2, byte_order); loc_ptr += 2; if (pc >= low && pc < high) { *locexpr_length = length; return loc_ptr; } loc_ptr += length; } }
static gdb_byte * find_location_expression (struct dwarf2_loclist_baton *baton, size_t *locexpr_length, CORE_ADDR pc) { CORE_ADDR low, high; gdb_byte *loc_ptr, *buf_end; int length; unsigned int addr_size = gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT; CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); /* Adjust base_address for relocatable objects. */ CORE_ADDR base_offset = ANOFFSET (baton->objfile->section_offsets, SECT_OFF_TEXT (baton->objfile)); CORE_ADDR base_address = baton->base_address + base_offset; loc_ptr = baton->data; buf_end = baton->data + baton->size; while (1) { low = dwarf2_read_address (loc_ptr, buf_end, &length); loc_ptr += length; high = dwarf2_read_address (loc_ptr, buf_end, &length); loc_ptr += length; /* An end-of-list entry. */ if (low == 0 && high == 0) return NULL; /* A base-address-selection entry. */ if ((low & base_mask) == base_mask) { base_address = high; continue; } /* Otherwise, a location expression entry. */ low += base_address; high += base_address; length = extract_unsigned_integer (loc_ptr, 2); loc_ptr += 2; if (pc >= low && pc < high) { *locexpr_length = length; return loc_ptr; } loc_ptr += length; } }
static void vmap_symtab (struct vmap *vp) { struct objfile *objfile; struct section_offsets *new_offsets; int i; objfile = vp->objfile; if (objfile == NULL) { /* OK, it's not an objfile we opened ourselves. Currently, that can only happen with the exec file, so relocate the symbols for the symfile. */ if (symfile_objfile == NULL) return; objfile = symfile_objfile; } else if (!vp->loaded) /* If symbols are not yet loaded, offsets are not yet valid. */ return; new_offsets = (struct section_offsets *) alloca (SIZEOF_N_SECTION_OFFSETS (objfile->num_sections)); for (i = 0; i < objfile->num_sections; ++i) new_offsets->offsets[i] = ANOFFSET (objfile->section_offsets, i); /* The symbols in the object file are linked to the VMA of the section, relocate them VMA relative. */ new_offsets->offsets[SECT_OFF_TEXT (objfile)] = vp->tstart - vp->tvma; new_offsets->offsets[SECT_OFF_DATA (objfile)] = vp->dstart - vp->dvma; new_offsets->offsets[SECT_OFF_BSS (objfile)] = vp->dstart - vp->dvma; /* Perform the same adjustment as the loader if the .data and .bss sections overlap. */ new_offsets->offsets[SECT_OFF_BSS (objfile)] += bss_data_overlap (objfile); objfile_relocate (objfile, new_offsets); }
static int add_pe_forwarded_sym (minimal_symbol_reader &reader, const char *sym_name, const char *forward_dll_name, const char *forward_func_name, int ordinal, const char *dll_name, struct objfile *objfile) { CORE_ADDR vma, baseaddr; struct bound_minimal_symbol msymbol; enum minimal_symbol_type msymtype; char *qualified_name, *bare_name; int forward_dll_name_len = strlen (forward_dll_name); int forward_func_name_len = strlen (forward_func_name); int forward_len = forward_dll_name_len + forward_func_name_len + 2; char *forward_qualified_name = (char *) alloca (forward_len); short section; xsnprintf (forward_qualified_name, forward_len, "%s!%s", forward_dll_name, forward_func_name); msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name); if (!msymbol.minsym) { int i; for (i = 0; i < forward_dll_name_len; i++) forward_qualified_name[i] = tolower (forward_qualified_name[i]); msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name); } if (!msymbol.minsym) { if (debug_coff_pe_read) fprintf_unfiltered (gdb_stdlog, _("Unable to find function \"%s\" in" " dll \"%s\", forward of \"%s\" in dll \"%s\"\n"), forward_func_name, forward_dll_name, sym_name, dll_name); return 0; } if (debug_coff_pe_read > 1) fprintf_unfiltered (gdb_stdlog, _("Adding forwarded exported symbol" " \"%s\" in dll \"%s\", pointing to \"%s\"\n"), sym_name, dll_name, forward_qualified_name); vma = BMSYMBOL_VALUE_ADDRESS (msymbol); msymtype = MSYMBOL_TYPE (msymbol.minsym); section = MSYMBOL_SECTION (msymbol.minsym); /* Generate a (hopefully unique) qualified name using the first part of the dll name, e.g. KERNEL32!AddAtomA. This matches the style used by windbg from the "Microsoft Debugging Tools for Windows". */ if (sym_name == NULL || *sym_name == '\0') bare_name = xstrprintf ("#%d", ordinal); else bare_name = xstrdup (sym_name); qualified_name = xstrprintf ("%s!%s", dll_name, bare_name); /* Note that this code makes a minimal symbol whose value may point outside of any section in this objfile. These symbols can't really be relocated properly, but nevertheless we make a stab at it, choosing an approach consistent with the history of this code. */ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); reader.record_with_info (qualified_name, vma - baseaddr, msymtype, section); /* Enter the plain name as well, which might not be unique. */ reader.record_with_info (bare_name, vma - baseaddr, msymtype, section); xfree (qualified_name); xfree (bare_name); return 1; }
void read_pe_exported_syms (struct objfile *objfile) { bfd *dll = objfile->obfd; unsigned long nbnormal, nbforward; unsigned long pe_header_offset, opthdr_ofs, num_entries, i; unsigned long export_opthdrrva, export_opthdrsize; unsigned long export_rva, export_size, nsections, secptr, expptr; unsigned long exp_funcbase; unsigned char *expdata, *erva; unsigned long name_rvas, ordinals, nexp, ordbase; char *dll_name = (char *) dll->filename; int otherix = PE_SECTION_TABLE_SIZE; int is_pe64 = 0; int is_pe32 = 0; /* Array elements are for text, data and bss in that order Initialization with RVA_START > RVA_END guarantees that unused sections won't be matched. */ struct read_pe_section_data *section_data; struct pe_sections_info pe_sections_info; struct cleanup *back_to = make_cleanup (null_cleanup, 0); char const *target = bfd_get_target (objfile->obfd); section_data = xzalloc (PE_SECTION_TABLE_SIZE * sizeof (struct read_pe_section_data)); make_cleanup (free_current_contents, §ion_data); for (i=0; i < PE_SECTION_TABLE_SIZE; i++) { section_data[i].vma_offset = 0; section_data[i].rva_start = 1; section_data[i].rva_end = 0; }; section_data[PE_SECTION_INDEX_TEXT].ms_type = mst_text; section_data[PE_SECTION_INDEX_TEXT].section_name = ".text"; section_data[PE_SECTION_INDEX_DATA].ms_type = mst_data; section_data[PE_SECTION_INDEX_DATA].section_name = ".data"; section_data[PE_SECTION_INDEX_BSS].ms_type = mst_bss; section_data[PE_SECTION_INDEX_BSS].section_name = ".bss"; is_pe64 = (strcmp (target, "pe-x86-64") == 0 || strcmp (target, "pei-x86-64") == 0); is_pe32 = (strcmp (target, "pe-i386") == 0 || strcmp (target, "pei-i386") == 0 || strcmp (target, "pe-arm-wince-little") == 0 || strcmp (target, "pei-arm-wince-little") == 0); if (!is_pe32 && !is_pe64) { /* This is not a recognized PE format file. Abort now, because the code is untested on anything else. *FIXME* test on further architectures and loosen or remove this test. */ do_cleanups (back_to); return; } /* Get pe_header, optional header and numbers of export entries. */ pe_header_offset = pe_get32 (dll, 0x3c); opthdr_ofs = pe_header_offset + 4 + 20; if (is_pe64) num_entries = pe_get32 (dll, opthdr_ofs + 108); else num_entries = pe_get32 (dll, opthdr_ofs + 92); if (num_entries < 1) /* No exports. */ { do_cleanups (back_to); return; } if (is_pe64) { export_opthdrrva = pe_get32 (dll, opthdr_ofs + 112); export_opthdrsize = pe_get32 (dll, opthdr_ofs + 116); } else { export_opthdrrva = pe_get32 (dll, opthdr_ofs + 96); export_opthdrsize = pe_get32 (dll, opthdr_ofs + 100); } nsections = pe_get16 (dll, pe_header_offset + 4 + 2); secptr = (pe_header_offset + 4 + 20 + pe_get16 (dll, pe_header_offset + 4 + 16)); expptr = 0; export_size = 0; /* Get the rva and size of the export section. */ for (i = 0; i < nsections; i++) { char sname[8]; unsigned long secptr1 = secptr + 40 * i; unsigned long vaddr = pe_get32 (dll, secptr1 + 12); unsigned long vsize = pe_get32 (dll, secptr1 + 16); unsigned long fptr = pe_get32 (dll, secptr1 + 20); bfd_seek (dll, (file_ptr) secptr1, SEEK_SET); bfd_bread (sname, (bfd_size_type) sizeof (sname), dll); if ((strcmp (sname, ".edata") == 0) || (vaddr <= export_opthdrrva && export_opthdrrva < vaddr + vsize)) { if (strcmp (sname, ".edata") != 0) { if (debug_coff_pe_read) fprintf_unfiltered (gdb_stdlog, _("Export RVA for dll " "\"%s\" is in section \"%s\"\n"), dll_name, sname); } else if (export_opthdrrva != vaddr && debug_coff_pe_read) fprintf_unfiltered (gdb_stdlog, _("Wrong value of export RVA" " for dll \"%s\": 0x%lx instead of 0x%lx\n"), dll_name, export_opthdrrva, vaddr); expptr = fptr + (export_opthdrrva - vaddr); break; } } export_rva = export_opthdrrva; export_size = export_opthdrsize; if (export_size == 0) { /* Empty export table. */ do_cleanups (back_to); return; } /* Scan sections and store the base and size of the relevant sections. */ for (i = 0; i < nsections; i++) { unsigned long secptr1 = secptr + 40 * i; unsigned long vsize = pe_get32 (dll, secptr1 + 8); unsigned long vaddr = pe_get32 (dll, secptr1 + 12); unsigned long characteristics = pe_get32 (dll, secptr1 + 36); char sec_name[SCNNMLEN + 1]; int sectix; bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET); bfd_bread (sec_name, (bfd_size_type) SCNNMLEN, dll); sec_name[SCNNMLEN] = '\0'; sectix = read_pe_section_index (sec_name); if (sectix != PE_SECTION_INDEX_INVALID) { section_data[sectix].rva_start = vaddr; section_data[sectix].rva_end = vaddr + vsize; } else { char *name; section_data = xrealloc (section_data, (otherix + 1) * sizeof (struct read_pe_section_data)); name = xstrdup (sec_name); section_data[otherix].section_name = name; make_cleanup (xfree, name); section_data[otherix].rva_start = vaddr; section_data[otherix].rva_end = vaddr + vsize; section_data[otherix].vma_offset = 0; if (characteristics & IMAGE_SCN_CNT_CODE) section_data[otherix].ms_type = mst_text; else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) section_data[otherix].ms_type = mst_data; else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) section_data[otherix].ms_type = mst_bss; else section_data[otherix].ms_type = mst_unknown; otherix++; } } expdata = (unsigned char *) xmalloc (export_size); make_cleanup (xfree, expdata); bfd_seek (dll, (file_ptr) expptr, SEEK_SET); bfd_bread (expdata, (bfd_size_type) export_size, dll); erva = expdata - export_rva; nexp = pe_as32 (expdata + 24); name_rvas = pe_as32 (expdata + 32); ordinals = pe_as32 (expdata + 36); ordbase = pe_as32 (expdata + 16); exp_funcbase = pe_as32 (expdata + 28); /* Use internal dll name instead of full pathname. */ dll_name = pe_as32 (expdata + 12) + erva; pe_sections_info.nb_sections = otherix; pe_sections_info.sections = section_data; bfd_map_over_sections (dll, get_section_vmas, &pe_sections_info); /* Adjust the vma_offsets in case this PE got relocated. This assumes that *all* sections share the same relocation offset as the text section. */ for (i = 0; i < otherix; i++) { section_data[i].vma_offset += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); } /* Truncate name at first dot. Should maybe also convert to all lower case for convenience on Windows. */ read_pe_truncate_name (dll_name); if (debug_coff_pe_read) fprintf_unfiltered (gdb_stdlog, _("DLL \"%s\" has %ld export entries," " base=%ld\n"), dll_name, nexp, ordbase); nbforward = 0; nbnormal = 0; /* Iterate through the list of symbols. */ for (i = 0; i < nexp; i++) { /* Pointer to the names vector. */ unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4); /* Retrieve ordinal value. */ unsigned long ordinal = pe_as16 (erva + ordinals + i * 2); /* Pointer to the function address vector. */ /* This is relatived to ordinal value. */ unsigned long func_rva = pe_as32 (erva + exp_funcbase + ordinal * 4); /* Find this symbol's section in our own array. */ int sectix = 0; int section_found = 0; /* First handle forward cases. */ if (func_rva >= export_rva && func_rva < export_rva + export_size) { char *forward_name = (char *) (erva + func_rva); char *funcname = (char *) (erva + name_rva); char *forward_dll_name = forward_name; char *forward_func_name = forward_name; char *sep = strrchr (forward_name, '.'); if (sep) { int len = (int) (sep - forward_name); forward_dll_name = alloca (len + 1); strncpy (forward_dll_name, forward_name, len); forward_dll_name[len] = '\0'; forward_func_name = ++sep; } if (add_pe_forwarded_sym (funcname, forward_dll_name, forward_func_name, ordinal, dll_name, objfile) != 0) ++nbforward; continue; } for (sectix = 0; sectix < otherix; ++sectix) { if ((func_rva >= section_data[sectix].rva_start) && (func_rva < section_data[sectix].rva_end)) { section_found = 1; add_pe_exported_sym (erva + name_rva, func_rva, ordinal, section_data + sectix, dll_name, objfile); ++nbnormal; break; } } if (!section_found) { char *funcname = (char *) (erva + name_rva); if (name_rva == 0) { add_pe_exported_sym (NULL, func_rva, ordinal, section_data, dll_name, objfile); ++nbnormal; } else if (debug_coff_pe_read) fprintf_unfiltered (gdb_stdlog, _("Export name \"%s\" ord. %lu," " RVA 0x%lx in dll \"%s\" not handled\n"), funcname, ordinal, func_rva, dll_name); } } if (debug_coff_pe_read) fprintf_unfiltered (gdb_stdlog, _("Finished reading \"%s\", exports %ld," " forwards %ld, total %ld/%ld.\n"), dll_name, nbnormal, nbforward, nbnormal + nbforward, nexp); /* Discard expdata and section_data. */ do_cleanups (back_to); }
void read_pe_exported_syms (struct objfile *objfile) { bfd *dll = objfile->obfd; unsigned long pe_header_offset, opthdr_ofs, num_entries, i; unsigned long export_rva, export_size, nsections, secptr, expptr; unsigned long exp_funcbase; unsigned char *expdata, *erva; unsigned long name_rvas, ordinals, nexp, ordbase; char *dll_name; /* Array elements are for text, data and bss in that order Initialization with start_rva > end_rva guarantees that unused sections won't be matched. */ struct read_pe_section_data section_data[PE_SECTION_TABLE_SIZE] = { {0, 1, 0, mst_text}, {0, 1, 0, mst_data}, {0, 1, 0, mst_bss} }; struct cleanup *back_to = 0; char const *target = bfd_get_target (objfile->obfd); if ((strcmp (target, "pe-i386") != 0) && (strcmp (target, "pei-i386") != 0)) { /* This is not an i386 format file. Abort now, because the code is untested on anything else. *FIXME* test on further architectures and loosen or remove this test. */ return; } /* Get pe_header, optional header and numbers of export entries. */ pe_header_offset = pe_get32 (dll, 0x3c); opthdr_ofs = pe_header_offset + 4 + 20; num_entries = pe_get32 (dll, opthdr_ofs + 92); if (num_entries < 1) /* No exports. */ { return; } export_rva = pe_get32 (dll, opthdr_ofs + 96); export_size = pe_get32 (dll, opthdr_ofs + 100); nsections = pe_get16 (dll, pe_header_offset + 4 + 2); secptr = (pe_header_offset + 4 + 20 + pe_get16 (dll, pe_header_offset + 4 + 16)); expptr = 0; /* Get the rva and size of the export section. */ for (i = 0; i < nsections; i++) { char sname[8]; unsigned long secptr1 = secptr + 40 * i; unsigned long vaddr = pe_get32 (dll, secptr1 + 12); unsigned long vsize = pe_get32 (dll, secptr1 + 16); unsigned long fptr = pe_get32 (dll, secptr1 + 20); bfd_seek (dll, (file_ptr) secptr1, SEEK_SET); bfd_bread (sname, (bfd_size_type) 8, dll); if (vaddr <= export_rva && vaddr + vsize > export_rva) { expptr = fptr + (export_rva - vaddr); if (export_rva + export_size > vaddr + vsize) export_size = vsize - (export_rva - vaddr); break; } } if (export_size == 0) { /* Empty export table. */ return; } /* Scan sections and store the base and size of the relevant sections. */ for (i = 0; i < nsections; i++) { unsigned long secptr1 = secptr + 40 * i; unsigned long vsize = pe_get32 (dll, secptr1 + 8); unsigned long vaddr = pe_get32 (dll, secptr1 + 12); unsigned long flags = pe_get32 (dll, secptr1 + 36); char sec_name[9]; int sectix; sec_name[8] = '\0'; bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET); bfd_bread (sec_name, (bfd_size_type) 8, dll); sectix = read_pe_section_index (sec_name); if (sectix != PE_SECTION_INDEX_INVALID) { section_data[sectix].rva_start = vaddr; section_data[sectix].rva_end = vaddr + vsize; } } expdata = (unsigned char *) xmalloc (export_size); back_to = make_cleanup (xfree, expdata); bfd_seek (dll, (file_ptr) expptr, SEEK_SET); bfd_bread (expdata, (bfd_size_type) export_size, dll); erva = expdata - export_rva; nexp = pe_as32 (expdata + 24); name_rvas = pe_as32 (expdata + 32); ordinals = pe_as32 (expdata + 36); ordbase = pe_as32 (expdata + 16); exp_funcbase = pe_as32 (expdata + 28); /* Use internal dll name instead of full pathname. */ dll_name = pe_as32 (expdata + 12) + erva; bfd_map_over_sections (dll, get_section_vmas, section_data); /* Adjust the vma_offsets in case this PE got relocated. This assumes that *all* sections share the same relocation offset as the text section. */ for (i = 0; i < PE_SECTION_TABLE_SIZE; i++) { section_data[i].vma_offset += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); } printf_filtered ("Minimal symbols from %s...", dll_name); wrap_here (""); /* Truncate name at first dot. Should maybe also convert to all lower case for convenience on Windows. */ read_pe_truncate_name (dll_name); /* Iterate through the list of symbols. */ for (i = 0; i < nexp; i++) { /* Pointer to the names vector. */ unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4); /* Pointer to the function address vector. */ unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4); /* Find this symbol's section in our own array. */ int sectix = 0; for (sectix = 0; sectix < PE_SECTION_TABLE_SIZE; ++sectix) { if ((func_rva >= section_data[sectix].rva_start) && (func_rva < section_data[sectix].rva_end)) { add_pe_exported_sym (erva + name_rva, func_rva, section_data + sectix, dll_name, objfile); break; } } } /* discard expdata. */ do_cleanups (back_to); }
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; }
static void read_alphacoff_dynamic_symtab (struct section_offsets *section_offsets, struct objfile *objfile) { bfd *abfd = objfile->obfd; struct alphacoff_dynsecinfo si; char *sym_secptr; char *str_secptr; char *dyninfo_secptr; char *got_secptr; bfd_size_type sym_secsize; bfd_size_type str_secsize; bfd_size_type dyninfo_secsize; bfd_size_type got_secsize; int sym_count; int i; int stripped; Elfalpha_External_Sym *x_symp; char *dyninfo_p; char *dyninfo_end; int got_entry_size = 8; int dt_mips_local_gotno = -1; int dt_mips_gotsym = -1; struct cleanup *cleanups; /* We currently only know how to handle alpha dynamic symbols. */ if (bfd_get_arch (abfd) != bfd_arch_alpha) return; /* Locate the dynamic symbols sections and read them in. */ memset ((char *) &si, 0, sizeof (si)); bfd_map_over_sections (abfd, alphacoff_locate_sections, (void *) & si); if (si.sym_sect == NULL || si.str_sect == NULL || si.dyninfo_sect == NULL || si.got_sect == NULL) return; sym_secsize = bfd_get_section_size (si.sym_sect); str_secsize = bfd_get_section_size (si.str_sect); dyninfo_secsize = bfd_get_section_size (si.dyninfo_sect); got_secsize = bfd_get_section_size (si.got_sect); sym_secptr = xmalloc (sym_secsize); cleanups = make_cleanup (xfree, sym_secptr); str_secptr = xmalloc (str_secsize); make_cleanup (xfree, str_secptr); dyninfo_secptr = xmalloc (dyninfo_secsize); make_cleanup (xfree, dyninfo_secptr); got_secptr = xmalloc (got_secsize); make_cleanup (xfree, got_secptr); if (!bfd_get_section_contents (abfd, si.sym_sect, sym_secptr, (file_ptr) 0, sym_secsize)) return; if (!bfd_get_section_contents (abfd, si.str_sect, str_secptr, (file_ptr) 0, str_secsize)) return; if (!bfd_get_section_contents (abfd, si.dyninfo_sect, dyninfo_secptr, (file_ptr) 0, dyninfo_secsize)) return; if (!bfd_get_section_contents (abfd, si.got_sect, got_secptr, (file_ptr) 0, got_secsize)) return; /* Find the number of local GOT entries and the index for the the first dynamic symbol in the GOT. */ for (dyninfo_p = dyninfo_secptr, dyninfo_end = dyninfo_p + dyninfo_secsize; dyninfo_p < dyninfo_end; dyninfo_p += sizeof (Elfalpha_External_Dyn)) { Elfalpha_External_Dyn *x_dynp = (Elfalpha_External_Dyn *) dyninfo_p; long dyn_tag; dyn_tag = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_tag); if (dyn_tag == DT_NULL) break; else if (dyn_tag == DT_MIPS_LOCAL_GOTNO) { if (dt_mips_local_gotno < 0) dt_mips_local_gotno = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_un.d_val); } else if (dyn_tag == DT_MIPS_GOTSYM) { if (dt_mips_gotsym < 0) dt_mips_gotsym = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_un.d_val); } } if (dt_mips_local_gotno < 0 || dt_mips_gotsym < 0) return; /* Scan all dynamic symbols and enter them into the minimal symbol table if appropriate. */ sym_count = sym_secsize / sizeof (Elfalpha_External_Sym); stripped = (bfd_get_symcount (abfd) == 0); /* Skip first symbol, which is a null dummy. */ for (i = 1, x_symp = (Elfalpha_External_Sym *) sym_secptr + 1; i < sym_count; i++, x_symp++) { unsigned long strx; char *name; bfd_vma sym_value; unsigned char sym_info; unsigned int sym_shndx; int isglobal; enum minimal_symbol_type ms_type; strx = bfd_h_get_32 (abfd, (bfd_byte *) x_symp->st_name); if (strx >= str_secsize) continue; name = str_secptr + strx; if (*name == '\0' || *name == '.') continue; sym_value = bfd_h_get_64 (abfd, (bfd_byte *) x_symp->st_value); sym_info = bfd_h_get_8 (abfd, (bfd_byte *) x_symp->st_info); sym_shndx = bfd_h_get_16 (abfd, (bfd_byte *) x_symp->st_shndx); if (sym_shndx >= (SHN_LORESERVE & 0xffff)) sym_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff); isglobal = (ELF_ST_BIND (sym_info) == STB_GLOBAL); if (sym_shndx == SHN_UNDEF) { /* Handle undefined functions which are defined in a shared library. */ if (ELF_ST_TYPE (sym_info) != STT_FUNC || ELF_ST_BIND (sym_info) != STB_GLOBAL) continue; ms_type = mst_solib_trampoline; /* If sym_value is nonzero, it points to the shared library trampoline entry, which is what we are looking for. If sym_value is zero, then we have to get the GOT entry for the symbol. If the GOT entry is nonzero, it represents the quickstart address of the function and we use that as the symbol value. If the GOT entry is zero, the function address has to be resolved by the runtime loader before the executable is started. We are unable to find any meaningful address for these functions in the executable file, so we skip them. */ if (sym_value == 0) { int got_entry_offset = (i - dt_mips_gotsym + dt_mips_local_gotno) * got_entry_size; if (got_entry_offset < 0 || got_entry_offset >= got_secsize) continue; sym_value = bfd_h_get_64 (abfd, (bfd_byte *) (got_secptr + got_entry_offset)); if (sym_value == 0) continue; } } else { /* Symbols defined in the executable itself. We only care about them if this is a stripped executable, otherwise they have been retrieved from the normal symbol table already. */ if (!stripped) continue; if (sym_shndx == SHN_MIPS_TEXT) { if (isglobal) ms_type = mst_text; else ms_type = mst_file_text; sym_value += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)); } else if (sym_shndx == SHN_MIPS_DATA) { if (isglobal) ms_type = mst_data; else ms_type = mst_file_data; sym_value += ANOFFSET (section_offsets, SECT_OFF_DATA (objfile)); } else if (sym_shndx == SHN_MIPS_ACOMMON) { if (isglobal) ms_type = mst_bss; else ms_type = mst_file_bss; sym_value += ANOFFSET (section_offsets, SECT_OFF_BSS (objfile)); } else if (sym_shndx == SHN_ABS) { ms_type = mst_abs; } else { continue; } } prim_record_minimal_symbol (name, sym_value, ms_type, objfile); } do_cleanups (cleanups); }
static void som_symtab_read (bfd *abfd, struct objfile *objfile, struct section_offsets *section_offsets) { struct cleanup *cleanup; struct gdbarch *gdbarch = get_objfile_arch (objfile); unsigned int number_of_symbols; int val, dynamic; char *stringtab; asection *shlib_info; struct som_external_symbol_dictionary_record *buf, *bufp, *endbufp; char *symname; const int symsize = sizeof (struct som_external_symbol_dictionary_record); number_of_symbols = bfd_get_symcount (abfd); /* Allocate a buffer to read in the debug info. We avoid using alloca because the memory size could be so large that we could hit the stack size limit. */ buf = xmalloc (symsize * number_of_symbols); cleanup = make_cleanup (xfree, buf); bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET); val = bfd_bread (buf, symsize * number_of_symbols, abfd); if (val != symsize * number_of_symbols) error (_("Couldn't read symbol dictionary!")); /* Allocate a buffer to read in the som stringtab section of the debugging info. Again, we avoid using alloca because the data could be so large that we could potentially hit the stack size limitat. */ stringtab = xmalloc (obj_som_stringtab_size (abfd)); make_cleanup (xfree, stringtab); bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET); val = bfd_bread (stringtab, obj_som_stringtab_size (abfd), abfd); if (val != obj_som_stringtab_size (abfd)) error (_("Can't read in HP string table.")); /* We need to determine if objfile is a dynamic executable (so we can do the right thing for ST_ENTRY vs ST_CODE symbols). There's nothing in the header which easily allows us to do this. This code used to rely upon the existence of a $SHLIB_INFO$ section to make this determination. HP claims that it is more accurate to check for a nonzero text offset, but they have not provided any information about why that test is more accurate. */ dynamic = (ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)) != 0); endbufp = buf + number_of_symbols; for (bufp = buf; bufp < endbufp; ++bufp) { enum minimal_symbol_type ms_type; unsigned int flags = bfd_getb32 (bufp->flags); unsigned int symbol_type = (flags >> SOM_SYMBOL_TYPE_SH) & SOM_SYMBOL_TYPE_MASK; unsigned int symbol_scope = (flags >> SOM_SYMBOL_SCOPE_SH) & SOM_SYMBOL_SCOPE_MASK; CORE_ADDR symbol_value = bfd_getb32 (bufp->symbol_value); asection *section = NULL; QUIT; /* Compute the section. */ switch (symbol_scope) { case SS_EXTERNAL: if (symbol_type != ST_STORAGE) section = bfd_und_section_ptr; else section = bfd_com_section_ptr; break; case SS_UNSAT: if (symbol_type != ST_STORAGE) section = bfd_und_section_ptr; else section = bfd_com_section_ptr; break; case SS_UNIVERSAL: section = bfd_section_from_som_symbol (abfd, bufp); break; case SS_LOCAL: section = bfd_section_from_som_symbol (abfd, bufp); break; } switch (symbol_scope) { case SS_UNIVERSAL: case SS_EXTERNAL: switch (symbol_type) { case ST_SYM_EXT: case ST_ARG_EXT: continue; case ST_CODE: case ST_PRI_PROG: case ST_SEC_PROG: case ST_MILLICODE: symname = bfd_getb32 (bufp->name) + stringtab; ms_type = mst_text; symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); break; case ST_ENTRY: symname = bfd_getb32 (bufp->name) + stringtab; /* For a dynamic executable, ST_ENTRY symbols are the stubs, while the ST_CODE symbol is the real function. */ if (dynamic) ms_type = mst_solib_trampoline; else ms_type = mst_text; symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); break; case ST_STUB: symname = bfd_getb32 (bufp->name) + stringtab; ms_type = mst_solib_trampoline; symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); break; case ST_DATA: symname = bfd_getb32 (bufp->name) + stringtab; ms_type = mst_data; break; default: continue; } break; #if 0 /* SS_GLOBAL and SS_LOCAL are two names for the same thing (!). */ case SS_GLOBAL: #endif case SS_LOCAL: switch (symbol_type) { case ST_SYM_EXT: case ST_ARG_EXT: continue; case ST_CODE: symname = bfd_getb32 (bufp->name) + stringtab; ms_type = mst_file_text; symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); check_strange_names: /* Utah GCC 2.5, FSF GCC 2.6 and later generate correct local label prefixes for stabs, constant data, etc. So we need only filter out L$ symbols which are left in due to limitations in how GAS generates SOM relocations. When linking in the HPUX C-library the HP linker has the nasty habit of placing section symbols from the literal subspaces in the middle of the program's text. Filter those out as best we can. Check for first and last character being '$'. And finally, the newer HP compilers emit crud like $PIC_foo$N in some circumstance (PIC code I guess). It's also claimed that they emit D$ symbols too. What stupidity. */ if ((symname[0] == 'L' && symname[1] == '$') || (symname[0] == '$' && symname[strlen (symname) - 1] == '$') || (symname[0] == 'D' && symname[1] == '$') || (strncmp (symname, "L0\001", 3) == 0) || (strncmp (symname, "$PIC", 4) == 0)) continue; break; case ST_PRI_PROG: case ST_SEC_PROG: case ST_MILLICODE: symname = bfd_getb32 (bufp->name) + stringtab; ms_type = mst_file_text; symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); break; case ST_ENTRY: symname = bfd_getb32 (bufp->name) + stringtab; /* SS_LOCAL symbols in a shared library do not have export stubs, so we do not have to worry about using mst_file_text vs mst_solib_trampoline here like we do for SS_UNIVERSAL and SS_EXTERNAL symbols above. */ ms_type = mst_file_text; symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); break; case ST_STUB: symname = bfd_getb32 (bufp->name) + stringtab; ms_type = mst_solib_trampoline; symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); break; case ST_DATA: symname = bfd_getb32 (bufp->name) + stringtab; ms_type = mst_file_data; goto check_strange_names; default: continue; } break; /* This can happen for common symbols when -E is passed to the final link. No idea _why_ that would make the linker force common symbols to have an SS_UNSAT scope, but it does. This also happens for weak symbols, but their type is ST_DATA. */ case SS_UNSAT: switch (symbol_type) { case ST_STORAGE: case ST_DATA: symname = bfd_getb32 (bufp->name) + stringtab; ms_type = mst_data; break; default: continue; } break; default: continue; } if (bfd_getb32 (bufp->name) > obj_som_stringtab_size (abfd)) error (_("Invalid symbol data; bad HP string table offset: %s"), plongest (bfd_getb32 (bufp->name))); if (bfd_is_const_section (section)) { struct obj_section *iter; ALL_OBJFILE_OSECTIONS (objfile, iter) { CORE_ADDR start; CORE_ADDR len; if (bfd_is_const_section (iter->the_bfd_section)) continue; start = bfd_get_section_vma (iter->objfile->obfd, iter->the_bfd_section); len = bfd_get_section_size (iter->the_bfd_section); if (start <= symbol_value && symbol_value < start + len) { section = iter->the_bfd_section; break; } } } prim_record_minimal_symbol_and_info (symname, symbol_value, ms_type, gdb_bfd_section_index (objfile->obfd, section), objfile); }
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; }