diff options
39 files changed, 679 insertions, 322 deletions
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 7a8318e..ec60f23 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -2913,6 +2913,18 @@ const char *bfd_format_string (bfd_format format); && bfd_is_abs_section ((H)->u.def.section) \ && !(H)->rel_from_abs) +bool _bfd_generic_link_add_one_symbol + (struct bfd_link_info *info, + bfd *abfd, + const char *name, + flagword flags, + asection *section, + bfd_vma value, + const char *string, + bool copy, + bool collect, + struct bfd_link_hash_entry **hashp); + bool bfd_link_align_section (asection *, unsigned int); bool bfd_link_split_section (bfd *abfd, asection *sec); diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c index 2798efd..e2f1a4d 100644 --- a/bfd/coff-alpha.c +++ b/bfd/coff-alpha.c @@ -2359,7 +2359,7 @@ static const struct ecoff_backend_data alpha_ecoff_backend_data = alpha_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags, _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL + NULL, NULL, NULL, }, /* Supported architecture. */ bfd_arch_alpha, diff --git a/bfd/coff-arm.c b/bfd/coff-arm.c index ab5f7b0..ee57451 100644 --- a/bfd/coff-arm.c +++ b/bfd/coff-arm.c @@ -1876,8 +1876,8 @@ record_arm_to_thumb_glue (struct bfd_link_info * info, it. */ bh = NULL; val = globals->arm_glue_size + 1; - bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, - BSF_GLOBAL, s, val, NULL, true, false, &bh); + _bfd_generic_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, + BSF_GLOBAL, s, val, NULL, true, false, &bh); free (tmp_name); @@ -1929,8 +1929,8 @@ record_thumb_to_arm_glue (struct bfd_link_info * info, bh = NULL; val = globals->thumb_glue_size + 1; - bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, - BSF_GLOBAL, s, val, NULL, true, false, &bh); + _bfd_generic_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, + BSF_GLOBAL, s, val, NULL, true, false, &bh); /* If we mark it 'thumb', the disassembler will do a better job. */ myh = (struct coff_link_hash_entry *) bh; @@ -1952,8 +1952,8 @@ record_thumb_to_arm_glue (struct bfd_link_info * info, bh = NULL; val = globals->thumb_glue_size + (globals->support_old_code ? 8 : 4); - bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, - BSF_LOCAL, s, val, NULL, true, false, &bh); + _bfd_generic_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, + BSF_LOCAL, s, val, NULL, true, false, &bh); free (tmp_name); diff --git a/bfd/coff-mips.c b/bfd/coff-mips.c index e2c632c..8c4d4f7 100644 --- a/bfd/coff-mips.c +++ b/bfd/coff-mips.c @@ -1316,7 +1316,7 @@ static const struct ecoff_backend_data mips_ecoff_backend_data = _bfd_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags, _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL + NULL, NULL, }, /* Supported architecture. */ bfd_arch_mips, diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c index 7a20dba..ae9a0f6 100644 --- a/bfd/coff-rs6000.c +++ b/bfd/coff-rs6000.c @@ -4584,7 +4584,6 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data = xcoff_ppc_relocate_section, coff_rtype_to_howto, NULL, /* _bfd_coff_adjust_symndx */ - _bfd_generic_link_add_one_symbol, coff_link_output_has_begun, coff_final_link_postscript, NULL /* print_pdata. */ @@ -4774,7 +4773,6 @@ static const struct xcoff_backend_data_rec bfd_pmac_xcoff_backend_data = xcoff_ppc_relocate_section, coff_rtype_to_howto, NULL, /* _bfd_coff_adjust_symndx */ - _bfd_generic_link_add_one_symbol, coff_link_output_has_begun, coff_final_link_postscript, NULL /* print_pdata. */ diff --git a/bfd/coff-sh.c b/bfd/coff-sh.c index 275c4f5..c3e0e42 100644 --- a/bfd/coff-sh.c +++ b/bfd/coff-sh.c @@ -3108,7 +3108,7 @@ static const bfd_coff_backend_data bfd_coff_small_swap_table = coff_print_aux, coff_reloc16_extra_cases, coff_reloc16_estimate, coff_classify_symbol, coff_compute_section_file_positions, coff_start_final_link, coff_relocate_section, coff_rtype_to_howto, - coff_adjust_symndx, coff_link_add_one_symbol, + coff_adjust_symndx, coff_link_output_has_begun, coff_final_link_postscript, bfd_pe_print_pdata }; diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c index 5a4bcbf..ec7ed08 100644 --- a/bfd/coff64-rs6000.c +++ b/bfd/coff64-rs6000.c @@ -2495,7 +2495,6 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data = xcoff64_ppc_relocate_section, coff_rtype_to_howto, NULL, /* _bfd_coff_adjust_symndx */ - _bfd_generic_link_add_one_symbol, coff_link_output_has_begun, coff_final_link_postscript, NULL /* print_pdata. */ @@ -2768,7 +2767,6 @@ static const struct xcoff_backend_data_rec bfd_xcoff_aix5_backend_data = xcoff64_ppc_relocate_section, coff_rtype_to_howto, NULL, /* _bfd_coff_adjust_symndx */ - _bfd_generic_link_add_one_symbol, coff_link_output_has_begun, coff_final_link_postscript, NULL /* print_pdata. */ diff --git a/bfd/coffcode.h b/bfd/coffcode.h index 325a8ab..bd0374f 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -1516,11 +1516,6 @@ CODE_FRAGMENT . (bfd *, struct bfd_link_info *, bfd *, asection *, . struct internal_reloc *, bool *); . -. bool (*_bfd_coff_link_add_one_symbol) -. (struct bfd_link_info *, bfd *, const char *, flagword, -. asection *, bfd_vma, const char *, bool, bool, -. struct bfd_link_hash_entry **); -. . bool (*_bfd_coff_link_output_has_begun) . (bfd *, struct coff_final_link_info *); . @@ -1659,10 +1654,6 @@ INTERNAL .#define bfd_coff_adjust_symndx(obfd, info, ibfd, sec, rel, adjustedp)\ . ((coff_backend_info (abfd)->_bfd_coff_adjust_symndx)\ . (obfd, info, ibfd, sec, rel, adjustedp)) -.#define bfd_coff_link_add_one_symbol(info, abfd, name, flags, section,\ -. value, string, cp, coll, hashp)\ -. ((coff_backend_info (abfd)->_bfd_coff_link_add_one_symbol)\ -. (info, abfd, name, flags, section, value, string, cp, coll, hashp)) . .#define bfd_coff_link_output_has_begun(a,p) \ . ((coff_backend_info (a)->_bfd_coff_link_output_has_begun) (a, p)) @@ -5513,10 +5504,6 @@ dummy_reloc16_extra_cases (bfd *abfd ATTRIBUTE_UNUSED, #define coff_adjust_symndx NULL #endif -#ifndef coff_link_add_one_symbol -#define coff_link_add_one_symbol _bfd_generic_link_add_one_symbol -#endif - #ifndef coff_link_output_has_begun static bool @@ -5615,7 +5602,7 @@ static const bfd_coff_backend_data bfd_coff_std_swap_table ATTRIBUTE_UNUSED = coff_print_aux, coff_reloc16_extra_cases, coff_reloc16_estimate, coff_classify_symbol, coff_compute_section_file_positions, coff_start_final_link, coff_relocate_section, coff_rtype_to_howto, - coff_adjust_symndx, coff_link_add_one_symbol, + coff_adjust_symndx, coff_link_output_has_begun, coff_final_link_postscript, bfd_pe_print_pdata }; @@ -5656,7 +5643,7 @@ static const bfd_coff_backend_data ticoff0_swap_table = coff_print_aux, coff_reloc16_extra_cases, coff_reloc16_estimate, coff_classify_symbol, coff_compute_section_file_positions, coff_start_final_link, coff_relocate_section, coff_rtype_to_howto, - coff_adjust_symndx, coff_link_add_one_symbol, + coff_adjust_symndx, coff_link_output_has_begun, coff_final_link_postscript, bfd_pe_print_pdata }; @@ -5698,7 +5685,7 @@ static const bfd_coff_backend_data ticoff1_swap_table = coff_print_aux, coff_reloc16_extra_cases, coff_reloc16_estimate, coff_classify_symbol, coff_compute_section_file_positions, coff_start_final_link, coff_relocate_section, coff_rtype_to_howto, - coff_adjust_symndx, coff_link_add_one_symbol, + coff_adjust_symndx, coff_link_output_has_begun, coff_final_link_postscript, bfd_pe_print_pdata /* huh */ }; @@ -5941,7 +5928,7 @@ static const bfd_coff_backend_data bigobj_swap_table = coff_print_aux, coff_reloc16_extra_cases, coff_reloc16_estimate, coff_classify_symbol, coff_compute_section_file_positions, coff_start_final_link, coff_relocate_section, coff_rtype_to_howto, - coff_adjust_symndx, coff_link_add_one_symbol, + coff_adjust_symndx, coff_link_output_has_begun, coff_final_link_postscript, bfd_pe_print_pdata /* huh */ }; diff --git a/bfd/cofflink.c b/bfd/cofflink.c index 876aed7..501731b 100644 --- a/bfd/cofflink.c +++ b/bfd/cofflink.c @@ -445,7 +445,7 @@ coff_link_add_symbols (bfd *abfd, if (addit) { - if (! (bfd_coff_link_add_one_symbol + if (! (_bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value, (const char *) NULL, copy, false, (struct bfd_link_hash_entry **) sym_hash))) diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h index b2f70fb..ae6d303 100644 --- a/bfd/libbfd-in.h +++ b/bfd/libbfd-in.h @@ -645,12 +645,6 @@ extern bool _bfd_generic_link_add_archive_symbols /* Forward declaration to avoid prototype errors. */ typedef struct bfd_link_hash_entry _bfd_link_hash_entry; -/* Generic routine to add a single symbol. */ -extern bool _bfd_generic_link_add_one_symbol - (struct bfd_link_info *, bfd *, const char *name, flagword, - asection *, bfd_vma, const char *, bool copy, - bool constructor, struct bfd_link_hash_entry **) ATTRIBUTE_HIDDEN; - /* Generic routine to mark section as supplying symbols only. */ extern void _bfd_generic_link_just_syms (asection *, struct bfd_link_info *) ATTRIBUTE_HIDDEN; diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 4f6f5ea..d367fea 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -651,12 +651,6 @@ extern bool _bfd_generic_link_add_archive_symbols /* Forward declaration to avoid prototype errors. */ typedef struct bfd_link_hash_entry _bfd_link_hash_entry; -/* Generic routine to add a single symbol. */ -extern bool _bfd_generic_link_add_one_symbol - (struct bfd_link_info *, bfd *, const char *name, flagword, - asection *, bfd_vma, const char *, bool copy, - bool constructor, struct bfd_link_hash_entry **) ATTRIBUTE_HIDDEN; - /* Generic routine to mark section as supplying symbols only. */ extern void _bfd_generic_link_just_syms (asection *, struct bfd_link_info *) ATTRIBUTE_HIDDEN; diff --git a/bfd/libcoff.h b/bfd/libcoff.h index d0cfd09..05ebe35 100644 --- a/bfd/libcoff.h +++ b/bfd/libcoff.h @@ -864,11 +864,6 @@ typedef struct (bfd *, struct bfd_link_info *, bfd *, asection *, struct internal_reloc *, bool *); - bool (*_bfd_coff_link_add_one_symbol) - (struct bfd_link_info *, bfd *, const char *, flagword, - asection *, bfd_vma, const char *, bool, bool, - struct bfd_link_hash_entry **); - bool (*_bfd_coff_link_output_has_begun) (bfd *, struct coff_final_link_info *); @@ -1005,10 +1000,6 @@ typedef struct #define bfd_coff_adjust_symndx(obfd, info, ibfd, sec, rel, adjustedp)\ ((coff_backend_info (abfd)->_bfd_coff_adjust_symndx)\ (obfd, info, ibfd, sec, rel, adjustedp)) -#define bfd_coff_link_add_one_symbol(info, abfd, name, flags, section,\ - value, string, cp, coll, hashp)\ - ((coff_backend_info (abfd)->_bfd_coff_link_add_one_symbol)\ - (info, abfd, name, flags, section, value, string, cp, coll, hashp)) #define bfd_coff_link_output_has_begun(a,p) \ ((coff_backend_info (a)->_bfd_coff_link_output_has_begun) (a, p)) diff --git a/bfd/linker.c b/bfd/linker.c index 2a4b8f0..a9a23e5 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -1378,7 +1378,25 @@ hash_entry_bfd (struct bfd_link_hash_entry *h) /*NOTREACHED*/ } -/* Add a symbol to the global hash table. +/* +FUNCTION + _bfd_generic_link_add_one_symbol + +SYNOPSIS + bool _bfd_generic_link_add_one_symbol + (struct bfd_link_info *info, + bfd *abfd, + const char *name, + flagword flags, + asection *section, + bfd_vma value, + const char *string, + bool copy, + bool collect, + struct bfd_link_hash_entry **hashp); + +DESCRIPTION + Add a symbol to the global hash table. ABFD is the BFD the symbol comes from. NAME is the name of the symbol. FLAGS is the BSF_* bits associated with the symbol. diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c index 2901268..9938108 100644 --- a/bfd/peXXigen.c +++ b/bfd/peXXigen.c @@ -593,7 +593,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; PEAOUTHDR *aouthdr_out = (PEAOUTHDR *) out; bfd_vma sa, fa, ib; - IMAGE_DATA_DIRECTORY idata2, idata5, tls; + IMAGE_DATA_DIRECTORY idata2, idata5, tls, loadcfg; sa = extra->SectionAlignment; fa = extra->FileAlignment; @@ -602,6 +602,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) idata2 = pe->pe_opthdr.DataDirectory[PE_IMPORT_TABLE]; idata5 = pe->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE]; tls = pe->pe_opthdr.DataDirectory[PE_TLS_TABLE]; + loadcfg = pe->pe_opthdr.DataDirectory[PE_LOAD_CONFIG_TABLE]; if (aouthdr_in->tsize) { @@ -651,6 +652,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) extra->DataDirectory[PE_IMPORT_TABLE] = idata2; extra->DataDirectory[PE_IMPORT_ADDRESS_TABLE] = idata5; extra->DataDirectory[PE_TLS_TABLE] = tls; + extra->DataDirectory[PE_LOAD_CONFIG_TABLE] = loadcfg; if (extra->DataDirectory[PE_IMPORT_TABLE].VirtualAddress == 0) /* Until other .idata fixes are made (pending patch), the entry for @@ -4403,6 +4405,7 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) struct coff_link_hash_entry *h1; struct bfd_link_info *info = pfinfo->info; bool result = true; + char name[20]; /* There are a few fields that need to be filled in now while we have symbol table access. @@ -4430,8 +4433,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) else { _bfd_error_handler - (_("%pB: unable to fill in DataDictionary[1] because .idata$2 is missing"), - abfd); + (_("%pB: unable to fill in DataDirectory[%d]: %s is missing"), + abfd, PE_IMPORT_TABLE, ".idata$2"); result = false; } @@ -4450,8 +4453,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) else { _bfd_error_handler - (_("%pB: unable to fill in DataDictionary[1] because .idata$4 is missing"), - abfd); + (_("%pB: unable to fill in DataDirectory[%d]: %s is missing"), + abfd, PE_IMPORT_TABLE, ".idata$4"); result = false; } @@ -4471,8 +4474,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) else { _bfd_error_handler - (_("%pB: unable to fill in DataDictionary[12] because .idata$5 is missing"), - abfd); + (_("%pB: unable to fill in DataDirectory[%d]: %s is missing"), + abfd, PE_IMPORT_ADDRESS_TABLE, ".idata$5"); result = false; } @@ -4491,8 +4494,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) else { _bfd_error_handler - (_("%pB: unable to fill in DataDictionary[PE_IMPORT_ADDRESS_TABLE (12)] because .idata$6 is missing"), - abfd); + (_("%pB: unable to fill in DataDirectory[%d]: %s is missing"), + abfd, PE_IMPORT_ADDRESS_TABLE, ".idata$6"); result = false; } } @@ -4533,17 +4536,16 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) else { _bfd_error_handler - (_("%pB: unable to fill in DataDictionary[PE_IMPORT_ADDRESS_TABLE(12)]" - " because .idata$6 is missing"), abfd); + (_("%pB: unable to fill in DataDirectory[%d]: %s not defined correctly"), + abfd, PE_IMPORT_ADDRESS_TABLE, "__IAT_end__"); result = false; } } } - h1 = coff_link_hash_lookup (coff_hash_table (info), - (bfd_get_symbol_leading_char (abfd) != 0 - ? "__tls_used" : "_tls_used"), - false, false, true); + name[0] = bfd_get_symbol_leading_char (abfd); + strcpy (name + !!name[0], "_tls_used"); + h1 = coff_link_hash_lookup (coff_hash_table (info), name, false, false, true); if (h1 != NULL) { if ((h1->root.type == bfd_link_hash_defined @@ -4558,8 +4560,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) else { _bfd_error_handler - (_("%pB: unable to fill in DataDictionary[9] because __tls_used is missing"), - abfd); + (_("%pB: unable to fill in DataDirectory[%d]: %s not defined correctly"), + abfd, PE_TLS_TABLE, name); result = false; } /* According to PECOFF sepcifications by Microsoft version 8.2 @@ -4573,6 +4575,81 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) #endif } + name[0] = bfd_get_symbol_leading_char (abfd); + strcpy (name + !!name[0], "_load_config_used"); + h1 = coff_link_hash_lookup (coff_hash_table (info), name, false, false, true); + if (h1 != NULL) + { + char data[4]; + if ((h1->root.type == bfd_link_hash_defined + || h1->root.type == bfd_link_hash_defweak) + && h1->root.u.def.section != NULL + && h1->root.u.def.section->output_section != NULL) + { + pe_data (abfd)->pe_opthdr.DataDirectory[PE_LOAD_CONFIG_TABLE].VirtualAddress = + (h1->root.u.def.value + + h1->root.u.def.section->output_section->vma + + h1->root.u.def.section->output_offset + - pe_data (abfd)->pe_opthdr.ImageBase); + + if (pe_data (abfd)->pe_opthdr.DataDirectory[PE_LOAD_CONFIG_TABLE].VirtualAddress + & (bfd_arch_bits_per_address (abfd) / bfd_arch_bits_per_byte (abfd) + - 1)) + { + _bfd_error_handler + (_("%pB: unable to fill in DataDirectory[%d]: %s not properly aligned"), + abfd, PE_LOAD_CONFIG_TABLE, name); + result = false; + } + + /* The size is stored as the first 4 bytes at _load_config_used. */ + if (bfd_get_section_contents (abfd, + h1->root.u.def.section->output_section, data, + h1->root.u.def.section->output_offset + h1->root.u.def.value, + 4)) + { + uint32_t size = bfd_get_32 (abfd, data); + /* The Microsoft PE format documentation says for compatibility + with Windows XP and earlier, the size must be 64 for x86 + images. */ + pe_data (abfd)->pe_opthdr.DataDirectory[PE_LOAD_CONFIG_TABLE].Size + = (bfd_get_arch (abfd) == bfd_arch_i386 + && ((bfd_get_mach (abfd) & ~bfd_mach_i386_intel_syntax) + == bfd_mach_i386_i386) + && ((pe_data (abfd)->pe_opthdr.Subsystem + == IMAGE_SUBSYSTEM_WINDOWS_GUI) + || (pe_data (abfd)->pe_opthdr.Subsystem + == IMAGE_SUBSYSTEM_WINDOWS_CUI)) + && (pe_data (abfd)->pe_opthdr.MajorSubsystemVersion * 256 + + pe_data (abfd)->pe_opthdr.MinorSubsystemVersion + <= 0x0501)) + ? 64 : size; + + if (size > h1->root.u.def.section->size - h1->root.u.def.value) + { + _bfd_error_handler + (_("%pB: unable to fill in DataDirectory[%d]: size too large for the containing section"), + abfd, PE_LOAD_CONFIG_TABLE); + result = false; + } + } + else + { + _bfd_error_handler + (_("%pB: unable to fill in DataDirectory[%d]: size can't be read from %s"), + abfd, PE_LOAD_CONFIG_TABLE, name); + result = false; + } + } + else + { + _bfd_error_handler + (_("%pB: unable to fill in DataDirectory[%d]: %s not defined correctly"), + abfd, PE_LOAD_CONFIG_TABLE, name); + result = false; + } + } + /* If there is a .pdata section and we have linked pdata finally, we need to sort the entries ascending. */ #if !defined(COFF_WITH_pep) && (defined(COFF_WITH_pex64) || defined(COFF_WITH_peAArch64) || defined(COFF_WITH_peLoongArch64) || defined (COFF_WITH_peRiscV64)) diff --git a/bfd/version.h b/bfd/version.h index ec40174..09a913a 100644 --- a/bfd/version.h +++ b/bfd/version.h @@ -16,7 +16,7 @@ In releases, the date is not included in either version strings or sonames. */ -#define BFD_VERSION_DATE 20250404 +#define BFD_VERSION_DATE 20250407 #define BFD_VERSION @bfd_version@ #define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@ #define REPORT_BUGS_TO @report_bugs_to@ diff --git a/binutils/nm.c b/binutils/nm.c index 4e86057..7ef5d61 100644 --- a/binutils/nm.c +++ b/binutils/nm.c @@ -79,7 +79,15 @@ struct extended_symbol_info #define SYM_STAB_DESC(sym) (sym->sinfo->stab_desc) #define SYM_STAB_OTHER(sym) (sym->sinfo->stab_other) #define SYM_SIZE(sym) \ - (sym->elfinfo ? sym->elfinfo->internal_elf_sym.st_size: sym->ssize) + (sym->elfinfo \ + && sym->elfinfo->internal_elf_sym.st_size \ + ? sym->elfinfo->internal_elf_sym.st_size \ + : sym->coffinfo \ + && ISFCN (sym->coffinfo->native->u.syment.n_type) \ + && sym->coffinfo->native->u.syment.n_numaux \ + && sym->coffinfo->native[1].u.auxent.x_sym.x_misc.x_fsize \ + ? sym->coffinfo->native[1].u.auxent.x_sym.x_misc.x_fsize \ + : sym->ssize) /* The output formatting functions. */ static void print_object_filename_bsd (const char *); @@ -1036,9 +1044,9 @@ size_forward2 (const void *P_x, const void *P_y) return sorters[0][reverse_sort] (x->minisym, y->minisym); } -/* Sort the symbols by size. ELF provides a size but for other formats - we have to make a guess by assuming that the difference between the - address of a symbol and the address of the next higher symbol is the +/* Sort the symbols by size. ELF and COFF may provide a size but for other + formats we have to make a guess by assuming that the difference between + the address of a symbol and the address of the next higher symbol is the size. */ static long @@ -1081,6 +1089,8 @@ sort_symbols_by_size (bfd *abfd, bool is_dynamic, void *minisyms, asection *sec; bfd_vma sz; asymbol *temp; + const elf_symbol_type *elfsym; + const coff_symbol_type *coffsym; if (from + size < fromend) { @@ -1100,8 +1110,15 @@ sort_symbols_by_size (bfd *abfd, bool is_dynamic, void *minisyms, we can't rely on that information for the symbol size. Ditto for bfd/section.c:global_syms like *ABS*. */ if ((sym->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) == 0 - && bfd_get_flavour (abfd) == bfd_target_elf_flavour) - sz = ((elf_symbol_type *) sym)->internal_elf_sym.st_size; + && (elfsym = elf_symbol_from (sym)) != NULL + && elfsym->internal_elf_sym.st_size != 0) + sz = elfsym->internal_elf_sym.st_size; + else if ((sym->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) == 0 + && (coffsym = coff_symbol_from (sym)) != NULL + && ISFCN (coffsym->native->u.syment.n_type) + && coffsym->native->u.syment.n_numaux != 0 + && coffsym->native[1].u.auxent.x_sym.x_misc.x_fsize != 0) + sz = coffsym->native[1].u.auxent.x_sym.x_misc.x_fsize; else if ((sym->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) == 0 && bfd_is_com_section (sec)) sz = sym->value; diff --git a/binutils/testsuite/binutils-all/nm-coff-1.s b/binutils/testsuite/binutils-all/nm-coff-1.s new file mode 100644 index 0000000..3efc10e --- /dev/null +++ b/binutils/testsuite/binutils-all/nm-coff-1.s @@ -0,0 +1,26 @@ + .globl text_symbol1 + .globl text_symbol2 + .globl text_symbol3 + .macro ENDFN name:req + .def \name + .type 0x20 /* DT_FUNC */ + .scl 2 /* C_EXT */ + .endef + .def \name + .scl 0xff /* C_EFCN */ + .val . + .endef + .endm + .text +text_symbol1: + .long 0 + .long 0 + .long 0 + ENDFN text_symbol1 +text_symbol2: + .long 0 + .long 0 + ENDFN text_symbol2 +text_symbol3: + .long 0 + ENDFN text_symbol3 diff --git a/binutils/testsuite/binutils-all/nm-coff-sdef-1.s b/binutils/testsuite/binutils-all/nm-coff-sdef-1.s new file mode 100644 index 0000000..f1a10bb --- /dev/null +++ b/binutils/testsuite/binutils-all/nm-coff-sdef-1.s @@ -0,0 +1,26 @@ + .globl text_symbol1 + .globl text_symbol2 + .globl text_symbol3 + .macro ENDFN name:req + .sdef \name + .type 0x20 /* DT_FUNC */ + .scl 2 /* C_EXT */ + .endef + .sdef \name + .scl 0xff /* C_EFCN */ + .val . + .endef + .endm + .text +text_symbol1: + .byte 0,0,0,0 + .byte 0,0,0,0 + .byte 0,0,0,0 + ENDFN text_symbol1 +text_symbol2: + .byte 0,0,0,0 + .byte 0,0,0,0 + ENDFN text_symbol2 +text_symbol3: + .byte 0,0,0,0 + ENDFN text_symbol3 diff --git a/binutils/testsuite/binutils-all/nm.exp b/binutils/testsuite/binutils-all/nm.exp index e1b2d16..b81126b 100644 --- a/binutils/testsuite/binutils-all/nm.exp +++ b/binutils/testsuite/binutils-all/nm.exp @@ -163,6 +163,12 @@ if { [is_elf_format] || [istarget wasm32-*-*] || [istarget bpf-*-*]} { set nm_1_src "nm-elf-1.s" +} elseif {[is_coff_format] && ![istarget arm*-*-*]} { + if {[istarget *c4x-*-*] || [istarget *c54x-*-*]} { + set nm_1_src "nm-coff-sdef-1.s" + } else { + set nm_1_src "nm-coff-1.s" + } } else { set nm_1_src "nm-1.s" } diff --git a/gas/config/obj-coff.c b/gas/config/obj-coff.c index 19759cd..eb5784e 100644 --- a/gas/config/obj-coff.c +++ b/gas/config/obj-coff.c @@ -1887,8 +1887,8 @@ static const pseudo_typeS coff_pseudo_table[] = {"loc", obj_coff_loc, 0}, {"optim", s_ignore, 0}, /* For sun386i cc (?) */ {"weak", obj_coff_weak, 0}, -#if defined TC_TIC4X - /* The tic4x uses sdef instead of def. */ +#if defined (TC_TIC4X) || defined (TC_TIC54X) + /* The tic4x and tic54x use sdef instead of def. */ {"sdef", obj_coff_def, 0}, #endif #if defined(SEH_CMDS) @@ -35,6 +35,11 @@ a -h or --help option, which prints each options and a brief description. +* On systems that support linkage namespaces, the output of the command + "info sharedlibraries" may add one more column, NS, which identifies the + namespace into which the library was loaded, if more than one namespace + is active. + * New commands maintenance check psymtabs diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index e034ac5..4e4509a 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -22172,6 +22172,11 @@ be determined then the address range for the @code{.text} section from the library will be listed. If the @code{.text} section cannot be found then no addresses will be listed. +On systems that support linkage namespaces, the output includes an +additional column @code{NS} if the inferior has more than one active +namespace when the command is used. This column the linkage namespace +that the shared library was loaded into. + @kindex info dll @item info dll @var{regex} This is an alias of @code{info sharedlibrary}. diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 398123f..2f839bd 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -405,11 +405,54 @@ struct svr4_info The special entry zero is reserved for a linear list to support gdbstubs that do not support namespaces. */ std::map<CORE_ADDR, std::vector<svr4_so>> solib_lists; + + /* Mapping between r_debug[_ext] addresses and a user-friendly + identifier for the namespace. A vector is used to make it + easy to assign new internal IDs to namespaces. + + For gdbservers that don't support namespaces, the first (and only) + entry of the vector will be 0. + + A note on consistency. We can't make the IDs be consistent before + and after the initial relocation of the inferior (when the global + _r_debug is relocated, as mentioned in the previous comment). It is + likely that this is a non-issue, since the inferior can't have called + dlmopen yet, but I think it is worth noting. + + The only issue I am aware at this point is that, if when parsing an + XML file, we read an LMID that given by an XML file (and read in + library_list_start_library) is the identifier obtained with dlinfo + instead of the address of r_debug[_ext], and after attaching the + inferior adds another SO to that namespace, we might double-count it + since we won't have access to the LMID later on. However, this is + already a problem with the existing solib_lists code. */ + std::vector<CORE_ADDR> namespace_id; + + /* This identifies which namespaces are active. A namespace is considered + active when there is at least one shared object loaded into it. */ + std::set<size_t> active_namespaces; }; /* Per-program-space data key. */ static const registry<program_space>::key<svr4_info> solib_svr4_pspace_data; +/* Check if the lmid address is already assigned an ID in the svr4_info, + and if not, assign it one and add it to the list of known namespaces. */ +static void +svr4_maybe_add_namespace (svr4_info *info, CORE_ADDR lmid) +{ + int i; + for (i = 0; i < info->namespace_id.size (); i++) + { + if (info->namespace_id[i] == lmid) + break; + } + if (i == info->namespace_id.size ()) + info->namespace_id.push_back (lmid); + + info->active_namespaces.insert (i); +} + /* Return whether DEBUG_BASE is the default namespace of INFO. */ static bool @@ -1041,14 +1084,18 @@ library_list_start_library (struct gdb_xml_parser *parser, /* Older versions did not supply lmid. Put the element into the flat list of the special namespace zero in that case. */ gdb_xml_value *at_lmid = xml_find_attribute (attributes, "lmid"); + svr4_info *info = get_svr4_info (current_program_space); if (at_lmid == nullptr) - solist = list->cur_list; + { + solist = list->cur_list; + svr4_maybe_add_namespace (info, 0); + } else { ULONGEST lmid = *(ULONGEST *) at_lmid->value.get (); solist = &list->solib_lists[lmid]; + svr4_maybe_add_namespace (info, lmid); } - solist->emplace_back (name, std::move (li)); } @@ -1286,6 +1333,8 @@ svr4_current_sos_direct (struct svr4_info *info) /* Remove any old libraries. We're going to read them back in again. */ info->solib_lists.clear (); + info->active_namespaces.clear (); + /* Fall back to manual examination of the target if the packet is not supported or gdbserver failed to find DT_DEBUG. gdb.server/solib-list.exp tests a case where gdbserver cannot find the shared libraries list while @@ -1333,7 +1382,10 @@ svr4_current_sos_direct (struct svr4_info *info) ignore_first = true; auto cleanup = make_scope_exit ([info] () - { info->solib_lists.clear (); }); + { + info->solib_lists.clear (); + info->active_namespaces.clear (); + }); /* Collect the sos in each namespace. */ CORE_ADDR debug_base = info->debug_base; @@ -1343,8 +1395,11 @@ svr4_current_sos_direct (struct svr4_info *info) /* Walk the inferior's link map list, and build our so_list list. */ lm = solib_svr4_r_map (debug_base); if (lm != 0) - svr4_read_so_list (info, lm, 0, info->solib_lists[debug_base], - ignore_first); + { + svr4_maybe_add_namespace (info, debug_base); + svr4_read_so_list (info, lm, 0, info->solib_lists[debug_base], + ignore_first); + } } /* On Solaris, the dynamic linker is not in the normal list of @@ -1361,8 +1416,11 @@ svr4_current_sos_direct (struct svr4_info *info) { /* Add the dynamic linker's namespace unless we already did. */ if (info->solib_lists.find (debug_base) == info->solib_lists.end ()) - svr4_read_so_list (info, debug_base, 0, info->solib_lists[debug_base], - 0); + { + svr4_maybe_add_namespace (info, debug_base); + svr4_read_so_list (info, debug_base, 0, info->solib_lists[debug_base], + 0); + } } cleanup.release (); @@ -1778,6 +1836,10 @@ solist_update_incremental (svr4_info *info, CORE_ADDR debug_base, return 0; prev_lm = 0; + + /* If the list is empty, we are seeing a new namespace for the + first time, so assign it an internal ID. */ + svr4_maybe_add_namespace (info, debug_base); } else prev_lm = solist.back ().lm_info->lm_addr; @@ -1845,6 +1907,8 @@ disable_probes_interface (svr4_info *info) free_probes_table (info); info->solib_lists.clear (); + info->namespace_id.clear (); + info->active_namespaces.clear (); } /* Update the solib list as appropriate when using the @@ -3042,6 +3106,8 @@ svr4_solib_create_inferior_hook (int from_tty) /* Clear the probes-based interface's state. */ free_probes_table (info); info->solib_lists.clear (); + info->namespace_id.clear (); + info->active_namespaces.clear (); /* Relocate the main executable if necessary. */ svr4_relocate_main_executable (); @@ -3460,6 +3526,32 @@ svr4_find_solib_addr (solib &so) return li->l_addr_inferior; } +/* See solib_ops::find_solib_ns in solist.h. */ + +static int +svr4_find_solib_ns (const solib &so) +{ + CORE_ADDR debug_base = find_debug_base_for_solib (&so); + svr4_info *info = get_svr4_info (current_program_space); + for (int i = 0; i < info->namespace_id.size (); i++) + { + if (info->namespace_id[i] == debug_base) + { + gdb_assert (info->active_namespaces.count (i) == 1); + return i; + } + } + error (_("No namespace found")); +} + +/* see solib_ops::num_active_namespaces in solist.h. */ +static int +svr4_num_active_namespaces () +{ + svr4_info *info = get_svr4_info (current_program_space); + return info->active_namespaces.size (); +} + const struct solib_ops svr4_so_ops = { svr4_relocate_section_addresses, @@ -3475,6 +3567,8 @@ const struct solib_ops svr4_so_ops = svr4_update_solib_event_breakpoints, svr4_handle_solib_event, svr4_find_solib_addr, + svr4_find_solib_ns, + svr4_num_active_namespaces, }; void _initialize_svr4_solib (); diff --git a/gdb/solib.c b/gdb/solib.c index 1d26970..3ddd4f9 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -1051,12 +1051,24 @@ info_sharedlibrary_command (const char *pattern, int from_tty) } } + /* How many columns the table should have. If the inferior has + more than one namespace active, we need a column to show that. */ + int num_cols = 4; + const solib_ops *ops = gdbarch_so_ops (gdbarch); + if (ops->num_active_namespaces != nullptr + && ops->num_active_namespaces () > 1) + num_cols++; + { - ui_out_emit_table table_emitter (uiout, 4, nr_libs, "SharedLibraryTable"); + ui_out_emit_table table_emitter (uiout, num_cols, nr_libs, + "SharedLibraryTable"); /* The "- 1" is because ui_out adds one space between columns. */ uiout->table_header (addr_width - 1, ui_left, "from", "From"); uiout->table_header (addr_width - 1, ui_left, "to", "To"); + if (ops->num_active_namespaces != nullptr + && ops->num_active_namespaces () > 1) + uiout->table_header (5, ui_left, "namespace", "NS"); uiout->table_header (12 - 1, ui_left, "syms-read", "Syms Read"); uiout->table_header (0, ui_noalign, "name", "Shared Object Library"); @@ -1083,6 +1095,19 @@ info_sharedlibrary_command (const char *pattern, int from_tty) uiout->field_skip ("to"); } + if (ops->num_active_namespaces != nullptr + && ops->num_active_namespaces ()> 1) + { + try + { + uiout->field_fmt ("namespace", "[[%d]]", ops->find_solib_ns (so)); + } + catch (const gdb_exception_error &er) + { + uiout->field_skip ("namespace"); + } + } + if (!top_level_interpreter ()->interp_ui_out ()->is_mi_like_p () && so.symbols_loaded && !objfile_has_symbols (so.objfile)) { diff --git a/gdb/solist.h b/gdb/solist.h index 9a157a4..03d2392 100644 --- a/gdb/solist.h +++ b/gdb/solist.h @@ -180,6 +180,20 @@ struct solib_ops name). */ std::optional<CORE_ADDR> (*find_solib_addr) (solib &so); + + /* Return which linker namespace contains the current so. + If the linker or libc does not support linkage namespaces at all + (which is basically all of them but solib-svr4), this function should + be set to nullptr, so that "info shared" won't add an unnecessary + column. + + If the namespace can not be determined (such as when we're stepping + though the dynamic linker), this function should throw a + gdb_exception_error. */ + int (*find_solib_ns) (const solib &so); + + /* Returns the number of active namespaces in the inferior. */ + int (*num_active_namespaces) (); }; /* A unique pointer to a so_list. */ diff --git a/gdb/testsuite/gdb.base/attach-pie-noexec.exp b/gdb/testsuite/gdb.base/attach-pie-noexec.exp index 4e6ede1..20c93b5 100644 --- a/gdb/testsuite/gdb.base/attach-pie-noexec.exp +++ b/gdb/testsuite/gdb.base/attach-pie-noexec.exp @@ -35,7 +35,7 @@ if ![runto_main] { } set test "sanity check info shared" gdb_test_multiple "info shared" $test { - -re "From\[ \t\]+To\[ \t\]+Syms Read\[ \t\]+Shared Object Library\r\n0x.*\r\n$gdb_prompt $" { + -re "From\[ \t\]+To(\\s+NS)?\[ \t\]+Syms Read\[ \t\]+Shared Object Library\r\n0x.*\r\n$gdb_prompt $" { pass $test } -re "No shared libraries loaded at this time\\.\r\n$gdb_prompt $" { @@ -62,6 +62,6 @@ if { ![gdb_attach $testpid] } { return } gdb_test "set architecture $arch" "The target architecture is set to \"$arch\"\\." -gdb_test "info shared" "From\[ \t\]+To\[ \t\]+Syms Read\[ \t\]+Shared Object Library\r\n0x.*" +gdb_test "info shared" "From\[ \t\]+To(\\s+NS)?\[ \t\]+Syms Read\[ \t\]+Shared Object Library\r\n0x.*" kill_wait_spawned_process $test_spawn_id diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c new file mode 100644 index 0000000..86cbb0f --- /dev/null +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c @@ -0,0 +1,28 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +int gdb_dlmopen_glob = 0; + +__attribute__((visibility ("default"))) +int +inc (int n) +{ + int amount = gdb_dlmopen_glob; + return n + amount; /* bp.inc. */ +} diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c new file mode 100644 index 0000000..3bcd819 --- /dev/null +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c @@ -0,0 +1,54 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#define _GNU_SOURCE +#include <dlfcn.h> +#include <stddef.h> +#include <assert.h> +#include <unistd.h> +#include <stdio.h> + +int +main (void) +{ + void *handle[4]; + int (*fun) (int); + Lmid_t lmid; + int dl; + + handle[0] = dlmopen (LM_ID_NEWLM, DSO_NAME, RTLD_LAZY | RTLD_LOCAL); + assert (handle[0] != NULL); + + handle[1] = dlmopen (LM_ID_NEWLM, DSO_NAME, RTLD_LAZY | RTLD_LOCAL); + assert (handle[1] != NULL); + + handle[2] = dlmopen (LM_ID_NEWLM, DSO_NAME, RTLD_LAZY | RTLD_LOCAL); + assert (handle[2] != NULL); + + dlclose (handle[0]); /* TAG: first dlclose */ + dlclose (handle[1]); /* TAG: second dlclose */ + dlclose (handle[2]); /* TAG: third dlclose */ + + handle[3] = dlmopen (LM_ID_NEWLM, DSO_NAME, RTLD_LAZY | RTLD_LOCAL); + dlinfo (handle[3], RTLD_DI_LMID, &lmid); + + dlclose (handle[3]); /* TAG: fourth dlclose */ + + return 0; +} diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp new file mode 100644 index 0000000..03b7a52 --- /dev/null +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp @@ -0,0 +1,106 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2025 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# +# Test several things related to handling linker namespaces: +# * That the user-facing namespace ID is consistent; + +require allow_dlmopen_tests + +standard_testfile -main.c -lib.c + +set srcfile_lib $srcfile2 +set binfile_lib [standard_output_file dlmopen-lib.so] + +if { [build_executable "build shlib" $binfile_lib $srcfile_lib \ + [list debug shlib]] == -1 } { + return +} + +if { [build_executable "failed to build" $testfile $srcfile \ + [list additional_flags=-DDSO_NAME=\"$binfile_lib\" \ + shlib_load debug]] } { + return +} + +# Run the command "info sharedlibrary" and get the first namespace +# for the so +proc get_first_so_ns {} { + set ns -1 + gdb_test_multiple "info sharedlibrary" "get SO namespace" -lbl { + -re "From\\s+To\\s+\(NS\\s+\)?Syms\\s+Read\\s+Shared Object Library\r\n" { + exp_continue + } + -re "^$::hex\\s+$::hex\\s+\\\[\\\[($::decimal)\\\]\\\]\\s+\[^\r\n]+$::binfile_lib.*" { + set ns $expect_out(1,string) + } + -re "^$::gdb_prompt $" { + } + -re "^\[^\r\n\]+\r\n" { + exp_continue + } + } + return $ns +} + +# Run the tests relating to the command "info sharedlibrary", to +# verify that the namespace ID is consistent. +proc test_info_shared {} { + clean_restart $::binfile + + if { ![runto_main] } { + return + } + + # First test that we don't print a namespace column at the start. + gdb_test "info sharedlibrary" \ + "From\\s+To\\s+Syms\\s+Read\\s+Shared Object Library.*" \ + "before loading anything" + + gdb_breakpoint [gdb_get_line_number "TAG: first dlclose"] + gdb_continue_to_breakpoint "TAG: first dlclose" + + # Next, test that we *do* print a namespace column after loading SOs. + gdb_test "info sharedlibrary" \ + "From\\s+To\\s+NS\\s+Syms\\s+Read\\s+Shared Object Library.*" \ + "after loading everything" + + gdb_assert {[get_first_so_ns] == 1} "before closing any library" + + gdb_test "next" ".*second dlclose.*" "close first library" + gdb_assert {[get_first_so_ns] == 2} "after closing one library" + + gdb_test "next" ".*third dlclose.*" "close second library" + gdb_assert {[get_first_so_ns] == 3} "before closing two libraries" + + gdb_breakpoint [gdb_get_line_number "TAG: fourth dlclose"] + gdb_continue_to_breakpoint "TAG: fourth dlclose" + # As of writing this test, glibc's LMID is just an index on an array of + # namespaces. After closing a namespace, requesting a new one will + # return the index of the lowest-closed namespace, so this will likely + # be namespace 1, and because of glibc's reuse of the r_debug object, + # GDB should be able to assign the same number. + gdb_assert {[get_first_so_ns] == [get_integer_valueof "lmid" "-1"]} \ + "reopen a namespace" + + gdb_test "next" ".*return 0.*" "final namespace inactive" + gdb_test "info sharedlibrary" \ + "From\\s+To\\s+Syms\\s+Read\\s+Shared Object Library.*" \ + "after unloading everything" +} + +test_info_shared diff --git a/gdb/testsuite/gdb.base/dlmopen.exp b/gdb/testsuite/gdb.base/dlmopen.exp index a8e3b08..084c5bc 100644 --- a/gdb/testsuite/gdb.base/dlmopen.exp +++ b/gdb/testsuite/gdb.base/dlmopen.exp @@ -106,7 +106,7 @@ proc check_dso_count { dso num } { set count 0 gdb_test_multiple "info shared" "info shared" { - -re "$hex $hex Yes \[^\r\n\]*$dso\r\n" { + -re "$hex $hex \(\[\[$::decimal\]\]\\s+\)\?Yes \[^\r\n\]*$dso\r\n" { # use longer form so debug remote does not interfere set count [expr $count + 1] exp_continue @@ -233,12 +233,12 @@ proc get_dyld_info {} { set dyld_count 0 set dyld_start_addr "" gdb_test_multiple "info sharedlibrary" "" { - -re "From\\s+To\\s+Syms\\s+Read\\s+Shared Object Library\r\n" { + -re "From\\s+To\\s+\(NS\\s+\)?Syms\\s+Read\\s+Shared Object Library\r\n" { exp_continue } - -re "^($::hex)\\s+$::hex\\s+\[^/\]+(/\[^\r\n\]+)\r\n" { + -re "^($::hex)\\s+$::hex\\s+\(\#$::decimal\\s+\)?\[^/\]+(/\[^\r\n\]+)\r\n" { set addr $expect_out(1,string) - set lib $expect_out(2,string) + set lib $expect_out(3,string) if { [is_dyln $lib] } { # This looks like it might be the dynamic linker. diff --git a/gdb/testsuite/gdb.mi/mi-dlmopen.exp b/gdb/testsuite/gdb.mi/mi-dlmopen.exp index a5743f8..c0208eb 100644 --- a/gdb/testsuite/gdb.mi/mi-dlmopen.exp +++ b/gdb/testsuite/gdb.mi/mi-dlmopen.exp @@ -81,12 +81,12 @@ proc get_dyld_info {} { set dyld_count 0 set dyld_start_addr "" gdb_test_multiple "info sharedlibrary" "" { - -re "~\"From\\s+To\\s+Syms\\s+Read\\s+Shared Object Library\\\\n\"\r\n" { + -re "~\"From\\s+To(\\s+NS)?\\s+Syms\\s+Read\\s+Shared Object Library\\\\n\"\r\n" { exp_continue } - -re "^~\"($::hex)\\s+$::hex\\s+\[^/\]+(/\[^\r\n\]+)\\\\n\"\r\n" { + -re "^~\"($::hex)\\s+${::hex}(\\s+$::decimal)?\\s+\[^/\]+(/\[^\r\n\]+)\\\\n\"\r\n" { set addr $expect_out(1,string) - set lib $expect_out(2,string) + set lib $expect_out(3,string) if { [is_dyln $lib] } { # This looks like it might be the dynamic linker. diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc index c08c9ae..96855f0 100644 --- a/gdbserver/regcache.cc +++ b/gdbserver/regcache.cc @@ -353,8 +353,7 @@ supply_register_by_name_zeroed (struct regcache *regcache, #endif /* Supply the whole register set whose contents are stored in BUF, to - REGCACHE. If BUF is NULL, all the registers' values are recorded - as unavailable. */ + REGCACHE. */ void supply_regblock (struct regcache *regcache, const void *buf) diff --git a/gprofng/src/DwarfLib.cc b/gprofng/src/DwarfLib.cc index 9b40401..d399c33 100644 --- a/gprofng/src/DwarfLib.cc +++ b/gprofng/src/DwarfLib.cc @@ -204,12 +204,6 @@ ElfReloc::dump_rela_debug_sec (int sec) if (ScnSize == 0 || EntSize == 0) return; - Elf_Internal_Shdr *shdr_sym = elf->get_shdr (shdr->sh_link); - if (shdr_sym == NULL) - return; - Elf_Data *data_sym = elf->elf_getdata (shdr->sh_link); - Elf_Data *data_str = elf->elf_getdata (shdr_sym->sh_link); - char *Strtab = data_str ? (char*) data_str->d_buf : NULL; Elf_Internal_Rela rela; int n, cnt = (int) (ScnSize / EntSize); @@ -233,7 +227,8 @@ ElfReloc::dump_rela_debug_sec (int sec) int ndx = (int) GELF_R_SYM (rela.r_info); Elf_Internal_Shdr *secHdr; Elf_Internal_Sym sym; - elf->elf_getsym (data_sym, ndx, &sym); + asymbol *asym; + asym = elf->elf_getsym (ndx, &sym, false); Dprintf (DUMP_RELA_SEC, NTXT ("%3d:%5d |%11lld |0x%016llx | %-15s|"), n, (int) rela.r_addend, (long long) rela.r_offset, (long long) rela.r_info, @@ -243,12 +238,9 @@ ElfReloc::dump_rela_debug_sec (int sec) case STT_FUNC: case STT_OBJECT: case STT_NOTYPE: - secHdr = elf->get_shdr (sym.st_shndx); - if (secHdr) - Dprintf (DUMP_RELA_SEC, NTXT (" img_offset=0x%llx"), - (long long) (sym.st_value + secHdr->sh_offset)); - if (Strtab && sym.st_name) - Dprintf (DUMP_RELA_SEC, NTXT (" %s"), Strtab + sym.st_name); + Dprintf (DUMP_RELA_SEC, NTXT (" img_offset=0x%llx"), + (long long) (bfd_asymbol_value (asym))); + Dprintf (DUMP_RELA_SEC, NTXT (" %s"), bfd_asymbol_name (asym)); break; case STT_SECTION: secHdr = elf->get_shdr (sym.st_shndx); @@ -311,10 +303,6 @@ ElfReloc::get_elf_reloc (Elf *elfp, char *sec_name, ElfReloc *rlc) return rlc; int cnt = (int) (data->d_size / shdr->sh_entsize); - Elf_Internal_Shdr *shdr_sym = elfp->get_shdr (shdr->sh_link); - if (shdr_sym == NULL) - return rlc; - Elf_Data *data_sym = elfp->elf_getdata (shdr->sh_link); Vector<Sreloc *> *vp = NULL; for (int n = 0; n < cnt; n++) @@ -331,7 +319,7 @@ ElfReloc::get_elf_reloc (Elf *elfp, char *sec_name, ElfReloc *rlc) } int ndx = (int) GELF_R_SYM (rela.r_info); Elf_Internal_Sym sym; - elfp->elf_getsym (data_sym, ndx, &sym); + elfp->elf_getsym (ndx, &sym, false); srlc = new Sreloc; srlc->offset = rela.r_offset; diff --git a/gprofng/src/Elf.cc b/gprofng/src/Elf.cc index b9da240..f0fd121 100644 --- a/gprofng/src/Elf.cc +++ b/gprofng/src/Elf.cc @@ -533,42 +533,43 @@ Elf::elf_strptr (unsigned int sec, uint64_t off) return NULL; } -Elf_Internal_Sym * -Elf::elf_getsym (Elf_Data *edta, unsigned int ndx, Elf_Internal_Sym *dst) +long +Elf::elf_getSymCount (bool is_dynamic) { - if (dst == NULL || edta == NULL) - return NULL; - if (elf_getclass () == ELFCLASS32) - { - if (edta->d_size <= ndx * sizeof (Elf32_Sym)) - return NULL; - Elf32_Sym *hdr = (Elf32_Sym*) bind (edta->d_off + ndx * sizeof (Elf32_Sym), sizeof (Elf32_Sym)); - if (hdr == NULL) - return NULL; - dst->st_name = decode (hdr->st_name); - dst->st_value = decode (hdr->st_value); - dst->st_size = decode (hdr->st_size); - dst->st_info = ELF64_ST_INFO (ELF32_ST_BIND (decode (hdr->st_info)), - ELF32_ST_TYPE (decode (hdr->st_info))); - dst->st_other = decode (hdr->st_other); - dst->st_shndx = decode (hdr->st_shndx); - } + if (bfd_dynsym == NULL && bfd_sym == NULL) + get_bfd_symbols (); + if (is_dynamic) + return bfd_dynsymcnt; + return bfd_symcnt; +} + +/* Returns an ASYMBOL on index NDX if it exists. If DST is defined, + the internal elf symbol at intex NDX is copied into it. IS_DYNAMIC + selects the type of the symbol. */ + +asymbol * +Elf::elf_getsym (unsigned int ndx, Elf_Internal_Sym *dst, bool is_dynamic) +{ + asymbol *asym; + + if (bfd_dynsym == NULL && bfd_sym == NULL) + get_bfd_symbols (); + + if (is_dynamic) + if (ndx < bfd_dynsymcnt) + asym = bfd_dynsym[ndx]; + else + return NULL; else - { - if (edta->d_size <= ndx * sizeof (Elf64_Sym)) - return NULL; - Elf64_Sym *hdr = (Elf64_Sym*) bind (edta->d_off + ndx * sizeof (Elf64_Sym), - sizeof (Elf64_Sym)); - if (hdr == NULL) - return NULL; - dst->st_name = decode (hdr->st_name); - dst->st_value = decode (hdr->st_value); - dst->st_size = decode (hdr->st_size); - dst->st_info = decode (hdr->st_info); - dst->st_other = decode (hdr->st_other); - dst->st_shndx = decode (hdr->st_shndx); - } - return dst; + if (ndx < bfd_symcnt) + asym = bfd_sym[ndx]; + else + return NULL; + + if (dst != NULL) + *dst = ((elf_symbol_type *) asym)->internal_elf_sym; + + return asym; } Elf_Internal_Rela * diff --git a/gprofng/src/Elf.h b/gprofng/src/Elf.h index 7c32dfe..b324c39 100644 --- a/gprofng/src/Elf.h +++ b/gprofng/src/Elf.h @@ -92,7 +92,8 @@ public: int64_t elf_checksum (); uint64_t get_baseAddr(); char *elf_strptr (unsigned int sec, uint64_t off); - Elf_Internal_Sym *elf_getsym (Elf_Data *edta, unsigned int ndx, Elf_Internal_Sym *dst); + long elf_getSymCount (bool is_dynamic); + asymbol *elf_getsym (unsigned int ndx, Elf_Internal_Sym *dst, bool is_dynamic); Elf_Internal_Rela *elf_getrel (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst); Elf_Internal_Rela *elf_getrela (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst); Elf64_Ancillary *elf_getancillary (Elf_Data *edta, unsigned int ndx, Elf64_Ancillary *dst); diff --git a/gprofng/src/Stabs.cc b/gprofng/src/Stabs.cc index 2120319..b98ac28 100644 --- a/gprofng/src/Stabs.cc +++ b/gprofng/src/Stabs.cc @@ -241,6 +241,40 @@ RelValueCmp (const void *a, const void *b) (item1->value == item2->value) ? 0 : -1; } +/* Remove all duplicate symbols which can be in SymLst. The + duplication is due to processing of both static and dynamic + symbols. This function is called before computing symbol + aliases. */ + +void +Stabs::removeDupSyms () +{ + long ind, i, last; + Symbol *symA, *symB; + SymLst->sort (SymImgOffsetCmp); + dump (); + + last = 0; + ind = SymLst->size (); + for (i = 0; i < ind; i++) + { + symA = SymLst->fetch (i); + if (symA->img_offset == 0) // Ignore this bad symbol + continue; + + SymLst->put (last++, symA); + for (long k = i + 1; k < ind; k++, i++) + { + symB = SymLst->fetch (k); + if (symA->img_offset != symB->img_offset) + break; + if (strcmp (symA->name, symB->name) != 0) + break; + } + } + SymLst->truncate (last); +} + Stabs * Stabs::NewStabs (char *_path, char *lo_name) { @@ -272,7 +306,7 @@ Stabs::Stabs (char *_path, char *_lo_name) stabsModules = NULL; textsz = 0; wsize = Wnone; - st_check_symtab = st_check_relocs = false; + st_check_symtab = false; status = DBGD_ERR_NONE; if (openElf (false) == NULL) @@ -412,7 +446,6 @@ Stabs::read_symbols (Vector<Function*> *functions) if (openElf (true) == NULL) return false; check_Symtab (); - check_Relocs (); if (functions) { Function *fp; @@ -1703,43 +1736,31 @@ Stabs::check_Symtab () pltSym->flags |= SYM_PLT; } } - if (elf->symtab) - readSymSec (elf->symtab, elf); - else - { - readSymSec (elf->SUNW_ldynsym, elf); - readSymSec (elf->dynsym, elf); - } + + // Read first static symbols + readSymSec (elf, false); + + // Read dynamic symbols + readSymSec (elf, true); } void -Stabs::readSymSec (unsigned int sec, Elf *elf) +Stabs::readSymSec (Elf *elf, bool is_dynamic) { Symbol *sitem; Sp_lang_code local_lcode; - if (sec == 0) - return; - // Get ELF data - Elf_Data *data = elf->elf_getdata (sec); - if (data == NULL) - return; - uint64_t SymtabSize = data->d_size; - Elf_Internal_Shdr *shdr = elf->get_shdr (sec); - - if ((SymtabSize == 0) || (shdr->sh_entsize == 0)) - return; - Elf_Data *data_str = elf->elf_getdata (shdr->sh_link); - if (data_str == NULL) - return; - char *Strtab = (char *) data_str->d_buf; + unsigned int tot = elf->elf_getSymCount (is_dynamic); // read func symbolic table - for (unsigned int n = 0, tot = SymtabSize / shdr->sh_entsize; n < tot; n++) + for (unsigned int n = 0; n < tot; n++) { Elf_Internal_Sym Sym; - elf->elf_getsym (data, n, &Sym); - const char *st_name = Sym.st_name < data_str->d_size ? - (Strtab + Sym.st_name) : NTXT ("no_name"); + asymbol *asym; + asym = elf->elf_getsym (n, &Sym, is_dynamic); + // TBD: convert this check to an assert + if (asym == NULL) + break; + const char *st_name = bfd_asymbol_name (asym); switch (GELF_ST_TYPE (Sym.st_info)) { case STT_FUNC: @@ -1814,6 +1835,7 @@ Stabs::readSymSec (unsigned int sec, Elf *elf) } } } + removeDupSyms (); fixSymtabAlias (); SymLst->sort (SymValueCmp); get_save_addr (elf->need_swap_endian); @@ -1821,142 +1843,6 @@ Stabs::readSymSec (unsigned int sec, Elf *elf) }//check_Symtab void -Stabs::check_Relocs () -{ - // We may have many relocation tables to process: .rela.text%foo, - // rela.text%bar, etc. On Intel, compilers generate .rel.text sections - // which have to be processed as well. A lot of rework is needed here. - Symbol *sptr = NULL; - if (st_check_relocs) - return; - st_check_relocs = true; - - Elf *elf = openElf (false); - if (elf == NULL) - return; - for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++) - { - bool use_rela, use_PLT; - char *name = elf->get_sec_name (sec); - if (name == NULL) - continue; - if (strncmp (name, NTXT (".rela.text"), 10) == 0) - { - use_rela = true; - use_PLT = false; - } - else if (streq (name, NTXT (".rela.plt"))) - { - use_rela = true; - use_PLT = true; - } - else if (strncmp (name, NTXT (".rel.text"), 9) == 0) - { - use_rela = false; - use_PLT = false; - } - else if (streq (name, NTXT (".rel.plt"))) - { - use_rela = false; - use_PLT = true; - } - else - continue; - - Elf_Internal_Shdr *shdr = elf->get_shdr (sec); - if (shdr == NULL) - continue; - - // Get ELF data - Elf_Data *data = elf->elf_getdata (sec); - if (data == NULL) - continue; - uint64_t ScnSize = data->d_size; - uint64_t EntSize = shdr->sh_entsize; - if ((ScnSize == 0) || (EntSize == 0)) - continue; - int tot = (int) (ScnSize / EntSize); - - // Get corresponding text section - Elf_Internal_Shdr *shdr_txt = elf->get_shdr (shdr->sh_info); - if (shdr_txt == NULL) - continue; - if (!(shdr_txt->sh_flags & SHF_EXECINSTR)) - continue; - - // Get corresponding symbol table section - Elf_Internal_Shdr *shdr_sym = elf->get_shdr (shdr->sh_link); - if (shdr_sym == NULL) - continue; - Elf_Data *data_sym = elf->elf_getdata (shdr->sh_link); - - // Get corresponding string table section - Elf_Data *data_str = elf->elf_getdata (shdr_sym->sh_link); - if (data_str == NULL) - continue; - char *Strtab = (char*) data_str->d_buf; - for (int n = 0; n < tot; n++) - { - Elf_Internal_Sym sym; - Elf_Internal_Rela rela; - char *symName; - if (use_rela) - elf->elf_getrela (data, n, &rela); - else - { - // GElf_Rela is extended GElf_Rel - elf->elf_getrel (data, n, &rela); - rela.r_addend = 0; - } - - int ndx = (int) GELF_R_SYM (rela.r_info); - elf->elf_getsym (data_sym, ndx, &sym); - switch (GELF_ST_TYPE (sym.st_info)) - { - case STT_FUNC: - case STT_OBJECT: - case STT_NOTYPE: - if (sym.st_name == 0 || sym.st_name >= data_str->d_size) - continue; - symName = Strtab + sym.st_name; - break; - case STT_SECTION: - { - Elf_Internal_Shdr *secHdr = elf->get_shdr (sym.st_shndx); - if (secHdr == NULL) - continue; - if (sptr == NULL) - sptr = new Symbol; - sptr->value = secHdr->sh_offset + rela.r_addend; - long index = SymLst->bisearch (0, -1, &sptr, SymFindCmp); - if (index == -1) - continue; - Symbol *sp = SymLst->fetch (index); - if (sptr->value != sp->value) - continue; - symName = sp->name; - break; - } - default: - continue; - } - Reloc *reloc = new Reloc; - reloc->name = dbe_strdup (symName); - reloc->type = GELF_R_TYPE (rela.r_info); - reloc->value = use_PLT ? rela.r_offset - : rela.r_offset + shdr_txt->sh_offset; - reloc->addend = rela.r_addend; - if (use_PLT) - RelPLTLst->append (reloc); - else - RelLst->append (reloc); - } - } - delete sptr; - RelLst->sort (RelValueCmp); -} //check_Relocs - -void Stabs::get_save_addr (bool need_swap_endian) { if (elfDis->is_Intel ()) diff --git a/gprofng/src/Stabs.h b/gprofng/src/Stabs.h index 42aa6fb..d34741f 100644 --- a/gprofng/src/Stabs.h +++ b/gprofng/src/Stabs.h @@ -129,8 +129,7 @@ class Stabs { // Interface with Elf Symbol Table void check_Symtab(); - void readSymSec(unsigned int sec, Elf *elf); - void check_Relocs(); + void readSymSec (Elf *elf, bool is_dynamic); void get_save_addr(bool need_swap_endian); Symbol *map_PC_to_sym(uint64_t pc); Symbol *pltSym; @@ -146,9 +145,10 @@ class Stabs { Map<const char*, Symbol*> *get_elf_symbols(); Dwarf *dwarf; - bool st_check_symtab, st_check_relocs; + bool st_check_symtab; Function *createFunction(LoadObject *lo, Module *module, Symbol *sym); void fixSymtabAlias(); + void removeDupSyms (); // Interface with dwarf Dwarf *openDwarf(); diff --git a/gprofng/src/vec.h b/gprofng/src/vec.h index 04cce4e..a768a02 100644 --- a/gprofng/src/vec.h +++ b/gprofng/src/vec.h @@ -112,6 +112,13 @@ public: return data[index]; } + void + truncate (long ncount) + { + if (count > ncount && ncount >= 0) + count = ncount; + } + // Return the first index in "this" that equals "item". // Return -1 if "item" is not found. long find (const ITEM item); diff --git a/ld/pe-dll.c b/ld/pe-dll.c index de1cfaf..4a2ea03 100644 --- a/ld/pe-dll.c +++ b/ld/pe-dll.c @@ -2639,9 +2639,9 @@ make_import_fixup_mark (arelent *rel, char *name) memcpy (fixup_name, buf, prefix_len); bh = NULL; - bfd_coff_link_add_one_symbol (&link_info, abfd, fixup_name, BSF_GLOBAL, - current_sec, /* sym->section, */ - rel->address, NULL, true, false, &bh); + _bfd_generic_link_add_one_symbol (&link_info, abfd, fixup_name, BSF_GLOBAL, + current_sec, /* sym->section, */ + rel->address, NULL, true, false, &bh); return bh->root.string; } |