From b08d5a8fb42f4586d756068065186b5af7e48dad Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Tue, 26 Jul 2005 05:00:05 +0000 Subject: [PATCH] Adjust for monotone. --- .cvsignore | 7 + ABOUT-NLS | 588 ++ AUTHORS | 2 + COPYING | 162 + COPYING.GPL | 340 ++ CREATE-MINI | 47 + ChangeLog | 112 + GPG-KEY | 33 + INSTALL | 182 + Makefile.am | 36 + NEWS | 786 +++ NOTES | 73 + README | 6 + THANKS | 5 + TODO | 168 + config/.cvsignore | 1 + config/ChangeLog | 53 + config/Makefile.am | 38 + config/config.guess | 1459 +++++ config/config.sub | 1549 +++++ config/depcomp | 436 ++ config/elfutils.spec.in | 385 ++ config/install-sh | 251 + config/missing | 336 ++ config/mkinstalldirs | 101 + configure.ac | 276 + doc/.cvsignore | 1 + doc/ChangeLog | 12 + doc/Makefile.am | 29 + doc/elfutils.sgml | 444 ++ fake-src/FULL | 3 + fake-src/Makefile.am | 24 + fake-src/Makefile.in | 390 ++ fake-src/addr2line | 2 + fake-src/dwarf.h | 557 ++ fake-src/elflint.in | 4 + fake-src/nm | 2 + fake-src/readelf | 2 + fake-src/size | 2 + fake-src/strip | 20 + lib/.cvsignore | 1 + lib/ChangeLog | 39 + lib/Makefile.am | 35 + lib/crc32.c | 86 + lib/crc32_file.c | 59 + lib/dynamicsizehash.c | 316 + lib/dynamicsizehash.h | 107 + lib/fixedsizehash.h | 255 + lib/list.h | 85 + lib/next_prime.c | 54 + lib/system.h | 40 + lib/xmalloc.c | 68 + lib/xstrdup.c | 27 + lib/xstrndup.c | 31 + libasm/.cvsignore | 1 + libasm/ChangeLog | 52 + libasm/Makefile.am | 86 + libasm/asm_abort.c | 45 + libasm/asm_addint16.c | 17 + libasm/asm_addint32.c | 17 + libasm/asm_addint64.c | 17 + libasm/asm_addint8.c | 105 + libasm/asm_addsleb128.c | 84 + libasm/asm_addstrz.c | 113 + libasm/asm_adduint16.c | 17 + libasm/asm_adduint32.c | 17 + libasm/asm_adduint64.c | 17 + libasm/asm_adduint8.c | 41 + libasm/asm_adduleb128.c | 80 + libasm/asm_align.c | 147 + libasm/asm_begin.c | 151 + libasm/asm_end.c | 593 ++ libasm/asm_error.c | 183 + libasm/asm_fill.c | 62 + libasm/asm_getelf.c | 29 + libasm/asm_newabssym.c | 121 + libasm/asm_newcomsym.c | 102 + libasm/asm_newscn.c | 202 + libasm/asm_newscn_ingrp.c | 66 + libasm/asm_newscngrp.c | 90 + libasm/asm_newsubscn.c | 84 + libasm/asm_newsym.c | 123 + libasm/asm_scngrp_newsignature.c | 33 + libasm/libasm.h | 155 + libasm/libasm.map | 33 + libasm/libasmP.h | 268 + libasm/symbolhash.c | 39 + libasm/symbolhash.h | 25 + libcpu/.cvsignore | 1 + libcpu/ChangeLog | 11 + libcpu/Makefile.am | 21 + libcpu/i386_dis.c | 1 + libdw/.cvsignore | 1 + libdw/ChangeLog | 512 ++ libdw/Makefile.am | 108 + libdw/dwarf.h | 581 ++ libdw/dwarf_abbrev_hash.c | 29 + libdw/dwarf_abbrev_hash.h | 24 + libdw/dwarf_abbrevhaschildren.c | 29 + libdw/dwarf_addrdie.c | 39 + libdw/dwarf_arrayorder.c | 33 + libdw/dwarf_attr.c | 40 + libdw/dwarf_attr_integrate.c | 43 + libdw/dwarf_begin.c | 85 + libdw/dwarf_begin_elf.c | 252 + libdw/dwarf_bitoffset.c | 33 + libdw/dwarf_bitsize.c | 33 + libdw/dwarf_bytesize.c | 33 + libdw/dwarf_child.c | 159 + libdw/dwarf_cuoffset.c | 32 + libdw/dwarf_diename.c | 31 + libdw/dwarf_dieoffset.c | 32 + libdw/dwarf_end.c | 75 + libdw/dwarf_error.c | 180 + libdw/dwarf_filesrc.c | 36 + libdw/dwarf_formaddr.c | 44 + libdw/dwarf_formblock.c | 72 + libdw/dwarf_formflag.c | 40 + libdw/dwarf_formref.c | 67 + libdw/dwarf_formref_die.c | 28 + libdw/dwarf_formsdata.c | 68 + libdw/dwarf_formstring.c | 58 + libdw/dwarf_formudata.c | 68 + libdw/dwarf_func_col.c | 27 + libdw/dwarf_func_entrypc.c | 33 + libdw/dwarf_func_file.c | 72 + libdw/dwarf_func_highpc.c | 26 + libdw/dwarf_func_line.c | 47 + libdw/dwarf_func_lowpc.c | 26 + libdw/dwarf_func_name.c | 30 + libdw/dwarf_getabbrev.c | 127 + libdw/dwarf_getabbrevattr.c | 64 + libdw/dwarf_getabbrevcode.c | 29 + libdw/dwarf_getabbrevtag.c | 29 + libdw/dwarf_getarange_addr.c | 47 + libdw/dwarf_getarangeinfo.c | 38 + libdw/dwarf_getaranges.c | 212 + libdw/dwarf_getattrcnt.c | 33 + libdw/dwarf_getattrs.c | 94 + libdw/dwarf_getelf.c | 33 + libdw/dwarf_getfuncs.c | 63 + libdw/dwarf_getloclist.c | 454 ++ libdw/dwarf_getmacros.c | 119 + libdw/dwarf_getpubnames.c | 213 + libdw/dwarf_getscopes.c | 334 ++ libdw/dwarf_getscopevar.c | 147 + libdw/dwarf_getsrc_die.c | 58 + libdw/dwarf_getsrc_file.c | 158 + libdw/dwarf_getsrcfiles.c | 60 + libdw/dwarf_getsrclines.c | 652 +++ libdw/dwarf_getstring.c | 51 + libdw/dwarf_hasattr.c | 37 + libdw/dwarf_hasattr_integrate.c | 42 + libdw/dwarf_haschildren.c | 49 + libdw/dwarf_hasform.c | 32 + libdw/dwarf_haspc.c | 105 + libdw/dwarf_highpc.c | 34 + libdw/dwarf_lineaddr.c | 31 + libdw/dwarf_linebeginstatement.c | 31 + libdw/dwarf_lineblock.c | 31 + libdw/dwarf_linecol.c | 31 + libdw/dwarf_lineendsequence.c | 31 + libdw/dwarf_lineepiloguebegin.c | 31 + libdw/dwarf_lineno.c | 31 + libdw/dwarf_lineprologueend.c | 31 + libdw/dwarf_linesrc.c | 41 + libdw/dwarf_lowpc.c | 34 + libdw/dwarf_macro_opcode.c | 31 + libdw/dwarf_macro_param1.c | 31 + libdw/dwarf_macro_param2.c | 34 + libdw/dwarf_nextcu.c | 132 + libdw/dwarf_offabbrev.c | 36 + libdw/dwarf_offdie.c | 55 + libdw/dwarf_onearange.c | 35 + libdw/dwarf_onesrcline.c | 35 + libdw/dwarf_siblingof.c | 115 + libdw/dwarf_srclang.c | 33 + libdw/dwarf_tag.c | 82 + libdw/dwarf_whatattr.c | 28 + libdw/dwarf_whatform.c | 28 + libdw/libdw.h | 564 ++ libdw/libdw.map | 92 + libdw/libdwP.h | 378 ++ libdw/libdw_alloc.c | 59 + libdw/libdw_findcu.c | 110 + libdw/libdw_form.c | 112 + libdw/memory-access.c | 35 + libdw/memory-access.h | 240 + libdwarf/.cvsignore | 1 + libdwarf/AVAILABLE | 136 + libdwarf/ChangeLog | 3 + libdwarf/Makefile.am | 103 + libdwarf/dwarf.h | 549 ++ libdwarf/dwarf_abbrev_hash.c | 29 + libdwarf/dwarf_abbrev_hash.h | 24 + libdwarf/dwarf_arrayorder.c | 31 + libdwarf/dwarf_attr.c | 113 + libdwarf/dwarf_attrlist.c | 182 + libdwarf/dwarf_bitoffset.c | 31 + libdwarf/dwarf_bitsize.c | 31 + libdwarf/dwarf_bytesize.c | 31 + libdwarf/dwarf_child.c | 123 + libdwarf/dwarf_dealloc.c | 32 + libdwarf/dwarf_die_CU_offset.c | 33 + libdwarf/dwarf_diename.c | 139 + libdwarf/dwarf_dieoffset.c | 31 + libdwarf/dwarf_elf_init.c | 197 + libdwarf/dwarf_errmsg.c | 67 + libdwarf/dwarf_errno.c | 26 + libdwarf/dwarf_error.c | 52 + libdwarf/dwarf_find_macro_value_start.c | 45 + libdwarf/dwarf_finish.c | 40 + libdwarf/dwarf_form.c | 107 + libdwarf/dwarf_formaddr.c | 42 + libdwarf/dwarf_formblock.c | 76 + libdwarf/dwarf_formflag.c | 39 + libdwarf/dwarf_formref.c | 67 + libdwarf/dwarf_formsdata.c | 72 + libdwarf/dwarf_formstring.c | 51 + libdwarf/dwarf_formudata.c | 72 + libdwarf/dwarf_get_abbrev.c | 111 + libdwarf/dwarf_get_abbrev_children_flag.c | 29 + libdwarf/dwarf_get_abbrev_code.c | 29 + libdwarf/dwarf_get_abbrev_entry.c | 63 + libdwarf/dwarf_get_abbrev_tag.c | 29 + libdwarf/dwarf_get_address_size.c | 30 + libdwarf/dwarf_get_arange.c | 41 + libdwarf/dwarf_get_arange_info.c | 48 + libdwarf/dwarf_get_aranges.c | 186 + libdwarf/dwarf_get_cie_info.c | 53 + libdwarf/dwarf_get_cie_of_fde.c | 30 + libdwarf/dwarf_get_cu_die_offset.c | 43 + libdwarf/dwarf_get_elf.c | 33 + libdwarf/dwarf_get_fde_at_pc.c | 57 + libdwarf/dwarf_get_fde_instr_bytes.c | 33 + libdwarf/dwarf_get_fde_list_eh.c | 363 ++ libdwarf/dwarf_get_fde_n.c | 36 + libdwarf/dwarf_get_fde_range.c | 44 + libdwarf/dwarf_get_globals.c | 176 + libdwarf/dwarf_get_loclist_entry.c | 88 + libdwarf/dwarf_get_str.c | 43 + libdwarf/dwarf_getabbrev.c | 73 + libdwarf/dwarf_getconstant.c | 125 + libdwarf/dwarf_global_cu_offset.c | 44 + libdwarf/dwarf_global_die_offset.c | 33 + libdwarf/dwarf_global_formref.c | 73 + libdwarf/dwarf_global_name_offsets.c | 64 + libdwarf/dwarf_globname.c | 38 + libdwarf/dwarf_hasattr.c | 98 + libdwarf/dwarf_hasform.c | 31 + libdwarf/dwarf_highpc.c | 108 + libdwarf/dwarf_init.c | 92 + libdwarf/dwarf_lineaddr.c | 30 + libdwarf/dwarf_linebeginstatement.c | 30 + libdwarf/dwarf_lineblock.c | 30 + libdwarf/dwarf_lineendsequence.c | 30 + libdwarf/dwarf_lineepiloguebegin.c | 30 + libdwarf/dwarf_lineno.c | 30 + libdwarf/dwarf_lineoff.c | 30 + libdwarf/dwarf_lineprologueend.c | 30 + libdwarf/dwarf_linesrc.c | 44 + libdwarf/dwarf_loclist.c | 470 ++ libdwarf/dwarf_lowpc.c | 108 + libdwarf/dwarf_next_cu_header.c | 234 + libdwarf/dwarf_offdie.c | 123 + libdwarf/dwarf_seterrarg.c | 30 + libdwarf/dwarf_seterrhand.c | 30 + libdwarf/dwarf_siblingof.c | 257 + libdwarf/dwarf_srcfiles.c | 344 ++ libdwarf/dwarf_srclang.c | 31 + libdwarf/dwarf_srclines.c | 745 +++ libdwarf/dwarf_tag.c | 30 + libdwarf/dwarf_whatattr.c | 30 + libdwarf/dwarf_whatform.c | 30 + libdwarf/libdwarf.h | 514 ++ libdwarf/libdwarf.map | 81 + libdwarf/libdwarfP.h | 319 ++ libdwarf/memory-access.h | 207 + libdwfl/.cvsignore | 1 + libdwfl/ChangeLog | 13 + libdwfl/Makefile.am | 114 + libdwfl/argp-std.c | 164 + libdwfl/cu.c | 275 + libdwfl/dwfl_addrdie.c | 21 + libdwfl/dwfl_addrdwarf.c | 22 + libdwfl/dwfl_addrmodule.c | 38 + libdwfl/dwfl_begin.c | 33 + libdwfl/dwfl_cumodule.c | 21 + libdwfl/dwfl_end.c | 26 + libdwfl/dwfl_error.c | 222 + libdwfl/dwfl_getdwarf.c | 40 + libdwfl/dwfl_getmodules.c | 37 + libdwfl/dwfl_getsrc.c | 21 + libdwfl/dwfl_lineinfo.c | 40 + libdwfl/dwfl_linemodule.c | 23 + libdwfl/dwfl_module.c | 188 + libdwfl/dwfl_module_addrdie.c | 30 + libdwfl/dwfl_module_getdwarf.c | 480 ++ libdwfl/dwfl_module_getsrc.c | 60 + libdwfl/dwfl_module_getsrc_file.c | 144 + libdwfl/dwfl_module_info.c | 44 + libdwfl/dwfl_module_nextcu.c | 29 + libdwfl/dwfl_nextcu.c | 52 + libdwfl/dwfl_report_elf.c | 117 + libdwfl/elf-from-memory.c | 328 ++ libdwfl/find-debuginfo.c | 157 + libdwfl/libdwfl.h | 262 + libdwfl/libdwfl.map | 39 + libdwfl/libdwflP.h | 237 + libdwfl/lines.c | 37 + libdwfl/linux-kernel-modules.c | 243 + libdwfl/linux-proc-maps.c | 285 + libdwfl/loc2c-runtime.h | 125 + libdwfl/loc2c.c | 1398 +++++ libdwfl/loc2c.h | 63 + libdwfl/ptest.c | 117 + libdwfl/relocate.c | 293 + libdwfl/test2.c | 268 + libebl/.cvsignore | 1 + libebl/ChangeLog | 281 + libebl/Makefile.am | 201 + libebl/alpha_destr.c | 27 + libebl/alpha_init.c | 41 + libebl/alpha_symbol.c | 101 + libebl/arm_destr.c | 27 + libebl/arm_init.c | 41 + libebl/arm_symbol.c | 121 + libebl/eblbackendname.c | 28 + libebl/eblclosebackend.c | 39 + libebl/eblcopyrelocp.c | 28 + libebl/eblcorenote.c | 191 + libebl/eblcorenotetypename.c | 68 + libebl/ebldebugscnp.c | 29 + libebl/ebldynamictagcheck.c | 41 + libebl/ebldynamictagname.c | 97 + libebl/eblgotpcreloccheck.c | 29 + libebl/eblgstrtab.c | 350 ++ libebl/eblmachineflagcheck.c | 28 + libebl/eblmachineflagname.c | 76 + libebl/eblobjecttypename.c | 48 + libebl/eblobjnote.c | 87 + libebl/eblobjnotetypename.c | 54 + libebl/eblopenbackend.c | 551 ++ libebl/eblosabiname.c | 69 + libebl/eblrelocsimpletype.c | 27 + libebl/eblreloctypecheck.c | 28 + libebl/eblreloctypename.c | 38 + libebl/eblrelocvaliduse.c | 28 + libebl/eblsectionname.c | 81 + libebl/eblsectionstripp.c | 52 + libebl/eblsectiontypename.c | 103 + libebl/eblsegmenttypename.c | 75 + libebl/eblshflagscombine.c | 29 + libebl/eblstrtab.c | 337 ++ libebl/eblsymbolbindingname.c | 57 + libebl/eblsymboltypename.c | 63 + libebl/eblwstrtab.c | 344 ++ libebl/i386_corenote.c | 162 + libebl/i386_destr.c | 27 + libebl/i386_init.c | 47 + libebl/i386_symbol.c | 163 + libebl/ia64_destr.c | 27 + libebl/ia64_init.c | 43 + libebl/ia64_symbol.c | 187 + libebl/libebl.h | 208 + libebl/libeblP.h | 118 + libebl/libebl_alpha.h | 37 + libebl/libebl_alpha.map | 11 + libebl/libebl_arm.h | 37 + libebl/libebl_arm.map | 11 + libebl/libebl_i386.h | 54 + libebl/libebl_i386.map | 14 + libebl/libebl_ia64.h | 43 + libebl/libebl_ia64.map | 11 + libebl/libebl_ppc.h | 47 + libebl/libebl_ppc.map | 12 + libebl/libebl_ppc64.h | 50 + libebl/libebl_ppc64.map | 12 + libebl/libebl_sh.h | 34 + libebl/libebl_sh.map | 10 + libebl/libebl_sparc.h | 41 + libebl/libebl_sparc.map | 11 + libebl/libebl_x86_64.h | 47 + libebl/libebl_x86_64.map | 13 + libebl/ppc64_destr.c | 27 + libebl/ppc64_init.c | 44 + libebl/ppc64_symbol.c | 235 + libebl/ppc_destr.c | 27 + libebl/ppc_init.c | 43 + libebl/ppc_symbol.c | 174 + libebl/sh_destr.c | 27 + libebl/sh_init.c | 40 + libebl/sh_symbol.c | 99 + libebl/sparc_destr.c | 26 + libebl/sparc_init.c | 46 + libebl/sparc_symbol.c | 149 + libebl/x86_64_corenote.c | 171 + libebl/x86_64_destr.c | 27 + libebl/x86_64_init.c | 44 + libebl/x86_64_symbol.c | 136 + libelf-po/.cvsignore | 1 + libelf-po/ChangeLog | 15 + libelf-po/Makefile.in.in | 302 + libelf-po/Makevars | 25 + libelf-po/POTFILES.in | 5 + libelf-po/Rules-quot | 42 + libelf-po/boldquot.sed | 10 + libelf-po/en@boldquot.header | 25 + libelf-po/en@quot.header | 22 + libelf-po/insert-header.sin | 23 + libelf-po/quot.sed | 6 + libelf/.cvsignore | 1 + libelf/ChangeLog | 141 + libelf/Makefile.am | 120 + libelf/abstract.h | 283 + libelf/common.h | 146 + libelf/dl-hash.h | 70 + libelf/elf-knowledge.h | 94 + libelf/elf.h | 2577 +++++++++ libelf/elf32_checksum.c | 145 + libelf/elf32_fsize.c | 59 + libelf/elf32_getehdr.c | 65 + libelf/elf32_getphdr.c | 198 + libelf/elf32_getshdr.c | 182 + libelf/elf32_newehdr.c | 80 + libelf/elf32_newphdr.c | 138 + libelf/elf32_updatefile.c | 610 ++ libelf/elf32_updatenull.c | 384 ++ libelf/elf32_xlatetof.c | 111 + libelf/elf32_xlatetom.c | 112 + libelf/elf64_checksum.c | 19 + libelf/elf64_fsize.c | 19 + libelf/elf64_getehdr.c | 19 + libelf/elf64_getphdr.c | 19 + libelf/elf64_getshdr.c | 19 + libelf/elf64_newehdr.c | 19 + libelf/elf64_newphdr.c | 19 + libelf/elf64_updatefile.c | 18 + libelf/elf64_updatenull.c | 18 + libelf/elf64_xlatetof.c | 19 + libelf/elf64_xlatetom.c | 19 + libelf/elf_begin.c | 1073 ++++ libelf/elf_clone.c | 69 + libelf/elf_cntl.c | 71 + libelf/elf_end.c | 203 + libelf/elf_error.c | 366 ++ libelf/elf_fill.c | 35 + libelf/elf_flagdata.c | 59 + libelf/elf_flagehdr.c | 56 + libelf/elf_flagelf.c | 58 + libelf/elf_flagphdr.c | 56 + libelf/elf_flagscn.c | 56 + libelf/elf_flagshdr.c | 56 + libelf/elf_getarhdr.c | 53 + libelf/elf_getarsym.c | 241 + libelf/elf_getbase.c | 33 + libelf/elf_getdata.c | 454 ++ libelf/elf_getident.c | 51 + libelf/elf_getscn.c | 77 + libelf/elf_getshnum.c | 64 + libelf/elf_getshstrndx.c | 168 + libelf/elf_hash.c | 33 + libelf/elf_kind.c | 33 + libelf/elf_memory.c | 40 + libelf/elf_ndxscn.c | 36 + libelf/elf_newdata.c | 97 + libelf/elf_newscn.c | 143 + libelf/elf_next.c | 53 + libelf/elf_nextscn.c | 77 + libelf/elf_rand.c | 49 + libelf/elf_rawdata.c | 66 + libelf/elf_rawfile.c | 51 + libelf/elf_readall.c | 116 + libelf/elf_strptr.c | 122 + libelf/elf_update.c | 178 + libelf/elf_version.c | 58 + libelf/exttypes.h | 86 + libelf/gelf.h | 308 + libelf/gelf_checksum.c | 37 + libelf/gelf_freechunk.c | 45 + libelf/gelf_fsize.c | 96 + libelf/gelf_getclass.c | 33 + libelf/gelf_getdyn.c | 99 + libelf/gelf_getehdr.c | 88 + libelf/gelf_getlib.c | 68 + libelf/gelf_getmove.c | 70 + libelf/gelf_getphdr.c | 117 + libelf/gelf_getrel.c | 96 + libelf/gelf_getrela.c | 97 + libelf/gelf_getshdr.c | 91 + libelf/gelf_getsym.c | 105 + libelf/gelf_getsyminfo.c | 68 + libelf/gelf_getsymshndx.c | 128 + libelf/gelf_getverdaux.c | 70 + libelf/gelf_getverdef.c | 69 + libelf/gelf_getvernaux.c | 72 + libelf/gelf_getverneed.c | 72 + libelf/gelf_getversym.c | 77 + libelf/gelf_newehdr.c | 36 + libelf/gelf_newphdr.c | 36 + libelf/gelf_rawchunk.c | 71 + libelf/gelf_update_dyn.c | 104 + libelf/gelf_update_ehdr.c | 103 + libelf/gelf_update_lib.c | 72 + libelf/gelf_update_move.c | 69 + libelf/gelf_update_phdr.c | 120 + libelf/gelf_update_rel.c | 102 + libelf/gelf_update_rela.c | 105 + libelf/gelf_update_shdr.c | 94 + libelf/gelf_update_sym.c | 113 + libelf/gelf_update_syminfo.c | 80 + libelf/gelf_update_symshndx.c | 143 + libelf/gelf_update_verdaux.c | 69 + libelf/gelf_update_verdef.c | 69 + libelf/gelf_update_vernaux.c | 69 + libelf/gelf_update_verneed.c | 69 + libelf/gelf_update_versym.c | 69 + libelf/gelf_xlate.c | 182 + libelf/gelf_xlate.h | 43 + libelf/gelf_xlatetof.c | 41 + libelf/gelf_xlatetom.c | 41 + libelf/libelf.h | 343 ++ libelf/libelf.map | 106 + libelf/libelfP.h | 534 ++ libelf/libelf_crc32.c | 23 + libelf/libelf_next_prime.c | 21 + libelf/nlist.c | 224 + libelf/nlist.h | 44 + libelf/version_xlate.h | 208 + m4/.cvsignore | 1 + m4/ChangeLog | 31 + m4/Makefile.am | 20 + m4/codeset.m4 | 23 + m4/gettext.m4 | 587 ++ m4/iconv.m4 | 103 + m4/lcmessage.m4 | 32 + m4/progtest.m4 | 59 + po/.cvsignore | 1 + po/ChangeLog | 19 + po/Makefile.in.in | 302 + po/Makevars | 25 + po/POTFILES.in | 24 + po/Rules-quot | 42 + po/boldquot.sed | 10 + po/en@boldquot.header | 25 + po/en@quot.header | 22 + po/insert-header.sin | 23 + po/quot.sed | 6 + src/.cvsignore | 1 + src/ChangeLog | 413 ++ src/Makefile.am | 144 + src/addr2line.c | 372 ++ src/elf32-i386.script | 215 + src/elfcmp.c | 611 ++ src/elflint.c | 2617 +++++++++ src/findtextrel.c | 596 ++ src/i386_ld.c | 894 +++ src/ld.c | 1506 +++++ src/ld.h | 1074 ++++ src/ldgeneric.c | 6376 +++++++++++++++++++++ src/ldlex.l | 349 ++ src/ldscript.y | 795 +++ src/libld_elf_i386.map | 7 + src/nm.c | 1282 +++++ src/none_ld.c | 1 + src/readelf.c | 4997 ++++++++++++++++ src/sectionhash.c | 69 + src/sectionhash.h | 23 + src/size.c | 682 +++ src/strip.c | 1750 ++++++ src/symbolhash.c | 29 + src/symbolhash.h | 24 + src/unaligned.h | 98 + src/versionhash.c | 28 + src/versionhash.h | 22 + src/xelf.h | 387 ++ src/ylwrap | 154 + tests/.cvsignore | 1 + tests/ChangeLog | 126 + tests/Makefile.am | 113 + tests/allfcts.c | 50 + tests/arextract.c | 155 + tests/arsymtest.c | 132 + tests/asm-tst1.c | 239 + tests/asm-tst2.c | 261 + tests/asm-tst3.c | 322 ++ tests/asm-tst4.c | 88 + tests/asm-tst5.c | 100 + tests/asm-tst6.c | 134 + tests/asm-tst7.c | 164 + tests/asm-tst8.c | 172 + tests/asm-tst9.c | 318 + tests/ecp.c | 88 + tests/get-aranges.c | 134 + tests/get-files.c | 83 + tests/get-lines.c | 129 + tests/get-pubnames.c | 90 + tests/hash.c | 41 + tests/line2addr.c | 65 + tests/msg_tst.c | 99 + tests/newfile.c | 166 + tests/newscn.c | 58 + tests/run-allfcts.sh | 46 + tests/run-arextract.sh | 33 + tests/run-arsymtest.sh | 41 + tests/run-ecp-test.sh | 25 + tests/run-ecp-test2.sh | 23 + tests/run-elflint-test.sh | 28 + tests/run-get-aranges.sh | 71 + tests/run-get-files.sh | 64 + tests/run-get-lines.sh | 67 + tests/run-get-pubnames.sh | 53 + tests/run-line2addr.sh | 44 + tests/run-show-abbrev.sh | 355 ++ tests/run-show-ciefde.sh | 319 ++ tests/run-show-die-info.sh | 988 ++++ tests/run-strip-test.sh | 51 + tests/run-strip-test2.sh | 17 + tests/run-strip-test3.sh | 17 + tests/run-strip-test4.sh | 5 + tests/run-strip-test5.sh | 5 + tests/run-strip-test6.sh | 5 + tests/saridx.c | 253 + tests/scnnames.c | 87 + tests/sectiondump.c | 178 + tests/show-abbrev.c | 127 + tests/show-ciefde.c | 218 + tests/show-die-info.c | 475 ++ tests/showptable.c | 135 + tests/test-nlist.c | 79 + tests/testfile.bz2 | Bin 0 -> 8115 bytes tests/testfile10.bz2 | Bin 0 -> 2635 bytes tests/testfile11.bz2 | Bin 0 -> 30561 bytes tests/testfile12.bz2 | Bin 0 -> 9948 bytes tests/testfile13.bz2 | Bin 0 -> 1593 bytes tests/testfile14.bz2 | Bin 0 -> 2903 bytes tests/testfile15.bz2 | Bin 0 -> 3132 bytes tests/testfile15.debug.bz2 | Bin 0 -> 28499 bytes tests/testfile16.bz2 | Bin 0 -> 8424 bytes tests/testfile16.debug.bz2 | Bin 0 -> 23520 bytes tests/testfile17.bz2 | Bin 0 -> 1660 bytes tests/testfile17.debug.bz2 | Bin 0 -> 9134 bytes tests/testfile18.bz2 | Bin 0 -> 1721 bytes tests/testfile2.bz2 | Bin 0 -> 6400 bytes tests/testfile3.bz2 | Bin 0 -> 8051 bytes tests/testfile4.bz2 | Bin 0 -> 41405 bytes tests/testfile5.bz2 | Bin 0 -> 5646 bytes tests/testfile6.bz2 | Bin 0 -> 30577 bytes tests/testfile7.bz2 | Bin 0 -> 3107 bytes tests/testfile8.bz2 | Bin 0 -> 31982 bytes tests/testfile9.bz2 | Bin 0 -> 8367 bytes tests/update1.c | 120 + tests/update2.c | 143 + tests/update3.c | 198 + tests/update4.c | 353 ++ 655 files changed, 94872 insertions(+) create mode 100644 .cvsignore create mode 100644 ABOUT-NLS create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 COPYING.GPL create mode 100644 CREATE-MINI create mode 100644 ChangeLog create mode 100644 GPG-KEY create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 NOTES create mode 100644 README create mode 100644 THANKS create mode 100644 TODO create mode 100644 config/.cvsignore create mode 100644 config/ChangeLog create mode 100644 config/Makefile.am create mode 100644 config/config.guess create mode 100644 config/config.sub create mode 100644 config/depcomp create mode 100644 config/elfutils.spec.in create mode 100644 config/install-sh create mode 100644 config/missing create mode 100644 config/mkinstalldirs create mode 100644 configure.ac create mode 100644 doc/.cvsignore create mode 100644 doc/ChangeLog create mode 100644 doc/Makefile.am create mode 100644 doc/elfutils.sgml create mode 100644 fake-src/FULL create mode 100644 fake-src/Makefile.am create mode 100644 fake-src/Makefile.in create mode 100644 fake-src/addr2line create mode 100644 fake-src/dwarf.h create mode 100644 fake-src/elflint.in create mode 100644 fake-src/nm create mode 100644 fake-src/readelf create mode 100644 fake-src/size create mode 100644 fake-src/strip create mode 100644 lib/.cvsignore create mode 100644 lib/ChangeLog create mode 100644 lib/Makefile.am create mode 100644 lib/crc32.c create mode 100644 lib/crc32_file.c create mode 100644 lib/dynamicsizehash.c create mode 100644 lib/dynamicsizehash.h create mode 100644 lib/fixedsizehash.h create mode 100644 lib/list.h create mode 100644 lib/next_prime.c create mode 100644 lib/system.h create mode 100644 lib/xmalloc.c create mode 100644 lib/xstrdup.c create mode 100644 lib/xstrndup.c create mode 100644 libasm/.cvsignore create mode 100644 libasm/ChangeLog create mode 100644 libasm/Makefile.am create mode 100644 libasm/asm_abort.c create mode 100644 libasm/asm_addint16.c create mode 100644 libasm/asm_addint32.c create mode 100644 libasm/asm_addint64.c create mode 100644 libasm/asm_addint8.c create mode 100644 libasm/asm_addsleb128.c create mode 100644 libasm/asm_addstrz.c create mode 100644 libasm/asm_adduint16.c create mode 100644 libasm/asm_adduint32.c create mode 100644 libasm/asm_adduint64.c create mode 100644 libasm/asm_adduint8.c create mode 100644 libasm/asm_adduleb128.c create mode 100644 libasm/asm_align.c create mode 100644 libasm/asm_begin.c create mode 100644 libasm/asm_end.c create mode 100644 libasm/asm_error.c create mode 100644 libasm/asm_fill.c create mode 100644 libasm/asm_getelf.c create mode 100644 libasm/asm_newabssym.c create mode 100644 libasm/asm_newcomsym.c create mode 100644 libasm/asm_newscn.c create mode 100644 libasm/asm_newscn_ingrp.c create mode 100644 libasm/asm_newscngrp.c create mode 100644 libasm/asm_newsubscn.c create mode 100644 libasm/asm_newsym.c create mode 100644 libasm/asm_scngrp_newsignature.c create mode 100644 libasm/libasm.h create mode 100644 libasm/libasm.map create mode 100644 libasm/libasmP.h create mode 100644 libasm/symbolhash.c create mode 100644 libasm/symbolhash.h create mode 100644 libcpu/.cvsignore create mode 100644 libcpu/ChangeLog create mode 100644 libcpu/Makefile.am create mode 100644 libcpu/i386_dis.c create mode 100644 libdw/.cvsignore create mode 100644 libdw/ChangeLog create mode 100644 libdw/Makefile.am create mode 100644 libdw/dwarf.h create mode 100644 libdw/dwarf_abbrev_hash.c create mode 100644 libdw/dwarf_abbrev_hash.h create mode 100644 libdw/dwarf_abbrevhaschildren.c create mode 100644 libdw/dwarf_addrdie.c create mode 100644 libdw/dwarf_arrayorder.c create mode 100644 libdw/dwarf_attr.c create mode 100644 libdw/dwarf_attr_integrate.c create mode 100644 libdw/dwarf_begin.c create mode 100644 libdw/dwarf_begin_elf.c create mode 100644 libdw/dwarf_bitoffset.c create mode 100644 libdw/dwarf_bitsize.c create mode 100644 libdw/dwarf_bytesize.c create mode 100644 libdw/dwarf_child.c create mode 100644 libdw/dwarf_cuoffset.c create mode 100644 libdw/dwarf_diename.c create mode 100644 libdw/dwarf_dieoffset.c create mode 100644 libdw/dwarf_end.c create mode 100644 libdw/dwarf_error.c create mode 100644 libdw/dwarf_filesrc.c create mode 100644 libdw/dwarf_formaddr.c create mode 100644 libdw/dwarf_formblock.c create mode 100644 libdw/dwarf_formflag.c create mode 100644 libdw/dwarf_formref.c create mode 100644 libdw/dwarf_formref_die.c create mode 100644 libdw/dwarf_formsdata.c create mode 100644 libdw/dwarf_formstring.c create mode 100644 libdw/dwarf_formudata.c create mode 100644 libdw/dwarf_func_col.c create mode 100644 libdw/dwarf_func_entrypc.c create mode 100644 libdw/dwarf_func_file.c create mode 100644 libdw/dwarf_func_highpc.c create mode 100644 libdw/dwarf_func_line.c create mode 100644 libdw/dwarf_func_lowpc.c create mode 100644 libdw/dwarf_func_name.c create mode 100644 libdw/dwarf_getabbrev.c create mode 100644 libdw/dwarf_getabbrevattr.c create mode 100644 libdw/dwarf_getabbrevcode.c create mode 100644 libdw/dwarf_getabbrevtag.c create mode 100644 libdw/dwarf_getarange_addr.c create mode 100644 libdw/dwarf_getarangeinfo.c create mode 100644 libdw/dwarf_getaranges.c create mode 100644 libdw/dwarf_getattrcnt.c create mode 100644 libdw/dwarf_getattrs.c create mode 100644 libdw/dwarf_getelf.c create mode 100644 libdw/dwarf_getfuncs.c create mode 100644 libdw/dwarf_getloclist.c create mode 100644 libdw/dwarf_getmacros.c create mode 100644 libdw/dwarf_getpubnames.c create mode 100644 libdw/dwarf_getscopes.c create mode 100644 libdw/dwarf_getscopevar.c create mode 100644 libdw/dwarf_getsrc_die.c create mode 100644 libdw/dwarf_getsrc_file.c create mode 100644 libdw/dwarf_getsrcfiles.c create mode 100644 libdw/dwarf_getsrclines.c create mode 100644 libdw/dwarf_getstring.c create mode 100644 libdw/dwarf_hasattr.c create mode 100644 libdw/dwarf_hasattr_integrate.c create mode 100644 libdw/dwarf_haschildren.c create mode 100644 libdw/dwarf_hasform.c create mode 100644 libdw/dwarf_haspc.c create mode 100644 libdw/dwarf_highpc.c create mode 100644 libdw/dwarf_lineaddr.c create mode 100644 libdw/dwarf_linebeginstatement.c create mode 100644 libdw/dwarf_lineblock.c create mode 100644 libdw/dwarf_linecol.c create mode 100644 libdw/dwarf_lineendsequence.c create mode 100644 libdw/dwarf_lineepiloguebegin.c create mode 100644 libdw/dwarf_lineno.c create mode 100644 libdw/dwarf_lineprologueend.c create mode 100644 libdw/dwarf_linesrc.c create mode 100644 libdw/dwarf_lowpc.c create mode 100644 libdw/dwarf_macro_opcode.c create mode 100644 libdw/dwarf_macro_param1.c create mode 100644 libdw/dwarf_macro_param2.c create mode 100644 libdw/dwarf_nextcu.c create mode 100644 libdw/dwarf_offabbrev.c create mode 100644 libdw/dwarf_offdie.c create mode 100644 libdw/dwarf_onearange.c create mode 100644 libdw/dwarf_onesrcline.c create mode 100644 libdw/dwarf_siblingof.c create mode 100644 libdw/dwarf_srclang.c create mode 100644 libdw/dwarf_tag.c create mode 100644 libdw/dwarf_whatattr.c create mode 100644 libdw/dwarf_whatform.c create mode 100644 libdw/libdw.h create mode 100644 libdw/libdw.map create mode 100644 libdw/libdwP.h create mode 100644 libdw/libdw_alloc.c create mode 100644 libdw/libdw_findcu.c create mode 100644 libdw/libdw_form.c create mode 100644 libdw/memory-access.c create mode 100644 libdw/memory-access.h create mode 100644 libdwarf/.cvsignore create mode 100644 libdwarf/AVAILABLE create mode 100644 libdwarf/ChangeLog create mode 100644 libdwarf/Makefile.am create mode 100644 libdwarf/dwarf.h create mode 100644 libdwarf/dwarf_abbrev_hash.c create mode 100644 libdwarf/dwarf_abbrev_hash.h create mode 100644 libdwarf/dwarf_arrayorder.c create mode 100644 libdwarf/dwarf_attr.c create mode 100644 libdwarf/dwarf_attrlist.c create mode 100644 libdwarf/dwarf_bitoffset.c create mode 100644 libdwarf/dwarf_bitsize.c create mode 100644 libdwarf/dwarf_bytesize.c create mode 100644 libdwarf/dwarf_child.c create mode 100644 libdwarf/dwarf_dealloc.c create mode 100644 libdwarf/dwarf_die_CU_offset.c create mode 100644 libdwarf/dwarf_diename.c create mode 100644 libdwarf/dwarf_dieoffset.c create mode 100644 libdwarf/dwarf_elf_init.c create mode 100644 libdwarf/dwarf_errmsg.c create mode 100644 libdwarf/dwarf_errno.c create mode 100644 libdwarf/dwarf_error.c create mode 100644 libdwarf/dwarf_find_macro_value_start.c create mode 100644 libdwarf/dwarf_finish.c create mode 100644 libdwarf/dwarf_form.c create mode 100644 libdwarf/dwarf_formaddr.c create mode 100644 libdwarf/dwarf_formblock.c create mode 100644 libdwarf/dwarf_formflag.c create mode 100644 libdwarf/dwarf_formref.c create mode 100644 libdwarf/dwarf_formsdata.c create mode 100644 libdwarf/dwarf_formstring.c create mode 100644 libdwarf/dwarf_formudata.c create mode 100644 libdwarf/dwarf_get_abbrev.c create mode 100644 libdwarf/dwarf_get_abbrev_children_flag.c create mode 100644 libdwarf/dwarf_get_abbrev_code.c create mode 100644 libdwarf/dwarf_get_abbrev_entry.c create mode 100644 libdwarf/dwarf_get_abbrev_tag.c create mode 100644 libdwarf/dwarf_get_address_size.c create mode 100644 libdwarf/dwarf_get_arange.c create mode 100644 libdwarf/dwarf_get_arange_info.c create mode 100644 libdwarf/dwarf_get_aranges.c create mode 100644 libdwarf/dwarf_get_cie_info.c create mode 100644 libdwarf/dwarf_get_cie_of_fde.c create mode 100644 libdwarf/dwarf_get_cu_die_offset.c create mode 100644 libdwarf/dwarf_get_elf.c create mode 100644 libdwarf/dwarf_get_fde_at_pc.c create mode 100644 libdwarf/dwarf_get_fde_instr_bytes.c create mode 100644 libdwarf/dwarf_get_fde_list_eh.c create mode 100644 libdwarf/dwarf_get_fde_n.c create mode 100644 libdwarf/dwarf_get_fde_range.c create mode 100644 libdwarf/dwarf_get_globals.c create mode 100644 libdwarf/dwarf_get_loclist_entry.c create mode 100644 libdwarf/dwarf_get_str.c create mode 100644 libdwarf/dwarf_getabbrev.c create mode 100644 libdwarf/dwarf_getconstant.c create mode 100644 libdwarf/dwarf_global_cu_offset.c create mode 100644 libdwarf/dwarf_global_die_offset.c create mode 100644 libdwarf/dwarf_global_formref.c create mode 100644 libdwarf/dwarf_global_name_offsets.c create mode 100644 libdwarf/dwarf_globname.c create mode 100644 libdwarf/dwarf_hasattr.c create mode 100644 libdwarf/dwarf_hasform.c create mode 100644 libdwarf/dwarf_highpc.c create mode 100644 libdwarf/dwarf_init.c create mode 100644 libdwarf/dwarf_lineaddr.c create mode 100644 libdwarf/dwarf_linebeginstatement.c create mode 100644 libdwarf/dwarf_lineblock.c create mode 100644 libdwarf/dwarf_lineendsequence.c create mode 100644 libdwarf/dwarf_lineepiloguebegin.c create mode 100644 libdwarf/dwarf_lineno.c create mode 100644 libdwarf/dwarf_lineoff.c create mode 100644 libdwarf/dwarf_lineprologueend.c create mode 100644 libdwarf/dwarf_linesrc.c create mode 100644 libdwarf/dwarf_loclist.c create mode 100644 libdwarf/dwarf_lowpc.c create mode 100644 libdwarf/dwarf_next_cu_header.c create mode 100644 libdwarf/dwarf_offdie.c create mode 100644 libdwarf/dwarf_seterrarg.c create mode 100644 libdwarf/dwarf_seterrhand.c create mode 100644 libdwarf/dwarf_siblingof.c create mode 100644 libdwarf/dwarf_srcfiles.c create mode 100644 libdwarf/dwarf_srclang.c create mode 100644 libdwarf/dwarf_srclines.c create mode 100644 libdwarf/dwarf_tag.c create mode 100644 libdwarf/dwarf_whatattr.c create mode 100644 libdwarf/dwarf_whatform.c create mode 100644 libdwarf/libdwarf.h create mode 100644 libdwarf/libdwarf.map create mode 100644 libdwarf/libdwarfP.h create mode 100644 libdwarf/memory-access.h create mode 100644 libdwfl/.cvsignore create mode 100644 libdwfl/ChangeLog create mode 100644 libdwfl/Makefile.am create mode 100644 libdwfl/argp-std.c create mode 100644 libdwfl/cu.c create mode 100644 libdwfl/dwfl_addrdie.c create mode 100644 libdwfl/dwfl_addrdwarf.c create mode 100644 libdwfl/dwfl_addrmodule.c create mode 100644 libdwfl/dwfl_begin.c create mode 100644 libdwfl/dwfl_cumodule.c create mode 100644 libdwfl/dwfl_end.c create mode 100644 libdwfl/dwfl_error.c create mode 100644 libdwfl/dwfl_getdwarf.c create mode 100644 libdwfl/dwfl_getmodules.c create mode 100644 libdwfl/dwfl_getsrc.c create mode 100644 libdwfl/dwfl_lineinfo.c create mode 100644 libdwfl/dwfl_linemodule.c create mode 100644 libdwfl/dwfl_module.c create mode 100644 libdwfl/dwfl_module_addrdie.c create mode 100644 libdwfl/dwfl_module_getdwarf.c create mode 100644 libdwfl/dwfl_module_getsrc.c create mode 100644 libdwfl/dwfl_module_getsrc_file.c create mode 100644 libdwfl/dwfl_module_info.c create mode 100644 libdwfl/dwfl_module_nextcu.c create mode 100644 libdwfl/dwfl_nextcu.c create mode 100644 libdwfl/dwfl_report_elf.c create mode 100644 libdwfl/elf-from-memory.c create mode 100644 libdwfl/find-debuginfo.c create mode 100644 libdwfl/libdwfl.h create mode 100644 libdwfl/libdwfl.map create mode 100644 libdwfl/libdwflP.h create mode 100644 libdwfl/lines.c create mode 100644 libdwfl/linux-kernel-modules.c create mode 100644 libdwfl/linux-proc-maps.c create mode 100644 libdwfl/loc2c-runtime.h create mode 100644 libdwfl/loc2c.c create mode 100644 libdwfl/loc2c.h create mode 100644 libdwfl/ptest.c create mode 100644 libdwfl/relocate.c create mode 100644 libdwfl/test2.c create mode 100644 libebl/.cvsignore create mode 100644 libebl/ChangeLog create mode 100644 libebl/Makefile.am create mode 100644 libebl/alpha_destr.c create mode 100644 libebl/alpha_init.c create mode 100644 libebl/alpha_symbol.c create mode 100644 libebl/arm_destr.c create mode 100644 libebl/arm_init.c create mode 100644 libebl/arm_symbol.c create mode 100644 libebl/eblbackendname.c create mode 100644 libebl/eblclosebackend.c create mode 100644 libebl/eblcopyrelocp.c create mode 100644 libebl/eblcorenote.c create mode 100644 libebl/eblcorenotetypename.c create mode 100644 libebl/ebldebugscnp.c create mode 100644 libebl/ebldynamictagcheck.c create mode 100644 libebl/ebldynamictagname.c create mode 100644 libebl/eblgotpcreloccheck.c create mode 100644 libebl/eblgstrtab.c create mode 100644 libebl/eblmachineflagcheck.c create mode 100644 libebl/eblmachineflagname.c create mode 100644 libebl/eblobjecttypename.c create mode 100644 libebl/eblobjnote.c create mode 100644 libebl/eblobjnotetypename.c create mode 100644 libebl/eblopenbackend.c create mode 100644 libebl/eblosabiname.c create mode 100644 libebl/eblrelocsimpletype.c create mode 100644 libebl/eblreloctypecheck.c create mode 100644 libebl/eblreloctypename.c create mode 100644 libebl/eblrelocvaliduse.c create mode 100644 libebl/eblsectionname.c create mode 100644 libebl/eblsectionstripp.c create mode 100644 libebl/eblsectiontypename.c create mode 100644 libebl/eblsegmenttypename.c create mode 100644 libebl/eblshflagscombine.c create mode 100644 libebl/eblstrtab.c create mode 100644 libebl/eblsymbolbindingname.c create mode 100644 libebl/eblsymboltypename.c create mode 100644 libebl/eblwstrtab.c create mode 100644 libebl/i386_corenote.c create mode 100644 libebl/i386_destr.c create mode 100644 libebl/i386_init.c create mode 100644 libebl/i386_symbol.c create mode 100644 libebl/ia64_destr.c create mode 100644 libebl/ia64_init.c create mode 100644 libebl/ia64_symbol.c create mode 100644 libebl/libebl.h create mode 100644 libebl/libeblP.h create mode 100644 libebl/libebl_alpha.h create mode 100644 libebl/libebl_alpha.map create mode 100644 libebl/libebl_arm.h create mode 100644 libebl/libebl_arm.map create mode 100644 libebl/libebl_i386.h create mode 100644 libebl/libebl_i386.map create mode 100644 libebl/libebl_ia64.h create mode 100644 libebl/libebl_ia64.map create mode 100644 libebl/libebl_ppc.h create mode 100644 libebl/libebl_ppc.map create mode 100644 libebl/libebl_ppc64.h create mode 100644 libebl/libebl_ppc64.map create mode 100644 libebl/libebl_sh.h create mode 100644 libebl/libebl_sh.map create mode 100644 libebl/libebl_sparc.h create mode 100644 libebl/libebl_sparc.map create mode 100644 libebl/libebl_x86_64.h create mode 100644 libebl/libebl_x86_64.map create mode 100644 libebl/ppc64_destr.c create mode 100644 libebl/ppc64_init.c create mode 100644 libebl/ppc64_symbol.c create mode 100644 libebl/ppc_destr.c create mode 100644 libebl/ppc_init.c create mode 100644 libebl/ppc_symbol.c create mode 100644 libebl/sh_destr.c create mode 100644 libebl/sh_init.c create mode 100644 libebl/sh_symbol.c create mode 100644 libebl/sparc_destr.c create mode 100644 libebl/sparc_init.c create mode 100644 libebl/sparc_symbol.c create mode 100644 libebl/x86_64_corenote.c create mode 100644 libebl/x86_64_destr.c create mode 100644 libebl/x86_64_init.c create mode 100644 libebl/x86_64_symbol.c create mode 100644 libelf-po/.cvsignore create mode 100644 libelf-po/ChangeLog create mode 100644 libelf-po/Makefile.in.in create mode 100644 libelf-po/Makevars create mode 100644 libelf-po/POTFILES.in create mode 100644 libelf-po/Rules-quot create mode 100644 libelf-po/boldquot.sed create mode 100644 libelf-po/en@boldquot.header create mode 100644 libelf-po/en@quot.header create mode 100644 libelf-po/insert-header.sin create mode 100644 libelf-po/quot.sed create mode 100644 libelf/.cvsignore create mode 100644 libelf/ChangeLog create mode 100644 libelf/Makefile.am create mode 100644 libelf/abstract.h create mode 100644 libelf/common.h create mode 100644 libelf/dl-hash.h create mode 100644 libelf/elf-knowledge.h create mode 100644 libelf/elf.h create mode 100644 libelf/elf32_checksum.c create mode 100644 libelf/elf32_fsize.c create mode 100644 libelf/elf32_getehdr.c create mode 100644 libelf/elf32_getphdr.c create mode 100644 libelf/elf32_getshdr.c create mode 100644 libelf/elf32_newehdr.c create mode 100644 libelf/elf32_newphdr.c create mode 100644 libelf/elf32_updatefile.c create mode 100644 libelf/elf32_updatenull.c create mode 100644 libelf/elf32_xlatetof.c create mode 100644 libelf/elf32_xlatetom.c create mode 100644 libelf/elf64_checksum.c create mode 100644 libelf/elf64_fsize.c create mode 100644 libelf/elf64_getehdr.c create mode 100644 libelf/elf64_getphdr.c create mode 100644 libelf/elf64_getshdr.c create mode 100644 libelf/elf64_newehdr.c create mode 100644 libelf/elf64_newphdr.c create mode 100644 libelf/elf64_updatefile.c create mode 100644 libelf/elf64_updatenull.c create mode 100644 libelf/elf64_xlatetof.c create mode 100644 libelf/elf64_xlatetom.c create mode 100644 libelf/elf_begin.c create mode 100644 libelf/elf_clone.c create mode 100644 libelf/elf_cntl.c create mode 100644 libelf/elf_end.c create mode 100644 libelf/elf_error.c create mode 100644 libelf/elf_fill.c create mode 100644 libelf/elf_flagdata.c create mode 100644 libelf/elf_flagehdr.c create mode 100644 libelf/elf_flagelf.c create mode 100644 libelf/elf_flagphdr.c create mode 100644 libelf/elf_flagscn.c create mode 100644 libelf/elf_flagshdr.c create mode 100644 libelf/elf_getarhdr.c create mode 100644 libelf/elf_getarsym.c create mode 100644 libelf/elf_getbase.c create mode 100644 libelf/elf_getdata.c create mode 100644 libelf/elf_getident.c create mode 100644 libelf/elf_getscn.c create mode 100644 libelf/elf_getshnum.c create mode 100644 libelf/elf_getshstrndx.c create mode 100644 libelf/elf_hash.c create mode 100644 libelf/elf_kind.c create mode 100644 libelf/elf_memory.c create mode 100644 libelf/elf_ndxscn.c create mode 100644 libelf/elf_newdata.c create mode 100644 libelf/elf_newscn.c create mode 100644 libelf/elf_next.c create mode 100644 libelf/elf_nextscn.c create mode 100644 libelf/elf_rand.c create mode 100644 libelf/elf_rawdata.c create mode 100644 libelf/elf_rawfile.c create mode 100644 libelf/elf_readall.c create mode 100644 libelf/elf_strptr.c create mode 100644 libelf/elf_update.c create mode 100644 libelf/elf_version.c create mode 100644 libelf/exttypes.h create mode 100644 libelf/gelf.h create mode 100644 libelf/gelf_checksum.c create mode 100644 libelf/gelf_freechunk.c create mode 100644 libelf/gelf_fsize.c create mode 100644 libelf/gelf_getclass.c create mode 100644 libelf/gelf_getdyn.c create mode 100644 libelf/gelf_getehdr.c create mode 100644 libelf/gelf_getlib.c create mode 100644 libelf/gelf_getmove.c create mode 100644 libelf/gelf_getphdr.c create mode 100644 libelf/gelf_getrel.c create mode 100644 libelf/gelf_getrela.c create mode 100644 libelf/gelf_getshdr.c create mode 100644 libelf/gelf_getsym.c create mode 100644 libelf/gelf_getsyminfo.c create mode 100644 libelf/gelf_getsymshndx.c create mode 100644 libelf/gelf_getverdaux.c create mode 100644 libelf/gelf_getverdef.c create mode 100644 libelf/gelf_getvernaux.c create mode 100644 libelf/gelf_getverneed.c create mode 100644 libelf/gelf_getversym.c create mode 100644 libelf/gelf_newehdr.c create mode 100644 libelf/gelf_newphdr.c create mode 100644 libelf/gelf_rawchunk.c create mode 100644 libelf/gelf_update_dyn.c create mode 100644 libelf/gelf_update_ehdr.c create mode 100644 libelf/gelf_update_lib.c create mode 100644 libelf/gelf_update_move.c create mode 100644 libelf/gelf_update_phdr.c create mode 100644 libelf/gelf_update_rel.c create mode 100644 libelf/gelf_update_rela.c create mode 100644 libelf/gelf_update_shdr.c create mode 100644 libelf/gelf_update_sym.c create mode 100644 libelf/gelf_update_syminfo.c create mode 100644 libelf/gelf_update_symshndx.c create mode 100644 libelf/gelf_update_verdaux.c create mode 100644 libelf/gelf_update_verdef.c create mode 100644 libelf/gelf_update_vernaux.c create mode 100644 libelf/gelf_update_verneed.c create mode 100644 libelf/gelf_update_versym.c create mode 100644 libelf/gelf_xlate.c create mode 100644 libelf/gelf_xlate.h create mode 100644 libelf/gelf_xlatetof.c create mode 100644 libelf/gelf_xlatetom.c create mode 100644 libelf/libelf.h create mode 100644 libelf/libelf.map create mode 100644 libelf/libelfP.h create mode 100644 libelf/libelf_crc32.c create mode 100644 libelf/libelf_next_prime.c create mode 100644 libelf/nlist.c create mode 100644 libelf/nlist.h create mode 100644 libelf/version_xlate.h create mode 100644 m4/.cvsignore create mode 100644 m4/ChangeLog create mode 100644 m4/Makefile.am create mode 100644 m4/codeset.m4 create mode 100644 m4/gettext.m4 create mode 100644 m4/iconv.m4 create mode 100644 m4/lcmessage.m4 create mode 100644 m4/progtest.m4 create mode 100644 po/.cvsignore create mode 100644 po/ChangeLog create mode 100644 po/Makefile.in.in create mode 100644 po/Makevars create mode 100644 po/POTFILES.in create mode 100644 po/Rules-quot create mode 100644 po/boldquot.sed create mode 100644 po/en@boldquot.header create mode 100644 po/en@quot.header create mode 100644 po/insert-header.sin create mode 100644 po/quot.sed create mode 100644 src/.cvsignore create mode 100644 src/ChangeLog create mode 100644 src/Makefile.am create mode 100644 src/addr2line.c create mode 100644 src/elf32-i386.script create mode 100644 src/elfcmp.c create mode 100644 src/elflint.c create mode 100644 src/findtextrel.c create mode 100644 src/i386_ld.c create mode 100644 src/ld.c create mode 100644 src/ld.h create mode 100644 src/ldgeneric.c create mode 100644 src/ldlex.l create mode 100644 src/ldscript.y create mode 100644 src/libld_elf_i386.map create mode 100644 src/nm.c create mode 100644 src/none_ld.c create mode 100644 src/readelf.c create mode 100644 src/sectionhash.c create mode 100644 src/sectionhash.h create mode 100644 src/size.c create mode 100644 src/strip.c create mode 100644 src/symbolhash.c create mode 100644 src/symbolhash.h create mode 100644 src/unaligned.h create mode 100644 src/versionhash.c create mode 100644 src/versionhash.h create mode 100644 src/xelf.h create mode 100644 src/ylwrap create mode 100644 tests/.cvsignore create mode 100644 tests/ChangeLog create mode 100644 tests/Makefile.am create mode 100644 tests/allfcts.c create mode 100644 tests/arextract.c create mode 100644 tests/arsymtest.c create mode 100644 tests/asm-tst1.c create mode 100644 tests/asm-tst2.c create mode 100644 tests/asm-tst3.c create mode 100644 tests/asm-tst4.c create mode 100644 tests/asm-tst5.c create mode 100644 tests/asm-tst6.c create mode 100644 tests/asm-tst7.c create mode 100644 tests/asm-tst8.c create mode 100644 tests/asm-tst9.c create mode 100644 tests/ecp.c create mode 100644 tests/get-aranges.c create mode 100644 tests/get-files.c create mode 100644 tests/get-lines.c create mode 100644 tests/get-pubnames.c create mode 100644 tests/hash.c create mode 100644 tests/line2addr.c create mode 100644 tests/msg_tst.c create mode 100644 tests/newfile.c create mode 100644 tests/newscn.c create mode 100644 tests/run-allfcts.sh create mode 100644 tests/run-arextract.sh create mode 100644 tests/run-arsymtest.sh create mode 100644 tests/run-ecp-test.sh create mode 100644 tests/run-ecp-test2.sh create mode 100644 tests/run-elflint-test.sh create mode 100644 tests/run-get-aranges.sh create mode 100644 tests/run-get-files.sh create mode 100644 tests/run-get-lines.sh create mode 100644 tests/run-get-pubnames.sh create mode 100644 tests/run-line2addr.sh create mode 100644 tests/run-show-abbrev.sh create mode 100644 tests/run-show-ciefde.sh create mode 100644 tests/run-show-die-info.sh create mode 100644 tests/run-strip-test.sh create mode 100644 tests/run-strip-test2.sh create mode 100644 tests/run-strip-test3.sh create mode 100644 tests/run-strip-test4.sh create mode 100644 tests/run-strip-test5.sh create mode 100644 tests/run-strip-test6.sh create mode 100644 tests/saridx.c create mode 100644 tests/scnnames.c create mode 100644 tests/sectiondump.c create mode 100644 tests/show-abbrev.c create mode 100644 tests/show-ciefde.c create mode 100644 tests/show-die-info.c create mode 100644 tests/showptable.c create mode 100644 tests/test-nlist.c create mode 100644 tests/testfile.bz2 create mode 100644 tests/testfile10.bz2 create mode 100644 tests/testfile11.bz2 create mode 100644 tests/testfile12.bz2 create mode 100644 tests/testfile13.bz2 create mode 100644 tests/testfile14.bz2 create mode 100644 tests/testfile15.bz2 create mode 100644 tests/testfile15.debug.bz2 create mode 100644 tests/testfile16.bz2 create mode 100644 tests/testfile16.debug.bz2 create mode 100644 tests/testfile17.bz2 create mode 100644 tests/testfile17.debug.bz2 create mode 100644 tests/testfile18.bz2 create mode 100644 tests/testfile2.bz2 create mode 100644 tests/testfile3.bz2 create mode 100644 tests/testfile4.bz2 create mode 100644 tests/testfile5.bz2 create mode 100644 tests/testfile6.bz2 create mode 100644 tests/testfile7.bz2 create mode 100644 tests/testfile8.bz2 create mode 100644 tests/testfile9.bz2 create mode 100644 tests/update1.c create mode 100644 tests/update2.c create mode 100644 tests/update3.c create mode 100644 tests/update4.c diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 00000000..433ac27e --- /dev/null +++ b/.cvsignore @@ -0,0 +1,7 @@ +Makefile.in +aclocal.m4 +autom4te.cache +config.h.in +configure +elfutils.spec +osl2.0 diff --git a/ABOUT-NLS b/ABOUT-NLS new file mode 100644 index 00000000..7e121c5b --- /dev/null +++ b/ABOUT-NLS @@ -0,0 +1,588 @@ +Notes on the Free Translation Project +************************************* + + Free software is going international! The Free Translation Project +is a way to get maintainers of free software, translators, and users all +together, so that will gradually become able to speak many languages. +A few packages already provide translations for their messages. + + If you found this `ABOUT-NLS' file inside a distribution, you may +assume that the distributed package does use GNU `gettext' internally, +itself available at your nearest GNU archive site. But you do _not_ +need to install GNU `gettext' prior to configuring, installing or using +this package with messages translated. + + Installers will find here some useful hints. These notes also +explain how users should proceed for getting the programs to use the +available translations. They tell how people wanting to contribute and +work at translations should contact the appropriate team. + + When reporting bugs in the `intl/' directory or bugs which may be +related to internationalization, you should tell about the version of +`gettext' which is used. The information can be found in the +`intl/VERSION' file, in internationalized packages. + +INSTALL Matters +=============== + + Some packages are "localizable" when properly installed; the +programs they contain can be made to speak your own native language. +Most such packages use GNU `gettext'. Other packages have their own +ways to internationalization, predating GNU `gettext'. + + By default, this package will be installed to allow translation of +messages. It will automatically detect whether the system already +provides the GNU `gettext' functions. If not, the GNU `gettext' own +library will be used. This library is wholly contained within this +package, usually in the `intl/' subdirectory, so prior installation of +the GNU `gettext' package is _not_ required. Installers may use +special options at configuration time for changing the default +behaviour. The command: + + ./configure --disable-nls + +will bypass any pre-existing `gettext' to _totally_ disable translation +of messages. + + The configuration process will not test for the `catgets' function +and therefore it will not be used. The reason is that even an +emulation of `gettext' on top of `catgets' could not provide all the +extensions of the GNU `gettext' library. + + Internationalized packages have usually many `po/LL.po' files, where +LL gives an ISO 639 two-letter code identifying the language. Unless +translations have been forbidden at `configure' time by using the +`--disable-nls' switch, all available translations are installed +together with the package. However, the environment variable `LINGUAS' +may be set, prior to configuration, to limit the installed set. +`LINGUAS' should then contain a space separated list of two-letter +codes, stating which languages are allowed. + +Using This Package +================== + + As a user, if your language has been installed for this package, you +only have to set the `LANG' environment variable to the appropriate +`LL_CC' combination. Here `LL' is an ISO 639 two-letter language code, +and `CC' is an ISO 3166 two-letter country code. For example, let's +suppose that you speak German and live in Germany. At the shell +prompt, merely execute `setenv LANG de_DE' (in `csh'), +`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash'). +This can be done from your `.login' or `.profile' file, once and for +all. + + You might think that the country code specification is redundant. +But in fact, some languages have dialects in different countries. For +example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The +country code serves to distinguish the dialects. + + The locale naming convention of `LL_CC', with `LL' denoting the +language and `CC' denoting the country, is the one use on systems based +on GNU libc. On other systems, some variations of this scheme are +used, such as `LL' or `LL_CC.ENCODING'. You can get the list of +locales supported by your system for your country by running the command +`locale -a | grep '^LL''. + + Not all programs have translations for all languages. By default, an +English message is shown in place of a nonexistent translation. If you +understand other languages, you can set up a priority list of languages. +This is done through a different environment variable, called +`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG' +for the purpose of message handling, but you still need to have `LANG' +set to the primary language; this is required by other parts of the +system libraries. For example, some Swedish users who would rather +read translations in German than English for when Swedish is not +available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'. + + In the `LANGUAGE' environment variable, but not in the `LANG' +environment variable, `LL_CC' combinations can be abbreviated as `LL' +to denote the language's main dialect. For example, `de' is equivalent +to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT' +(Portuguese as spoken in Portugal) in this context. + +Translating Teams +================= + + For the Free Translation Project to be a success, we need interested +people who like their own language and write it well, and who are also +able to synergize with other translators speaking the same language. +Each translation team has its own mailing list. The up-to-date list of +teams can be found at the Free Translation Project's homepage, +`http://www.iro.umontreal.ca/contrib/po/HTML/', in the "National teams" +area. + + If you'd like to volunteer to _work_ at translating messages, you +should become a member of the translating team for your own language. +The subscribing address is _not_ the same as the list itself, it has +`-request' appended. For example, speakers of Swedish can send a +message to `sv-request@li.org', having this message body: + + subscribe + + Keep in mind that team members are expected to participate +_actively_ in translations, or at solving translational difficulties, +rather than merely lurking around. If your team does not exist yet and +you want to start one, or if you are unsure about what to do or how to +get started, please write to `translation@iro.umontreal.ca' to reach the +coordinator for all translator teams. + + The English team is special. It works at improving and uniformizing +the terminology in use. Proven linguistic skill are praised more than +programming skill, here. + +Available Packages +================== + + Languages are not equally supported in all packages. The following +matrix shows the current state of internationalization, as of May 2003. +The matrix shows, in regard of each package, for which languages PO +files have been submitted to translation coordination, with a +translation percentage of at least 50%. + + Ready PO files am az be bg ca cs da de el en en_GB eo es + +-------------------------------------------+ + a2ps | [] [] [] [] | + aegis | () | + anubis | | + ap-utils | | + bash | [] [] [] | + batchelor | | + bfd | [] [] | + binutils | [] [] | + bison | [] [] [] | + bluez-pin | [] [] | + clisp | | + clisp | [] [] [] | + coreutils | [] [] [] [] | + cpio | [] [] [] | + darkstat | () [] | + diffutils | [] [] [] [] [] [] [] | + e2fsprogs | [] [] | + enscript | [] [] [] [] | + error | [] [] [] [] [] | + fetchmail | [] () [] [] [] [] | + fileutils | [] [] [] | + findutils | [] [] [] [] [] [] | + flex | [] [] [] [] | + gas | [] | + gawk | [] [] [] [] | + gcal | [] | + gcc | [] [] | + gettext | [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] | + gettext-tools | [] [] | + gimp-print | [] [] [] [] [] | + gliv | | + glunarclock | [] [] [] | + gnucash | () [] | + gnucash-glossary | [] () [] | + gnupg | [] () [] [] [] [] | + gpe-calendar | [] | + gpe-conf | [] | + gpe-contacts | [] | + gpe-edit | | + gpe-login | [] | + gpe-ownerinfo | [] | + gpe-sketchbook | [] | + gpe-timesheet | | + gpe-today | [] | + gpe-todo | [] | + gphoto2 | [] [] [] [] | + gprof | [] [] | + gpsdrive | () () () | + grep | [] [] [] [] [] | + gretl | [] | + hello | [] [] [] [] [] [] | + id-utils | [] [] | + indent | [] [] [] [] | + jpilot | [] [] [] [] | + jwhois | [] | + kbd | [] [] [] [] [] | + ld | [] [] | + libc | [] [] [] [] [] [] | + libgpewidget | [] | + libiconv | [] [] [] [] [] | + lifelines | [] () | + lilypond | [] | + lingoteach | | + lingoteach_lessons | () () | + lynx | [] [] [] [] | + m4 | [] [] [] [] | + mailutils | [] [] | + make | [] [] [] | + man-db | [] () [] [] () | + mysecretdiary | [] [] [] | + nano | [] () [] [] [] | + nano_1_0 | [] () [] [] [] | + opcodes | [] [] | + parted | [] [] [] [] [] | + ptx | [] [] [] [] [] | + python | | + radius | | + recode | [] [] [] [] [] [] | + screem | | + sed | [] [] [] [] [] | + sh-utils | [] [] [] | + sharutils | [] [] [] [] [] [] | + sketch | [] () [] | + soundtracker | [] [] [] | + sp | [] | + tar | [] [] [] [] | + texinfo | [] [] [] [] | + textutils | [] [] [] [] | + tin | () () | + util-linux | [] [] [] [] [] | + vorbis-tools | [] [] [] | + wastesedge | () | + wdiff | [] [] [] [] | + wget | [] [] [] [] [] [] [] | + xchat | [] [] [] | + xpad | | + +-------------------------------------------+ + am az be bg ca cs da de el en en_GB eo es + 0 1 4 2 31 17 54 60 14 1 4 12 56 + + et fa fi fr ga gl he hr hu id it ja ko + +----------------------------------------+ + a2ps | [] [] [] () () | + aegis | | + anubis | [] | + ap-utils | [] | + bash | [] [] | + batchelor | [] | + bfd | [] [] | + binutils | [] [] | + bison | [] [] [] [] | + bluez-pin | [] [] [] [] | + clisp | | + clisp | [] | + coreutils | [] [] [] [] | + cpio | [] [] [] [] | + darkstat | () [] [] [] | + diffutils | [] [] [] [] [] [] [] | + e2fsprogs | | + enscript | [] [] | + error | [] [] [] [] | + fetchmail | [] | + fileutils | [] [] [] [] [] | + findutils | [] [] [] [] [] [] [] [] [] [] [] | + flex | [] [] | + gas | [] | + gawk | [] [] | + gcal | [] | + gcc | [] | + gettext | [] [] [] | + gettext-runtime | [] [] [] [] | + gettext-tools | [] | + gimp-print | [] [] | + gliv | () | + glunarclock | [] [] [] [] | + gnucash | [] | + gnucash-glossary | [] | + gnupg | [] [] [] [] [] [] [] | + gpe-calendar | [] | + gpe-conf | | + gpe-contacts | [] | + gpe-edit | [] [] | + gpe-login | [] | + gpe-ownerinfo | [] [] [] | + gpe-sketchbook | [] | + gpe-timesheet | [] [] [] | + gpe-today | [] [] | + gpe-todo | [] [] | + gphoto2 | [] [] [] | + gprof | [] [] | + gpsdrive | () [] () () | + grep | [] [] [] [] [] [] [] [] [] [] [] | + gretl | [] | + hello | [] [] [] [] [] [] [] [] [] [] [] [] [] | + id-utils | [] [] [] | + indent | [] [] [] [] [] [] [] [] | + jpilot | [] () | + jwhois | [] [] [] [] | + kbd | [] | + ld | [] | + libc | [] [] [] [] [] [] | + libgpewidget | [] [] [] | + libiconv | [] [] [] [] [] [] [] [] | + lifelines | () | + lilypond | [] | + lingoteach | [] [] | + lingoteach_lessons | | + lynx | [] [] [] [] | + m4 | [] [] [] [] | + mailutils | | + make | [] [] [] [] [] [] | + man-db | [] () () | + mysecretdiary | [] [] | + nano | [] [] [] [] | + nano_1_0 | [] [] [] [] | + opcodes | [] [] | + parted | [] [] [] | + ptx | [] [] [] [] [] [] [] | + python | | + radius | | + recode | [] [] [] [] [] [] | + screem | | + sed | [] [] [] [] [] [] [] [] | + sh-utils | [] [] [] [] [] [] | + sharutils | [] [] [] [] [] | + sketch | [] | + soundtracker | [] [] [] | + sp | [] () | + tar | [] [] [] [] [] [] [] [] [] | + texinfo | [] [] [] [] | + textutils | [] [] [] [] [] | + tin | [] () | + util-linux | [] [] [] [] () [] | + vorbis-tools | [] | + wastesedge | () | + wdiff | [] [] [] [] [] | + wget | [] [] [] [] [] [] [] [] | + xchat | [] [] [] | + xpad | | + +----------------------------------------+ + et fa fi fr ga gl he hr hu id it ja ko + 20 1 15 73 14 24 8 10 30 31 19 31 9 + + lg lt lv ms nb nl nn no pl pt pt_BR ro + +----------------------------------------+ + a2ps | [] [] () () () [] [] | + aegis | () | + anubis | [] [] | + ap-utils | () | + bash | [] | + batchelor | | + bfd | | + binutils | | + bison | [] [] [] [] | + bluez-pin | [] | + clisp | | + clisp | [] | + coreutils | [] | + cpio | [] [] [] | + darkstat | [] [] [] [] | + diffutils | [] [] [] | + e2fsprogs | | + enscript | [] [] | + error | [] [] | + fetchmail | () () | + fileutils | [] | + findutils | [] [] [] [] | + flex | [] | + gas | | + gawk | [] | + gcal | | + gcc | | + gettext | [] | + gettext-runtime | [] | + gettext-tools | | + gimp-print | [] | + gliv | [] | + glunarclock | [] | + gnucash | | + gnucash-glossary | [] [] | + gnupg | | + gpe-calendar | [] [] | + gpe-conf | [] [] | + gpe-contacts | [] | + gpe-edit | [] [] | + gpe-login | [] [] | + gpe-ownerinfo | [] [] | + gpe-sketchbook | [] [] | + gpe-timesheet | [] [] | + gpe-today | [] [] | + gpe-todo | [] [] | + gphoto2 | | + gprof | [] | + gpsdrive | () () () | + grep | [] [] [] [] | + gretl | | + hello | [] [] [] [] [] [] [] [] [] | + id-utils | [] [] [] | + indent | [] [] [] | + jpilot | () () | + jwhois | [] [] [] | + kbd | | + ld | | + libc | [] [] [] [] | + libgpewidget | [] [] | + libiconv | [] [] | + lifelines | | + lilypond | [] | + lingoteach | | + lingoteach_lessons | | + lynx | [] [] | + m4 | [] [] [] [] | + mailutils | | + make | [] [] | + man-db | [] | + mysecretdiary | [] | + nano | [] [] [] [] | + nano_1_0 | [] [] [] [] | + opcodes | [] [] [] | + parted | [] [] [] | + ptx | [] [] [] [] [] [] [] | + python | | + radius | | + recode | [] [] [] | + screem | | + sed | [] [] | + sh-utils | [] | + sharutils | [] | + sketch | [] | + soundtracker | | + sp | | + tar | [] [] [] [] [] [] | + texinfo | [] | + textutils | [] | + tin | | + util-linux | [] [] | + vorbis-tools | [] [] | + wastesedge | | + wdiff | [] [] [] [] | + wget | [] [] [] | + xchat | [] [] | + xpad | [] | + +----------------------------------------+ + lg lt lv ms nb nl nn no pl pt pt_BR ro + 0 0 2 11 7 26 3 4 18 15 34 34 + + ru sk sl sr sv ta tr uk vi wa zh_CN zh_TW + +-------------------------------------------+ + a2ps | [] [] [] [] [] | 16 + aegis | () | 0 + anubis | [] [] | 5 + ap-utils | () | 1 + bash | [] | 7 + batchelor | | 1 + bfd | [] [] [] | 7 + binutils | [] [] [] | 7 + bison | [] [] | 13 + bluez-pin | | 7 + clisp | | 0 + clisp | | 5 + coreutils | [] [] [] [] [] | 14 + cpio | [] [] [] | 13 + darkstat | [] () () | 9 + diffutils | [] [] [] [] | 21 + e2fsprogs | [] | 3 + enscript | [] [] [] | 11 + error | [] [] [] | 14 + fetchmail | [] | 7 + fileutils | [] [] [] [] [] [] | 15 + findutils | [] [] [] [] [] [] | 27 + flex | [] [] [] | 10 + gas | [] | 3 + gawk | [] [] | 9 + gcal | [] [] | 4 + gcc | [] | 4 + gettext | [] [] [] [] [] [] | 15 + gettext-runtime | [] [] [] [] [] [] | 16 + gettext-tools | [] [] | 5 + gimp-print | [] [] | 10 + gliv | | 1 + glunarclock | [] [] [] | 11 + gnucash | [] [] | 4 + gnucash-glossary | [] [] [] | 8 + gnupg | [] [] [] [] | 16 + gpe-calendar | [] | 5 + gpe-conf | | 3 + gpe-contacts | [] | 4 + gpe-edit | [] | 5 + gpe-login | [] | 5 + gpe-ownerinfo | [] | 7 + gpe-sketchbook | [] | 5 + gpe-timesheet | [] | 6 + gpe-today | [] | 6 + gpe-todo | [] | 6 + gphoto2 | [] [] | 9 + gprof | [] [] | 7 + gpsdrive | [] [] | 3 + grep | [] [] [] [] | 24 + gretl | | 2 + hello | [] [] [] [] [] | 33 + id-utils | [] [] [] | 11 + indent | [] [] [] [] | 19 + jpilot | [] [] [] [] [] | 10 + jwhois | () () [] [] | 10 + kbd | [] [] | 8 + ld | [] [] | 5 + libc | [] [] [] [] | 20 + libgpewidget | | 6 + libiconv | [] [] [] [] [] [] | 21 + lifelines | [] | 2 + lilypond | [] | 4 + lingoteach | | 2 + lingoteach_lessons | () | 0 + lynx | [] [] [] [] | 14 + m4 | [] [] [] | 15 + mailutils | | 2 + make | [] [] [] [] | 15 + man-db | [] | 6 + mysecretdiary | [] [] | 8 + nano | [] [] [] | 15 + nano_1_0 | [] [] [] | 15 + opcodes | [] [] | 9 + parted | [] [] | 13 + ptx | [] [] [] | 22 + python | | 0 + radius | | 0 + recode | [] [] [] [] | 19 + screem | [] | 1 + sed | [] [] [] [] [] | 20 + sh-utils | [] [] [] | 13 + sharutils | [] [] [] [] | 16 + sketch | [] | 5 + soundtracker | [] | 7 + sp | [] | 3 + tar | [] [] [] [] [] | 24 + texinfo | [] [] [] [] | 13 + textutils | [] [] [] [] [] | 15 + tin | | 1 + util-linux | [] [] | 14 + vorbis-tools | [] | 7 + wastesedge | | 0 + wdiff | [] [] [] [] | 17 + wget | [] [] [] [] [] [] [] | 25 + xchat | [] [] [] | 11 + xpad | | 1 + +-------------------------------------------+ + 50 teams ru sk sl sr sv ta tr uk vi wa zh_CN zh_TW + 97 domains 32 19 16 0 56 0 48 10 1 1 12 23 913 + + Some counters in the preceding matrix are higher than the number of +visible blocks let us expect. This is because a few extra PO files are +used for implementing regional variants of languages, or language +dialects. + + For a PO file in the matrix above to be effective, the package to +which it applies should also have been internationalized and +distributed as such by its maintainer. There might be an observable +lag between the mere existence a PO file and its wide availability in a +distribution. + + If May 2003 seems to be old, you may fetch a more recent copy of +this `ABOUT-NLS' file on most GNU archive sites. The most up-to-date +matrix with full percentage details can be found at +`http://www.iro.umontreal.ca/contrib/po/HTML/matrix.html'. + +Using `gettext' in new packages +=============================== + + If you are writing a freely available program and want to +internationalize it you are welcome to use GNU `gettext' in your +package. Of course you have to respect the GNU Library General Public +License which covers the use of the GNU `gettext' library. This means +in particular that even non-free programs can use `libintl' as a shared +library, whereas only free software can use `libintl' as a static +library or use modified versions of `libintl'. + + Once the sources are changed appropriately and the setup can handle +the use of `gettext' the only thing missing are the translations. The +Free Translation Project is also available for packages which are not +developed inside the GNU project. Therefore the information given above +applies also for every other Free Software Project. Contact +`translation@iro.umontreal.ca' to make the `.pot' files available to +the translation teams. + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..29b776f0 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +For Now: +Ulrich Drepper. diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..ed8461a8 --- /dev/null +++ b/COPYING @@ -0,0 +1,162 @@ + The Open Software License + v. 1.0 + +This Open Software License (the "License") applies to any original +work of authorship (the "Original Work") whose owner (the "Licensor") +has placed the following notice immediately following the copyright +notice for the Original Work: "Licensed under the Open Software +License version 1.0" + +License Terms + +1) Grant of Copyright License. Licensor hereby grants You a +world-wide, royalty-free, non-exclusive, perpetual, non-sublicenseable +license to do the following: + + a) to reproduce the Original Work in copies; + + b) to prepare derivative works ("Derivative Works") based upon the + Original Work; + + c) to distribute copies of the Original Work and Derivative Works + to the public, with the proviso that copies of Original Work or + Derivative Works that You distribute shall be licensed under the + Open Software License; + + d) to perform the Original Work publicly; and + + e) to display the Original Work publicly. + +2) Grant of Patent License. Licensor hereby grants You a world-wide, +royalty-free, non-exclusive, perpetual, non-sublicenseable license, +under patent claims owned or controlled by the Licensor that are +embodied in the Original Work as furnished by the Licensor ("Licensed +Claims") to make, use, sell and offer for sale the Original Work. +Licensor hereby grants You a world-wide, royalty-free, non-exclusive, +perpetual, non-sublicenseable license under the Licensed Claims to +make, use, sell and offer for sale Derivative Works. + +3) Grant of Source Code License. The term "Source Code" means the +preferred form of the Original Work for making modifications to it and +all available documentation describing how to access and modify the +Original Work. Licensor hereby agrees to provide a machine-readable +copy of the Source Code of the Original Work along with each copy of +the Original Work that Licensor distributes. Licensor reserves the +right to satisfy this obligation by placing a machine-readable copy of +the Source Code in an information repository reasonably calculated to +permit inexpensive and convenient access by You for as long as +Licensor continues to distribute the Original Work, and by publishing +the address of that information repository in a notice immediately +following the copyright notice that applies to the Original Work. + +4) Exclusions From License Grant. Nothing in this License shall be +deemed to grant any rights to trademarks, copyrights, patents, trade +secrets or any other intellectual property of Licensor except as +expressly stated herein. No patent license is granted to make, use, +sell or offer to sell embodiments of any patent claims other than the +Licensed Claims defined in Section 2. No right is granted to the +trademarks of Licensor even if such marks are included in the Original +Work. Nothing in this License shall be interpreted to prohibit +Licensor from licensing under different terms from this License any +Original Work that Licensor otherwise would have a right to license. + +5) External Deployment. The term "External Deployment" means the use +or distribution of the Original Work or Derivative Works in any way +such that the Original Work or Derivative Works may be accessed or +used by anyone other than You, whether the Original Work or Derivative +Works are distributed to those persons, made available as an +application intended for use over a computer network, or used to +provide services or otherwise deliver content to anyone other than +You. As an express condition for the grants of license hereunder, You +agree that any External Deployment by You shall be deemed a +distribution and shall be licensed to all under the terms of this +License, as prescribed in section 1(c) herein. + +6) Warranty and Disclaimer of Warranty. LICENSOR WARRANTS THAT THE +COPYRIGHT IN AND TO THE ORIGINAL WORK IS OWNED BY THE LICENSOR OR THAT +THE ORIGINAL WORK IS DISTRIBUTED BY LICENSOR UNDER A VALID CURRENT +LICENSE FROM THE COPYRIGHT OWNER. EXCEPT AS EXPRESSLY STATED IN THE +IMMEDIATELY PRECEEDING SENTENCE, THE ORIGINAL WORK IS PROVIDED UNDER +THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY, EITHER EXPRESS OR +IMPLIED, INCLUDING, WITHOUT LIMITATION, THE WARRANTY OF +NON-INFRINGEMENT AND WARRANTIES THAT THE ORIGINAL WORK IS MERCHANTABLE +OR FIT FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF +THE ORIGINAL WORK IS WITH YOU. THIS DISCLAIMER OF WARRANTY CONSTITUTES +AN ESSENTIAL PART OF THIS LICENSE. NO LICENSE TO ORIGINAL WORK IS +GRANTED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +7) Limitation of Liability. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL +THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, +SHALL THE LICENSOR BE LIABLE TO ANY PERSON FOR ANY DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER ARISING +AS A RESULT OF THIS LICENSE OR THE USE OF THE ORIGINAL WORK INCLUDING, +WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, +COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL +DAMAGES OR LOSSES, EVEN IF SUCH PERSON SHALL HAVE BEEN INFORMED OF THE +POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT +APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH +PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH +LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION +AND LIMITATION MAY NOT APPLY TO YOU. + +8) Acceptance and Termination. Nothing else but this License (or +another written agreement between Licensor and You) grants You +permission to create Derivative Works based upon the Original Work, +and any attempt to do so except under the terms of this License (or +another written agreement between Licensor and You) is expressly +prohibited by U.S. copyright law, the equivalent laws of other +countries, and by international treaty. Therefore, by exercising any +of the rights granted to You in Sections 1 and 2 herein, You indicate +Your acceptance of this License and all of its terms and conditions. +This license shall terminate immediately and you may no longer +exercise any of the rights granted to You by this License upon Your +failure to honor the proviso in Section 1(c) herein. + +9) Mutual Termination for Patent Action. This License shall terminate +automatically and You may no longer exercise any of the rights granted +to You by this License if You file a lawsuit in any court alleging +that any OSI Certified open source software that is licensed under any +license containing this "Mutual Termination for Patent Action" clause +infringes any patent claims that are essential to use that software. + +10) Jurisdiction, Venue and Governing Law. You agree that any lawsuit +arising under or relating to this License shall be maintained in the +courts of the jurisdiction wherein the Licensor resides or in which +Licensor conducts its primary business, and under the laws of that +jurisdiction excluding its conflict-of-law provisions. The application +of the United Nations Convention on Contracts for the International +Sale of Goods is expressly excluded. Any use of the Original Work +outside the scope of this License or after its termination shall be +subject to the requirements and penalties of the U.S. Copyright Act, +17 U.S.C. § 101 et seq., the equivalent laws of other countries, and +international treaty. This section shall survive the termination of +this License. + +11) Attorneys Fees. In any action to enforce the terms of this License +or seeking damages relating thereto, the prevailing party shall be +entitled to recover its costs and expenses, including, without +limitation, reasonable attorneys' fees and costs incurred in +connection with such action, including any appeal of such action. This +section shall survive the termination of this License. + +12) Miscellaneous. This License represents the complete agreement +concerning the subject matter hereof. If any provision of this License +is held to be unenforceable, such provision shall be reformed only to +the extent necessary to make it enforceable. + +13) Definition of "You" in This License. "You" throughout this +License, whether in upper or lower case, means an individual or a +legal entity exercising rights under, and complying with all of the +terms of, this License. For legal entities, "You" includes any entity +that controls, is controlled by, or is under common control with you. +For purposes of this definition, "control" means (i) the power, direct +or indirect, to cause the direction or management of such entity, +whether by contract or otherwise, or (ii) ownership of fifty percent +(50%) or more of the outstanding shares, or (iii) beneficial ownership +of such entity. + +This license is Copyright (C) 2002 Lawrence E. Rosen. All rights +reserved. Permission is hereby granted to copy and distribute this +license without modification. This license may not be modified without +the express written permission of its copyright owner. diff --git a/COPYING.GPL b/COPYING.GPL new file mode 100644 index 00000000..60549be5 --- /dev/null +++ b/COPYING.GPL @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/CREATE-MINI b/CREATE-MINI new file mode 100644 index 00000000..281d4f4a --- /dev/null +++ b/CREATE-MINI @@ -0,0 +1,47 @@ +make dist + +tar jxf elfutils-*.tar.bz2 + +cd elfutils-* + +cp -a $srcdir/fake-src . + +Change SUBDIRS in Makefile.am to only $(mini_SUBDIRS) plus fake-src + Remove COPYING.GPL from EXTRA_DIST + +Remove all AC_CONFIG_FILES lines in configure.ac accept +AC_CONFIG_FILES([config/Makefile]) +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([m4/Makefile]) +AC_CONFIG_FILES([elfutils.spec:config/elfutils.spec.in]) +AC_CONFIG_FILES([lib/Makefile]) +AC_CONFIG_FILES([libelf/Makefile libelf-po/Makefile.in]) + +Add +AC_CONFIG_FILES([fake-src/Makefile]) + +Change lib/Makefile.am: + libeu_a_SOURCES only next_prime.c crc32.c + noinst_HEADERS only fixedsizehash.h system.h + remove EXTRA_DIST + remove xmalloc_no_Werror + +mv COPYING.GPL COPYING + +set gpl and fake at beginning of elfutils.spec.in to 1 + +automake + +autoconf + +mkdir build + +cd build + +../configure + +make + +make dist + +rpmbuild -ta elfutils-*.tar.gz diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..2561ca28 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,112 @@ +2005-07-21 Roland McGrath + + * configure.ac: Take --enable-libebl-subdir=DIR to set LIBEBL_SUBDIR. + +2005-06-01 Roland McGrath + + * Makefile.am (all_SUBDIRS): Add libdwfl. + * configure.ac: Write libdwfl/Makefile. + +2005-05-19 Roland McGrath + + * configure.ac [AH_BOTTOM] (INTDECL, _INTDECL): New macros. + +2005-05-10 Ulrich Drepper + + * configure.ac: Define MODVERSION in config.h. + +2005-02-22 Ulrich Drepper + + * Makefile.am (all_SUBDIRS): Don't add doc subdir for now. + * configure.ac: Don't use doc subdir for now. + +2005-02-15 Ulrich Drepper + + * configure.ac: Remove AM_GNU_GETTEXT use. Use only AM_PO_SUBDIRS. + +2005-02-06 Ulrich Drepper + + * configure.ac (AM_INIT_AUTOMAKE): Removed dist-bzip2. + + * Makefile.am (EXTRA_DIST): Remove splint.rc. + * splint.rc: Removed. + +2004-09-25 Ulrich Drepper + + * configure.ac: Make compile with gcc 4.0. + +2004-03-06 Ulrich Drepper + + * configure.ac: Use AS_HELP_STRING where applicable. + +2004-01-23 Ulrich Drepper + + * configure.ac: Check for C99 compiler. + + * configure.ac: Change locking macros in config.h to at least + evaluate the parameter. Define base_cpu to none for generic linker. + +2004-01-21 Ulrich Drepper + + * configure.ac: Print error message in case --disable-generic is + used if no linker support for the architecture is available. + +2004-01-18 Ulrich Drepper + + * configure.ac: Dont generate libebl-po/Makefile.in, + libdw-po/Makefile.in, libasm-po/Makefile.in. + + * Makefile.am (all_SUBDIRS): Remove libebl-po, libdw-po, libasm-po. + +2004-01-17 Ulrich Drepper + + * configure.ac: Pretty printing of help message. + + * configure.ac: Move AC_SYS_LARGEFILE test to the front. + + * configure.ac: Add --enable-mudflap option. + +2004-01-17 Ulrich Drepper + + * configure.ac: Major cleanups. Use aux dir. + * config.guess: Moved to new config subdir. + * config.rpath: Likewise. + * config.sub: Likewise. + * depcomp: Likewise. + * install-sh: Likewise. + * missing: Likewise. + * mkinstalldirs: Likewise. + * Makefile.am (mini_SUBDIRS): Add config. + (EXTRA_DIST): Remove config.rpath. + + * configure.ac: Add AC_REVISION. + + * configure.ac: Add --enable-mudflap option. + +2004-01-11 Ulrich Drepper + + * configure.ac: Drop libdwarf directory. Add libdw-po. + * Makefile.am (all_SUBDIRS): Likewise. + * elfutils.spec: Don't distribute anything from libdwarf. + +2004-01-05 Ulrich Drepper + + * Makefile.am: Support separate libelf built. + + * elfutils.spec.in: Create separata elfutils-libelf-devel package. + Install libdw DSOs. + + * configure.ac (AC_CONFIG_SRCDIR): Use libelf/libelf.h as the file + name. + +2003-08-13 Ulrich Drepper + + * elfutils.spec.in: Remove references to libebl.so. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. + +2000-08-25 Ulrich Drepper + + * The beginning. See the NEWS file for the time being. diff --git a/GPG-KEY b/GPG-KEY new file mode 100644 index 00000000..cd60f822 --- /dev/null +++ b/GPG-KEY @@ -0,0 +1,33 @@ +Public key for drepper@redhat.com +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.2.1 (GNU/Linux) + +mQGiBDuFth0RBACPcHEkyqJE26wTXuuuCxpqJjxlBnNFkJGkWUoeu89QjzWgzXy/ +EA8+ptNBgCTPKnLEqhkRUyxAT/Uz+t+xbKqUtL54IzYfxO4NQsN/VVM0uppNfIJb +MWvAjvpp2HCkd/32i693rlH+G9dvG8K57by3PBRHBgH2L8Q7t/QvA2AWpwCgzokX +DDUiitysGn4rWO0rBBoR6OED/3ehpcHtbGixNoubRZAxpw99VTKs/I76OkrQzqcm ++w+zwZeihJXC88yAHA77/LBB3YKaX3G4CmDQUbeRJ9zPlETTLmRMcF61dQdq/3qV +Biq1sm6ctZ4uEpm8HnysKMT+VY4Xmj9LLzF2BdING9frcX9rk8Vk25iCLBronS0M +IU3WA/sEvlUFlfbyCBRBoq+Rlr9u05fnHc7CLMKI7EIS1T1dLPxH1ivuUhyYNGAM +RhCivBbT2Z0t/R4ksu3VdnPGkCyAAdWNSafSGqCYUzQH0u5Z8HK6c2iXrIX3Ipk5 +DhQOQ6k1tyYzuQw3cCf7RYRJ9/iup8RlscVt2kmGnSucqpxJCbQjVWxyaWNoIERy +ZXBwZXIgPGRyZXBwZXJAcmVkaGF0LmNvbT6IVwQTEQIAFwUCO4W2HQULBwoDBAMV +AwIDFgIBAheAAAoJENoowjp5/0R0SqUAoL5HBbaRWR19vjldUeJvYCG2AR94AKDL +nmVEaykaZWyyNg0OTuxLe1boa4hGBBARAgAGBQI8iQDvAAoJEFWW3Qzpv2U97wgA +n1RVl6FbIHVVmT224nOp5b98OZVnAJ9ehXzM60RbmGi3kJNS30II+SGft4hGBBMR +AgAGBQI9Tvt0AAoJEP3S3qzTM8uhUy0AoNqATBj2usEtJduGHukKZ9mQaycFAJ9y +lq0MmZJwMZ3699e6rgMiHAMAVbkCDQQ7hbZPEAgAzuFAPq1sYUtpJClwX7+pdz1K +dIgbxDKoSHh2rSRx24HLYY/xg9ps6fZF21/SBialKaB8BFnIeh8S9LXUtWt9aUeC +klnnQwPbR0BGRcZAS7+nHZ9agiMd4CRe4RWFmS6KhIeUsDa70+8XhIm/C+Ogd7ag +kBw7ykTb/jWHMyvcP9iY0QtmIatfVTDJUm7Rm5TtM1mDCml/gWIQJ5ezr9gv2NUG +3kpNYwP+G9o4BLyTOHamix/0YHI/HiZSYiwq40ao0zROd/yXY6/a3mitN96AidJL +5I5tbqnrFy6LmRvWmyOxWkJD/bF31rrO5PfVUgcVpUxbtW44PtVilhLuh+qjTwAD +BQf+NTHwjUw1j+PZs/y5XnPw0x0ZdYGEl0I7NqtMgCxI4ZHT9jaLcLXARb3UVEuc +1LuJ1tAA1ss1c1NLK3Lg+uZzeKMRffRYEUg0Emer8QGWr1uSOxDHcAzuRZX3PYNX +cEGEyEm443DDnXr/4b8zYK6O+sy1Ld+SVxxp6jwtk0LyT7okgD0E1dDUzX+qxpsV +ujbzdH4bdqocKouMNMT+BHeobNZpR4Tyz5+pwW+rw1+XZebyBUkIPXOoWPZpUTDG +fZ+om9xfg0JOcKZIZ0X91dLQp5x99aCmzwWeWy9LFPTAf9pYky8wXzteEotE/Tkm +DeA1caPC9IEK9BBrrS9TeubrEIhGBBgRAgAGBQI7hbZPAAoJENoowjp5/0R0Z38A +mgM4FAquwltH0ooTdAmBMoCfKb4/AJ9ufAh4Rl9sFaCie/j8jdo02bcV1A== +=Yeua +-----END PGP PUBLIC KEY BLOCK----- diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..b42a17ac --- /dev/null +++ b/INSTALL @@ -0,0 +1,182 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..7d27a7c4 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,36 @@ +## Process this file with automake to create Makefile.in +## Configure input file for elfutils. +## +## Copyright (C) 1996-2002, 2003, 2004, 2005 Red Hat, 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, version 2. +## +## 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, write to the Free Software Foundation, +## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +ACLOCAL_AMFLAGS = -I m4 + +mini_SUBDIRS = config m4 lib libelf libelf-po +# Add doc back when we have some real content. +all_SUBDIRS = libebl libdw libdwfl libcpu libasm src po tests +SUBDIRS = $(mini_SUBDIRS) $(all_SUBDIRS) + +EXTRA_DIST = elfutils.spec GPG-KEY NOTES COPYING.GPL + +distcheck-hook: + chmod -R u+w $(distdir) + +rpm: dist + rpmbuild -ts --sign elfutils-@PACKAGE_VERSION@.tar.gz + +# Tell version 3.79 and up of GNU make to not build goals in this +# directory in parallel. +.NOTPARALLEL: diff --git a/NEWS b/NEWS new file mode 100644 index 00000000..c3ddfbb8 --- /dev/null +++ b/NEWS @@ -0,0 +1,786 @@ +Version 0.110: + +libelf: fix a numbe rof problems with elf_update + +elfcmp: fix a few bugs. Compare gaps. + +Fix a few PLT problems and mudflap build issues. + +libebl: Don't expose Ebl structure definition in libebl.h. It's now private. + +Version 0.109: + +libebl: Check for matching modules. + +elflint: Check that copy relocations only happen for OBJECT or NOTYPE symbols. + +elfcmp: New program. + +libdwfl: New library. + +Version 0.108: + +strip: fix bug introduced in last change + +libdw: records returned by dwarf_getsrclines are now sorted by address + +Version 0.107: + +readelf: improve DWARF output format + +strip: support Linux kernel modules + +Version 0.106: + +libdw: Updated dwarf.h from DWARF3 spec +libdw: add new funtions dwarf_func_entrypc, dwarf_func_file, dwarf_func_line, +dwarf_func_col, dwarf_getsrc_file + +Version 0.105: + +addr2line: New program + +libdw: add new functions: dwarf_addrdie, dwarf_macro_*, dwarf_getfuncs, +dwarf_func_*. + +findtextrel: use dwarf_addrdie + +Version 0.104: + +findtextrel: New program. + +Version 0.103: + +libdw: Fix using libdw.h with gcc < 4 and C++ code. Compiler bug. + +Version 0.102: + +More Makefile and spec file cleanups. + +Version 0.101: + +Remove most gettext autoconf handling. + +Add more warnings + +Fix resulting problems. One actual bug found and fixed this way + +Version 0.100: + +libebl: Fix x86-64 relocations. + +Add -Wunused -Wextra warnings. + +Some cleanups resulting from those additional warnings. + +Lots of Makefile cleanup. + +Version 0.99: + +libelf: add gelf_checksum prototype to + +libelf: fix elf*_checksum handling of NOBITS sections + +Finish mudflap support. + +Fix three bugs found by mudflap. + +ld: add as_needed support + +Version 0.98: + +readelf: in section to segment mapping, indicate read-only sections. + +elflint: more relaxation for GNU ld + +Version 0.97: + +Fix compiling with gcc 4.0. +Some tests called elflint without appropriate LD_LIBRARY_PATH. + +Version 0.96: + +Fix support for platforms with lib64. + +Version 0.95: + +libebl: add ppc and ppc64 support + +readelf: fix minimal memory leak. + +Add support to compile with mudflap. + +Modernize configure.ac. Move scripts in config subdir. + +Modernize *-po directory infrastructure. + +libelf: Add gelf_getlib and gelf_update_lib + +readelf: print liblist sections + +Version 0.94: + +Fix some minimal build problems. + +Version 0.93: + +ibdw: tons of new functionality and bug fixes. Several interface changes. + +readelf: use libdw now. + +libdwarf: removed completely. + +Version 0.92: + +configuration changes. + +Version 0.91: + +libdw: fix memory handling. Implement source line handling. +nm: use libdw instead of libdwarf. +libelf: change to GPL from OSL1 for now. + +Version 0.90: + +libebl: Recognize a few more section types and dynamic tags and return +approriate strings. + +Version 0.89: + +strip: fix overwriting of symbol table in input file. + +Version 0.88: + +libebl: Add some ia64 bits. + +Version 0.87: + +Bug fixes for big endian and some 64-bit machines. + +Version 0.86: + +strip: fix handling of Alpha and s390x which use incorrect hash bucket sizes. + +ld: tons of changes, moving towards usability. + +Version 0.85: + +strip: update section group symbol index if the associated symbol table changed + +libelf: fix two problems with generating output not via mmap + +elflint: add probably 10-15 more tests +libebl: add support for some of the new tests + +ld: gazillion changes + +Version 0.84: + +elflint: deal with .rel.dyn section. Fix a problem with rela platforms. +Handle PT_GNU_STACK. Change to write messages to stdout. + +readelf: fix a problem with version information in the symbol table output. + +strip: update all version symbol table entries + +Version 0.83: + +size: fix a warning + +strip: last changed caused problems when the symbol table is before the +relocation section. Fixed. This fix also improved the asymptotic +behavior if many symbol table sections are present. + +Version 0.82: + +Run strip tests with the correct libelf and libebl. + +libelf: fix bug in verneed byte order changing code. + +Version 0.81: + +strip: Remove unused symbol table entries. This might require updating +various other sections. + +Version 0.80: + +Fix some libelf problems with ET_REL files. + +Version 0.79: + +More warning changes, mainly by jbj. + +libdw: yet more new code. dwarf_child and dwarf_sibling should now actually +work. + +Version 0.78: + +libdw: 10+ new functions. get-pubnames2 works now fully. Almost all the +code needed for nm is in place. + +Version 0.77: + +cleanups to compile cleanly with gcc 3.3 and -Werror. + +libdw: some new code. + +Version 0.76: + +libebl: Fix last patch to recognize relocation sections. We must not +use the name. + +Version 0.75: + +libebl: .debug_ranges is a DWARF 3 debug section +libebl: recognize relocation sections for debug section +Patches by Jakub Jelinek. + +Version 0.74: + +Cleanups and more SPARC support by Tom Callaway . + +Version 0.73: + +64-bit cleanups for the programs. + +Version 0.72: + +libelf: and yet more fun with endian tranformation at output time. + +Version 0.71: + +libelf: more fun with endian tranformation at output time. Add test for it. + +Version 0.70: + +libelf: Two little bugs left from previous patch to handle section output +order. + +libelf: add unlikely in some more places. + +Version 0.69: + +libelf: fix output routines to handle case where section indeces and +ordre in the output file don't match correctly. Patch by Jakub. + +elflint: fix test of note section content for 64-bit platforms and files +with different byte order. + +Version 0.68: + +libebl: Fix SH_ENTSIZE_HASH definition (patch by Jakub) + +Version 0.67: + +libelf: correct mistake in error string handling. + +libelf: Implement ELF_F_PERMISSIVE. +strip: Implement --permissive option. + +Version 0.66: + +strip: Implement -g option. + +libelf: Handle broken hash table entry sizes. + +libebl: New function ebl_debugscn_p. Use it where appropriate. + +Version 0.65: + +libelf: Use correct file size for NOBITS section with ELF_F_LAYOUT set + +Version 0.64: + +libelf: Make error handling more robust. +libelf: Use TLS in error handler if configured with --enable-tls + +tests: input files are now distributed, not uuencoded in the shell scripts + +libdw: implement error handling, dwarf_get_pubnames + +Version 0.63: + +Build (incomplete) libdw. + +Version 0.62: + +Get rid of libtool. + +Version 0.61: + +Fix URL of OSL. + +Version 0.60: + +libebl: Handle .gnu.warning.* sections correctly. + +size: Implement -t option. + +libebl: Add IA-64 support. +libebl: Update SH relocations. +libebl: Add Alpha support. +libebl: Add Arm support. +libebl: Add support for all currently known architecture to the loader. + +Version 0.59: + +nm: Implement -S option. Correct portable output format. Implement -s option. + +libelf: Take offset of archive into account in elf_rand. + +Version 0.58: + +strip: fix handling of ET_REL files. +Add tests for strip. + +Version 0.57: + +strip: respect layout of input file + +Version 0.56: + +strip: handle files with large number of sections. + +Version 0.55: + +libelf: quite a few bug fixes by Alex Larsson. + +strip: implement -f option to place stripped sections into a separate +file. By Alex Larsson. + +Version 0.54: + +strip: don't let STT_SECTION symbols keeps sections from being removed + +elflint: local symbols are allowed in .dynsym +elflint: special case .rel.dyn a bit + +Version 0.53: + +elflint: check types and flags of special sections defined in gABI + +libebl: add x86-64 support + +Version 0.52: + +Start improvement of debug info handling in nm. + +libasm: implement asm_adduleb128 and asm_addsleb128 and a test for them + +Version 0.51: + +Fix build on 64-bit platforms. + +Version 0.50: + +nm: print file/line number also for local symbols + +use versions scripts not libtool's useless -export-symbols option + +Version 0.49: + +Update to autoconf 2.54 and automake 1.7. + +elflint: check note sections + +libdwarf: a number of bug fixes + +readelf: print .debug_info section content + +dwarf.h: Update from draft 7 + +Version 0.48: + +libcpu: beginning + +libelf: new function to read parts of the ELF file + +libebl: support for note section handling + +readelf: dump note sections + +Version 0.47: + +libelf: fix little new section-handling related bugs in elf_getshstrndx +and elf_nextscn + +elflint: tests for mandatory content of dynamic section + +libasm: better handling of absolute symbols + +Version 0.46: + +libasm: rewrite to store Elf_Scn* instead of indices + +nm: finish many-section support + +nm: use debug in to print file/line info in sysv format + +libdwarf: fix a few bugs in DIE handling + +Version 0.45: + +libelf: major rewrite to keep Elf_Scn references valid until elf_end + +Version 0.44: + +libasm: Add support for bss, ABS, and COM sections. + +libebl: ebl_section_name takes now two index arguments to distinguish +between special sections and extended sections + +Version 0.43: + +General: fix a few problem gcc 3.1 had with the code. + +libelf: implement {gelf,elf32,elf64}_checksum + +libelf: optimze DSO: fewer relocations, fewer PLTs + +add msg_tst test + +ld: use correct section header string table index; write correct index + +add dependencies for *.sym files + +Version 0.42: + +libelf: add elf_getshnum and elf_getshstrndx + +libebl: update section type name function + +elflint: tons of fixes wrt large number of sections. New tests in this area. +Same amount of other bug fixes. + +size, strip, nm: better support for large number of sections. Including +using correct section header string table + +libasm: correctly create data structures for large number of sections + +new tests asm-tst4 and asm-tst5 to check large number of sections + +libasm: implement section group generation + +elflint: more tests on section groups. Improve performance on existing +section group tests + +Version 0.41: + +ld: add undefined symbols to dynamic symbol table if --export-dynamic is +not given + +ld: fix value of e_entry + +Version 0.40: + +elflint: print section names in error messages + +elflint: mustn't warn about multiple DT_NULL + +ld: don't emit all symbols if --export-dynamic is not given + +ld: correct compute symbol address in output file (section index was off by 1) + +ld: generate correct version info in dynsym without --export-dynamic and +in symtab + +Version 0.39: + +Fix check of various e_*size entries in elflint. + +Handle text output in asm_newsym. + +Finish checks in asm-tst3. + +Version 0.38: + +Update to autoconf 2.53, automake 1.6, gettext 0.11+. + +Introduce *.sym files to restrict export from DSOs. + +Use attribute_hidden and internal_function to optimize DSO code. + +Add TLS definitions in elf.h and handle them in readelf. + +Fix bug in verdef section generation in ld. + +Add initial libasm code. + +Version 0.37: + +Implement better hash size optimization heuristic in ld. It uses a formula +taking number of tests into account. + +Lots of small bug fixes. + +Improve readelf output format. Respect various sh_link/sh_info values. +Correctly print versioning information for symbol tables. + +Version 0.36: + +Implement preprocessing of linker script. Recognize -z combreloc. + +Version 0.35: + +Implement -z ignore|record for ld. + +Implement creating of .gnu.version_r and .gnu.version sections. The +.gnu.version does not yet contain correct info for defined and versioned +symbols (means .gnu.version_d is not yet implemented). + +Implement gelf_update_* functions to create versioning data. + +Version 0.34: + +Add DT_RUNPATH/DT_RPATH entries to dynamic section. Create .plt and +.rel.plt sections (completely). Add support for all four PLT related +dynamic section entries. Add callback function for PLT creation. + +More tests in elflint. Add support for very strict checking which for +now flags level 2 (deprecated features) usage. + +Version 0.33: + +Create dynamic symbol table, dynamic string table, and hash table to ld. + +Add hash table histogram support to readelf. + +Version 0.32: + +more work on elflint + +ld now creates the dynamic section and references it. Start adding entries +to dynamic section. + +Version 0.31: + +Start implementing elflint. + +Version 0.30: + +Fix handling of NOBITS sections in elf_getdata. + +Start implementing generation of executables and DSOs in ld. +Generation of program header mostly done. Address computation done. +Extension of linker script syntax. + +Various cleanups. + +Implement section group handling in readelf. + +Version 0.29: + +Implement section groups. This involved a lot of code moving. The +new code is entirely untested since gas/gcc are currently not able to +create section groups. ld works fine on files without section groups. + +Version 0.28: + +Fix problem with adding more section in elf_newscn. The section pointers +for the data buffers wasn't adjusted. + +Fix elf_getdata with nonzero second parameter. Correctly handle creation +of internal data buffer for machines without unaligned access. + +Version 0.27: + +Start adding support to selectively add sections. Includes support for +section groups. +Add --gc-sections/--no-gc-sections options. +Add general section merging support. + +Fix a bug in section group support in strip. + +Fix some potential problems with hash value in dynamic hash implementation. + +Version 0.26: + +section merging works in ld. + +Version 0.25: + +Actually create data structures from version map file and use it to hide +symbols in ld. + +Implement -s -s for ld. + +Version 0.24: + +Improve relocation table output in readelf. Avoid some crashes. +Finish many section handling in readelf. + +Finish: finish implementation of ld -r. At least some simple tests pass. + +Version 0.23: + +Fix a number of errors in ELF_C_WRITE handling. + +Almost finished implementation of ld -r. The data sections are all copied. +Handling of symbol tables is missing. + +Version 0.22: + +Handle DSO and archive input files correctly if -r option is given. + +Gracefully deal with no phdr in new file in libelf. +Fix various small error handling problems. +Don't mmap file for output unless the command says so. + +Add code to create ELF section header table to ld finalize routines. + +Version 0.21: + +Fix some problems with recursive handling of archives in libelf. + +Improve messages printed by nm. + +Add symbol binding name handling to libebl. Fix section name handling in +libebl. + +readelf and nm use more libebl functions. + +Handle XINDEX correctly in nm and string. + +Add first machine ld backend library (i386). +Use it. Recognize -r and --shared. Avoid using -lxxx parameters for -r. +Create ELF header in output file. Change mode of output file according to +output file type. Reorganize callback initialization in ld. + +Version 0.20: + +Fix some memory leaks in libelf. + +Version 0.19: + +Implement reading version script. Both inside linker scripts and via the +--version-script command line parameter. Uses the same code. +What remains to be done is to implement a data structure which allows +efficient matching against the version names to decide which pattern +matches. + +Beginning of output generation and output writing functions. + +Version 0.18: + +Finish implementation for DSO input file handling. Implement rpath, runpath, +and LD_LIBRARY_PATH handling. + +Version 0.17: + +make handling of e_shnum overflow in libelf standard conforming + +ld now actually can handle DSOs in linker scripts. Handling of DT_RUNPATH, +DT_RPATH, -rpath, -rpath-link still remains to be implemented. + +fix handling of -L parameters. Make actual use of the default_paths element. + +make re-definition of symbols in and from DSO compatible with existing linker + +Version 0.16: + +more work on assigning input sections to output sections. + +Add gelf_xlatetof and gelf_xlatetom which were accidently left out. + +Fix memory handling of section headers. + +Version 0.15: + +Add many-section support to ld. Add various new command line parameters. +Allow pagesize to be specified in linker script or on the command line. +Collect input sections in list for the output section according to the rules +specified in the linker script. + +Version 0.14: + +Fix some problems in the internal list handling which had the result +that we didn't look for some of the unresolved symbols. + +Free some memory if we know we don't need it anymore. + +Optimize the list of unresolved symbols. Throw out symbols which are +meanwhile resolved. + +Version 0.13: + +Got file reading correct now. The files are all read while parsing +the parameters. No creating of data structures to describe the linker +command line. The symbol table is built up while reading the files. +DSOs are handled now. -( -) handling is optimized. + +Version 0.12: + +Linker read linker scripts everywhere. Handles --whole-archive. Recognizes +--dynamic and --static. Collects defined and undefined symbols. Recognizes +conflicts. + +libebl now defines functions to call the callbacks. Add generic name handling +in these new functions. Remove the code from readelf and call the new +functions. + +Version 0.11: + +Start of linker. Basic argument parsing, finding of input files, +linker script reading. + +Version 0.10: + +Implement dwarf_get_fde_n(), dwarf_get_abbrev(), dwarf_get_abbrev_tag(), +dwarf_get_abbrev_code(), dwarf_get_abbrev_children_flag(), +dwarf_get_abbrev_entry(), dwarf_get_fde_at_pc(), and tests for it. + +Version 0.9: + +Implement dwarf_get_fde_list_eh(), dwarf_get_cie_of_fde(), +dwarf_get_fde_range(), dwarf_get_cie_info(), dwarf_get_fde_instr_bytes(), +and tests for them. + +Version 0.8: + +Make handling of binaries in other byte order work and add tests for it. + +Version 0.7: + +Implement dwarf_get_aranges(), dwarf_get_arange(), dwarf_get_cu_die_offset(), +dwarf_get_arange_info(), and tests for them. + +Version 0.6: + +Implement dwarf_get_global(), dwarf_globname(), dwarf_global_die_offset(), +dwarf_global_cu_offset(), dwarf_global_name_offsets(), and tests for them + +Version 0.5: + +Implemented dwarf_srclines(), dwarf_srcfiles(), dwarf_linebeginstatement(), +dwarf_lineendsequence(), dwarf_lineno(), dwarf_lineaddr(), dwarf_lineoff(), +dwarf_linesrc(), dwarf_lineblock(), dwarf_lineprologueend(), +dwarf_lineepiloguebegin(), and tests for them. + +Version 0.4: + +Implemented dwarf_loclist(). + +Version 0.3: + +Implemented dwarf_dieoffset(), dwarf_die_CU_offset(), dwarf_diename() and +tests. + +Implemented dwarf_attrlist(), dwarf_hasattr(), dwarf_attr(), dwarf_lowpc(), +dwarf_highpc(), dwarf_bytesize(), dwarf_bitsize(), dwarf_bitoffset(), +dwarf_srclang(), dwarf_arrayorder(), dwarf_hasform(), dwarf_whatform(), +dwarf_whatattr(), dwarf_formref(), dwarf_global_formref(), dwarf_formaddr(), +dwarf_formflag(), dwarf_formudata(), dwarf_formsdata(), dwarf_formblock, +dwarf_formstring() and tests for them. + +Version 0.2: + +Implemented dwarf_offdie()), dwarf_tag(), dwarf_dieoffset(), +dwarf_die_CU_offset(), dwarf_diename() and tests for them. + +Version 0.1: + +First libdwarf functions work. + +Version 0.0: + +libelf and parts of libebl are done. diff --git a/NOTES b/NOTES new file mode 100644 index 00000000..4f06b8d2 --- /dev/null +++ b/NOTES @@ -0,0 +1,73 @@ +- old GNU ld's behavior wrt DSOs seems to be severely broken. + + y.o reference foo() + y1.o defines foo(), references bar() + y2.o defines bar() + libbar.so defines bar() + + Running + + gcc -o y y.o -lbar y1.o y2.o + + uses the bar() definition from libbar.so and does not mention the definition + in y2.o at all (no duplicate symbol message). Correct is to use the + definition in y2.o. + + + y.o reference foo() + y1.o defines foo(), references bar() + y2.o in liby2.a defines bar() + libbar.so defines bar() + + Running + + gcc -o y y.o -lbar y1.o -ly3 + + has to use the definition in -lbar and not pull the definition from liby3.a. + + +- the old linker follows DT_NEEDED entries and adds the objects referenced + this way which define a symbol which is needed as a DT_NEEDED to the + generated binary. This is wrong since the DT_NEEDED changes the search + path in the object (which is breadth first). + + +- the old linker supported extern "C++", extern "java" in version scripts. + I believe this implementation is severly broken and needs a redesign + (how do wildcards work with these languages*?). Therefore it is left + out for now. + + +- what should happen if two sections in different files with the same + name have different types and/or the flags are different + + +- section names in input files are mostly irrelevant. Exceptions: + + .comment/SHT_PROGBITS in strip, ld + + .debug \ + .line | + .debug_srcinfo | + .debug_sfnames | + .debug_aranges | + .debug_pubnames | + .debug_info | + .debug_abbrev | + .debug_line | + .debug_abbrev > DWARF sections in ld + .debug_line | + .debug_frame | + .debug_str | + .debug_loc | + .debug_macinfo | + .debug_weaknames | + .debug_funcnames | + .debug_typenames | + .debug_varnames / + + Sections created in output files follow the naming of special section + from the gABI. + + In no place is a section solely indentified by its name. Internal + references always use the section index. diff --git a/README b/README new file mode 100644 index 00000000..afc94077 --- /dev/null +++ b/README @@ -0,0 +1,6 @@ +Fundamental design decision: + +- the sizes of external and internal types are assumed to be the same. + This leaves byte ordering aside. While assuming this the code can be + greatly simplified and speed increases. Since no change violating this + assumption is in sight this is believed to be a worthwhile optimization. diff --git a/THANKS b/THANKS new file mode 100644 index 00000000..543436c2 --- /dev/null +++ b/THANKS @@ -0,0 +1,5 @@ +At least the following have submitted valuable patches: + +Jeff Johnson building. rpm wrestling +Alexander Larsson separate debug info +Jakub Jelinek bug fixes, testing diff --git a/TODO b/TODO new file mode 100644 index 00000000..bf4a0333 --- /dev/null +++ b/TODO @@ -0,0 +1,168 @@ + ToDo list for elfutils -*-outline-*- + ---------------------- + +Time-stamp: <2003-08-07 12:52:49 drepper> + +* mkinstalldirs + + Remove everywhere. Use mkdir -p. + +* libelf: + +** verify section + + Currently the elf_update function trusts the user blindly if the + ELF_F_LAYOUT flag is set. This is OK if the data is prepared by a + ELF_C_NULL call but not if the user prepared the data herself + +** break out archive handling from elf_begin + + The handling of archives (especially of the symbol tables) must be + broken out of elf_begin. There are several different forms of + archives and only when having the archive handling separately this + remains maintainable. + + +* libdwarf + +** Should we do more error checking? + + Most functions don't check whether they get a NULL value passed for + a pointer argument. It could be argued that this is OK since it's + a bug inthe program. But perhaps one could catch the case and return + an error which would allow the program using libdwarf to have fewer + places with error checking. + +** More memory access checks needed + + All accesses to the debug sections should make sure the offsets are + valid. This is currently especially a problem with leb128 accesses. + +** Low level macro information operations + + in 5.11.3 are not implemented. gcc currently does not emit this + information so I cannot test it. + +** Rename dwarf_getabbrev + +** dwarf_loclist() + + This function and its interface seem to be misdesigned. The specification + is unclear and its changed between v2 and v2.1. Other implementation + implement even different behavior. + + +* nm: + +** add demangler support + + Use demangler from libiberty. + +** add support to read debugging symbols + + Implement -l option for BSD and POSIX format + + +* strip: + +** support SHT_SYMTAB_SHNDX + + should be removed if not needed anymore + +* ld: + +** sanity check .rel sh_info content + + the sh_info of all .rel sections with the same name must point to + sections which also have the same name + +** use ld.so.conf + + to locate shared libraries also use /etc/ld.so.conf + +** handle object files for different architectures + + ld.so is expected to ignore object files for different architectures and + continue looking for a matching file (e.g., ignore 32-bit binaries on + 64-bit platforms and vice versa). We probably need the same in ld. + +** reuse after elf_end + + Some files are closed using elf_end. They are removed from memory only + if no reference is left (especially for archives this is a problem). + The old mapping should be reused in that case. The problem is worse + for files which are not mapped read-only (archives again). + + +** size for STT_SECTION entries + + The STT_SECTION entries have zero for the size but can easily get + the size of the section. + +* elflint + +** additional checks + + 1st GOT entry == _DYNAMIC + + if TEXTREL check whether any relocation touches RO segment + + if TEXTREL not set check that no relocation touches RO segment + + check versioning info: + + always BASE in verdef + sh_size/sh_entsize matches last offset != 0 + + check whether any relocation is for a merge-able section + +** possibly missing tests + + at most one extended section index table for a symtab + + no extended section index table != ET_REL + + no extended section index table for SHT_DYNSYM + +** relax + + prelink generated files + + +* mcs + + Sun has it. Can modify sections which are not in segments. + + -a string + Append string to the comment section of the ELF object + files. If string contains embedded blanks, it must be + enclosed in quotation marks. + + -c Compress the contents of the comment section of the + ELF object files. All duplicate entries are removed. + The ordering of the remaining entries is not dis- + turbed. + + -d Delete the contents of the comment section from the + ELF object files. The section header for the comment + section is also removed. + + -n name + Specify the name of the comment section to access if + other than .comment. By default, mcs deals with the + section named .comment. This option can be used to + specify another section. mcs can take multiple -n + options to allow for specification of multiple sec- + tion comments. + + -p Print the contents of the comment section on the stan- + dard output. Each section printed is tagged by the + name of the file from which it was extracted, using + the format file[member_name]: for archive files and + file: for other files. + + -V Print on standard error the version number of mcs. + +Local Variables: +eval:(hide-body) +End: diff --git a/config/.cvsignore b/config/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/config/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/config/ChangeLog b/config/ChangeLog new file mode 100644 index 00000000..27adfbf4 --- /dev/null +++ b/config/ChangeLog @@ -0,0 +1,53 @@ +2005-07-21 Ulrich Drepper + + * elfutils.spec.in: Distribute eu-elfcmp. + +2005-04-01 Ulrich Drepper + + * elfutils.spec.in: Distribute eu-addr2line. + +2005-03-17 Ulrich Drepper + + * elfutils.spec.in: Distribute libdw.{a,so,h}. + +2005-02-22 Ulrich Drepper + + * Makefile.am: Ignore result of cvs run. + + * elfutils.spec.in: Simplify build process by not using a subdir. + This means we can use %configure. + +2005-02-18 Ulrich Drepper + + * Makefile.am: Automatically added changelog from NEWS file on dist. + +2005-02-15 Ulrich Drepper + + * elfutils.spec.in: Make sure RPM_OPT_FLAGS is used. During + %build, really do build the binaries. + Remove --enable-shared configure parameters. + +2005-02-07 Ulrich Drepper + + * elfutils.spec.in (BuildRequires): Up gcc requirement to 3.4. + +2004-11-23 Ulrich Drepper + + * elfutils.spec.in: Some more changes for the RPM with the fake + binaries. + +2004-01-29 Ulrich Drepper + + * elfutils.spec.in: Update BuildRequires. + +2004-01-17 Ulrich Drepper + + * Makefile.am: New file. + * config.guess: Moved to here from toplevel. + * config.rpath: Likewise. + * config.sub: Likewise. + * depcomp: Likewise. + * install-sh: Likewise. + * missing: Likewise. + * mkinstalldirs: Likewise. + * elfutils.spec.in: New file. diff --git a/config/Makefile.am b/config/Makefile.am new file mode 100644 index 00000000..45a78deb --- /dev/null +++ b/config/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to produce Makefile.in -*-Makefile-*- +## Configure input file for elfutils. +## +## Copyright (C) 2004, 2005 Red Hat, 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, version 2. +## +## 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, write to the Free Software Foundation, +## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +EXTRA_DIST = elfutils.spec.in + +$(srcdir)/elfutils.spec.in: $(top_srcdir)/NEWS + @tmpname=$$(mktemp $${TMPDIR:-/tmp}/elfutils.XXXXXX); \ + date +'* %a %b %e %Y' | tr '[\n]' '[ ]' > $$tmpname; \ + getent passwd "$$(whoami)" | \ + awk 'BEGIN {FS=":"} { printf $$5; exit 0}' >> $$tmpname; \ + echo -n " <$(whoami)@redhat.com> " >> $$tmpname; \ + sed 's/Version \(.*\):$$/\1-1/;q' $(top_srcdir)/NEWS >> $$tmpname; \ + sed '2,/^Version /p;d' $(top_srcdir)/NEWS | \ + head -n -1 | \ + awk '{ if ($$0 == "") { if (line != "") { printf "- "; fflush(); system("echo \"" line "\" | fold -w 70"); line=""; } } else { line=line $$0; }} END { if (line != "") { printf "- "; system("echo \"" line "\" | fold -w 70")}}' >> $$tmpname; \ + echo >> $$tmpname; \ + sed "/^%changelog/r $$tmpname" $@ > $@.new; \ + rm -f $$tmpname; \ + mv -f $@.new $@ + -@if [ -d $(srcdir)/CVS ]; then \ + cd $(srcdir); \ + cvs ci -m "Added changelog." $(@F); \ + fi diff --git a/config/config.guess b/config/config.guess new file mode 100644 index 00000000..dd1688b7 --- /dev/null +++ b/config/config.guess @@ -0,0 +1,1459 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2004-06-11' + +# This file 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 2 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + amd64:OpenBSD:*:*) + echo x86_64-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + cats:OpenBSD:*:*) + echo arm-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + luna88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + macppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvmeppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mipseb-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit 0 ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit 0 ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit 0 ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha*:OpenVMS:*:*) + echo alpha-hp-vms + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit 0 ;; + DRS?6000:UNIX_SV:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7 && exit 0 ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c \ + && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && exit 0 + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + # avoid double evaluation of $set_cc_for_build + test -n "$CC_FOR_BUILD" || eval $set_cc_for_build + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + *:UNICOS/mp:*:*) + echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + # Determine whether the default compiler uses glibc. + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #if __GLIBC__ >= 2 + LIBC=gnu + #else + LIBC= + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + # GNU/KFreeBSD systems have a "k" prefix to indicate we are using + # FreeBSD's kernel, but not the complete OS. + case ${LIBC} in gnu) kernel_only='k' ;; esac + echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit 0 ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit 0 ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit 0 ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit 0 ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit 0 ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit 0 ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit 0 ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit 0 ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i*86:*:5:[78]*) + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit 0 ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit 0 ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + case `uname -p` in + *86) UNAME_PROCESSOR=i686 ;; + powerpc) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit 0 ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config/config.sub b/config/config.sub new file mode 100644 index 00000000..ba331039 --- /dev/null +++ b/config/config.sub @@ -0,0 +1,1549 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2004-03-12' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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 2 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | msp430 \ + | ns16k | ns32k \ + | openrisc | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | msp430-* \ + | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ + | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nv1) + basic_machine=nv1-cray + os=-unicosmp + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + or32 | or32-*) + basic_machine=or32-unknown + os=-coff + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config/depcomp b/config/depcomp new file mode 100644 index 00000000..368e3be9 --- /dev/null +++ b/config/depcomp @@ -0,0 +1,436 @@ +#! /bin/sh + +# depcomp - compile a program generating dependencies as side-effects +# Copyright 1999, 2000 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 2, 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi +# `libtool' can also be set to `yes' or `no'. + +if test -z "$depfile"; then + base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'` + dir=`echo "$object" | sed 's,/.*$,/,'` + if test "$dir" = "$object"; then + dir= + fi + # FIXME: should be _deps on DOS. + depfile="$dir.deps/$base" +fi + +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. This file always lives in the current directory. + # Also, the AIX compiler puts `$object:' at the start of each line; + # $object doesn't have directory information. + stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + outname="$stripped.o" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 AIX compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + + base=`echo "$object" | sed -e 's/\.o$/.d/' -e 's/\.lo$/.d/'` + tmpdepfile1="$base.o.d" + tmpdepfile2="$base.d" + if test "$libtool" = yes; then + "$@" -Wc,-MD + else + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + if test -f "$tmpdepfile1"; then + tmpdepfile="$tmpdepfile1" + else + tmpdepfile="$tmpdepfile2" + fi + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a space and a tab in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + test -z "$dashmflag" && dashmflag=-M + ( IFS=" " + case " $* " in + *" --mode=compile "*) # this is libtool, let us make it quiet + for arg + do # cycle over the arguments + case "$arg" in + "--mode=compile") + # insert --quiet before "--mode=compile" + set fnord "$@" --quiet + shift # fnord + ;; + esac + set fnord "$@" "$arg" + shift # fnord + shift # "$arg" + done + ;; + esac + "$@" $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + ) & + proc=$! + "$@" + stat=$? + wait "$proc" + if test "$stat" != 0; then exit $stat; fi + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + # X makedepend + ( + shift + cleared=no + for arg in "$@"; do + case $cleared in no) + set ""; shift + cleared=yes + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift;; + -*) + ;; + *) + set fnord "$@" "$arg"; shift;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} 2>/dev/null -o"$obj_suffix" -f"$tmpdepfile" "$@" + ) & + proc=$! + "$@" + stat=$? + wait "$proc" + if test "$stat" != 0; then exit $stat; fi + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + ( IFS=" " + case " $* " in + *" --mode=compile "*) + for arg + do # cycle over the arguments + case $arg in + "--mode=compile") + # insert --quiet before "--mode=compile" + set fnord "$@" --quiet + shift # fnord + ;; + esac + set fnord "$@" "$arg" + shift # fnord + shift # "$arg" + done + ;; + esac + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + ) & + proc=$! + "$@" + stat=$? + wait "$proc" + if test "$stat" != 0; then exit $stat; fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + ( IFS=" " + case " $* " in + *" --mode=compile "*) + for arg + do # cycle over the arguments + case $arg in + "--mode=compile") + # insert --quiet before "--mode=compile" + set fnord "$@" --quiet + shift # fnord + ;; + esac + set fnord "$@" "$arg" + shift # fnord + shift # "$arg" + done + ;; + esac + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + ) & + proc=$! + "$@" + stat=$? + wait "$proc" + if test "$stat" != 0; then exit $stat; fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 diff --git a/config/elfutils.spec.in b/config/elfutils.spec.in new file mode 100644 index 00000000..85681f51 --- /dev/null +++ b/config/elfutils.spec.in @@ -0,0 +1,385 @@ +# -*- rpm-spec-*- +%define fake 0 +Summary: A collection of utilities and DSOs to handle compiled objects. +Name: elfutils +Version: @PACKAGE_VERSION@ +Release: 1 +%if %{fake} +License: GPL +%else +License: OSL +%endif +Group: Development/Tools +#URL: file://home/devel/drepper/ +Source: elfutils-%{version}.tar.gz +Obsoletes: libelf libelf-devel +Requires: elfutils-libelf = %{version}-%{release} +%if %{fake} +Requires: binutils >= 2.14.90.0.4-26.2 +%endif +Requires: glibc >= 2.3.1-2 + +# ExcludeArch: xxx + +BuildRoot: %{_tmppath}/%{name}-root +BuildRequires: gcc >= 3.4 +BuildRequires: bison >= 1.875 +BuildRequires: flex >= 2.5.4a +BuildRequires: bzip2 + +%define _gnu %{nil} +%define _programprefix eu- + +%description +Elfutils is a collection of utilities, including ld (a linker), +nm (for listing symbols from object files), size (for listing the +section sizes of an object or archive file), strip (for discarding +symbols), readelf (to see the raw ELF file structures), and elflint +(to check for well-formed ELF files). Also included are numerous +helper libraries which implement DWARF, ELF, and machine-specific ELF +handling. + +%package devel +Summary: Development libraries to handle compiled objects. +Group: Development/Tools +%if %{fake} +License: GPL +%else +License: OSL +%endif +Requires: elfutils = %{version}-%{release} +Requires: elfutils-libelf-devel = %{version}-%{release} + +%description devel +The elfutils-devel package contains the libraries to create +applications for handling compiled objects. libebl provides some +higher-level ELF access functionality. libdw provides access to +the DWARF debugging information. libasm provides a programmable +assembler interface. + +%package libelf +Summary: Library to read and write ELF files. +Group: Development/Tools +%if %{fake} +License: GPL +%endif + +%description libelf +The elfutils-libelf package provides a DSO which allows reading and +writing ELF files on a high level. Third party programs depend on +this package to read internals of ELF files. The programs of the +elfutils package use it also to generate new ELF files. + +%package libelf-devel +Summary: Development support for libelf +Group: Development/Tools +Requires: elfutils-libelf = %{version}-%{release} +Conflicts: libelf-devel +%if %{fake} +License: GPL +%endif + +%description libelf-devel +The elfutils-libelf-devel package contains the libraries to create +applications for handling compiled objects. libelf allows you to +access the internals of the ELF object file format, so you can see the +different sections of an ELF file. + +%prep +%setup -q + +%build +%configure --program-prefix=%{_programprefix} +make + +%install +rm -rf ${RPM_BUILD_ROOT} +mkdir -p ${RPM_BUILD_ROOT}%{_prefix} + +%makeinstall + +chmod +x ${RPM_BUILD_ROOT}%{_prefix}/%{_lib}/lib*.so* +%if !%{fake} +chmod +x ${RPM_BUILD_ROOT}%{_prefix}/%{_lib}/elfutils/lib*.so* +%endif + +%if !%{fake} +# XXX Nuke unpackaged files +{ cd ${RPM_BUILD_ROOT} + rm -f .%{_bindir}/eu-ld + rm -f .%{_includedir}/elfutils/libasm.h + rm -f .%{_libdir}/libasm-%{version}.so + rm -f .%{_libdir}/libasm.so.* + rm -f .%{_libdir}/libasm.so + rm -f .%{_libdir}/libasm.a +} +%endif + +%check +make check + +%clean +rm -rf ${RPM_BUILD_ROOT} + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%post libelf -p /sbin/ldconfig + +%postun libelf -p /sbin/ldconfig + +%files +%defattr(-,root,root) +%doc README TODO +%if %{fake} +%doc fake-src/FULL +%endif +%{_bindir}/eu-elflint +%{_bindir}/eu-nm +%{_bindir}/eu-readelf +%{_bindir}/eu-size +%{_bindir}/eu-strip +%{_bindir}/eu-findtextrel +%{_bindir}/eu-addr2line +%{_bindir}/eu-elfcmp +%if !%{fake} +#%{_bindir}/eu-ld +#%{_libdir}/libasm-%{version}.so +%{_libdir}/libdw-%{version}.so +%{_libdir}/libdwfl-%{version}.so +#%{_libdir}/libasm.so.* +%{_libdir}/libdw.so.* +%{_libdir}/libdwfl.so.* +%dir %{_libdir}/elfutils +%{_libdir}/elfutils/lib*.so +%endif + +%files devel +%defattr(-,root,root) +%{_includedir}/dwarf.h +%dir %{_includedir}/elfutils +%{_includedir}/elfutils/elf-knowledge.h +%if !%{fake} +%{_includedir}/elfutils/libebl.h +%{_includedir}/elfutils/libdw.h +%{_includedir}/elfutils/libdwfl.h +#%{_libdir}/libasm.a +%{_libdir}/libebl.a +%{_libdir}/libdw.a +%{_libdir}/libdwfl.a +#%{_libdir}/libasm.so +%{_libdir}/libdw.so +%{_libdir}/libdwfl.so +%endif + +%files libelf +%defattr(-,root,root) +%{_libdir}/libelf-%{version}.so +%{_libdir}/libelf.so.* + +%files libelf-devel +%defattr(-,root,root) +%{_includedir}/libelf.h +%{_includedir}/gelf.h +%{_includedir}/nlist.h +%{_libdir}/libelf.a +%{_libdir}/libelf.so + +%changelog +* Sun Jul 24 2005 Ulrich Drepper <@redhat.com> 0.110-1 +- libelf: fix a numbe rof problems with elf_update +- elfcmp: fix a few bugs. Compare gaps. +- Fix a few PLT problems and mudflap build issues. +- libebl: Don't expose Ebl structure definition in libebl.h. It's now p +rivate. + +* Thu Jul 21 2005 Ulrich Drepper <@redhat.com> 0.109-1 +- libebl: Check for matching modules. +- elflint: Check that copy relocations only happen for OBJECT or NOTYPE +symbols. +- elfcmp: New program. +- libdwfl: New library. + +* Mon May 9 2005 Ulrich Drepper <@redhat.com> 0.108-1 +- strip: fix bug introduced in last change +- libdw: records returned by dwarf_getsrclines are now sorted by address + +* Sun May 8 2005 Ulrich Drepper <@redhat.com> 0.108-1 +- strip: fix bug introduced in last change + +* Sun May 8 2005 Ulrich Drepper <@redhat.com> 0.107-1 +- readelf: improve DWARF output format +- strip: support Linux kernel modules + +* Fri Apr 29 2005 Ulrich Drepper 0.107-1 +- readelf: improve DWARF output format + +* Mon Apr 4 2005 Ulrich Drepper 0.106-1 +- libdw: Updated dwarf.h from DWARF3 speclibdw: add new funtions dwarf_f +unc_entrypc, dwarf_func_file, dwarf_func_line,dwarf_func_col, dwarf_ge +tsrc_file + +* Fri Apr 1 2005 Ulrich Drepper 0.105-1 +- addr2line: New program +- libdw: add new functions: dwarf_addrdie, dwarf_macro_*, dwarf_getfuncs +,dwarf_func_*. +- findtextrel: use dwarf_addrdie + +* Mon Mar 28 2005 Ulrich Drepper 0.104-1 +- findtextrel: New program. + +* Mon Mar 21 2005 Ulrich Drepper 0.103-1 +- libdw: Fix using libdw.h with gcc < 4 and C++ code. Compiler bug. + +* Tue Feb 22 2005 Ulrich Drepper 0.102-1 +- More Makefile and spec file cleanups. + +* Fri Jan 16 2004 Jakub Jelinek 0.94-1 +- upgrade to 0.94 + +* Fri Jan 16 2004 Jakub Jelinek 0.93-1 +- upgrade to 0.93 + +* Thu Jan 8 2004 Jakub Jelinek 0.92-1 +- full version +- macroized spec file for GPL or OSL builds +- include only libelf under GPL plus wrapper scripts + +* Wed Jan 7 2004 Jakub Jelinek 0.91-2 +- macroized spec file for GPL or OSL builds + +* Wed Jan 7 2004 Ulrich Drepper +- split elfutils-devel into two packages. + +* Wed Jan 7 2004 Jakub Jelinek 0.91-1 +- include only libelf under GPL plus wrapper scripts + +* Tue Dec 23 2003 Jeff Johnson 0.89-3 +- readelf, not readline, in %%description (#111214). + +* Fri Sep 26 2003 Bill Nottingham 0.89-1 +- update to 0.89 (fix eu-strip) + +* Tue Sep 23 2003 Jakub Jelinek 0.86-3 +- update to 0.86 (fix eu-strip on s390x/alpha) +- libebl is an archive now; remove references to DSO + +* Mon Jul 14 2003 Jeff Johnson 0.84-3 +- upgrade to 0.84 (readelf/elflint improvements, rawhide bugs fixed). + +* Fri Jul 11 2003 Jeff Johnson 0.83-3 +- upgrade to 0.83 (fix invalid ELf handle on *.so strip, more). + +* Wed Jul 9 2003 Jeff Johnson 0.82-3 +- upgrade to 0.82 (strip tests fixed on big-endian). + +* Tue Jul 8 2003 Jeff Johnson 0.81-3 +- upgrade to 0.81 (strip excludes unused symtable entries, test borked). + +* Thu Jun 26 2003 Jeff Johnson 0.80-3 +- upgrade to 0.80 (debugedit changes for kernel in progress). + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Wed May 21 2003 Jeff Johnson 0.79-2 +- upgrade to 0.79 (correct formats for size_t, more of libdw "works"). + +* Mon May 19 2003 Jeff Johnson 0.78-2 +- upgrade to 0.78 (libdwarf bugfix, libdw additions). + +* Mon Feb 24 2003 Elliot Lee +- debuginfo rebuild + +* Thu Feb 20 2003 Jeff Johnson 0.76-2 +- use the correct way of identifying the section via the sh_info link. + +* Sat Feb 15 2003 Jakub Jelinek 0.75-2 +- update to 0.75 (eu-strip -g fix) + +* Tue Feb 11 2003 Jakub Jelinek 0.74-2 +- update to 0.74 (fix for writing with some non-dirty sections) + +* Thu Feb 6 2003 Jeff Johnson 0.73-3 +- another -0.73 update (with sparc fixes). +- do "make check" in %%check, not %%install, section. + +* Mon Jan 27 2003 Jeff Johnson 0.73-2 +- update to 0.73 (with s390 fixes). + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Wed Jan 22 2003 Jakub Jelinek 0.72-4 +- fix arguments to gelf_getsymshndx and elf_getshstrndx +- fix other warnings +- reenable checks on s390x + +* Sat Jan 11 2003 Karsten Hopp 0.72-3 +- temporarily disable checks on s390x, until someone has + time to look at it + +* Thu Dec 12 2002 Jakub Jelinek 0.72-2 +- update to 0.72 + +* Wed Dec 11 2002 Jakub Jelinek 0.71-2 +- update to 0.71 + +* Wed Dec 11 2002 Jeff Johnson 0.69-4 +- update to 0.69. +- add "make check" and segfault avoidance patch. +- elfutils-libelf needs to run ldconfig. + +* Tue Dec 10 2002 Jeff Johnson 0.68-2 +- update to 0.68. + +* Fri Dec 6 2002 Jeff Johnson 0.67-2 +- update to 0.67. + +* Tue Dec 3 2002 Jeff Johnson 0.65-2 +- update to 0.65. + +* Mon Dec 2 2002 Jeff Johnson 0.64-2 +- update to 0.64. + +* Sun Dec 1 2002 Ulrich Drepper 0.64 +- split packages further into elfutils-libelf + +* Sat Nov 30 2002 Jeff Johnson 0.63-2 +- update to 0.63. + +* Fri Nov 29 2002 Ulrich Drepper 0.62 +- Adjust for dropping libtool + +* Sun Nov 24 2002 Jeff Johnson 0.59-2 +- update to 0.59 + +* Thu Nov 14 2002 Jeff Johnson 0.56-2 +- update to 0.56 + +* Thu Nov 7 2002 Jeff Johnson 0.54-2 +- update to 0.54 + +* Sun Oct 27 2002 Jeff Johnson 0.53-2 +- update to 0.53 +- drop x86_64 hack, ICE fixed in gcc-3.2-11. + +* Sat Oct 26 2002 Jeff Johnson 0.52-3 +- get beehive to punch a rhpkg generated package. + +* Wed Oct 23 2002 Jeff Johnson 0.52-2 +- build in 8.0.1. +- x86_64: avoid gcc-3.2 ICE on x86_64 for now. + +* Tue Oct 22 2002 Ulrich Drepper 0.52 +- Add libelf-devel to conflicts for elfutils-devel + +* Mon Oct 21 2002 Ulrich Drepper 0.50 +- Split into runtime and devel package + +* Fri Oct 18 2002 Ulrich Drepper 0.49 +- integrate into official sources + +* Wed Oct 16 2002 Jeff Johnson 0.46-1 +- Swaddle. diff --git a/config/install-sh b/config/install-sh new file mode 100644 index 00000000..398a88e1 --- /dev/null +++ b/config/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + : +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=$mkdirprog + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + : + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + : + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + : + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' + ' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + : + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + : + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/config/missing b/config/missing new file mode 100644 index 00000000..dd583709 --- /dev/null +++ b/config/missing @@ -0,0 +1,336 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright 1996, 1997, 1999, 2000 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# 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 2, 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing 0.4 - GNU automake" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. + You can get \`$1Help2man' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then + # We have makeinfo, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + tar) + shift + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + fi + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar ${1+"$@"} && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar ${1+"$@"} && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" ${1+"$@"} && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" ${1+"$@"} && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/config/mkinstalldirs b/config/mkinstalldirs new file mode 100644 index 00000000..4fbbc3e8 --- /dev/null +++ b/config/mkinstalldirs @@ -0,0 +1,101 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.1.1.1 2003/08/12 06:44:46 drepper Exp $ + +errstatus=0 +dirmode="" + +usage="\ +Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." + +# process command line arguments +while test $# -gt 0 ; do + case "${1}" in + -h | --help | --h* ) # -h for help + echo "${usage}" 1>&2; exit 0 ;; + -m ) # -m PERM arg + shift + test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; } + dirmode="${1}" + shift ;; + -- ) shift; break ;; # stop option processing + -* ) echo "${usage}" 1>&2; exit 1 ;; # unknown option + * ) break ;; # first non-opt arg + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in +0) exit 0 ;; +esac + +case $dirmode in +'') + if mkdir -p -- . 2>/dev/null; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + fi ;; +*) + if mkdir -m "$dirmode" -p -- . 2>/dev/null; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + fi ;; +esac + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + + lasterr="" + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 3 +# End: +# mkinstalldirs ends here diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..12cd5518 --- /dev/null +++ b/configure.ac @@ -0,0 +1,276 @@ +dnl Process this file with autoconf to produce a configure script. +dnl Configure input file for elfutils. -*-autoconf-*- +dnl +dnl Copyright (C) 1996-2002, 2003, 2004, 2005 Red Hat, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation, version 2. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software Foundation, +dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +dnl +AC_INIT([Red Hat elfutils],[0.110],[http://bugzilla.redhat.com/bugzilla/], + [elfutils]) + +AC_CONFIG_AUX_DIR([config]) +AC_CONFIG_FILES([config/Makefile]) + +AC_COPYRIGHT([Copyright (C) 1996-2003, 2004, 2005 Red Hat, Inc.]) +AC_PREREQ(2.59) dnl Minimum Autoconf version required. + +AM_INIT_AUTOMAKE([gnits 1.7]) + +dnl Unique ID for this build. +MODVERSION="Build on $(hostname) $(date +%FT%R:%S%z)" +AC_SUBST([MODVERSION]) +AC_DEFINE_UNQUOTED(MODVERSION, "$MODVERSION") +AH_TEMPLATE([MODVERSION], [Identifier for modules in the build.]) + +AC_CONFIG_SRCDIR([libelf/libelf.h]) +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_HEADERS([config.h]) + +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_FILES([m4/Makefile]) + +dnl The RPM spec file. We substitute a few values in the file. +AC_CONFIG_FILES([elfutils.spec:config/elfutils.spec.in]) + + +AC_CANONICAL_HOST + +AC_ARG_ENABLE([tls], +AS_HELP_STRING([--enable-tls], [enable use of thread local storage]), +AC_DEFINE(USE_TLS)) +AH_TEMPLATE([USE_TLS], [Defined if thread local storage should be used.]) + +dnl Add all the languages for which translations are available. +ALL_LINGUAS= + +AC_PROG_CC +AC_PROG_RANLIB +AC_PROG_YACC +AM_PROG_LEX + +AC_CACHE_CHECK([for gcc with C99 support], ac_cv_c99, [dnl +old_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -std=gnu99" +AC_COMPILE_IFELSE([dnl +int foo (int a) { for (int i = 0; i < a; ++i) if (i % 4) break; int s = a; }], + ac_cv_c99=yes, ac_cv_c99=no) +CFLAGS="$old_CFLAGS"]) +AS_IF([test "x$ac_cv_c99" != xyes], + AC_MSG_ERROR([gcc with C99 support required])) + +LOCALEDIR=$datadir +AC_SUBST(LOCALEDIR) +AC_DEFINE_UNQUOTED(LOCALEDIR, "$LOCALEDIR") +AH_TEMPLATE([LOCALEDIR], [Directory to place translation files in.]) + +DATADIRNAME=$datadir +AC_SUBST(DATADIRNAME) + +dnl This test must come as early as possible after the compiler configuration +dnl tests, because the choice of the file model can (in principle) affect +dnl whether functions and headers are available, whether they work, etc. +AC_SYS_LARGEFILE + +dnl Enable the linker to be build as a native-only linker. By default it +dnl can handle all architectures but this comes at a cost. A native +dnl will be slightly faster, small, and has fewer dependencies. +native_ld=no +AC_ARG_ENABLE([generic], +AS_HELP_STRING([--disable-generic], [do not build generic linker]), [dnl +if test "$enable_generic" = no; then + case "$host_cpu" in + i?86) + AC_DEFINE(NATIVE_ELF, 32) + native_ld=yes + base_cpu=i386 + ;; + *) + AC_MSG_ERROR([no machine-specific linker for this configuration available]) + ;; + esac +fi]) +AH_TEMPLATE([NATIVE_ELF], +[Define to 32 or 64 if a specific implementation is wanted.]) +AM_CONDITIONAL(NATIVE_LD, test "$native_ld" = yes) +dnl The automake generated Makefile cannot deal with macros in the name +dnl of files if at any time there is no such file, even if the filename +dnl would not be used. +AS_IF([test -z "$base_cpu"], [base_cpu=none]) +AC_SUBST(base_cpu) + +dnl Enable debugging via mudflap. This option will cause most libraries +dnl to be built as archives which are statically linked into the applications. +dnl All code, as far as possible, is compiled instrumented to catch all +dnl the bugs valgrind is able to catch. +use_mudflap=no +AC_ARG_ENABLE([mudflap], +AS_HELP_STRING([--enable-mudflap], +[build binaries with mudflap instrumentation]), [dnl +if test "x$enable_mudflap" = xyes; then + # Check whether the compiler support -fmudflap. + old_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fmudflap" + AC_TRY_COMPILE([], [], use_mudflap=yes, use_mudflap=fail) + CFLAGS="$old_CFLAGS" +fi]) +if test "$use_mudflap" = fail; then + AC_MSG_FAILURE([--enable-mudflap requires a compiler which understands this option]) +fi +AM_CONDITIONAL(MUDFLAP, test "$use_mudflap" = yes) + +LIBEBL_SUBDIR="$PACKAGE" +AC_ARG_ENABLE([libebl-subdir], +AS_HELP_STRING([--enable-libebl-subdir=DIR], +[install libebl_CPU modules in $(libdir)/DIR]), [dnl +LIBEBL_SUBDIR="$enable_libebl_subdir"]) +AC_SUBST([LIBEBL_SUBDIR]) +AC_DEFINE_UNQUOTED(LIBEBL_SUBDIR, "$LIBEBL_SUBDIR") +AH_TEMPLATE([LIBEBL_SUBDIR], [$libdir subdirectory containing libebl modules.]) + +dnl The directories with content. + +dnl Documentation. +dnl Commented out for now. +dnl AC_CONFIG_FILES([doc/Makefile]) + +dnl Support library. +AC_CONFIG_FILES([lib/Makefile]) + +dnl ELF library. +AC_CONFIG_FILES([libelf/Makefile libelf-po/Makefile.in]) + +dnl Higher-level ELF support library. +AC_CONFIG_FILES([libebl/Makefile]) + +dnl DWARF library. +AC_CONFIG_FILES([libdw/Makefile]) + +dnl Higher-level DWARF support library. +AC_CONFIG_FILES([libdwfl/Makefile]) + +dnl CPU handling library. +AC_CONFIG_FILES([libcpu/Makefile]) + +dnl Assembler library. +AC_CONFIG_FILES([libasm/Makefile]) + +dnl Tools. +AC_CONFIG_FILES([src/Makefile po/Makefile.in]) + +dnl Test suite. +AC_CONFIG_FILES([tests/Makefile]) + +# Get the definitions necessary to create the Makefiles in the po +# subdirectories. This is a small subset of the gettext rules. +AC_SUBST(USE_NLS, yes) +AM_PO_SUBDIRS + + +dnl Test of the config.h file. We hide all kinds of configuration magic +dnl in there. +AH_BOTTOM([ +/* Eventually we will allow multi-threaded applications to use the + libraries. Therefore we will add the necessary locking although + the macros used expand to nothing for now. */ +#define lock_lock(lock) ((void) (lock)) +#define rwlock_define(class,name) class int name +#define rwlock_init(lock) ((void) (lock)) +#define rwlock_fini(lock) ((void) (lock)) +#define rwlock_rdlock(lock) ((void) (lock)) +#define rwlock_wrlock(lock) ((void) (lock)) +#define rwlock_unlock(lock) ((void) (lock)) +#define tls_key_t void * +#define key_create(keyp, freefct) (1) +#define getspecific(key) key +#define setspecific(key,val) key = val +#define once_define(class,name) class int name +#define once_execute(name,fct) \ + do { \ + if (name == 0) \ + fct (); \ + name = 1; \ + } while (0) + +/* gettext helper macro. */ +#define N_(Str) Str + +/* Compiler-specific definitions. */ +#define strong_alias(name, aliasname) \ + extern __typeof (name) aliasname __attribute__ ((alias (#name))); + +#ifdef __i386__ +# define internal_function_def __attribute__ ((regparm (3), stdcall)) +#else +# define internal_function_def /* nothing */ +#endif + +# define internal_function \ + internal_function_def __attribute__ ((visibility ("internal"))) +# define internal_strong_alias(name, aliasname) \ + extern __typeof (name) aliasname __attribute__ ((alias (#name), visibility ("internal"))) internal_function_def; + +#define attribute_hidden \ + __attribute__ ((visibility ("hidden"))) + +/* Define ALLOW_UNALIGNED if the architecture allows operations on + unaligned memory locations. */ +#if defined __i386__ || defined __alpha__ || defined __x86_64__ || defined __ia64__ +# define ALLOW_UNALIGNED 1 +#else +# define ALLOW_UNALIGNED 0 +#endif + +#define unlikely(expr) __builtin_expect (expr, 0) +#define likely(expr) __builtin_expect (expr, 1) + +#define obstack_calloc(ob, size) \ + ({ size_t _s = (size); memset (obstack_alloc (ob, _s), '\0', _s); }) +#define obstack_strdup(ob, str) \ + ({ const char *_s = (str); obstack_copy0 (ob, _s, strlen (_s)); }) +#define obstack_strndup(ob, str, n) \ + ({ const char *_s = (str); obstack_copy0 (ob, _s, strnlen (_s, n)); }) + +#if __STDC_VERSION__ >= 199901L +# define flexarr_size /* empty */ +#else +# define flexarr_size 0 +#endif + +/* Calling conventions. */ +#ifdef __i386__ +# define CALLING_CONVENTION regparm (3), stdcall +# define AND_CALLING_CONVENTION , regparm (3), stdcall +#else +# define CALLING_CONVENTION +# define AND_CALLING_CONVENTION +#endif + +/* Avoid PLT entries. */ +#ifdef PIC +# define INTUSE(name) _INTUSE(name) +# define _INTUSE(name) __##name##_internal +# define INTDEF(name) _INTDEF(name) +# define _INTDEF(name) \ + extern __typeof__ (name) __##name##_internal __attribute__ ((alias (#name))); +# define INTDECL(name) _INTDECL(name) +# define _INTDECL(name) \ + extern __typeof__ (name) __##name##_internal attribute_hidden; +#else +# define INTUSE(name) name +# define INTDEF(name) /* empty */ +# define INTDECL(name) /* empty */ +#endif +]) + +AC_OUTPUT diff --git a/doc/.cvsignore b/doc/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/doc/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/doc/ChangeLog b/doc/ChangeLog new file mode 100644 index 00000000..380a0cd7 --- /dev/null +++ b/doc/ChangeLog @@ -0,0 +1,12 @@ +2005-04-29 Ulrich Drepper + + * elfutils.sgml: Some typo fixes and a few extensions. + Patch by Eric Christopher . + +2005-02-22 Ulrich Drepper + + * Makefile.am: Prefer pdf. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 00000000..9297306d --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,29 @@ +## Process this file with automake to create Makefile.in +## Configure input file for elfutils. +## +## Copyright (C) 1996-2001, 2002, 2005 Red Hat, Inc. +## +## This program is Open Source software; you can redistribute it and/or +## modify it under the terms of the Open Software License version 1.0 as +## published by the Open Source Initiative. +## +## You should have received a copy of the Open Software License along +## with this program; if not, you may obtain a copy of the Open Software +## License version 1.0 from http://www.opensource.org/licenses/osl.php or +## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +## 3001 King Ranch Road, Ukiah, CA 95482. */ +## +EXTRA_DIST = elfutils.sgml + +CLEANFILES = elfutils.dvi + +# We need only a few special rules to generate the various output formats +# from the SGML sources. +.PHONY: dvi pdf html +pdf: $(srcdir)elfutils.pdf +dvi: $(srcdir)elfutils.dvi + +$(srcdir)%.dvi: %.sgml + db2dvi $^ +$(srcdir)%.pdf: %.sgml + db2pdf $^ diff --git a/doc/elfutils.sgml b/doc/elfutils.sgml new file mode 100644 index 00000000..d7fea40d --- /dev/null +++ b/doc/elfutils.sgml @@ -0,0 +1,444 @@ +new-bu"> +]> + + + New Binutils User's and Reference Manual + + + <filename>libelf</filename> <acronym>ABI</acronym> + + The ABI of the + libelf implemented in the &package; package + is following that of Sun's implementation which in turn in derived + from the original SysVr4 implementation. There are some + extensions over Sun's versions, though, which makes it impossible + to replace this implementation with Sun's. + + + + + + Elf_Data + Descriptor for Data Buffer + + + + +#include <libelf.h> + + + + + Description + + The Elf_Data structure is as + a descriptor for a data buffer associated with a section. + Every data buffer is associated with a specific section (see + Elf_Scn). + + A data buffer is created when reading a file. In + this case only a single buffer is present in the section. The + user can add as many sections as wanted to a section and they + can be retrieved using the elf_getdata + and elf_rawdata functions. + + The Elf_Data structure + contains the following members: + + + void *d_buf + Elf_Type d_type + size_t d_size + off_t d_off + size_t d_align + unsigned int d_version + + + All of these members can be modified directly by the + user. They can be used to resize a section, to change its + content or type, and many more tasks. This is also true for + the data read from a file. The meaning of each member is as + follows: + + + + d_buf + + The d_buf member is + the pointer to the buffer with the actual data. When + the ELF file was read from a file the first and only + data buffer of a section is allocated by the + libelf library. The user should + not try to resize or free this buffer. When the user + adds a new data buffer to a section the associated + memory block is normally allocated by the user. It is + important that the buffer must have a lifetime at least + until the ELF file is closed entirely (important when + the buffer is allocated on the stack). If the buffer is + not allocated on the stack it is the user's + responsibility to free the buffer after it is not used + anymore. The d_buf member + can contain a null pointer if the data buffer is + empty. + + + + + d_type + + The d_type + determines how the data of the buffer is interpreted. + This type is determined from the section type and must + be the same for all data buffers for a section. See + Elf_Type for more information. + The + function uses this information to convert the data of + the buffer between the external form and the form + represented to the user and back if necessary. + + + + + d_version + + The d_version + contains the ELF version of the file. + + + + + d_size + + The d_size contains + the size of the buffer in bytes. + + + + + d_off + + The d_off is the + offset into the section in bytes. + + + + + d_align + + The d_align is the + address alignment of the section in bytes. + + + + + + + + + + + elf_getdata + Get washed data of section + + + + + +#include <libelf.h> + + + Elf_Data *elf_getdata + Elf_Scn *scn + Elf_Data *data + + + + + + Description + + The elf_getdata function allows + the user to retrieve the data buffers of the section + scn. There can be more than one buffer + if the user explicitly added them. When a file is read the + libelf library creates exactly one data + buffer. + + The first buffer in the list can be obtained by + passing a null pointer in the parameter + data. To get the next data buffer the + previously returned value must be passed in the + data parameter. If there are no more + buffer left in the list a null pointer is returned. + + If the data parameter is not a + null pointer it must be a descriptor for a buffer + associated with the section scn. If + this is not the case a null pointer is returned. To + facilitate error handling elf_getdata + also returns a null pointer if the scn + parameter is a null pointer. + + + + + + elf_update + update an ELF descriptor + + + + + +#include <libelf.h> + + + off_t elf_update + Elf *elf + Elf_Cmd cmd + + + + + + Description + + The user is responsible for filling in the following + fields in the named data structures: + + + Fields not set by <function>elf_update</function> + + + + + + Data Structure + Member + Exception + + + + + Elfxx_Ehdr + e_ident[EI_DATA] + see below + + + + e_type + + + + + + e_machine + + + + + e_version + see below + + + + e_entry + + + + + e_phoff + if ELF_F_LAYOUT is used + + + + e_shoff + if ELF_F_LAYOUT is used + + + + e_flags + + + + + e_shstrndx + + + + Elfxx_Phdr + p_type + + + + + p_offset + + + + + p_vaddr + + + + + p_paddr + + + + + p_filesz + + + + + p_memsz + + + + + p_flags + + + + + p_align + + + + + Elfxx_Shdr + sh_name + + + + + sh_type + + + + + sh_flags + + + + + sh_addr + + + + + sh_offset + if ELF_F_LAYOUT is used + + + + sh_size + if ELF_F_LAYOUT is used + + + + sh_link + + + + + + sh_info + + + + + sh_addralign + if ELF_F_LAYOUT is used + + + + sh_entsize + + + + + Elf_Data + d_buf + + + + + d_type + + + + + d_size + + + + + d_off + if ELF_F_LAYOUT is used + + + + d_align + + + + + + d_version + + + + +
+ + Two fields of the ELF header are handled in a special + way: + + + + e_version + + The user can set this field to the vvalue for + the version to be used. It is an error if the library + cannot handle this version. If the field contains the + value EV_NONE the library will fill in + its own internal version. + + + + + e_ident[EI_DATA] + + The user should fill in the byte ordering for + the file. If the value of the field is + ELFDATANONE the library replaces it + with the native byte ordering for the machine. + + + +
+
+
+ + + <filename>libelf</filename> Internals + + Since the binary format handling tools need constant + attention since there are always new machines and varients + therefore coming out it is important to have the implementation + well documented. Only this way extensions can be made in the + right places and the mistakes of the past avoided. + +
+ diff --git a/fake-src/FULL b/fake-src/FULL new file mode 100644 index 00000000..15e65684 --- /dev/null +++ b/fake-src/FULL @@ -0,0 +1,3 @@ +The full elfutils package is available from Red Hat's web site at: + + ***FILE ME IN*** diff --git a/fake-src/Makefile.am b/fake-src/Makefile.am new file mode 100644 index 00000000..d8b0ffff --- /dev/null +++ b/fake-src/Makefile.am @@ -0,0 +1,24 @@ +## Process this file with automake to create Makefile.in +## Configure input file for elfutils. +## +## Copyright (C) 1996-2002, 2003, 2004, 2005 Red Hat, 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, version 2. +## +## 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, write to the Free Software Foundation, +## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +bin_SCRIPTS = readelf nm size strip elflint addr2line +EXTRA_DIST = readelf nm size strip elflint.in addr2line FULL +include_HEADERS = dwarf.h + +elflint: $(srcdir)/elflint.in + sed "s/@EUVERSION@/$(VERSION)/" $< > $@ diff --git a/fake-src/Makefile.in b/fake-src/Makefile.in new file mode 100644 index 00000000..0c2d41dd --- /dev/null +++ b/fake-src/Makefile.in @@ -0,0 +1,390 @@ +# Makefile.in generated by automake 1.7.9 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = @host@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GMSGFMT = @GMSGFMT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LOCALEDIR = @LOCALEDIR@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGMERGE = @MSGMERGE@ +NATIVE_LD_FALSE = @NATIVE_LD_FALSE@ +NATIVE_LD_TRUE = @NATIVE_LD_TRUE@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +base_cpu = @base_cpu@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +bin_SCRIPTS = readelf nm size strip elflint +EXTRA_DIST = readelf nm size strip elflint.in FULL +include_HEADERS = dwarf.h +subdir = fake-src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SCRIPTS = $(bin_SCRIPTS) + +DIST_SOURCES = +HEADERS = $(include_HEADERS) + +DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.in Makefile.am +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnits fake-src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +binSCRIPT_INSTALL = $(INSTALL_SCRIPT) +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f $$d$$p; then \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " $(binSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(bindir)/$$f"; \ + $(binSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +installcheck-binSCRIPTS: $(bin_SCRIPTS) + bad=0; pid=$$$$; list="$(bin_SCRIPTS)"; for p in $$list; do \ + case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ + *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ + esac; \ + f=`echo "$$p" | sed 's,^.*/,,;$(transform)'`; \ + for opt in --help --version; do \ + if $(DESTDIR)$(bindir)/$$f $$opt > c$${pid}_.out 2> c$${pid}_.err \ + && test -n "`cat c$${pid}_.out`" \ + && test -z "`cat c$${pid}_.err`"; then :; \ + else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ + done; \ + done; rm -f c$${pid}_.???; exit $$bad +uninstall-info-am: +includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(includedir) + @list='$(include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(includedir)/$$f"; \ + $(includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(includedir)/$$f; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(includedir)/$$f"; \ + rm -f $(DESTDIR)$(includedir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(SCRIPTS) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(includedir) +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-includeHEADERS + +install-exec-am: install-binSCRIPTS + +install-info: install-info-am + +install-man: + +installcheck-am: installcheck-binSCRIPTS + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binSCRIPTS uninstall-includeHEADERS \ + uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic ctags \ + distclean distclean-generic distclean-tags distdir dvi dvi-am \ + info info-am install install-am install-binSCRIPTS install-data \ + install-data-am install-exec install-exec-am \ + install-includeHEADERS install-info install-info-am install-man \ + install-strip installcheck installcheck-am \ + installcheck-binSCRIPTS installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binSCRIPTS uninstall-includeHEADERS uninstall-info-am + + +elflint: $(srcdir)/elflint.in + sed "s/@EUVERSION@/$(VERSION)/" $< > $@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/fake-src/addr2line b/fake-src/addr2line new file mode 100644 index 00000000..d7ed0d54 --- /dev/null +++ b/fake-src/addr2line @@ -0,0 +1,2 @@ +#!/bin/bash +exec addr2line "$@" diff --git a/fake-src/dwarf.h b/fake-src/dwarf.h new file mode 100644 index 00000000..a1daaf18 --- /dev/null +++ b/fake-src/dwarf.h @@ -0,0 +1,557 @@ +/* This file defines standard DWARF types, structures, and macros. + Copyright (C) 2000, 2002 Red Hat, 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _DWARF_H +#define _DWARF_H 1 + +/* DWARF tags. */ +enum + { + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_param = 0x2f, + DW_TAG_template_value_param = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + DW_TAG_lo_user = 0x4080, + DW_TAG_MIPS_loop = 0x4081, + DW_TAG_format_label = 0x4101, + DW_TAG_function_template = 0x4102, + DW_TAG_class_template = 0x4103, + DW_TAG_hi_user = 0xffff + }; + + +/* Children determination encodings. */ +enum + { + DW_CHILDREN_no = 0, + DW_CHILDREN_yes = 1 + }; + + +/* DWARF attributes encodings. */ +enum + { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_stride_size = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_items = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + DW_AT_lo_user = 0x2000, + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + DW_AT_MIPS_stride_byte = 0x200c, + DW_AT_MIPS_stride_elem = 0x200d, + DW_AT_MIPS_ptr_dopetype = 0x200e, + DW_AT_MIPS_allocatable_dopetype = 0x200f, + DW_AT_MIPS_assumed_shape_dopetype = 0x2010, + DW_AT_MIPS_assumed_size = 0x2011, + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_hi_user = 0x3fff + }; + + +/* DWARF form encodings. */ +enum + { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16 + }; + + +/* DWARF location operation encodings. */ +enum + { + DW_OP_addr = 0x03, /* Constant address. */ + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, /* Unsigned 1-byte constant. */ + DW_OP_const1s = 0x09, /* Signed 1-byte constant. */ + DW_OP_const2u = 0x0a, /* Unsigned 2-byte constant. */ + DW_OP_const2s = 0x0b, /* Signed 2-byte constant. */ + DW_OP_const4u = 0x0c, /* Unsigned 4-byte constant. */ + DW_OP_const4s = 0x0d, /* Signed 4-byte constant. */ + DW_OP_const8u = 0x0e, /* Unsigned 8-byte constant. */ + DW_OP_const8s = 0x0f, /* Signed 8-byte constant. */ + DW_OP_constu = 0x10, /* Unsigned LEB128 constant. */ + DW_OP_consts = 0x11, /* Signed LEB128 constant. */ + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, /* 1-byte stack index. */ + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, /* Unsigned LEB128 addend. */ + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, /* Signed 2-byte constant. */ + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_skip = 0x2f, /* Signed 2-byte constant. */ + DW_OP_lit0 = 0x30, /* Literal 0. */ + DW_OP_lit1 = 0x31, /* Literal 1. */ + DW_OP_lit2 = 0x32, /* Literal 2. */ + DW_OP_lit3 = 0x33, /* Literal 3. */ + DW_OP_lit4 = 0x34, /* Literal 4. */ + DW_OP_lit5 = 0x35, /* Literal 5. */ + DW_OP_lit6 = 0x36, /* Literal 6. */ + DW_OP_lit7 = 0x37, /* Literal 7. */ + DW_OP_lit8 = 0x38, /* Literal 8. */ + DW_OP_lit9 = 0x39, /* Literal 9. */ + DW_OP_lit10 = 0x3a, /* Literal 10. */ + DW_OP_lit11 = 0x3b, /* Literal 11. */ + DW_OP_lit12 = 0x3c, /* Literal 12. */ + DW_OP_lit13 = 0x3d, /* Literal 13. */ + DW_OP_lit14 = 0x3e, /* Literal 14. */ + DW_OP_lit15 = 0x3f, /* Literal 15. */ + DW_OP_lit16 = 0x40, /* Literal 16. */ + DW_OP_lit17 = 0x41, /* Literal 17. */ + DW_OP_lit18 = 0x42, /* Literal 18. */ + DW_OP_lit19 = 0x43, /* Literal 19. */ + DW_OP_lit20 = 0x44, /* Literal 20. */ + DW_OP_lit21 = 0x45, /* Literal 21. */ + DW_OP_lit22 = 0x46, /* Literal 22. */ + DW_OP_lit23 = 0x47, /* Literal 23. */ + DW_OP_lit24 = 0x48, /* Literal 24. */ + DW_OP_lit25 = 0x49, /* Literal 25. */ + DW_OP_lit26 = 0x4a, /* Literal 26. */ + DW_OP_lit27 = 0x4b, /* Literal 27. */ + DW_OP_lit28 = 0x4c, /* Literal 28. */ + DW_OP_lit29 = 0x4d, /* Literal 29. */ + DW_OP_lit30 = 0x4e, /* Literal 30. */ + DW_OP_lit31 = 0x4f, /* Literal 31. */ + DW_OP_reg0 = 0x50, /* Register 0. */ + DW_OP_reg1 = 0x51, /* Register 1. */ + DW_OP_reg2 = 0x52, /* Register 2. */ + DW_OP_reg3 = 0x53, /* Register 3. */ + DW_OP_reg4 = 0x54, /* Register 4. */ + DW_OP_reg5 = 0x55, /* Register 5. */ + DW_OP_reg6 = 0x56, /* Register 6. */ + DW_OP_reg7 = 0x57, /* Register 7. */ + DW_OP_reg8 = 0x58, /* Register 8. */ + DW_OP_reg9 = 0x59, /* Register 9. */ + DW_OP_reg10 = 0x5a, /* Register 10. */ + DW_OP_reg11 = 0x5b, /* Register 11. */ + DW_OP_reg12 = 0x5c, /* Register 12. */ + DW_OP_reg13 = 0x5d, /* Register 13. */ + DW_OP_reg14 = 0x5e, /* Register 14. */ + DW_OP_reg15 = 0x5f, /* Register 15. */ + DW_OP_reg16 = 0x60, /* Register 16. */ + DW_OP_reg17 = 0x61, /* Register 17. */ + DW_OP_reg18 = 0x62, /* Register 18. */ + DW_OP_reg19 = 0x63, /* Register 19. */ + DW_OP_reg20 = 0x64, /* Register 20. */ + DW_OP_reg21 = 0x65, /* Register 21. */ + DW_OP_reg22 = 0x66, /* Register 22. */ + DW_OP_reg23 = 0x67, /* Register 24. */ + DW_OP_reg24 = 0x68, /* Register 24. */ + DW_OP_reg25 = 0x69, /* Register 25. */ + DW_OP_reg26 = 0x6a, /* Register 26. */ + DW_OP_reg27 = 0x6b, /* Register 27. */ + DW_OP_reg28 = 0x6c, /* Register 28. */ + DW_OP_reg29 = 0x6d, /* Register 29. */ + DW_OP_reg30 = 0x6e, /* Register 30. */ + DW_OP_reg31 = 0x6f, /* Register 31. */ + DW_OP_breg0 = 0x70, /* Base register 0. */ + DW_OP_breg1 = 0x71, /* Base register 1. */ + DW_OP_breg2 = 0x72, /* Base register 2. */ + DW_OP_breg3 = 0x73, /* Base register 3. */ + DW_OP_breg4 = 0x74, /* Base register 4. */ + DW_OP_breg5 = 0x75, /* Base register 5. */ + DW_OP_breg6 = 0x76, /* Base register 6. */ + DW_OP_breg7 = 0x77, /* Base register 7. */ + DW_OP_breg8 = 0x78, /* Base register 8. */ + DW_OP_breg9 = 0x79, /* Base register 9. */ + DW_OP_breg10 = 0x7a, /* Base register 10. */ + DW_OP_breg11 = 0x7b, /* Base register 11. */ + DW_OP_breg12 = 0x7c, /* Base register 12. */ + DW_OP_breg13 = 0x7d, /* Base register 13. */ + DW_OP_breg14 = 0x7e, /* Base register 14. */ + DW_OP_breg15 = 0x7f, /* Base register 15. */ + DW_OP_breg16 = 0x80, /* Base register 16. */ + DW_OP_breg17 = 0x81, /* Base register 17. */ + DW_OP_breg18 = 0x82, /* Base register 18. */ + DW_OP_breg19 = 0x83, /* Base register 19. */ + DW_OP_breg20 = 0x84, /* Base register 20. */ + DW_OP_breg21 = 0x85, /* Base register 21. */ + DW_OP_breg22 = 0x86, /* Base register 22. */ + DW_OP_breg23 = 0x87, /* Base register 23. */ + DW_OP_breg24 = 0x88, /* Base register 24. */ + DW_OP_breg25 = 0x89, /* Base register 25. */ + DW_OP_breg26 = 0x8a, /* Base register 26. */ + DW_OP_breg27 = 0x8b, /* Base register 27. */ + DW_OP_breg28 = 0x8c, /* Base register 28. */ + DW_OP_breg29 = 0x8d, /* Base register 29. */ + DW_OP_breg30 = 0x8e, /* Base register 30. */ + DW_OP_breg31 = 0x8f, /* Base register 31. */ + DW_OP_regx = 0x90, /* Unsigned LEB128 register. */ + DW_OP_fbreg = 0x91, /* Signed LEB128 register. */ + DW_OP_bregx = 0x92, /* ULEB128 register followed by SLEB128 off. */ + DW_OP_piece = 0x93, /* ULEB128 size of piece addressed. */ + DW_OP_deref_size = 0x94, /* 1-byte size of data retrieved. */ + DW_OP_xderef_size = 0x95, /* 1-byte size of data retrieved. */ + DW_OP_nop = 0x96, + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + + DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */ + DW_OP_hi_user = 0xff /* Implementation-defined range end. */ + }; + + +/* DWARF base type encodings. */ +enum + { + DW_ATE_void = 0x0, + DW_ATE_address = 0x1, + DW_ATE_boolean = 0x2, + DW_ATE_complex_float = 0x3, + DW_ATE_float = 0x4, + DW_ATE_signed = 0x5, + DW_ATE_signed_char = 0x6, + DW_ATE_unsigned = 0x7, + DW_ATE_unsigned_char = 0x8, + + DW_ATE_lo_user = 0x80, + DW_ATE_hi_user = 0xff + }; + + +/* DWARF accessibility encodings. */ +enum + { + DW_ACCESS_public = 1, + DW_ACCESS_protected = 2, + DW_ACCESS_private = 3 + }; + + +/* DWARF visibility encodings. */ +enum + { + DW_VIS_local = 1, + DW_VIS_exported = 2, + DW_VIS_qualified = 3 + }; + + +/* DWARF virtuality encodings. */ +enum + { + DW_VIRTUALITY_none = 0, + DW_VIRTUALITY_virtual = 1, + DW_VIRTUALITY_pure_virtual = 2 + }; + + +/* DWARF language encodings. */ +enum + { + DW_LANG_C89 = 0x0001, + DW_LANG_C = 0x0002, + DW_LANG_Ada83 = 0x0003, + DW_LANG_C_plus_plus = 0x0004, + DW_LANG_Cobol74 = 0x0005, + DW_LANG_Cobol85 = 0x0006, + DW_LANG_Fortran77 = 0x0007, + DW_LANG_Fortran90 = 0x0008, + DW_LANG_Pascal83 = 0x0009, + DW_LANG_Modula2 = 0x000a, + DW_LANG_Java = 0x000b, + DW_LANG_C99 = 0x000c, + DW_LANG_Ada95 = 0x000d, + DW_LANG_Fortran95 = 0x000e, + DW_LANG_PL1 = 0x000f, + DW_LANG_lo_user = 0x8000, + DW_LANG_Mips_Assembler = 0x8001, + DW_LANG_hi_user = 0xffff + }; + + +/* DWARF identifier case encodings. */ +enum + { + DW_ID_case_sensitive = 0, + DW_ID_up_case = 1, + DW_ID_down_case = 2, + DW_ID_case_insensitive = 3 + }; + + +/* DWARF calling conventions encodings. */ +enum + { + DW_CC_normal = 0x1, + DW_CC_program = 0x2, + DW_CC_nocall = 0x3, + DW_CC_lo_user = 0x40, + DW_CC_hi_user = 0xff + }; + + +/* DWARF inline encodings. */ +enum + { + DW_INL_not_inlined = 0, + DW_INL_inlined = 1, + DW_INL_declared_not_inlined = 2, + DW_INL_declared_inlined = 3 + }; + + +/* DWARF ordering encodings. */ +enum + { + DW_ORD_row_major = 0, + DW_ORD_col_major = 1 + }; + + +/* DWARF discriminant descriptor encodings. */ +enum + { + DW_DSC_label = 0, + DW_DSC_range = 1 + }; + + +/* DWARF standard opcode encodings. */ +enum + { + DW_LNS_copy = 1, + DW_LNS_advance_pc = 2, + DW_LNS_advance_line = 3, + DW_LNS_set_file = 4, + DW_LNS_set_column = 5, + DW_LNS_negate_stmt = 6, + DW_LNS_set_basic_block = 7, + DW_LNS_const_add_pc = 8, + DW_LNS_fixed_advance_pc = 9, + DW_LNS_set_prologue_end = 10, + DW_LNS_set_epilog_begin = 11 + }; + + +/* DWARF extended opcide encodings. */ +enum + { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3 + }; + + +/* DWARF macinfo type encodings. */ +enum + { + DW_MACINFO_define = 1, + DW_MACINFO_undef = 2, + DW_MACINFO_start_file = 3, + DW_MACINFO_end_file = 4, + DW_MACINFO_vendor_ext = 255 + }; + + +/* DWARF call frame instruction encodings. */ +enum + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_extended = 0, + + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_low_user = 0x1c, + DW_CFA_MIPS_advance_loc8 = 0x1d, + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_high_user = 0x3f + }; + + +/* DWARF XXX. */ +#define DW_ADDR_none 0 + +#endif /* dwarf.h */ diff --git a/fake-src/elflint.in b/fake-src/elflint.in new file mode 100644 index 00000000..d67af93a --- /dev/null +++ b/fake-src/elflint.in @@ -0,0 +1,4 @@ +#!/bin/bash +printf 'eu-elflint is only available in the full-featured elfutils package\n' 2>&1 +printf 'See /usr/share/doc/elfutils-@EUVERSION@/FULL' +exit 1 diff --git a/fake-src/nm b/fake-src/nm new file mode 100644 index 00000000..52a06747 --- /dev/null +++ b/fake-src/nm @@ -0,0 +1,2 @@ +#!/bin/bash +exec nm "$@" diff --git a/fake-src/readelf b/fake-src/readelf new file mode 100644 index 00000000..6fef6e21 --- /dev/null +++ b/fake-src/readelf @@ -0,0 +1,2 @@ +#!/bin/bash +exec readelf "$@" diff --git a/fake-src/size b/fake-src/size new file mode 100644 index 00000000..0b6b3386 --- /dev/null +++ b/fake-src/size @@ -0,0 +1,2 @@ +#!/bin/bash +exec size "$@" diff --git a/fake-src/strip b/fake-src/strip new file mode 100644 index 00000000..0d1e739d --- /dev/null +++ b/fake-src/strip @@ -0,0 +1,20 @@ +#!/bin/bash +[ "$1" != "-f" -a "$2" != "-f" ] && exec strip "$@" +if [ "$1" = "-f" ]; then + opts= + debug="$2" + file="$3" + [ $# -ne 3 ] && exit 1 + file "$file" 2>/dev/null | grep -q relocatable && opts=-g +elif [ "$1" = "-g" ]; then + opts=-g + debug="$3" + file="$4" + [ $# -ne 4 ] && exit 1 +else + exit 1 +fi +set -e +objcopy --only-keep-debug "$file" "$debug" +strip $opts "$file" +objcopy --add-gnu-debuglink="$debug" "$file" diff --git a/lib/.cvsignore b/lib/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/lib/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/lib/ChangeLog b/lib/ChangeLog new file mode 100644 index 00000000..9ddc2163 --- /dev/null +++ b/lib/ChangeLog @@ -0,0 +1,39 @@ +2005-05-03 Roland McGrath + + * crc32_file.c: New file. + * Makefile.am (libeu_a_SOURCES): Add it. + * system.h: Declare crc32_file. + +2005-04-30 Ulrich Drepper + + * Makefile.am: Use -ffunction-sections for xmalloc.c. + +2005-02-15 Ulrich Drepper + + * dynamicsizehash.c (lookup): Mark val parameter as possibly unused. + +2005-02-06 Ulrich Drepper + + * fixedsizehash.h: Mark unused parameters. Correct CLASS and + const order for fshash_find. + + * Makefile.am: Cleanup AM_CFLAGS handling. Add -Wunused -Wextra. + +2005-02-05 Ulrich Drepper + + * Makefile.am [MUDFLAP] (AM_CFLAGS): Add -fpic and -fmudflap. + +2004-01-17 Ulrich Drepper + + * Makefile.am: Support building with mudflap. + +2003-09-22 Ulrich Drepper + + * Makefile.am (AM_CFLAGS): Add -fpic. + + * Makefile.am (noinst_HEADERS): Add list.h. + * list.h: New file. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 00000000..facb5634 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,35 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 1996-2001, 2002, 2004, 2005 Red Hat, 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, version 2. +## +## 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, write to the Free Software Foundation, +## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H +if MUDFLAP +AM_CFLAGS = -fmudflap +else +AM_CFLAGS = +endif +AM_CFLAGS += -fpic -Wall -Wshadow -Werror -Wunused -Wextra $($(*F)_CFLAGS) +INCLUDES = -I$(srcdir)/../libelf -I.. + +noinst_LIBRARIES = libeu.a + +libeu_a_SOURCES = xstrdup.c xstrndup.c xmalloc.c next_prime.c \ + crc32.c crc32_file.c + +noinst_HEADERS = fixedsizehash.h system.h dynamicsizehash.h list.h +EXTRA_DIST = dynamicsizehash.c + +xmalloc_CFLAGS = -ffunction-sections diff --git a/lib/crc32.c b/lib/crc32.c new file mode 100644 index 00000000..a198e8e4 --- /dev/null +++ b/lib/crc32.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2002 Red Hat, 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include "system.h" + + +/* Table computed with Mark Adler's makecrc.c utility. */ +static const uint32_t crc32_table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d +}; + +uint32_t +crc32 (uint32_t crc, unsigned char *buf, size_t len) +{ + unsigned char *end; + + crc = ~crc; + for (end = buf + len; buf < end; ++buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc; +} diff --git a/lib/crc32_file.c b/lib/crc32_file.c new file mode 100644 index 00000000..e6d468b4 --- /dev/null +++ b/lib/crc32_file.c @@ -0,0 +1,59 @@ +#include "system.h" +#include +#include +#include +#include + +int +crc32_file (int fd, uint32_t *resp) +{ + unsigned char buffer[1024 * 8]; + uint32_t crc = 0; + off_t off = 0; + ssize_t count; + + struct stat st; + if (fstat (fd, &st) == 0) + { + /* Try mapping in the file data. */ + size_t mapsize = st.st_size; + void *mapped = mmap (NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0); + if (mapped == MAP_FAILED && errno == ENOMEM) + { + const size_t pagesize = sysconf (_SC_PAGE_SIZE); + mapsize = ((mapsize / 2) + pagesize - 1) & -pagesize; + while (mapsize >= pagesize + && (mapped = mmap (NULL, mapsize, PROT_READ, MAP_PRIVATE, + fd, 0)) == MAP_FAILED && errno == ENOMEM) + mapsize /= 2; + } + if (mapped != MAP_FAILED) + { + do + { + if (st.st_size <= (off_t) mapsize) + { + *resp = crc32 (crc, mapped, st.st_size); + munmap (mapped, mapsize); + return 0; + } + crc = crc32 (crc, mapped, mapsize); + off += mapsize; + st.st_size -= mapsize; + } while (mmap (mapped, mapsize, PROT_READ, MAP_FIXED|MAP_PRIVATE, + fd, off) == mapped); + munmap (mapped, mapsize); + } + } + + while ((count = TEMP_FAILURE_RETRY (pread (fd, buffer, sizeof buffer, + off))) > 0) + { + off += count; + crc = crc32 (crc, buffer, count); + } + + *resp = crc; + + return count == 0 ? 0 : -1; +} diff --git a/lib/dynamicsizehash.c b/lib/dynamicsizehash.c new file mode 100644 index 00000000..61759636 --- /dev/null +++ b/lib/dynamicsizehash.c @@ -0,0 +1,316 @@ +/* Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include + +/* Before including this file the following macros must be defined: + + NAME name of the hash table structure. + TYPE data type of the hash table entries + COMPARE comparison function taking two pointers to TYPE objects + + The following macros if present select features: + + ITERATE iterating over the table entries is possible + REVERSE iterate in reverse order of insert + */ + + +static size_t +lookup (htab, hval, val) + NAME *htab; + unsigned long int hval; + TYPE val __attribute__ ((unused)); +{ + /* First hash function: simply take the modul but prevent zero. */ + size_t idx = 1 + hval % htab->size; + + if (htab->table[idx].hashval != 0) + { + unsigned long int hash; + + if (htab->table[idx].hashval == hval + && COMPARE (htab->table[idx].data, val) == 0) + return idx; + + /* Second hash function as suggested in [Knuth]. */ + hash = 1 + hval % (htab->size - 2); + + do + { + if (idx <= hash) + idx = htab->size + idx - hash; + else + idx -= hash; + + /* If entry is found use it. */ + if (htab->table[idx].hashval == hval + && COMPARE (htab->table[idx].data, val) == 0) + return idx; + } + while (htab->table[idx].hashval); + } + return idx; +} + + +static void +insert_entry_2 (NAME *htab, unsigned long int hval, size_t idx, TYPE data) +{ +#ifdef ITERATE + if (htab->table[idx].hashval == 0) + { +# ifdef REVERSE + htab->table[idx].next = htab->first; + htab->first = &htab->table[idx]; +# else + /* Add the new value to the list. */ + if (htab->first == NULL) + htab->first = htab->table[idx].next = &htab->table[idx]; + else + { + htab->table[idx].next = htab->first->next; + htab->first = htab->first->next = &htab->table[idx]; + } +# endif + } +#endif + + htab->table[idx].hashval = hval; + htab->table[idx].data = data; + + ++htab->filled; + if (100 * htab->filled > 90 * htab->size) + { + /* Table is filled more than 90%. Resize the table. */ +#ifdef ITERATE + __typeof__ (htab->first) first; +# ifndef REVERSE + __typeof__ (htab->first) runp; +# endif +#else + unsigned long int old_size = htab->size; +#endif +#define _TABLE(name) \ + name##_ent *table = htab->table +#define TABLE(name) _TABLE (name) + TABLE(NAME); + + htab->size = next_prime (htab->size * 2); + htab->filled = 0; +#ifdef ITERATE + first = htab->first; + htab->first = NULL; +#endif + htab->table = calloc ((1 + htab->size), sizeof (htab->table[0])); + if (htab->table == NULL) + { + /* We cannot enlarge the table. Live with what we got. This + might lead to an infinite loop at some point, though. */ + htab->table = table; + return; + } + + /* Add the old entries to the new table. When iteration is + supported we maintain the order. */ +#ifdef ITERATE +# ifdef REVERSE + while (first != NULL) + { + insert_entry_2 (htab, first->hashval, + lookup (htab, first->hashval, first->data), + first->data); + + first = first->next; + } +# else + assert (first != NULL); + runp = first = first->next; + do + insert_entry_2 (htab, runp->hashval, + lookup (htab, runp->hashval, runp->data), runp->data); + while ((runp = runp->next) != first); +# endif +#else + for (idx = 1; idx <= old_size; ++idx) + if (table[idx].hashval != 0) + insert_entry_2 (htab, table[idx].hashval, + lookup (htab, table[idx].hashval, table[idx].data), + table[idx].data); +#endif + + free (table); + } +} + + +int +#define INIT(name) _INIT (name) +#define _INIT(name) \ + name##_init +INIT(NAME) (htab, init_size) + NAME *htab; + unsigned long int init_size; +{ + /* We need the size to be a prime. */ + init_size = next_prime (init_size); + + /* Initialize the data structure. */ + htab->size = init_size; + htab->filled = 0; +#ifdef ITERATE + htab->first = NULL; +#endif + htab->table = (void *) calloc ((init_size + 1), sizeof (htab->table[0])); + if (htab->table == NULL) + return -1; + + return 0; +} + + +int +#define FREE(name) _FREE (name) +#define _FREE(name) \ + name##_free +FREE(NAME) (htab) + NAME *htab; +{ + free (htab->table); + return 0; +} + + +int +#define INSERT(name) _INSERT (name) +#define _INSERT(name) \ + name##_insert +INSERT(NAME) (htab, hval, data) + NAME *htab; + unsigned long int hval; + TYPE data; +{ + size_t idx; + + /* Make the hash value nonzero. */ + hval = hval ?: 1; + + idx = lookup (htab, hval, data); + + if (htab->table[idx].hashval != 0) + /* We don't want to overwrite the old value. */ + return -1; + + /* An empty bucket has been found. */ + insert_entry_2 (htab, hval, idx, data); + return 0; +} + + +#ifdef OVERWRITE +int +#define INSERT(name) _INSERT (name) +#define _INSERT(name) \ + name##_overwrite +INSERT(NAME) (htab, hval, data) + NAME *htab; + unsigned long int hval; + TYPE data; +{ + size_t idx; + + /* Make the hash value nonzero. */ + hval = hval ?: 1; + + idx = lookup (htab, hval, data); + + /* The correct bucket has been found. */ + insert_entry_2 (htab, hval, idx, data); + return 0; +} +#endif + + +TYPE +#define FIND(name) _FIND (name) +#define _FIND(name) \ + name##_find +FIND(NAME) (htab, hval, val) + NAME *htab; + unsigned long int hval; + TYPE val; +{ + size_t idx; + + /* Make the hash value nonzero. */ + hval = hval ?: 1; + + idx = lookup (htab, hval, val); + + if (htab->table[idx].hashval == 0) + return NULL; + + return htab->table[idx].data; +} + + +#ifdef ITERATE +# define ITERATEFCT(name) _ITERATEFCT (name) +# define _ITERATEFCT(name) \ + name##_iterate +TYPE +ITERATEFCT(NAME) (htab, ptr) + NAME *htab; + void **ptr; +{ + void *p = *ptr; + +# define TYPENAME(name) _TYPENAME (name) +# define _TYPENAME(name) name##_ent + +# ifdef REVERSE + if (p == NULL) + p = htab->first; + else + p = ((TYPENAME(NAME) *) p)->next; + + if (p == NULL) + { + *ptr = NULL; + return NULL; + } +# else + if (p == NULL) + { + if (htab->first == NULL) + return NULL; + p = htab->first->next; + } + else + { + if (p == htab->first) + return NULL; + + p = ((TYPENAME(NAME) *) p)->next; + } +# endif + + /* Prepare the next element. If possible this will pull the data + into the cache, for reading. */ + __builtin_prefetch (((TYPENAME(NAME) *) p)->next, 0, 2); + + return ((TYPENAME(NAME) *) (*ptr = p))->data; +} +#endif diff --git a/lib/dynamicsizehash.h b/lib/dynamicsizehash.h new file mode 100644 index 00000000..39a706fd --- /dev/null +++ b/lib/dynamicsizehash.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include + +/* Before including this file the following macros must be defined: + + NAME name of the hash table structure. + TYPE data type of the hash table entries + + The following macros if present select features: + + ITERATE iterating over the table entries is possible + */ + + +/* Optionally include an entry pointing to the first used entry. */ +#ifdef ITERATE +# define FIRST(name) name##_ent *first; +# define NEXT(name) struct name##_ent *next; +#else +# define FIRST(name) +# define NEXT(name) +#endif + + +/* Defined separately. */ +extern size_t next_prime (size_t seed); + + +/* Table entry type. */ +#define _DYNHASHENTTYPE(name) \ + typedef struct name##_ent \ + { \ + unsigned long int hashval; \ + TYPE data; \ + NEXT (name) \ + } name##_ent +#define DYNHASHENTTYPE(name) _DYNHASHENTTYPE (name) +DYNHASHENTTYPE (NAME); + + +/* Type of the dynamic hash table data structure. */ +#define _DYNHASHTYPE(name) \ +typedef struct \ +{ \ + unsigned long int size; \ + unsigned long int filled; \ + name##_ent *table; \ + FIRST (name) \ +} name +#define DYNHASHTYPE(name) _DYNHASHTYPE (name) +DYNHASHTYPE (NAME); + + + +#define _FUNCTIONS(name) \ +/* Initialize the hash table. */ \ +extern int name##_init (name *htab, unsigned long int init_size); \ + \ +/* Free resources allocated for hash table. */ \ +extern int name##_free (name *htab); \ + \ +/* Insert new entry. */ \ +extern int name##_insert (name *htab, unsigned long int hval, TYPE data); \ + \ +/* Insert new entry, possibly overwrite old entry. */ \ +extern int name##_overwrite (name *htab, unsigned long int hval, TYPE data); \ + \ +/* Find entry in hash table. */ \ +extern TYPE name##_find (name *htab, unsigned long int hval, TYPE val); +#define FUNCTIONS(name) _FUNCTIONS (name) +FUNCTIONS (NAME) + + +#ifdef ITERATE +# define _XFUNCTIONS(name) \ +/* Get next element in table. */ \ +extern TYPE name##_iterate (name *htab, void **ptr); +# define XFUNCTIONS(name) _XFUNCTIONS (name) +XFUNCTIONS (NAME) +#endif + +#ifndef NO_UNDEF +# undef DYNHASHENTTYPE +# undef DYNHASHTYPE +# undef FUNCTIONS +# undef _FUNCTIONS +# undef XFUNCTIONS +# undef _XFUNCTIONS +# undef NAME +# undef TYPE +# undef ITERATE +# undef COMPARE +# undef FIRST +# undef NEXT +#endif diff --git a/lib/fixedsizehash.h b/lib/fixedsizehash.h new file mode 100644 index 00000000..c1c607dd --- /dev/null +++ b/lib/fixedsizehash.h @@ -0,0 +1,255 @@ +/* Fixed size hash table with internal linking. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include + +#include + +#define CONCAT(t1,t2) __CONCAT (t1,t2) + +/* Before including this file the following macros must be defined: + + TYPE data type of the hash table entries + HASHFCT name of the hashing function to use + HASHTYPE type used for the hashing value + COMPARE comparison function taking two pointers to TYPE objects + CLASS can be defined to `static' to avoid exporting the functions + PREFIX prefix to be used for function and data type names + STORE_POINTER if defined the table stores a pointer and not an element + of type TYPE + INSERT_HASH if defined alternate insert function which takes a hash + value is defined + NO_FINI_FCT if defined the fini function is not defined +*/ + + +/* Defined separately. */ +extern size_t next_prime (size_t seed); + + +/* Set default values. */ +#ifndef HASHTYPE +# define HASHTYPE size_t +#endif + +#ifndef CLASS +# define CLASS +#endif + +#ifndef PREFIX +# define PREFIX +#endif + + +/* The data structure. */ +struct CONCAT(PREFIX,fshash) +{ + size_t nslots; + struct CONCAT(PREFIX,fshashent) + { + HASHTYPE hval; +#ifdef STORE_POINTER +# define ENTRYP(el) (el).entry + TYPE *entry; +#else +# define ENTRYP(el) &(el).entry + TYPE entry; +#endif + } table[0]; +}; + + +/* Constructor for the hashing table. */ +CLASS struct CONCAT(PREFIX,fshash) * +CONCAT(PREFIX,fshash_init) (size_t nelems) +{ + struct CONCAT(PREFIX,fshash) *result; + /* We choose a size for the hashing table 150% over the number of + entries. This will guarantee short medium search lengths. */ + const size_t max_size_t = ~((size_t) 0); + + if (nelems >= (max_size_t / 3) * 2) + { + errno = EINVAL; + return NULL; + } + + /* Adjust the size to be used for the hashing table. */ + nelems = next_prime (MAX ((nelems * 3) / 2, 10)); + + /* Allocate the data structure for the result. */ + result = (struct CONCAT(PREFIX,fshash) *) + xcalloc (sizeof (struct CONCAT(PREFIX,fshash)) + + (nelems + 1) * sizeof (struct CONCAT(PREFIX,fshashent)), 1); + if (result == NULL) + return NULL; + + result->nslots = nelems; + + return result; +} + + +#ifndef NO_FINI_FCT +CLASS void +CONCAT(PREFIX,fshash_fini) (struct CONCAT(PREFIX,fshash) *htab) +{ + free (htab); +} +#endif + + +static struct CONCAT(PREFIX,fshashent) * +CONCAT(PREFIX,fshash_lookup) (struct CONCAT(PREFIX,fshash) *htab, + HASHTYPE hval, TYPE *data) +{ + size_t idx = 1 + hval % htab->nslots; + + if (htab->table[idx].hval != 0) + { + HASHTYPE hash; + + /* See whether this is the same entry. */ + if (htab->table[idx].hval == hval + && COMPARE (data, ENTRYP (htab->table[idx])) == 0) + return &htab->table[idx]; + + /* Second hash function as suggested in [Knuth]. */ + hash = 1 + hval % (htab->nslots - 2); + + do + { + if (idx <= hash) + idx = htab->nslots + idx - hash; + else + idx -= hash; + + if (htab->table[idx].hval == hval + && COMPARE (data, ENTRYP(htab->table[idx])) == 0) + return &htab->table[idx]; + } + while (htab->table[idx].hval != 0); + } + + return &htab->table[idx]; +} + + +CLASS int +__attribute__ ((unused)) +CONCAT(PREFIX,fshash_insert) (struct CONCAT(PREFIX,fshash) *htab, + const char *str, + size_t len __attribute__ ((unused)), TYPE *data) +{ + HASHTYPE hval = HASHFCT (str, len ?: strlen (str)); + struct CONCAT(PREFIX,fshashent) *slot; + + slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data); + if (slot->hval != 0) + /* We don't want to overwrite the old value. */ + return -1; + + slot->hval = hval; +#ifdef STORE_POINTER + slot->entry = data; +#else + slot->entry = *data; +#endif + + return 0; +} + + +#ifdef INSERT_HASH +CLASS int +__attribute__ ((unused)) +CONCAT(PREFIX,fshash_insert_hash) (struct CONCAT(PREFIX,fshash) *htab, + HASHTYPE hval, TYPE *data) +{ + struct CONCAT(PREFIX,fshashent) *slot; + + slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data); + if (slot->hval != 0) + /* We don't want to overwrite the old value. */ + return -1; + + slot->hval = hval; +#ifdef STORE_POINTER + slot->entry = data; +#else + slot->entry = *data; +#endif + + return 0; +} +#endif + + +CLASS int +__attribute__ ((unused)) +CONCAT(PREFIX,fshash_overwrite) (struct CONCAT(PREFIX,fshash) *htab, + const char *str, + size_t len __attribute__ ((unused)), + TYPE *data) +{ + HASHTYPE hval = HASHFCT (str, len ?: strlen (str)); + struct CONCAT(PREFIX,fshashent) *slot; + + slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data); + slot->hval = hval; +#ifdef STORE_POINTER + slot->entry = data; +#else + slot->entry = *data; +#endif + + return 0; +} + + +CLASS const TYPE * +CONCAT(PREFIX,fshash_find) (const struct CONCAT(PREFIX,fshash) *htab, + const char *str, + size_t len __attribute__ ((unused)), TYPE *data) +{ + HASHTYPE hval = HASHFCT (str, len ?: strlen (str)); + struct CONCAT(PREFIX,fshashent) *slot; + + slot = CONCAT(PREFIX,fshash_lookup) ((struct CONCAT(PREFIX,fshash) *) htab, + hval, data); + if (slot->hval == 0) + /* Not found. */ + return NULL; + + return ENTRYP(*slot); +} + + +/* Unset the macros we expect. */ +#undef TYPE +#undef HASHFCT +#undef HASHTYPE +#undef COMPARE +#undef CLASS +#undef PREFIX +#undef INSERT_HASH +#undef STORE_POINTER +#undef NO_FINI_FCT diff --git a/lib/list.h b/lib/list.h new file mode 100644 index 00000000..c039a0ba --- /dev/null +++ b/lib/list.h @@ -0,0 +1,85 @@ +/* Copyright (C) 2001, 2002, 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef LIST_H +#define LIST_H 1 + +/* Add element to the end of a circular, double-linked list. */ +#define CDBL_LIST_ADD_REAR(first, newp) \ + do { \ + __typeof (newp) _newp = (newp); \ + assert (_newp->next == NULL); \ + assert (_newp->previous == NULL); \ + if (unlikely ((first) == NULL)) \ + (first) = _newp->next = _newp->previous = _newp; \ + else \ + { \ + _newp->next = (first); \ + _newp->previous = (first)->previous; \ + _newp->previous->next = _newp->next->previous = _newp; \ + } \ + } while (0) + +/* Remove element from circular, double-linked list. */ +#define CDBL_LIST_DEL(first, elem) \ + do { \ + __typeof (elem) _elem = (elem); \ + /* Check whether the element is indeed on the list. */ \ + assert (first != NULL && _elem != NULL \ + && (first != elem \ + || ({ __typeof (elem) _runp = first->next; \ + while (_runp != first) \ + if (_runp == _elem) \ + break; \ + else \ + _runp = _runp->next; \ + _runp == _elem; }))); \ + if (unlikely (_elem->next == _elem)) \ + first = NULL; \ + else \ + { \ + _elem->next->previous = _elem->previous; \ + _elem->previous->next = _elem->next; \ + if (unlikely (first == _elem)) \ + first = _elem->next; \ + } \ + assert ((_elem->next = _elem->previous = NULL, 1)); \ + } while (0) + + +/* Add element to the front of a single-linked list. */ +#define SNGL_LIST_PUSH(first, newp) \ + do { \ + __typeof (newp) _newp = (newp); \ + assert (_newp->next == NULL); \ + _newp->next = first; \ + first = _newp; \ + } while (0) + + +/* Add element to the rear of a circular single-linked list. */ +#define CSNGL_LIST_ADD_REAR(first, newp) \ + do { \ + __typeof (newp) _newp = (newp); \ + assert (_newp->next == NULL); \ + if (unlikely ((first) == NULL)) \ + (first) = _newp->next = _newp; \ + else \ + { \ + _newp->next = (first)->next; \ + (first) = (first)->next = _newp; \ + } \ + } while (0) + + +#endif /* list.h */ diff --git a/lib/next_prime.c b/lib/next_prime.c new file mode 100644 index 00000000..5d608046 --- /dev/null +++ b/lib/next_prime.c @@ -0,0 +1,54 @@ +/* Determine prime number. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include + + +/* Test whether CANDIDATE is a prime. */ +static int +is_prime (size_t candidate) +{ + /* No even number and none less than 10 will be passed here. */ + size_t divn = 3; + size_t sq = divn * divn; + + while (sq < candidate && candidate % divn != 0) + { + size_t old_sq = sq; + ++divn; + sq += 4 * divn; + if (sq < old_sq) + return 1; + ++divn; + } + + return candidate % divn != 0; +} + + +/* We need primes for the table size. */ +size_t +next_prime (size_t seed) +{ + /* Make it definitely odd. */ + seed |= 1; + + while (!is_prime (seed)) + seed += 2; + + return seed; +} diff --git a/lib/system.h b/lib/system.h new file mode 100644 index 00000000..e29c2dbb --- /dev/null +++ b/lib/system.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2000, 2002, 2004, 2005 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef LIB_SYSTEM_H +#define LIB_SYSTEM_H 1 + +#include +#include + +extern void *xmalloc (size_t) __attribute__ ((__malloc__)); +extern void *xcalloc (size_t, size_t) __attribute__ ((__malloc__)); +extern void *xrealloc (void *, size_t) __attribute__ ((__malloc__)); + +extern char *xstrdup (const char *) __attribute__ ((__malloc__)); +extern char *xstrndup (const char *, size_t) __attribute__ ((__malloc__)); + + +extern uint32_t crc32 (uint32_t crc, unsigned char *buf, size_t len); +extern int crc32_file (int fd, uint32_t *resp); + +/* A special gettext function we use if the strings are too short. */ +#define sgettext(Str) \ + ({ const char *__res = strrchr (gettext (Str), '|'); \ + __res ? __res + 1 : Str; }) + +#define gettext_noop(Str) Str + +#endif /* system.h */ diff --git a/lib/xmalloc.c b/lib/xmalloc.c new file mode 100644 index 00000000..0934e641 --- /dev/null +++ b/lib/xmalloc.c @@ -0,0 +1,68 @@ +/* Copyright (C) 2000, 2002 Free Software Foundation, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include "system.h" + +#ifndef _ +# define _(str) gettext (str) +#endif + + +/* Allocate N bytes of memory dynamically, with error checking. */ +void * +xmalloc (n) + size_t n; +{ + void *p; + + p = malloc (n); + if (p == NULL) + error (EXIT_FAILURE, 0, _("memory exhausted")); + return p; +} + + +/* Allocate memory for N elements of S bytes, with error checking. */ +void * +xcalloc (n, s) + size_t n, s; +{ + void *p; + + p = calloc (n, s); + if (p == NULL) + error (EXIT_FAILURE, 0, _("memory exhausted")); + return p; +} + + +/* Change the size of an allocated block of memory P to N bytes, + with error checking. */ +void * +xrealloc (p, n) + void *p; + size_t n; +{ + p = realloc (p, n); + if (p == NULL) + error (EXIT_FAILURE, 0, _("memory exhausted")); + return p; +} diff --git a/lib/xstrdup.c b/lib/xstrdup.c new file mode 100644 index 00000000..ad70a630 --- /dev/null +++ b/lib/xstrdup.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2000, 2002 Free Software Foundation, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "system.h" + + +/* Return a newly allocated copy of STRING. */ +char * +xstrdup (string) + const char *string; +{ + return strcpy (xmalloc (strlen (string) + 1), string); +} diff --git a/lib/xstrndup.c b/lib/xstrndup.c new file mode 100644 index 00000000..946f3616 --- /dev/null +++ b/lib/xstrndup.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2000, 2002 Free Software Foundation, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "system.h" + + +/* Return a newly allocated copy of STRING. */ +char * +xstrndup (string, n) + const char *string; + size_t n; +{ + char *res; + size_t len = strnlen (string, n); + *((char *) mempcpy ((res = xmalloc (len + 1)), string, len)) = '\0'; + return res; +} diff --git a/libasm/.cvsignore b/libasm/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/libasm/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/libasm/ChangeLog b/libasm/ChangeLog new file mode 100644 index 00000000..8b7b44d2 --- /dev/null +++ b/libasm/ChangeLog @@ -0,0 +1,52 @@ +2005-02-15 Ulrich Drepper + + * Makefile (AM_CFLAGS): Add -Wunused -Wextra -Wformat=2. + + * asm_end.c (text_end): Mark parameter as possibly unused. + +2005-02-06 Ulrich Drepper + + * Makefile.am: Remove lint handling. + +2005-02-05 Ulrich Drepper + + * asm_end.c (binary_end): Don't terminate with error() in case + something goes wrong. + + * Makefile.am: Check for text relocations in constructed DSO. + + * Makefile.am (AM_CFLAGS): More warnings. Add -fmudflap for MUDFLAP. + + * asm_end.c (binary_end): Remove shadowing variables. + Little cleanups. + + * asm_newsym.c: Allocate memory for the string parameter. + +2005-02-04 Ulrich Drepper + + * asm_newscn_ingrp.c (asm_newscn_ingrp): Use INTUSE to reference + asm_newscn. + +2004-09-25 Ulrich Drepper + + * asm_error.c: Make compile with gcc 4.0. + +2004-01-20 Ulrich Drepper + + * Makefile.am: Support building with mudflap. + +2004-01-18 Ulrich Drepper + + * libasmP.h (_): Use elfutils domain. + +2004-01-17 Ulrich Drepper + + * Makefile.am: Support building with mudflap. + +2003-08-13 Ulrich Drepper + + * Makefile.in: Depend on libebl.a, not libebl.so. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/libasm/Makefile.am b/libasm/Makefile.am new file mode 100644 index 00000000..34b19d24 --- /dev/null +++ b/libasm/Makefile.am @@ -0,0 +1,86 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 2002, 2004, 2005 Red Hat, Inc. +## +## This program is Open Source software; you can redistribute it and/or +## modify it under the terms of the Open Software License version 1.0 as +## published by the Open Source Initiative. +## +## You should have received a copy of the Open Software License along +## with this program; if not, you may obtain a copy of the Open Software +## License version 1.0 from http://www.opensource.org/licenses/osl.php or +## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +## 3001 King Ranch Road, Ukiah, CA 95482. +## +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H +if MUDFLAP +AM_CFLAGS = -fmudflap +else +AM_CFLAGS = +endif +AM_CFLAGS += -Wall -Wshadow -Werror -Wunused -Wextra -Wformat=2 +INCLUDES = -I. -I$(srcdir) -I.. -I$(top_srcdir)/libelf -I$(top_srcdir)/libebl \ + -I$(top_srcdir)/lib +GCC_INCLUDE = -I$(shell $(CC) -print-file-name=include) +VERSION = 1 + +lib_LIBRARIES = libasm.a +if !MUDFLAP +noinst_LIBRARIES = libasm_pic.a +noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so) +endif +euincludedir = ${includedir}/elfutils +euinclude_HEADERS = libasm.h + +libasm_a_SOURCES = asm_begin.c asm_abort.c asm_end.c asm_error.c \ + asm_getelf.c asm_newscn.c asm_newscn_ingrp.c \ + asm_newsubscn.c asm_newsym.c asm_newcomsym.c \ + asm_newabssym.c \ + asm_newscngrp.c asm_scngrp_newsignature.c \ + asm_fill.c asm_align.c asm_addstrz.c \ + asm_addint8.c asm_adduint8.c \ + asm_addint16.c asm_adduint16.c \ + asm_addint32.c asm_adduint32.c \ + asm_addint64.c asm_adduint64.c \ + asm_adduleb128.c asm_addsleb128.c \ + symbolhash.c + +if !MUDFLAP +libasm_pic_a_SOURCES = +am_libasm_pic_a_OBJECTS = $(libasm_a_SOURCES:.c=.os) + +libasm_so_SOURCES = +libasm.so: libasm_pic.a libasm.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libasm.map,--no-undefined \ + -Wl,--soname,$@.$(VERSION) \ + ../libebl/libebl.a ../libelf/libelf.so + if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi + ln -fs $@ $@.$(VERSION) + + +%.os: %.c %.o + if $(COMPILE) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \ + -MF "$(DEPDIR)/$*.Tpo" `test -f '$<' || echo '$(srcdir)/'`$<; \ + then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ + rm -f "$(DEPDIR)/$*.Tpo"; \ + else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ + fi + +install: install-am libasm.so + $(mkinstalldirs) $(DESTDIR)$(libdir) + $(INSTALL_PROGRAM) libasm.so $(DESTDIR)$(libdir)/libasm-$(PACKAGE_VERSION).so + ln -fs libasm-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libasm.so.$(VERSION) + ln -fs libasm.so.$(VERSION) $(DESTDIR)$(libdir)/libasm.so + +uninstall: uninstall-am + rm -f $(DESTDIR)$(libdir)/libasm-$(PACKAGE_VERSION).so + rm -f $(DESTDIR)$(libdir)/libasm.so.$(VERSION) + rm -f $(DESTDIR)$(libdir)/libasm.so + rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils +endif + +noinst_HEADERS = libasmP.h symbolhash.h +EXTRA_DIST = libasm.map + +CLEANFILES = $(am_libasm_pic_a_OBJECTS) diff --git a/libasm/asm_abort.c b/libasm/asm_abort.c new file mode 100644 index 00000000..f35757ca --- /dev/null +++ b/libasm/asm_abort.c @@ -0,0 +1,45 @@ +/* Abort operations on the assembler context, free all resources. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include + + +int +asm_abort (ctx) + AsmCtx_t *ctx; +{ + if (ctx == NULL) + /* Something went wrong earlier. */ + return -1; + + if (likely (! ctx->textp)) + /* First free the ELF file. We don't care about the result. */ + (void) elf_end (ctx->out.elf); + + /* Now close the temporary file and remove it. */ + (void) unlink (ctx->tmp_fname); + + /* Free the resources. */ + __libasm_finictx (ctx); + + return 0; +} diff --git a/libasm/asm_addint16.c b/libasm/asm_addint16.c new file mode 100644 index 00000000..98125171 --- /dev/null +++ b/libasm/asm_addint16.c @@ -0,0 +1,17 @@ +/* Add integer to a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#define SIZE 16 + +#include "asm_addint8.c" diff --git a/libasm/asm_addint32.c b/libasm/asm_addint32.c new file mode 100644 index 00000000..05ac3d25 --- /dev/null +++ b/libasm/asm_addint32.c @@ -0,0 +1,17 @@ +/* Add integer to a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#define SIZE 32 + +#include "asm_addint8.c" diff --git a/libasm/asm_addint64.c b/libasm/asm_addint64.c new file mode 100644 index 00000000..f9d93f80 --- /dev/null +++ b/libasm/asm_addint64.c @@ -0,0 +1,17 @@ +/* Add integer to a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#define SIZE 64 + +#include "asm_addint8.c" diff --git a/libasm/asm_addint8.c b/libasm/asm_addint8.c new file mode 100644 index 00000000..35d9bf57 --- /dev/null +++ b/libasm/asm_addint8.c @@ -0,0 +1,105 @@ +/* Add integer to a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#ifndef SIZE +# define SIZE 8 +#endif + +#define FCT(size) _FCT(size) +#define _FCT(size) asm_addint##size +#define TYPE(size) _TYPE(size) +#define _TYPE(size) int##size##_t +#define BSWAP(size) _BSWAP(size) +#define _BSWAP(size) bswap_##size + + +int +FCT(SIZE) (asmscn, num) + AsmScn_t *asmscn; + TYPE(SIZE) num; +{ + if (asmscn == NULL) + return -1; + + if (asmscn->type == SHT_NOBITS && unlikely (num != 0)) + { + __libasm_seterrno (ASM_E_TYPE); + return -1; + } + + if (unlikely (asmscn->ctx->textp)) + { + // XXX Needs to use backend specified pseudo-ops + if (SIZE == 8) + printf ("\t.byte\t%" PRId8 "\n", (int8_t) num); + else if (SIZE == 16) + printf ("\t.value\t%" PRId16 "\n", (int16_t) num); + else if (SIZE == 32) + printf ("\t.long\t%" PRId32 "\n", (int32_t) num); + else + { + // XXX This is not necessary for 64-bit machines + bool is_leb = (elf_getident (asmscn->ctx->out.elf, NULL)[EI_DATA] + == ELFDATA2LSB); + + printf ("\t.long\t%" PRId32 "\n\t.long\t%" PRId32 "\n", + (int32_t) (is_leb + ? num % 0x100000000ll : num / 0x100000000ll), + (int32_t) (is_leb + ? num / 0x100000000ll : num % 0x100000000ll)); + } + } + else + { +#if SIZE > 8 + bool is_leb = (elf_getident (asmscn->ctx->out.elf, NULL)[EI_DATA] + == ELFDATA2LSB); +#endif + TYPE(SIZE) var = num; + + /* Make sure we have enough room. */ + if (__libasm_ensure_section_space (asmscn, SIZE / 8) != 0) + return -1; + +#if SIZE > 8 + if ((BYTE_ORDER == LITTLE_ENDIAN && !is_leb) + || (BYTE_ORDER == BIG_ENDIAN && is_leb)) + var = BSWAP(SIZE) (var); +#endif + + /* Copy the variable value. */ + if (likely (asmscn->type == SHT_NOBITS)) + memcpy (&asmscn->content->data[asmscn->content->len], &var, SIZE / 8); + + /* Adjust the pointer in the data buffer. */ + asmscn->content->len += SIZE / 8; + + /* Increment the offset in the (sub)section. */ + asmscn->offset += SIZE / 8; + } + + return 0; +} +INTDEF(FCT(SIZE)) diff --git a/libasm/asm_addsleb128.c b/libasm/asm_addsleb128.c new file mode 100644 index 00000000..0661b36e --- /dev/null +++ b/libasm/asm_addsleb128.c @@ -0,0 +1,84 @@ +/* Add signed little endian base 128 integer to a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +int +asm_addsleb128 (asmscn, num) + AsmScn_t *asmscn; + int32_t num; +{ + if (asmscn == NULL) + return -1; + + if (asmscn->type == SHT_NOBITS && unlikely (num != 0)) + { + __libasm_seterrno (ASM_E_TYPE); + return -1; + } + + if (unlikely (asmscn->ctx->textp)) + printf ("\t.sleb128\t%" PRId32 "\n", num); + else + { + char tmpbuf[(sizeof (num) * 8 + 6) / 7]; + char *dest = tmpbuf; + uint32_t byte; + int32_t endval = num >> 31; + + if (num == 0) + byte = 0; + else + while (1) + { + byte = num & 0x7f; + + num >>= 7; + if (num == endval) + /* This is the last byte. */ + break; + + *dest++ = byte | 0x80; + } + + *dest++ = byte; + + /* Number of bytes produced. */ + size_t nbytes = dest - tmpbuf; + + /* Make sure we have enough room. */ + if (__libasm_ensure_section_space (asmscn, nbytes) != 0) + return -1; + + /* Copy the bytes. */ + if (likely (asmscn->type != SHT_NOBITS)) + memcpy (&asmscn->content->data[asmscn->content->len], tmpbuf, nbytes); + + /* Adjust the pointer in the data buffer. */ + asmscn->content->len += nbytes; + + /* Increment the offset in the (sub)section. */ + asmscn->offset += nbytes; + } + + return 0; +} diff --git a/libasm/asm_addstrz.c b/libasm/asm_addstrz.c new file mode 100644 index 00000000..e183b0b5 --- /dev/null +++ b/libasm/asm_addstrz.c @@ -0,0 +1,113 @@ +/* Add string to a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include + + +/* Add zero terminated string STR of size LEN to (sub)section ASMSCN. */ +int +asm_addstrz (asmscn, str, len) + AsmScn_t *asmscn; + const char *str; + size_t len; +{ + if (asmscn == NULL) + return -1; + + if (unlikely (asmscn->type == SHT_NOBITS)) + { + if (len == 0) + { + if (str[0] != '\0') + { + __libasm_seterrno (ASM_E_TYPE); + return -1; + } + } + else + { + size_t cnt; + + for (cnt = 0; cnt < len; ++cnt) + if (str[cnt] != '\0') + { + __libasm_seterrno (ASM_E_TYPE); + return -1; + } + } + } + + if (len == 0) + len = strlen (str) + 1; + + if (unlikely (asmscn->ctx->textp)) + { + bool nextline = true; + + do + { + if (nextline) + { + fputs ("\t.string\t\"", asmscn->ctx->out.file); + nextline = false; + } + + if (*str == '\0') + fputs ("\\000", asmscn->ctx->out.file); + else if (! isascii (*str)) + fprintf (asmscn->ctx->out.file, "\\%03o", + (unsigned int) *((unsigned char *)str)); + else if (*str == '\\') + fputs ("\\\\", asmscn->ctx->out.file); + else if (*str == '\n') + { + fputs ("\\n\"", asmscn->ctx->out.file); + nextline = true; + } + else + fputc (*str, asmscn->ctx->out.file); + + ++str; + } + while (--len > 0 && (len > 1 || *str != '\0')); + + if (! nextline) + fputs ("\"\n", asmscn->ctx->out.file); + } + else + { + /* Make sure there is enough room. */ + if (__libasm_ensure_section_space (asmscn, len) != 0) + return -1; + + /* Copy the string. */ + memcpy (&asmscn->content->data[asmscn->content->len], str, len); + + /* Adjust the pointer in the data buffer. */ + asmscn->content->len += len; + + /* Increment the offset in the (sub)section. */ + asmscn->offset += len; + } + + return 0; +} diff --git a/libasm/asm_adduint16.c b/libasm/asm_adduint16.c new file mode 100644 index 00000000..8c1e698f --- /dev/null +++ b/libasm/asm_adduint16.c @@ -0,0 +1,17 @@ +/* Add unsigned integer to a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#define SIZE 16 + +#include "asm_adduint8.c" diff --git a/libasm/asm_adduint32.c b/libasm/asm_adduint32.c new file mode 100644 index 00000000..a2257954 --- /dev/null +++ b/libasm/asm_adduint32.c @@ -0,0 +1,17 @@ +/* Add unsigned integer to a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#define SIZE 32 + +#include "asm_adduint8.c" diff --git a/libasm/asm_adduint64.c b/libasm/asm_adduint64.c new file mode 100644 index 00000000..edda4d38 --- /dev/null +++ b/libasm/asm_adduint64.c @@ -0,0 +1,17 @@ +/* Add unsigned integer to a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#define SIZE 64 + +#include "asm_adduint8.c" diff --git a/libasm/asm_adduint8.c b/libasm/asm_adduint8.c new file mode 100644 index 00000000..7bfb3414 --- /dev/null +++ b/libasm/asm_adduint8.c @@ -0,0 +1,41 @@ +/* Add unsigned integer to a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#ifndef SIZE +# define SIZE 8 +#endif + +#define UFCT(size) _UFCT(size) +#define _UFCT(size) asm_adduint##size +#define FCT(size) _FCT(size) +#define _FCT(size) asm_addint##size +#define UTYPE(size) _UTYPE(size) +#define _UTYPE(size) uint##size##_t +#define TYPE(size) _TYPE(size) +#define _TYPE(size) int##size##_t + + +int +UFCT(SIZE) (asmscn, num) + AsmScn_t *asmscn; + UTYPE(SIZE) num; +{ + return INTUSE(FCT(SIZE)) (asmscn, (TYPE(SIZE)) num); +} diff --git a/libasm/asm_adduleb128.c b/libasm/asm_adduleb128.c new file mode 100644 index 00000000..521d265a --- /dev/null +++ b/libasm/asm_adduleb128.c @@ -0,0 +1,80 @@ +/* Add integer to a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libasmP.h" + + +int +asm_adduleb128 (asmscn, num) + AsmScn_t *asmscn; + uint32_t num; +{ + if (asmscn == NULL) + return -1; + + if (asmscn->type == SHT_NOBITS && unlikely (num != 0)) + { + __libasm_seterrno (ASM_E_TYPE); + return -1; + } + + if (unlikely (asmscn->ctx->textp)) + printf ("\t.uleb128\t%" PRIu32 "\n", num); + else + { + char tmpbuf[(sizeof (num) * 8 + 6) / 7]; + char *dest = tmpbuf; + uint32_t byte; + + while (1) + { + byte = num & 0x7f; + + num >>= 7; + if (num == 0) + /* This is the last byte. */ + break; + + *dest++ = byte | 0x80; + } + + *dest++ = byte; + + /* Number of bytes produced. */ + size_t nbytes = dest - tmpbuf; + + /* Make sure we have enough room. */ + if (__libasm_ensure_section_space (asmscn, nbytes) != 0) + return -1; + + /* Copy the bytes. */ + if (likely (asmscn->type != SHT_NOBITS)) + memcpy (&asmscn->content->data[asmscn->content->len], tmpbuf, nbytes); + + /* Adjust the pointer in the data buffer. */ + asmscn->content->len += nbytes; + + /* Increment the offset in the (sub)section. */ + asmscn->offset += nbytes; + } + + return 0; +} diff --git a/libasm/asm_align.c b/libasm/asm_align.c new file mode 100644 index 00000000..e7350924 --- /dev/null +++ b/libasm/asm_align.c @@ -0,0 +1,147 @@ +/* Align section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include + + +int +asm_align (asmscn, value) + AsmScn_t *asmscn; + GElf_Word value; +{ + if (asmscn == NULL) + /* An earlier error. */ + return -1; + + /* The alignment value must be a power of two. */ + if (unlikely (! powerof2 (value))) + { + __libasm_seterrno (ASM_E_INVALID); + return -1; + } + + rwlock_wrlock (asmscn->ctx->lock); + + int result = 0; + + /* Fillbytes necessary? */ + if ((asmscn->offset & (value - 1)) != 0) + { + /* Add fillbytes. */ + size_t cnt; + size_t byteptr; + + cnt = value - (asmscn->offset & (value - 1)); + + /* Ensure there is enough room to add the fill bytes. */ + result = __libasm_ensure_section_space (asmscn, cnt); + if (result != 0) + goto out; + + /* Fill in the bytes. We align the pattern according to the + current offset. */ + byteptr = asmscn->offset % asmscn->pattern->len; + + /* Update the total size. */ + asmscn->offset += cnt; + + do + { + asmscn->content->data[asmscn->content->len++] + = asmscn->pattern->bytes[byteptr++]; + + if (byteptr == asmscn->pattern->len) + byteptr = 0; + } + while (--cnt > 0); + } + + /* Remember the maximum alignment for this subsection. */ + if (asmscn->max_align < value) + { + asmscn->max_align = value; + + /* Update the parent as well (if it exists). */ + if (asmscn->subsection_id != 0) + { + rwlock_wrlock (asmscn->data.up->ctx->lock); + + if (asmscn->data.up->max_align < value) + asmscn->data.up->max_align = value; + + rwlock_unlock (asmscn->data.up->ctx->lock); + } + } + + out: + rwlock_unlock (asmscn->ctx->lock); + + return result; +} + + +/* Ensure there are at least LEN bytes available in the output buffer + for ASMSCN. */ +int +__libasm_ensure_section_space (asmscn, len) + AsmScn_t *asmscn; + size_t len; +{ + /* The blocks with the section content are kept in a circular + single-linked list. */ + size_t size; + + if (asmscn->content == NULL) + { + /* This is the first block. */ + size = MAX (2 * len, 960); + + asmscn->content = (struct AsmData *) malloc (sizeof (struct AsmData) + + size); + if (asmscn->content == NULL) + return -1; + + asmscn->content->next = asmscn->content; + } + else + { + struct AsmData *newp; + + if (asmscn->content->maxlen - asmscn->content->len >= len) + /* Nothing to do, there is enough space. */ + return 0; + + size = MAX (2 *len, MIN (32768, 2 * asmscn->offset)); + + newp = (struct AsmData *) malloc (sizeof (struct AsmData) + size); + if (newp == NULL) + return -1; + + newp->next = asmscn->content->next; + asmscn->content = asmscn->content->next = newp; + } + + asmscn->content->len = 0; + asmscn->content->maxlen = size; + + return 0; +} diff --git a/libasm/asm_begin.c b/libasm/asm_begin.c new file mode 100644 index 00000000..3896f78f --- /dev/null +++ b/libasm/asm_begin.c @@ -0,0 +1,151 @@ +/* Create descriptor for assembling. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include "libasmP.h" +#include + + +static AsmCtx_t * +prepare_text_output (AsmCtx_t *result) +{ + return result; +} + + +static AsmCtx_t * +prepare_binary_output (AsmCtx_t *result, int machine, int klass, int data) +{ + GElf_Ehdr *ehdr; + GElf_Ehdr ehdr_mem; + + /* Create the ELF descriptor for the file. */ + result->out.elf = elf_begin (result->fd, ELF_C_WRITE_MMAP, NULL); + if (result->out.elf == NULL) + { + err_libelf: + unlink (result->tmp_fname); + close (result->fd); + free (result); + __libasm_seterrno (ASM_E_LIBELF); + return NULL; + } + + /* Create the ELF header for the output file. */ + if (gelf_newehdr (result->out.elf, klass) == 0) + goto err_libelf; + + ehdr = gelf_getehdr (result->out.elf, &ehdr_mem); + /* If this failed we are in trouble. */ + assert (ehdr != NULL); + + /* We create an object file. */ + ehdr->e_type = ET_REL; + /* Set the ELF version. */ + ehdr->e_version = EV_CURRENT; + + /* Use the machine value the user provided. */ + ehdr->e_machine = machine; + /* Same for the class and endianness. */ + ehdr->e_ident[EI_CLASS] = klass; + ehdr->e_ident[EI_DATA] = data; + + memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG); + + /* Write the ELF header information back. */ + (void) gelf_update_ehdr (result->out.elf, ehdr); + + /* No section so far. */ + result->section_list = NULL; + + /* Initialize the hash table. */ + asm_symbol_tab_init (&result->symbol_tab, 67); + result->nsymbol_tab = 0; + /* And the string tables. */ + result->section_strtab = ebl_strtabinit (true); + result->symbol_strtab = ebl_strtabinit (true); + + /* We have no section groups so far. */ + result->groups = NULL; + result->ngroups = 0; + + return result; +} + + +AsmCtx_t * +asm_begin (fname, textp, machine, klass, data) + const char *fname; + bool textp; + int machine; + int klass; + int data; +{ + size_t fname_len = strlen (fname); + AsmCtx_t *result; + + + /* First order of business: find the appropriate backend. If it + does not exist we don't have to look further. */ + // XXX + + /* Create the file descriptor. We do not generate the output file + right away. Instead we create a temporary file in the same + directory which, if everything goes alright, will replace a + possibly existing file with the given name. */ + result = (AsmCtx_t *) malloc (sizeof (AsmCtx_t) + 2 * fname_len + 9); + if (result == NULL) + return NULL; + + /* Initialize the lock. */ + rwlock_init (result->lock); + + /* Create the name of the temporary file. */ + result->fname = stpcpy (mempcpy (result->tmp_fname, fname, fname_len), + ".XXXXXX") + 1; + memcpy (result->fname, fname, fname_len + 1); + + /* Create the temporary file. */ + result->fd = mkstemp (result->tmp_fname); + if (result->fd == -1) + { + int save_errno = errno; + free (result); + __libasm_seterrno (ASM_E_CANNOT_CREATE); + errno = save_errno; + return NULL; + } + + /* Initialize the counter for temporary symbols. */ + result->tempsym_count = 0; + + /* Now we differentiate between textual and binary output. */ + result->textp = textp; + if (textp) + result = prepare_text_output (result); + else + result = prepare_binary_output (result, machine, klass, data); + + return result; +} diff --git a/libasm/asm_end.c b/libasm/asm_end.c new file mode 100644 index 00000000..74f01f08 --- /dev/null +++ b/libasm/asm_end.c @@ -0,0 +1,593 @@ +/* Finalize operations on the assembler context, free all resources. + Copyright (C) 2002, 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +static int +text_end (AsmCtx_t *ctx __attribute__ ((unused))) +{ + // XXX Does anything have to be done? + return 0; +} + + +static int +binary_end (AsmCtx_t *ctx) +{ + void *symtab = NULL; + struct Ebl_Strent *symscn_strent = NULL; + struct Ebl_Strent *strscn_strent = NULL; + struct Ebl_Strent *xndxscn_strent = NULL; + Elf_Scn *shstrscn; + struct Ebl_Strent *shstrscn_strent; + size_t shstrscnndx; + size_t symscnndx = 0; + size_t strscnndx = 0; + size_t xndxscnndx = 0; + Elf_Data *data; + Elf_Data *shstrtabdata; + Elf_Data *strtabdata = NULL; + Elf_Data *xndxdata = NULL; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + AsmScn_t *asmscn; + int result = 0; + + /* Iterate over the created sections and compute the offsets of the + various subsections and fill in the content. */ + for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext) + { +#if 0 + Elf_Scn *scn = elf_getscn (ctx->out.elf, asmscn->data.main.scnndx); +#else + Elf_Scn *scn = asmscn->data.main.scn; +#endif + off_t offset = 0; + AsmScn_t *asmsubscn = asmscn; + + do + { + struct AsmData *content = asmsubscn->content; + bool first = true; + + offset = ((offset + asmsubscn->max_align - 1) + & ~(asmsubscn->max_align - 1)); + + /* Update the offset for this subsection. This field now + stores the offset of the first by in this subsection. */ + asmsubscn->offset = offset; + + /* Note that the content list is circular. */ + if (content != NULL) + do + { + Elf_Data *newdata = elf_newdata (scn); + + if (newdata == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + + newdata->d_buf = content->data; + newdata->d_type = ELF_T_BYTE; + newdata->d_size = content->len; + newdata->d_off = offset; + newdata->d_align = first ? asmsubscn->max_align : 1; + + offset += content->len; + } + while ((content = content->next) != asmsubscn->content); + } + while ((asmsubscn = asmsubscn->subnext) != NULL); + } + + + /* Create the symbol table if necessary. */ + if (ctx->nsymbol_tab > 0) + { + /* Create the symbol table and string table section names. */ + symscn_strent = ebl_strtabadd (ctx->section_strtab, ".symtab", 8); + strscn_strent = ebl_strtabadd (ctx->section_strtab, ".strtab", 8); + + /* Create the symbol string table section. */ + Elf_Scn *strscn = elf_newscn (ctx->out.elf); + strtabdata = elf_newdata (strscn); + shdr = gelf_getshdr (strscn, &shdr_mem); + if (strtabdata == NULL || shdr == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + strscnndx = elf_ndxscn (strscn); + + ebl_strtabfinalize (ctx->symbol_strtab, strtabdata); + + shdr->sh_type = SHT_STRTAB; + assert (shdr->sh_entsize == 0); + + (void) gelf_update_shdr (strscn, shdr); + + /* Create the symbol table section. */ + Elf_Scn *symscn = elf_newscn (ctx->out.elf); + data = elf_newdata (symscn); + shdr = gelf_getshdr (symscn, &shdr_mem); + if (data == NULL || shdr == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + symscnndx = elf_ndxscn (symscn); + + /* We know how many symbols there will be in the symbol table. */ + data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM, + ctx->nsymbol_tab + 1, EV_CURRENT); + symtab = malloc (data->d_size); + if (symtab == NULL) + return -1; + data->d_buf = symtab; + data->d_type = ELF_T_SYM; + data->d_off = 0; + + /* Clear the first entry. */ + GElf_Sym syment; + memset (&syment, '\0', sizeof (syment)); + (void) gelf_update_sym (data, 0, &syment); + + /* Iterate over the symbol table. */ + void *runp = NULL; + int ptr_local = 1; /* Start with index 1; zero remains unused. */ + int ptr_nonlocal = ctx->nsymbol_tab; + uint32_t *xshndx = NULL; + AsmSym_t *sym; + while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL) + if (asm_emit_symbol_p (ebl_string (sym->strent))) + { + assert (ptr_local <= ptr_nonlocal); + + syment.st_name = ebl_strtaboffset (sym->strent); + syment.st_info = GELF_ST_INFO (sym->binding, sym->type); + syment.st_other = 0; + syment.st_value = sym->scn->offset + sym->offset; + syment.st_size = sym->size; + + /* Add local symbols at the beginning, the other from + the end. */ + int ptr = sym->binding == STB_LOCAL ? ptr_local++ : ptr_nonlocal--; + + /* Determine the section index. We have to handle the + overflow correctly. */ + Elf_Scn *scn = (sym->scn->subsection_id == 0 + ? sym->scn->data.main.scn + : sym->scn->data.up->data.main.scn); + + Elf32_Word ndx; + if (unlikely (scn == ASM_ABS_SCN)) + ndx = SHN_ABS; + else if (unlikely (scn == ASM_COM_SCN)) + ndx = SHN_COMMON; + else if (unlikely ((ndx = elf_ndxscn (scn)) >= SHN_LORESERVE)) + { + if (unlikely (xshndx == NULL)) + { + /* The extended section index section does not yet + exist. */ + Elf_Scn *xndxscn; + + xndxscn = elf_newscn (ctx->out.elf); + xndxdata = elf_newdata (xndxscn); + shdr = gelf_getshdr (xndxscn, &shdr_mem); + if (xndxdata == NULL || shdr == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + xndxscnndx = elf_ndxscn (xndxscn); + + shdr->sh_type = SHT_SYMTAB_SHNDX; + shdr->sh_entsize = sizeof (Elf32_Word); + shdr->sh_addralign = sizeof (Elf32_Word); + shdr->sh_link = symscnndx; + + (void) gelf_update_shdr (xndxscn, shdr); + + xndxscn_strent = ebl_strtabadd (ctx->section_strtab, + ".symtab_shndx", 14); + + /* Note that using 'elf32_fsize' instead of + 'gelf_fsize' here is correct. */ + xndxdata->d_size = elf32_fsize (ELF_T_WORD, + ctx->nsymbol_tab + 1, + EV_CURRENT); + xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size); + if (xshndx == NULL) + return -1; + /* Using ELF_T_WORD here relies on the fact that the + 32- and 64-bit types are the same size. */ + xndxdata->d_type = ELF_T_WORD; + xndxdata->d_off = 0; + } + + /* Store the real section index in the extended setion + index table. */ + assert ((size_t) ptr < ctx->nsymbol_tab + 1); + xshndx[ptr] = ndx; + + /* And signal that this happened. */ + ndx = SHN_XINDEX; + } + syment.st_shndx = ndx; + + /* Remember where we put the symbol. */ + sym->symidx = ptr; + + (void) gelf_update_sym (data, ptr, &syment); + } + + assert (ptr_local == ptr_nonlocal + 1); + + shdr->sh_type = SHT_SYMTAB; + shdr->sh_link = strscnndx; + shdr->sh_info = ptr_local; + shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT); + shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1, + EV_CURRENT); + + (void) gelf_update_shdr (symscn, shdr); + } + + + /* Create the section header string table section and fill in the + references in the section headers. */ + shstrscn = elf_newscn (ctx->out.elf); + shstrtabdata = elf_newdata (shstrscn); + shdr = gelf_getshdr (shstrscn, &shdr_mem); + if (shstrscn == NULL || shstrtabdata == NULL || shdr == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + + + /* Add the name of the section header string table. */ + shstrscn_strent = ebl_strtabadd (ctx->section_strtab, ".shstrtab", 10); + + ebl_strtabfinalize (ctx->section_strtab, shstrtabdata); + + shdr->sh_type = SHT_STRTAB; + assert (shdr->sh_entsize == 0); + shdr->sh_name = ebl_strtaboffset (shstrscn_strent); + + (void) gelf_update_shdr (shstrscn, shdr); + + + /* Create the section groups. */ + if (ctx->groups != NULL) + { + AsmScnGrp_t *runp = ctx->groups->next; + + do + { + Elf_Scn *scn; + Elf32_Word *grpdata; + + scn = runp->scn; + assert (scn != NULL); + shdr = gelf_getshdr (scn, &shdr_mem); + assert (shdr != NULL); + + data = elf_newdata (scn); + if (data == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + + /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize' + here. */ + data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1, + EV_CURRENT); + grpdata = data->d_buf = malloc (data->d_size); + if (grpdata == NULL) + return -1; + data->d_type = ELF_T_WORD; + data->d_off = 0; + data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT); + + /* The first word of the section is filled with the flag word. */ + *grpdata++ = runp->flags; + + if (runp->members != NULL) + { + AsmScn_t *member = runp->members->data.main.next_in_group; + + do + { + /* Only sections, not subsections, can be registered + as member of a group. The subsections get + automatically included. */ + assert (member->subsection_id == 0); + + *grpdata++ = elf_ndxscn (member->data.main.scn); + } + while ((member = member->data.main.next_in_group) + != runp->members->data.main.next_in_group); + } + + /* Construct the section header. */ + shdr->sh_name = ebl_strtaboffset (runp->strent); + shdr->sh_type = SHT_GROUP; + shdr->sh_flags = 0; + shdr->sh_link = symscnndx; + /* If the user did not specify a signature we use the initial + empty symbol in the symbol table as the signature. */ + shdr->sh_info = (runp->signature != NULL + ? runp->signature->symidx : 0); + + (void) gelf_update_shdr (scn, shdr); + } + while ((runp = runp->next) != ctx->groups->next); + } + + + /* Add the name to the symbol section. */ + if (likely (symscnndx != 0)) + { + Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx); + + shdr = gelf_getshdr (scn, &shdr_mem); + + shdr->sh_name = ebl_strtaboffset (symscn_strent); + + (void) gelf_update_shdr (scn, shdr); + + + /* Add the name to the string section. */ + assert (strscnndx != 0); + scn = elf_getscn (ctx->out.elf, strscnndx); + + shdr = gelf_getshdr (scn, &shdr_mem); + + shdr->sh_name = ebl_strtaboffset (strscn_strent); + + (void) gelf_update_shdr (scn, shdr); + + + /* Add the name to the extended symbol index section. */ + if (xndxscnndx != 0) + { + scn = elf_getscn (ctx->out.elf, xndxscnndx); + + shdr = gelf_getshdr (scn, &shdr_mem); + + shdr->sh_name = ebl_strtaboffset (xndxscn_strent); + + (void) gelf_update_shdr (scn, shdr); + } + } + + + /* Iterate over the created sections and fill in the names. */ + for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext) + { + shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem); + /* This better should not fail. */ + assert (shdr != NULL); + + shdr->sh_name = ebl_strtaboffset (asmscn->data.main.strent); + + /* We now know the maximum alignment. */ + shdr->sh_addralign = asmscn->max_align; + + (void) gelf_update_shdr (asmscn->data.main.scn, shdr); + } + + /* Put the reference to the section header string table in the ELF + header. */ + ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem); + assert (ehdr != NULL); + + shstrscnndx = elf_ndxscn (shstrscn); + if (unlikely (shstrscnndx > SHN_HIRESERVE) + || unlikely (shstrscnndx == SHN_XINDEX)) + { + /* The index of the section header string sectio is too large. */ + Elf_Scn *scn = elf_getscn (ctx->out.elf, 0); + + /* Get the header for the zeroth section. */ + shdr = gelf_getshdr (scn, &shdr_mem); + /* This better does not fail. */ + assert (shdr != NULL); + + /* The sh_link field of the zeroth section header contains the value. */ + shdr->sh_link = shstrscnndx; + + (void) gelf_update_shdr (scn, shdr); + + /* This is the sign for the overflow. */ + ehdr->e_shstrndx = SHN_XINDEX; + } + else + ehdr->e_shstrndx = elf_ndxscn (shstrscn); + + gelf_update_ehdr (ctx->out.elf, ehdr); + + /* Write out the ELF file. */ + if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP)) < 0) + { + __libasm_seterrno (ASM_E_LIBELF); + result = -1; + } + + /* We do not need the section header and symbol string tables anymore. */ + free (shstrtabdata->d_buf); + if (strtabdata != NULL) + free (strtabdata->d_buf); + /* We might have allocated the extended symbol table index. */ + if (xndxdata != NULL) + free (xndxdata->d_buf); + + /* Free section groups memory. */ + AsmScnGrp_t *scngrp = ctx->groups; + if (scngrp != NULL) + do + free (elf_getdata (scngrp->scn, NULL)->d_buf); + while ((scngrp = scngrp->next) != ctx->groups); + + /* Finalize the ELF handling. */ + if (unlikely (elf_end (ctx->out.elf)) != 0) + { + __libasm_seterrno (ASM_E_LIBELF); + result = -1; + } + + /* Free the temporary resources. */ + free (symtab); + + return result; +} + + +int +asm_end (ctx) + AsmCtx_t *ctx; +{ + int result; + + if (ctx == NULL) + /* Something went wrong earlier. */ + return -1; + + result = unlikely (ctx->textp) ? text_end (ctx) : binary_end (ctx); + if (result != 0) + return result; + + /* Make the new file globally readable and user/group-writable. */ + if (fchmod (ctx->fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) != 0) + { + __libasm_seterrno (ASM_E_CANNOT_CHMOD); + return -1; + } + + /* Rename output file. */ + if (rename (ctx->tmp_fname, ctx->fname) != 0) + { + __libasm_seterrno (ASM_E_CANNOT_RENAME); + return -1; + } + + /* Free the resources. */ + __libasm_finictx (ctx); + + return 0; +} + + +static void +free_section (AsmScn_t *scnp) +{ + void *oldp; + + if (scnp->subnext != NULL) + free_section (scnp->subnext); + + struct AsmData *data = scnp->content; + if (data != NULL) + do + { + oldp = data; + data = data->next; + free (oldp); + } + while (oldp != scnp->content); + + free (scnp); +} + + +void +__libasm_finictx (ctx) + AsmCtx_t *ctx; +{ + /* Iterate through section table and free individual entries. */ + AsmScn_t *scn = ctx->section_list; + while (scn != NULL) + { + AsmScn_t *oldp = scn; + scn = scn->allnext; + free_section (oldp); + } + + /* Free the resources of the symbol table. */ + void *runp = NULL; + AsmSym_t *sym; + while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL) + free (sym); + asm_symbol_tab_free (&ctx->symbol_tab); + + + /* Free section groups. */ + AsmScnGrp_t *scngrp = ctx->groups; + if (scngrp != NULL) + do + { + AsmScnGrp_t *oldp = scngrp; + + scngrp = scngrp->next; + free (oldp); + } + while (scngrp != ctx->groups); + + + if (unlikely (ctx->textp)) + { + /* Close the stream. */ + fclose (ctx->out.file); + } + else + { + /* Close the output file. */ + /* XXX We should test for errors here but what would we do if we'd + find any. */ + (void) close (ctx->fd); + + /* And the string tables. */ + ebl_strtabfree (ctx->section_strtab); + ebl_strtabfree (ctx->symbol_strtab); + } + + /* Initialize the lock. */ + rwlock_fini (ctx->lock); + + /* Finally free the data structure. */ + free (ctx); +} diff --git a/libasm/asm_error.c b/libasm/asm_error.c new file mode 100644 index 00000000..9d2d81ed --- /dev/null +++ b/libasm/asm_error.c @@ -0,0 +1,183 @@ +/* Error handling in libasm. + Copyright (C) 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libasmP.h" + + +/* This is the key for the thread specific memory. */ +static tls_key_t key; + +/* The error number. Used in non-threaded programs. */ +static int global_error; +static bool threaded; +/* We need to initialize the thread-specific data. */ +once_define (static, once); + +/* The initialization and destruction functions. */ +static void init (void); +static void free_key_mem (void *mem); + + +int +asm_errno (void) +{ + int result; + + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if (threaded) + { + /* We have a key. Use it to get the thread-specific buffer. */ + int *buffer = getspecific (key); + if (buffer == NULL) + { + /* No buffer allocated so far. */ + buffer = (int *) malloc (sizeof (int)); + if (buffer == NULL) + /* No more memory available. We use the static buffer. */ + buffer = &global_error; + + setspecific (key, buffer); + + *buffer = 0; + } + + result = *buffer; + *buffer = ASM_E_NOERROR; + return result; + } + + result = global_error; + global_error = ASM_E_NOERROR; + return result; +} + + +void +__libasm_seterrno (value) + int value; +{ + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if (threaded) + { + /* We have a key. Use it to get the thread-specific buffer. */ + int *buffer = getspecific (key); + if (buffer == NULL) + { + /* No buffer allocated so far. */ + buffer = malloc (sizeof (int)); + if (buffer == NULL) + /* No more memory available. We use the static buffer. */ + buffer = &global_error; + + setspecific (key, buffer); + } + + *buffer = value; + } + + global_error = value; +} + + +/* Return the appropriate message for the error. */ +static const char *msgs[ASM_E_NUM] = +{ + [ASM_E_NOERROR] = N_("no error"), + [ASM_E_NOMEM] = N_("out of memory"), + [ASM_E_CANNOT_CREATE] = N_("cannot create output file"), + [ASM_E_INVALID] = N_("invalid parameter"), + [ASM_E_CANNOT_CHMOD] = N_("cannot change mode of output file"), + [ASM_E_CANNOT_RENAME] = N_("cannot rename output file"), + [ASM_E_DUPLSYM] = N_("duplicate symbol"), + [ASM_E_TYPE] = N_("invalid section type for operation") +}; + +const char * +asm_errmsg (error) + int error; +{ + int last_error; + + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if ((error == 0 || error == -1) && threaded) + { + /* We have a key. Use it to get the thread-specific buffer. */ + int *buffer = (int *) getspecific (key); + if (buffer == NULL) + { + /* No buffer allocated so far. */ + buffer = (int *) malloc (sizeof (int)); + if (buffer == NULL) + /* No more memory available. We use the static buffer. */ + buffer = &global_error; + + setspecific (key, buffer); + *buffer = 0; + } + + last_error = *buffer; + } + else + last_error = global_error; + + if (error < -1) + return _("Unknown error"); + if (error == 0 && last_error == 0) + /* No error. */ + return NULL; + + if (error != -1) + last_error = error; + + if (last_error == ASM_E_LIBELF) + return elf_errmsg (-1); + + return _(msgs[last_error]); +} + + +/* Free the thread specific data, this is done if a thread terminates. */ +static void +free_key_mem (void *mem) +{ + free (mem); + setspecific (key, NULL); +} + + +/* Initialize the key for the global variable. */ +static void +init (void) +{ + // XXX Screw you, gcc4, the unused function attribute does not work. + __asm ("" :: "r" (free_key_mem)); + + if (key_create (&key, free_key_mem) == 0) + /* Creating the key succeeded. */ + threaded = true; +} diff --git a/libasm/asm_fill.c b/libasm/asm_fill.c new file mode 100644 index 00000000..67b64417 --- /dev/null +++ b/libasm/asm_fill.c @@ -0,0 +1,62 @@ +/* Determine fill pattern for a section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include + + +int +asm_fill (asmscn, bytes, len) + AsmScn_t *asmscn; + void *bytes; + size_t len; +{ + struct FillPattern *pattern; + struct FillPattern *old_pattern; + + if (asmscn == NULL) + /* Some earlier error. */ + return -1; + + if (bytes == NULL) + /* Use the default pattern. */ + pattern = (struct FillPattern *) __libasm_default_pattern; + else + { + /* Allocate appropriate memory. */ + pattern = (struct FillPattern *) malloc (sizeof (struct FillPattern) + + len); + if (pattern == NULL) + return -1; + + pattern->len = len; + memcpy (pattern->bytes, bytes, len); + } + + old_pattern = asmscn->pattern; + asmscn->pattern = pattern; + + /* Free the old data structure if we have allocated it. */ + if (old_pattern != __libasm_default_pattern) + free (old_pattern); + + return 0; +} diff --git a/libasm/asm_getelf.c b/libasm/asm_getelf.c new file mode 100644 index 00000000..3bbb0d90 --- /dev/null +++ b/libasm/asm_getelf.c @@ -0,0 +1,29 @@ +/* Return ELF descriptor associated with the assembler context. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +Elf * +asm_getelf (ctx) + AsmCtx_t *ctx; +{ + return ctx != NULL ? ctx->out.elf : NULL; +} diff --git a/libasm/asm_newabssym.c b/libasm/asm_newabssym.c new file mode 100644 index 00000000..fba46f0f --- /dev/null +++ b/libasm/asm_newabssym.c @@ -0,0 +1,121 @@ +/* Create new ABS symbol. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + + +/* Object for special COMMON section. */ +static const AsmScn_t __libasm_abs_scn = + { + .data = { + .main = { + .scn = ASM_ABS_SCN + } + } + }; + + +AsmSym_t * +asm_newabssym (ctx, name, size, value, type, binding) + AsmCtx_t *ctx; + const char *name; + GElf_Xword size; + GElf_Addr value; + int type; + int binding; +{ + AsmSym_t *result; + + if (ctx == NULL) + /* Something went wrong before. */ + return NULL; + + /* Common symbols are public. Therefore the user must provide a + name. */ + if (name == NULL) + { + __libasm_seterrno (ASM_E_INVALID); + return NULL; + } + + rwlock_wrlock (ctx->lock); + + result = (AsmSym_t *) malloc (sizeof (AsmSym_t)); + if (result == NULL) + return NULL; + + result->scn = (AsmScn_t *) &__libasm_abs_scn; + result->size = size; + result->type = type; + result->binding = binding; + result->symidx = 0; + result->strent = ebl_strtabadd (ctx->symbol_strtab, name, 0); + + /* The value of an ABS symbol must not be modified. Since there are + no subsection and the initial offset of the section is 0 we can + get the alignment recorded by storing it into the offset + field. */ + result->offset = value; + + if (unlikely (ctx->textp)) + { + /* An absolute symbol can be defined by giving a symbol a + specific value. */ + if (binding == STB_GLOBAL) + fprintf (ctx->out.file, "\t.globl %s\n", name); + else if (binding == STB_WEAK) + fprintf (ctx->out.file, "\t.weak %s\n", name); + + if (type == STT_OBJECT) + fprintf (ctx->out.file, "\t.type %s,@object\n", name); + else if (type == STT_FUNC) + fprintf (ctx->out.file, "\t.type %s,@function\n", name); + + fprintf (ctx->out.file, "%s = %llu\n", + name, (unsigned long long int) value); + + if (size != 0) + fprintf (ctx->out.file, "\t.size %s, %llu\n", + name, (unsigned long long int) size); + } + else + { + /* Put the symbol in the hash table so that we can later find it. */ + if (asm_symbol_tab_insert (&ctx->symbol_tab, elf_hash (name), result) + != 0) + { + /* The symbol already exists. */ + __libasm_seterrno (ASM_E_DUPLSYM); + free (result); + result = NULL; + } + else if (name != NULL && asm_emit_symbol_p (name)) + /* Only count non-private symbols. */ + ++ctx->nsymbol_tab; + } + + rwlock_unlock (ctx->lock); + + return result; +} diff --git a/libasm/asm_newcomsym.c b/libasm/asm_newcomsym.c new file mode 100644 index 00000000..61e5a909 --- /dev/null +++ b/libasm/asm_newcomsym.c @@ -0,0 +1,102 @@ +/* Create new COMMON symbol. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + + +/* Object for special COMMON section. */ +static const AsmScn_t __libasm_com_scn = + { + .data = { + .main = { + .scn = ASM_COM_SCN + } + } + }; + + +AsmSym_t * +asm_newcomsym (ctx, name, size, align) + AsmCtx_t *ctx; + const char *name; + GElf_Xword size; + GElf_Addr align; +{ + AsmSym_t *result; + + if (ctx == NULL) + /* Something went wrong before. */ + return NULL; + + /* Common symbols are public. Therefore the user must provide a + name. */ + if (name == NULL) + { + __libasm_seterrno (ASM_E_INVALID); + return NULL; + } + + rwlock_wrlock (ctx->lock); + + result = (AsmSym_t *) malloc (sizeof (AsmSym_t)); + if (result == NULL) + return NULL; + + result->scn = (AsmScn_t *) &__libasm_com_scn; + result->size = size; + /* XXX Do we have to allow a different type? */ + result->type = STT_OBJECT; + /* XXX Do we have to allow a different binding? */ + result->binding = STB_GLOBAL; + result->symidx = 0; + result->strent = ebl_strtabadd (ctx->symbol_strtab, name, 0); + + /* The value of a COM symbol is the alignment. Since there are no + subsection and the initial offset of the section is 0 we can get + the alignment recorded by storing it into the offset field. */ + result->offset = align; + + if (unlikely (ctx->textp)) + fprintf (ctx->out.file, "\t.comm %s, %" PRIuMAX ", %" PRIuMAX "\n", + name, (uintmax_t) size, (uintmax_t) align); + else + { + /* Put the symbol in the hash table so that we can later find it. */ + if (asm_symbol_tab_insert (&ctx->symbol_tab, elf_hash (name), result) + != 0) + { + /* The symbol already exists. */ + __libasm_seterrno (ASM_E_DUPLSYM); + free (result); + result = NULL; + } + else if (name != NULL && asm_emit_symbol_p (name)) + /* Only count non-private symbols. */ + ++ctx->nsymbol_tab; + } + + rwlock_unlock (ctx->lock); + + return result; +} diff --git a/libasm/asm_newscn.c b/libasm/asm_newscn.c new file mode 100644 index 00000000..75890a60 --- /dev/null +++ b/libasm/asm_newscn.c @@ -0,0 +1,202 @@ +/* Create new section in output file. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* Memory for the default pattern. The type uses a flexible array + which does work well with a static initializer. So we play some + dirty tricks here. */ +static const struct +{ + struct FillPattern pattern; + char zero; +} xdefault_pattern = + { + .pattern = + { + .len = 1 + }, + .zero = '\0' + }; +const struct FillPattern *__libasm_default_pattern = &xdefault_pattern.pattern; + + +static AsmScn_t * +text_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags) +{ + /* Buffer where we construct the flag string. */ + char flagstr[sizeof (GElf_Xword) * 8 + 5]; + char *wp = flagstr; + const char *typestr = ""; + + /* Only write out the flag string if this is the first time the + section is selected. Some assemblers cannot cope with the + .section pseudo-op otherwise. */ + wp = stpcpy (wp, ", \""); + + if (flags & SHF_WRITE) + *wp++ = 'w'; + if (flags & SHF_ALLOC) + *wp++ = 'a'; + if (flags & SHF_EXECINSTR) + *wp++ = 'x'; + if (flags & SHF_MERGE) + *wp++ = 'M'; + if (flags & SHF_STRINGS) + *wp++ = 'S'; + if (flags & SHF_LINK_ORDER) + *wp++ = 'L'; + + *wp++ = '"'; + + if (type == SHT_PROGBITS) + typestr = ",@progbits"; + else if (type == SHT_NOBITS) + typestr = ",@nobits"; + + /* Terminate the string. */ + *wp = '\0'; + + printf ("\t.section \"%s\"%s%s\n", result->name, flagstr, typestr); + + return result; +} + + +static AsmScn_t * +binary_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags, + size_t scnname_len) +{ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Scn *scn; + + /* The initial subsection has the number zero. */ + result->subsection_id = 0; + + /* We start at offset zero. */ + result->offset = 0; + /* And generic alignment. */ + result->max_align = 1; + + /* No output yet. */ + result->content = NULL; + + /* Put the default fill pattern in place. */ + result->pattern = (struct FillPattern *) __libasm_default_pattern; + + /* There are no subsections so far. */ + result->subnext = NULL; + + /* Add the name to the section header string table. */ + result->data.main.strent = ebl_strtabadd (result->ctx->section_strtab, + result->name, scnname_len); + assert (result->data.main.strent != NULL); + + /* Create the new ELF section. */ + result->data.main.scn = scn = elf_newscn (result->ctx->out.elf); + if (scn == NULL) + { + free (result); + __libasm_seterrno (ASM_E_LIBELF); + return NULL; + } + + /* Not part of a section group (yet). */ + result->data.main.next_in_group = NULL; + + /* Remember the flags. */ + shdr = gelf_getshdr (scn, &shdr_mem); + + shdr->sh_flags = flags; + result->type = shdr->sh_type = type; + + (void) gelf_update_shdr (scn, shdr); + + return result; +} + + +AsmScn_t * +asm_newscn (ctx, scnname, type, flags) + AsmCtx_t *ctx; + const char *scnname; + GElf_Word type; + GElf_Xword flags; +{ + size_t scnname_len = strlen (scnname) + 1; + unsigned long int hval; + AsmScn_t *result; + + /* If no context is given there might be an earlier error. */ + if (ctx == NULL) + return NULL; + + /* Check whether only flags are set which areselectable by the user. */ + if (unlikely ((flags & ~(SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE + | SHF_STRINGS | SHF_LINK_ORDER)) != 0) + /* We allow only two section types: data and data without file + representation. */ + || (type != SHT_PROGBITS && unlikely (type != SHT_NOBITS))) + { + __libasm_seterrno (ASM_E_INVALID); + return NULL; + } + + hval = elf_hash (scnname); + + rwlock_wrlock (ctx->lock); + + /* This is a new section. */ + result = (AsmScn_t *) malloc (sizeof (AsmScn_t) + scnname_len); + if (result != NULL) + { + /* Add the name. */ + memcpy (result->name, scnname, scnname_len); + + /* Add the reference to the context. */ + result->ctx = ctx; + + /* Perform operations according to output mode. */ + result = (unlikely (ctx->textp) + ? text_newscn (result, type, flags) + : binary_newscn (result, type, flags, scnname_len)); + + /* If everything went well finally add the new section to the hash + table. */ + if (result != NULL) + { + result->allnext = ctx->section_list; + ctx->section_list = result; + } + } + + rwlock_unlock (ctx->lock); + + return result; +} +INTDEF(asm_newscn) diff --git a/libasm/asm_newscn_ingrp.c b/libasm/asm_newscn_ingrp.c new file mode 100644 index 00000000..bfbdc6a0 --- /dev/null +++ b/libasm/asm_newscn_ingrp.c @@ -0,0 +1,66 @@ +/* Create new section, which is member of a group, in output file. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "libasmP.h" + + +AsmScn_t * +asm_newscn_ingrp (ctx, scnname, type, flags, grp) + AsmCtx_t *ctx; + const char *scnname; + GElf_Word type; + GElf_Xword flags; + AsmScnGrp_t *grp; +{ + AsmScn_t *result = INTUSE (asm_newscn) (ctx, scnname, type, flags); + + if (likely (result != NULL)) + { + /* We managed to create a section group. Add it to the section + group. */ + if (grp->nmembers == 0) + { + assert (grp->members == NULL); + grp->members = result->data.main.next_in_group = result; + } + else + { + result->data.main.next_in_group + = grp->members->data.main.next_in_group; + grp->members = grp->members->data.main.next_in_group = result; + } + + ++grp->nmembers; + + /* Set the SHF_GROUP flag. */ + if (likely (! ctx->textp)) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (result->data.main.scn, &shdr_mem); + + assert (shdr != NULL); + shdr->sh_flags |= SHF_GROUP; + + (void) gelf_update_shdr (result->data.main.scn, shdr); + } + } + + return result; +} diff --git a/libasm/asm_newscngrp.c b/libasm/asm_newscngrp.c new file mode 100644 index 00000000..c1c8be3e --- /dev/null +++ b/libasm/asm_newscngrp.c @@ -0,0 +1,90 @@ +/* Create new section group. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libasmP.h" +#include + + + +AsmScnGrp_t * +asm_newscngrp (ctx, grpname, signature, flags) + AsmCtx_t *ctx; + const char *grpname; + AsmSym_t *signature; + Elf32_Word flags; +{ + AsmScnGrp_t *result; + size_t grpname_len = strlen (grpname) + 1; + + if (ctx == NULL) + return NULL; + + if ((flags & ~GRP_COMDAT) != 0) + { + /* This is not a supported flag. */ + __libasm_seterrno (ASM_E_INVALID); + return NULL; + } + + result = (AsmScnGrp_t *) malloc (sizeof (AsmScnGrp_t) + grpname_len); + if (result == NULL) + return NULL; + + result->signature = signature; + result->members = NULL; + result->nmembers = 0; + result->flags = flags; + + memcpy (result->name, grpname, grpname_len); + result->strent = ebl_strtabadd (ctx->section_strtab, result->name, + grpname_len); + + if (unlikely (ctx->textp)) + // XXX TBI. What is the format? + abort (); + else + { + result->scn = elf_newscn (ctx->out.elf); + if (result->scn == NULL) + { + /* Couldn't allocate a new section. */ + __libasm_seterrno (ASM_E_LIBELF); + free (result); + return NULL; + } + } + + /* Enqueue is the context data structure. */ + if (ctx->ngroups == 0) + { + assert (ctx->groups == NULL); + ctx->groups = result->next = result; + } + else + { + result->next = ctx->groups->next; + ctx->groups = ctx->groups->next = result; + } + ++ctx->ngroups; + + return result; +} diff --git a/libasm/asm_newsubscn.c b/libasm/asm_newsubscn.c new file mode 100644 index 00000000..e767720e --- /dev/null +++ b/libasm/asm_newsubscn.c @@ -0,0 +1,84 @@ +/* Create new subsection section in given section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include +#include + + +AsmScn_t * +asm_newsubscn (asmscn, nr) + AsmScn_t *asmscn; + unsigned int nr; +{ + AsmScn_t *runp; + AsmScn_t *newp; + + /* Just return if no section is given. The error must have been + somewhere else. */ + if (asmscn == NULL) + return NULL; + + /* Determine whether there is already a subsection with this number. */ + runp = asmscn->subsection_id == 0 ? asmscn : asmscn->data.up; + while (1) + { + if (runp->subsection_id == nr) + /* Found it. */ + return runp; + + if (runp->subnext == NULL || runp->subnext->subsection_id > nr) + break; + + runp = runp->subnext; + } + + newp = (AsmScn_t *) malloc (sizeof (AsmScn_t)); + if (newp == NULL) + return NULL; + + /* Same assembler context than the original section. */ + newp->ctx = runp->ctx; + + /* User provided the subsectio nID. */ + newp->subsection_id = nr; + + /* Inherit the parent's type. */ + newp->type = runp->type; + + /* Pointer to the zeroth subsection. */ + newp->data.up = runp->subsection_id == 0 ? runp : runp->data.up; + + /* We start at offset zero. */ + newp->offset = 0; + /* And generic alignment. */ + newp->max_align = 1; + + /* No output yet. */ + newp->content = NULL; + + /* Inherit the fill pattern from the section this one is derived from. */ + newp->pattern = asmscn->pattern; + + /* Enqueue at the right position in the list. */ + newp->subnext = runp->subnext; + runp->subnext = newp; + + return newp; +} diff --git a/libasm/asm_newsym.c b/libasm/asm_newsym.c new file mode 100644 index 00000000..70ad9e5d --- /dev/null +++ b/libasm/asm_newsym.c @@ -0,0 +1,123 @@ +/* Define new symbol for current position in given section. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + + +AsmSym_t * +asm_newsym (asmscn, name, size, type, binding) + AsmScn_t *asmscn; + const char *name; + GElf_Xword size; + int type; + int binding; +{ +#define TEMPSYMLEN 10 + char tempsym[TEMPSYMLEN]; + AsmSym_t *result; + + if (asmscn == NULL) + /* Something went wrong before. */ + return NULL; + + /* Generate a temporary symbol if necessary. */ + if (name == NULL) + { + /* If a local symbol name is created the symbol better have + local binding. */ + if (binding != STB_LOCAL) + { + __libasm_seterrno (ASM_E_INVALID); + return NULL; + } + + // XXX This requires getting the format from the machine backend. */ + snprintf (tempsym, TEMPSYMLEN, ".L%07u", asmscn->ctx->tempsym_count++); + + name = tempsym; + } + + size_t name_len = strlen (name) + 1; + + result = (AsmSym_t *) malloc (sizeof (AsmSym_t) + name_len); + if (result == NULL) + return NULL; + + rwlock_wrlock (asmscn->ctx->lock); + + result->scn = asmscn; + result->offset = asmscn->offset; + result->size = size; + result->type = type; + result->binding = binding; + result->symidx = 0; + result->strent = ebl_strtabadd (asmscn->ctx->symbol_strtab, + memcpy (result + 1, name, name_len), 0); + + if (unlikely (asmscn->ctx->textp)) + { + /* We are only interested in the name and don't need to know whether + it is a local name or not. */ + /* First print the binding pseudo-op. */ + if (binding == STB_GLOBAL) + fprintf (asmscn->ctx->out.file, "\t.globl\t%s\n", name); + else if (binding == STB_WEAK) + fprintf (asmscn->ctx->out.file, "\t.weak\t%s\n", name); + + /* Next the symbol type. */ + if (type == STT_OBJECT) + fprintf (asmscn->ctx->out.file, "\t.type\t%s,@object\n", name); + else if (type == STT_FUNC) + fprintf (asmscn->ctx->out.file, "\t.type\t%s,@function\n", name); + + /* Finally the size and the label. */ + fprintf (asmscn->ctx->out.file, "\t.size\t%s,%" PRIuMAX "\n%s:\n", + name, (uintmax_t) size, name); + } + else + { + /* Put the symbol in the hash table so that we can later find it. */ + if (asm_symbol_tab_insert (&asmscn->ctx->symbol_tab, elf_hash (name), + result) != 0) + { + /* The symbol already exists. */ + __libasm_seterrno (ASM_E_DUPLSYM); + /* Note that we can free the entry since there must be no + reference in the string table to the string. We can only + fail to insert the symbol into the symbol table if there + is already a symbol with this name. In this case the + ebl_strtabadd function would use the previously provided + name. */ + free (result); + result = NULL; + } + else if (name != tempsym && asm_emit_symbol_p (name)) + /* Only count non-private symbols. */ + ++asmscn->ctx->nsymbol_tab; + } + + rwlock_unlock (asmscn->ctx->lock); + + return result; +} diff --git a/libasm/asm_scngrp_newsignature.c b/libasm/asm_scngrp_newsignature.c new file mode 100644 index 00000000..d4042a24 --- /dev/null +++ b/libasm/asm_scngrp_newsignature.c @@ -0,0 +1,33 @@ +/* Update signature of section group. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libasmP.h" + + +int +asm_scngrp_newsignature (grp, signature) + AsmScnGrp_t *grp; + AsmSym_t *signature; +{ + if (grp == NULL || signature == NULL) + return 1; + + grp->signature = signature; + + return 0; +} diff --git a/libasm/libasm.h b/libasm/libasm.h new file mode 100644 index 00000000..dbdd6fc2 --- /dev/null +++ b/libasm/libasm.h @@ -0,0 +1,155 @@ +/* Interface for libasm. + Copyright (C) 2002 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBASM_H +#define _LIBASM_H 1 + +#include +#include + +#include + + +/* Opaque type for the assembler context descriptor. */ +typedef struct AsmCtx AsmCtx_t; + +/* Opaque type for a section. */ +typedef struct AsmScn AsmScn_t; + +/* Opaque type for a section group. */ +typedef struct AsmScnGrp AsmScnGrp_t; + +/* Opaque type for a symbol. */ +typedef struct AsmSym AsmSym_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Create output file and return descriptor for assembler context. If + TEXTP is true the output is an assembler format text file. + Otherwise an object file is created. The MACHINE parameter + corresponds to an EM_ constant from , KLASS specifies the + class (32- or 64-bit), and DATA specifies the byte order (little or + big endian). */ +extern AsmCtx_t *asm_begin (const char *fname, bool textp, int machine, + int klass, int data); + +/* Abort the operation on the assembler context and free all resources. */ +extern int asm_abort (AsmCtx_t *ctx); + +/* Finalize output file and free all resources. */ +extern int asm_end (AsmCtx_t *ctx); + + +/* Return handle for the named section. If it was not used before + create it. */ +extern AsmScn_t *asm_newscn (AsmCtx_t *ctx, const char *scnname, + GElf_Word type, GElf_Xword flags); + + +/* Similar to 'asm_newscn', but make it part of section group GRP. */ +extern AsmScn_t *asm_newscn_ingrp (AsmCtx_t *ctx, const char *scnname, + GElf_Word type, GElf_Xword flags, + AsmScnGrp_t *grp); + +/* Create new subsection NR in the given section. */ +extern AsmScn_t *asm_newsubscn (AsmScn_t *asmscn, unsigned int nr); + + +/* Return handle for new section group. The signature symbol can be + set later. */ +extern AsmScnGrp_t *asm_newscngrp (AsmCtx_t *ctx, const char *grpname, + AsmSym_t *signature, Elf32_Word flags); + +/* Set or overwrite signature symbol for group. */ +extern int asm_scngrp_newsignature (AsmScnGrp_t *grp, AsmSym_t *signature); + + +/* Add zero terminated string STR of size LEN to (sub)section ASMSCN. */ +extern int asm_addstrz (AsmScn_t *asmscn, const char *str, size_t len); + +/* Add 8-bit signed integer NUM to (sub)section ASMSCN. */ +extern int asm_addint8 (AsmScn_t *asmscn, int8_t num); + +/* Add 8-bit unsigned integer NUM to (sub)section ASMSCN. */ +extern int asm_adduint8 (AsmScn_t *asmscn, uint8_t num); + +/* Add 16-bit signed integer NUM to (sub)section ASMSCN. */ +extern int asm_addint16 (AsmScn_t *asmscn, int16_t num); + +/* Add 16-bit unsigned integer NUM to (sub)section ASMSCN. */ +extern int asm_adduint16 (AsmScn_t *asmscn, uint16_t num); + +/* Add 32-bit signed integer NUM to (sub)section ASMSCN. */ +extern int asm_addint32 (AsmScn_t *asmscn, int32_t num); + +/* Add 32-bit unsigned integer NUM to (sub)section ASMSCN. */ +extern int asm_adduint32 (AsmScn_t *asmscn, uint32_t num); + +/* Add 64-bit signed integer NUM to (sub)section ASMSCN. */ +extern int asm_addint64 (AsmScn_t *asmscn, int64_t num); + +/* Add 64-bit unsigned integer NUM to (sub)section ASMSCN. */ +extern int asm_adduint64 (AsmScn_t *asmscn, uint64_t num); + + +/* Add signed little endian base 128 integer NUM to (sub)section ASMSCN. */ +extern int asm_addsleb128 (AsmScn_t *asmscn, int32_t num); + +/* Add unsigned little endian base 128 integer NUM to (sub)section ASMSCN. */ +extern int asm_adduleb128 (AsmScn_t *asmscn, uint32_t num); + + +/* Define new symbol NAME for current position in given section ASMSCN. */ +extern AsmSym_t *asm_newsym (AsmScn_t *asmscn, const char *name, + GElf_Xword size, int type, int binding); + + +/* Define new common symbol NAME with given SIZE and alignment. */ +extern AsmSym_t *asm_newcomsym (AsmCtx_t *ctx, const char *name, + GElf_Xword size, GElf_Addr align); + +/* Define new common symbol NAME with given SIZE, VALUE, TYPE, and BINDING. */ +extern AsmSym_t *asm_newabssym (AsmCtx_t *ctx, const char *name, + GElf_Xword size, GElf_Addr value, + int type, int binding); + + +/* Align (sub)section offset according to VALUE. */ +extern int asm_align (AsmScn_t *asmscn, GElf_Word value); + +/* Set the byte pattern used to fill gaps created by alignment. */ +extern int asm_fill (AsmScn_t *asmscn, void *bytes, size_t len); + + +/* Return ELF descriptor created for the output file of the given context. */ +extern Elf *asm_getelf (AsmCtx_t *ctx); + + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int asm_errno (void); + +/* Return error string for ERROR. If ERROR is zero, return error string + for most recent error or NULL is none occurred. If ERROR is -1 the + behaviour is similar to the last case except that not NULL but a legal + string is returned. */ +extern const char *asm_errmsg (int __error); + +#ifdef __cplusplus +} +#endif + +#endif /* libasm.h */ diff --git a/libasm/libasm.map b/libasm/libasm.map new file mode 100644 index 00000000..b0b5b5b7 --- /dev/null +++ b/libasm/libasm.map @@ -0,0 +1,33 @@ +ELFUTILS_1.0 { + global: + asm_abort; + asm_addint16; + asm_addint32; + asm_addint64; + asm_addint8; + asm_addsleb128; + asm_addstrz; + asm_adduint16; + asm_adduint32; + asm_adduint64; + asm_adduint8; + asm_adduleb128; + asm_align; + asm_begin; + asm_end; + asm_errmsg; + asm_errno; + asm_fill; + asm_getelf; + asm_newabssym; + asm_newcomsym; + asm_newscn; + asm_newscn_ingrp; + asm_newscngrp; + asm_newsubscn; + asm_newsym; + asm_scngrp_newsignature; + + local: + *; +}; diff --git a/libasm/libasmP.h b/libasm/libasmP.h new file mode 100644 index 00000000..2e4954f6 --- /dev/null +++ b/libasm/libasmP.h @@ -0,0 +1,268 @@ +/* Internal definitions for libasm. + Copyright (C) 2002, 2004 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBASMP_H +#define _LIBASMP_H 1 + +#include + +#include +#include + +/* gettext helper macros. */ +#define _(Str) dgettext ("elfutils", Str) + + +/* Known error codes. */ +enum + { + ASM_E_NOERROR, + ASM_E_NOMEM, /* No more memory. */ + ASM_E_CANNOT_CREATE, /* Output file cannot be created. */ + ASM_E_INVALID, /* Invalid parameters. */ + ASM_E_CANNOT_CHMOD, /* Cannot change mode of output file. */ + ASM_E_CANNOT_RENAME, /* Cannot rename output file. */ + ASM_E_DUPLSYM, /* Duplicate symbol definition. */ + ASM_E_LIBELF, /* Refer to error in libelf. */ + ASM_E_TYPE, /* Invalid section type for operation. */ + ASM_E_NUM /* Keep this entry as the last. */ + }; + + +/* Special sections. */ +#define ASM_ABS_SCN ((Elf_Scn *) 1) +#define ASM_COM_SCN ((Elf_Scn *) 2) + + +/* And the hash table for symbols. */ +#include + + +/* Descriptor for a section. */ +struct AsmScn +{ + /* The underlying assembler context. */ + AsmCtx_t *ctx; + + /* Subsection ID. */ + unsigned int subsection_id; + + /* Section type. */ + GElf_Word type; + + union + { + /* Data only stored in the record for subsection zero. */ + struct + { + /* The ELF section. */ + Elf_Scn *scn; + + /* Entry in the section header string table. */ + struct Ebl_Strent *strent; + + /* Next member of group. */ + struct AsmScn *next_in_group; + } main; + + /* Pointer to the record for subsection zero. */ + AsmScn_t *up; + } data; + + /* Current offset in the (sub)section. */ + GElf_Off offset; + /* Maximum alignment of the section so far. */ + GElf_Word max_align; + + /* Section content. */ + struct AsmData + { + /* Currently used number of bytes in the block. */ + size_t len; + + /* Number of bytes allocated. */ + size_t maxlen; + + /* Pointer to the next block. */ + struct AsmData *next; + + /* The actual data. */ + char data[flexarr_size]; + } *content; + + /* Fill pattern. */ + struct FillPattern + { + size_t len; + char bytes[flexarr_size]; + } *pattern; + + /* Next subsection. */ + AsmScn_t *subnext; + + /* List of all allocated sections. */ + AsmScn_t *allnext; + + /* Name of the section. */ + char name[flexarr_size]; +}; + + +/* Descriptor used for the assembling session. */ +struct AsmCtx +{ + /* File descriptor of the temporary file. */ + int fd; + + /* True if text output is wanted. */ + bool textp; + + /* Output file handle. */ + union + { + /* ELF descriptor of the temporary file. */ + Elf *elf; + /* I/O stream for text output. */ + FILE *file; + } out; + + + /* List with defined sections. */ + AsmScn_t *section_list; + /* Section header string table. */ + struct Ebl_Strtab *section_strtab; + + /* Table with defined symbols. */ + asm_symbol_tab symbol_tab; + /* Number of symbols in the table. */ + unsigned int nsymbol_tab; + /* Symbol string table. */ + struct Ebl_Strtab *symbol_strtab; + + /* List of section groups. */ + struct AsmScnGrp *groups; + /* Number of section groups. */ + size_t ngroups; + + /* Current required alignment for common symbols. */ + GElf_Word common_align; + + /* Lock to handle multithreaded programs. */ + rwlock_define (,lock); + + /* Counter for temporary symbols. */ + unsigned int tempsym_count; + + /* Name of the output file. */ + char *fname; + /* The name of the temporary file. */ + char tmp_fname[flexarr_size]; +}; + + +/* Descriptor for a symbol. */ +struct AsmSym +{ + /* Reference to the section which contains the symbol. */ + AsmScn_t *scn; + + /* Type of the symbol. */ + int8_t type; + /* Binding of the symbol. */ + int8_t binding; + + /* Size of the symbol. */ + GElf_Xword size; + + /* Offset in the section. */ + GElf_Off offset; + + /* Symbol table index of the symbol in the symbol table. */ + size_t symidx; + + /* Reference to name of the symbol. */ + struct Ebl_Strent *strent; +}; + + +/* Descriptor for section group. */ +struct AsmScnGrp +{ + /* Entry in the section header string table. */ + struct Ebl_Strent *strent; + + /* The ELF section. */ + Elf_Scn *scn; + + /* The signature. */ + struct AsmSym *signature; + + /* First member. */ + struct AsmScn *members; + /* Number of members. */ + size_t nmembers; + + /* Flags. */ + Elf32_Word flags; + + /* Next group. */ + struct AsmScnGrp *next; + + /* Name of the section group. */ + char name[flexarr_size]; +}; + + +/* The default fill pattern: one zero byte. */ +extern const struct FillPattern *__libasm_default_pattern + attribute_hidden; + + +/* Ensure there are at least LEN bytes available in the output buffer + for ASMSCN. */ +extern int __libasm_ensure_section_space (AsmScn_t *asmscn, size_t len) + internal_function; + +/* Free all resources associated with the assembler context. */ +extern void __libasm_finictx (AsmCtx_t *ctx) internal_function; + +/* Set error code. */ +extern void __libasm_seterrno (int err) internal_function; + +/* Return handle for the named section. If it was not used before + create it. */ +extern AsmScn_t *__asm_newscn_internal (AsmCtx_t *ctx, const char *scnname, + GElf_Word type, GElf_Xword flags) + attribute_hidden; + + +/* Internal aliases of the asm_addintXX functions. */ +extern int __asm_addint8_internal (AsmScn_t *asmscn, int8_t num) + attribute_hidden; +extern int __asm_addint16_internal (AsmScn_t *asmscn, int16_t num) + attribute_hidden; +extern int __asm_addint32_internal (AsmScn_t *asmscn, int32_t num) + attribute_hidden; +extern int __asm_addint64_internal (AsmScn_t *asmscn, int64_t num) + attribute_hidden; + + + +/* Test whether given symbol is an internal symbol and if yes, whether + we should nevertheless emit it in the symbol table. */ +// XXX The second part should probably be controlled by an option which +// isn't implemented yet +// XXX Also, the format will change with the backend. +#define asm_emit_symbol_p(name) (strncmp (name, ".L", 2) != 0) + +#endif /* libasmP.h */ diff --git a/libasm/symbolhash.c b/libasm/symbolhash.c new file mode 100644 index 00000000..62d2c852 --- /dev/null +++ b/libasm/symbolhash.c @@ -0,0 +1,39 @@ +/* Symbol hash table implementation. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include +#include + +/* Definitions for the symbol hash table. */ +#define TYPE AsmSym_t * +#define NAME asm_symbol_tab +#define ITERATE 1 +#define REVERSE 1 +#define COMPARE(a, b) \ + strcmp (ebl_string ((a)->strent), ebl_string ((b)->strent)) + +#define next_prime __libasm_next_prime +extern size_t next_prime (size_t) attribute_hidden; + +#include "../lib/dynamicsizehash.c" + +#undef next_prime +#define next_prime attribute_hidden __libasm_next_prime +#include "../lib/next_prime.c" diff --git a/libasm/symbolhash.h b/libasm/symbolhash.h new file mode 100644 index 00000000..4377b4b5 --- /dev/null +++ b/libasm/symbolhash.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef SYMBOLHASH_H +#define SYMBOLHASH_H 1 + +/* Definitions for the symbol hash table. */ +#define TYPE AsmSym_t * +#define NAME asm_symbol_tab +#define ITERATE 1 +#define COMPARE(a, b) \ + strcmp (ebl_string ((a)->strent), ebl_string ((b)->strent)) +#include + +#endif /* symbolhash.h */ diff --git a/libcpu/.cvsignore b/libcpu/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/libcpu/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/libcpu/ChangeLog b/libcpu/ChangeLog new file mode 100644 index 00000000..5c2a4ac7 --- /dev/null +++ b/libcpu/ChangeLog @@ -0,0 +1,11 @@ +2005-02-15 Ulrich Drepper + + * Makefile (AM_CFLAGS): Add -Wunused -Wextra -Wformat=2. + +2005-02-05 Ulrich Drepper + + * Makefile.am (AM_CFLAGS): Define, instead of adding things to DEFS. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am new file mode 100644 index 00000000..02fb8020 --- /dev/null +++ b/libcpu/Makefile.am @@ -0,0 +1,21 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 2002, 2005 Red Hat, Inc. +## +## This program is Open Source software; you can redistribute it and/or +## modify it under the terms of the Open Software License version 1.0 as +## published by the Open Source Initiative. +## +## You should have received a copy of the Open Software License along +## with this program; if not, you may obtain a copy of the Open Software +## License version 1.0 from http://www.opensource.org/licenses/osl.php or +## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +## 3001 King Ranch Road, Ukiah, CA 95482. +## +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H +AM_CFLAGS = -Wall -Wshadow -Werror -Wextra -Wformat=2 -Wunused +INCLUDES = -I$(srcdir) + +noinst_LIBRARIES = libcpu_i386.a + +libcpu_i386_a_SOURCES = i386_dis.c diff --git a/libcpu/i386_dis.c b/libcpu/i386_dis.c new file mode 100644 index 00000000..971746e3 --- /dev/null +++ b/libcpu/i386_dis.c @@ -0,0 +1 @@ +int foo; diff --git a/libdw/.cvsignore b/libdw/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/libdw/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/libdw/ChangeLog b/libdw/ChangeLog new file mode 100644 index 00000000..28c582ad --- /dev/null +++ b/libdw/ChangeLog @@ -0,0 +1,512 @@ +2005-07-23 Ulrich Drepper + + * dwarf_error.c: Add internal alias for dwarf_errno. + * libdwP.h: Declare __dwarf_errno_internal. + * dwarf_getloclist.c: Use INTDEF for dwarf_errno. + + * dwarf_error.c [USE_TLS]: Actually use __thread in definition of + global_error. + +2005-06-01 Roland McGrath + + * dwarf_getaranges.c (dwarf_getaranges): Sort result array. + * dwarf_getarange_addr.c (dwarf_getarange_addr): Use binary search. + +2005-06-08 Roland McGrath + + * memory-access.h (get_uleb128_step, get_uleb128): Remove casts. + (get_sleb128_step, get_sleb128): Likewise. + * dwarf_getattrs.c (dwarf_getattrs): Add consts. + * dwarf_getloclist.c (getloclist): Likewise. + * dwarf_formblock.c (dwarf_formblock): Likewise. + * dwarf_getsrclines.c (dwarf_getsrclines): Likewise. + * dwarf_getabbrevattr.c (dwarf_getabbrevattr): Likewise. + * dwarf_formref.c (dwarf_formref): Likewise. + * dwarf_formsdata.c (dwarf_formsdata): Likewise. + * dwarf_formudata.c (dwarf_formudata): Likewise. + * dwarf_haschildren.c (dwarf_haschildren): Likewise. + * dwarf_child.c (__libdw_find_attr, __libdw_find_attr): Likewise. + * dwarf_tag.c (dwarf_tag): Likewise. + * dwarf_getabbrev.c (__libdw_getabbrev): Likewise. + * memory-access.c (__libdw_get_uleb128, __libdw_get_sleb128): Likewise. + * libdw_form.c (__libdw_form_val_len): Likewise. + * libdwP.h: Update decl. + +2005-06-04 Roland McGrath + + * memory-access.h (get_uleb128_rest_return): New macro. + [! IS_LIBDW] (__libdw_get_uleb128): New static, defined using it. + (get_sleb128_rest_return): New macro. + [! IS_LIBDW] (__libdw_get_sleb128): New static, defined using it. + * memory-access.c: New file. + * Makefile.am (libdw_a_SOURCES): Add it. + (DEFS): Add -DIS_LIBDW. + +2005-05-31 Roland McGrath + + * dwarf_formref_die.c (dwarf_formref_die): Add CU header offset to + formref offset. + +2005-05-30 Roland McGrath + + * dwarf_getloclist.c (dwarf_addrloclists): Use DW_AT_entry_pc for base + address if DW_AT_low_pc is missing. Not to spec, but GCC generates it. + + * dwarf_getloclist.c (dwarf_addrloclists): Don't sign-extend 4-byte + BEGIN value. Instead, match base address entries separately for + 32/64 size cases. + +2005-05-28 Roland McGrath + + * dwarf_getloclist.c (dwarf_addrloclists): Fix decoding to advance + past location expression contents. + +2005-05-23 Roland McGrath + + * dwarf_getsrclines.c: Comment typo fix. + + * dwarf_haspc.c (dwarf_haspc): Fix CU DIE address calculation. + * dwarf_getloclist.c (dwarf_addrloclists): Likewise. + +2005-05-22 Ulrich Drepper + + * libdwP.h: Only use INTDECL for alias prototypes. + +2005-05-19 Roland McGrath + + * dwarf_getloclist.c (attr_ok): Permit DW_AT_static_link too. + + * dwarf_getscopevar.c: New file. + * Makefile.am (libdw_a_SOURCES): Add it. + * libdw.h: Declare dwarf_getscopevar. + + * dwarf_getsrcfiles.c: Add INTDEF. + * dwarf_haschildren.c: Likewise. + * libdwP.h (dwarf_getsrcfiles, dwarf_haschildren): Add INTDECL. + + * dwarf_getscopes.c: New file. + * Makefile.am (libdw_a_SOURCES): Add it. + * libdw.h: Declare dwarf_getscopes. + * libdw.map: Add it. + +2005-05-18 Roland McGrath + + * libdwP.h (IDX_debug_ranges): New enum constant. + * dwarf_begin_elf.c (dwarf_scnnames): Add it for ".debug_ranges". + * libdwP.h (DWARF_E_NO_DEBUG_RANGES): New enum constant. + * dwarf_error.c (errmsgs): Add it. + * dwarf_haspc.c: New file. + * libdw.h: Declare dwarf_haspc. + * libdw.map: Add it. + * libdwP.h: Add INTDECL. + + * dwarf_attr_integrate.c: New file. + * dwarf_hasattr_integrate.c: New file. + * Makefile.am (libdw_a_SOURCES): Add them. + * libdw.h: Declare dwarf_attr_integrate, dwarf_hasattr_integrate. + * libdw.map: Add them. + + * dwarf_hasattr.c: Add INTDEF. + * libdwP.h: Add INTDECL for it. + + * dwarf_formref_die.c: New file. + * Makefile.am (libdw_a_SOURCES): Add it. + * libdw.h (dwarf_formref_die): Declare it. + * libdwP.h (dwarf_formref_die): Add INTDECL. + * libdw.map: Add it. + + * dwarf_getloclist.c (attr_ok, getloclist): New functions, broken out + of ... + (dwarf_getloclist): ... here. Call them. + (dwarf_addrloclists): New function. + * libdw.h: Declare it. + * libdw.map: Add it. + + * dwarf_getmacros.c (dwarf_getmacros): Don't bail at + DW_MACINFO_end_file. Recognize type 0 as terminator. + +2005-05-05 Roland McGrath + + * dwarf_getsrc_die.c (dwarf_getsrc_die): Use binary search. + + * dwarf_getsrclines.c (dwarf_getsrclines): Sort result array, since + the line program does not produce all entries in ascending order. + +2005-04-25 Ulrich Drepper + + * dwarf_getsrc_file.c (dwarf_getsrc_file): Handle multiple + occurences (e.g., inlines) better. + +2005-04-24 Ulrich Drepper + + * libdw.h (DWARF_END_ABBREV): Define. + * dwarf_getabbrev.c (__libdw_getabbrev): Return DWARF_END_ABBREV if + end is reached. + * dwarf_offabbrev.c (dwarf_offabbrev): Return -1 on error, 1 if end + of records reached. + * dwarf_tag.c (__libdw_findabbrev): Also recognize DWARF_END_ABBREV + as error of __libdw_getabbrev. + +2005-04-04 Ulrich Drepper + + * dwarf_getsrc_file.c (dwarf_getsrc_file): Minor optimization. + + * dwarf_getsrc_file.c (dwarf_getsrc_file): Always pass number of + results back to caller. + +2005-04-04 Roland McGrath + + * dwarf_getsrc_file.c (dwarf_getsrc_file): Use size_t for CUHL. + + * dwarf_func_line.c (__libdw_func_intval): Use internal_function in + defn. + +2005-04-04 Ulrich Drepper + + * dwarf_getsrc_file.c (dwarf_getsrc_file): Use INTUSE. + + * dwarf_getsrc_file.c: New file. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getsrc_file.c. + * libdw.h: Declare dwarf_getsrc_file. + * libdw.map: Add dwarf_getsrc_file. + +2005-04-02 Ulrich Drepper + + * dwarf_func_entrypc.c: New file. + * dwarf_func_col.c: New file. + * dwarf_func_line.c: New file. + * dwarf_func_file.c: New file. + * libdw.h: Add prototypes for new functions. + * libdw.map: Add dwarf_func_entrypc, dwarf_func_col, dwarf_func_line, + dwarf_func_file. + * Makefile.am (libdw_a_SOURCES): Add dwarf_func_entrypc.c, + dwarf_func_col.c, dwarf_func_line.c, dwarf_func_file.c. + * libdwP.h (struct Dwarf_Func_s): Add cudie element. + Declare __libdw_func_intval and __dwarf_formsdata_internal. + * dwarf_getfuncs.c: Also fill in cudie in Dwarf_Func object. + * dwarf_formsdata.c: Use INTUSE and INTDEF to avoid PLTs. + + * dwarf.h: Add some DWARF3 definitions. + +2005-04-01 Ulrich Drepper + + * dwarf_getfuncs.c: New file. + * dwarf_func_highpc.c: New file. + * dwarf_func_lowpc.c: New file. + * dwarf_func_name.c: New file. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getfuncs.c, + dwarf_func_highpc.c, dwarf_func_lowpc.c, and dwarf_func_name.c. + * libdw.map: Add dwarf_getfuncs, dwarf_func_highpc, dwarf_func_lowpc, + and dwarf_func_name. + * libdw.h: Add prototypes for new functions. + * dwarf_child.c: Use INTUSE and INTDEF to avoid PLTs. + * dwarf_siblingof.c: Likewise. + * dwarf_dieoffset.c: Likewise. + * dwarf_highpc.c: Likewise. + * dwarf_lowpc.c: Likewise. + * libdwP.h: Add prototypes for internal functions. + Define Dwarf_Func_s structure. + +2005-03-29 Ulrich Drepper + + * libdw.h: Add padding in Dwarf_die. + + * dwarf_arrayorder.c: Use INTUSE and INTDEF to avoid PLTs. + * dwarf_attr.c: Likewise. + * dwarf_begin.c: Likewise. + * dwarf_begin_elf.c: Likewise. + * dwarf_bitoffset.c: Likewise. + * dwarf_bitsize.c: Likewise. + * dwarf_bytesize.c: Likewise. + * dwarf_diename.c: Likewise. + * dwarf_formaddr.c: Likewise. + * dwarf_formblock.c: Likewise. + * dwarf_formref.c: Likewise. + * dwarf_formstring.c: Likewise. + * dwarf_formudata.c: Likewise. + * dwarf_getarange_addr.c: Likewise. + * dwarf_getarangeinfo.c: Likewise. + * dwarf_getaranges.c: Likewise. + * dwarf_getloclist.c: Likewise. + * dwarf_getmacros.c: Likewise. + * dwarf_getsrc_die.c: Likewise. + * dwarf_getsrcfiles.c: Likewise. + * dwarf_getsrclines.c: Likewise. + * dwarf_highpc.c: Likewise. + * dwarf_lowpc.c: Likewise. + * dwarf_nextcu.c: Likewise. + * dwarf_offdie.c: Likewise. + * dwarf_siblingof.c: Likewise. + * dwarf_srclang.c: Likewise. + * dwarf_tag.c: Likewise. + * libdw_findcu.c: Likewise. + * libdwP.h: Add prototypes for internal functions. + + * dwarf_addrdie.c: New file. + * dwarf_macro_opcode.c: New file. + * dwarf_macro_param1.c: New file. + * dwarf_macro_param2.c: New file. + * libdw.h: Add declarations. Move Dwarf_Macro definition to libdwP.h. + * libdwP.h: Remove Dwarf_Macro definition. + * Makefile.am (libdw_a_SOURCES): Add dwarf_addrdie.c, + dwarf_macro_opcode.c, dwarf_macro_param1.c, and dwarf_macro_param2.c. + * libdw.map: Add entries for new functions. + +2005-03-21 Ulrich Drepper + + * libdw.h: Handle broken gcc < 4. + +2005-02-15 Ulrich Drepper + + * Makefile (AM_CFLAGS): Add -Wunused -Wextra -Wformat=2. + + * dwarf_begin_elf.c: Fix warnings. + * dwarf_dieoffset.c: Likewise. + * dwarf_end.c: Likewise. + * dwarf_error.c: Likewise. + * dwarf_getpubnames.c: Likewise. + + * libdwP.h: Add new error values. + * dwarf_error.c: Support new error values. + * dwarf_getpubnames.c: Check parameter value. + +2005-02-05 Ulrich Drepper + + * Makefile.am: Check for text relocations in constructed DSO. + + * Makefile.am [MUDFLAP] (AM_CFLAGS): Add -fmudflap. + +2005-02-04 Ulrich Drepper + + * dwarf_siblingof.c (dwarf_siblingof): Add some buffer boundary + checks to not read over buffer boundaries for ill-formed DWARF data. + +2004-09-25 Ulrich Drepper + + * dwarf_child.c: Make compile with gcc 4.0. + * dwarf_error.c: Likewise. + * dwarf_formblock.c: Likewise. + * dwarf_getabbrev.c: Likewise. + * dwarf_getattrs.c: Likewise. + * dwarf_getsrclines.c: Likewise. + * dwarf_tag.c: Likewise. + * libdw_form.c: Likewise. + +2004-01-20 Ulrich Drepper + + * Makefile.am: Support building with mudflap. + + * dwarf_getloclist.c: Fix warnings gcc 3.4 spits out. + * dwarf_getsrclines.c: Likewise. + * dwarf_memory-access.h: Likewise. + +2004-01-19 Ulrich Drepper + + * dwarf_getsrcfiles.c: Third parameter can be NULL. + + * libdw.h: Define Dwarf_macro. Declare dwarf_getmacros. + Third parameter of dwarf_getsrcfiles can be NULL. + + * libdw.map: Add dwarf_getmacros. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getmacros. + * dwarf_getmacros.c: New file. + +2004-01-18 Ulrich Drepper + + * libdw.h: Second parameter of dwarf_getaranges can be NULL. + + * dwarf_nextcu.c: Return -1 if dwarf parameter is NULL. + + * dwarf_getsrclines.c: + Use read_2ubyte_unaligned_inc instead of _inc-less variant. + + * dwarf_getaranges.c: Allow naranges parameter to be NULL. + + * libdwP.h (_): Use elfutils domain. + + * dwarf_getsrclines.c (dwarf_getsrclines): Add more branch prediction. + + * dwarf_getsrclines.c: Fix typo in comment. + +2004-01-17 Ulrich Drepper + + * Makefile.am: Support building with mudflap. + +2004-01-16 Ulrich Drepper + + * memory-access.h: Add lots of const in case a pointer passed is const. + + * dwarf_formflag.c: New file. + * dwarf_getattrs.c: New file. + * dwarf_error.c: Add new error value. + * libdw.h: Add prototypes for new functions. Adjust prototype for + dwarf_getpubnames. + * libdw.map: Add new functions. + * dwarf_getpubnames.c: Change type of return value and fourth parameter + to ptrdiff_t. + * libdwP.h: Add new error value. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getattrs.c and + dwarf_formflag.c. + + * dwarf_getpubnames.c (dwarf_getpubnames): Just fail if dbg is NULL. + +2004-01-12 Ulrich Drepper + + * dwarf_getarange_addr.c: New file + * dwarf_getarangeinfo.c: New file. + * dwarf_getaranges.c: New file. + * dwarf_onerange.c: New file. + * libdw.h: Declare new functions. Define Dwarf_Arange and + Dwarf_Aranges. + * libdw.map: Add new functions. + * libdwP.h: Add new errors. Add aranges member to struct Dwarf. + Define Dwarf_Aranges_s and Dwarf_Arange_s. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getaranges.c, + dwarf_onearange.c, dwarf_getarangeinfo.c, dwarf_getarange_addr.c. + * dwarf_error.c: Add new message. + +2004-01-11 Ulrich Drepper + + * Makefile.am (libdw_a_SOURCES): Add dwarf_lineaddr.c, dwarf_linecol.c, + dwarf_linebeginstatement.c, dwarf_lineendsequence.c, dwarf_lineblock.c, + dwarf_lineprologueend.c, dwarf_lineepiloguebegin.c, dwarf_onesrcline.c. + * dwarf_error.c: Add another message. + * dwarf_getsrc_die.c: Adjust for Dwarf_Files and Dwarf_Lines + introduction. + * dwarf_filesrc.c: Likewise. + * dwarf_getsrcfiles.c: Likewise. + * dwarf_getsrclines.c: Likewise. + * dwarf_lineaddr.c: New file. + * dwarf_linebeginstatement.c: New file. + * dwarf_lineblock.c: New file. + * dwarf_linecol.c: New file. + * dwarf_lineendsequence.c: New file. + * dwarf_lineepiloguebegin.c: New file. + * dwarf_lineno.c: New file. + * dwarf_lineprologueend.c: New file. + * dwarf_onesrcline.c: New file. + * dwarf_lineno.c: Change interface to store result in object pointed + to by second parameter. + * libdw.h: Add prototypes for new functions. Change dwarf_lineno + prototype. Define Dwarf_Files and Dwarf_Lines. + * libdw.map: Add new functions. + * libdwP.h: Define Dwarf_Files_s and Dwarf_Lines_s. + * libdw_findcu.c: Don't initialize nlines field. + + * dwarf_siblingof: Little optimization. + + * dwarf_begin.c: Remember that the ELF descriptor must be closed. + * dwarf_end.c: Close ELF descriptor if free_elf is set. + * libdwP.h (struct Dwarf): Add free_elf field. + + * Makefile.am (libdw_a_SOURCES): Add dwarf_getstring.c and + dwarf_offabbrev.c. + * dwarf_getstring.c: New file. + * dwarf_offabbrev.c: New file. + * libdw.map: Add dwarf_getstring and dwarf_offabbrev. + * dwarf_getabbrev.c (__libdw_getabbrev): Add new dbg and result + parameters. Don't allocate memory if not necessary and don't lookup + previous results if no CU given. + (dwarf_getabbrev): Adjust call to __libdw_getabbrev. + * dwarf_tag.c: Adjust call to __libdw_getabbrev. + * libdw.h: Declare dwarf_offabbrev and dwarf_getstring. + * libdwP.h: Change prototype for __libdw_getabbrev. + + * dwarf_getabbrevattr.c: Add offsetp parameter. Fill in before + returning if this is wanted. + +2004-01-09 Ulrich Drepper + + * dwarf_nextcu.c: Add new parameter offset_sizep. Initialize it + with offset_size value. + * libdw.h: Adjust dwarf_nextcu prototype. + * libdwP.h (struct Dwarf_CU): Add offset_size member. + * libdw_findcu.c: Adjust dwarf_nextcu call. Initialize offset_size + member of new CU struct. + * dwarf_formstring.c: Depend on offset_size not address_size for + DW_FORM_strp handling. + * dwarf_form.c: Likewise for DW_FORM_strp and DW_FORM_ref_addr. + + * dwarf_tag.c (__libdw_findabbrev): Return correct value for + failing lookup. + (dwarf_tag): Correctly recognize failed lookup. + + * dwarf_end.c (cu_free): Call tdestroy for locs member. Use new + function noop_free. + * dwarf_error.c: Add message for DWARF_E_NO_BLOCK. + * dwarf_formblock.c: New file. + * dwarf_getloclist.c: Rewrite to handle a single block. + * libdw.h: Define Dwarf_Block. Rename Dwarf_Loc members. Remove + Dwarf_Locdesc definition. Declare dwarf_formblock. Remove + dwarf_getloclistent declaration. + * libdw.map: Add dwarf_formblock, remove dwarf_getloclistent. + * libdwP.h: Define struct loc_s and DWARF_E_NO_BLOCK. + Add locs member to struct Dwarf_CU. + * libdw_fundcu.c: Initialize locs member of new CU. + * Makefile.am (libdw_a_SOURCES): Add dwarf_formblock.c. + Remove dwarf_getloclistent.c. + +2004-01-07 Ulrich Drepper + + * libdw.h: Use __nonnull__ attribute only for gcc >= 3.3. + * libdwP.h: Likewise. + + * dwarf_getloclist.c: New file. + * dwarf_getloclistent.c: New file. + * libdw.h: Define Dwarf_Loc and Dwarf_Locdesc. + Declare dwarf_getloclistent and dwarf_getloclist. + * libdw.map: Add dwarf_getloclistent and dwarf_getloclist. + * libdwP.h: Define DWARF_E_NO_LOCLIST. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getloclistent.c and + dwarf_getloclist.c. + + * dwarf_error.c: More error messages. + +2004-01-06 Ulrich Drepper + + * dwarf_getsrclines.c: Remove debugging support. + + * dwarf_getsrcfiles.c: New file. + * dwarf_filesrc.c: New file. + * libdw.h: Declare these functions. Define Dwarf_File. + * libdwP.c: Adjust Dwarf_File_s definition. + * libdw.map: Add these functions. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getsrcfiles.c and + dwarf_filesrc.c. + * dwarf_getsrclines.c: Initialize cu->files. + +2004-01-05 Ulrich Drepper + + * libdw.h: Add more nonnull function attributes. + + * dwarf_begin_elf.c (dwarf_begin_elf): Don't initialize mem_tail->next. + * dwarf_end.c (cu_free): New function. + (dwarf_end): Also free CU tree. Correct freeing of memory blocks. + * dwarf_error.c (errmsgs): Add new messages. + * dwarf_getsrc_die.c: New file. + * dwarf_getsrclines.c: New file. + * dwarf_lineno.c: New file. + * dwarf_linesrc.c: New file. + * dwarf_nextcu.c (dwarf_nextcu): Use read_*byte_unaligned_inc + instead of the *_inc-less variants. + * libdw.h: Define Dwarf_Line. Add some function attributes. Declare + dwarf_getsrclines, dwarf_getsrc_die, dwarf_lineno, and dwarf_linesrc. + * libdw.map: Add dwarf_getsrclines, dwarf_getsrc_die, dwarf_lineno, + and dwarf_linesrc. + * libdwP.h: Add more error codes. + (struct Dwarf): Remove mem_tail.next member. + (Dwarf_File): Define type. + (struct Dwarf_Line_s): Define type. + (struct Dwarf_CU): Add lines and nlines members. + (libdw_alloc): Define local variable _tail and use it. + Add some function attributes. + * libdw_alloc.c (__libdw_allocate): Don't initialize next member. + * libdw_findcu.c (__libdw_findcu): Initialize lines and nlines members. + * memory-access.h: Add unlikely for the endian conversion paths. + * Makefile.am (AM_CFLAGS): Add -std parameter. + (libdw_a_SOURCES): Add dwarf_getsrclines, dwarf_getsrc_die, + dwarf_lineno, and dwarf_linesrc. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/libdw/Makefile.am b/libdw/Makefile.am new file mode 100644 index 00000000..17be31dd --- /dev/null +++ b/libdw/Makefile.am @@ -0,0 +1,108 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. +## +## This program is Open Source software; you can redistribute it and/or +## modify it under the terms of the Open Software License version 1.0 as +## published by the Open Source Initiative. +## +## You should have received a copy of the Open Software License along +## with this program; if not, you may obtain a copy of the Open Software +## License version 1.0 from http://www.opensource.org/licenses/osl.php or +## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +## 3001 King Ranch Road, Ukiah, CA 95482. +## +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -DIS_LIBDW +if MUDFLAP +AM_CFLAGS = -fmudflap +else +AM_CFLAGS = +endif +AM_CFLAGS += -Wall -Werror -Wshadow -Wunused -Wformat=2 -Wextra -std=gnu99 +INCLUDES = -I. -I$(srcdir) -I$(srcdir)/../libelf -I.. -I$(srcdir)/../lib +VERSION = 1 + +lib_LIBRARIES = libdw.a +if !MUDFLAP +noinst_LIBRARIES = libdw_pic.a +noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so) +endif + +include_HEADERS = dwarf.h +euincludedir = ${includedir}/elfutils +euinclude_HEADERS = libdw.h + +libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \ + dwarf_getpubnames.c dwarf_getabbrev.c dwarf_tag.c \ + dwarf_error.c dwarf_nextcu.c dwarf_diename.c dwarf_offdie.c \ + dwarf_attr.c dwarf_formstring.c dwarf_abbrev_hash.c \ + dwarf_attr_integrate.c dwarf_hasattr_integrate.c \ + dwarf_child.c dwarf_haschildren.c dwarf_formaddr.c \ + dwarf_formudata.c dwarf_formsdata.c dwarf_lowpc.c \ + dwarf_haspc.c dwarf_highpc.c \ + dwarf_formref.c dwarf_formref_die.c dwarf_siblingof.c \ + dwarf_dieoffset.c dwarf_cuoffset.c dwarf_hasattr.c \ + dwarf_hasform.c dwarf_whatform.c dwarf_whatattr.c \ + dwarf_bytesize.c dwarf_arrayorder.c dwarf_bitsize.c \ + dwarf_bitoffset.c dwarf_srclang.c dwarf_getabbrevtag.c \ + dwarf_getabbrevcode.c dwarf_abbrevhaschildren.c \ + dwarf_getattrcnt.c dwarf_getabbrevattr.c \ + dwarf_getsrclines.c dwarf_getsrc_die.c \ + dwarf_getscopes.c dwarf_getscopevar.c \ + dwarf_linesrc.c dwarf_lineno.c dwarf_lineaddr.c \ + dwarf_linecol.c dwarf_linebeginstatement.c \ + dwarf_lineendsequence.c dwarf_lineblock.c \ + dwarf_lineprologueend.c dwarf_lineepiloguebegin.c \ + dwarf_onesrcline.c dwarf_formblock.c \ + dwarf_getsrcfiles.c dwarf_filesrc.c \ + dwarf_getloclist.c dwarf_getstring.c dwarf_offabbrev.c \ + dwarf_getaranges.c dwarf_onearange.c dwarf_getarangeinfo.c \ + dwarf_getarange_addr.c dwarf_getattrs.c dwarf_formflag.c \ + dwarf_getmacros.c dwarf_macro_opcode.c dwarf_macro_param1.c \ + dwarf_macro_param2.c dwarf_addrdie.c \ + dwarf_getfuncs.c dwarf_func_name.c dwarf_func_lowpc.c \ + dwarf_func_highpc.c dwarf_func_entrypc.c dwarf_func_file.c \ + dwarf_func_line.c dwarf_func_col.c dwarf_getsrc_file.c \ + libdw_findcu.c libdw_form.c libdw_alloc.c memory-access.c + + +if !MUDFLAP +libdw_pic_a_SOURCES = +am_libdw_pic_a_OBJECTS = $(libdw_a_SOURCES:.c=.os) + +libdw_so_SOURCES = +libdw.so: libdw_pic.a $(srcdir)/libdw.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libdw.map,--no-undefined \ + -Wl,--soname,$@.$(VERSION),-z,defs \ + ../libelf/libelf.so + if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi + ln -fs $@ $@.$(VERSION) + + +%.os: %.c %.o + if $(COMPILE) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \ + -MF "$(DEPDIR)/$*.Tpo" `test -f '$<' || echo '$(srcdir)/'`$<; \ + then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ + rm -f "$(DEPDIR)/$*.Tpo"; \ + else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ + fi + +install: install-am libdw.so + $(mkinstalldirs) $(DESTDIR)$(libdir) + $(INSTALL_PROGRAM) libdw.so $(DESTDIR)$(libdir)/libdw-$(PACKAGE_VERSION).so + ln -fs libdw-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libdw.so.$(VERSION) + ln -fs libdw.so.$(VERSION) $(DESTDIR)$(libdir)/libdw.so + +uninstall: uninstall-am + rm -f $(DESTDIR)$(libdir)/libdw-$(PACKAGE_VERSION).so + rm -f $(DESTDIR)$(libdir)/libdw.so.$(VERSION) + rm -f $(DESTDIR)$(libdir)/libdw.so + rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils +endif + +noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h + +EXTRA_DIST = libdw.map + +CLEANFILES = $(am_libdw_pic_a_OBJECTS) diff --git a/libdw/dwarf.h b/libdw/dwarf.h new file mode 100644 index 00000000..ce011aac --- /dev/null +++ b/libdw/dwarf.h @@ -0,0 +1,581 @@ +/* This file defines standard DWARF types, structures, and macros. + Copyright (C) 2000, 2002, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _DWARF_H +#define _DWARF_H 1 + +/* DWARF tags. */ +enum + { + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_param = 0x2f, + DW_TAG_template_value_param = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + DW_TAG_dwarf_procedure = 0x36, + DW_TAG_restrict_type = 0x37, + DW_TAG_interface_type = 0x38, + DW_TAG_namespace = 0x39, + DW_TAG_imported_module = 0x3a, + DW_TAG_unspecified_type = 0x3b, + DW_TAG_partial_unit = 0x3c, + DW_TAG_imported_unit = 0x3d, + DW_TAG_mutable_type = 0x3e, + DW_TAG_lo_user = 0x4080, + DW_TAG_MIPS_loop = 0x4081, + DW_TAG_format_label = 0x4101, + DW_TAG_function_template = 0x4102, + DW_TAG_class_template = 0x4103, + DW_TAG_hi_user = 0xffff + }; + + +/* Children determination encodings. */ +enum + { + DW_CHILDREN_no = 0, + DW_CHILDREN_yes = 1 + }; + + +/* DWARF attributes encodings. */ +enum + { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_stride_size = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_items = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + DW_AT_allocated = 0x4e, + DW_AT_associated = 0x4f, + DW_AT_data_location = 0x50, + DW_AT_stride = 0x51, + DW_AT_entry_pc = 0x52, + DW_AT_use_UTF8 = 0x53, + DW_AT_extension = 0x54, + DW_AT_ranges = 0x55, + DW_AT_trampoline = 0x56, + DW_AT_call_column = 0x57, + DW_AT_call_file = 0x58, + DW_AT_call_line = 0x59, + DW_AT_description = 0x5a, + DW_AT_lo_user = 0x2000, + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + DW_AT_MIPS_stride_byte = 0x200c, + DW_AT_MIPS_stride_elem = 0x200d, + DW_AT_MIPS_ptr_dopetype = 0x200e, + DW_AT_MIPS_allocatable_dopetype = 0x200f, + DW_AT_MIPS_assumed_shape_dopetype = 0x2010, + DW_AT_MIPS_assumed_size = 0x2011, + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_hi_user = 0x3fff + }; + + +/* DWARF form encodings. */ +enum + { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16 + }; + + +/* DWARF location operation encodings. */ +enum + { + DW_OP_addr = 0x03, /* Constant address. */ + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, /* Unsigned 1-byte constant. */ + DW_OP_const1s = 0x09, /* Signed 1-byte constant. */ + DW_OP_const2u = 0x0a, /* Unsigned 2-byte constant. */ + DW_OP_const2s = 0x0b, /* Signed 2-byte constant. */ + DW_OP_const4u = 0x0c, /* Unsigned 4-byte constant. */ + DW_OP_const4s = 0x0d, /* Signed 4-byte constant. */ + DW_OP_const8u = 0x0e, /* Unsigned 8-byte constant. */ + DW_OP_const8s = 0x0f, /* Signed 8-byte constant. */ + DW_OP_constu = 0x10, /* Unsigned LEB128 constant. */ + DW_OP_consts = 0x11, /* Signed LEB128 constant. */ + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, /* 1-byte stack index. */ + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, /* Unsigned LEB128 addend. */ + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, /* Signed 2-byte constant. */ + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_skip = 0x2f, /* Signed 2-byte constant. */ + DW_OP_lit0 = 0x30, /* Literal 0. */ + DW_OP_lit1 = 0x31, /* Literal 1. */ + DW_OP_lit2 = 0x32, /* Literal 2. */ + DW_OP_lit3 = 0x33, /* Literal 3. */ + DW_OP_lit4 = 0x34, /* Literal 4. */ + DW_OP_lit5 = 0x35, /* Literal 5. */ + DW_OP_lit6 = 0x36, /* Literal 6. */ + DW_OP_lit7 = 0x37, /* Literal 7. */ + DW_OP_lit8 = 0x38, /* Literal 8. */ + DW_OP_lit9 = 0x39, /* Literal 9. */ + DW_OP_lit10 = 0x3a, /* Literal 10. */ + DW_OP_lit11 = 0x3b, /* Literal 11. */ + DW_OP_lit12 = 0x3c, /* Literal 12. */ + DW_OP_lit13 = 0x3d, /* Literal 13. */ + DW_OP_lit14 = 0x3e, /* Literal 14. */ + DW_OP_lit15 = 0x3f, /* Literal 15. */ + DW_OP_lit16 = 0x40, /* Literal 16. */ + DW_OP_lit17 = 0x41, /* Literal 17. */ + DW_OP_lit18 = 0x42, /* Literal 18. */ + DW_OP_lit19 = 0x43, /* Literal 19. */ + DW_OP_lit20 = 0x44, /* Literal 20. */ + DW_OP_lit21 = 0x45, /* Literal 21. */ + DW_OP_lit22 = 0x46, /* Literal 22. */ + DW_OP_lit23 = 0x47, /* Literal 23. */ + DW_OP_lit24 = 0x48, /* Literal 24. */ + DW_OP_lit25 = 0x49, /* Literal 25. */ + DW_OP_lit26 = 0x4a, /* Literal 26. */ + DW_OP_lit27 = 0x4b, /* Literal 27. */ + DW_OP_lit28 = 0x4c, /* Literal 28. */ + DW_OP_lit29 = 0x4d, /* Literal 29. */ + DW_OP_lit30 = 0x4e, /* Literal 30. */ + DW_OP_lit31 = 0x4f, /* Literal 31. */ + DW_OP_reg0 = 0x50, /* Register 0. */ + DW_OP_reg1 = 0x51, /* Register 1. */ + DW_OP_reg2 = 0x52, /* Register 2. */ + DW_OP_reg3 = 0x53, /* Register 3. */ + DW_OP_reg4 = 0x54, /* Register 4. */ + DW_OP_reg5 = 0x55, /* Register 5. */ + DW_OP_reg6 = 0x56, /* Register 6. */ + DW_OP_reg7 = 0x57, /* Register 7. */ + DW_OP_reg8 = 0x58, /* Register 8. */ + DW_OP_reg9 = 0x59, /* Register 9. */ + DW_OP_reg10 = 0x5a, /* Register 10. */ + DW_OP_reg11 = 0x5b, /* Register 11. */ + DW_OP_reg12 = 0x5c, /* Register 12. */ + DW_OP_reg13 = 0x5d, /* Register 13. */ + DW_OP_reg14 = 0x5e, /* Register 14. */ + DW_OP_reg15 = 0x5f, /* Register 15. */ + DW_OP_reg16 = 0x60, /* Register 16. */ + DW_OP_reg17 = 0x61, /* Register 17. */ + DW_OP_reg18 = 0x62, /* Register 18. */ + DW_OP_reg19 = 0x63, /* Register 19. */ + DW_OP_reg20 = 0x64, /* Register 20. */ + DW_OP_reg21 = 0x65, /* Register 21. */ + DW_OP_reg22 = 0x66, /* Register 22. */ + DW_OP_reg23 = 0x67, /* Register 24. */ + DW_OP_reg24 = 0x68, /* Register 24. */ + DW_OP_reg25 = 0x69, /* Register 25. */ + DW_OP_reg26 = 0x6a, /* Register 26. */ + DW_OP_reg27 = 0x6b, /* Register 27. */ + DW_OP_reg28 = 0x6c, /* Register 28. */ + DW_OP_reg29 = 0x6d, /* Register 29. */ + DW_OP_reg30 = 0x6e, /* Register 30. */ + DW_OP_reg31 = 0x6f, /* Register 31. */ + DW_OP_breg0 = 0x70, /* Base register 0. */ + DW_OP_breg1 = 0x71, /* Base register 1. */ + DW_OP_breg2 = 0x72, /* Base register 2. */ + DW_OP_breg3 = 0x73, /* Base register 3. */ + DW_OP_breg4 = 0x74, /* Base register 4. */ + DW_OP_breg5 = 0x75, /* Base register 5. */ + DW_OP_breg6 = 0x76, /* Base register 6. */ + DW_OP_breg7 = 0x77, /* Base register 7. */ + DW_OP_breg8 = 0x78, /* Base register 8. */ + DW_OP_breg9 = 0x79, /* Base register 9. */ + DW_OP_breg10 = 0x7a, /* Base register 10. */ + DW_OP_breg11 = 0x7b, /* Base register 11. */ + DW_OP_breg12 = 0x7c, /* Base register 12. */ + DW_OP_breg13 = 0x7d, /* Base register 13. */ + DW_OP_breg14 = 0x7e, /* Base register 14. */ + DW_OP_breg15 = 0x7f, /* Base register 15. */ + DW_OP_breg16 = 0x80, /* Base register 16. */ + DW_OP_breg17 = 0x81, /* Base register 17. */ + DW_OP_breg18 = 0x82, /* Base register 18. */ + DW_OP_breg19 = 0x83, /* Base register 19. */ + DW_OP_breg20 = 0x84, /* Base register 20. */ + DW_OP_breg21 = 0x85, /* Base register 21. */ + DW_OP_breg22 = 0x86, /* Base register 22. */ + DW_OP_breg23 = 0x87, /* Base register 23. */ + DW_OP_breg24 = 0x88, /* Base register 24. */ + DW_OP_breg25 = 0x89, /* Base register 25. */ + DW_OP_breg26 = 0x8a, /* Base register 26. */ + DW_OP_breg27 = 0x8b, /* Base register 27. */ + DW_OP_breg28 = 0x8c, /* Base register 28. */ + DW_OP_breg29 = 0x8d, /* Base register 29. */ + DW_OP_breg30 = 0x8e, /* Base register 30. */ + DW_OP_breg31 = 0x8f, /* Base register 31. */ + DW_OP_regx = 0x90, /* Unsigned LEB128 register. */ + DW_OP_fbreg = 0x91, /* Signed LEB128 register. */ + DW_OP_bregx = 0x92, /* ULEB128 register followed by SLEB128 off. */ + DW_OP_piece = 0x93, /* ULEB128 size of piece addressed. */ + DW_OP_deref_size = 0x94, /* 1-byte size of data retrieved. */ + DW_OP_xderef_size = 0x95, /* 1-byte size of data retrieved. */ + DW_OP_nop = 0x96, + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + + DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */ + DW_OP_hi_user = 0xff /* Implementation-defined range end. */ + }; + + +/* DWARF base type encodings. */ +enum + { + DW_ATE_void = 0x0, + DW_ATE_address = 0x1, + DW_ATE_boolean = 0x2, + DW_ATE_complex_float = 0x3, + DW_ATE_float = 0x4, + DW_ATE_signed = 0x5, + DW_ATE_signed_char = 0x6, + DW_ATE_unsigned = 0x7, + DW_ATE_unsigned_char = 0x8, + DW_ATE_imaginary_float = 0x9, + + DW_ATE_lo_user = 0x80, + DW_ATE_hi_user = 0xff + }; + + +/* DWARF accessibility encodings. */ +enum + { + DW_ACCESS_public = 1, + DW_ACCESS_protected = 2, + DW_ACCESS_private = 3 + }; + + +/* DWARF visibility encodings. */ +enum + { + DW_VIS_local = 1, + DW_VIS_exported = 2, + DW_VIS_qualified = 3 + }; + + +/* DWARF virtuality encodings. */ +enum + { + DW_VIRTUALITY_none = 0, + DW_VIRTUALITY_virtual = 1, + DW_VIRTUALITY_pure_virtual = 2 + }; + + +/* DWARF language encodings. */ +enum + { + DW_LANG_C89 = 0x0001, + DW_LANG_C = 0x0002, + DW_LANG_Ada83 = 0x0003, + DW_LANG_C_plus_plus = 0x0004, + DW_LANG_Cobol74 = 0x0005, + DW_LANG_Cobol85 = 0x0006, + DW_LANG_Fortran77 = 0x0007, + DW_LANG_Fortran90 = 0x0008, + DW_LANG_Pascal83 = 0x0009, + DW_LANG_Modula2 = 0x000a, + DW_LANG_Java = 0x000b, + DW_LANG_C99 = 0x000c, + DW_LANG_Ada95 = 0x000d, + DW_LANG_Fortran95 = 0x000e, + DW_LANG_PL1 = 0x000f, + DW_LANG_lo_user = 0x8000, + DW_LANG_Mips_Assembler = 0x8001, + DW_LANG_hi_user = 0xffff + }; + + +/* DWARF identifier case encodings. */ +enum + { + DW_ID_case_sensitive = 0, + DW_ID_up_case = 1, + DW_ID_down_case = 2, + DW_ID_case_insensitive = 3 + }; + + +/* DWARF calling conventions encodings. */ +enum + { + DW_CC_normal = 0x1, + DW_CC_program = 0x2, + DW_CC_nocall = 0x3, + DW_CC_lo_user = 0x40, + DW_CC_hi_user = 0xff + }; + + +/* DWARF inline encodings. */ +enum + { + DW_INL_not_inlined = 0, + DW_INL_inlined = 1, + DW_INL_declared_not_inlined = 2, + DW_INL_declared_inlined = 3 + }; + + +/* DWARF ordering encodings. */ +enum + { + DW_ORD_row_major = 0, + DW_ORD_col_major = 1 + }; + + +/* DWARF discriminant descriptor encodings. */ +enum + { + DW_DSC_label = 0, + DW_DSC_range = 1 + }; + + +/* DWARF standard opcode encodings. */ +enum + { + DW_LNS_copy = 1, + DW_LNS_advance_pc = 2, + DW_LNS_advance_line = 3, + DW_LNS_set_file = 4, + DW_LNS_set_column = 5, + DW_LNS_negate_stmt = 6, + DW_LNS_set_basic_block = 7, + DW_LNS_const_add_pc = 8, + DW_LNS_fixed_advance_pc = 9, + DW_LNS_set_prologue_end = 10, + DW_LNS_set_epilog_begin = 11, + DW_LNS_set_isa = 12 + }; + + +/* DWARF extended opcide encodings. */ +enum + { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3, + + DW_LNE_lo_user = 128, + DW_LNE_hi_user = 255 + }; + + +/* DWARF macinfo type encodings. */ +enum + { + DW_MACINFO_define = 1, + DW_MACINFO_undef = 2, + DW_MACINFO_start_file = 3, + DW_MACINFO_end_file = 4, + DW_MACINFO_vendor_ext = 255 + }; + + +/* DWARF call frame instruction encodings. */ +enum + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_extended = 0, + + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_low_user = 0x1c, + DW_CFA_MIPS_advance_loc8 = 0x1d, + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_high_user = 0x3f + }; + + +/* DWARF XXX. */ +#define DW_ADDR_none 0 + +#endif /* dwarf.h */ diff --git a/libdw/dwarf_abbrev_hash.c b/libdw/dwarf_abbrev_hash.c new file mode 100644 index 00000000..009e757f --- /dev/null +++ b/libdw/dwarf_abbrev_hash.c @@ -0,0 +1,29 @@ +/* Implementation of hash table for DWARF .debug_abbrev section content. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#define NO_UNDEF +#include "libdwP.h" + +#define next_prime __libdwarf_next_prime +extern size_t next_prime (size_t) attribute_hidden; + +#include + +#undef next_prime +#define next_prime attribute_hidden __libdwarf_next_prime +#include "../lib/next_prime.c" diff --git a/libdw/dwarf_abbrev_hash.h b/libdw/dwarf_abbrev_hash.h new file mode 100644 index 00000000..ef3cc48b --- /dev/null +++ b/libdw/dwarf_abbrev_hash.h @@ -0,0 +1,24 @@ +/* Hash table for DWARF .debug_abbrev section content. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _DWARF_ABBREV_HASH_H +#define _DWARF_ABBREV_HASH_H 1 + +#define NAME Dwarf_Abbrev_Hash +#define TYPE Dwarf_Abbrev * +#define COMPARE(a, b) (0) + +#include + +#endif /* dwarf_abbrev_hash.h */ diff --git a/libdw/dwarf_abbrevhaschildren.c b/libdw/dwarf_abbrevhaschildren.c new file mode 100644 index 00000000..2261b2f3 --- /dev/null +++ b/libdw/dwarf_abbrevhaschildren.c @@ -0,0 +1,29 @@ +/* Return true if abbreviation is children flag set. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "libdwP.h" + + +int +dwarf_abbrevhaschildren (abbrev) + Dwarf_Abbrev *abbrev; +{ + return abbrev == NULL ? -1 : abbrev->has_children; +} diff --git a/libdw/dwarf_addrdie.c b/libdw/dwarf_addrdie.c new file mode 100644 index 00000000..c3fd4661 --- /dev/null +++ b/libdw/dwarf_addrdie.c @@ -0,0 +1,39 @@ +/* Return CU DIE containing given address. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +Dwarf_Die * +dwarf_addrdie (dbg, addr, result) + Dwarf *dbg; + Dwarf_Addr addr; + Dwarf_Die *result; +{ + Dwarf_Aranges *aranges; + size_t naranges; + Dwarf_Off off; + + if (INTUSE(dwarf_getaranges) (dbg, &aranges, &naranges) != 0 + || INTUSE(dwarf_getarangeinfo) (INTUSE(dwarf_getarange_addr) (aranges, + addr), + NULL, NULL, &off) != 0) + return NULL; + + return INTUSE(dwarf_offdie) (dbg, off, result); +} diff --git a/libdw/dwarf_arrayorder.c b/libdw/dwarf_arrayorder.c new file mode 100644 index 00000000..a1ea09fa --- /dev/null +++ b/libdw/dwarf_arrayorder.c @@ -0,0 +1,33 @@ +/* Return array order attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_arrayorder (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_ordering, + &attr_mem), + &value) == 0 ? (int) value : -1; +} diff --git a/libdw/dwarf_attr.c b/libdw/dwarf_attr.c new file mode 100644 index 00000000..8ebbb8f5 --- /dev/null +++ b/libdw/dwarf_attr.c @@ -0,0 +1,40 @@ +/* Return specific DWARF attribute of a DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +Dwarf_Attribute * +dwarf_attr (die, search_name, result) + Dwarf_Die *die; + unsigned int search_name; + Dwarf_Attribute *result; +{ + if (die == NULL) + return NULL; + + /* Search for the attribute with the given name. */ + result->valp = __libdw_find_attr (die, search_name, &result->code, + &result->form); + /* Always fill in the CU information. */ + result->cu = die->cu; + + return result->code == search_name ? result : NULL; +} +INTDEF(dwarf_attr) diff --git a/libdw/dwarf_attr_integrate.c b/libdw/dwarf_attr_integrate.c new file mode 100644 index 00000000..4b27296a --- /dev/null +++ b/libdw/dwarf_attr_integrate.c @@ -0,0 +1,43 @@ +/* Return specific DWARF attribute of a DIE, integrating DW_AT_abstract_origin. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + +Dwarf_Attribute * +dwarf_attr_integrate (Dwarf_Die *die, unsigned int search_name, + Dwarf_Attribute *result) +{ + Dwarf_Die die_mem; + + do + { + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, search_name, result); + if (attr != NULL) + return attr; + + attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin, result); + if (attr == NULL) + break; + + die = INTUSE(dwarf_formref_die) (attr, &die_mem); + } + while (die != NULL); + + return NULL; +} +INTDEF (dwarf_attr_integrate) diff --git a/libdw/dwarf_begin.c b/libdw/dwarf_begin.c new file mode 100644 index 00000000..70a1b07d --- /dev/null +++ b/libdw/dwarf_begin.c @@ -0,0 +1,85 @@ +/* Create descriptor from file descriptor for processing file. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include + + +Dwarf * +dwarf_begin (fd, cmd) + int fd; + Dwarf_Cmd cmd; +{ + Elf *elf; + Elf_Cmd elfcmd; + Dwarf *result = NULL; + + switch (cmd) + { + case DWARF_C_READ: + elfcmd = ELF_C_READ_MMAP; + break; + case DWARF_C_WRITE: + elfcmd = ELF_C_WRITE; + break; + case DWARF_C_RDWR: + elfcmd = ELF_C_RDWR; + break; + default: + /* No valid mode. */ + __libdw_seterrno (DWARF_E_INVALID_CMD); + return NULL; + } + + /* We have to call `elf_version' here since the user might have not + done it or initialized libelf with a different version. This + would break libdwarf since we are using the ELF data structures + in a certain way. */ + elf_version (EV_CURRENT); + + /* Get an ELF descriptor. */ + elf = elf_begin (fd, elfcmd, NULL); + if (elf == NULL) + { + /* Test why the `elf_begin" call failed. */ + struct stat64 st; + + if (fstat64 (fd, &st) == 0 && ! S_ISREG (st.st_mode)) + __libdw_seterrno (DWARF_E_NO_REGFILE); + else if (errno == EBADF) + __libdw_seterrno (DWARF_E_INVALID_FILE); + else + __libdw_seterrno (DWARF_E_IO_ERROR); + } + else + { + /* Do the real work now that we have an ELF descriptor. */ + result = INTUSE(dwarf_begin_elf) (elf, cmd, NULL); + + /* If this failed, free the resources. */ + if (result == NULL) + elf_end (elf); + else + result->free_elf = true; + } + + return result; +} diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c new file mode 100644 index 00000000..427ffc39 --- /dev/null +++ b/libdw/dwarf_begin_elf.c @@ -0,0 +1,252 @@ +/* Create descriptor from ELF descriptor for processing file. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include "libdwP.h" + + +/* Section names. */ +static const char dwarf_scnnames[IDX_last][17] = +{ + [IDX_debug_info] = ".debug_info", + [IDX_debug_abbrev] = ".debug_abbrev", + [IDX_debug_aranges] = ".debug_aranges", + [IDX_debug_line] = ".debug_line", + [IDX_debug_frame] = ".debug_frame", + [IDX_eh_frame] = ".eh_frame", + [IDX_debug_loc] = ".debug_loc", + [IDX_debug_pubnames] = ".debug_pubnames", + [IDX_debug_str] = ".debug_str", + [IDX_debug_funcnames] = ".debug_funcnames", + [IDX_debug_typenames] = ".debug_typenames", + [IDX_debug_varnames] = ".debug_varnames", + [IDX_debug_weaknames] = ".debug_weaknames", + [IDX_debug_macinfo] = ".debug_macinfo", + [IDX_debug_ranges] = ".debug_ranges" +}; +#define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0])) + + +static void +check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp) +{ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + /* Get the section header data. */ + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + /* This should never happen. If it does something is + wrong in the libelf library. */ + abort (); + + + /* Make sure the section is part of a section group only iff we + really need it. If we are looking for the global (= non-section + group debug info) we have to ignore all the info in section + groups. If we are looking into a section group we cannot look at + a section which isn't part of the section group. */ + if (! inscngrp && (shdr->sh_flags & SHF_GROUP) != 0) + /* Ignore the section. */ + return; + + + /* We recognize the DWARF section by their names. This is not very + safe and stable but the best we can do. */ + const char *scnname = elf_strptr (result->elf, ehdr->e_shstrndx, + shdr->sh_name); + if (scnname == NULL) + { + /* The section name must be valid. Otherwise is the ELF file + invalid. */ + __libdw_seterrno (DWARF_E_INVALID_ELF); + free (result); + return; + } + + + /* Recognize the various sections. Most names start with .debug_. */ + size_t cnt; + for (cnt = 0; cnt < ndwarf_scnnames; ++cnt) + if (strcmp (scnname, dwarf_scnnames[cnt]) == 0) + { + /* Found it. Remember where the data is. */ + if (unlikely (result->sectiondata[cnt] != NULL)) + /* A section appears twice. That's bad. We ignore the section. */ + break; + + /* Get the section data. */ + Elf_Data *data = elf_getdata (scn, NULL); + if (data != NULL && data->d_size != 0) + /* Yep, there is actually data available. */ + result->sectiondata[cnt] = data; + + break; + } +} + + +/* Check whether all the necessary DWARF information is available. */ +static Dwarf * +valid_p (Dwarf *result) +{ + /* We looked at all the sections. Now determine whether all the + sections with debugging information we need are there. + + XXX Which sections are absolutely necessary? Add tests if + necessary. For now we require only .debug_info. Hopefully this + is correct. */ + if (unlikely (result->sectiondata[IDX_debug_info] == NULL)) + { + __libdw_seterrno (DWARF_E_NO_DWARF); + result = NULL; + } + + return result; +} + + +static Dwarf * +global_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr) +{ + Elf_Scn *scn = NULL; + + while ((scn = elf_nextscn (elf, scn)) != NULL) + check_section (result, ehdr, scn, false); + + return valid_p (result); +} + + +static Dwarf * +scngrp_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr, Elf_Scn *scngrp) +{ + /* SCNGRP is the section descriptor for a section group which might + contain debug sections. */ + Elf_Data *data = elf_getdata (scngrp, NULL); + if (data == NULL) + { + /* We cannot read the section content. Fail! */ + free (result); + return NULL; + } + + /* The content of the section is a number of 32-bit words which + represent section indices. The first word is a flag word. */ + Elf32_Word *scnidx = (Elf32_Word *) data->d_buf; + size_t cnt; + for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size; ++cnt) + { + Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]); + if (scn == NULL) + { + /* A section group refers to a non-existing section. Should + never happen. */ + __libdw_seterrno (DWARF_E_INVALID_ELF); + free (result); + return NULL; + } + + check_section (result, ehdr, scn, true); + } + + return valid_p (result); +} + + +Dwarf * +dwarf_begin_elf (elf, cmd, scngrp) + Elf *elf; + Dwarf_Cmd cmd; + Elf_Scn *scngrp; +{ + GElf_Ehdr *ehdr; + GElf_Ehdr ehdr_mem; + + /* Get the ELF header of the file. We need various pieces of + information from it. */ + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + if (elf_kind (elf) != ELF_K_ELF) + __libdw_seterrno (DWARF_E_NOELF); + else + __libdw_seterrno (DWARF_E_GETEHDR_ERROR); + + return NULL; + } + + + /* Default memory allocation size. */ + size_t mem_default_size = sysconf (_SC_PAGESIZE) - 4 * sizeof (void *); + + /* Allocate the data structure. */ + Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf) + mem_default_size); + if (result == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + /* Fill in some values. */ + if ((BYTE_ORDER == LITTLE_ENDIAN && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + || (BYTE_ORDER == BIG_ENDIAN && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) + result->other_byte_order = true; + + result->elf = elf; + + /* Initialize the memory handling. */ + result->mem_default_size = mem_default_size; + result->oom_handler = __libdw_oom; + result->mem_tail = (struct libdw_memblock *) (result + 1); + result->mem_tail->size = (result->mem_default_size + - offsetof (struct libdw_memblock, mem)); + result->mem_tail->remaining = result->mem_tail->size; + result->mem_tail->prev = NULL; + + + if (cmd == DWARF_C_READ || cmd == DWARF_C_RDWR) + { + /* If the caller provides a section group we get the DWARF + sections only from this setion group. Otherwise we search + for the first section with the required name. Further + sections with the name are ignored. The DWARF specification + does not really say this is allowed. */ + if (scngrp == NULL) + return global_read (result, elf, ehdr); + else + return scngrp_read (result, elf, ehdr, scngrp); + } + else if (cmd == DWARF_C_WRITE) + { + __libdw_seterrno (DWARF_E_UNIMPL); + free (result); + return NULL; + } + + __libdw_seterrno (DWARF_E_INVALID_CMD); + free (result); + return NULL; +} +INTDEF(dwarf_begin_elf) diff --git a/libdw/dwarf_bitoffset.c b/libdw/dwarf_bitoffset.c new file mode 100644 index 00000000..52ab1759 --- /dev/null +++ b/libdw/dwarf_bitoffset.c @@ -0,0 +1,33 @@ +/* Return bit offset attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_bitoffset (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_bit_offset, + &attr_mem), + &value) == 0 ? (int) value : -1; +} diff --git a/libdw/dwarf_bitsize.c b/libdw/dwarf_bitsize.c new file mode 100644 index 00000000..c67b4ccf --- /dev/null +++ b/libdw/dwarf_bitsize.c @@ -0,0 +1,33 @@ +/* Return bit size attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_bitsize (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_bit_size, + &attr_mem), + &value) == 0 ? (int) value : -1; +} diff --git a/libdw/dwarf_bytesize.c b/libdw/dwarf_bytesize.c new file mode 100644 index 00000000..3e0b05a8 --- /dev/null +++ b/libdw/dwarf_bytesize.c @@ -0,0 +1,33 @@ +/* Return byte size attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_bytesize (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_byte_size, + &attr_mem), + &value) == 0 ? (int) value : -1; +} diff --git a/libdw/dwarf_child.c b/libdw/dwarf_child.c new file mode 100644 index 00000000..8dbe9179 --- /dev/null +++ b/libdw/dwarf_child.c @@ -0,0 +1,159 @@ +/* Return vhild of current DIE. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" +#include + +/* Some arbitrary value not conflicting with any existing code. */ +#define INVALID 0xffffe444 + + +unsigned char * +internal_function_def +__libdw_find_attr (Dwarf_Die *die, unsigned int search_name, + unsigned int *codep, unsigned int *formp) +{ + Dwarf *dbg = die->cu->dbg; + const unsigned char *readp = (unsigned char *) die->addr; + + /* First we have to get the abbreviation code so that we can decode + the data in the DIE. */ + unsigned int abbrev_code; + get_uleb128 (abbrev_code, readp); + + /* Find the abbreviation entry. */ + Dwarf_Abbrev *abbrevp = die->abbrev; + if (abbrevp == NULL) + { + abbrevp = __libdw_findabbrev (die->cu, abbrev_code); + die->abbrev = abbrevp ?: (Dwarf_Abbrev *) -1l; + } + if (unlikely (die->abbrev == (Dwarf_Abbrev *) -1l)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* Search the name attribute. */ + unsigned char *const endp + = ((unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + + dbg->sectiondata[IDX_debug_abbrev]->d_size); + + const unsigned char *attrp = die->abbrev->attrp; + while (1) + { + /* Are we still in bounds? This test needs to be refined. */ + if (unlikely (attrp + 1 >= endp)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* Get attribute name and form. + + XXX We don't check whether this reads beyond the end of the + section. */ + unsigned int attr_name; + get_uleb128 (attr_name, attrp); + unsigned int attr_form; + get_uleb128 (attr_form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* Is this the name attribute? */ + if (attr_name == search_name && search_name != INVALID) + { + if (codep != NULL) + *codep = attr_name; + if (formp != NULL) + *formp = attr_form; + + return (unsigned char *) readp; + } + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len = __libdw_form_val_len (dbg, die->cu, attr_form, readp); + + if (unlikely (len == (size_t) -1l)) + { + readp = NULL; + break; + } + + // XXX We need better boundary checks. + readp += len; + } + } + + // XXX Do we need other values? + if (codep != NULL) + *codep = INVALID; + if (formp != NULL) + *formp = INVALID; + + return (unsigned char *) readp; +} + + +int +dwarf_child (die, result) + Dwarf_Die *die; + Dwarf_Die *result; +{ + /* Ignore previous errors. */ + if (die == NULL) + return -1; + + /* Skip past the last attribute. */ + void *addr = NULL; + + /* If we already know there are no children do not search. */ + if (die->abbrev != (Dwarf_Abbrev *) -1 + && (die->abbrev == NULL || die->abbrev->has_children)) + addr = __libdw_find_attr (die, INVALID, NULL, NULL); + if (die->abbrev == (Dwarf_Abbrev *) -1l) + return -1; + + /* Make sure the DIE really has children. */ + if (! die->abbrev->has_children) + /* There cannot be any children. */ + return 1; + + if (addr == NULL) + return -1; + + /* RESULT can be the same as DIE. So preserve what we need. */ + struct Dwarf_CU *cu = die->cu; + + /* Clear the entire DIE structure. This signals we have not yet + determined any of the information. */ + memset (result, '\0', sizeof (Dwarf_Die)); + + /* We have the address. */ + result->addr = addr; + + /* Same CU as the parent. */ + result->cu = cu; + + return 0; +} +INTDEF(dwarf_child) diff --git a/libdw/dwarf_cuoffset.c b/libdw/dwarf_cuoffset.c new file mode 100644 index 00000000..f3adfa83 --- /dev/null +++ b/libdw/dwarf_cuoffset.c @@ -0,0 +1,32 @@ +/* Return offset of DIE in CU. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +Dwarf_Off +dwarf_cuoffset (die) + Dwarf_Die *die; +{ + return (die == NULL + ? (Dwarf_Off) -1l + : (die->addr + - die->cu->dbg->sectiondata[IDX_debug_info]->d_buf + - die->cu->start)); +} diff --git a/libdw/dwarf_diename.c b/libdw/dwarf_diename.c new file mode 100644 index 00000000..41d763c5 --- /dev/null +++ b/libdw/dwarf_diename.c @@ -0,0 +1,31 @@ +/* Return string in name attribute of DIE. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +const char * +dwarf_diename (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + + return INTUSE(dwarf_formstring) (INTUSE(dwarf_attr) (die, DW_AT_name, + &attr_mem)); +} diff --git a/libdw/dwarf_dieoffset.c b/libdw/dwarf_dieoffset.c new file mode 100644 index 00000000..e678a404 --- /dev/null +++ b/libdw/dwarf_dieoffset.c @@ -0,0 +1,32 @@ +/* Return offset of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +Dwarf_Off +dwarf_dieoffset (die) + Dwarf_Die *die; +{ + return (die == NULL + ? ~0ul + : (Dwarf_Off) (die->addr + - die->cu->dbg->sectiondata[IDX_debug_info]->d_buf)); +} +INTDEF(dwarf_dieoffset) diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c new file mode 100644 index 00000000..935bd3d2 --- /dev/null +++ b/libdw/dwarf_end.c @@ -0,0 +1,75 @@ +/* Release debugging handling context. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libdwP.h" + + + +static void +noop_free (void *arg __attribute__ ((unused))) +{ +} + + +static void +cu_free (void *arg) +{ + struct Dwarf_CU *p = (struct Dwarf_CU *) arg; + + Dwarf_Abbrev_Hash_free (&p->abbrev_hash); + + tdestroy (p->locs, noop_free); +} + + +int +dwarf_end (dwarf) + Dwarf *dwarf; +{ + if (dwarf != NULL) + { + /* The search tree for the CUs. NB: the CU data itself is + allocated separately, but the abbreviation hash tables need + to be handled. */ + tdestroy (dwarf->cu_tree, cu_free); + + struct libdw_memblock *memp = dwarf->mem_tail; + /* The first block is allocated together with the Dwarf object. */ + while (memp->prev != NULL) + { + struct libdw_memblock *prevp = memp->prev; + free (memp); + memp = prevp; + } + + /* Free the pubnames helper structure. */ + free (dwarf->pubnames_sets); + + /* Free the ELF descriptor if necessary. */ + if (dwarf->free_elf) + elf_end (dwarf->elf); + + /* Free the context descriptor. */ + free (dwarf); + } + + return 0; +} diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c new file mode 100644 index 00000000..85d928c9 --- /dev/null +++ b/libdw/dwarf_error.c @@ -0,0 +1,180 @@ +/* Retrieve ELF descriptor used for DWARF access. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libdwP.h" + + +#ifdef USE_TLS +/* The error number. */ +static __thread int global_error; +#else +/* This is the key for the thread specific memory. */ +static tls_key_t key; + +/* The error number. Used in non-threaded programs. */ +static int global_error; +static bool threaded; +/* We need to initialize the thread-specific data. */ +once_define (static, once); + +/* The initialization and destruction functions. */ +static void init (void); +static void free_key_mem (void *mem); +#endif /* TLS */ + + +int +dwarf_errno (void) +{ + int result; + +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if (threaded) + { + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + result = (intptr_t) getspecific (key); + + setspecific (key, (void *) (intptr_t) DWARF_E_NOERROR); + return result; + } +#endif /* TLS */ + + result = global_error; + global_error = DWARF_E_NOERROR; + return result; +} +INTDEF(dwarf_errno) + + +/* XXX For now we use string pointers. Once the table stablelizes + make it more DSO-friendly. */ +static const char *errmsgs[] = + { + [DWARF_E_NOERROR] = N_("no error"), + [DWARF_E_UNKNOWN_ERROR] = N_("unknown error"), + [DWARF_E_INVALID_ACCESS] = N_("invalid access"), + [DWARF_E_NO_REGFILE] = N_("no regular file"), + [DWARF_E_IO_ERROR] = N_("I/O error"), + [DWARF_E_INVALID_ELF] = N_("invalid ELF file"), + [DWARF_E_NO_DWARF] = N_("no DWARF information"), + [DWARF_E_NOELF] = N_("no ELF file"), + [DWARF_E_GETEHDR_ERROR] = N_("cannot get ELF header"), + [DWARF_E_NOMEM] = N_("out of memory"), + [DWARF_E_UNIMPL] = N_("not implemented"), + [DWARF_E_INVALID_CMD] = N_("invalid command"), + [DWARF_E_INVALID_VERSION] = N_("invalid version"), + [DWARF_E_INVALID_FILE] = N_("invalid file"), + [DWARF_E_NO_ENTRY] = N_("no entries found"), + [DWARF_E_INVALID_DWARF] = N_("invalid DWARF"), + [DWARF_E_NO_STRING] = N_("no string data"), + [DWARF_E_NO_ADDR] = N_("no address value"), + [DWARF_E_NO_CONSTANT] = N_("no constant value"), + [DWARF_E_NO_REFERENCE] = N_("no reference value"), + [DWARF_E_INVALID_REFERENCE] = N_("invalid reference value"), + [DWARF_E_NO_DEBUG_LINE] = N_(".debug_line section missing"), + [DWARF_E_INVALID_DEBUG_LINE] = N_("invalid .debug_line section"), + [DWARF_E_TOO_BIG] = N_("debug information too big"), + [DWARF_E_VERSION] = N_("invalid DWARF version"), + [DWARF_E_INVALID_DIR_IDX] = N_("invalid directory index"), + [DWARF_E_ADDR_OUTOFRANGE] = N_("address out of range"), + [DWARF_E_NO_LOCLIST] = N_("no location list value"), + [DWARF_E_NO_BLOCK] = N_("no block data"), + [DWARF_E_INVALID_LINE_IDX] = N_("invalid line index"), + [DWARF_E_INVALID_ARANGE_IDX] = N_("invalid address range index"), + [DWARF_E_NO_MATCH] = N_("no matching address range"), + [DWARF_E_NO_FLAG] = N_("no flag value"), + [DWARF_E_INVALID_OFFSET] = N_("invalid offset"), + [DWARF_E_NO_DEBUG_RANGES] = N_(".debug_ranges section missing"), + }; +#define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0])) + + +void +__libdw_seterrno (value) + int value; +{ +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if (threaded) + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + setspecific (key, (void *) (intptr_t) value); +#endif /* TLS */ + + global_error = (value >= 0 && value < (int) nerrmsgs + ? value : DWARF_E_UNKNOWN_ERROR); +} + + +const char * +dwarf_errmsg (error) + int error; +{ + int last_error; + +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if ((error == 0 || error == -1) && threaded) + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + last_error = (intptr_t) getspecific (key); + else +#endif /* TLS */ + last_error = global_error; + + if (error == 0) + return last_error != 0 ? _(errmsgs[last_error]) : NULL; + else if (error < -1 || error >= (int) nerrmsgs) + return _(errmsgs[DWARF_E_UNKNOWN_ERROR]); + + return _(errmsgs[error == -1 ? last_error : error]); +} + + +#ifndef USE_TLS +/* Free the thread specific data, this is done if a thread terminates. */ +static void +free_key_mem (void *mem __attribute__ ((unused))) +{ + setspecific (key, NULL); +} + + +/* Initialize the key for the global variable. */ +static void +init (void) +{ + // XXX Screw you, gcc4, the unused function attribute does not work. + __asm ("" :: "r" (free_key_mem)); + + if (key_create (&key, free_key_mem) == 0) + /* Creating the key succeeded. */ + threaded = true; +} +#endif /* TLS */ diff --git a/libdw/dwarf_filesrc.c b/libdw/dwarf_filesrc.c new file mode 100644 index 00000000..770c004b --- /dev/null +++ b/libdw/dwarf_filesrc.c @@ -0,0 +1,36 @@ +/* Find source file information. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +const char * +dwarf_filesrc (Dwarf_Files *file, size_t idx, Dwarf_Word *mtime, + Dwarf_Word *length) +{ + if (file == NULL || idx >= file->nfiles) + return NULL; + + if (mtime != NULL) + *mtime = file->info[idx].mtime; + + if (length != NULL) + *length = file->info[idx].length; + + return file->info[idx].name; +} diff --git a/libdw/dwarf_formaddr.c b/libdw/dwarf_formaddr.c new file mode 100644 index 00000000..168eb89a --- /dev/null +++ b/libdw/dwarf_formaddr.c @@ -0,0 +1,44 @@ +/* Return address represented by attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_formaddr (attr, return_addr) + Dwarf_Attribute *attr; + Dwarf_Addr *return_addr; +{ + if (attr == NULL) + return -1; + + if (unlikely (attr->form != DW_FORM_addr)) + { + __libdw_seterrno (DWARF_E_NO_ADDR); + return -1; + } + + if (attr->cu->address_size == 8) + *return_addr = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + else + *return_addr = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + + return 0; +} +INTDEF(dwarf_formaddr) diff --git a/libdw/dwarf_formblock.c b/libdw/dwarf_formblock.c new file mode 100644 index 00000000..30c2ac93 --- /dev/null +++ b/libdw/dwarf_formblock.c @@ -0,0 +1,72 @@ +/* Return block represented by attribute. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_formblock (attr, return_block) + Dwarf_Attribute *attr; + Dwarf_Block *return_block; +{ + if (attr == NULL) + return -1; + + const unsigned char *datap; + + switch (attr->form) + { + case DW_FORM_block1: + return_block->length = *(uint8_t *) attr->valp; + return_block->data = attr->valp + 1; + break; + + case DW_FORM_block2: + return_block->length = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + return_block->data = attr->valp + 2; + break; + + case DW_FORM_block4: + return_block->length = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + return_block->data = attr->valp + 4; + break; + + case DW_FORM_block: + datap = attr->valp; + get_uleb128 (return_block->length, datap); + return_block->data = (unsigned char *) datap; + break; + + default: + __libdw_seterrno (DWARF_E_NO_BLOCK); + return -1; + } + + if (return_block->data + return_block->length + > ((unsigned char *) attr->cu->dbg->sectiondata[IDX_debug_info]->d_buf + + attr->cu->dbg->sectiondata[IDX_debug_info]->d_size)) + { + /* Block does not fit. */ + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + return 0; +} +INTDEF(dwarf_formblock) diff --git a/libdw/dwarf_formflag.c b/libdw/dwarf_formflag.c new file mode 100644 index 00000000..ac344019 --- /dev/null +++ b/libdw/dwarf_formflag.c @@ -0,0 +1,40 @@ +/* Return flag represented by attribute. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_formflag (attr, return_bool) + Dwarf_Attribute *attr; + bool *return_bool; +{ + if (attr == NULL) + return -1; + + if (unlikely (attr->form != DW_FORM_flag)) + { + __libdw_seterrno (DWARF_E_NO_FLAG); + return -1; + } + + *return_bool = *attr->valp != 0; + + return 0; +} diff --git a/libdw/dwarf_formref.c b/libdw/dwarf_formref.c new file mode 100644 index 00000000..ea569905 --- /dev/null +++ b/libdw/dwarf_formref.c @@ -0,0 +1,67 @@ +/* Return reference offset represented by attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_formref (attr, return_offset) + Dwarf_Attribute *attr; + Dwarf_Off *return_offset; +{ + if (attr == NULL) + return -1; + + const unsigned char *datap; + + switch (attr->form) + { + case DW_FORM_ref1: + *return_offset = *attr->valp; + break; + + case DW_FORM_ref2: + *return_offset = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref4: + *return_offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref8: + *return_offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref_udata: + datap = attr->valp; + get_uleb128 (*return_offset, datap); + break; + + case DW_FORM_ref_addr: + __libdw_seterrno (DWARF_E_INVALID_REFERENCE); + return -1; + + default: + __libdw_seterrno (DWARF_E_NO_REFERENCE); + return -1; + } + + return 0; +} +INTDEF(dwarf_formref) diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c new file mode 100644 index 00000000..7f5b4f97 --- /dev/null +++ b/libdw/dwarf_formref_die.c @@ -0,0 +1,28 @@ +/* Look up the DIE in a reference-form attribute. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + +Dwarf_Die * +dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *die_mem) +{ + Dwarf_Off offset; + return (unlikely (INTUSE(dwarf_formref) (attr, &offset) != 0) ? NULL + : INTUSE(dwarf_offdie) (attr->cu->dbg, attr->cu->start + offset, + die_mem)); +} +INTDEF (dwarf_formref_die) diff --git a/libdw/dwarf_formsdata.c b/libdw/dwarf_formsdata.c new file mode 100644 index 00000000..a5b6b88a --- /dev/null +++ b/libdw/dwarf_formsdata.c @@ -0,0 +1,68 @@ +/* Return signed constant represented by attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_formsdata (attr, return_sval) + Dwarf_Attribute *attr; + Dwarf_Sword *return_sval; +{ + if (attr == NULL) + return -1; + + const unsigned char *datap; + + switch (attr->form) + { + case DW_FORM_data1: + *return_sval = *attr->valp; + break; + + case DW_FORM_data2: + *return_sval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data4: + *return_sval = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data8: + *return_sval = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_sdata: + datap = attr->valp; + get_sleb128 (*return_sval, datap); + break; + + case DW_FORM_udata: + datap = attr->valp; + get_uleb128 (*return_sval, datap); + break; + + default: + __libdw_seterrno (DWARF_E_NO_CONSTANT); + return -1; + } + + return 0; +} +INTDEF(dwarf_formsdata) diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c new file mode 100644 index 00000000..eac1cc05 --- /dev/null +++ b/libdw/dwarf_formstring.c @@ -0,0 +1,58 @@ +/* Return string associated with given attribute. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +const char * +dwarf_formstring (attrp) + Dwarf_Attribute *attrp; +{ + /* Ignore earlier errors. */ + if (attrp == NULL) + return NULL; + + /* We found it. Now determine where the string is stored. */ + if (attrp->form == DW_FORM_string) + /* A simple inlined string. */ + return (const char *) attrp->valp; + + Dwarf *dbg = attrp->cu->dbg; + + if (unlikely (attrp->form != DW_FORM_strp) + || dbg->sectiondata[IDX_debug_str] == NULL) + { + invalid_error: + __libdw_seterrno (DWARF_E_NO_STRING); + return NULL; + } + + uint64_t off; + // XXX We need better boundary checks. + if (attrp->cu->offset_size == 8) + off = read_8ubyte_unaligned (dbg, attrp->valp); + else + off = read_4ubyte_unaligned (dbg, attrp->valp); + + if (off >= dbg->sectiondata[IDX_debug_str]->d_size) + goto invalid_error; + + return (const char *) dbg->sectiondata[IDX_debug_str]->d_buf + off; +} +INTDEF(dwarf_formstring) diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c new file mode 100644 index 00000000..67985621 --- /dev/null +++ b/libdw/dwarf_formudata.c @@ -0,0 +1,68 @@ +/* Return unsigned constant represented by attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_formudata (attr, return_uval) + Dwarf_Attribute *attr; + Dwarf_Word *return_uval; +{ + if (attr == NULL) + return -1; + + const unsigned char *datap; + + switch (attr->form) + { + case DW_FORM_data1: + *return_uval = *attr->valp; + break; + + case DW_FORM_data2: + *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data4: + *return_uval = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data8: + *return_uval = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_sdata: + datap = attr->valp; + get_sleb128 (*return_uval, datap); + break; + + case DW_FORM_udata: + datap = attr->valp; + get_uleb128 (*return_uval, datap); + break; + + default: + __libdw_seterrno (DWARF_E_NO_CONSTANT); + return -1; + } + + return 0; +} +INTDEF(dwarf_formudata) diff --git a/libdw/dwarf_func_col.c b/libdw/dwarf_func_col.c new file mode 100644 index 00000000..feda1435 --- /dev/null +++ b/libdw/dwarf_func_col.c @@ -0,0 +1,27 @@ +/* Get line number of beginning of given function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_func_col (Dwarf_Func *func, int *colp) +{ + return __libdw_func_intval (func, colp, DW_AT_decl_column); +} diff --git a/libdw/dwarf_func_entrypc.c b/libdw/dwarf_func_entrypc.c new file mode 100644 index 00000000..6b5103e0 --- /dev/null +++ b/libdw/dwarf_func_entrypc.c @@ -0,0 +1,33 @@ +/* Get entry address of function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_func_entrypc (Dwarf_Func *func, Dwarf_Addr *return_addr) +{ + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (func->die, DW_AT_entry_pc, + &attr_mem); + if (attr != NULL) + return INTUSE(dwarf_formaddr) (attr, return_addr); + + return INTUSE(dwarf_lowpc) (func->die, return_addr); +} diff --git a/libdw/dwarf_func_file.c b/libdw/dwarf_func_file.c new file mode 100644 index 00000000..d5302df0 --- /dev/null +++ b/libdw/dwarf_func_file.c @@ -0,0 +1,72 @@ +/* Return file name containing definition of the given function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "libdwP.h" + + +const char * +dwarf_func_file (Dwarf_Func *func) +{ + Dwarf_Attribute attr_mem; + Dwarf_Sword idx = 0; + Dwarf_Die *die = func->die; + + if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr) (die, DW_AT_decl_file, + &attr_mem), &idx) != 0) + return NULL; + + /* Zero means no source file information available. */ + if (idx == 0) + { + __libdw_seterrno (DWARF_E_NO_ENTRY); + return NULL; + } + + /* Get the array of source files for the CU. */ + struct Dwarf_CU *cu = die->cu; + if (cu->lines == NULL) + { + Dwarf_Lines *lines; + size_t nlines; + + /* Let the more generic function do the work. It'll create more + data but that will be needed in an real program anyway. */ + (void) INTUSE(dwarf_getsrclines) (func->cudie, &lines, &nlines); + assert (cu->lines != NULL); + } + + if (cu->lines == (void *) -1l) + { + /* If the file index is not zero, there must be file information + available. */ + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + assert (cu->files != NULL && cu->files != (void *) -1l); + + if (idx >= cu->files->nfiles) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + return cu->files->info[idx].name; +} diff --git a/libdw/dwarf_func_highpc.c b/libdw/dwarf_func_highpc.c new file mode 100644 index 00000000..c5d2eec3 --- /dev/null +++ b/libdw/dwarf_func_highpc.c @@ -0,0 +1,26 @@ +/* Get end address of function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_func_highpc (Dwarf_Func *func, Dwarf_Addr *return_addr) +{ + return INTUSE(dwarf_highpc) (func->die, return_addr); +} diff --git a/libdw/dwarf_func_line.c b/libdw/dwarf_func_line.c new file mode 100644 index 00000000..6259b9f1 --- /dev/null +++ b/libdw/dwarf_func_line.c @@ -0,0 +1,47 @@ +/* Get line number of beginning of given function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include "libdwP.h" + + +int +dwarf_func_line (Dwarf_Func *func, int *linep) +{ + return __libdw_func_intval (func, linep, DW_AT_decl_line); +} + + +int internal_function +__libdw_func_intval (Dwarf_Func *func, int *linep, int attval) +{ + Dwarf_Attribute attr_mem; + Dwarf_Sword line; + + int res = INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr) (func->die, attval, + &attr_mem), &line); + if (res == 0) + { + assert (line >= 0 && line <= INT_MAX); + *linep = line; + } + + return res; +} diff --git a/libdw/dwarf_func_lowpc.c b/libdw/dwarf_func_lowpc.c new file mode 100644 index 00000000..d364e6c6 --- /dev/null +++ b/libdw/dwarf_func_lowpc.c @@ -0,0 +1,26 @@ +/* Get start address of function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_func_lowpc (Dwarf_Func *func, Dwarf_Addr *return_addr) +{ + return INTUSE(dwarf_lowpc) (func->die, return_addr); +} diff --git a/libdw/dwarf_func_name.c b/libdw/dwarf_func_name.c new file mode 100644 index 00000000..4151c359 --- /dev/null +++ b/libdw/dwarf_func_name.c @@ -0,0 +1,30 @@ +/* Get function name. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +const char * +dwarf_func_name (Dwarf_Func *func) +{ + Dwarf_Attribute attr_mem; + + return INTUSE(dwarf_formstring) (INTUSE(dwarf_attr) (func->die, DW_AT_name, + &attr_mem)); +} diff --git a/libdw/dwarf_getabbrev.c b/libdw/dwarf_getabbrev.c new file mode 100644 index 00000000..a6968a83 --- /dev/null +++ b/libdw/dwarf_getabbrev.c @@ -0,0 +1,127 @@ +/* Get abbreviation at given offset. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "libdwP.h" + + +Dwarf_Abbrev * +internal_function_def +__libdw_getabbrev (dbg, cu, offset, lengthp, result) + Dwarf *dbg; + struct Dwarf_CU *cu; + Dwarf_Off offset; + size_t *lengthp; + Dwarf_Abbrev *result; +{ + /* Don't fail if there is not .debug_abbrev section. */ + if (dbg->sectiondata[IDX_debug_abbrev] == NULL) + return NULL; + + const unsigned char *abbrevp + = (unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + offset; + if (*abbrevp == '\0') + /* We are past the last entry. */ + return DWARF_END_ABBREV; + + /* 7.5.3 Abbreviations Tables + + [...] Each declaration begins with an unsigned LEB128 number + representing the abbreviation code itself. [...] The + abbreviation code is followed by another unsigned LEB128 + number that encodes the entry's tag. [...] + + [...] Following the tag encoding is a 1-byte value that + determines whether a debugging information entry using this + abbreviation has child entries or not. [...] + + [...] Finally, the child encoding is followed by a series of + attribute specifications. Each attribute specification + consists of two parts. The first part is an unsigned LEB128 + number representing the attribute's name. The second part is + an unsigned LEB128 number representing the attribute's form. */ + const unsigned char *start_abbrevp = abbrevp; + unsigned int code; + get_uleb128 (code, abbrevp); + + /* Check whether this code is already in the hash table. */ + bool foundit = false; + Dwarf_Abbrev *abb = NULL; + if (cu == NULL + || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL)) == NULL) + { + if (result == NULL) + abb = libdw_typed_alloc (dbg, Dwarf_Abbrev); + else + abb = result; + } + else + { + foundit = true; + + assert (abb->offset == offset); + + /* If the caller doesn't need the length we are done. */ + if (lengthp == NULL) + goto out; + } + + /* If there is already a value in the hash table we are going to + overwrite its content. This must not be a problem, since the + content better be the same. */ + abb->code = code; + get_uleb128 (abb->tag, abbrevp); + abb->has_children = *abbrevp++ == DW_CHILDREN_yes; + abb->attrp = (unsigned char *) abbrevp; + abb->offset = offset; + + /* Skip over all the attributes and count them while doing so. */ + abb->attrcnt = 0; + unsigned int attrname; + unsigned int attrform; + do + { + get_uleb128 (attrname, abbrevp); + get_uleb128 (attrform, abbrevp); + } + while (attrname != 0 && attrform != 0 && ++abb->attrcnt); + + /* Return the length to the caller if she asked for it. */ + if (lengthp != NULL) + *lengthp = abbrevp - start_abbrevp; + + /* Add the entry to the hash table. */ + if (cu != NULL && ! foundit) + (void) Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb); + + out: + return abb; +} + + +Dwarf_Abbrev * +dwarf_getabbrev (die, offset, lengthp) + Dwarf_Die *die; + Dwarf_Off offset; + size_t *lengthp; +{ + return __libdw_getabbrev (die->cu->dbg, die->cu, + die->cu->orig_abbrev_offset + offset, lengthp, + NULL); +} diff --git a/libdw/dwarf_getabbrevattr.c b/libdw/dwarf_getabbrevattr.c new file mode 100644 index 00000000..8cdf6a3d --- /dev/null +++ b/libdw/dwarf_getabbrevattr.c @@ -0,0 +1,64 @@ +/* Get specific attribute of abbreviation. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "libdwP.h" + + +int +dwarf_getabbrevattr (abbrev, idx, namep, formp, offsetp) + Dwarf_Abbrev *abbrev; + size_t idx; + unsigned int *namep; + unsigned int *formp; + Dwarf_Off *offsetp; +{ + if (abbrev == NULL) + return -1; + + size_t cnt = 0; + const unsigned char *attrp = abbrev->attrp; + const unsigned char *start_attrp; + unsigned int name; + unsigned int form; + + do + { + start_attrp = attrp; + + /* Attribute code and form are encoded as ULEB128 values. */ + get_uleb128 (name, attrp); + get_uleb128 (form, attrp); + + /* If both values are zero the index is out of range. */ + if (name == 0 && form == 0) + return -1; + } + while (cnt++ < idx); + + /* Store the result if requested. */ + if (namep != NULL) + *namep = name; + if (formp != NULL) + *formp = form; + if (offsetp != NULL) + *offsetp = (start_attrp - abbrev->attrp) + abbrev->offset; + + return 0; +} diff --git a/libdw/dwarf_getabbrevcode.c b/libdw/dwarf_getabbrevcode.c new file mode 100644 index 00000000..ef3dac46 --- /dev/null +++ b/libdw/dwarf_getabbrevcode.c @@ -0,0 +1,29 @@ +/* Get abbreviation code. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "libdwP.h" + + +unsigned int +dwarf_getabbrevcode (abbrev) + Dwarf_Abbrev *abbrev; +{ + return abbrev == NULL ? 0 : abbrev->code; +} diff --git a/libdw/dwarf_getabbrevtag.c b/libdw/dwarf_getabbrevtag.c new file mode 100644 index 00000000..4707fdd1 --- /dev/null +++ b/libdw/dwarf_getabbrevtag.c @@ -0,0 +1,29 @@ +/* Get abbreviation tag. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "libdwP.h" + + +unsigned int +dwarf_getabbrevtag (abbrev) + Dwarf_Abbrev *abbrev; +{ + return abbrev == NULL ? 0 : abbrev->tag; +} diff --git a/libdw/dwarf_getarange_addr.c b/libdw/dwarf_getarange_addr.c new file mode 100644 index 00000000..2d0408e4 --- /dev/null +++ b/libdw/dwarf_getarange_addr.c @@ -0,0 +1,47 @@ +/* Get address range which includes given address. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +Dwarf_Arange * +dwarf_getarange_addr (aranges, addr) + Dwarf_Aranges *aranges; + Dwarf_Addr addr; +{ + if (aranges == NULL) + return NULL; + + /* The ranges are sorted by address, so we can use binary search. */ + size_t l = 0, u = aranges->naranges; + while (l < u) + { + size_t idx = (l + u) / 2; + if (addr < aranges->info[idx].addr) + u = idx; + else if (addr > aranges->info[idx].addr + && addr - aranges->info[idx].addr >= aranges->info[idx].length) + l = idx + 1; + else + return &aranges->info[idx]; + } + + __libdw_seterrno (DWARF_E_NO_MATCH); + return NULL; +} +INTDEF(dwarf_getarange_addr) diff --git a/libdw/dwarf_getarangeinfo.c b/libdw/dwarf_getarangeinfo.c new file mode 100644 index 00000000..eb1f539d --- /dev/null +++ b/libdw/dwarf_getarangeinfo.c @@ -0,0 +1,38 @@ +/* Return list address ranges. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_getarangeinfo (Dwarf_Arange *arange, Dwarf_Addr *addrp, + Dwarf_Word *lengthp, Dwarf_Off *offsetp) +{ + if (arange == NULL) + return -1; + + if (addrp != NULL) + *addrp = arange->addr; + if (lengthp != NULL) + *lengthp = arange->length; + if (offsetp != NULL) + *offsetp = arange->offset; + + return 0; +} +INTDEF(dwarf_getarangeinfo) diff --git a/libdw/dwarf_getaranges.c b/libdw/dwarf_getaranges.c new file mode 100644 index 00000000..f7cf050f --- /dev/null +++ b/libdw/dwarf_getaranges.c @@ -0,0 +1,212 @@ +/* Return list address ranges. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "libdwP.h" + + +struct arangelist +{ + Dwarf_Arange arange; + struct arangelist *next; +}; + +/* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers. */ +static int +compare_aranges (const void *a, const void *b) +{ + Dwarf_Arange *const *p1 = a, *const *p2 = b; + Dwarf_Arange *l1 = *p1, *l2 = *p2; + return l1->addr - l2->addr; +} + +int +dwarf_getaranges (dbg, aranges, naranges) + Dwarf *dbg; + Dwarf_Aranges **aranges; + size_t *naranges; +{ + if (dbg == NULL) + return -1; + + if (dbg->aranges != NULL) + { + *aranges = dbg->aranges; + if (naranges != NULL) + *naranges = dbg->aranges->naranges; + return 0; + } + + if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL) + return -1; + + struct arangelist *arangelist = NULL; + unsigned int narangelist = 0; + + const char *readp + = (const char *) dbg->sectiondata[IDX_debug_aranges]->d_buf; + const char *readendp = readp + dbg->sectiondata[IDX_debug_aranges]->d_size; + + while (readp < readendp) + { + const char *hdrstart = readp; + + /* Each entry starts with a header: + + 1. A 4-byte or 12-byte length containing the length of the + set of entries for this compilation unit, not including the + length field itself. [...] + + 2. A 2-byte version identifier containing the value 2 for + DWARF Version 2.1. + + 3. A 4-byte or 8-byte offset into the .debug_info section. [...] + + 4. A 1-byte unsigned integer containing the size in bytes of + an address (or the offset portion of an address for segmented + addressing) on the target system. + + 5. A 1-byte unsigned integer containing the size in bytes of + a segment descriptor on the target system. */ + Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp); + unsigned int length_bytes = 4; + if (length == 0xffffffff) + { + length = read_8ubyte_unaligned_inc (dbg, readp); + length_bytes = 8; + } + + unsigned int version = read_2ubyte_unaligned_inc (dbg, readp); + if (version != 2) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + Dwarf_Word offset; + if (length_bytes == 4) + offset = read_4ubyte_unaligned_inc (dbg, readp); + else + offset = read_8ubyte_unaligned_inc (dbg, readp); + + unsigned int address_size = *readp++; + if (address_size != 4 && address_size != 8) + goto invalid; + + /* Ignore the segment size value. */ + // XXX Really? + (void) *readp++; + + /* Round the address to the next multiple of 2*address_size. */ + readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size))) + % (2 * address_size)); + + while (1) + { + Dwarf_Word range_address; + Dwarf_Word range_length; + + if (address_size == 4) + { + range_address = read_4ubyte_unaligned_inc (dbg, readp); + range_length = read_4ubyte_unaligned_inc (dbg, readp); + } + else + { + range_address = read_8ubyte_unaligned_inc (dbg, readp); + range_length = read_8ubyte_unaligned_inc (dbg, readp); + } + + /* Two zero values mark the end. */ + if (range_address == 0 && range_length == 0) + break; + + struct arangelist *new_arange = + (struct arangelist *) alloca (sizeof (struct arangelist)); + + new_arange->arange.addr = range_address; + new_arange->arange.length = range_length; + + /* We store the actual CU DIE offset, not the CU header offset. */ + const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf + + offset); + unsigned int offset_size; + if (read_4ubyte_unaligned_noncvt (cu_header) == 0xffffffff) + offset_size = 8; + else + offset_size = 4; + new_arange->arange.offset = offset + 3 * offset_size - 4 + 3; + + new_arange->next = arangelist; + arangelist = new_arange; + ++narangelist; + } + } + + if (narangelist == 0) + { + if (naranges != NULL) + *naranges = 0; + *aranges = NULL; + return 0; + } + + /* Allocate the array for the result. */ + void *buf = libdw_alloc (dbg, Dwarf_Aranges, + sizeof (Dwarf_Aranges) + + narangelist * sizeof (Dwarf_Arange), 1); + + /* First use the buffer for the pointers, and sort the entries. + We'll write the pointers in the end of the buffer, and then + copy into the buffer from the beginning so the overlap works. */ + assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *)); + Dwarf_Arange **sortaranges = (buf + sizeof (Dwarf_Aranges) + + ((sizeof (Dwarf_Arange) + - sizeof (Dwarf_Arange *)) * narangelist)); + + /* The list is in LIFO order and usually they come in clumps with + ascending addresses. So fill from the back to probably start with + runs already in order before we sort. */ + unsigned int i = narangelist; + while (i-- > 0) + { + sortaranges[i] = &arangelist->arange; + arangelist = arangelist->next; + } + assert (arangelist == NULL); + + /* Sort by ascending address. */ + qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges); + + /* Now that they are sorted, put them in the final array. + The buffers overlap, so we've clobbered the early elements + of SORTARANGES by the time we're reading the later ones. */ + *aranges = buf; + (*aranges)->dbg = dbg; + (*aranges)->naranges = narangelist; + dbg->aranges = *aranges; + if (naranges != NULL) + *naranges = narangelist; + for (i = 0; i < narangelist; ++i) + (*aranges)->info[i] = *sortaranges[i]; + + return 0; +} +INTDEF(dwarf_getaranges) diff --git a/libdw/dwarf_getattrcnt.c b/libdw/dwarf_getattrcnt.c new file mode 100644 index 00000000..0758e030 --- /dev/null +++ b/libdw/dwarf_getattrcnt.c @@ -0,0 +1,33 @@ +/* Get number of attributes of abbreviation. + Copyright (C) 2003, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_getattrcnt (abbrev, attrcntp) + Dwarf_Abbrev *abbrev; + size_t *attrcntp; +{ + if (abbrev == NULL) + return -1; + + *attrcntp = abbrev->attrcnt; + + return 0; +} diff --git a/libdw/dwarf_getattrs.c b/libdw/dwarf_getattrs.c new file mode 100644 index 00000000..8e6326d7 --- /dev/null +++ b/libdw/dwarf_getattrs.c @@ -0,0 +1,94 @@ +/* Get attributes of the DIE. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +ptrdiff_t +dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *), + void *arg, ptrdiff_t offset) +{ + if (die == NULL) + return -1l; + + const unsigned char *die_addr = die->addr; + + /* Get the abbreviation code. */ + unsigned int u128; + get_uleb128 (u128, die_addr); + + if (die->abbrev == NULL) + /* Find the abbreviation. */ + die->abbrev = __libdw_findabbrev (die->cu, u128); + + if (die->abbrev == (Dwarf_Abbrev *) -1l) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1l; + } + + /* This is where the attributes start. */ + const unsigned char *attrp = die->abbrev->attrp + offset; + + /* Go over the list of attributes. */ + Dwarf *dbg = die->cu->dbg; + while (1) + { + /* Are we still in bounds? */ + if (unlikely (attrp + >= ((unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + + dbg->sectiondata[IDX_debug_abbrev]->d_size))) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + /* Get attribute name and form. */ + Dwarf_Attribute attr; + // XXX Fix bound checks + get_uleb128 (attr.code, attrp); + get_uleb128 (attr.form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr.code == 0 && attr.form == 0) + return 0; + + /* Fill in the rest. */ + attr.valp = (unsigned char *) die_addr; + attr.cu = die->cu; + + /* Now call the callback function. */ + if (callback (&attr, arg) != DWARF_CB_OK) + return attrp - die->abbrev->attrp; + + /* Skip over the rest of this attribute (if there is any). */ + if (attr.form != 0) + { + size_t len = __libdw_form_val_len (dbg, die->cu, attr.form, + die_addr); + + if (unlikely (len == (size_t) -1l)) + /* Something wrong with the file. */ + return -1l; + + // XXX We need better boundary checks. + die_addr += len; + } + } + /* NOTREACHED */ +} diff --git a/libdw/dwarf_getelf.c b/libdw/dwarf_getelf.c new file mode 100644 index 00000000..1e2a06aa --- /dev/null +++ b/libdw/dwarf_getelf.c @@ -0,0 +1,33 @@ +/* Retrieve ELF descriptor used for DWARF access. + Copyright (C) 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "libdwP.h" + + +Elf * +dwarf_get_elf (dwarf) + Dwarf *dwarf; +{ + if (dwarf == NULL) + /* Some error occurred before. */ + return NULL; + + return dwarf->elf; +} diff --git a/libdw/dwarf_getfuncs.c b/libdw/dwarf_getfuncs.c new file mode 100644 index 00000000..149f1860 --- /dev/null +++ b/libdw/dwarf_getfuncs.c @@ -0,0 +1,63 @@ +/* Get function information. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +ptrdiff_t +dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Func *, void *), + void *arg, ptrdiff_t offset) +{ + if (unlikely (cudie == NULL + || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit)) + return -1; + + Dwarf_Die die_mem; + Dwarf_Die *die; + + int res; + if (offset == 0) + res = INTUSE(dwarf_child) (cudie, &die_mem); + else + { + die = INTUSE(dwarf_offdie) (cudie->cu->dbg, offset, &die_mem); + res = INTUSE(dwarf_siblingof) (die, &die_mem); + } + die = res != 0 ? NULL : &die_mem; + + while (die != NULL) + { + if (INTUSE(dwarf_tag) (die) == DW_TAG_subprogram) + { + Dwarf_Func fct; + + fct.die = die; + fct.cudie = cudie; + + if (callback (&fct, arg) != DWARF_CB_OK) + return INTUSE(dwarf_dieoffset) (die); + } + + if (INTUSE(dwarf_siblingof) (die, &die_mem) != 0) + break; + } + + /* That's all. */ + return 0; +} diff --git a/libdw/dwarf_getloclist.c b/libdw/dwarf_getloclist.c new file mode 100644 index 00000000..ab7c3869 --- /dev/null +++ b/libdw/dwarf_getloclist.c @@ -0,0 +1,454 @@ +/* Return location expression list. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include + + +static bool +attr_ok (Dwarf_Attribute *attr) +{ + if (attr == NULL) + return false; + + /* Must be one of the attributes listed below. */ + switch (attr->code) + { + case DW_AT_location: + case DW_AT_data_member_location: + case DW_AT_vtable_elem_location: + case DW_AT_string_length: + case DW_AT_use_location: + case DW_AT_frame_base: + case DW_AT_return_addr: + case DW_AT_static_link: + break; + + default: + __libdw_seterrno (DWARF_E_NO_LOCLIST); + return false; + } + + return true; +} + + +struct loclist +{ + uint8_t atom; + Dwarf_Word number; + Dwarf_Word number2; + Dwarf_Word offset; + struct loclist *next; +}; + + +static int +loc_compare (const void *p1, const void *p2) +{ + const struct loc_s *l1 = (const struct loc_s *) p1; + const struct loc_s *l2 = (const struct loc_s *) p2; + + if ((uintptr_t) l1->addr < (uintptr_t) l2->addr) + return -1; + if ((uintptr_t) l1->addr > (uintptr_t) l2->addr) + return 1; + + return 0; +} + +static int +getloclist (struct Dwarf_CU *cu, const Dwarf_Block *block, + Dwarf_Loc **llbuf, size_t *listlen) +{ + Dwarf *dbg = cu->dbg; + + /* Check whether we already looked at this list. */ + struct loc_s fake = { .addr = block->data }; + struct loc_s **found = tfind (&fake, &cu->locs, loc_compare); + if (found != NULL) + { + /* We already saw it. */ + *llbuf = (*found)->loc; + *listlen = (*found)->nloc; + + return 0; + } + + const unsigned char *data = block->data; + const unsigned char *const end_data = data + block->length; + + struct loclist *loclist = NULL; + unsigned int n = 0; + /* Decode the opcodes. It is possible in some situations to have a + block of size zero. */ + while (data < end_data) + { + struct loclist *newloc; + newloc = (struct loclist *) alloca (sizeof (struct loclist)); + newloc->number = 0; + newloc->number2 = 0; + newloc->offset = data - block->data; + newloc->next = loclist; + loclist = newloc; + ++n; + + switch ((newloc->atom = *data++)) + { + case DW_OP_addr: + /* Address, depends on address size of CU. */ + if (cu->address_size == 4) + { + if (unlikely (data + 4 > end_data)) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + newloc->number = read_4ubyte_unaligned_inc (dbg, data); + } + else + { + if (unlikely (data + 8 > end_data)) + goto invalid; + + newloc->number = read_8ubyte_unaligned_inc (dbg, data); + } + break; + + case DW_OP_deref: + case DW_OP_dup: + case DW_OP_drop: + case DW_OP_over: + case DW_OP_swap: + case DW_OP_rot: + case DW_OP_xderef: + case DW_OP_abs: + case DW_OP_and: + case DW_OP_div: + case DW_OP_minus: + case DW_OP_mod: + case DW_OP_mul: + case DW_OP_neg: + case DW_OP_not: + case DW_OP_or: + case DW_OP_plus: + case DW_OP_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + case DW_OP_eq: + case DW_OP_ge: + case DW_OP_gt: + case DW_OP_le: + case DW_OP_lt: + case DW_OP_ne: + case DW_OP_lit0 ... DW_OP_lit31: + case DW_OP_reg0 ... DW_OP_reg31: + case DW_OP_nop: + case DW_OP_push_object_address: + case DW_OP_call_ref: + /* No operand. */ + break; + + case DW_OP_const1u: + case DW_OP_pick: + case DW_OP_deref_size: + case DW_OP_xderef_size: + if (unlikely (data >= end_data)) + goto invalid; + + newloc->number = *data++; + break; + + case DW_OP_const1s: + if (unlikely (data >= end_data)) + goto invalid; + + newloc->number = *((int8_t *) data); + ++data; + break; + + case DW_OP_const2u: + if (unlikely (data + 2 > end_data)) + goto invalid; + + newloc->number = read_2ubyte_unaligned_inc (dbg, data); + break; + + case DW_OP_const2s: + case DW_OP_skip: + case DW_OP_bra: + case DW_OP_call2: + if (unlikely (data + 2 > end_data)) + goto invalid; + + newloc->number = read_2sbyte_unaligned_inc (dbg, data); + break; + + case DW_OP_const4u: + if (unlikely (data + 4 > end_data)) + goto invalid; + + newloc->number = read_4ubyte_unaligned_inc (dbg, data); + break; + + case DW_OP_const4s: + case DW_OP_call4: + if (unlikely (data + 4 > end_data)) + goto invalid; + + newloc->number = read_4sbyte_unaligned_inc (dbg, data); + break; + + case DW_OP_const8u: + if (unlikely (data + 8 > end_data)) + goto invalid; + + newloc->number = read_8ubyte_unaligned_inc (dbg, data); + break; + + case DW_OP_const8s: + if (unlikely (data + 8 > end_data)) + goto invalid; + + newloc->number = read_8sbyte_unaligned_inc (dbg, data); + break; + + case DW_OP_constu: + case DW_OP_plus_uconst: + case DW_OP_regx: + case DW_OP_piece: + /* XXX Check size. */ + get_uleb128 (newloc->number, data); + break; + + case DW_OP_consts: + case DW_OP_breg0 ... DW_OP_breg31: + case DW_OP_fbreg: + /* XXX Check size. */ + get_sleb128 (newloc->number, data); + break; + + case DW_OP_bregx: + /* XXX Check size. */ + get_uleb128 (newloc->number, data); + get_sleb128 (newloc->number2, data); + break; + + default: + goto invalid; + } + } + + if (unlikely (n == 0)) + { + /* This is not allowed. + + XXX Is it? */ + goto invalid; + } + + /* Allocate the array. */ + Dwarf_Loc *result = libdw_alloc (dbg, Dwarf_Loc, sizeof (Dwarf_Loc), n); + + /* Store the result. */ + *llbuf = result; + *listlen = n; + + do + { + /* We populate the array from the back since the list is + backwards. */ + --n; + result[n].atom = loclist->atom; + result[n].number = loclist->number; + result[n].number2 = loclist->number2; + result[n].offset = loclist->offset; + + loclist = loclist->next; + } + while (n > 0); + + /* Insert a record in the search tree so that we can find it again + later. */ + struct loc_s *newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), + 1); + newp->addr = block->data; + newp->loc = result; + newp->nloc = *listlen; + (void) tsearch (newp, &cu->locs, loc_compare); + + /* We did it. */ + return 0; +} + +int +dwarf_getloclist (attr, llbuf, listlen) + Dwarf_Attribute *attr; + Dwarf_Loc **llbuf; + size_t *listlen; +{ + if (! attr_ok (attr)) + return -1; + + /* If it has a block form, it's a single location expression. */ + Dwarf_Block block; + if (INTUSE(dwarf_formblock) (attr, &block) != 0) + return -1; + + return getloclist (attr->cu, &block, llbuf, listlen); +} + +int +dwarf_addrloclists (attr, address, llbufs, listlens, maxlocs) + Dwarf_Attribute *attr; + Dwarf_Addr address; + Dwarf_Loc **llbufs; + size_t *listlens; + size_t maxlocs; +{ + if (! attr_ok (attr)) + return -1; + + if (llbufs == NULL) + maxlocs = SIZE_MAX; + + /* If it has a block form, it's a single location expression. */ + Dwarf_Block block; + if (INTUSE(dwarf_formblock) (attr, &block) == 0) + { + if (maxlocs == 0) + return 0; + if (llbufs != NULL && + getloclist (attr->cu, &block, &llbufs[0], &listlens[0]) != 0) + return -1; + return listlens[0] == 0 ? 0 : 1; + } + + int error = INTUSE(dwarf_errno) (); + if (error != DWARF_E_NO_BLOCK) + { + __libdw_seterrno (error); + return -1; + } + + /* Must have the form data4 or data8 which act as an offset. */ + Dwarf_Word offset; + if (INTUSE(dwarf_formudata) (attr, &offset) != 0) + return -1; + + const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc]; + if (d == NULL) + { + __libdw_seterrno (DWARF_E_NO_LOCLIST); + return -1; + } + + /* Fetch the CU's base address. */ + Dwarf_Addr base; + Dwarf_Die cudie = + { + .cu = attr->cu, + .addr = ((char *) attr->cu->dbg->sectiondata[IDX_debug_info]->d_buf + + attr->cu->start + 3 * attr->cu->offset_size - 4 + 3), + }; + + + /* Find the base address of the compilation unit. It will + normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, + the base address could be overridden by DW_AT_entry_pc. It's + been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc + for compilation units with discontinuous ranges. */ + Dwarf_Attribute attr_mem; + if (INTUSE(dwarf_lowpc) (&cudie, &base) != 0 + && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie, DW_AT_entry_pc, + &attr_mem), + &base) != 0) + return -1; + + unsigned char *readp = d->d_buf + offset; + size_t got = 0; + while (got < maxlocs) + { + if ((unsigned char *) d->d_buf + d->d_size - readp + < attr->cu->address_size * 2) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + Dwarf_Addr begin; + Dwarf_Addr end; + if (attr->cu->address_size == 8) + { + begin = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); + end = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); + + if (begin == (Elf64_Addr) -1l) /* Base address entry. */ + { + base = end; + continue; + } + } + else + { + begin = read_4ubyte_unaligned_inc (attr->cu->dbg, readp); + end = read_4ubyte_unaligned_inc (attr->cu->dbg, readp); + + if (begin == (Elf32_Addr) -1) /* Base address entry. */ + { + base = end; + continue; + } + } + + if (begin == 0 && end == 0) /* End of list entry. */ + break; + + if ((unsigned char *) d->d_buf + d->d_size - readp < 2) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + /* We have a location expression. */ + block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp); + block.data = readp; + if ((unsigned char *) d->d_buf + d->d_size - readp + < (ptrdiff_t) block.length) + goto invalid; + readp += block.length; + + if (address >= base + begin && address < base + end) + { + /* This one matches the address. */ + if (llbufs != NULL && getloclist (attr->cu, &block, + &llbufs[got], &listlens[got]) != 0) + return -1; + ++got; + } + } + + return got; +} diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c new file mode 100644 index 00000000..d3678c99 --- /dev/null +++ b/libdw/dwarf_getmacros.c @@ -0,0 +1,119 @@ +/* Get macro information. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +ptrdiff_t +dwarf_getmacros (die, callback, arg, offset) + Dwarf_Die *die; + int (*callback) (Dwarf_Macro *, void *); + void *arg; + ptrdiff_t offset; +{ + /* Get the appropriate attribute. */ + Dwarf_Attribute attr; + if (INTUSE(dwarf_attr) (die, DW_AT_macro_info, &attr) == NULL) + return -1; + + /* Offset into the .debug_macinfo section. */ + Dwarf_Word macoff; + if (INTUSE(dwarf_formudata) (&attr, &macoff) != 0) + return -1; + + const unsigned char *readp + = die->cu->dbg->sectiondata[IDX_debug_macinfo]->d_buf + offset; + const unsigned char *readendp + = readp + die->cu->dbg->sectiondata[IDX_debug_macinfo]->d_size; + + if (readp == readendp) + return 0; + + if (*readp != DW_MACINFO_start_file) + goto invalid; + + while (readp < readendp) + { + unsigned int opcode = *readp++; + unsigned int u128; + unsigned int u128_2 = 0; + const char *str = NULL; + const unsigned char *endp; + + switch (opcode) + { + case DW_MACINFO_define: + case DW_MACINFO_undef: + case DW_MACINFO_vendor_ext: + /* For the first two opcodes the parameters are + line, string + For the latter + number, string. + We can treat these cases together. */ + get_uleb128 (u128, readp); + + endp = memchr (readp, '\0', readendp - readp); + if (endp == NULL) + goto invalid; + + str = (char *) readp; + readp = endp + 1; + break; + + case DW_MACINFO_start_file: + /* The two parameters are line and file index. */ + get_uleb128 (u128, readp); + get_uleb128 (u128_2, readp); + break; + + case DW_MACINFO_end_file: + /* No parameters for this one. */ + u128 = 0; + break; + + case 0: + /* Nothing more to do. */ + return 0; + + default: + goto invalid; + } + + Dwarf_Macro mac; + mac.opcode = opcode; + mac.param1 = u128; + if (str == NULL) + mac.param2.u = u128_2; + else + mac.param2.s = str; + + if (callback (&mac, arg) != DWARF_CB_OK) + return (readp + - ((unsigned char *) die->cu->dbg->sectiondata[IDX_debug_macinfo]->d_buf + + offset)); + } + + /* If we come here the termination of the data for the CU is not + present. */ + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; +} diff --git a/libdw/dwarf_getpubnames.c b/libdw/dwarf_getpubnames.c new file mode 100644 index 00000000..5700cd77 --- /dev/null +++ b/libdw/dwarf_getpubnames.c @@ -0,0 +1,213 @@ +/* Get public symbol information. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + + +static int +get_offsets (Dwarf *dbg) +{ + size_t allocated = 0; + size_t cnt = 0; + struct pubnames_s *mem = NULL; + const size_t entsize = sizeof (struct pubnames_s); + unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf; + unsigned char *readp = startp; + unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size; + + while (readp + 14 < endp) + { + /* If necessary, allocate more entries. */ + if (cnt >= allocated) + { + allocated = MAX (10, 2 * allocated); + struct pubnames_s *newmem + = (struct pubnames_s *) realloc (mem, allocated * entsize); + if (newmem == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + err_return: + free (mem); + return -1; + } + + mem = newmem; + } + + /* Read the set header. */ + int len_bytes = 4; + Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp); + if (len == 0xffffffff) + { + len = read_8ubyte_unaligned_inc (dbg, readp); + len_bytes = 8; + } + + /* Now we know the offset of the first offset/name pair. */ + mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp; + mem[cnt].address_len = len_bytes; + if (mem[cnt].set_start >= dbg->sectiondata[IDX_debug_pubnames]->d_size) + /* Something wrong, the first entry is beyond the end of + the section. */ + break; + + /* Read the version. It better be two for now. */ + uint16_t version = read_2ubyte_unaligned (dbg, readp); + if (version != 2) + { + __libdw_seterrno (DWARF_E_INVALID_VERSION); + goto err_return; + } + + /* Get the CU offset. */ + if (len_bytes == 4) + mem[cnt].cu_offset = read_4ubyte_unaligned (dbg, readp + 2); + else + mem[cnt].cu_offset = read_8ubyte_unaligned (dbg, readp + 2); + + /* Determine the size of the CU header. */ + assert (dbg->sectiondata[IDX_debug_info] != NULL); + assert (dbg->sectiondata[IDX_debug_info]->d_buf != NULL); + assert (mem[cnt].cu_offset + 3 + < dbg->sectiondata[IDX_debug_info]->d_size); + unsigned char *infop + = ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf + + mem[cnt].cu_offset); + if (read_4ubyte_unaligned_noncvt (infop) == 0xffffffff) + mem[cnt].cu_header_size = 23; + else + mem[cnt].cu_header_size = 11; + + ++cnt; + + /* Advance to the next set. */ + readp += len; + } + + if (mem == NULL) + { + __libdw_seterrno (DWARF_E_NO_ENTRY); + return -1; + } + + dbg->pubnames_sets = (struct pubnames_s *) realloc (mem, cnt * entsize); + dbg->pubnames_nsets = cnt; + + return 0; +} + + +ptrdiff_t +dwarf_getpubnames (dbg, callback, arg, offset) + Dwarf *dbg; + int (*callback) (Dwarf *, Dwarf_Global *, void *); + void *arg; + ptrdiff_t offset; +{ + if (dbg == NULL) + return -1l; + + if (offset < 0) + { + __libdw_seterrno (DWARF_E_INVALID_OFFSET); + return -1l; + } + + /* Make sure it is a valid offset. */ + if (unlikely (dbg->sectiondata[IDX_debug_pubnames] == NULL + || ((size_t) offset + >= dbg->sectiondata[IDX_debug_pubnames]->d_size))) + /* No (more) entry. */ + return 0; + + /* If necessary read the set information. */ + if (dbg->pubnames_nsets == 0 && get_offsets (dbg) != 0) + return -1l; + + /* Find the place where to start. */ + size_t cnt; + if (offset == 0) + { + cnt = 0; + offset = dbg->pubnames_sets[0].set_start; + } + else + { + for (cnt = 0; cnt + 1 < dbg->pubnames_nsets; ++cnt) + if ((Dwarf_Off) offset >= dbg->pubnames_sets[cnt].set_start) + { + assert ((Dwarf_Off) offset + < dbg->pubnames_sets[cnt + 1].set_start); + break; + } + assert (cnt + 1 < dbg->pubnames_nsets); + } + + unsigned char *startp + = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; + unsigned char *readp = startp + offset; + while (1) + { + Dwarf_Global gl; + + gl.cu_offset = (dbg->pubnames_sets[cnt].cu_offset + + dbg->pubnames_sets[cnt].cu_header_size); + + while (1) + { + /* READP points to the next offset/name pair. */ + if (dbg->pubnames_sets[cnt].address_len == 4) + gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp); + else + gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp); + + /* If the offset is zero we reached the end of the set. */ + if (gl.die_offset == 0) + break; + + /* Add the CU offset. */ + gl.die_offset += dbg->pubnames_sets[cnt].cu_offset; + + gl.name = (char *) readp; + readp = (unsigned char *) rawmemchr (gl.name, '\0') + 1; + + /* We found name and DIE offset. Report it. */ + if (callback (dbg, &gl, arg) != DWARF_CB_OK) + { + /* The user wants us to stop. Return the offset of the + next entry. */ + return readp - startp; + } + } + + if (++cnt == dbg->pubnames_nsets) + /* This was the last set. */ + break; + + startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; + readp = startp + dbg->pubnames_sets[cnt].set_start; + } + + /* We are done. No more entries. */ + return 0; +} diff --git a/libdw/dwarf_getscopes.c b/libdw/dwarf_getscopes.c new file mode 100644 index 00000000..21d6f20a --- /dev/null +++ b/libdw/dwarf_getscopes.c @@ -0,0 +1,334 @@ +/* Return scope DIEs containing PC address. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" +#include + + +enum die_class { ignore, match, match_inline, walk, imported }; + +static enum die_class +classify_die (Dwarf_Die *die) +{ + switch (INTUSE(dwarf_tag) (die)) + { + /* DIEs with addresses we can try to match. */ + case DW_TAG_compile_unit: + case DW_TAG_module: + case DW_TAG_lexical_block: + case DW_TAG_with_stmt: + case DW_TAG_catch_block: + case DW_TAG_try_block: + case DW_TAG_entry_point: + return match; + case DW_TAG_inlined_subroutine: + return match_inline; + case DW_TAG_subprogram: + /* This might be a concrete out-of-line instance of an inline, in + which case it is not guaranteed to be owned by the right scope and + we will search for its origin as for DW_TAG_inlined_subroutine. */ + return (INTUSE(dwarf_hasattr) (die, DW_AT_abstract_origin) + ? match_inline : match); + + /* DIEs without addresses that can own DIEs with addresses. */ + case DW_TAG_namespace: + return walk; + + /* Special indirection required. */ + case DW_TAG_imported_unit: + return imported; + + /* Other DIEs we have no reason to descend. */ + default: + break; + } + return ignore; +} + +/* DIE contains PC. Find its child that contains PC. Returns -1 for + errors, 0 for no matches. On success, *SCOPES gets the malloc'd array + of containing scopes. A positive return value is the number of those + scopes. A return value < -1 is -1 - number of those scopes, when the + outermost scope is a concrete instance of an inline subroutine. */ +static int +find_pc (unsigned int depth, Dwarf_Die *die, Dwarf_Addr pc, Dwarf_Die **scopes) +{ + Dwarf_Die child; + if (INTUSE(dwarf_child) (die, &child) != 0) + return -1; + + /* Recurse on this DIE to search within its children. + Return nonzero if this gets an error or a final result. */ + inline int search_child (void) + { + int n = find_pc (depth + 1, &child, pc, scopes); + if (n > 0) + /* That stored the N innermost scopes. Now store ours. */ + (*scopes)[n++] = child; + return n; + } + + /* Check each of our child DIEs. */ + enum die_class got = ignore; + do + { + enum die_class child_class = classify_die (&child); + switch (child_class) + { + case match: + case match_inline: + if (INTUSE(dwarf_haspc) (&child, pc) > 0) + break; + continue; + + case walk: + if (INTUSE(dwarf_haschildren) (&child)) + got = walk; + continue; + + case imported: + got = walk; + continue; + + default: + case ignore: + continue; + } + + /* We get here only when the PC has matched. */ + got = child_class; + break; + } + while (INTUSE(dwarf_siblingof) (&child, &child) == 0); + + switch (got) + { + case match: + case match_inline: + /* We have a DIE that matched the PC. */ + if (INTUSE(dwarf_haschildren) (&child)) + { + /* Recurse on this DIE to narrow within its children. + Return now if this gets an error or a final result. */ + int result = search_child (); + if (result < 0 || (got == match && result > 0)) + return result; + if (result > 0) /* got == match_inline */ + /* We have a winner, but CHILD is a concrete inline instance + so DIE and its containing scopes do not actually apply. + DIE is the scope that inlined the function. Our root + caller must find the abstract scope that defines us. */ + return -1 - result; + } + + /* This DIE has no children containing the PC, so this is it. */ + *scopes = malloc (depth * sizeof (*scopes)[0]); + if (*scopes == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + (*scopes)[0] = child; + return got == match ? 1 : -2; + + case walk: + /* We don't have anything matching the PC, but we have some things + we might descend to find one. Recurse on each of those. */ + if (INTUSE(dwarf_child) (die, &child) != 0) + return -1; + do + switch (classify_die (&child)) + { + case walk: + if (INTUSE(dwarf_haschildren) (&child)) + { + /* Recurse on this DIE to look for the PC within its children. + Return now if this gets an error or a final result. */ + int result = search_child (); + if (result != 0) + return result; + } + break; + + case imported: + { + /* This imports another compilation unit to appear + as part of this one, inside the current scope. + Recurse to search the referenced unit, but without + recording it as an inner scoping level. */ + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child, DW_AT_import, + &attr_mem); + if (INTUSE(dwarf_formref_die) (attr, &child) != NULL) + { + int result = find_pc (depth, &child, pc, scopes); + if (result != 0) + return result; + } + } + break; + + default: + break; + } + while (INTUSE(dwarf_siblingof) (&child, &child) == 0); + break; + + default: + case ignore: + /* Nothing to see here. */ + break; + } + + /* No matches. */ + return 0; +} + + +/* OWNER owns OWNED. Find intermediate scopes. *SCOPES was allocated by + find_pc and has SKIP elements. We realloc it, append more containing + scopes, and return 1 + the number appended. Returns -1 on errors, + or 0 when OWNED was not found within OWNER. */ +static int +find_die (unsigned int depth, Dwarf_Die *owner, Dwarf_Die *owned, + Dwarf_Die **scopes, unsigned int skip) +{ + Dwarf_Die child; + if (INTUSE(dwarf_child) (owner, &child) != 0) + return -1; + + do + { + if (child.addr == owned->addr) + /* This is the one. OWNER is the innermost owner. */ + return 1; + + /* Unfortunately we cannot short-circuit the dead-end paths just by + checking the physical layout to see if OWNED falls within CHILD. + If it doesn't, there may still be a DW_TAG_imported_unit that + refers to its true owner indirectly. */ + + switch (classify_die (&child)) + { + case match: + case match_inline: + case walk: + if (INTUSE(dwarf_haschildren) (&child)) + { + /* Recurse on this DIE to look for OWNED within its children. + Return now if this gets an error or a final result. */ + int n = find_die (depth + 1, &child, owned, scopes, skip); + if (n < 0) + return n; + if (n > 1) + { + /* We have a winner. CHILD owns the owner of OWNED. */ + (*scopes)[skip + n - 1] = child; + return n + 1; + } + if (n > 0) /* n == 1 */ + { + /* CHILD is the direct owner of OWNED. */ + Dwarf_Die *nscopes = realloc (*scopes, + (skip + depth) + * sizeof nscopes[0]); + if (nscopes == NULL) + { + free (*scopes); + *scopes = NULL; + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + nscopes[skip] = child; + *scopes = nscopes; + return 2; + } + } + break; + + case imported: + { + /* This is imports another compilation unit to appear + as part of this one, inside the current scope. + Recurse to search the referenced unit, but without + recording it as an inner scoping level. */ + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child, DW_AT_import, + &attr_mem); + if (INTUSE(dwarf_formref_die) (attr, &child) != NULL) + { + int result = find_die (depth, &child, owner, scopes, skip); + if (result != 0) + return result; + } + } + break; + + default: + break; + } + } + while (INTUSE(dwarf_siblingof) (&child, &child) == 0); + + return 0; +} + + +int +dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes) +{ + if (cudie == NULL) + return -1; + + int n = find_pc (1, cudie, pc, scopes); + if (likely (n >= -1)) + /* We have an error or a final result. */ + return n; + + /* We have the scopes out to one that is a concrete instance of an + inlined subroutine (usually DW_TAG_inlined_subroutine, but can + be DW_TAG_subprogram for a concrete out-of-line instance). + Now we must find the lexical scopes that contain the + corresponding abstract inline subroutine definition. */ + + n = -n - 1; + + Dwarf_Attribute attr_mem; + Dwarf_Die die_mem; + Dwarf_Die *origin = INTUSE(dwarf_formref_die) + (INTUSE(dwarf_attr) (&(*scopes)[n - 1], DW_AT_abstract_origin, &attr_mem), + &die_mem); + if (unlikely (origin == NULL)) + goto invalid; + + int result = find_die (0, cudie, origin, scopes, n); + if (likely (result > 0)) + return n + result - 1; + + if (result == 0) /* No match, shouldn't happen. */ + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + } + + free (*scopes); + *scopes = NULL; + return -1; +} diff --git a/libdw/dwarf_getscopevar.c b/libdw/dwarf_getscopevar.c new file mode 100644 index 00000000..3ceb292d --- /dev/null +++ b/libdw/dwarf_getscopevar.c @@ -0,0 +1,147 @@ +/* Find a named variable or parameter within given scopes. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "libdwP.h" +#include + + +/* Find the containing CU's files. */ +static int +getfiles (Dwarf_Die *die, Dwarf_Files **files) +{ + Dwarf_Die cudie = + { + .cu = die->cu, + .addr = ((char *) die->cu->dbg->sectiondata[IDX_debug_info]->d_buf + + 3 * die->cu->offset_size - 4 + 3), + }; + return INTUSE(dwarf_getsrcfiles) (&cudie, files, NULL); +} + +/* Fetch an attribute that should have a constant integer form. */ +static int +getattr (Dwarf_Die *die, int search_name, Dwarf_Word *value) +{ + Dwarf_Attribute attr_mem; + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, search_name, + &attr_mem), value); +} + +/* Search SCOPES[0..NSCOPES-1] for a variable called NAME. + Ignore the first SKIP_SHADOWS scopes that match the name. + If MATCH_FILE is not null, accept only declaration in that source file; + if MATCH_LINENO or MATCH_LINECOL are also nonzero, accept only declaration + at that line and column. + + If successful, fill in *RESULT with the DIE of the variable found, + and return N where SCOPES[N] is the scope defining the variable. + Return -1 for errors or -2 for no matching variable found. */ + +int +dwarf_getscopevar (Dwarf_Die *scopes, int nscopes, + const char *name, int skip_shadows, + const char *match_file, int match_lineno, int match_linecol, + Dwarf_Die *result) +{ + /* Match against the given file name. */ + size_t match_file_len = match_file == NULL ? 0 : strlen (match_file); + bool lastfile_matches = false; + const char *lastfile = NULL; + inline bool file_matches (Dwarf_Files *files, size_t idx) + { + if (idx >= files->nfiles) + return false; + + const char *file = files->info[idx].name; + if (file != lastfile) + { + size_t len = strlen (file); + lastfile_matches = (len >= match_file_len + && !memcmp (match_file, file, match_file_len) + && (len == match_file_len + || file[len - match_file_len - 1] == '/')); + } + return lastfile_matches; + } + + /* Start with the innermost scope and move out. */ + for (int out = 0; out < nscopes; ++out) + if (INTUSE(dwarf_haschildren) (&scopes[out])) + { + if (INTUSE(dwarf_child) (&scopes[out], result) != 0) + return -1; + do + { + switch (INTUSE(dwarf_tag) (result)) + { + case DW_TAG_variable: + case DW_TAG_formal_parameter: + break; + + default: + continue; + } + + /* Only get here for a variable or parameter. Check the name. */ + Dwarf_Attribute attr_mem; + const char *diename = INTUSE(dwarf_formstring) + (INTUSE(dwarf_attr_integrate) (result, DW_AT_name, &attr_mem)); + if (diename != NULL && !strcmp (name, diename)) + { + /* We have a matching name. */ + + if (skip_shadows > 0) + { + /* Punt this scope for the one it shadows. */ + --skip_shadows; + break; + } + + if (match_file != NULL) + { + /* Check its decl_file. */ + + Dwarf_Word i; + Dwarf_Files *files; + if (getattr (result, DW_AT_decl_file, &i) != 0 + || getfiles (&scopes[out], &files) != 0) + break; + + if (!file_matches (files, i)) + break; + + if (match_lineno > 0 + && (getattr (result, DW_AT_decl_line, &i) != 0 + || (int) i != match_lineno)) + break; + if (match_linecol > 0 + && (getattr (result, DW_AT_decl_column, &i) != 0 + || (int) i != match_linecol)) + break; + } + + /* We have a winner! */ + return out; + } + } + while (INTUSE(dwarf_siblingof) (result, result) == 0); + } + + return -2; +} diff --git a/libdw/dwarf_getsrc_die.c b/libdw/dwarf_getsrc_die.c new file mode 100644 index 00000000..e3ce4f2a --- /dev/null +++ b/libdw/dwarf_getsrc_die.c @@ -0,0 +1,58 @@ +/* Find line information for address. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" +#include + + +Dwarf_Line * +dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr) +{ + Dwarf_Lines *lines; + size_t nlines; + + if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0) + return NULL; + + /* The lines are sorted by address, so we can use binary search. */ + size_t l = 0, u = nlines; + while (l < u) + { + size_t idx = (l + u) / 2; + if (addr < lines->info[idx].addr) + u = idx; + else if (addr > lines->info[idx].addr) + l = idx + 1; + else + return &lines->info[idx]; + } + + if (nlines > 0) + assert (lines->info[nlines - 1].end_sequence); + + /* If none were equal, the closest one below is what we want. We + never want the last one, because it's the end-sequence marker + with an address at the high bound of the CU's code. If the debug + information is faulty and no end-sequence marker is present, we + still ignore it. */ + if (u > 0 && u < nlines && addr > lines->info[u - 1].addr) + return &lines->info[u - 1]; + + __libdw_seterrno (DWARF_E_ADDR_OUTOFRANGE); + return NULL; +} diff --git a/libdw/dwarf_getsrc_file.c b/libdw/dwarf_getsrc_file.c new file mode 100644 index 00000000..a10581d4 --- /dev/null +++ b/libdw/dwarf_getsrc_file.c @@ -0,0 +1,158 @@ +/* Find line information for given file/line/column triple. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "libdwP.h" + + +int +dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column, + Dwarf_Line ***srcsp, size_t *nsrcs) +{ + if (dbg == NULL) + return -1; + + bool is_basename = strchr (fname, '/') == NULL; + + size_t max_match = *nsrcs ?: ~0u; + size_t act_match = *nsrcs; + size_t cur_match = 0; + Dwarf_Line **match = *nsrcs == 0 ? NULL : *srcsp; + + Dwarf_Off off = 0; + size_t cuhl; + Dwarf_Off noff; + + while (INTUSE(dwarf_nextcu) (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0) + { + Dwarf_Die cudie_mem; + Dwarf_Die *cudie = INTUSE(dwarf_offdie) (dbg, off + cuhl, &cudie_mem); + if (cudie == NULL) + continue; + + /* Get the line number information for this file. */ + Dwarf_Lines *lines; + size_t nlines; + if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0) + return -1; + + /* Search through all the line number records for a matching + file and line/column number. If any of the numbers is zero, + no match is performed. */ + unsigned int lastfile = UINT_MAX; + bool lastmatch = false; + for (size_t cnt = 0; cnt < nlines; ++cnt) + { + Dwarf_Line *line = &lines->info[cnt]; + + if (lastfile != line->file) + { + lastfile = line->file; + if (lastfile >= line->files->nfiles) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + /* Match the name with the name the user provided. */ + const char *fname2 = line->files->info[lastfile].name; + if (is_basename) + lastmatch = strcmp (basename (fname2), fname) == 0; + else + lastmatch = strcmp (fname2, fname) == 0; + } + if (!lastmatch) + continue; + + /* See whether line and possibly column match. */ + if (lineno != 0 + && (lineno > line->line + || (column != 0 && column > line->column))) + /* Cannot match. */ + continue; + + /* Determine whether this is the best match so far. */ + size_t inner; + for (inner = 0; inner < cur_match; ++inner) + if (match[inner]->files == line->files + && match[inner]->file == line->file) + break; + if (inner < cur_match + && (match[inner]->line != line->line + || match[inner]->line != lineno + || (column != 0 + && (match[inner]->column != line->column + || match[inner]->column != column)))) + { + /* We know about this file already. If this is a better + match for the line number, use it. */ + if (match[inner]->line >= line->line + && (match[inner]->line != line->line + || match[inner]->column >= line->column)) + /* Use the new line. Otherwise the old one. */ + match[inner] = line; + continue; + } + + if (cur_match < max_match) + { + if (cur_match == act_match) + { + /* Enlarge the array for the results. */ + act_match += 10; + Dwarf_Line **newp = realloc (match, + act_match + * sizeof (Dwarf_Line *)); + if (newp == NULL) + { + free (match); + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + match = newp; + } + + match[cur_match++] = line; + } + } + + /* If we managed to find as many matches as the user requested + already, there is no need to go on to the next CU. */ + if (cur_match == max_match) + break; + + off = noff; + } + + if (cur_match > 0) + { + assert (*nsrcs == 0 || *srcsp == match); + + *nsrcs = cur_match; + *srcsp = match; + + return 0; + } + + __libdw_seterrno (DWARF_E_NO_MATCH); + return -1; +} diff --git a/libdw/dwarf_getsrcfiles.c b/libdw/dwarf_getsrcfiles.c new file mode 100644 index 00000000..6472bf44 --- /dev/null +++ b/libdw/dwarf_getsrcfiles.c @@ -0,0 +1,60 @@ +/* Return source file information of CU. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "libdwP.h" + + +int +dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, size_t *nfiles) +{ + if (unlikely (cudie == NULL + || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit)) + return -1; + + int res = -1; + + /* Get the information if it is not already known. */ + struct Dwarf_CU *const cu = cudie->cu; + if (cu->lines == NULL) + { + Dwarf_Lines *lines; + size_t nlines; + + /* Let the more generic function do the work. It'll create more + data but that will be needed in an real program anyway. */ + res = INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines); + } + else if (cu->files != (void *) -1l) + /* We already have the information. */ + res = 0; + + if (likely (res == 0)) + { + assert (cu->files != NULL && cu->files != (void *) -1l); + *files = cu->files; + if (nfiles != NULL) + *nfiles = cu->files->nfiles; + } + + // XXX Eventually: unlocking here. + + return res; +} +INTDEF (dwarf_getsrcfiles) diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c new file mode 100644 index 00000000..37e14aee --- /dev/null +++ b/libdw/dwarf_getsrclines.c @@ -0,0 +1,652 @@ +/* Return line number information of CU. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include "dwarf.h" +#include "libdwP.h" + + +struct filelist +{ + Dwarf_Fileinfo info; + struct filelist *next; +}; + +struct linelist +{ + Dwarf_Line line; + struct linelist *next; +}; + + +/* Compare by Dwarf_Line.addr, given pointers into an array of pointers. */ +static int +compare_lines (const void *a, const void *b) +{ + Dwarf_Line *const *p1 = a; + Dwarf_Line *const *p2 = b; + + return (*p1)->addr - (*p2)->addr; +} + + +/* Adds a new line to the matrix. We cannot define a function because + we want to use alloca. */ +#define NEW_LINE(end_seq) \ + do { \ + /* Add the new line. */ \ + new_line = (struct linelist *) alloca (sizeof (struct linelist)); \ + \ + /* Set the line information. */ \ + new_line->line.addr = address; \ + new_line->line.file = file; \ + new_line->line.line = line; \ + new_line->line.column = column; \ + new_line->line.is_stmt = is_stmt; \ + new_line->line.basic_block = basic_block; \ + new_line->line.end_sequence = end_seq; \ + new_line->line.prologue_end = prologue_end; \ + new_line->line.epilogue_begin = epilogue_begin; \ + \ + new_line->next = linelist; \ + linelist = new_line; \ + ++nlinelist; \ + } while (0) + + +int +dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines) +{ + if (unlikely (cudie == NULL + || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit)) + return -1; + + int res = -1; + + /* Get the information if it is not already known. */ + struct Dwarf_CU *const cu = cudie->cu; + if (cu->lines == NULL) + { + /* Failsafe mode: no data found. */ + cu->lines = (void *) -1l; + cu->files = (void *) -1l; + + /* The die must have a statement list associated. */ + Dwarf_Attribute stmt_list_mem; + Dwarf_Attribute *stmt_list = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, + &stmt_list_mem); + + /* Get the offset into the .debug_line section. NB: this call + also checks whether the previous dwarf_attr call failed. */ + Dwarf_Word offset; + if (INTUSE(dwarf_formudata) (stmt_list, &offset) != 0) + goto out; + + Dwarf *dbg = cu->dbg; + if (dbg->sectiondata[IDX_debug_line] == NULL) + { + __libdw_seterrno (DWARF_E_NO_DEBUG_LINE); + goto out; + } + const uint8_t *linep = dbg->sectiondata[IDX_debug_line]->d_buf + offset; + const uint8_t *lineendp = (dbg->sectiondata[IDX_debug_line]->d_buf + + dbg->sectiondata[IDX_debug_line]->d_size); + + /* Get the compilation directory. */ + Dwarf_Attribute compdir_attr_mem; + Dwarf_Attribute *compdir_attr = INTUSE(dwarf_attr) (cudie, + DW_AT_comp_dir, + &compdir_attr_mem); + const char *comp_dir = INTUSE(dwarf_formstring) (compdir_attr); + + if (unlikely (linep + 4 > lineendp)) + { + invalid_data: + __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE); + goto out; + } + Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); + unsigned int length = 4; + if (unlikely (unit_length == 0xffffffff)) + { + if (unlikely (linep + 8 > lineendp)) + goto invalid_data; + unit_length = read_8ubyte_unaligned_inc (dbg, linep); + length = 8; + } + + /* Check whether we have enough room in the section. */ + if (unit_length < 2 + length + 5 * 1 + || unlikely (linep + unit_length > lineendp)) + goto invalid_data; + lineendp = linep + unit_length; + + /* The next element of the header is the version identifier. */ + uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep); + if (unlikely (version != DWARF_VERSION)) + { + __libdw_seterrno (DWARF_E_VERSION); + goto out; + } + + /* Next comes the header length. */ + Dwarf_Word header_length; + if (length == 4) + header_length = read_4ubyte_unaligned_inc (dbg, linep); + else + header_length = read_8ubyte_unaligned_inc (dbg, linep); + const unsigned char *header_start = linep; + + /* Next the minimum instruction length. */ + uint_fast8_t minimum_instr_len = *linep++; + + /* Then the flag determining the default value of the is_stmt + register. */ + uint_fast8_t default_is_stmt = *linep++; + + /* Now the line base. */ + int_fast8_t line_base = *((int_fast8_t *) linep); + ++linep; + + /* And the line range. */ + uint_fast8_t line_range = *linep++; + + /* The opcode base. */ + uint_fast8_t opcode_base = *linep++; + + /* Remember array with the standard opcode length (-1 to account for + the opcode with value zero not being mentioned). */ + const uint8_t *standard_opcode_lengths = linep - 1; + linep += opcode_base - 1; + if (unlikely (linep >= lineendp)) + goto invalid_data; + + /* First comes the list of directories. Add the compilation + directory first since the index zero is used for it. */ + struct dirlist + { + const char *dir; + size_t len; + struct dirlist *next; + } comp_dir_elem = + { + .dir = comp_dir, + .len = comp_dir ? strlen (comp_dir) : 0, + .next = NULL + }; + struct dirlist *dirlist = &comp_dir_elem; + unsigned int ndirlist = 1; + + // XXX Directly construct array to conserve memory? + while (*linep != 0) + { + struct dirlist *new_dir = + (struct dirlist *) alloca (sizeof (*new_dir)); + + new_dir->dir = (char *) linep; + uint8_t *endp = memchr (linep, '\0', lineendp - linep); + if (endp == NULL) + goto invalid_data; + new_dir->len = endp - linep; + new_dir->next = dirlist; + dirlist = new_dir; + ++ndirlist; + linep = endp + 1; + } + /* Skip the final NUL byte. */ + ++linep; + + /* Rearrange the list in array form. */ + struct dirlist **dirarray + = (struct dirlist **) alloca (ndirlist * sizeof (*dirarray)); + while (ndirlist-- > 0) + { + dirarray[ndirlist] = dirlist; + dirlist = dirlist->next; + } + + /* Now read the files. */ + struct filelist null_file = + { + .info = + { + .name = "???", + .mtime = 0, + .length = 0 + }, + .next = NULL + }; + struct filelist *filelist = &null_file; + unsigned int nfilelist = 1; + + if (unlikely (linep >= lineendp)) + goto invalid_data; + while (*linep != 0) + { + struct filelist *new_file = + (struct filelist *) alloca (sizeof (*new_file)); + + /* First comes the file name. */ + char *fname = (char *) linep; + uint8_t *endp = memchr (fname, '\0', lineendp - linep); + if (endp == NULL) + goto invalid_data; + size_t fnamelen = endp - (uint8_t *) fname; + linep = endp + 1; + + /* Then the index. */ + Dwarf_Word diridx; + get_uleb128 (diridx, linep); + if (unlikely (diridx >= ndirlist)) + { + __libdw_seterrno (DWARF_E_INVALID_DIR_IDX); + goto out; + } + + if (*fname == '/') + /* It's an absolute path. */ + new_file->info.name = fname; + else + { + new_file->info.name = libdw_alloc (dbg, char, 1, + dirarray[diridx]->len + 1 + + fnamelen + 1); + char *cp = new_file->info.name; + + if (dirarray[diridx]->dir != NULL) + { + /* This value could be NULL in case the DW_AT_comp_dir + was not present. We cannot do much in this case. + The easiest thing is to convert the path in an + absolute path. */ + cp = stpcpy (cp, dirarray[diridx]->dir); + } + *cp++ = '/'; + strcpy (cp, fname); + assert (strlen (new_file->info.name) + < dirarray[diridx]->len + 1 + fnamelen + 1); + } + + /* Next comes the modification time. */ + get_uleb128 (new_file->info.mtime, linep); + + /* Finally the length of the file. */ + get_uleb128 (new_file->info.length, linep); + + new_file->next = filelist; + filelist = new_file; + ++nfilelist; + } + /* Skip the final NUL byte. */ + ++linep; + + /* Consistency check. */ + if (unlikely (linep != header_start + header_length)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + goto out; + } + + /* We are about to process the statement program. Initialize the + state machine registers (see 6.2.2 in the v2.1 specification). */ + Dwarf_Word address = 0; + size_t file = 1; + size_t line = 1; + size_t column = 0; + uint_fast8_t is_stmt = default_is_stmt; + int basic_block = 0; + int prologue_end = 0; + int epilogue_begin = 0; + + /* Process the instructions. */ + struct linelist *linelist = NULL; + unsigned int nlinelist = 0; + while (linep < lineendp) + { + struct linelist *new_line; + unsigned int opcode; + unsigned int u128; + int s128; + + /* Read the opcode. */ + opcode = *linep++; + + /* Is this a special opcode? */ + if (likely (opcode >= opcode_base)) + { + /* Yes. Handling this is quite easy since the opcode value + is computed with + + opcode = (desired line increment - line_base) + + (line_range * address advance) + opcode_base + */ + int line_increment = (line_base + + (opcode - opcode_base) % line_range); + unsigned int address_increment = (minimum_instr_len + * ((opcode - opcode_base) + / line_range)); + + /* Perform the increments. */ + line += line_increment; + address += address_increment; + + /* Add a new line with the current state machine values. */ + NEW_LINE (0); + + /* Reset the flags. */ + basic_block = 0; + prologue_end = 0; + epilogue_begin = 0; + } + else if (opcode == 0) + { + /* This an extended opcode. */ + if (unlikely (linep + 2 > lineendp)) + goto invalid_data; + + /* The length. */ + unsigned int len = *linep++; + + if (unlikely (linep + len > lineendp)) + goto invalid_data; + + /* The sub-opcode. */ + opcode = *linep++; + + switch (opcode) + { + case DW_LNE_end_sequence: + /* Add a new line with the current state machine values. + The is the end of the sequence. */ + NEW_LINE (1); + + /* Reset the registers. */ + address = 0; + file = 1; + line = 1; + column = 0; + is_stmt = default_is_stmt; + basic_block = 0; + prologue_end = 0; + epilogue_begin = 0; + break; + + case DW_LNE_set_address: + /* The value is an address. The size is defined as + apporiate for the target machine. We use the + address size field from the CU header. */ + if (cu->address_size == 4) + address = read_4ubyte_unaligned_inc (dbg, linep); + else + address = read_8ubyte_unaligned_inc (dbg, linep); + break; + + case DW_LNE_define_file: + { + char *fname = (char *) linep; + uint8_t *endp = memchr (linep, '\0', lineendp - linep); + if (endp == NULL) + goto invalid_data; + size_t fnamelen = endp - linep; + linep = endp + 1; + + unsigned int diridx; + get_uleb128 (diridx, linep); + Dwarf_Word mtime; + get_uleb128 (mtime, linep); + Dwarf_Word filelength; + get_uleb128 (filelength, linep); + + struct filelist *new_file = + (struct filelist *) alloca (sizeof (*new_file)); + if (fname[0] == '/') + new_file->info.name = fname; + else + { + new_file->info.name = + libdw_alloc (dbg, char, 1, (dirarray[diridx]->len + 1 + + fnamelen + 1)); + char *cp = new_file->info.name; + + if (dirarray[diridx]->dir != NULL) + /* This value could be NULL in case the + DW_AT_comp_dir was not present. We + cannot do much in this case. The easiest + thing is to convert the path in an + absolute path. */ + cp = stpcpy (cp, dirarray[diridx]->dir); + *cp++ = '/'; + strcpy (cp, fname); + } + + new_file->info.mtime = mtime; + new_file->info.length = filelength; + new_file->next = filelist; + filelist = new_file; + ++nfilelist; + } + break; + + default: + /* Unknown, ignore it. */ + linep += len - 1; + break; + } + } + else if (opcode <= DW_LNS_set_epilog_begin) + { + /* This is a known standard opcode. */ + switch (opcode) + { + case DW_LNS_copy: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + /* Add a new line with the current state machine values. */ + NEW_LINE (0); + + /* Reset the flags. */ + basic_block = 0; + /* XXX Whether the following two lines are necessary is + unclear. I guess the current v2.1 specification has + a bug in that it says clearing these two registers is + not necessary. */ + prologue_end = 0; + epilogue_begin = 0; + break; + + case DW_LNS_advance_pc: + /* Takes one uleb128 parameter which is added to the + address. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + get_uleb128 (u128, linep); + address += minimum_instr_len * u128; + break; + + case DW_LNS_advance_line: + /* Takes one sleb128 parameter which is added to the + line. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + get_sleb128 (s128, linep); + line += s128; + break; + + case DW_LNS_set_file: + /* Takes one uleb128 parameter which is stored in file. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + get_uleb128 (u128, linep); + file = u128; + break; + + case DW_LNS_set_column: + /* Takes one uleb128 parameter which is stored in column. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + get_uleb128 (u128, linep); + column = u128; + break; + + case DW_LNS_negate_stmt: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + is_stmt = 1 - is_stmt; + break; + + case DW_LNS_set_basic_block: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + basic_block = 1; + break; + + case DW_LNS_const_add_pc: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + address += (minimum_instr_len + * ((255 - opcode_base) / line_range)); + break; + + case DW_LNS_fixed_advance_pc: + /* Takes one 16 bit parameter which is added to the + address. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + address += read_2ubyte_unaligned_inc (dbg, linep); + break; + + case DW_LNS_set_prologue_end: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + prologue_end = 1; + break; + + case DW_LNS_set_epilog_begin: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + epilogue_begin = 1; + break; + } + } + else + { + /* This is a new opcode the generator but not we know about. + Read the parameters associated with it but then discard + everything. Read all the parameters for this opcode. */ + for (int n = standard_opcode_lengths[opcode]; n > 0; --n) + get_uleb128 (u128, linep); + + /* Next round, ignore this opcode. */ + continue; + } + } + + /* Put all the files in an array. */ + Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files, + sizeof (Dwarf_Files) + + nfilelist * sizeof (Dwarf_Fileinfo), + 1); + files->nfiles = nfilelist; + while (nfilelist-- > 0) + { + files->info[nfilelist] = filelist->info; + filelist = filelist->next; + } + assert (filelist == NULL); + + /* Remember the debugging descriptor. */ + files->dbg = dbg; + + /* Make the file data structure available through the CU. */ + cu->files = files; + + void *buf = libdw_alloc (dbg, Dwarf_Lines, (sizeof (Dwarf_Lines) + + (sizeof (Dwarf_Line) + * nlinelist)), 1); + + /* First use the buffer for the pointers, and sort the entries. + We'll write the pointers in the end of the buffer, and then + copy into the buffer from the beginning so the overlap works. */ + assert (sizeof (Dwarf_Line) >= sizeof (Dwarf_Line *)); + Dwarf_Line **sortlines = (buf + sizeof (Dwarf_Lines) + + ((sizeof (Dwarf_Line) + - sizeof (Dwarf_Line *)) * nlinelist)); + + /* The list is in LIFO order and usually they come in clumps with + ascending addresses. So fill from the back to probably start with + runs already in order before we sort. */ + unsigned int i = nlinelist; + while (i-- > 0) + { + sortlines[i] = &linelist->line; + linelist = linelist->next; + } + assert (linelist == NULL); + + /* Sort by ascending address. */ + qsort (sortlines, nlinelist, sizeof sortlines[0], &compare_lines); + + /* Now that they are sorted, put them in the final array. + The buffers overlap, so we've clobbered the early elements + of SORTLINES by the time we're reading the later ones. */ + cu->lines = buf; + cu->lines->nlines = nlinelist; + for (i = 0; i < nlinelist; ++i) + { + cu->lines->info[i] = *sortlines[i]; + cu->lines->info[i].files = files; + } + + /* Success. */ + res = 0; + } + else if (cu->lines != (void *) -1l) + /* We already have the information. */ + res = 0; + + if (likely (res == 0)) + { + *lines = cu->lines; + *nlines = cu->lines->nlines; + } + out: + + // XXX Eventually: unlocking here. + + return res; +} +INTDEF(dwarf_getsrclines) diff --git a/libdw/dwarf_getstring.c b/libdw/dwarf_getstring.c new file mode 100644 index 00000000..e4abe8cb --- /dev/null +++ b/libdw/dwarf_getstring.c @@ -0,0 +1,51 @@ +/* Get string. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +const char * +dwarf_getstring (dbg, offset, lenp) + Dwarf *dbg; + Dwarf_Off offset; + size_t *lenp; +{ + if (dbg == NULL) + return NULL; + + if (dbg->sectiondata[IDX_debug_str] == NULL + || offset >= dbg->sectiondata[IDX_debug_str]->d_size) + { + no_string: + __libdw_seterrno (DWARF_E_NO_STRING); + return NULL; + } + + const char *result = ((const char *) dbg->sectiondata[IDX_debug_str]->d_buf + + offset); + const char *endp = memchr (result, '\0', + dbg->sectiondata[IDX_debug_str]->d_size - offset); + if (endp == NULL) + goto no_string; + + if (lenp != NULL) + *lenp = endp - result; + + return result; +} diff --git a/libdw/dwarf_hasattr.c b/libdw/dwarf_hasattr.c new file mode 100644 index 00000000..88dbee49 --- /dev/null +++ b/libdw/dwarf_hasattr.c @@ -0,0 +1,37 @@ +/* Check whether given DIE has specific attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_hasattr (die, search_name) + Dwarf_Die *die; + unsigned int search_name; +{ + if (die == NULL) + return 0; + + /* Search for the attribute with the given name. */ + unsigned int code; + (void) __libdw_find_attr (die, search_name, &code, NULL); + + return code == search_name; +} +INTDEF (dwarf_hasattr) diff --git a/libdw/dwarf_hasattr_integrate.c b/libdw/dwarf_hasattr_integrate.c new file mode 100644 index 00000000..423aa2a2 --- /dev/null +++ b/libdw/dwarf_hasattr_integrate.c @@ -0,0 +1,42 @@ +/* Check whether DIE has specific attribute, integrating DW_AT_abstract_origin. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + +int +dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name) +{ + Dwarf_Die die_mem; + + do + { + if (INTUSE(dwarf_hasattr) (die, search_name)) + return 1; + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin, + &attr_mem); + if (attr == NULL) + break; + + die = INTUSE(dwarf_formref_die) (attr, &die_mem); + } + while (die != NULL); + + return 0; +} diff --git a/libdw/dwarf_haschildren.c b/libdw/dwarf_haschildren.c new file mode 100644 index 00000000..05a5b526 --- /dev/null +++ b/libdw/dwarf_haschildren.c @@ -0,0 +1,49 @@ +/* Return string associated with given attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" +#include + + +int +dwarf_haschildren (die) + Dwarf_Die *die; +{ + /* Find the abbreviation entry. */ + Dwarf_Abbrev *abbrevp = die->abbrev; + if (abbrevp != (Dwarf_Abbrev *) -1l) + { + const unsigned char *readp = (unsigned char *) die->addr; + + /* First we have to get the abbreviation code so that we can decode + the data in the DIE. */ + unsigned int abbrev_code; + get_uleb128 (abbrev_code, readp); + + abbrevp = __libdw_findabbrev (die->cu, abbrev_code); + die->abbrev = abbrevp ?: (Dwarf_Abbrev *) -1l; + } + if (unlikely (die->abbrev == (Dwarf_Abbrev *) -1l)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return 0; + } + + return die->abbrev->has_children; +} +INTDEF (dwarf_haschildren) diff --git a/libdw/dwarf_hasform.c b/libdw/dwarf_hasform.c new file mode 100644 index 00000000..392b1f13 --- /dev/null +++ b/libdw/dwarf_hasform.c @@ -0,0 +1,32 @@ +/* Check whether given attribute has specific form. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_hasform (attr, search_form) + Dwarf_Attribute *attr; + unsigned int search_form; +{ + if (attr == NULL) + return 0; + + return attr->form == search_form; +} diff --git a/libdw/dwarf_haspc.c b/libdw/dwarf_haspc.c new file mode 100644 index 00000000..7f29296d --- /dev/null +++ b/libdw/dwarf_haspc.c @@ -0,0 +1,105 @@ +/* Determine whether a DIE covers a PC address. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" +#include + + +int +dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc) +{ + if (die == NULL) + return -1; + + /* Usually there is a single contiguous range. */ + Dwarf_Addr lowpc, highpc; + if (INTUSE(dwarf_highpc) (die, &highpc) == 0 + && INTUSE(dwarf_lowpc) (die, &lowpc) == 0) + return pc >= lowpc && pc < highpc; + + /* We have to look for a noncontiguous range. */ + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges, &attr_mem); + if (attr == NULL) + return -1; + + /* Must have the form data4 or data8 which act as an offset. */ + Dwarf_Word offset; + if (INTUSE(dwarf_formudata) (attr, &offset) != 0) + return -1; + + const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_ranges]; + if (d == NULL) + { + __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES); + return -1; + } + + /* Fetch the CU's base address. */ + Dwarf_Addr base; + Dwarf_Die cudie = + { + .cu = attr->cu, + .addr = ((char *) attr->cu->dbg->sectiondata[IDX_debug_info]->d_buf + + attr->cu->start + 3 * attr->cu->offset_size - 4 + 3), + }; + if (INTUSE(dwarf_lowpc) (&cudie, &base) != 0) + return -1; + + unsigned char *readp = d->d_buf + offset; + Dwarf_Addr begin; + Dwarf_Addr end; + do + { + next: + if ((unsigned char *) d->d_buf + d->d_size - readp + < attr->cu->address_size * 2) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + if (attr->cu->address_size == 8) + { + begin = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); + end = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); + } + else + { + begin = (Dwarf_Sword) read_4sbyte_unaligned_inc (attr->cu->dbg, + readp); + end = read_4ubyte_unaligned_inc (attr->cu->dbg, readp); + } + + if (begin == (Dwarf_Addr) -1l) /* Base address entry. */ + { + base = end; + goto next; + } + + if (begin == 0 && end == 0) /* End of list entry. */ + /* This is not the droid you are looking for. */ + return 0; + + /* We have an address range entry. */ + } + while (pc < base + begin || pc >= base + end); + + /* This one matches the address. */ + return 1; +} +INTDEF (dwarf_haspc) diff --git a/libdw/dwarf_highpc.c b/libdw/dwarf_highpc.c new file mode 100644 index 00000000..d842569a --- /dev/null +++ b/libdw/dwarf_highpc.c @@ -0,0 +1,34 @@ +/* Return high PC attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_highpc (die, return_addr) + Dwarf_Die *die; + Dwarf_Addr *return_addr; +{ + Dwarf_Attribute attr_mem; + + return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_high_pc, + &attr_mem), + return_addr); +} +INTDEF(dwarf_highpc) diff --git a/libdw/dwarf_lineaddr.c b/libdw/dwarf_lineaddr.c new file mode 100644 index 00000000..ddfc01ba --- /dev/null +++ b/libdw/dwarf_lineaddr.c @@ -0,0 +1,31 @@ +/* Return line address. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_lineaddr (Dwarf_Line *line, Dwarf_Addr *addrp) +{ + if (line == NULL) + return -1; + + *addrp = line->addr; + + return 0; +} diff --git a/libdw/dwarf_linebeginstatement.c b/libdw/dwarf_linebeginstatement.c new file mode 100644 index 00000000..d974d8f4 --- /dev/null +++ b/libdw/dwarf_linebeginstatement.c @@ -0,0 +1,31 @@ +/* Return true if record is for beginning of a statement. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_linebeginstatement (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->is_stmt; + + return 0; +} diff --git a/libdw/dwarf_lineblock.c b/libdw/dwarf_lineblock.c new file mode 100644 index 00000000..a6b8e0c2 --- /dev/null +++ b/libdw/dwarf_lineblock.c @@ -0,0 +1,31 @@ +/* Return true if record is for beginning of a basic block. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_lineblock (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->basic_block; + + return 0; +} diff --git a/libdw/dwarf_linecol.c b/libdw/dwarf_linecol.c new file mode 100644 index 00000000..2430d372 --- /dev/null +++ b/libdw/dwarf_linecol.c @@ -0,0 +1,31 @@ +/* Return column in line. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_linecol (Dwarf_Line *line, int *colp) +{ + if (line == NULL) + return -1; + + *colp = line->column; + + return 0; +} diff --git a/libdw/dwarf_lineendsequence.c b/libdw/dwarf_lineendsequence.c new file mode 100644 index 00000000..c49fabe2 --- /dev/null +++ b/libdw/dwarf_lineendsequence.c @@ -0,0 +1,31 @@ +/* Return true if record is for end of sequence. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_lineendsequence (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->end_sequence; + + return 0; +} diff --git a/libdw/dwarf_lineepiloguebegin.c b/libdw/dwarf_lineepiloguebegin.c new file mode 100644 index 00000000..ee4f5bb7 --- /dev/null +++ b/libdw/dwarf_lineepiloguebegin.c @@ -0,0 +1,31 @@ +/* Return true if record is for beginning of epilogue. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_lineepiloguebegin (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->epilogue_begin; + + return 0; +} diff --git a/libdw/dwarf_lineno.c b/libdw/dwarf_lineno.c new file mode 100644 index 00000000..5ad24067 --- /dev/null +++ b/libdw/dwarf_lineno.c @@ -0,0 +1,31 @@ +/* Return line number. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_lineno (Dwarf_Line *line, int *linep) +{ + if (line == NULL) + return -1; + + *linep = line->line; + + return 0; +} diff --git a/libdw/dwarf_lineprologueend.c b/libdw/dwarf_lineprologueend.c new file mode 100644 index 00000000..e869025c --- /dev/null +++ b/libdw/dwarf_lineprologueend.c @@ -0,0 +1,31 @@ +/* Return true if record is for end of prologue. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_lineprologueend (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->prologue_end; + + return 0; +} diff --git a/libdw/dwarf_linesrc.c b/libdw/dwarf_linesrc.c new file mode 100644 index 00000000..0aca1d6f --- /dev/null +++ b/libdw/dwarf_linesrc.c @@ -0,0 +1,41 @@ +/* Find line information for address. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +const char * +dwarf_linesrc (Dwarf_Line *line, Dwarf_Word *mtime, Dwarf_Word *length) +{ + if (line == NULL) + return NULL; + + if (line->file >= line->files->nfiles) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + if (mtime != NULL) + *mtime = line->files->info[line->file].mtime; + + if (length != NULL) + *length = line->files->info[line->file].length; + + return line->files->info[line->file].name; +} diff --git a/libdw/dwarf_lowpc.c b/libdw/dwarf_lowpc.c new file mode 100644 index 00000000..c8cec0c1 --- /dev/null +++ b/libdw/dwarf_lowpc.c @@ -0,0 +1,34 @@ +/* Return low PC attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_lowpc (die, return_addr) + Dwarf_Die *die; + Dwarf_Addr *return_addr; +{ + Dwarf_Attribute attr_mem; + + return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc, + &attr_mem), + return_addr); +} +INTDEF(dwarf_lowpc) diff --git a/libdw/dwarf_macro_opcode.c b/libdw/dwarf_macro_opcode.c new file mode 100644 index 00000000..1401db2d --- /dev/null +++ b/libdw/dwarf_macro_opcode.c @@ -0,0 +1,31 @@ +/* Return macro opcode. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep) +{ + if (macro == NULL) + return -1; + + *opcodep = macro->opcode; + + return 0; +} diff --git a/libdw/dwarf_macro_param1.c b/libdw/dwarf_macro_param1.c new file mode 100644 index 00000000..adac7613 --- /dev/null +++ b/libdw/dwarf_macro_param1.c @@ -0,0 +1,31 @@ +/* Return first macro parameter. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_macro_param1 (Dwarf_Macro *macro, Dwarf_Word *paramp) +{ + if (macro == NULL) + return -1; + + *paramp = macro->param1; + + return 0; +} diff --git a/libdw/dwarf_macro_param2.c b/libdw/dwarf_macro_param2.c new file mode 100644 index 00000000..1b49aa7f --- /dev/null +++ b/libdw/dwarf_macro_param2.c @@ -0,0 +1,34 @@ +/* Return second macro parameter. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp, const char **strp) +{ + if (macro == NULL) + return -1; + + if (paramp != NULL) + *paramp = macro->param2.u; + if (strp != NULL) + *strp = macro->param2.s; + + return 0; +} diff --git a/libdw/dwarf_nextcu.c b/libdw/dwarf_nextcu.c new file mode 100644 index 00000000..9dc7633e --- /dev/null +++ b/libdw/dwarf_nextcu.c @@ -0,0 +1,132 @@ +/* Advance to next CU header. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp, + address_sizep, offset_sizep) + Dwarf *dwarf; + Dwarf_Off off; + Dwarf_Off *next_off; + size_t *header_sizep; + Dwarf_Off *abbrev_offsetp; + uint8_t *address_sizep; + uint8_t *offset_sizep; +{ + /* Maybe there has been an error before. */ + if (dwarf == NULL) + return -1; + + /* If we reached the end before don't do anything. */ + if (off == (Dwarf_Off) -1l + /* Make sure there is enough space in the .debug_info section + for at least the initial word. We cannot test the rest since + we don't know yet whether this is a 64-bit object or not. */ + || unlikely (off + 4 >= dwarf->sectiondata[IDX_debug_info]->d_size)) + { + *next_off = (Dwarf_Off) -1l; + return 1; + } + + /* This points into the .debug_info section to the beginning of the + CU entry. */ + char *bytes = (char *) dwarf->sectiondata[IDX_debug_info]->d_buf + off; + + /* The format of the CU header is described in dwarf2p1 7.5.1: + + 1. A 4-byte or 12-byte unsigned integer representing the length + of the .debug_info contribution for that compilation unit, not + including the length field itself. In the 32-bit DWARF format, + this is a 4-byte unsigned integer (which must be less than + 0xffffff00); in the 64-bit DWARF format, this consists of the + 4-byte value 0xffffffff followed by an 8-byte unsigned integer + that gives the actual length (see Section 7.4). + + 2. A 2-byte unsigned integer representing the version of the + DWARF information for that compilation unit. For DWARF Version + 2.1, the value in this field is 2. + + 3. A 4-byte or 8-byte unsigned offset into the .debug_abbrev + section. This offset associates the compilation unit with a + particular set of debugging information entry abbreviations. In + the 32-bit DWARF format, this is a 4-byte unsigned length; in + the 64-bit DWARF format, this is an 8-byte unsigned length (see + Section 7.4). + + 4. A 1-byte unsigned integer representing the size in bytes of + an address on the target architecture. If the system uses + segmented addressing, this value represents the size of the + offset portion of an address. */ + uint64_t length = read_4ubyte_unaligned_inc (dwarf, bytes); + size_t offset_size = 4; + if (length == 0xffffffffu) + offset_size = 8; + + /* Now we know how large the header is. Note the trick in the + computation. If the offset_size is 4 the '- 4' term undoes the + '2 *'. If offset_size is 8 this term computes the size of the + escape value plus the 8 byte offset. */ + if (unlikely (off + 2 * offset_size - 4 + sizeof (uint16_t) + + offset_size + sizeof (uint8_t) + >= dwarf->sectiondata[IDX_debug_info]->d_size)) + { + *next_off = -1; + return 1; + } + + if (length == 0xffffffffu) + /* This is a 64-bit DWARF format. */ + length = read_8ubyte_unaligned_inc (dwarf, bytes); + + /* Read the version stamp. Always a 16-bit value. + XXX Do we need the value? */ + read_2ubyte_unaligned_inc (dwarf, bytes); + + /* Get offset in .debug_abbrev. Note that the size of the entry + depends on whether this is a 32-bit or 64-bit DWARF definition. */ + uint64_t abbrev_offset; + if (offset_size == 4) + abbrev_offset = read_4ubyte_unaligned_inc (dwarf, bytes); + else + abbrev_offset = read_8ubyte_unaligned_inc (dwarf, bytes); + if (abbrev_offsetp != NULL) + *abbrev_offsetp = abbrev_offset; + + /* The address size. Always an 8-bit value. */ + uint8_t address_size = *bytes++; + if (address_sizep != NULL) + *address_sizep = address_size; + + /* Store the offset size. */ + if (offset_sizep != NULL) + *offset_sizep = offset_size; + + /* Store the header length. */ + if (header_sizep != NULL) + *header_sizep = (bytes + - ((char *) dwarf->sectiondata[IDX_debug_info]->d_buf + + off)); + + /* See above for an explanation of the trick in this formula. */ + *next_off = off + 2 * offset_size - 4 + length; + + return 0; +} +INTDEF(dwarf_nextcu) diff --git a/libdw/dwarf_offabbrev.c b/libdw/dwarf_offabbrev.c new file mode 100644 index 00000000..97370d60 --- /dev/null +++ b/libdw/dwarf_offabbrev.c @@ -0,0 +1,36 @@ +/* Get abbreviation at given offset. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp, + Dwarf_Abbrev *abbrevp) +{ + if (dbg == NULL) + return -1; + + Dwarf_Abbrev *abbrev = __libdw_getabbrev (dbg, NULL, offset, lengthp, + abbrevp); + + if (abbrev == NULL) + return -1; + + return abbrev == DWARF_END_ABBREV ? 1 : 0; +} diff --git a/libdw/dwarf_offdie.c b/libdw/dwarf_offdie.c new file mode 100644 index 00000000..84300e1a --- /dev/null +++ b/libdw/dwarf_offdie.c @@ -0,0 +1,55 @@ +/* Return DIE at given offset. + Copyright (C) 2002, 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +Dwarf_Die * +dwarf_offdie (dbg, offset, result) + Dwarf *dbg; + Dwarf_Off offset; + Dwarf_Die *result; +{ + if (dbg == NULL) + return NULL; + + if (offset >= dbg->sectiondata[IDX_debug_info]->d_size) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* Clear the entire DIE structure. This signals we have not yet + determined any of the information. */ + memset (result, '\0', sizeof (Dwarf_Die)); + + result->addr = (char *) dbg->sectiondata[IDX_debug_info]->d_buf + offset; + + /* Get the CU. */ + result->cu = __libdw_findcu (dbg, offset); + if (result->cu == NULL) + { + /* This should never happen. The input file is malformed. */ + __libdw_seterrno (DWARF_E_INVALID_DWARF); + result = NULL; + } + + return result; +} +INTDEF(dwarf_offdie) diff --git a/libdw/dwarf_onearange.c b/libdw/dwarf_onearange.c new file mode 100644 index 00000000..0c372526 --- /dev/null +++ b/libdw/dwarf_onearange.c @@ -0,0 +1,35 @@ +/* Return one of the address range entries. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +Dwarf_Arange * +dwarf_onearange (Dwarf_Aranges *aranges, size_t idx) +{ + if (aranges == NULL) + return NULL; + + if (idx >= aranges->naranges) + { + __libdw_seterrno (DWARF_E_INVALID_ARANGE_IDX); + return NULL; + } + + return &aranges->info[idx]; +} diff --git a/libdw/dwarf_onesrcline.c b/libdw/dwarf_onesrcline.c new file mode 100644 index 00000000..9234ef9a --- /dev/null +++ b/libdw/dwarf_onesrcline.c @@ -0,0 +1,35 @@ +/* Return one of the sources lines of a CU. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +Dwarf_Line * +dwarf_onesrcline (Dwarf_Lines *lines, size_t idx) +{ + if (lines == NULL) + return NULL; + + if (idx >= lines->nlines) + { + __libdw_seterrno (DWARF_E_INVALID_LINE_IDX); + return NULL; + } + + return &lines->info[idx]; +} diff --git a/libdw/dwarf_siblingof.c b/libdw/dwarf_siblingof.c new file mode 100644 index 00000000..bd965ea8 --- /dev/null +++ b/libdw/dwarf_siblingof.c @@ -0,0 +1,115 @@ +/* Return sibling of given DIE. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" +#include +#include + + +int +dwarf_siblingof (die, result) + Dwarf_Die *die; + Dwarf_Die *result; +{ + /* Ignore previous errors. */ + if (die == NULL) + return -1; + + unsigned int level = 0; + + /* Copy of the current DIE. */ + Dwarf_Die this_die = *die; + /* Temporary attributes we create. */ + Dwarf_Attribute sibattr; + /* Copy of the CU in the request. */ + sibattr.cu = this_die.cu; + /* That's the address we start looking. */ + unsigned char *addr = this_die.addr; + /* End of the buffer. */ + unsigned char *endp + = ((unsigned char *) sibattr.cu->dbg->sectiondata[IDX_debug_info]->d_buf + + sibattr.cu->end); + + /* Search for the beginning of the next die on this level. We + must not return the dies for children of the given die. */ + do + { + /* Find the end of the DIE or the sibling attribute. */ + addr = __libdw_find_attr (&this_die, DW_AT_sibling, &sibattr.code, + &sibattr.form); + if (sibattr.code == DW_AT_sibling) + { + Dwarf_Off offset; + sibattr.valp = addr; + if (INTUSE(dwarf_formref) (&sibattr, &offset) != 0) + /* Something went wrong. */ + return -1; + + /* Compute the next address. */ + addr = ((unsigned char *) + sibattr.cu->dbg->sectiondata[IDX_debug_info]->d_buf + + sibattr.cu->start + offset); + } + else if (unlikely (addr == NULL) + || unlikely (this_die.abbrev == (Dwarf_Abbrev *) -1l)) + return -1; + else if (this_die.abbrev->has_children) + /* This abbreviation has children. */ + ++level; + + + while (1) + { + /* Make sure we are still in range. Some producers might skip + the trailing NUL bytes. */ + if (addr >= endp) + return 1; + + if (*addr != '\0') + break; + + if (level-- == 0) + /* No more sibling at all. */ + return 1; + + ++addr; + } + + /* Initialize the 'current DIE'. */ + this_die.addr = addr; + this_die.abbrev = NULL; + } + while (level > 0); + + /* Maybe we reached the end of the CU. */ + if (addr >= endp) + return 1; + + /* Clear the entire DIE structure. This signals we have not yet + determined any of the information. */ + memset (result, '\0', sizeof (Dwarf_Die)); + + /* We have the address. */ + result->addr = addr; + + /* Same CU as the parent. */ + result->cu = sibattr.cu; + + return 0; +} +INTDEF(dwarf_siblingof) diff --git a/libdw/dwarf_srclang.c b/libdw/dwarf_srclang.c new file mode 100644 index 00000000..3fb06a1e --- /dev/null +++ b/libdw/dwarf_srclang.c @@ -0,0 +1,33 @@ +/* Return source language attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +int +dwarf_srclang (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_language, + &attr_mem), + &value) == 0 ? (int) value : -1; +} diff --git a/libdw/dwarf_tag.c b/libdw/dwarf_tag.c new file mode 100644 index 00000000..939b6811 --- /dev/null +++ b/libdw/dwarf_tag.c @@ -0,0 +1,82 @@ +/* Return tag of given DIE. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +Dwarf_Abbrev * +internal_function_def +__libdw_findabbrev (struct Dwarf_CU *cu, unsigned int code) +{ + Dwarf_Abbrev *abb; + + /* See whether the entry is already in the hash table. */ + abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL); + if (abb == NULL) + while (cu->last_abbrev_offset != (size_t) -1l) + { + size_t length; + + /* Find the next entry. It gets automatically added to the + hash table. */ + abb = __libdw_getabbrev (cu->dbg, cu, cu->last_abbrev_offset, &length, + NULL); + if (abb == NULL || abb == DWARF_END_ABBREV) + { + /* Make sure we do not try to search for it again. */ + cu->last_abbrev_offset = (size_t) -1l; + abb = (void *) -1l; + break; + } + + cu->last_abbrev_offset += length; + + /* Is this the code we are looking for? */ + if (abb->code == code) + break; + } + + return abb; +} + + +int +dwarf_tag (die) + Dwarf_Die *die; +{ + /* Do we already know the abbreviation? */ + if (die->abbrev == NULL) + { + /* Get the abbreviation code. */ + unsigned int u128; + const unsigned char *addr = die->addr; + get_uleb128 (u128, addr); + + /* Find the abbreviation. */ + die->abbrev = __libdw_findabbrev (die->cu, u128); + } + + if (die->abbrev == (Dwarf_Abbrev *) -1l) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return DW_TAG_invalid; + } + + return die->abbrev->tag; +} +INTDEF(dwarf_tag) diff --git a/libdw/dwarf_whatattr.c b/libdw/dwarf_whatattr.c new file mode 100644 index 00000000..ad5d868f --- /dev/null +++ b/libdw/dwarf_whatattr.c @@ -0,0 +1,28 @@ +/* Return attribute code of given attribute. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +unsigned int +dwarf_whatattr (attr) + Dwarf_Attribute *attr; +{ + return attr == NULL ? 0 : attr->code; +} diff --git a/libdw/dwarf_whatform.c b/libdw/dwarf_whatform.c new file mode 100644 index 00000000..99da1c97 --- /dev/null +++ b/libdw/dwarf_whatform.c @@ -0,0 +1,28 @@ +/* Return form code of given attribute. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libdwP.h" + + +unsigned int +dwarf_whatform (attr) + Dwarf_Attribute *attr; +{ + return attr == NULL ? 0 : attr->form; +} diff --git a/libdw/libdw.h b/libdw/libdw.h new file mode 100644 index 00000000..786be22a --- /dev/null +++ b/libdw/libdw.h @@ -0,0 +1,564 @@ +/* Interfaces for libdw. + Copyright (C) 2002, 2004, 2005 Red Hat, Inc. + Contributed by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBDW_H +#define _LIBDW_H 1 + +#include +#include +#include + + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +# define __nonnull_attribute__(...) __attribute__ ((__nonnull__ (__VA_ARGS__))) +#else +# define __nonnull_attribute__(args...) +#endif + + +/* Mode for the session. */ +typedef enum + { + DWARF_C_READ, /* Read .. */ + DWARF_C_RDWR, /* Read and write .. */ + DWARF_C_WRITE, /* Write .. */ + } +Dwarf_Cmd; + + +/* Callback results. */ +enum +{ + DWARF_CB_OK = 0, + DWARF_CB_ABORT +}; + + +/* Error values. */ +enum + { + DW_TAG_invalid = 0 +#define DW_TAG_invalid DW_TAG_invalid + }; + + +/* Type for offset in DWARF file. */ +typedef GElf_Off Dwarf_Off; + +/* Type for address in DWARF file. */ +typedef GElf_Addr Dwarf_Addr; + +/* Integer types. Big enough to hold any numeric value. */ +typedef GElf_Xword Dwarf_Word; +typedef GElf_Sxword Dwarf_Sword; +/* For the times we know we do not need that much. */ +typedef GElf_Half Dwarf_Half; + + +/* DWARF abbreviation record. */ +typedef struct Dwarf_Abbrev Dwarf_Abbrev; + +/* Returned to show the last DIE has be returned. */ +#define DWARF_END_ABBREV ((Dwarf_Abbrev *) -1l) + +/* Source code line information for CU. */ +typedef struct Dwarf_Lines_s Dwarf_Lines; + +/* One source code line information. */ +typedef struct Dwarf_Line_s Dwarf_Line; + +/* Source file information. */ +typedef struct Dwarf_Files_s Dwarf_Files; + +/* One address range record. */ +typedef struct Dwarf_Arange_s Dwarf_Arange; + +/* Address ranges of a file. */ +typedef struct Dwarf_Aranges_s Dwarf_Aranges; + +/* CU representation. */ +struct Dwarf_CU; + +/* Function information. */ +typedef struct Dwarf_Func_s Dwarf_Func; + +/* Macro information. */ +typedef struct Dwarf_Macro_s Dwarf_Macro; + +/* Attribute representation. */ +typedef struct +{ + unsigned int code; + unsigned int form; + unsigned char *valp; + struct Dwarf_CU *cu; +} Dwarf_Attribute; + + +/* Data block representation. */ +typedef struct +{ + Dwarf_Word length; + unsigned char *data; +} Dwarf_Block; + + +/* DIE information. */ +typedef struct +{ + /* The offset can be computed from the address. */ + void *addr; + struct Dwarf_CU *cu; + Dwarf_Abbrev *abbrev; + // XXX We'll see what other information will be needed. + long int padding__; +} Dwarf_Die; + +/* Returned to show the last DIE has be returned. */ +#define DWARF_END_DIE ((Dwarf_Die *) -1l) + + +/* Global symbol information. */ +typedef struct +{ + Dwarf_Off cu_offset; + Dwarf_Off die_offset; + const char *name; +} Dwarf_Global; + + +// XXX It remains to be seen whether the next two need to be exported. +/* Location record. */ +typedef struct +{ + uint8_t atom; /* Operation */ + Dwarf_Word number; /* Operand */ + Dwarf_Word number2; /* Possible second operand */ + Dwarf_Word offset; /* Offset in location expression */ +} Dwarf_Loc; + + +/* Handle for debug sessions. */ +typedef struct Dwarf Dwarf; + + +/* Out-Of-Memory handler. */ +#if __GNUC__ < 4 +typedef void (*Dwarf_OOM) (void); +#else +typedef void (*__attribute__ ((noreturn)) Dwarf_OOM) (void); +#endif + + +/* Create a handle for a new debug session. */ +extern Dwarf *dwarf_begin (int fildes, Dwarf_Cmd cmd); + +/* Create a handle for a new debug session for an ELF file. */ +extern Dwarf *dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp); + +/* Retrieve ELF descriptor used for DWARF access. */ +extern Elf *dwarf_getelf (Dwarf *dwarf); + +/* Release debugging handling context. */ +extern int dwarf_end (Dwarf *dwarf); + + +/* Get the data block for the .debug_info section. */ +extern Elf_Data *dwarf_getscn_info (Dwarf *dwarf); + +/* Read the header for the DWARF CU header. */ +extern int dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off, + size_t *header_sizep, Dwarf_Off *abbrev_offsetp, + uint8_t *address_sizep, uint8_t *offset_sizep) + __nonnull_attribute__ (3); + + +/* Return DIE at given offset. */ +extern Dwarf_Die *dwarf_offdie (Dwarf *dbg, Dwarf_Off offset, + Dwarf_Die *result) __nonnull_attribute__ (3); + +/* Return offset of DIE. */ +extern Dwarf_Off dwarf_dieoffset (Dwarf_Die *die); + +/* Return offset of DIE in CU. */ +extern Dwarf_Off dwarf_cuoffset (Dwarf_Die *die); + +/* Return CU DIE containing given address. */ +extern Dwarf_Die *dwarf_addrdie (Dwarf *dbg, Dwarf_Addr addr, + Dwarf_Die *result) __nonnull_attribute__ (3); + +/* Return child of current DIE. */ +extern int dwarf_child (Dwarf_Die *die, Dwarf_Die *result) + __nonnull_attribute__ (2); + +/* Return sibling of given DIE. */ +extern int dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result) + __nonnull_attribute__ (2); + +/* Check whether the DIE has children. */ +extern int dwarf_haschildren (Dwarf_Die *die); + +/* Get attributes of the DIE. */ +extern ptrdiff_t dwarf_getattrs (Dwarf_Die *die, + int (*callback) (Dwarf_Attribute *, void *), + void *arg, ptrdiff_t offset); + +/* Return tag of given DIE. */ +extern int dwarf_tag (Dwarf_Die *die); + + +/* Return specific attribute of DIE. */ +extern Dwarf_Attribute *dwarf_attr (Dwarf_Die *die, unsigned int search_name, + Dwarf_Attribute *result) + __nonnull_attribute__ (3); + +/* Check whether given DIE has specific attribute. */ +extern int dwarf_hasattr (Dwarf_Die *die, unsigned int search_name); + +/* These are the same as dwarf_attr and dwarf_hasattr, respectively, + but they resolve an indirect attribute through DW_AT_abstract_origin. */ +extern Dwarf_Attribute *dwarf_attr_integrate (Dwarf_Die *die, + unsigned int search_name, + Dwarf_Attribute *result) + __nonnull_attribute__ (3); +extern int dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name); + + + + +/* Check whether given attribute has specific form. */ +extern int dwarf_hasform (Dwarf_Attribute *attr, unsigned int search_form); + +/* Return attribute code of given attribute. */ +extern unsigned int dwarf_whatattr (Dwarf_Attribute *attr); + +/* Return form code of given attribute. */ +extern unsigned int dwarf_whatform (Dwarf_Attribute *attr); + + +/* Return string associated with given attribute. */ +extern const char *dwarf_formstring (Dwarf_Attribute *attrp); + +/* Return unsigned constant represented by attribute. */ +extern int dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) + __nonnull_attribute__ (2); + +/* Return signed constant represented by attribute. */ +extern int dwarf_formsdata (Dwarf_Attribute *attr, Dwarf_Sword *return_uval) + __nonnull_attribute__ (2); + +/* Return address represented by attribute. */ +extern int dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return reference offset represented by attribute. */ +extern int dwarf_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset) + __nonnull_attribute__ (2); + +/* Look up the DIE in a reference-form attribute. */ +extern Dwarf_Die *dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *die_mem) + __nonnull_attribute__ (2); + +/* Return block represented by attribute. */ +extern int dwarf_formblock (Dwarf_Attribute *attr, Dwarf_Block *return_block) + __nonnull_attribute__ (2); + +/* Return flag represented by attribute. */ +extern int dwarf_formflag (Dwarf_Attribute *attr, bool *return_bool) + __nonnull_attribute__ (2); + + +/* Simplified attribute value access functions. */ + +/* Return string in name attribute of DIE. */ +extern const char *dwarf_diename (Dwarf_Die *die); + +/* Return high PC attribute of DIE. */ +extern int dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return low PC attribute of DIE. */ +extern int dwarf_lowpc (Dwarf_Die *die, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return 1 if DIE's lowpc/highpc or ranges attributes match the PC address, + 0 if not, or -1 for errors. */ +extern int dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc); + +/* Return byte size attribute of DIE. */ +extern int dwarf_bytesize (Dwarf_Die *die); + +/* Return bit size attribute of DIE. */ +extern int dwarf_bitsize (Dwarf_Die *die); + +/* Return bit offset attribute of DIE. */ +extern int dwarf_bitoffset (Dwarf_Die *die); + +/* Return array order attribute of DIE. */ +extern int dwarf_arrayorder (Dwarf_Die *die); + +/* Return source language attribute of DIE. */ +extern int dwarf_srclang (Dwarf_Die *die); + + +/* Get abbreviation at given offset for given DIE. */ +extern Dwarf_Abbrev *dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, + size_t *lengthp); + +/* Get abbreviation at given offset in .debug_abbrev section. */ +extern int dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp, + Dwarf_Abbrev *abbrevp) + __nonnull_attribute__ (4); + +/* Get abbreviation code. */ +extern unsigned int dwarf_getabbrevcode (Dwarf_Abbrev *abbrev); + +/* Get abbreviation tag. */ +extern unsigned int dwarf_getabbrevtag (Dwarf_Abbrev *abbrev); + +/* Return true if abbreviation is children flag set. */ +extern int dwarf_abbrevhaschildren (Dwarf_Abbrev *abbrev); + +/* Get number of attributes of abbreviation. */ +extern int dwarf_getattrcnt (Dwarf_Abbrev *abbrev, size_t *attrcntp) + __nonnull_attribute__ (2); + +/* Get specific attribute of abbreviation. */ +extern int dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, + unsigned int *namep, unsigned int *formp, + Dwarf_Off *offset); + + +/* Get string from-debug_str section. */ +extern const char *dwarf_getstring (Dwarf *dbg, Dwarf_Off offset, + size_t *lenp); + + +/* Get public symbol information. */ +extern ptrdiff_t dwarf_getpubnames (Dwarf *dbg, + int (*callback) (Dwarf *, Dwarf_Global *, + void *), + void *arg, ptrdiff_t offset) + __nonnull_attribute__ (2); + + +/* Get source file information for CU. */ +extern int dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, + size_t *nlines) __nonnull_attribute__ (2, 3); + +/* Return one of the source lines of the CU. */ +extern Dwarf_Line *dwarf_onesrcline (Dwarf_Lines *lines, size_t idx); + +/* Get the file source files used in the CU. */ +extern int dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, + size_t *nfiles) + __nonnull_attribute__ (2); + + +/* Get source for address in CU. */ +extern Dwarf_Line *dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr); + +/* Get source for file and line number. */ +extern int dwarf_getsrc_file (Dwarf *dbg, const char *fname, int line, int col, + Dwarf_Line ***srcsp, size_t *nsrcs) + __nonnull_attribute__ (2, 5, 6); + + +/* Return line address. */ +extern int dwarf_lineaddr (Dwarf_Line *line, Dwarf_Addr *addrp); + +/* Return line number. */ +extern int dwarf_lineno (Dwarf_Line *line, int *linep) + __nonnull_attribute__ (2); + +/* Return column in line. */ +extern int dwarf_linecol (Dwarf_Line *line, int *colp) + __nonnull_attribute__ (2); + +/* Return true if record is for beginning of a statement. */ +extern int dwarf_linebeginstatement (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for end of sequence. */ +extern int dwarf_lineendsequence (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for beginning of a basic block. */ +extern int dwarf_lineblock (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for end of prologue. */ +extern int dwarf_lineprologueend (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for beginning of epilogue. */ +extern int dwarf_lineepiloguebegin (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + + +/* Find line information for address. */ +extern const char *dwarf_linesrc (Dwarf_Line *line, + Dwarf_Word *mtime, Dwarf_Word *length); + +/* Return file information. */ +extern const char *dwarf_filesrc (Dwarf_Files *file, size_t idx, + Dwarf_Word *mtime, Dwarf_Word *length); + + +/* Return location expression list. */ +extern int dwarf_getloclist (Dwarf_Attribute *attr, Dwarf_Loc **llbuf, + size_t *listlen) __nonnull_attribute__ (2, 3); + +/* Return location expression lists. If the attribute uses a location + list, ADDRESS selects the relevant location expressions from the list. + There can be multiple matches, resulting in multiple expressions to + return. LLBUFS and LISTLENS are parallel arrays of NLOCS slots to fill + in. Returns the number of locations filled in, or -1 for errors. If + LLBUFS is a null pointer, stores nothing and returns the total number of + locations. A return value of zero means that the location list + indicated no value is accessible. */ +extern int dwarf_addrloclists (Dwarf_Attribute *attr, Dwarf_Addr address, + Dwarf_Loc **llbufs, size_t *listlens, + size_t nlocs); + + +/* Return scope DIEs containing PC address. + Sets *SCOPES to a malloc'd array of Dwarf_Die structures, + and returns the number of elements in the array. + (*SCOPES)[0] is the DIE for the innermost scope containing PC, + (*SCOPES)[1] is the DIE for the scope containing that scope, and so on. + Returns -1 for errors or 0 if no scopes match PC. */ +extern int dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, + Dwarf_Die **scopes); + +/* Search SCOPES[0..NSCOPES-1] for a variable called NAME. + Ignore the first SKIP_SHADOWS scopes that match the name. + If MATCH_FILE is not null, accept only declaration in that source file; + if MATCH_LINENO or MATCH_LINECOL are also nonzero, accept only declaration + at that line and column. + + If successful, fill in *RESULT with the DIE of the variable found, + and return N where SCOPES[N] is the scope defining the variable. + Return -1 for errors or -2 for no matching variable found. */ +extern int dwarf_getscopevar (Dwarf_Die *scopes, int nscopes, + const char *name, int skip_shadows, + const char *match_file, + int match_lineno, int match_linecol, + Dwarf_Die *result); + + + +/* Return list address ranges. */ +extern int dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, + size_t *naranges) + __nonnull_attribute__ (2); + +/* Return one of the address range entries. */ +extern Dwarf_Arange *dwarf_onearange (Dwarf_Aranges *aranges, size_t idx); + +/* Return information in address range record. */ +extern int dwarf_getarangeinfo (Dwarf_Arange *arange, Dwarf_Addr *addrp, + Dwarf_Word *lengthp, Dwarf_Off *offsetp); + +/* Get address range which includes given address. */ +extern Dwarf_Arange *dwarf_getarange_addr (Dwarf_Aranges *aranges, + Dwarf_Addr addr); + + + +/* Get functions in CUDIE. */ +extern ptrdiff_t dwarf_getfuncs (Dwarf_Die *cudie, + int (*callback) (Dwarf_Func *, void *), + void *arg, ptrdiff_t offset); + +/* Return name of function. */ +extern const char *dwarf_func_name (Dwarf_Func *func); + +/* Return start address of function. */ +extern int dwarf_func_lowpc (Dwarf_Func *func, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return end address of function. */ +extern int dwarf_func_highpc (Dwarf_Func *func, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return entry point address of function. */ +extern int dwarf_func_entrypc (Dwarf_Func *func, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return file name containing definition of the given function. */ +extern const char *dwarf_func_file (Dwarf_Func *func); + +/* Get line number of beginning of given function. */ +extern int dwarf_func_line (Dwarf_Func *func, int *linep) + __nonnull_attribute__ (2); + +/* Get column number of beginning of given function. */ +extern int dwarf_func_col (Dwarf_Func *func, int *colp) + __nonnull_attribute__ (2); + + +/* Call callback function for each of the macro information entry for + the CU. */ +extern ptrdiff_t dwarf_getmacros (Dwarf_Die *cudie, + int (*callback) (Dwarf_Macro *, void *), + void *arg, ptrdiff_t offset) + __nonnull_attribute__ (2); + +/* Return macro opcode. */ +extern int dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep) + __nonnull_attribute__ (2); + +/* Return first macro parameter. */ +extern int dwarf_macro_param1 (Dwarf_Macro *macro, Dwarf_Word *paramp) + __nonnull_attribute__ (2); + +/* Return second macro parameter. */ +extern int dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp, + const char **strp); + + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int dwarf_errno (void); + +/* Return error string for ERROR. If ERROR is zero, return error string + for most recent error or NULL is none occurred. If ERROR is -1 the + behaviour is similar to the last case except that not NULL but a legal + string is returned. */ +extern const char *dwarf_errmsg (int err); + + +/* Register new Out-Of-Memory handler. The old handler is returned. */ +extern Dwarf_OOM dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler); + + +/* Inline optimizations. */ +#ifdef __OPTIMIZE__ +/* Return attribute code of given attribute. */ +extern inline unsigned int +dwarf_whatattr (Dwarf_Attribute *attr) +{ + return attr == NULL ? 0 : attr->code; +} + +/* Return attribute code of given attribute. */ +extern inline unsigned int +dwarf_whatform (Dwarf_Attribute *attr) +{ + return attr == NULL ? 0 : attr->form; +} +#endif /* Optimize. */ + +#endif /* libdw.h */ diff --git a/libdw/libdw.map b/libdw/libdw.map new file mode 100644 index 00000000..ed3c989a --- /dev/null +++ b/libdw/libdw.map @@ -0,0 +1,92 @@ +ELFUTILS_1.0 { + global: + dwarf_abbrevhaschildren; + dwarf_addrdie; + dwarf_addrloclists; + dwarf_attr; + dwarf_attr_integrate; + dwarf_arrayorder; + dwarf_begin; + dwarf_begin_elf; + dwarf_bitoffset; + dwarf_bitsize; + dwarf_bytesize; + dwarf_child; + dwarf_cuoffset; + dwarf_diename; + dwarf_dieoffset; + dwarf_end; + dwarf_errmsg; + dwarf_errno; + dwarf_filesrc; + dwarf_formaddr; + dwarf_formblock; + dwarf_formflag; + dwarf_formref; + dwarf_formref_die; + dwarf_formsdata; + dwarf_formstring; + dwarf_formudata; + dwarf_func_col; + dwarf_func_entrypc; + dwarf_func_file; + dwarf_func_highpc; + dwarf_func_line; + dwarf_func_lowpc; + dwarf_func_name; + dwarf_getabbrev; + dwarf_getabbrevattr; + dwarf_getabbrevcode; + dwarf_getabbrevtag; + dwarf_getarange_addr; + dwarf_getarangeinfo; + dwarf_getaranges; + dwarf_getattrcnt; + dwarf_getattrs; + dwarf_getelf; + dwarf_getfuncs; + dwarf_getloclist; + dwarf_getmacros; + dwarf_getpubnames; + dwarf_getscopes; + dwarf_getscopevar; + dwarf_getscn_info; + dwarf_getsrc_die; + dwarf_getsrc_file; + dwarf_getsrcfiles; + dwarf_getsrclines; + dwarf_getstring; + dwarf_hasattr; + dwarf_hasattr_integrate; + dwarf_haspc; + dwarf_haschildren; + dwarf_hasform; + dwarf_highpc; + dwarf_lineaddr; + dwarf_linebeginstatement; + dwarf_lineblock; + dwarf_linecol; + dwarf_lineendsequence; + dwarf_lineepiloguebegin; + dwarf_lineno; + dwarf_lineprologueend; + dwarf_linesrc; + dwarf_lowpc; + dwarf_macro_opcode; + dwarf_macro_param1; + dwarf_macro_param2; + dwarf_offabbrev; + dwarf_offdie; + dwarf_onearange; + dwarf_onesrcline; + dwarf_nextcu; + dwarf_new_oom_handler; + dwarf_siblingof; + dwarf_srclang; + dwarf_tag; + dwarf_whatattr; + dwarf_whatform; + + local: + *; +}; diff --git a/libdw/libdwP.h b/libdw/libdwP.h new file mode 100644 index 00000000..05e02aa3 --- /dev/null +++ b/libdw/libdwP.h @@ -0,0 +1,378 @@ +/* Internal definitions for libdwarf. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBDWP_H +#define _LIBDWP_H 1 + +#include +#include + +#include + + +/* gettext helper macros. */ +#define _(Str) dgettext ("elfutils", Str) + + +/* Version of the DWARF specification we support. */ +#define DWARF_VERSION 2 + +/* Version of the CIE format. */ +#define CIE_VERSION 1 + + +/* Known location lists. */ +struct loc_s +{ + void *addr; + Dwarf_Loc *loc; + size_t nloc; +}; + +/* Valid indeces for the section data. */ +enum + { + IDX_debug_info = 0, + IDX_debug_abbrev, + IDX_debug_aranges, + IDX_debug_line, + IDX_debug_frame, + IDX_eh_frame, + IDX_debug_loc, + IDX_debug_pubnames, + IDX_debug_str, + IDX_debug_funcnames, + IDX_debug_typenames, + IDX_debug_varnames, + IDX_debug_weaknames, + IDX_debug_macinfo, + IDX_debug_ranges, + IDX_last + }; + + +/* Error values. */ +enum +{ + DWARF_E_NOERROR = 0, + DWARF_E_UNKNOWN_ERROR, + DWARF_E_INVALID_ACCESS, + DWARF_E_NO_REGFILE, + DWARF_E_IO_ERROR, + DWARF_E_INVALID_ELF, + DWARF_E_NO_DWARF, + DWARF_E_NOELF, + DWARF_E_GETEHDR_ERROR, + DWARF_E_NOMEM, + DWARF_E_UNIMPL, + DWARF_E_INVALID_CMD, + DWARF_E_INVALID_VERSION, + DWARF_E_INVALID_FILE, + DWARF_E_NO_ENTRY, + DWARF_E_INVALID_DWARF, + DWARF_E_NO_STRING, + DWARF_E_NO_ADDR, + DWARF_E_NO_CONSTANT, + DWARF_E_NO_REFERENCE, + DWARF_E_INVALID_REFERENCE, + DWARF_E_NO_DEBUG_LINE, + DWARF_E_INVALID_DEBUG_LINE, + DWARF_E_TOO_BIG, + DWARF_E_VERSION, + DWARF_E_INVALID_DIR_IDX, + DWARF_E_ADDR_OUTOFRANGE, + DWARF_E_NO_LOCLIST, + DWARF_E_NO_BLOCK, + DWARF_E_INVALID_LINE_IDX, + DWARF_E_INVALID_ARANGE_IDX, + DWARF_E_NO_MATCH, + DWARF_E_NO_FLAG, + DWARF_E_INVALID_OFFSET, + DWARF_E_NO_DEBUG_RANGES, +}; + + +/* This is the structure representing the debugging state. */ +struct Dwarf +{ + /* The underlying ELF file. */ + Elf *elf; + + /* The section data. */ + Elf_Data *sectiondata[IDX_last]; + + /* True if the file has a byte order different from the host. */ + bool other_byte_order; + + /* If true, we allocated the ELF descriptor ourselves. */ + bool free_elf; + + /* Information for traversing the .debug_pubnames section. This is + an array and separately allocated with malloc. */ + struct pubnames_s + { + Dwarf_Off cu_offset; + Dwarf_Off set_start; + unsigned int cu_header_size; + int address_len; + } *pubnames_sets; + size_t pubnames_nsets; + + /* Search tree for the CUs. */ + void *cu_tree; + Dwarf_Off next_cu_offset; + + /* Address ranges. */ + Dwarf_Aranges *aranges; + + /* Internal memory handling. This is basically a simplified + reimplementation of obstacks. Unfortunately the standard obstack + implementation is not usable in libraries. */ + struct libdw_memblock + { + size_t size; + size_t remaining; + struct libdw_memblock *prev; + char mem[0]; + } *mem_tail; + + /* Default size of allocated memory blocks. */ + size_t mem_default_size; + + /* Registered OOM handler. */ + Dwarf_OOM oom_handler; +}; + + +/* Abbreviation representation. */ +struct Dwarf_Abbrev +{ + unsigned int code; + unsigned int tag; + int has_children; + unsigned int attrcnt; + unsigned char *attrp; + Dwarf_Off offset; +}; + +#include "dwarf_abbrev_hash.h" + + +/* Files in line information records. */ +struct Dwarf_Files_s + { + Dwarf *dbg; + unsigned int nfiles; + struct Dwarf_Fileinfo_s + { + char *name; + Dwarf_Word mtime; + Dwarf_Word length; + } info[0]; + }; +typedef struct Dwarf_Fileinfo_s Dwarf_Fileinfo; + + +/* Representation of a row in the line table. */ +struct Dwarf_Lines_s + { + size_t nlines; + + struct Dwarf_Line_s + { + Dwarf_Addr addr; + unsigned int file; + int line; + unsigned short int column; + unsigned int is_stmt:1; + unsigned int basic_block:1; + unsigned int end_sequence:1; + unsigned int prologue_end:1; + unsigned int epilogue_begin:1; + + Dwarf_Files *files; + } info[0]; + }; + + +/* Representation of address ranges. */ +struct Dwarf_Aranges_s +{ + Dwarf *dbg; + size_t naranges; + + struct Dwarf_Arange_s + { + Dwarf_Addr addr; + Dwarf_Word length; + Dwarf_Off offset; + } info[0]; +}; + + +/* CU representation. */ +struct Dwarf_CU +{ + Dwarf *dbg; + Dwarf_Off start; + Dwarf_Off end; + uint8_t address_size; + uint8_t offset_size; + + /* Hash table for the abbreviations. */ + Dwarf_Abbrev_Hash abbrev_hash; + /* Offset of the first abbreviation. */ + size_t orig_abbrev_offset; + /* Offset past last read abbreviation. */ + size_t last_abbrev_offset; + + /* The srcline information. */ + Dwarf_Lines *lines; + + /* The source file information. */ + Dwarf_Files *files; + + /* Known location lists. */ + void *locs; +}; + + +/* Function information. */ +struct Dwarf_Func_s +{ + // XXX If we want to cache functions, we need to change this struct. + Dwarf_Die *die; + Dwarf_Die *cudie; +}; + + +/* Macro information. */ +struct Dwarf_Macro_s +{ + unsigned int opcode; + Dwarf_Word param1; + union + { + Dwarf_Word u; + const char *s; + } param2; +}; + + +/* We have to include the file at this point because the inline + functions access internals of the Dwarf structure. */ +#include "memory-access.h" + + +/* Set error value. */ +extern void __libdw_seterrno (int value) internal_function; + + +/* Memory handling, the easy parts. This macro does not do any locking. */ +#define libdw_alloc(dbg, type, tsize, cnt) \ + ({ struct libdw_memblock *_tail = (dbg)->mem_tail; \ + size_t _required = (tsize) * (cnt); \ + type *_result = (type *) (_tail->mem + (_tail->size - _tail->remaining));\ + size_t _padding = ((__alignof (type) \ + - ((uintptr_t) _result & (__alignof (type) - 1))) \ + & (__alignof (type) - 1)); \ + if (unlikely (_tail->remaining < _required + _padding)) \ + { \ + _result = (type *) __libdw_allocate (dbg, _required); \ + _tail = (dbg)->mem_tail; \ + } \ + else \ + { \ + _required += _padding; \ + _result = (type *) ((char *) _result + _padding); \ + } \ + _tail->remaining -= _required; \ + _result; }) + +#define libdw_typed_alloc(dbg, type) \ + libdw_alloc (dbg, type, sizeof (type), 1) + +/* Callback to allocate more. */ +extern void *__libdw_allocate (Dwarf *dbg, size_t minsize) + __attribute__ ((__malloc__)) __nonnull_attribute__ (1); + +/* Default OOM handler. */ +extern void __libdw_oom (void) __attribute ((noreturn, visibility ("hidden"))); + +/* Find CU for given offset. */ +extern struct Dwarf_CU *__libdw_findcu (Dwarf *dbg, Dwarf_Off offset) + __nonnull_attribute__ (1) internal_function; + +/* Return tag of given DIE. */ +extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu, + unsigned int code) + __nonnull_attribute__ (1) internal_function; + +/* Get abbreviation at given offset. */ +extern Dwarf_Abbrev *__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, + Dwarf_Off offset, size_t *lengthp, + Dwarf_Abbrev *result) + __nonnull_attribute__ (1) internal_function; + +/* Helper functions for form handling. */ +extern size_t __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, + unsigned int form, + const unsigned char *valp) + __nonnull_attribute__ (1, 2, 4) internal_function; + +/* Helper function to locate attribute. */ +extern unsigned char *__libdw_find_attr (Dwarf_Die *die, + unsigned int search_name, + unsigned int *codep, + unsigned int *formp) + __nonnull_attribute__ (1) internal_function; + +/* Helper function to access integer attribute. */ +extern int __libdw_func_intval (Dwarf_Func *func, int *linep, int attval) + __nonnull_attribute__ (1, 2) internal_function; + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int __dwarf_errno_internal (void); + + +/* Aliases to avoid PLTs. */ +INTDECL (dwarf_attr) +INTDECL (dwarf_attr_integrate) +INTDECL (dwarf_begin_elf) +INTDECL (dwarf_child) +INTDECL (dwarf_dieoffset) +INTDECL (dwarf_formaddr) +INTDECL (dwarf_formblock) +INTDECL (dwarf_formref) +INTDECL (dwarf_formref_die) +INTDECL (dwarf_formsdata) +INTDECL (dwarf_formstring) +INTDECL (dwarf_formudata) +INTDECL (dwarf_getarange_addr) +INTDECL (dwarf_getarangeinfo) +INTDECL (dwarf_getaranges) +INTDECL (dwarf_getsrcfiles) +INTDECL (dwarf_getsrclines) +INTDECL (dwarf_hasattr) +INTDECL (dwarf_haschildren) +INTDECL (dwarf_haspc) +INTDECL (dwarf_highpc) +INTDECL (dwarf_lowpc) +INTDECL (dwarf_nextcu) +INTDECL (dwarf_offdie) +INTDECL (dwarf_siblingof) +INTDECL (dwarf_tag) + +#endif /* libdwP.h */ diff --git a/libdw/libdw_alloc.c b/libdw/libdw_alloc.c new file mode 100644 index 00000000..1c53d366 --- /dev/null +++ b/libdw/libdw_alloc.c @@ -0,0 +1,59 @@ +/* Memory handling for libdw. + Copyright (C) 2003, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include "libdwP.h" + + +void * +__libdw_allocate (Dwarf *dbg, size_t minsize) +{ + size_t size = MAX (dbg->mem_default_size, + 2 * minsize + offsetof (struct libdw_memblock, mem)); + struct libdw_memblock *newp = malloc (size); + if (newp == NULL) + dbg->oom_handler (); + + newp->size = newp->remaining = size - offsetof (struct libdw_memblock, mem); + + newp->prev = dbg->mem_tail; + dbg->mem_tail = newp; + + return newp->mem; +} + + +Dwarf_OOM +dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler) +{ + Dwarf_OOM old = dbg->oom_handler; + dbg->oom_handler = handler; + return old; +} + + +void +__attribute ((noreturn, visibility ("hidden"))) +__libdw_oom (void) +{ + while (1) + error (EXIT_FAILURE, ENOMEM, "libdw"); +} diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c new file mode 100644 index 00000000..c1d3a451 --- /dev/null +++ b/libdw/libdw_findcu.c @@ -0,0 +1,110 @@ +/* Find CU for given offset. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "libdwP.h" + + +static int +findcu_cb (const void *arg1, const void *arg2) +{ + struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1; + struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2; + + /* Find out which of the two arguments is the search value. It has + end offset 0. */ + if (cu1->end == 0) + { + if (cu1->start < cu2->start) + return -1; + if (cu1->start >= cu2->end) + return 1; + } + else + { + if (cu2->start < cu1->start) + return 1; + if (cu2->start >= cu1->end) + return -1; + } + + return 0; +} + + +struct Dwarf_CU * +__libdw_findcu (dbg, start) + Dwarf *dbg; + Dwarf_Off start; +{ + /* Maybe we already know that CU. */ + struct Dwarf_CU fake = { .start = start, .end = 0 }; + struct Dwarf_CU **found = tfind (&fake, &dbg->cu_tree, findcu_cb); + if (found != NULL) + return *found; + + if (start < dbg->next_cu_offset) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* No. Then read more CUs. */ + while (1) + { + Dwarf_Off oldoff = dbg->next_cu_offset; + uint8_t address_size; + uint8_t offset_size; + Dwarf_Off abbrev_offset; + + if (INTUSE(dwarf_nextcu) (dbg, oldoff, &dbg->next_cu_offset, NULL, + &abbrev_offset, &address_size, &offset_size) + != 0) + /* No more entries. */ + return NULL; + + /* Create an entry for this CU. */ + struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU); + + newp->dbg = dbg; + newp->start = oldoff; + newp->end = dbg->next_cu_offset; + newp->address_size = address_size; + newp->offset_size = offset_size; + Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41); + newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset; + newp->lines = NULL; + newp->locs = NULL; + + /* Add the new entry to the search tree. */ + if (tsearch (newp, &dbg->cu_tree, findcu_cb) == NULL) + { + /* Something went wrong. Unfo the operation. */ + dbg->next_cu_offset = oldoff; + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + /* Is this the one we are looking for? */ + if (start < dbg->next_cu_offset) + // XXX Match exact offset. + return newp; + } + /* NOTREACHED */ +} diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c new file mode 100644 index 00000000..95d47140 --- /dev/null +++ b/libdw/libdw_form.c @@ -0,0 +1,112 @@ +/* Helper functions for form handling. + Copyright (C) 2003, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libdwP.h" + + +size_t +internal_function_def +__libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form, + const unsigned char *valp) +{ + const unsigned char *saved; + Dwarf_Word u128; + size_t result; + + switch (form) + { + case DW_FORM_addr: + result = cu->address_size; + break; + + case DW_FORM_strp: + case DW_FORM_ref_addr: + result = cu->offset_size; + break; + + case DW_FORM_block1: + result = *valp + 1; + break; + + case DW_FORM_block2: + result = read_2ubyte_unaligned (dbg, valp) + 2; + break; + + case DW_FORM_block4: + result = read_4ubyte_unaligned (dbg, valp) + 4; + break; + + case DW_FORM_block: + saved = valp; + get_uleb128 (u128, valp); + result = u128 + (valp - saved); + break; + + case DW_FORM_ref1: + case DW_FORM_data1: + case DW_FORM_flag: + result = 1; + break; + + case DW_FORM_data2: + case DW_FORM_ref2: + result = 2; + break; + + case DW_FORM_data4: + case DW_FORM_ref4: + result = 4; + break; + + case DW_FORM_data8: + case DW_FORM_ref8: + result = 8; + break; + + case DW_FORM_string: + result = strlen ((char *) valp) + 1; + break; + + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + saved = valp; + get_uleb128 (u128, valp); + result = valp - saved; + break; + + case DW_FORM_indirect: + saved = valp; + get_uleb128 (u128, valp); + // XXX Is this really correct? + result = __libdw_form_val_len (dbg, cu, u128, valp); + if (result != (size_t) -1) + result += valp - saved; + break; + + default: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + result = (size_t) -1l; + break; + } + + return result; +} diff --git a/libdw/memory-access.c b/libdw/memory-access.c new file mode 100644 index 00000000..04899a81 --- /dev/null +++ b/libdw/memory-access.c @@ -0,0 +1,35 @@ +/* Out of line functions for memory-access.h macros. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include "libdwP.h" +#include "memory-access.h" + +uint64_t +internal_function_def +__libdw_get_uleb128 (uint64_t acc, unsigned int i, const unsigned char **addrp) +{ + unsigned char __b; + get_uleb128_rest_return (acc, i, addrp); +} + +int64_t +internal_function_def +__libdw_get_sleb128 (int64_t acc, unsigned int i, const unsigned char **addrp) +{ + unsigned char __b; + int64_t _v = acc; + get_sleb128_rest_return (acc, i, addrp); +} diff --git a/libdw/memory-access.h b/libdw/memory-access.h new file mode 100644 index 00000000..8efd8993 --- /dev/null +++ b/libdw/memory-access.h @@ -0,0 +1,240 @@ +/* Unaligned memory access functionality. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _MEMORY_ACCESS_H +#define _MEMORY_ACCESS_H 1 + +#include +#include +#include + + +/* Number decoding macros. See 7.6 Variable Length Data. */ + +#define get_uleb128_step(var, addr, nth, break) \ + __b = *(addr)++; \ + var |= (uintmax_t) (__b & 0x7f) << (nth * 7); \ + if (likely ((__b & 0x80) == 0)) \ + break + +#define get_uleb128(var, addr) \ + do { \ + unsigned char __b; \ + var = 0; \ + get_uleb128_step (var, addr, 0, break); \ + var = __libdw_get_uleb128 (var, 1, &(addr)); \ + } while (0) + +#define get_uleb128_rest_return(var, i, addrp) \ + do { \ + for (; i < 10; ++i) \ + { \ + get_uleb128_step (var, *addrp, i, return var); \ + } \ + /* Other implementations set VALUE to UINT_MAX in this \ + case. So we better do this as well. */ \ + return UINT64_MAX; \ + } while (0) + +/* The signed case is similar, but we sign-extend the result. */ + +#define get_sleb128_step(var, addr, nth, break) \ + __b = *(addr)++; \ + _v |= (uint64_t) (__b & 0x7f) << (nth * 7); \ + if (likely ((__b & 0x80) == 0)) \ + { \ + var = (_v << (64 - (nth * 7) - 7) >> (64 - (nth * 7) - 7)); \ + break; \ + } \ + else do {} while (0) + +#define get_sleb128(var, addr) \ + do { \ + unsigned char __b; \ + int64_t _v = 0; \ + get_sleb128_step (var, addr, 0, break); \ + var = __libdw_get_sleb128 (_v, 1, &(addr)); \ + } while (0) + +#define get_sleb128_rest_return(var, i, addrp) \ + do { \ + for (; i < 9; ++i) \ + { \ + get_sleb128_step (var, *addrp, i, return var); \ + } \ + /* Other implementations set VALUE to INT_MAX in this \ + case. So we better do this as well. */ \ + return INT64_MAX; \ + } while (0) + +#ifdef IS_LIBDW +extern uint64_t __libdw_get_uleb128 (uint64_t acc, unsigned int i, + const unsigned char **addrp) + internal_function attribute_hidden; +extern int64_t __libdw_get_sleb128 (int64_t acc, unsigned int i, + const unsigned char **addrp) + internal_function attribute_hidden; +#else +static uint64_t +__attribute__ ((unused)) +__libdw_get_uleb128 (uint64_t acc, unsigned int i, const unsigned char **addrp) +{ + unsigned char __b; + get_uleb128_rest_return (acc, i, addrp); +} +static int64_t +__attribute__ ((unused)) +__libdw_get_sleb128 (int64_t acc, unsigned int i, const unsigned char **addrp) +{ + unsigned char __b; + int64_t _v = acc; + get_sleb128_rest_return (acc, i, addrp); +} +#endif + + +/* We use simple memory access functions in case the hardware allows it. + The caller has to make sure we don't have alias problems. */ +#if ALLOW_UNALIGNED + +# define read_2ubyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? bswap_16 (*((const uint16_t *) (Addr))) \ + : *((const uint16_t *) (Addr))) +# define read_2sbyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? (int16_t) bswap_16 (*((const int16_t *) (Addr))) \ + : *((const int16_t *) (Addr))) + +# define read_4ubyte_unaligned_noncvt(Addr) \ + *((const uint32_t *) (Addr)) +# define read_4ubyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? bswap_32 (*((const uint32_t *) (Addr))) \ + : *((const uint32_t *) (Addr))) +# define read_4sbyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \ + : *((const int32_t *) (Addr))) + +# define read_8ubyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? bswap_64 (*((const uint64_t *) (Addr))) \ + : *((const uint64_t *) (Addr))) +# define read_8sbyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \ + : *((const int64_t *) (Addr))) + +#else + +union unaligned + { + void *p; + uint16_t u2; + uint32_t u4; + uint64_t u8; + int16_t s2; + int32_t s4; + int64_t s8; + } __attribute__ ((packed)); + +static inline uint16_t +read_2ubyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return bswap_16 (up->u2); + return up->u2; +} +static inline int16_t +read_2sbyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return (int16_t) bswap_16 (up->u2); + return up->s2; +} + +static inline uint32_t +read_4ubyte_unaligned_noncvt (const void *p) +{ + const union unaligned *up = p; + return up->u4; +} +static inline uint32_t +read_4ubyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return bswap_32 (up->u4); + return up->u4; +} +static inline int32_t +read_4sbyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return (int32_t) bswap_32 (up->u4); + return up->s4; +} + +static inline uint64_t +read_8ubyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return bswap_64 (up->u8); + return up->u8; +} +static inline int64_t +read_8sbyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return (int64_t) bswap_64 (up->u8); + return up->s8; +} + +#endif /* allow unaligned */ + + +#define read_2ubyte_unaligned_inc(Dbg, Addr) \ + ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \ + t_; }) +#define read_2sbyte_unaligned_inc(Dbg, Addr) \ + ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \ + t_; }) + +#define read_4ubyte_unaligned_inc(Dbg, Addr) \ + ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \ + t_; }) +#define read_4sbyte_unaligned_inc(Dbg, Addr) \ + ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \ + t_; }) + +#define read_8ubyte_unaligned_inc(Dbg, Addr) \ + ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \ + t_; }) +#define read_8sbyte_unaligned_inc(Dbg, Addr) \ + ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \ + t_; }) + +#endif /* memory-access.h */ diff --git a/libdwarf/.cvsignore b/libdwarf/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/libdwarf/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/libdwarf/AVAILABLE b/libdwarf/AVAILABLE new file mode 100644 index 00000000..642dd27e --- /dev/null +++ b/libdwarf/AVAILABLE @@ -0,0 +1,136 @@ +Data Types: + + Dwarf_Bool + Dwarf_Off + Dwarf_Unsigned + Dwarf_Half + Dwarf_Small + Dwarf_Signed + Dwarf_Addr + Dwarf_Ptr + Dwarf_Handler + + Dwarf_Debug + Dwarf_Die + Dwarf_Line + Dwarf_Global + Dwarf_Loc + Dwarf_Locdesc + Dwarf_Block + Dwarf_Error + Dwarf_Attribute + Dwarf_Fde + Dwarf_Cie + Dwarf_Arange + + NOT!!!: + + Dwarf_Frame_Op + Dwarf_Macro_Details + + Dwarf_Weak + Dwarf_Func + Dwarf_Type + Dwarf_Var + Dwarf_Abbrev + +Functions: + + dwarf_init() + dwarf_elf_init() + dwarf_get_elf() + dwarf_finish() + dwarf_next_cu_header() + dwarf_siblingof() + dwarf_child() + dwarf_offdie() + dwarf_tag() + dwarf_dieoffset() + dwarf_die_CU_offset() + dwarf_diename() + dwarf_attrlist() + dwarf_srclang() + dwarf_arrayorder() + dwarf_hasform() + dwarf_whatattr() + dwarf_formref() + dwarf_global_formref() + dwarf_formaddr() + dwarf_formflag() + dwarf_hasattr() + dwarf_attr() + dwarf_lowpc() + dwarf_highpc() + dwarf_bytesize() + dwarf_bitsize() + dwarf_bitoffset() + dwarf_formudata() + dwarf_formblock() + dwarf_formstring() + dwarf_loclist() + dwarf_srclines() + dwarf_srcfiles() + dwarf_linebeginstatement() + dwarf_lineendsequence() + dwarf_lineno() + dwarf_lineaddr() + dwarf_lineoff() + dwarf_linesrc() + dwarf_lineblock() + dwarf_get_globals() + dwarf_globname() + dwarf_global_die_offset() + dwarf_global_cu_offset() + dwarf_global_name_offsets() + dwarf_find_macro_value_start() + dwarf_get_fde_list_eh() + dwarf_get_fde_range() + dwarf_get_cie_of_fde() + dwarf_get_cie_info() + dwarf_get_fde_instr_bytes() + dwarf_get_fde_n() + dwarf_get_fde_at_pc() + dwarf_get_str() + dwarf_get_aranges() + dwarf_get_cu_die_offset() + dwarf_get_loclist_entry() + dwarf_get_abbrev() + dwarf_get_abbrev_tag() + dwarf_get_abbrev_code() + dwarf_get_abbrev_children_flag() + dwarf_get_abbrev_entry() + dwarf_get_arange_info() + dwarf_get_address_size() + dwarf_errno() + dwarf_errmsg() + dwarf_seterrhand() + dwarf_seterrarg() + dwarf_dealloc() + + NOT!!!: + + dwarf_get_weaks() + dwarf_weakname() + dwarf_weak_die_offset() + dwarf_weak_cu_offset() + dwarf_weak_name_offsets() + dwarf_get_funcs() + dwarf_funcname() + dwarf_func_die_offset() + dwarf_func_cu_offset() + dwarf_func_name_offsets() + dwarf_get_types() + dwarf_typename() + dwarf_type_die_offset() + dwarf_type_cu_offset() + dwarf_type_name_offsets() + dwarf_get_vars() + dwarf_varname() + dwarf_var_die_offset() + dwarf_var_cu_offset() + dwarf_var_name_offsets() + dwarf_get_fde_list() + dwarf_get_fde_for_die() + dwarf_get_fde_info_for_reg() <<------- + dwarf_get_fde_info_for_all_regs() + dwarf_expand_frame_instructions() <<------- diff --git a/libdwarf/ChangeLog b/libdwarf/ChangeLog new file mode 100644 index 00000000..c46ffcb6 --- /dev/null +++ b/libdwarf/ChangeLog @@ -0,0 +1,3 @@ +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/libdwarf/Makefile.am b/libdwarf/Makefile.am new file mode 100644 index 00000000..8af7a674 --- /dev/null +++ b/libdwarf/Makefile.am @@ -0,0 +1,103 @@ +## Process this file with automake to create Makefile.in -*-Makefile-*- +## Configure input file for elfutils. +## +## Copyright (C) 2000, 2001, 2002 Red Hat, Inc. +## +## This program is Open Source software; you can redistribute it and/or +## modify it under the terms of the Open Software License version 1.0 as +## published by the Open Source Initiative. +## +## You should have received a copy of the Open Software License along +## with this program; if not, you may obtain a copy of the Open Software +## License version 1.0 from http://www.opensource.org/licenses/osl.php or +## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +## 3001 King Ranch Road, Ukiah, CA 95482. +## +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -DDWARF_DEBUG +AM_CFLAGS = -Wall -Werror +INCLUDES = -I. -I$(srcdir) -I$(srcdir)/../libelf -I.. -I$(srcdir)/../lib +VERSION = 1 + +lib_LIBRARIES = libdwarf.a +noinst_LIBRARIES = libdwarf_pic.a +noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so) +include_HEADERS = dwarf.h +euincludedir = ${includedir}/elfutils +euinclude_HEADERS = libdwarf.h + +libdwarf_a_SOURCES = dwarf_init.c dwarf_elf_init.c dwarf_get_elf.c \ + dwarf_finish.c \ + dwarf_next_cu_header.c dwarf_siblingof.c dwarf_child.c \ + dwarf_offdie.c \ + dwarf_tag.c dwarf_dieoffset.c dwarf_die_CU_offset.c \ + dwarf_diename.c dwarf_attrlist.c dwarf_hasattr.c \ + dwarf_attr.c dwarf_lowpc.c dwarf_highpc.c \ + dwarf_getconstant.c \ + dwarf_bytesize.c dwarf_bitsize.c dwarf_bitoffset.c \ + dwarf_srclang.c dwarf_whatattr.c dwarf_arrayorder.c \ + dwarf_hasform.c dwarf_whatform.c dwarf_formref.c \ + dwarf_global_formref.c dwarf_formaddr.c \ + dwarf_formstring.c dwarf_loclist.c \ + dwarf_formflag.c dwarf_formudata.c dwarf_formsdata.c \ + dwarf_formblock.c \ + dwarf_srclines.c dwarf_srcfiles.c \ + dwarf_linebeginstatement.c dwarf_lineendsequence.c \ + dwarf_lineno.c dwarf_lineaddr.c dwarf_lineoff.c \ + dwarf_linesrc.c dwarf_lineblock.c \ + dwarf_lineprologueend.c dwarf_lineepiloguebegin.c \ + dwarf_get_globals.c dwarf_globname.c \ + dwarf_global_die_offset.c dwarf_global_cu_offset.c \ + dwarf_global_name_offsets.c \ + dwarf_error.c dwarf_errno.c dwarf_errmsg.c \ + dwarf_abbrev_hash.c dwarf_getabbrev.c dwarf_form.c \ + dwarf_find_macro_value_start.c dwarf_get_str.c \ + dwarf_get_aranges.c dwarf_get_arange.c \ + dwarf_get_cu_die_offset.c dwarf_get_arange_info.c \ + dwarf_get_fde_list_eh.c dwarf_get_cie_of_fde.c \ + dwarf_get_cie_info.c dwarf_get_fde_instr_bytes.c \ + dwarf_get_fde_range.c dwarf_get_fde_n.c \ + dwarf_get_fde_at_pc.c \ + dwarf_get_loclist_entry.c \ + dwarf_get_abbrev.c dwarf_get_abbrev_tag.c \ + dwarf_get_abbrev_code.c dwarf_get_abbrev_children_flag.c\ + dwarf_get_abbrev_entry.c \ + dwarf_get_address_size.c \ + dwarf_seterrhand.c dwarf_seterrarg.c \ + dwarf_dealloc.c + +libdwarf_pic_a_SOURCES = +am_libdwarf_pic_a_OBJECTS = $(libdwarf_a_SOURCES:.c=.os) + +libdwarf_so_SOURCES = +libdwarf.so: libdwarf_pic.a libdwarf.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libdwarf.map,--no-undefined \ + -Wl,--soname,$@.$(VERSION),-z,defs \ + ../libelf/libelf.so + ln -fs $@ $@.$(VERSION) + + +%.os: %.c %.o + if $(COMPILE) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \ + -MF "$(DEPDIR)/$*.Tpo" `test -f '$<' || echo '$(srcdir)/'`$<; \ + then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ + rm -f "$(DEPDIR)/$*.Tpo"; \ + else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ + fi + +install: install-am libdwarf.so + $(mkinstalldirs) $(DESTDIR)$(libdir) + $(INSTALL_PROGRAM) libdwarf.so $(DESTDIR)$(libdir)/libdwarf-$(PACKAGE_VERSION).so + ln -fs libdwarf-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libdwarf.so.$(VERSION) + ln -fs libdwarf.so.$(VERSION) $(DESTDIR)$(libdir)/libdwarf.so + +uninstall: uninstall-am + rm -f $(DESTDIR)$(libdir)/libdwarf-$(PACKAGE_VERSION).so + rm -f $(DESTDIR)$(libdir)/libdwarf.so.$(VERSION) + rm -f $(DESTDIR)$(libdir)/libdwarf.so + rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils + +noinst_HEADERS = libdwarfP.h memory-access.h dwarf_abbrev_hash.h +EXTRA_DIST = AVAILABLE libdwarf.map + +CLEANFILES = $(am_libdwarf_pic_a_OBJECTS) diff --git a/libdwarf/dwarf.h b/libdwarf/dwarf.h new file mode 100644 index 00000000..81bdcc45 --- /dev/null +++ b/libdwarf/dwarf.h @@ -0,0 +1,549 @@ +/* This file defines standard DWARF types, structures, and macros. + Copyright (C) 2000, 2002 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _DWARF_H +#define _DWARF_H 1 + +/* DWARF tags. */ +enum + { + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_param = 0x2f, + DW_TAG_template_value_param = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + DW_TAG_lo_user = 0x4080, + DW_TAG_MIPS_loop = 0x4081, + DW_TAG_format_label = 0x4101, + DW_TAG_function_template = 0x4102, + DW_TAG_class_template = 0x4103, + DW_TAG_hi_user = 0xffff + }; + + +/* Children determination encodings. */ +enum + { + DW_CHILDREN_no = 0, + DW_CHILDREN_yes = 1 + }; + + +/* DWARF attributes encodings. */ +enum + { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_stride_size = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_items = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + DW_AT_lo_user = 0x2000, + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + DW_AT_MIPS_stride_byte = 0x200c, + DW_AT_MIPS_stride_elem = 0x200d, + DW_AT_MIPS_ptr_dopetype = 0x200e, + DW_AT_MIPS_allocatable_dopetype = 0x200f, + DW_AT_MIPS_assumed_shape_dopetype = 0x2010, + DW_AT_MIPS_assumed_size = 0x2011, + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_hi_user = 0x3fff + }; + + +/* DWARF form encodings. */ +enum + { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16 + }; + + +/* DWARF location operation encodings. */ +enum + { + DW_OP_addr = 0x03, /* Constant address. */ + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, /* Unsigned 1-byte constant. */ + DW_OP_const1s = 0x09, /* Signed 1-byte constant. */ + DW_OP_const2u = 0x0a, /* Unsigned 2-byte constant. */ + DW_OP_const2s = 0x0b, /* Signed 2-byte constant. */ + DW_OP_const4u = 0x0c, /* Unsigned 4-byte constant. */ + DW_OP_const4s = 0x0d, /* Signed 4-byte constant. */ + DW_OP_const8u = 0x0e, /* Unsigned 8-byte constant. */ + DW_OP_const8s = 0x0f, /* Signed 8-byte constant. */ + DW_OP_constu = 0x10, /* Unsigned LEB128 constant. */ + DW_OP_consts = 0x11, /* Signed LEB128 constant. */ + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, /* 1-byte stack index. */ + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, /* Unsigned LEB128 addend. */ + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, /* Signed 2-byte constant. */ + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_skip = 0x2f, /* Signed 2-byte constant. */ + DW_OP_lit0 = 0x30, /* Literal 0. */ + DW_OP_lit1 = 0x31, /* Literal 1. */ + DW_OP_lit2 = 0x32, /* Literal 2. */ + DW_OP_lit3 = 0x33, /* Literal 3. */ + DW_OP_lit4 = 0x34, /* Literal 4. */ + DW_OP_lit5 = 0x35, /* Literal 5. */ + DW_OP_lit6 = 0x36, /* Literal 6. */ + DW_OP_lit7 = 0x37, /* Literal 7. */ + DW_OP_lit8 = 0x38, /* Literal 8. */ + DW_OP_lit9 = 0x39, /* Literal 9. */ + DW_OP_lit10 = 0x3a, /* Literal 10. */ + DW_OP_lit11 = 0x3b, /* Literal 11. */ + DW_OP_lit12 = 0x3c, /* Literal 12. */ + DW_OP_lit13 = 0x3d, /* Literal 13. */ + DW_OP_lit14 = 0x3e, /* Literal 14. */ + DW_OP_lit15 = 0x3f, /* Literal 15. */ + DW_OP_lit16 = 0x40, /* Literal 16. */ + DW_OP_lit17 = 0x41, /* Literal 17. */ + DW_OP_lit18 = 0x42, /* Literal 18. */ + DW_OP_lit19 = 0x43, /* Literal 19. */ + DW_OP_lit20 = 0x44, /* Literal 20. */ + DW_OP_lit21 = 0x45, /* Literal 21. */ + DW_OP_lit22 = 0x46, /* Literal 22. */ + DW_OP_lit23 = 0x47, /* Literal 23. */ + DW_OP_lit24 = 0x48, /* Literal 24. */ + DW_OP_lit25 = 0x49, /* Literal 25. */ + DW_OP_lit26 = 0x4a, /* Literal 26. */ + DW_OP_lit27 = 0x4b, /* Literal 27. */ + DW_OP_lit28 = 0x4c, /* Literal 28. */ + DW_OP_lit29 = 0x4d, /* Literal 29. */ + DW_OP_lit30 = 0x4e, /* Literal 30. */ + DW_OP_lit31 = 0x4f, /* Literal 31. */ + DW_OP_reg0 = 0x50, /* Register 0. */ + DW_OP_reg1 = 0x51, /* Register 1. */ + DW_OP_reg2 = 0x52, /* Register 2. */ + DW_OP_reg3 = 0x53, /* Register 3. */ + DW_OP_reg4 = 0x54, /* Register 4. */ + DW_OP_reg5 = 0x55, /* Register 5. */ + DW_OP_reg6 = 0x56, /* Register 6. */ + DW_OP_reg7 = 0x57, /* Register 7. */ + DW_OP_reg8 = 0x58, /* Register 8. */ + DW_OP_reg9 = 0x59, /* Register 9. */ + DW_OP_reg10 = 0x5a, /* Register 10. */ + DW_OP_reg11 = 0x5b, /* Register 11. */ + DW_OP_reg12 = 0x5c, /* Register 12. */ + DW_OP_reg13 = 0x5d, /* Register 13. */ + DW_OP_reg14 = 0x5e, /* Register 14. */ + DW_OP_reg15 = 0x5f, /* Register 15. */ + DW_OP_reg16 = 0x60, /* Register 16. */ + DW_OP_reg17 = 0x61, /* Register 17. */ + DW_OP_reg18 = 0x62, /* Register 18. */ + DW_OP_reg19 = 0x63, /* Register 19. */ + DW_OP_reg20 = 0x64, /* Register 20. */ + DW_OP_reg21 = 0x65, /* Register 21. */ + DW_OP_reg22 = 0x66, /* Register 22. */ + DW_OP_reg23 = 0x67, /* Register 24. */ + DW_OP_reg24 = 0x68, /* Register 24. */ + DW_OP_reg25 = 0x69, /* Register 25. */ + DW_OP_reg26 = 0x6a, /* Register 26. */ + DW_OP_reg27 = 0x6b, /* Register 27. */ + DW_OP_reg28 = 0x6c, /* Register 28. */ + DW_OP_reg29 = 0x6d, /* Register 29. */ + DW_OP_reg30 = 0x6e, /* Register 30. */ + DW_OP_reg31 = 0x6f, /* Register 31. */ + DW_OP_breg0 = 0x70, /* Base register 0. */ + DW_OP_breg1 = 0x71, /* Base register 1. */ + DW_OP_breg2 = 0x72, /* Base register 2. */ + DW_OP_breg3 = 0x73, /* Base register 3. */ + DW_OP_breg4 = 0x74, /* Base register 4. */ + DW_OP_breg5 = 0x75, /* Base register 5. */ + DW_OP_breg6 = 0x76, /* Base register 6. */ + DW_OP_breg7 = 0x77, /* Base register 7. */ + DW_OP_breg8 = 0x78, /* Base register 8. */ + DW_OP_breg9 = 0x79, /* Base register 9. */ + DW_OP_breg10 = 0x7a, /* Base register 10. */ + DW_OP_breg11 = 0x7b, /* Base register 11. */ + DW_OP_breg12 = 0x7c, /* Base register 12. */ + DW_OP_breg13 = 0x7d, /* Base register 13. */ + DW_OP_breg14 = 0x7e, /* Base register 14. */ + DW_OP_breg15 = 0x7f, /* Base register 15. */ + DW_OP_breg16 = 0x80, /* Base register 16. */ + DW_OP_breg17 = 0x81, /* Base register 17. */ + DW_OP_breg18 = 0x82, /* Base register 18. */ + DW_OP_breg19 = 0x83, /* Base register 19. */ + DW_OP_breg20 = 0x84, /* Base register 20. */ + DW_OP_breg21 = 0x85, /* Base register 21. */ + DW_OP_breg22 = 0x86, /* Base register 22. */ + DW_OP_breg23 = 0x87, /* Base register 23. */ + DW_OP_breg24 = 0x88, /* Base register 24. */ + DW_OP_breg25 = 0x89, /* Base register 25. */ + DW_OP_breg26 = 0x8a, /* Base register 26. */ + DW_OP_breg27 = 0x8b, /* Base register 27. */ + DW_OP_breg28 = 0x8c, /* Base register 28. */ + DW_OP_breg29 = 0x8d, /* Base register 29. */ + DW_OP_breg30 = 0x8e, /* Base register 30. */ + DW_OP_breg31 = 0x8f, /* Base register 31. */ + DW_OP_regx = 0x90, /* Unsigned LEB128 register. */ + DW_OP_fbreg = 0x91, /* Signed LEB128 register. */ + DW_OP_bregx = 0x92, /* ULEB128 register followed by SLEB128 off. */ + DW_OP_piece = 0x93, /* ULEB128 size of piece addressed. */ + DW_OP_deref_size = 0x94, /* 1-byte size of data retrieved. */ + DW_OP_xderef_size = 0x95, /* 1-byte size of data retrieved. */ + DW_OP_nop = 0x96, + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + + DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */ + DW_OP_hi_user = 0xff /* Implementation-defined range end. */ + }; + + +/* DWARF base type encodings. */ +enum + { + DW_ATE_void = 0x0, + DW_ATE_address = 0x1, + DW_ATE_boolean = 0x2, + DW_ATE_complex_float = 0x3, + DW_ATE_float = 0x4, + DW_ATE_signed = 0x5, + DW_ATE_signed_char = 0x6, + DW_ATE_unsigned = 0x7, + DW_ATE_unsigned_char = 0x8, + + DW_ATE_lo_user = 0x80, + DW_ATE_hi_user = 0xff + }; + + +/* DWARF accessibility encodings. */ +enum + { + DW_ACCESS_public = 1, + DW_ACCESS_protected = 2, + DW_ACCESS_private = 3 + }; + + +/* DWARF visibility encodings. */ +enum + { + DW_VIS_local = 1, + DW_VIS_exported = 2, + DW_VIS_qualified = 3 + }; + + +/* DWARF virtuality encodings. */ +enum + { + DW_VIRTUALITY_none = 0, + DW_VIRTUALITY_virtual = 1, + DW_VIRTUALITY_pure_virtual = 2 + }; + + +/* DWARF language encodings. */ +enum + { + DW_LANG_C89 = 0x0001, + DW_LANG_C = 0x0002, + DW_LANG_Ada83 = 0x0003, + DW_LANG_C_plus_plus = 0x0004, + DW_LANG_Cobol74 = 0x0005, + DW_LANG_Cobol85 = 0x0006, + DW_LANG_Fortran77 = 0x0007, + DW_LANG_Fortran90 = 0x0008, + DW_LANG_Pascal83 = 0x0009, + DW_LANG_Modula2 = 0x000a, + DW_LANG_Java = 0x000b, + DW_LANG_C99 = 0x000c, + DW_LANG_Ada95 = 0x000d, + DW_LANG_Fortran95 = 0x000e, + DW_LANG_PL1 = 0x000f, + DW_LANG_lo_user = 0x8000, + DW_LANG_Mips_Assembler = 0x8001, + DW_LANG_hi_user = 0xffff + }; + + +/* DWARF identifier case encodings. */ +enum + { + DW_ID_case_sensitive = 0, + DW_ID_up_case = 1, + DW_ID_down_case = 2, + DW_ID_case_insensitive = 3 + }; + + +/* DWARF calling conventions encodings. */ +enum + { + DW_CC_normal = 0x1, + DW_CC_program = 0x2, + DW_CC_nocall = 0x3, + DW_CC_lo_user = 0x40, + DW_CC_hi_user = 0xff + }; + + +/* DWARF inline encodings. */ +enum + { + DW_INL_not_inlined = 0, + DW_INL_inlined = 1, + DW_INL_declared_not_inlined = 2, + DW_INL_declared_inlined = 3 + }; + + +/* DWARF ordering encodings. */ +enum + { + DW_ORD_row_major = 0, + DW_ORD_col_major = 1 + }; + + +/* DWARF discriminant descriptor encodings. */ +enum + { + DW_DSC_label = 0, + DW_DSC_range = 1 + }; + + +/* DWARF standard opcode encodings. */ +enum + { + DW_LNS_copy = 1, + DW_LNS_advance_pc = 2, + DW_LNS_advance_line = 3, + DW_LNS_set_file = 4, + DW_LNS_set_column = 5, + DW_LNS_negate_stmt = 6, + DW_LNS_set_basic_block = 7, + DW_LNS_const_add_pc = 8, + DW_LNS_fixed_advance_pc = 9, + DW_LNS_set_prologue_end = 10, + DW_LNS_set_epilog_begin = 11 + }; + + +/* DWARF extended opcide encodings. */ +enum + { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3 + }; + + +/* DWARF macinfo type encodings. */ +enum + { + DW_MACINFO_define = 1, + DW_MACINFO_undef = 2, + DW_MACINFO_start_file = 3, + DW_MACINFO_end_file = 4, + DW_MACINFO_vendor_ext = 255 + }; + + +/* DWARF call frame instruction encodings. */ +enum + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_extended = 0, + + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + DW_CFA_low_user = 0x1c, + DW_CFA_MIPS_advance_loc8 = 0x1d, + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_high_user = 0x3f + }; + + +/* DWARF XXX. */ +#define DW_ADDR_none 0 + +#endif /* dwarf.h */ diff --git a/libdwarf/dwarf_abbrev_hash.c b/libdwarf/dwarf_abbrev_hash.c new file mode 100644 index 00000000..a1964498 --- /dev/null +++ b/libdwarf/dwarf_abbrev_hash.c @@ -0,0 +1,29 @@ +/* Implementation of hash table for DWARF .debug_abbrev section content. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#define NO_UNDEF +#include "libdwarfP.h" + +#define next_prime __libdwarf_next_prime +extern size_t next_prime (size_t) attribute_hidden; + +#include + +#undef next_prime +#define next_prime attribute_hidden __libdwarf_next_prime +#include "../lib/next_prime.c" diff --git a/libdwarf/dwarf_abbrev_hash.h b/libdwarf/dwarf_abbrev_hash.h new file mode 100644 index 00000000..45c23462 --- /dev/null +++ b/libdwarf/dwarf_abbrev_hash.h @@ -0,0 +1,24 @@ +/* Hash table for DWARF .debug_abbrev section content. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _DWARF_ABBREV_HASH_H +#define _DWARF_ABBREV_HASH_H 1 + +#define NAME Dwarf_Abbrev_Hash +#define TYPE Dwarf_Abbrev +#define COMPARE(a, b) (0) + +#include + +#endif /* dwarf_abbrev_hash.h */ diff --git a/libdwarf/dwarf_arrayorder.c b/libdwarf/dwarf_arrayorder.c new file mode 100644 index 00000000..88f30800 --- /dev/null +++ b/libdwarf/dwarf_arrayorder.c @@ -0,0 +1,31 @@ +/* Return array ordering information associated with die. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_arrayorder (die, return_order, error) + Dwarf_Die die; + Dwarf_Unsigned *return_order; + Dwarf_Error *error; +{ + return __libdwarf_getconstant (die, DW_AT_ordering, return_order, error); +} diff --git a/libdwarf/dwarf_attr.c b/libdwarf/dwarf_attr.c new file mode 100644 index 00000000..f1b20f4d --- /dev/null +++ b/libdwarf/dwarf_attr.c @@ -0,0 +1,113 @@ +/* Return die attribute with specified of given type. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_attr (die, attr, return_attr, error) + Dwarf_Die die; + Dwarf_Half attr; + Dwarf_Attribute *return_attr; + Dwarf_Error *error; +{ + Dwarf_Debug dbg = die->cu->dbg; + Dwarf_Small *die_addr; + Dwarf_Word u128; + Dwarf_Abbrev abbrev; + Dwarf_Small *attrp; + + /* Address of the given die. */ + die_addr = die->addr; + + /* Get abbrev code. */ + get_uleb128 (u128, die_addr); + /* And get the abbreviation itself. */ + abbrev = __libdwarf_get_abbrev (dbg, die->cu, u128, error); + if (abbrev == NULL) + return DW_DLV_ERROR; + + /* This is where the attributes start. */ + attrp = abbrev->attrp; + + /* Search the name attribute. */ + while (1) + { + Dwarf_Word attr_name; + Dwarf_Word attr_form; + + /* Are we still in bounds? */ + if (unlikely (attrp + >= ((Dwarf_Small *) dbg->sections[IDX_debug_abbrev].addr + + dbg->sections[IDX_debug_abbrev].size))) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Get attribute name and form. + + XXX We don't check whether this reads beyond the end of the + section. */ + get_uleb128 (attr_name, attrp); + get_uleb128 (attr_form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* Is this the name attribute? */ + if (attr_name == attr) + { + Dwarf_Attribute new_attr; + + new_attr = + (Dwarf_Attribute) malloc (sizeof (struct Dwarf_Attribute_s)); + if (new_attr == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + new_attr->code = attr_name; + new_attr->form = attr_form; + new_attr->valp = die_addr; + new_attr->cu = die->cu; + + *return_attr = new_attr; + return DW_DLV_OK; + } + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len; + + if (__libdwarf_form_val_len (dbg, die->cu, attr_form, die_addr, &len, + error) != DW_DLV_OK) + return DW_DLV_ERROR; + + die_addr += len; + } + } + + /* No such attribute present. */ + return DW_DLV_NO_ENTRY; +} diff --git a/libdwarf/dwarf_attrlist.c b/libdwarf/dwarf_attrlist.c new file mode 100644 index 00000000..bef5a112 --- /dev/null +++ b/libdwarf/dwarf_attrlist.c @@ -0,0 +1,182 @@ +/* Return attribute list for die. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +struct attrlist +{ + struct attrlist *next; + Dwarf_Attribute attr; +}; + + +int +dwarf_attrlist (die, attrbuf, attrcount, error) + Dwarf_Die die; + Dwarf_Attribute **attrbuf; + Dwarf_Signed *attrcount; + Dwarf_Error *error; +{ + Dwarf_Debug dbg = die->cu->dbg; + Dwarf_Small *die_addr; + Dwarf_Word u128; + Dwarf_Abbrev abbrev; + Dwarf_Small *attrp; + struct attrlist *alist; + int nattr; + Dwarf_Attribute *result; + + /* Address of the given die. */ + die_addr = die->addr; + + /* Get abbrev code. */ + get_uleb128 (u128, die_addr); + /* And get the abbreviation itself. */ + abbrev = __libdwarf_get_abbrev (dbg, die->cu, u128, error); + if (abbrev == NULL) + return DW_DLV_ERROR; + + /* This is where the attributes start. */ + attrp = abbrev->attrp; + + /* Initialize the list. We create one because we don't know yet how + many attributes there will be. */ + alist = NULL; + nattr = 0; + + /* Go over the list of attributes. */ + while (1) + { + Dwarf_Word attr_name; + Dwarf_Word attr_form; + Dwarf_Attribute new_attr; + struct attrlist *new_alist; + + /* Are we still in bounds? */ + if (unlikely (attrp + >= ((Dwarf_Small *) dbg->sections[IDX_debug_abbrev].addr + + dbg->sections[IDX_debug_abbrev].size))) + { + while (alist != NULL) + { + free (alist->attr); + alist = alist->next; + } + + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Get attribute name and form. + + XXX We don't check whether this reads beyond the end of the + section. */ + get_uleb128 (attr_name, attrp); + get_uleb128 (attr_form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* Allocate the attribute data structure. */ + new_attr = (Dwarf_Attribute) malloc (sizeof (struct Dwarf_Attribute_s)); + if (new_attr == NULL) + { + while (alist != NULL) + { + free (alist->attr); + alist = alist->next; + } + + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + /* Fill in the values. */ + new_attr->code = attr_name; + new_attr->form = attr_form; + new_attr->valp = die_addr; + new_attr->cu = die->cu; + + /* Enqueue. */ + new_alist = (struct attrlist *) alloca (sizeof (struct attrlist)); + new_alist->attr = new_attr; + new_alist->next = alist; + alist = new_alist; + ++nattr; + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len; + + if (unlikely (__libdwarf_form_val_len (dbg, die->cu, attr_form, + die_addr, &len, error) + != DW_DLV_OK)) + { + while (alist != NULL) + { + free (alist->attr); + alist = alist->next; + } + + return DW_DLV_ERROR; + } + + die_addr += len; + } + } + + if (nattr == 0) + { + *attrcount = 0; + *attrbuf = NULL; + return DW_DLV_NO_ENTRY; + } + + /* Allocate the array for the result. */ + result = (Dwarf_Attribute *) malloc (nattr * sizeof (Dwarf_Attribute)); + if (result == NULL) + { + while (alist != NULL) + { + free (alist->attr); + alist = alist->next; + } + + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + /* Store the number of attributes and the result pointer. */ + *attrcount = nattr; + *attrbuf = result; + + /* Put the attribute entries in the array (in the right order). */ + do + { + result[--nattr] = alist->attr; + alist = alist->next; + } + while (nattr > 0); + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_bitoffset.c b/libdwarf/dwarf_bitoffset.c new file mode 100644 index 00000000..bfc91654 --- /dev/null +++ b/libdwarf/dwarf_bitoffset.c @@ -0,0 +1,31 @@ +/* Return bit offset value associated with die. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_bitoffset (die, return_size, error) + Dwarf_Die die; + Dwarf_Unsigned *return_size; + Dwarf_Error *error; +{ + return __libdwarf_getconstant (die, DW_AT_bit_offset, return_size, error); +} diff --git a/libdwarf/dwarf_bitsize.c b/libdwarf/dwarf_bitsize.c new file mode 100644 index 00000000..007975c7 --- /dev/null +++ b/libdwarf/dwarf_bitsize.c @@ -0,0 +1,31 @@ +/* Return bit size value associated with die. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_bitsize (die, return_size, error) + Dwarf_Die die; + Dwarf_Unsigned *return_size; + Dwarf_Error *error; +{ + return __libdwarf_getconstant (die, DW_AT_bit_size, return_size, error); +} diff --git a/libdwarf/dwarf_bytesize.c b/libdwarf/dwarf_bytesize.c new file mode 100644 index 00000000..68d728ad --- /dev/null +++ b/libdwarf/dwarf_bytesize.c @@ -0,0 +1,31 @@ +/* Return byte size value associated with die. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_bytesize (die, return_size, error) + Dwarf_Die die; + Dwarf_Unsigned *return_size; + Dwarf_Error *error; +{ + return __libdwarf_getconstant (die, DW_AT_byte_size, return_size, error); +} diff --git a/libdwarf/dwarf_child.c b/libdwarf/dwarf_child.c new file mode 100644 index 00000000..ee9c8336 --- /dev/null +++ b/libdwarf/dwarf_child.c @@ -0,0 +1,123 @@ +/* Return child of die. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_child (die, return_kid, error) + Dwarf_Die die; + Dwarf_Die *return_kid; + Dwarf_Error *error; +{ + Dwarf_Debug dbg = die->cu->dbg; + Dwarf_Abbrev abbrev; + Dwarf_Small *attrp; + Dwarf_Small *die_addr; + Dwarf_Word u128; + Dwarf_Die new_die; + + if (! die->abbrev->has_children) + return DW_DLV_NO_ENTRY; + + /* Address of the given die. */ + die_addr = die->addr; + + /* Get abbrev code. */ + get_uleb128 (u128, die_addr); + /* And get the abbreviation itself. */ + abbrev = __libdwarf_get_abbrev (dbg, die->cu, u128, error); + if (abbrev == NULL) + return DW_DLV_ERROR; + + /* This is where the attributes start. */ + attrp = abbrev->attrp; + + /* Skip over the attributes of the given die. */ + while (1) + { + Dwarf_Word attr_name; + Dwarf_Word attr_form; + + /* Are we still in bounds? */ + if (unlikely (attrp + >= ((Dwarf_Small *)dbg->sections[IDX_debug_abbrev].addr + + dbg->sections[IDX_debug_abbrev].size))) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Get attribute name and form. + + XXX We don't check whether this reads beyond the end of the + section. */ + get_uleb128 (attr_name, attrp); + get_uleb128 (attr_form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len; + + if (unlikely (__libdwarf_form_val_len (dbg, die->cu, attr_form, + die_addr, &len, error) + != DW_DLV_OK)) + return DW_DLV_ERROR; + + die_addr += len; + } + } + + /* Allocate the die structure for the result. */ + new_die = (Dwarf_Die) malloc (sizeof (struct Dwarf_Die_s)); + if (new_die == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } +#ifdef DWARF_DEBUG + new_die->memtag = DW_DLA_DIE; +#endif + + /* Remember the address. */ + new_die->addr = die_addr; + + /* And the compile unit. */ + new_die->cu = die->cu; + + /* 7.5.2 Debugging Information Entry + + Each debugging information entry begins with an unsigned LEB128 + number containing the abbreviation code for the entry. */ + get_uleb128 (u128, die_addr); + + /* Find the abbreviation. */ + new_die->abbrev = __libdwarf_get_abbrev (dbg, die->cu, u128, error); + if (new_die->abbrev == NULL) + return DW_DLV_ERROR; + + *return_kid = new_die; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_dealloc.c b/libdwarf/dwarf_dealloc.c new file mode 100644 index 00000000..365303bd --- /dev/null +++ b/libdwarf/dwarf_dealloc.c @@ -0,0 +1,32 @@ +/* Deallocate memory. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +void +dwarf_dealloc (dbg, space, alloc_type) + Dwarf_Debug dbg; + Dwarf_Ptr space; + Dwarf_Unsigned alloc_type; +{ + /* XXX For now we don't do anything fancy. */ + free (space); +} diff --git a/libdwarf/dwarf_die_CU_offset.c b/libdwarf/dwarf_die_CU_offset.c new file mode 100644 index 00000000..2d80fd5a --- /dev/null +++ b/libdwarf/dwarf_die_CU_offset.c @@ -0,0 +1,33 @@ +/* Return offset of die in compile unit data. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_die_CU_offset (die, return_offset, error) + Dwarf_Die die; + Dwarf_Off *return_offset; + Dwarf_Error *error; +{ + *return_offset = + (die->addr + - (Dwarf_Small *) die->cu->dbg->sections[IDX_debug_info].addr + - die->cu->offset); + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_diename.c b/libdwarf/dwarf_diename.c new file mode 100644 index 00000000..2dfcd57a --- /dev/null +++ b/libdwarf/dwarf_diename.c @@ -0,0 +1,139 @@ +/* Return string in name attribute of die. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +int +dwarf_diename (die, return_name, error) + Dwarf_Die die; + char **return_name; + Dwarf_Error *error; +{ + Dwarf_Debug dbg = die->cu->dbg; + Dwarf_Small *die_addr; + Dwarf_Word u128; + Dwarf_Abbrev abbrev; + Dwarf_Small *attrp; + + /* Address of the given die. */ + die_addr = die->addr; + + /* Get abbrev code. */ + get_uleb128 (u128, die_addr); + /* And get the abbreviation itself. */ + abbrev = __libdwarf_get_abbrev (dbg, die->cu, u128, error); + if (abbrev == NULL) + return DW_DLV_ERROR; + + /* This is where the attributes start. */ + attrp = abbrev->attrp; + + /* Search the name attribute. */ + while (1) + { + Dwarf_Word attr_name; + Dwarf_Word attr_form; + + /* Are we still in bounds? */ + if (unlikely (attrp + >= ((Dwarf_Small *)dbg->sections[IDX_debug_abbrev].addr + + dbg->sections[IDX_debug_abbrev].size))) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Get attribute name and form. + + XXX We don't check whether this reads beyond the end of the + section. */ + get_uleb128 (attr_name, attrp); + get_uleb128 (attr_form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* Is this the name attribute? */ + if (attr_name == DW_AT_name) + { + char *str; + + /* We found it. Duplicate the string and return. There are + two possible forms: DW_FORM_string and DW_FORM_strp. */ + if (attr_form == DW_FORM_string) + { + str = (char *) die_addr; + } + else if (likely (attr_form == DW_FORM_strp)) + { + Dwarf_Unsigned off; + Dwarf_Signed len; + + if (die->cu->offset_size == 4) + off = read_4ubyte_unaligned (dbg, die_addr); + else + off = read_8ubyte_unaligned (dbg, die_addr); + + /* This is an offset in the .debug_str section. Make sure + it's within range. */ + if (unlikely (dwarf_get_str (dbg, off, &str, &len, error) + != DW_DLV_OK)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + } + else + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + str = strdup (str); + if (str == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + *return_name = str; + return DW_DLV_OK; + } + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len; + + if (unlikely (__libdwarf_form_val_len (dbg, die->cu, attr_form, + die_addr, &len, error) + != DW_DLV_OK)) + return DW_DLV_ERROR; + + die_addr += len; + } + } + + /* No name attribute present. */ + return DW_DLV_NO_ENTRY; +} diff --git a/libdwarf/dwarf_dieoffset.c b/libdwarf/dwarf_dieoffset.c new file mode 100644 index 00000000..2886f9f8 --- /dev/null +++ b/libdwarf/dwarf_dieoffset.c @@ -0,0 +1,31 @@ +/* Return offset of die in .debug_info section. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_dieoffset (die, return_offset, error) + Dwarf_Die die; + Dwarf_Off *return_offset; + Dwarf_Error *error; +{ + *return_offset = + (die->addr - (Dwarf_Small *) die->cu->dbg->sections[IDX_debug_info].addr); + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_elf_init.c b/libdwarf/dwarf_elf_init.c new file mode 100644 index 00000000..d69d7474 --- /dev/null +++ b/libdwarf/dwarf_elf_init.c @@ -0,0 +1,197 @@ +/* Create descriptor from ELF handle for processing file. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + + +/* Section names. */ +static const char dwarf_scnnames[IDX_last][17] = +{ + [IDX_debug_info] = ".debug_info", + [IDX_debug_abbrev] = ".debug_abbrev", + [IDX_debug_aranges] = ".debug_aranges", + [IDX_debug_line] = ".debug_line", + [IDX_debug_frame] = ".debug_frame", + [IDX_eh_frame] = ".eh_frame", + [IDX_debug_loc] = ".debug_loc", + [IDX_debug_pubnames] = ".debug_pubnames", + [IDX_debug_str] = ".debug_str", + [IDX_debug_funcnames] = ".debug_funcnames", + [IDX_debug_typenames] = ".debug_typenames", + [IDX_debug_varnames] = ".debug_varnames", + [IDX_debug_weaknames] = ".debug_weaknames", + [IDX_debug_macinfo] = ".debug_macinfo" +}; +#define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0])) + + +int +dwarf_elf_init (elf, access, errhand, errarg, dbg, error) + Elf *elf; + Dwarf_Unsigned access; + Dwarf_Handler errhand; + Dwarf_Ptr errarg; + Dwarf_Debug *dbg; + Dwarf_Error *error; +{ + int result = DW_DLV_ERROR; + Dwarf_Debug newdbg; + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + Elf_Scn *scn; + + /* XXX For now nothing but read-only support is available. */ + if (access != DW_DLC_READ) + abort (); + + /* Get the ELF header of the file. We need various pieces of + information from it. */ + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + struct Dwarf_Debug_s tmpdbg; + + tmpdbg.dbg_errhand = errhand; + tmpdbg.dbg_errarg = errarg; + + if (elf_kind (elf) != ELF_K_ELF) + __libdwarf_error (&tmpdbg, error, DW_E_NOELF); + else + __libdwarf_error (&tmpdbg, error, DW_E_GETEHDR_ERROR); + + return result; + } + + /* Allocate and fill the result data structure. */ + newdbg = (Dwarf_Debug) calloc (1, sizeof (struct Dwarf_Debug_s)); + if (newdbg == NULL) + { + struct Dwarf_Debug_s tmpdbg; + + tmpdbg.dbg_errhand = errhand; + tmpdbg.dbg_errarg = errarg; + + __libdwarf_error (&tmpdbg, error, DW_E_NOMEM); + } + else + { + /* We have been able to allocate the memory for the debug handle. */ + newdbg->dbg_errhand = errhand; + newdbg->dbg_errarg = errarg; + newdbg->elf = elf; + if ((BYTE_ORDER == LITTLE_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + || (BYTE_ORDER == BIG_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) + newdbg->other_byte_order = 1; + newdbg->access = access; +#ifdef DWARF_DEBUG + newdbg->memtag = DW_DLA_DEBUG; +#endif + + /* All done. */ + *dbg = newdbg; + result = DW_DLV_OK; + + /* Find out whether the file actually has the necessary DWARF + sections. */ + scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + const char *scnname; + size_t cnt; + Elf_Data *data; + + /* Get the section header data. */ + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + /* This should never happen. If it does something is + wrong in the libelf library. */ + abort (); + + /* We recognize the DWARF section by their names. This is + not very safe and stable but the best we can do. */ + scnname = elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name); + if (scnname == NULL) + { + /* The section name must be valid. Otherwise is the ELF file + invalid. */ + __libdwarf_error (newdbg, error, DW_E_INVALID_ELF); + break; + } + + /* Recognize the various sections. Most names start with + .debug_. */ + for (cnt = 0; cnt < ndwarf_scnnames; ++cnt) + if (strcmp (scnname, dwarf_scnnames[cnt]) == 0) + break; + + if (cnt < ndwarf_scnnames) + { + /* Found it. Remember where the data is. */ + assert (cnt < IDX_last); + if (unlikely (newdbg->sections[cnt].addr != NULL)) + { + /* A section appears twice. That's bad. */ + __libdwarf_error (newdbg, error, DW_E_INVALID_DWARF); + break; + } + + /* Get the section data. */ + data = elf_getdata (scn, NULL); + if (data != NULL && data->d_size != 0) + { + /* Yep, there is actually data available. */ + newdbg->sections[cnt].addr = data->d_buf; + newdbg->sections[cnt].size = data->d_size; + } + } + } + + if (scn == NULL) + { + /* We looked at all the sections. Now determine whether all + the sections with debugging information we need are there. + + XXX Which sections are absolutely necessary? Add tests + if necessary. For now we require only .debug_info. Hopefully + this is correct. */ + if (newdbg->sections[IDX_debug_info].addr == NULL) + { + __libdwarf_error (newdbg, error, DW_E_NO_DWARF); + result = DW_DLV_NO_ENTRY; + } + else + result = DW_DLV_OK; + } + + if (result != DW_DLV_OK) + /* Something went wrong. */ + free (newdbg); + } + + return result; +} diff --git a/libdwarf/dwarf_errmsg.c b/libdwarf/dwarf_errmsg.c new file mode 100644 index 00000000..1d19f416 --- /dev/null +++ b/libdwarf/dwarf_errmsg.c @@ -0,0 +1,67 @@ +/* Return error message. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +/* Map error values to strings. */ +/* XXX This table should avoid string pointers. Fixing it can wait + until the code is stable. */ +static const char *msgs[] = +{ + [DW_E_NOERROR] = N_("no error"), + [DW_E_INVALID_ACCESS] = N_("invalid access mode"), + [DW_E_NO_REGFILE] = N_("no regular file"), + [DW_E_IO_ERROR] = N_("I/O error"), + [DW_E_NOMEM] = N_("out of memory"), + [DW_E_NOELF] = N_("file is not an ELF file"), + [DW_E_GETEHDR_ERROR] = N_("getehdr call failed"), + [DW_E_INVALID_ELF] = N_("invalid ELF file"), + [DW_E_INVALID_DWARF] = N_("invalid DWARF debugging information"), + [DW_E_NO_DWARF] = N_("no DWARF debugging information available"), + [DW_E_NO_CU] = N_("no compilation unit"), + [DW_E_1ST_NO_CU] = N_("first die is no compile unit die"), + [DW_E_INVALID_OFFSET] = N_("invalid offset"), + [DW_E_INVALID_REFERENCE] = N_("invalid reference form"), + [DW_E_NO_REFERENCE] = N_("no reference form"), + [DW_E_NO_ADDR] = N_("no address form"), + [DW_E_NO_FLAG] = N_("no flag form"), + [DW_E_NO_CONSTANT] = N_("no constant form"), + [DW_E_NO_BLOCK] = N_("no block form"), + [DW_E_NO_STRING] = N_("no string form"), + [DW_E_WRONG_ATTR] = N_("wrong attribute code"), + [DW_E_NO_DATA] = N_("no data form"), + [DW_E_NO_DEBUG_LINE] = N_(".debug_line section missing"), + [DW_E_VERSION_ERROR] = N_("version mismatch"), + [DW_E_INVALID_DIR_IDX] = N_("invalid directory index"), + [DW_E_INVALID_ADDR] = N_("invalid address"), + [DW_E_NO_ABBR] = N_("no valid abbreviation"), +}; +#define nmsgs (sizeof (msgs) / sizeof (msgs[0])) + + +const char * +dwarf_errmsg (Dwarf_Error error) +{ + const char *retval = N_("unknown error"); + + if (error->de_error < nmsgs) + retval = msgs[error->de_error]; + + return _(retval); +} diff --git a/libdwarf/dwarf_errno.c b/libdwarf/dwarf_errno.c new file mode 100644 index 00000000..4d659e09 --- /dev/null +++ b/libdwarf/dwarf_errno.c @@ -0,0 +1,26 @@ +/* Return error value. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +Dwarf_Unsigned +dwarf_errno (Dwarf_Error error) +{ + return error->de_error; +} diff --git a/libdwarf/dwarf_error.c b/libdwarf/dwarf_error.c new file mode 100644 index 00000000..16c0c45a --- /dev/null +++ b/libdwarf/dwarf_error.c @@ -0,0 +1,52 @@ +/* Handle error. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include + + +void +internal_function +__libdwarf_error (Dwarf_Debug dbg, Dwarf_Error *error, int errval) +{ + /* Allocate memory for the error structure given to the user. */ + Dwarf_Error errmem = (Dwarf_Error) malloc (sizeof (*error)); + /* We cannot report an error if we cannot allocate memory. */ + if (errmem == NULL) + return; + + errmem->de_error = errval; + + /* DBG must never be NULL. */ + assert (dbg != NULL); + + if (error != NULL) + /* If the user provides an ERROR parameter we have to use it. */ + *error = errmem; + else if (likely (dbg->dbg_errhand != NULL)) + /* Use the handler the user provided if possible. */ + dbg->dbg_errhand (error, dbg->dbg_errarg); + else + { + assert (! "error and dbg->dbg_errhand == NULL"); + abort (); + } +} diff --git a/libdwarf/dwarf_find_macro_value_start.c b/libdwarf/dwarf_find_macro_value_start.c new file mode 100644 index 00000000..fdaaf72a --- /dev/null +++ b/libdwarf/dwarf_find_macro_value_start.c @@ -0,0 +1,45 @@ +/* Find start of macro value. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +char * +dwarf_find_macro_value_start (macro_string) + char *macro_string; +{ + int with_paren = 0; + + while (*macro_string != '\0') + { + if (*macro_string == '(') + with_paren = 1; + else if (*macro_string == ')') + /* After the closing parenthesis there must be a space. */ + return macro_string + 2; + else if (*macro_string == ' ' && ! with_paren) + /* Not a function like macro and we found the space terminating + the name. */ + return macro_string + 1; + + ++macro_string; + } + + /* The macro has no value. Return a pointer to the NUL byte. */ + return macro_string; +} diff --git a/libdwarf/dwarf_finish.c b/libdwarf/dwarf_finish.c new file mode 100644 index 00000000..f689e79c --- /dev/null +++ b/libdwarf/dwarf_finish.c @@ -0,0 +1,40 @@ +/* Free resources allocated for debug handle. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_finish (dbg, error) + Dwarf_Debug dbg; + Dwarf_Error *error; +{ + if (dbg == NULL) + return DW_DLV_ERROR; + +#ifdef DWARF_DEBUG + if (dbg->memtag != DW_DLA_DEBUG) + return DW_DLV_ERROR; +#endif + + free (dbg); + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_form.c b/libdwarf/dwarf_form.c new file mode 100644 index 00000000..9adf3ede --- /dev/null +++ b/libdwarf/dwarf_form.c @@ -0,0 +1,107 @@ +/* Helper functions for form handling. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +int +internal_function +__libdwarf_form_val_len (Dwarf_Debug dbg, Dwarf_CU_Info cu, Dwarf_Word form, + Dwarf_Small *valp, size_t *len, Dwarf_Error *error) +{ + Dwarf_Small *saved; + Dwarf_Word u128; + + switch (form) + { + case DW_FORM_addr: + case DW_FORM_strp: + case DW_FORM_ref_addr: + *len = cu->address_size; + break; + + case DW_FORM_block1: + *len = *valp + 1; + break; + + case DW_FORM_block2: + *len = read_2ubyte_unaligned (dbg, valp) + 2; + break; + + case DW_FORM_block4: + *len = read_4ubyte_unaligned (dbg, valp) + 4; + break; + + case DW_FORM_block: + saved = valp; + get_uleb128 (u128, valp); + *len = u128 + (valp - saved); + break; + + case DW_FORM_ref1: + case DW_FORM_data1: + case DW_FORM_flag: + *len = 1; + break; + + case DW_FORM_data2: + case DW_FORM_ref2: + *len = 2; + break; + + case DW_FORM_data4: + case DW_FORM_ref4: + *len = 4; + break; + + case DW_FORM_data8: + case DW_FORM_ref8: + *len = 8; + break; + + case DW_FORM_string: + *len = strlen ((char *) valp) + 1; + break; + + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + saved = valp; + get_uleb128 (u128, valp); + *len = valp - saved; + break; + + case DW_FORM_indirect: + saved = valp; + get_uleb128 (u128, valp); + if (__libdwarf_form_val_len (dbg, cu, u128, valp, len, error) + != DW_DLV_OK) + return DW_DLV_ERROR; + *len += valp - saved; + break; + + default: + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_formaddr.c b/libdwarf/dwarf_formaddr.c new file mode 100644 index 00000000..148508fe --- /dev/null +++ b/libdwarf/dwarf_formaddr.c @@ -0,0 +1,42 @@ +/* Return address represented by attribute. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_formaddr (attr, return_addr, error) + Dwarf_Attribute attr; + Dwarf_Addr *return_addr; + Dwarf_Error *error; +{ + if (unlikely (attr->form != DW_FORM_addr)) + { + __libdwarf_error (attr->cu->dbg, error, DW_E_NO_ADDR); + return DW_DLV_ERROR; + } + + if (attr->cu->address_size == 4) + *return_addr = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + else + *return_addr = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_formblock.c b/libdwarf/dwarf_formblock.c new file mode 100644 index 00000000..44606edd --- /dev/null +++ b/libdwarf/dwarf_formblock.c @@ -0,0 +1,76 @@ +/* Return block of uninterpreted data represented by attribute. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +int +dwarf_formblock (attr, return_block, error) + Dwarf_Attribute attr; + Dwarf_Block **return_block; + Dwarf_Error *error; +{ + Dwarf_Small *attrp = attr->valp; + Dwarf_Unsigned len; + Dwarf_Ptr *data; + Dwarf_Block *result; + + switch (attr->form) + { + case DW_FORM_block1: + len = *attrp; + data = (Dwarf_Ptr) (attrp + 1); + break; + + case DW_FORM_block2: + len = read_2ubyte_unaligned (attr->cu->dbg, attrp); + data = (Dwarf_Ptr) (attrp + 2); + break; + + case DW_FORM_block4: + len = read_4ubyte_unaligned (attr->cu->dbg, attrp); + data = (Dwarf_Ptr) (attrp + 2); + break; + + case DW_FORM_block: + get_uleb128 (len, attrp); + data = (Dwarf_Ptr) attrp; + break; + + default: + __libdwarf_error (attr->cu->dbg, error, DW_E_NO_BLOCK); + return DW_DLV_ERROR; + } + + /* Allocate memory for the result. */ + result = (Dwarf_Block *) malloc (sizeof (Dwarf_Block)); + if (result == NULL) + { + __libdwarf_error (attr->cu->dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + result->bl_len = len; + result->bl_data = data; + + *return_block = result; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_formflag.c b/libdwarf/dwarf_formflag.c new file mode 100644 index 00000000..32a98fd8 --- /dev/null +++ b/libdwarf/dwarf_formflag.c @@ -0,0 +1,39 @@ +/* Return flag represented by attribute. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_formflag (attr, return_bool, error) + Dwarf_Attribute attr; + Dwarf_Bool *return_bool; + Dwarf_Error *error; +{ + if (unlikely (attr->form != DW_FORM_flag)) + { + __libdwarf_error (attr->cu->dbg, error, DW_E_NO_FLAG); + return DW_DLV_ERROR; + } + + *return_bool = attr->valp != 0; + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_formref.c b/libdwarf/dwarf_formref.c new file mode 100644 index 00000000..4ae353a8 --- /dev/null +++ b/libdwarf/dwarf_formref.c @@ -0,0 +1,67 @@ +/* Return compile-unit relative offset of reference associated with form. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_formref (attr, return_offset, error) + Dwarf_Attribute attr; + Dwarf_Off *return_offset; + Dwarf_Error *error; +{ + switch (attr->form) + { + case DW_FORM_ref1: + *return_offset = *attr->valp; + break; + + case DW_FORM_ref2: + *return_offset = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref4: + *return_offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref8: + *return_offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref_udata: + { + Dwarf_Off off; + Dwarf_Small *attrp = attr->valp; + get_uleb128 (off, attrp); + *return_offset = off; + } + break; + + case DW_FORM_ref_addr: + __libdwarf_error (attr->cu->dbg, error, DW_E_INVALID_REFERENCE); + return DW_DLV_ERROR; + + default: + __libdwarf_error (attr->cu->dbg, error, DW_E_NO_REFERENCE); + return DW_DLV_ERROR; + } + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_formsdata.c b/libdwarf/dwarf_formsdata.c new file mode 100644 index 00000000..8024e763 --- /dev/null +++ b/libdwarf/dwarf_formsdata.c @@ -0,0 +1,72 @@ +/* Return signed constant represented by attribute. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_formsdata (attr, return_sval, error) + Dwarf_Attribute attr; + Dwarf_Signed *return_sval; + Dwarf_Error *error; +{ + Dwarf_Signed u128; + + switch (attr->form) + { + case DW_FORM_data1: + *return_sval = *attr->valp; + break; + + case DW_FORM_data2: + *return_sval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data4: + *return_sval = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data8: + *return_sval = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_sdata: + { + Dwarf_Small *attrp = attr->valp; + get_sleb128 (u128, attrp); + *return_sval = u128; + } + break; + + case DW_FORM_udata: + { + Dwarf_Small *attrp = attr->valp; + get_uleb128 (u128, attrp); + *return_sval = u128; + } + break; + + default: + __libdwarf_error (attr->cu->dbg, error, DW_E_NO_CONSTANT); + return DW_DLV_ERROR; + } + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_formstring.c b/libdwarf/dwarf_formstring.c new file mode 100644 index 00000000..205a9466 --- /dev/null +++ b/libdwarf/dwarf_formstring.c @@ -0,0 +1,51 @@ +/* Return string represented by attribute. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +int +dwarf_formstring (attr, return_string, error) + Dwarf_Attribute attr; + char **return_string; + Dwarf_Error *error; +{ + char *result; + + if (attr->form == DW_FORM_string) + result = (char *) attr->valp; + else if (likely (attr->form == DW_FORM_strp)) + { + Dwarf_Unsigned offset; + + offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + + result = (char *) attr->cu->dbg->sections[IDX_debug_str].addr + offset; + } + else + { + __libdwarf_error (attr->cu->dbg, error, DW_E_NO_STRING); + return DW_DLV_ERROR; + } + + *return_string = result; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_formudata.c b/libdwarf/dwarf_formudata.c new file mode 100644 index 00000000..35e133cb --- /dev/null +++ b/libdwarf/dwarf_formudata.c @@ -0,0 +1,72 @@ +/* Return unsigned constant represented by attribute. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_formudata (attr, return_uval, error) + Dwarf_Attribute attr; + Dwarf_Unsigned *return_uval; + Dwarf_Error *error; +{ + Dwarf_Unsigned u128; + + switch (attr->form) + { + case DW_FORM_data1: + *return_uval = *attr->valp; + break; + + case DW_FORM_data2: + *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data4: + *return_uval = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data8: + *return_uval = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_sdata: + { + Dwarf_Small *attrp = attr->valp; + get_sleb128 (u128, attrp); + *return_uval = u128; + } + break; + + case DW_FORM_udata: + { + Dwarf_Small *attrp = attr->valp; + get_uleb128 (u128, attrp); + *return_uval = u128; + } + break; + + default: + __libdwarf_error (attr->cu->dbg, error, DW_E_NO_CONSTANT); + return DW_DLV_ERROR; + } + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_abbrev.c b/libdwarf/dwarf_get_abbrev.c new file mode 100644 index 00000000..0295f9bd --- /dev/null +++ b/libdwarf/dwarf_get_abbrev.c @@ -0,0 +1,111 @@ +/* Get abbreviation record. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +int +dwarf_get_abbrev (dbg, offset, return_abbrev, length, attr_count, error) + Dwarf_Debug dbg; + Dwarf_Unsigned offset; + Dwarf_Abbrev *return_abbrev; + Dwarf_Unsigned *length; + Dwarf_Unsigned *attr_count; + Dwarf_Error *error; +{ + Dwarf_Abbrev ent; + Dwarf_Small *abbrevp; + Dwarf_Small *start_abbrevp; + + /* Address in memory. */ + abbrevp = (Dwarf_Small *) dbg->sections[IDX_debug_abbrev].addr + offset; + + /* Remember where we started. */ + start_abbrevp = abbrevp; + + if (*abbrevp != '\0') + { + /* 7.5.3 Abbreviations Tables + + [...] Each declaration begins with an unsigned LEB128 number + representing the abbreviation code itself. [...] The + abbreviation code is followed by another unsigned LEB128 + number that encodes the entry's tag. [...] + + [...] Following the tag encoding is a 1-byte value that + determines whether a debugging information entry using this + abbreviation has child entries or not. [...] + + [...] Finally, the child encoding is followed by a series of + attribute specifications. Each attribute specification + consists of two parts. The first part is an unsigned LEB128 + number representing the attribute's name. The second part is + an unsigned LEB128 number representing the attribute s form. */ + Dwarf_Word abbrev_code; + Dwarf_Word abbrev_tag; + Dwarf_Word attr_name; + Dwarf_Word attr_form; + Dwarf_Unsigned attrcnt; + + /* XXX We have no tests for crossing the section boundary here. + We should compare with dbg->sections[IDX_debug_abbrev].size. */ + get_uleb128 (abbrev_code, abbrevp); + get_uleb128 (abbrev_tag, abbrevp); + + /* Get memory for the result. */ + ent = (Dwarf_Abbrev) malloc (sizeof (struct Dwarf_Abbrev_s)); + if (ent == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + ent->code = abbrev_code; + ent->tag = abbrev_tag; + ent->has_children = *abbrevp++ == DW_CHILDREN_yes; + ent->attrp = abbrevp; + ent->offset = offset; + + /* Skip over all the attributes. */ + attrcnt = 0; + do + { + get_uleb128 (attr_name, abbrevp); + get_uleb128 (attr_form, abbrevp); + } + while (attr_name != 0 && attr_form != 0 && ++attrcnt); + + /* Number of attributes. */ + *attr_count = ent->attrcnt = attrcnt; + + /* Store the actual abbreviation record. */ + *return_abbrev = ent; + } + else + /* Read over the NUL byte. */ + ++abbrevp; + + /* Length of the entry. */ + *length = abbrevp - start_abbrevp; + + /* If we come here we haven't found anything. */ + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_abbrev_children_flag.c b/libdwarf/dwarf_get_abbrev_children_flag.c new file mode 100644 index 00000000..079c85a8 --- /dev/null +++ b/libdwarf/dwarf_get_abbrev_children_flag.c @@ -0,0 +1,29 @@ +/* Get children flag of abbreviation record. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwarfP.h" + + +int dwarf_get_abbrev_children_flag (abbrev, return_flag, error) + Dwarf_Abbrev abbrev; + Dwarf_Signed *return_flag; + Dwarf_Error *error; +{ + *return_flag = abbrev->has_children; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_abbrev_code.c b/libdwarf/dwarf_get_abbrev_code.c new file mode 100644 index 00000000..08ecb43b --- /dev/null +++ b/libdwarf/dwarf_get_abbrev_code.c @@ -0,0 +1,29 @@ +/* Get code of abbreviation record. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwarfP.h" + + +int dwarf_get_abbrev_code (abbrev, return_code, error) + Dwarf_Abbrev abbrev; + Dwarf_Unsigned *return_code; + Dwarf_Error *error; +{ + *return_code = abbrev->code; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_abbrev_entry.c b/libdwarf/dwarf_get_abbrev_entry.c new file mode 100644 index 00000000..4deccd0d --- /dev/null +++ b/libdwarf/dwarf_get_abbrev_entry.c @@ -0,0 +1,63 @@ +/* Get attribute from abbreviation record. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +int +dwarf_get_abbrev_entry (abbrev, idx, attr_num, form, offset, error) + Dwarf_Abbrev abbrev; + Dwarf_Signed idx; + Dwarf_Half *attr_num; + Dwarf_Signed *form; + Dwarf_Off *offset; + Dwarf_Error *error; +{ + Dwarf_Small *attrp; + Dwarf_Small *start_attrp; + Dwarf_Word attr_name; + Dwarf_Word attr_form; + + if (idx < 0) + return DW_DLV_NO_ENTRY; + + /* Address in memory. */ + attrp = abbrev->attrp; + + /* Read the attributes, skip over the ones we don't want. */ + do + { + start_attrp = attrp; + + get_uleb128 (attr_name, attrp); + get_uleb128 (attr_form, attrp); + + if (attr_name == 0 || attr_form == 0) + return DW_DLV_NO_ENTRY; + } + while (idx-- > 0); + + *attr_num = attr_name; + *form = attr_form; + *offset = (start_attrp - abbrev->attrp) + abbrev->offset; + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_abbrev_tag.c b/libdwarf/dwarf_get_abbrev_tag.c new file mode 100644 index 00000000..b3f9fd1c --- /dev/null +++ b/libdwarf/dwarf_get_abbrev_tag.c @@ -0,0 +1,29 @@ +/* Get tag of abbreviation record. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwarfP.h" + + +int dwarf_get_abbrev_tag (abbrev, return_tag, error) + Dwarf_Abbrev abbrev; + Dwarf_Half *return_tag; + Dwarf_Error *error; +{ + *return_tag = abbrev->tag; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_address_size.c b/libdwarf/dwarf_get_address_size.c new file mode 100644 index 00000000..fe5234c9 --- /dev/null +++ b/libdwarf/dwarf_get_address_size.c @@ -0,0 +1,30 @@ +/* Return address size. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_get_address_size (dbg, addr_size, error) + Dwarf_Debug dbg; + Dwarf_Half *addr_size; + Dwarf_Error *error; +{ + *addr_size = elf_getident (dbg->elf, NULL)[EI_CLASS] == ELFCLASS64 ? 8 : 4; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_arange.c b/libdwarf/dwarf_get_arange.c new file mode 100644 index 00000000..02df19d2 --- /dev/null +++ b/libdwarf/dwarf_get_arange.c @@ -0,0 +1,41 @@ +/* Find matching range for address. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_get_arange (aranges, arange_count, address, return_arange, error) + Dwarf_Arange *aranges; + Dwarf_Unsigned arange_count; + Dwarf_Addr address; + Dwarf_Arange *return_arange; + Dwarf_Error *error; +{ + Dwarf_Unsigned cnt; + + for (cnt = 0; cnt < arange_count; ++cnt) + if (aranges[cnt]->address <= address + && address < aranges[cnt]->address + aranges[cnt]->length) + { + *return_arange = aranges[cnt]; + return DW_DLV_OK; + } + + return DW_DLV_NO_ENTRY; +} diff --git a/libdwarf/dwarf_get_arange_info.c b/libdwarf/dwarf_get_arange_info.c new file mode 100644 index 00000000..4d37e087 --- /dev/null +++ b/libdwarf/dwarf_get_arange_info.c @@ -0,0 +1,48 @@ +/* Return start, length, and CU DIE offset of range. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_get_arange_info (arange, start, length, cu_die_offset, error) + Dwarf_Arange arange; + Dwarf_Addr *start; + Dwarf_Unsigned *length; + Dwarf_Off *cu_die_offset; + Dwarf_Error *error; +{ + Dwarf_Small *cu_header; + unsigned int offset_size; + + *start = arange->address; + *length = arange->length; + + /* Determine the size of the CU header. */ + cu_header = + ((Dwarf_Small *) arange->info->dbg->sections[IDX_debug_info].addr + + arange->info->offset); + if (read_4ubyte_unaligned_noncvt (cu_header) == 0xffffffff) + offset_size = 8; + else + offset_size = 4; + + *cu_die_offset = arange->info->offset + 3 * offset_size - 4 + 3; + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_aranges.c b/libdwarf/dwarf_get_aranges.c new file mode 100644 index 00000000..b8cabb03 --- /dev/null +++ b/libdwarf/dwarf_get_aranges.c @@ -0,0 +1,186 @@ +/* Return list address ranges. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +struct arangelist +{ + Dwarf_Arange arange; + struct arangelist *next; +}; + + +int +dwarf_get_aranges (dbg, aranges, return_count, error) + Dwarf_Debug dbg; + Dwarf_Arange **aranges; + Dwarf_Signed *return_count; + Dwarf_Error *error; +{ + Dwarf_Small *readp; + Dwarf_Small *readendp; + struct arangelist *arangelist = NULL; + unsigned int narangelist = 0; + + if (dbg->sections[IDX_debug_aranges].addr == NULL) + return DW_DLV_NO_ENTRY; + + readp = (Dwarf_Small *) dbg->sections[IDX_debug_aranges].addr; + readendp = readp + dbg->sections[IDX_debug_aranges].size; + + while (readp < readendp) + { + Dwarf_Small *hdrstart = readp; + Dwarf_Unsigned length; + unsigned int length_bytes; + unsigned int version; + Dwarf_Unsigned offset; + unsigned int address_size; + unsigned int segment_size; + Dwarf_Arange_Info arange_info; + + /* Each entry starts with a header: + + 1. A 4-byte or 12-byte length containing the length of the + set of entries for this compilation unit, not including the + length field itself. [...] + + 2. A 2-byte version identifier containing the value 2 for + DWARF Version 2.1. + + 3. A 4-byte or 8-byte offset into the .debug_info section. [...] + + 4. A 1-byte unsigned integer containing the size in bytes of + an address (or the offset portion of an address for segmented + addressing) on the target system. + + 5. A 1-byte unsigned integer containing the size in bytes of + a segment descriptor on the target system. */ + length = read_4ubyte_unaligned (dbg, readp); + readp += 4; + length_bytes = 4; + if (length == 0xffffffff) + { + length = read_8ubyte_unaligned (dbg, readp); + readp += 8; + length_bytes = 8; + } + + version = read_2ubyte_unaligned (dbg, readp); + readp += 2; + if (version != 2) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + if (length_bytes == 4) + offset = read_4ubyte_unaligned (dbg, readp); + else + offset = read_8ubyte_unaligned (dbg, readp); + readp += length_bytes; + + address_size = *readp++; + segment_size = *readp++; + + /* Round the address to the next multiple of 2*address_size. */ + readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size))) + % (2 * address_size)); + + arange_info = + (Dwarf_Arange_Info) malloc (sizeof (struct Dwarf_Arange_s)); + if (arange_info == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + arange_info->dbg = dbg; + arange_info->offset = offset; + + while (1) + { + Dwarf_Unsigned range_address; + Dwarf_Unsigned range_length; + struct arangelist *new_arange; + + if (address_size == 4) + { + range_address = read_4ubyte_unaligned (dbg, readp); + readp += 4; + range_length = read_4ubyte_unaligned (dbg, readp); + readp += 4; + } + else if (likely (address_size == 8)) + { + range_address = read_8ubyte_unaligned (dbg, readp); + readp += 8; + range_length = read_8ubyte_unaligned (dbg, readp); + readp += 8; + } + else + abort (); + + /* Two zero values mark the end. */ + if (range_address == 0 && range_length == 0) + break; + + new_arange = + (struct arangelist *) alloca (sizeof (struct arangelist)); + new_arange->arange = + (Dwarf_Arange) malloc (sizeof (struct Dwarf_Arange_s)); + if (new_arange->arange == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + new_arange->arange->address = range_address; + new_arange->arange->length = range_length; + new_arange->arange->info = arange_info; + + new_arange->next = arangelist; + arangelist = new_arange; + ++narangelist; + } + } + + if (narangelist == 0) + return DW_DLV_NO_ENTRY; + + /* Allocate the array for the result. */ + *return_count = narangelist; + *aranges = (Dwarf_Arange *) malloc (narangelist + * sizeof (struct Dwarf_Arange_s)); + if (*aranges == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + while (narangelist-- > 0) + { + (*aranges)[narangelist] = arangelist->arange; + arangelist = arangelist->next; + } + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_cie_info.c b/libdwarf/dwarf_get_cie_info.c new file mode 100644 index 00000000..029d9c93 --- /dev/null +++ b/libdwarf/dwarf_get_cie_info.c @@ -0,0 +1,53 @@ +/* Get information about CIE. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_get_cie_info (cie, bytes_in_cie, version, augmenter, + code_alignment_factor, data_alignment_factor, + return_address_register, initial_instructions, + initial_instructions_length, error) + Dwarf_Cie cie; + Dwarf_Unsigned *bytes_in_cie; + Dwarf_Small *version; + char **augmenter; + Dwarf_Unsigned *code_alignment_factor; + Dwarf_Signed *data_alignment_factor; + Dwarf_Half *return_address_register; + Dwarf_Ptr *initial_instructions; + Dwarf_Unsigned *initial_instructions_length; + Dwarf_Error *error; +{ + *bytes_in_cie = cie->length; + + *version = CIE_VERSION; + + *augmenter = cie->augmentation; + + *code_alignment_factor = cie->code_alignment_factor; + *data_alignment_factor = cie->data_alignment_factor; + + *return_address_register = cie->return_address_register; + + *initial_instructions = cie->initial_instructions; + *initial_instructions_length = cie->initial_instructions_length; + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_cie_of_fde.c b/libdwarf/dwarf_get_cie_of_fde.c new file mode 100644 index 00000000..49718e9e --- /dev/null +++ b/libdwarf/dwarf_get_cie_of_fde.c @@ -0,0 +1,30 @@ +/* Get CIE of FDE. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_get_cie_of_fde (fde, return_cie, error) + Dwarf_Fde fde; + Dwarf_Cie *return_cie; + Dwarf_Error *error; +{ + *return_cie = fde->cie; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_cu_die_offset.c b/libdwarf/dwarf_get_cu_die_offset.c new file mode 100644 index 00000000..a358d5cf --- /dev/null +++ b/libdwarf/dwarf_get_cu_die_offset.c @@ -0,0 +1,43 @@ +/* Return offset of compile unit DIE containing the range. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_get_cu_die_offset (arange, return_offset, error) + Dwarf_Arange arange; + Dwarf_Off *return_offset; + Dwarf_Error *error; +{ + Dwarf_Small *cu_header; + unsigned int offset_size; + + /* Determine the size of the CU header. */ + cu_header = + ((Dwarf_Small *) arange->info->dbg->sections[IDX_debug_info].addr + + arange->info->offset); + if (read_4ubyte_unaligned_noncvt (cu_header) == 0xffffffff) + offset_size = 8; + else + offset_size = 4; + + *return_offset = arange->info->offset + 3 * offset_size - 4 + 3; + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_elf.c b/libdwarf/dwarf_get_elf.c new file mode 100644 index 00000000..9313e95a --- /dev/null +++ b/libdwarf/dwarf_get_elf.c @@ -0,0 +1,33 @@ +/* Return ELF handle. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_get_elf_init (dbg, elf, error) + Dwarf_Debug dbg; + Elf **elf; + Dwarf_Error *error; +{ + if (dbg == NULL) + return DW_DLV_ERROR; + + *elf = dbg->elf; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_fde_at_pc.c b/libdwarf/dwarf_get_fde_at_pc.c new file mode 100644 index 00000000..fee2efdb --- /dev/null +++ b/libdwarf/dwarf_get_fde_at_pc.c @@ -0,0 +1,57 @@ +/* Find FDE for given address. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwarfP.h" + + +int +dwarf_get_fde_at_pc (fde_data, pc_of_interest, returned_fde, lopc, hipc, error) + Dwarf_Fde *fde_data; + Dwarf_Addr pc_of_interest; + Dwarf_Fde *returned_fde; + Dwarf_Addr *lopc; + Dwarf_Addr *hipc; + Dwarf_Error *error; +{ + Dwarf_Debug dbg = fde_data[0]->cie->dbg; + int low = 0; + int high = dbg->fde_cnt - 1; + + /* Since the FDEs are sorted by their addresses and since there can + potentially be many FDEs we better use binary search. */ + while (low <= high) + { + int curidx = (low + high) / 2; + Dwarf_Fde cur = fde_data[curidx]; + + if (pc_of_interest < cur->initial_location) + high = curidx - 1; + else if (likely (cur->initial_location + cur->address_range + <= pc_of_interest)) + low = curidx + 1; + else + { + *returned_fde = cur; + *lopc = cur->initial_location; + *hipc = cur->initial_location + cur->address_range - 1; + return DW_DLV_OK; + } + } + + return DW_DLV_NO_ENTRY; +} diff --git a/libdwarf/dwarf_get_fde_instr_bytes.c b/libdwarf/dwarf_get_fde_instr_bytes.c new file mode 100644 index 00000000..74a5388e --- /dev/null +++ b/libdwarf/dwarf_get_fde_instr_bytes.c @@ -0,0 +1,33 @@ +/* Get frame construction instructions of FDE. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_get_fde_instr_bytes (fde, outinstrs, outlen, error) + Dwarf_Fde fde; + Dwarf_Ptr *outinstrs; + Dwarf_Unsigned *outlen; + Dwarf_Error *error; +{ + *outinstrs = fde->instructions; + *outlen = fde->instructions_length; + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_fde_list_eh.c b/libdwarf/dwarf_get_fde_list_eh.c new file mode 100644 index 00000000..bcda71b0 --- /dev/null +++ b/libdwarf/dwarf_get_fde_list_eh.c @@ -0,0 +1,363 @@ +/* Get frame descriptions. GCC version using .eh_frame. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +struct cielist +{ + Dwarf_Cie cie; + struct cielist *next; +}; + + +struct fdelist +{ + Dwarf_Fde fde; + Dwarf_Small *cie_id_ptr; + struct fdelist *next; +}; + + +int +dwarf_get_fde_list_eh (dbg, cie_data, cie_element_count, fde_data, + fde_element_count, error) + Dwarf_Debug dbg; + Dwarf_Cie **cie_data; + Dwarf_Signed *cie_element_count; + Dwarf_Fde **fde_data; + Dwarf_Signed *fde_element_count; + Dwarf_Error *error; +{ + Dwarf_Small *readp; + Dwarf_Small *readendp; + struct cielist *cielist = NULL; + struct cielist *copy_cielist; + unsigned int ncielist = 0; + struct fdelist *fdelist = NULL; + unsigned int nfdelist = 0; + + if (dbg->sections[IDX_eh_frame].addr == NULL) + return DW_DLV_NO_ENTRY; + + readp = (Dwarf_Small *) dbg->sections[IDX_eh_frame].addr; + readendp = readp + dbg->sections[IDX_eh_frame].size; + + while (readp < readendp) + { + /* Each CIE contains the following: + + 1. CIE_length (initial length) + + A constant that gives the number of bytes of the CIE + structure, not including the length field, itself [...]. + + 2. CIE_id + + A constant that is used to distinguish CIEs from FDEs. + + 3. version (ubyte) [...] + + 4. augmentation (array of ubyte) + + A null-terminated string that identifies the augmentation to + this CIE or to the FDEs that use it. + + 5. code_alignment_factor (unsigned LEB128) + + A constant that is factored out of all advance location + instructions (see below). + + 6. data_alignment_factor (signed LEB128) + + A constant that is factored out of all offset instructions + [...]. + + 7. return_address_register (ubyte) + + A constant that indicates which column in the rule table + represents the return address of the function. + + 8. initial_instructions (array of ubyte) [...] */ + Dwarf_Small *fde_cie_start; + Dwarf_Small *readstartp; + Dwarf_Small *cie_id_ptr; + Dwarf_Unsigned length; + unsigned int address_size; + Dwarf_Unsigned start_offset; + Dwarf_Unsigned cie_id; + + /* Remember where this entry started. */ + fde_cie_start = readp; + start_offset = (readp + - (Dwarf_Small *) dbg->sections[IDX_eh_frame].addr); + + length = read_4ubyte_unaligned (dbg, readp); + address_size = 4; + readp += 4; + if (length == 0xffffffff) + { + length = read_8ubyte_unaligned (dbg, readp); + readp += 8; + address_size = 8; + } + readstartp = readp; + + /* Requirement from the DWARF specification. */ + if (unlikely (length % address_size != 0)) + { + /* XXX Free resources. */ + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* No more entries. */ + if (length == 0) + break; + + cie_id_ptr = readp; + if (address_size == 4) + { + cie_id = read_4sbyte_unaligned (dbg, readp); + readp += 4; + } + else + { + cie_id = read_8sbyte_unaligned (dbg, readp); + readp += 8; + } + + /* Now we can distinguish between CIEs and FDEs. gcc uses 0 to + signal the record is a CIE. */ + if (cie_id == 0) + { + char *augmentation; + Dwarf_Unsigned code_alignment_factor; + Dwarf_Signed data_alignment_factor; + Dwarf_Small *initial_instructions; + Dwarf_Small return_address_register; + struct cielist *new_cie; + + if (unlikely (*readp++ != CIE_VERSION)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + augmentation = (char *) readp; + readp += strlen (augmentation) + 1; + + if (strcmp (augmentation, "") == 0) + { + get_uleb128 (code_alignment_factor, readp); + get_sleb128 (data_alignment_factor, readp); + return_address_register = *readp++; + initial_instructions = readp; + } + else if (strcmp (augmentation, "eh") == 0) + { + /* GCC exception handling. It has an extra field next + which is the address of a exception table. We ignore + this value since it's only used at runtime by the + exception handling. */ + readp += address_size; + + /* Now the standard fields. */ + get_uleb128 (code_alignment_factor, readp); + get_sleb128 (data_alignment_factor, readp); + return_address_register = *readp++; + initial_instructions = readp; + } + else + { + /* We don't know this augmentation. Skip the rest. The + specification says that nothing after the augmentation + string is usable. */ + code_alignment_factor = 0; + data_alignment_factor = 0; + return_address_register = 0; + initial_instructions = NULL; + } + + /* Go to the next record. */ + readp = readstartp + length; + + /* Create the new CIE record. */ + new_cie = (struct cielist *) alloca (sizeof (struct cielist)); + new_cie->cie = (Dwarf_Cie) malloc (sizeof (struct Dwarf_Cie_s)); + if (new_cie->cie == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + new_cie->cie->dbg = dbg; + new_cie->cie->length = length; + new_cie->cie->augmentation = augmentation; + new_cie->cie->code_alignment_factor = code_alignment_factor; + new_cie->cie->data_alignment_factor = data_alignment_factor; + new_cie->cie->return_address_register = return_address_register; + new_cie->cie->initial_instructions = initial_instructions; + new_cie->cie->initial_instructions_length = + readp - initial_instructions; + + new_cie->cie->offset = start_offset; + new_cie->cie->index = ncielist; + new_cie->next = cielist; + cielist = new_cie; + ++ncielist; + } + else + { + Dwarf_Addr initial_location; + Dwarf_Unsigned address_range; + Dwarf_Small *instructions; + struct fdelist *new_fde; + struct cielist *cie; + + if (address_size == 4) + { + initial_location = read_4ubyte_unaligned (dbg, readp); + readp += 4; + address_range = read_4ubyte_unaligned (dbg, readp); + readp += 4; + } + else + { + initial_location = read_8ubyte_unaligned (dbg, readp); + readp += 8; + address_range = read_8ubyte_unaligned (dbg, readp); + readp += 8; + } + + instructions = readp; + + /* Go to the next record. */ + readp = readstartp + length; + + /* Create the new FDE record. */ + new_fde = (struct fdelist *) alloca (sizeof (struct fdelist)); + new_fde->fde = (Dwarf_Fde) malloc (sizeof (struct Dwarf_Fde_s)); + if (new_fde->fde == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + new_fde->fde->initial_location = initial_location; + new_fde->fde->address_range = address_range; + new_fde->fde->instructions = instructions; + new_fde->fde->instructions_length = readp - instructions; + new_fde->fde->fde_bytes = fde_cie_start; + new_fde->fde->fde_byte_length = readstartp + length - fde_cie_start; + new_fde->fde->cie = NULL; + new_fde->cie_id_ptr = cie_id_ptr; + + for (cie = cielist; cie != NULL; cie = cie->next) + /* This test takes the non-standard way of using the CIE ID + in the GNU .eh_frame sectio into account. Instead of being + a direct offset in the section it is a offset from the + location of the FDE'S CIE ID value itself to the CIE entry. */ + if (cie->cie->offset + == (size_t) (cie_id_ptr - cie_id + - (Dwarf_Small *) dbg->sections[IDX_eh_frame].addr)) + { + new_fde->fde->cie = cie->cie; + break; + } + + new_fde->fde->offset = cie_id; + new_fde->next = fdelist; + fdelist = new_fde; + ++nfdelist; + } + } + + /* There must always be at least one CIE. */ + if (unlikely (ncielist == 0)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Create the lists. */ + *cie_data = (Dwarf_Cie *) malloc (ncielist * sizeof (struct Dwarf_Cie_s)); + if (nfdelist > 0) + *fde_data = (Dwarf_Fde *) malloc (nfdelist * sizeof (struct Dwarf_Fde_s)); + else + *fde_data = NULL; + if ((nfdelist > 0 && *fde_data == NULL) || *cie_data == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + /* Remember the counts. */ + dbg->fde_cnt = nfdelist; + dbg->cie_cnt = ncielist; + + /* Add all the CIEs. */ + copy_cielist = cielist; + *cie_element_count = ncielist; + while (ncielist-- > 0) + { + (*cie_data)[ncielist] = cielist->cie; + cielist = cielist->next; + } + + /* Add all the FDEs. */ + *fde_element_count = nfdelist; + while (nfdelist-- > 0) + { + (*fde_data)[nfdelist] = fdelist->fde; + + if (fdelist->fde->cie == NULL) + { + /* We have not yet found the CIE. Search now that we know + about all of them. */ + cielist = copy_cielist; + do + { + if (cielist->cie->offset + == (size_t) (fdelist->cie_id_ptr - fdelist->fde->offset + - (Dwarf_Small *) dbg->sections[IDX_eh_frame].addr)) + { + fdelist->fde->cie = cielist->cie; + break; + } + cielist = cielist->next; + } + while (cielist != NULL); + + if (cielist == NULL) + { + /* There is no matching CIE. This is bad. */ + /* XXX Free everything. */ + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + } + + fdelist = fdelist->next; + } + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_fde_n.c b/libdwarf/dwarf_get_fde_n.c new file mode 100644 index 00000000..5531deaf --- /dev/null +++ b/libdwarf/dwarf_get_fde_n.c @@ -0,0 +1,36 @@ +/* Get nth frame descriptions. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwarfP.h" + + +int +dwarf_get_fde_n (fde_data, fde_index, returned_fde, error) + Dwarf_Fde *fde_data; + Dwarf_Unsigned fde_index; + Dwarf_Fde *returned_fde; + Dwarf_Error *error; +{ + Dwarf_Debug dbg = fde_data[0]->cie->dbg; + + if (fde_index >= dbg->fde_cnt) + return DW_DLV_NO_ENTRY; + + *returned_fde = fde_data[fde_index]; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_fde_range.c b/libdwarf/dwarf_get_fde_range.c new file mode 100644 index 00000000..f7049145 --- /dev/null +++ b/libdwarf/dwarf_get_fde_range.c @@ -0,0 +1,44 @@ +/* Get information about the function range. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwarfP.h" + + +int +dwarf_get_fde_range (fde, low_pc, func_length, fde_bytes, fde_byte_length, + cie_offset, cie_index, fde_offset, error) + Dwarf_Fde fde; + Dwarf_Addr *low_pc; + Dwarf_Unsigned *func_length; + Dwarf_Ptr *fde_bytes; + Dwarf_Unsigned *fde_byte_length; + Dwarf_Off *cie_offset; + Dwarf_Signed *cie_index; + Dwarf_Off *fde_offset; + Dwarf_Error *error; +{ + *low_pc = fde->initial_location; + *func_length = fde->address_range; + *fde_bytes = fde->fde_bytes; + *fde_byte_length = fde->fde_byte_length; + *cie_offset = fde->cie->offset; + *cie_index = fde->cie->index; + *fde_offset = fde->offset; + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_globals.c b/libdwarf/dwarf_get_globals.c new file mode 100644 index 00000000..01b48ae7 --- /dev/null +++ b/libdwarf/dwarf_get_globals.c @@ -0,0 +1,176 @@ +/* Return list of global definitions. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +struct globallist +{ + Dwarf_Global global; + struct globallist *next; +}; + + +/* Read the whole given section. */ +int +dwarf_get_globals (dbg, globals, return_count, error) + Dwarf_Debug dbg; + Dwarf_Global **globals; + Dwarf_Signed *return_count; + Dwarf_Error *error; +{ + Dwarf_Small *readp; + Dwarf_Small *readendp; + struct globallist *globallist = NULL; + unsigned int ngloballist = 0; + + if (dbg->sections[IDX_debug_pubnames].addr == NULL) + return DW_DLV_NO_ENTRY; + + readp = (Dwarf_Small *) dbg->sections[IDX_debug_pubnames].addr; + readendp = readp + dbg->sections[IDX_debug_pubnames].size; + + while (readp < readendp) + { + Dwarf_Unsigned length; + Dwarf_Unsigned info_length; + unsigned int length_bytes; + unsigned int version; + Dwarf_Unsigned offset; + Dwarf_Global_Info global_info; + + /* Each entry starts with a header: + + 1. A 4-byte or 12-byte length of the set of entries for this + compilation unit, not including the length field itself. [...] + + 2. A 2-byte version identifier containing the value 2 for + DWARF Version 2.1. + + 3. A 4-byte or 8-byte offset into the .debug_info section. [...] + + 4. A 4-byte or 8-byte length containing the size in bytes of + the contents of the .debug_info section generated to + represent this compilation unit. [...] */ + length = read_4ubyte_unaligned (dbg, readp); + readp += 4; + length_bytes = 4; + if (length == 0xffffffff) + { + length = read_8ubyte_unaligned (dbg, readp); + readp += 8; + length_bytes = 8; + } + + version = read_2ubyte_unaligned (dbg, readp); + readp += 2; + if (unlikely (version != 2)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + if (length_bytes == 4) + { + offset = read_4ubyte_unaligned (dbg, readp); + readp += 4; + info_length = read_4ubyte_unaligned (dbg, readp); + readp += 4; + } + else + { + offset = read_8ubyte_unaligned (dbg, readp); + readp += 8; + info_length = read_8ubyte_unaligned (dbg, readp); + readp += 8; + } + + global_info = + (Dwarf_Global_Info) malloc (sizeof (struct Dwarf_Global_s)); + if (global_info == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + global_info->dbg = dbg; + global_info->offset = offset; + + /* Following the section contains tuples of offsets and + nul-terminated strings. */ + while (1) + { + Dwarf_Unsigned die_offset; + struct globallist *new_global; + + if (length_bytes == 4) + die_offset = read_4ubyte_unaligned (dbg, readp); + else + die_offset = read_8ubyte_unaligned (dbg, readp); + readp += length_bytes; + + if (die_offset == 0) + /* This closes this entry. */ + break; + + new_global = + (struct globallist *) alloca (sizeof (struct globallist)); + new_global->global = + (Dwarf_Global) malloc (sizeof (struct Dwarf_Global_s)); + if (new_global->global == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + new_global->global->offset = die_offset; + new_global->global->name = (char *) readp; + new_global->global->info = global_info; + + new_global->next = globallist; + globallist = new_global; + ++ngloballist; + + readp = (Dwarf_Small *) rawmemchr (readp, '\0') + 1; + } + } + + if (ngloballist == 0) + return DW_DLV_NO_ENTRY; + + /* Allocate the array for the result. */ + *return_count = ngloballist; + *globals = (Dwarf_Global *) malloc (ngloballist + * sizeof (struct Dwarf_Global_s)); + if (*globals == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + while (ngloballist-- > 0) + { + (*globals)[ngloballist] = globallist->global; + globallist = globallist->next; + } + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_loclist_entry.c b/libdwarf/dwarf_get_loclist_entry.c new file mode 100644 index 00000000..f6510c77 --- /dev/null +++ b/libdwarf/dwarf_get_loclist_entry.c @@ -0,0 +1,88 @@ +/* Return location list entry. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwarfP.h" + + +int +dwarf_get_loclist_entry (dbg, offset, hipc_offset, lopc_offset, data, + entry_len, next_entry, error) + Dwarf_Debug dbg; + Dwarf_Unsigned offset; + Dwarf_Addr *hipc_offset; + Dwarf_Addr *lopc_offset; + Dwarf_Ptr *data; + Dwarf_Unsigned *entry_len; + Dwarf_Unsigned *next_entry; + Dwarf_Error *error; +{ + Dwarf_Small *locp; + + /* Make sure we have room for at least two addresses. */ + if (unlikely (offset + 2 * dbg->cu_list->address_size + > dbg->sections[IDX_debug_loc].size)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + locp = (Dwarf_Small *) dbg->sections[IDX_debug_loc].addr + offset; + + /* Get the two values. */ + if (dbg->cu_list->address_size == 4) + { + *lopc_offset = read_4ubyte_unaligned (dbg, locp); + *hipc_offset = read_4ubyte_unaligned (dbg, locp + 4); + locp += 8; + offset += 8; + } + else + { + *lopc_offset = read_8ubyte_unaligned (dbg, locp); + *hipc_offset = read_8ubyte_unaligned (dbg, locp + 8); + locp += 16; + offset += 16; + } + + /* Does this signal the end? */ + if (*lopc_offset == 0 && *hipc_offset == 0) + return DW_DLV_OK; + + /* Make sure another 2 bytes are available for the length. */ + if (unlikely (offset + 2 > dbg->sections[IDX_debug_loc].size)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + *entry_len = read_2ubyte_unaligned (dbg, locp); + locp += 2; + offset += 2; + *data = locp; + + /* Now we know how long the block is. Test whether that much + data is available. */ + if (unlikely (offset + *entry_len > dbg->sections[IDX_debug_loc].size)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + *next_entry = offset + *entry_len; + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_get_str.c b/libdwarf/dwarf_get_str.c new file mode 100644 index 00000000..3f289c3d --- /dev/null +++ b/libdwarf/dwarf_get_str.c @@ -0,0 +1,43 @@ +/* Return string from debug string section. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "libdwarfP.h" + + +int +dwarf_get_str (dbg, offset, string, returned_str_len, error) + Dwarf_Debug dbg; + Dwarf_Off offset; + char **string; + Dwarf_Signed *returned_str_len; + Dwarf_Error *error; +{ + *string = (char *) dbg->sections[IDX_debug_str].addr; + if (*string == NULL) + return DW_DLV_NO_ENTRY; + + if (unlikely (offset >= dbg->sections[IDX_debug_str].size)) + return DW_DLV_NO_ENTRY; + + *string += offset; + *returned_str_len = strlen (*string); + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_getabbrev.c b/libdwarf/dwarf_getabbrev.c new file mode 100644 index 00000000..2220fc34 --- /dev/null +++ b/libdwarf/dwarf_getabbrev.c @@ -0,0 +1,73 @@ +/* Internal abbrev list handling + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +Dwarf_Abbrev +__libdwarf_get_abbrev (dbg, cu, code, error) + Dwarf_Debug dbg; + Dwarf_CU_Info cu; + Dwarf_Word code; + Dwarf_Error *error; +{ + Dwarf_Abbrev ent; + + /* See whether the entry is already in the hash table. */ + ent = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL); + if (ent != NULL) + return ent; + + while (1) + { + Dwarf_Unsigned length; + Dwarf_Unsigned attr_count; + + if (dwarf_get_abbrev (dbg, cu->last_abbrev_offset, &ent, &length, + &attr_count, error) != DW_DLV_OK) + return NULL; + + if (length == 1) + /* This is the end of the list. */ + break; + + /* Update the offset to the next record. */ + cu->last_abbrev_offset += length; + + /* Insert the new entry into the hashing table. */ + if (unlikely (Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, ent->code, ent) + != 0)) + { + free (ent); + __libdwarf_error (dbg, error, DW_E_NOMEM); + return NULL; + } + + /* Is this the code we are looking for? */ + if (ent->code == code) + /* Yes! */ + return ent; + } + + /* If we come here we haven't found anything. */ + __libdwarf_error (dbg, error, DW_E_NO_ABBR); + return NULL; +} diff --git a/libdwarf/dwarf_getconstant.c b/libdwarf/dwarf_getconstant.c new file mode 100644 index 00000000..39727f8a --- /dev/null +++ b/libdwarf/dwarf_getconstant.c @@ -0,0 +1,125 @@ +/* Return constant value of given attribute type associated with die. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +__libdwarf_getconstant (die, name, return_size, error) + Dwarf_Die die; + Dwarf_Half name; + Dwarf_Unsigned *return_size; + Dwarf_Error *error; +{ + Dwarf_Debug dbg = die->cu->dbg; + Dwarf_Small *die_addr; + Dwarf_Word u128; + Dwarf_Abbrev abbrev; + Dwarf_Small *attrp; + + /* Address of the given die. */ + die_addr = die->addr; + + /* Get abbrev code. */ + get_uleb128 (u128, die_addr); + /* And get the abbreviation itself. */ + abbrev = __libdwarf_get_abbrev (dbg, die->cu, u128, error); + if (abbrev == NULL) + return DW_DLV_ERROR; + + /* This is where the attributes start. */ + attrp = abbrev->attrp; + + /* Search the name attribute. */ + while (1) + { + Dwarf_Word attr_name; + Dwarf_Word attr_form; + + /* Are we still in bounds? */ + if (unlikely (attrp + >= ((Dwarf_Small *) dbg->sections[IDX_debug_abbrev].addr + + dbg->sections[IDX_debug_abbrev].size))) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Get attribute name and form. + + XXX We don't check whether this reads beyond the end of the + section. */ + get_uleb128 (attr_name, attrp); + get_uleb128 (attr_form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* Is this the name attribute? */ + if (unlikely (attr_name == name)) + { + switch (attr_form) + { + case DW_FORM_data1: + *return_size = *die_addr; + break; + case DW_FORM_data2: + *return_size = read_2ubyte_unaligned (dbg, die_addr); + break; + case DW_FORM_data4: + *return_size = read_4ubyte_unaligned (dbg, die_addr); + break; + case DW_FORM_data8: + *return_size = read_8ubyte_unaligned (dbg, die_addr); + break; + case DW_FORM_sdata: + get_sleb128 (u128, die_addr); + *return_size = u128; + break; + case DW_FORM_udata: + get_uleb128 (u128, die_addr); + *return_size = u128; + break; + default: + __libdwarf_error (dbg, error, DW_E_NO_CONSTANT); + return DW_DLV_ERROR; + } + + return DW_DLV_OK; + } + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len; + + if (unlikely (__libdwarf_form_val_len (dbg, die->cu, attr_form, + die_addr, &len, error) + != DW_DLV_OK)) + return DW_DLV_ERROR; + + die_addr += len; + } + } + + /* No such attribute present. */ + return DW_DLV_NO_ENTRY; +} diff --git a/libdwarf/dwarf_global_cu_offset.c b/libdwarf/dwarf_global_cu_offset.c new file mode 100644 index 00000000..b5a30f42 --- /dev/null +++ b/libdwarf/dwarf_global_cu_offset.c @@ -0,0 +1,44 @@ +/* Return offset of header of compile unit containing the global definition. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_global_cu_offset (global, return_offset, error) + Dwarf_Global global; + Dwarf_Off *return_offset; + Dwarf_Error *error; +{ + Dwarf_Small *cu_header; + unsigned int offset_size; + + cu_header = + ((Dwarf_Small *) global->info->dbg->sections[IDX_debug_info].addr + + global->info->offset); + if (read_4ubyte_unaligned_noncvt (cu_header) == 0xffffffff) + offset_size = 8; + else + offset_size = 4; + + *return_offset = global->info->offset + 3 * offset_size - 4 + 3; + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_global_die_offset.c b/libdwarf/dwarf_global_die_offset.c new file mode 100644 index 00000000..654340fc --- /dev/null +++ b/libdwarf/dwarf_global_die_offset.c @@ -0,0 +1,33 @@ +/* Return DIE offset for global definition. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_global_die_offset (global, return_offset, error) + Dwarf_Global global; + Dwarf_Off *return_offset; + Dwarf_Error *error; +{ + *return_offset = global->info->offset + global->offset; + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_global_formref.c b/libdwarf/dwarf_global_formref.c new file mode 100644 index 00000000..16ea7b7a --- /dev/null +++ b/libdwarf/dwarf_global_formref.c @@ -0,0 +1,73 @@ +/* Return .debug_info section global offset of reference associated with form. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_global_formref (attr, return_offset, error) + Dwarf_Attribute attr; + Dwarf_Off *return_offset; + Dwarf_Error *error; +{ + switch (attr->form) + { + case DW_FORM_ref1: + *return_offset = *attr->valp + attr->cu->offset; + break; + + case DW_FORM_ref2: + *return_offset = (read_2ubyte_unaligned (attr->cu->dbg, attr->valp) + + attr->cu->offset); + break; + + case DW_FORM_ref4: + *return_offset = (read_4ubyte_unaligned (attr->cu->dbg, attr->valp) + + attr->cu->offset); + break; + + case DW_FORM_ref8: + *return_offset = (read_8ubyte_unaligned (attr->cu->dbg, attr->valp) + + attr->cu->offset); + break; + + case DW_FORM_ref_udata: + { + Dwarf_Off off; + Dwarf_Small *attrp = attr->valp; + get_uleb128 (off, attrp); + *return_offset = off + attr->cu->offset; + } + break; + + case DW_FORM_ref_addr: + if (attr->cu->address_size == 4) + *return_offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + else + *return_offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + default: + __libdwarf_error (attr->cu->dbg, error, DW_E_NO_REFERENCE); + return DW_DLV_ERROR; + } + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_global_name_offsets.c b/libdwarf/dwarf_global_name_offsets.c new file mode 100644 index 00000000..a9b149c0 --- /dev/null +++ b/libdwarf/dwarf_global_name_offsets.c @@ -0,0 +1,64 @@ +/* Return name, DIE offset, and offset of the compile unit for global + definition. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_global_name_offsets (global, return_name, die_offset, cu_offset, error) + Dwarf_Global global; + char **return_name; + Dwarf_Off *die_offset; + Dwarf_Off *cu_offset; + Dwarf_Error *error; +{ + if (return_name != NULL) + { + *return_name = strdup (global->name); + if (*return_name == NULL) + { + __libdwarf_error (global->info->dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + } + + if (die_offset != NULL) + *die_offset = global->offset + global->info->offset; + + /* Determine the size of the CU header. */ + if (cu_offset != NULL) + { + Dwarf_Small *cu_header; + unsigned int offset_size; + + cu_header = + ((Dwarf_Small *) global->info->dbg->sections[IDX_debug_info].addr + + global->info->offset); + if (read_4ubyte_unaligned_noncvt (cu_header) == 0xffffffff) + offset_size = 8; + else + offset_size = 4; + + *cu_offset = global->info->offset + 3 * offset_size - 4 + 3; + } + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_globname.c b/libdwarf/dwarf_globname.c new file mode 100644 index 00000000..1c565290 --- /dev/null +++ b/libdwarf/dwarf_globname.c @@ -0,0 +1,38 @@ +/* Return name for global definition. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_globname (global, return_name, error) + Dwarf_Global global; + char **return_name; + Dwarf_Error *error; +{ + *return_name = strdup (global->name); + if (*return_name == NULL) + { + __libdwarf_error (global->info->dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_hasattr.c b/libdwarf/dwarf_hasattr.c new file mode 100644 index 00000000..337a3e10 --- /dev/null +++ b/libdwarf/dwarf_hasattr.c @@ -0,0 +1,98 @@ +/* Determine whether die has attribute specified of given type. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_hasattr (die, attr, return_bool, error) + Dwarf_Die die; + Dwarf_Half attr; + Dwarf_Bool *return_bool; + Dwarf_Error *error; +{ + Dwarf_Debug dbg = die->cu->dbg; + Dwarf_Small *die_addr; + Dwarf_Word u128; + Dwarf_Abbrev abbrev; + Dwarf_Small *attrp; + + /* Address of the given die. */ + die_addr = die->addr; + + /* Get abbrev code. */ + get_uleb128 (u128, die_addr); + /* And get the abbreviation itself. */ + abbrev = __libdwarf_get_abbrev (dbg, die->cu, u128, error); + if (abbrev == NULL) + return DW_DLV_ERROR; + + /* This is where the attributes start. */ + attrp = abbrev->attrp; + + /* Search the name attribute. */ + while (1) + { + Dwarf_Word attr_name; + Dwarf_Word attr_form; + + /* Are we still in bounds? */ + if (unlikely (attrp + >= ((Dwarf_Small *) dbg->sections[IDX_debug_abbrev].addr + + dbg->sections[IDX_debug_abbrev].size))) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Get attribute name and form. + + XXX We don't check whether this reads beyond the end of the + section. */ + get_uleb128 (attr_name, attrp); + get_uleb128 (attr_form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* Is this the name attribute? */ + if (attr_name == attr) + { + *return_bool = 1; + return DW_DLV_OK; + } + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len; + + if (unlikely (__libdwarf_form_val_len (dbg, die->cu, attr_form, + die_addr, &len, error) + != DW_DLV_OK)) + return DW_DLV_ERROR; + + die_addr += len; + } + } + + /* No such attribute present. */ + *return_bool = 0; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_hasform.c b/libdwarf/dwarf_hasform.c new file mode 100644 index 00000000..cfb6cf99 --- /dev/null +++ b/libdwarf/dwarf_hasform.c @@ -0,0 +1,31 @@ +/* Determine whether attribute has given form. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_hasform (attr, form, return_hasform, error) + Dwarf_Attribute attr; + Dwarf_Half form; + Dwarf_Bool *return_hasform; + Dwarf_Error *error; +{ + *return_hasform = attr->form == form; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_highpc.c b/libdwarf/dwarf_highpc.c new file mode 100644 index 00000000..5e56376d --- /dev/null +++ b/libdwarf/dwarf_highpc.c @@ -0,0 +1,108 @@ +/* Return high program counter value associated with die. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_highpc (die, return_highpc, error) + Dwarf_Die die; + Dwarf_Addr *return_highpc; + Dwarf_Error *error; +{ + Dwarf_Debug dbg = die->cu->dbg; + Dwarf_Small *die_addr; + Dwarf_Word u128; + Dwarf_Abbrev abbrev; + Dwarf_Small *attrp; + + /* Address of the given die. */ + die_addr = die->addr; + + /* Get abbrev code. */ + get_uleb128 (u128, die_addr); + /* And get the abbreviation itself. */ + abbrev = __libdwarf_get_abbrev (dbg, die->cu, u128, error); + if (abbrev == NULL) + return DW_DLV_ERROR; + + /* This is where the attributes start. */ + attrp = abbrev->attrp; + + /* Search the name attribute. */ + while (1) + { + Dwarf_Word attr_name; + Dwarf_Word attr_form; + + /* Are we still in bounds? */ + if (unlikely (attrp + >= ((Dwarf_Small *) dbg->sections[IDX_debug_abbrev].addr + + dbg->sections[IDX_debug_abbrev].size))) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Get attribute name and form. + + XXX We don't check whether this reads beyond the end of the + section. */ + get_uleb128 (attr_name, attrp); + get_uleb128 (attr_form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* Is this the name attribute? */ + if (unlikely (attr_name == DW_AT_high_pc)) + { + if (unlikely (attr_form != DW_FORM_addr)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + if (die->cu->address_size == 4) + *return_highpc = read_4ubyte_unaligned (dbg, die_addr); + else + *return_highpc = read_8ubyte_unaligned (dbg, die_addr); + + return DW_DLV_OK; + } + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len; + + if (unlikely (__libdwarf_form_val_len (dbg, die->cu, attr_form, + die_addr, &len, error) + != DW_DLV_OK)) + return DW_DLV_ERROR; + + die_addr += len; + } + } + + /* No such attribute present. */ + return DW_DLV_NO_ENTRY; +} diff --git a/libdwarf/dwarf_init.c b/libdwarf/dwarf_init.c new file mode 100644 index 00000000..bbb86602 --- /dev/null +++ b/libdwarf/dwarf_init.c @@ -0,0 +1,92 @@ +/* Create descriptor from file descriptor for processing file. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +int +dwarf_init (fd, access, errhand, errarg, dbg, error) + int fd; + Dwarf_Unsigned access; + Dwarf_Handler errhand; + Dwarf_Ptr errarg; + Dwarf_Debug *dbg; + Dwarf_Error *error; +{ + Elf *elf; + Elf_Cmd cmd; + struct Dwarf_Debug_s newdbg; + int result = DW_DLV_ERROR; + + switch (access) + { + case DW_DLC_READ: + cmd = ELF_C_READ_MMAP; + break; + case DW_DLC_WRITE: + cmd = ELF_C_WRITE; + break; + case DW_DLC_RDWR: + cmd = ELF_C_RDWR; + break; + default: + /* These are the error values we want to use. */ + newdbg.dbg_errhand = errhand; + newdbg.dbg_errarg = errarg; + + __libdwarf_error (&newdbg, error, DW_E_INVALID_ACCESS); + return DW_DLV_ERROR; + } + + /* We have to call `elf_version' here since the user might have not + done it or initialized libelf with a different version. This + would break libdwarf since we are using the ELF data structures + in a certain way. */ + elf_version (EV_CURRENT); + + /* Get an ELF descriptor. */ + elf = elf_begin (fd, cmd, NULL); + if (elf == NULL) + { + /* Test why the `elf_begin" call failed. */ + struct stat64 st; + + /* These are the error values we want to use. */ + newdbg.dbg_errhand = errhand; + newdbg.dbg_errarg = errarg; + + if (fstat64 (fd, &st) == 0 && ! S_ISREG (st.st_mode)) + __libdwarf_error (&newdbg, error, DW_E_NO_REGFILE); + else + __libdwarf_error (&newdbg, error, DW_E_IO_ERROR); + } + else + { + /* Do the real work now that we have an ELF descriptor. */ + result = dwarf_elf_init (elf, access, errhand, errarg, dbg, error); + + /* If this failed, free the resources. */ + if (result != DW_DLV_OK) + elf_end (elf); + } + + return result; +} diff --git a/libdwarf/dwarf_lineaddr.c b/libdwarf/dwarf_lineaddr.c new file mode 100644 index 00000000..4bf49435 --- /dev/null +++ b/libdwarf/dwarf_lineaddr.c @@ -0,0 +1,30 @@ +/* Return address associate with line. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_lineaddr (line, return_lineaddr, error) + Dwarf_Line line; + Dwarf_Addr *return_lineaddr; + Dwarf_Error *error; +{ + *return_lineaddr = line->addr; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_linebeginstatement.c b/libdwarf/dwarf_linebeginstatement.c new file mode 100644 index 00000000..d04c6ec9 --- /dev/null +++ b/libdwarf/dwarf_linebeginstatement.c @@ -0,0 +1,30 @@ +/* Determine whether line is the beginning of a statement. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_linebeginstatement (line, return_bool, error) + Dwarf_Line line; + Dwarf_Bool *return_bool; + Dwarf_Error *error; +{ + *return_bool = line->is_stmt; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_lineblock.c b/libdwarf/dwarf_lineblock.c new file mode 100644 index 00000000..f15e54b9 --- /dev/null +++ b/libdwarf/dwarf_lineblock.c @@ -0,0 +1,30 @@ +/* Determine whether line is marked as beginning a basic block. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_lineblock (line, return_bool, error) + Dwarf_Line line; + Dwarf_Bool *return_bool; + Dwarf_Error *error; +{ + *return_bool = line->basic_block; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_lineendsequence.c b/libdwarf/dwarf_lineendsequence.c new file mode 100644 index 00000000..93cbf8ec --- /dev/null +++ b/libdwarf/dwarf_lineendsequence.c @@ -0,0 +1,30 @@ +/* Determine whether line is marked as ending a text sequence. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_lineendsequence (line, return_bool, error) + Dwarf_Line line; + Dwarf_Bool *return_bool; + Dwarf_Error *error; +{ + *return_bool = line->end_sequence; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_lineepiloguebegin.c b/libdwarf/dwarf_lineepiloguebegin.c new file mode 100644 index 00000000..33df13f1 --- /dev/null +++ b/libdwarf/dwarf_lineepiloguebegin.c @@ -0,0 +1,30 @@ +/* Determine whether line is marked as beginning the epilogue. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_lineepiloguebegin (line, return_bool, error) + Dwarf_Line line; + Dwarf_Bool *return_bool; + Dwarf_Error *error; +{ + *return_bool = line->epilogue_begin; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_lineno.c b/libdwarf/dwarf_lineno.c new file mode 100644 index 00000000..83f911d5 --- /dev/null +++ b/libdwarf/dwarf_lineno.c @@ -0,0 +1,30 @@ +/* Return source statement line number. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_lineno (line, return_lineno, error) + Dwarf_Line line; + Dwarf_Unsigned *return_lineno; + Dwarf_Error *error; +{ + *return_lineno = line->line; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_lineoff.c b/libdwarf/dwarf_lineoff.c new file mode 100644 index 00000000..82f4bbcc --- /dev/null +++ b/libdwarf/dwarf_lineoff.c @@ -0,0 +1,30 @@ +/* Return column at which the statement begins. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_lineoff (line, return_lineoff, error) + Dwarf_Line line; + Dwarf_Signed *return_lineoff; + Dwarf_Error *error; +{ + *return_lineoff = line->column ?: -1; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_lineprologueend.c b/libdwarf/dwarf_lineprologueend.c new file mode 100644 index 00000000..f202f73d --- /dev/null +++ b/libdwarf/dwarf_lineprologueend.c @@ -0,0 +1,30 @@ +/* Determine whether line is marked as ending the prologue. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_lineprologueend (line, return_bool, error) + Dwarf_Line line; + Dwarf_Bool *return_bool; + Dwarf_Error *error; +{ + *return_bool = line->prologue_end; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_linesrc.c b/libdwarf/dwarf_linesrc.c new file mode 100644 index 00000000..5c990009 --- /dev/null +++ b/libdwarf/dwarf_linesrc.c @@ -0,0 +1,44 @@ +/* Return source file for line. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_linesrc (line, return_linesrc, error) + Dwarf_Line line; + char **return_linesrc; + Dwarf_Error *error; +{ + if (unlikely (line->file >= line->files->nfiles)) + { + __libdwarf_error (line->files->dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + *return_linesrc = strdup (line->files->info[line->file].name); + if (*return_linesrc == NULL) + { + __libdwarf_error (line->files->dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_loclist.c b/libdwarf/dwarf_loclist.c new file mode 100644 index 00000000..22a3944f --- /dev/null +++ b/libdwarf/dwarf_loclist.c @@ -0,0 +1,470 @@ +/* Return location expression list. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +struct loclist +{ + Dwarf_Small atom; + Dwarf_Unsigned number; + Dwarf_Unsigned number2; + Dwarf_Unsigned offset; + struct loclist *next; +}; + +struct locdesclist +{ + Dwarf_Addr lopc; + Dwarf_Addr hipc; + Dwarf_Half cents; + struct loclist *s; + struct locdesclist *next; +}; + + +int +dwarf_loclist (attr, llbuf, listlen, error) + Dwarf_Attribute attr; + Dwarf_Locdesc **llbuf; + Dwarf_Signed *listlen; + Dwarf_Error *error; +{ + Dwarf_CU_Info cu = attr->cu; + Dwarf_Debug dbg = cu->dbg; + Dwarf_Unsigned offset; + Dwarf_Unsigned offset_end; + Dwarf_Small *locp; + struct locdesclist *locdesclist; + Dwarf_Locdesc *result; + unsigned int n; + + /* Must by one of the attribute listed below. */ + if (attr->code != DW_AT_location + && attr->code != DW_AT_data_member_location + && attr->code != DW_AT_vtable_elem_location + && attr->code != DW_AT_string_length + && attr->code != DW_AT_use_location + && attr->code != DW_AT_return_addr) + { + __libdwarf_error (dbg, error, DW_E_WRONG_ATTR); + return DW_DLV_ERROR; + } + + /* Must have the form data4 or data8 which act as an offset. */ + if (attr->form == DW_FORM_data4) + offset = read_4ubyte_unaligned (dbg, attr->valp); + else if (likely (attr->form == DW_FORM_data8)) + offset = read_8ubyte_unaligned (dbg, attr->valp); + else + { + __libdwarf_error (dbg, error, DW_E_NO_DATA); + return DW_DLV_ERROR; + } + + /* Check whether the .debug_loc section is available. */ + if (unlikely (dbg->sections[IDX_debug_loc].addr == NULL)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* This is the part of the .debug_loc section we can read. */ + locp = (Dwarf_Small *) dbg->sections[IDX_debug_loc].addr + offset; + offset_end = offset + dbg->sections[IDX_debug_loc].size; + + locdesclist = NULL; + n = 0; + while (1) + { + Dwarf_Addr lopc; + Dwarf_Addr hipc; + Dwarf_Ptr data; + Dwarf_Unsigned len2; + struct locdesclist *newdesc; + Dwarf_Small *locp; + Dwarf_Small *blkendp; + Dwarf_Small *blkstartp; + + if (unlikely (dwarf_get_loclist_entry (dbg, offset, &hipc, &lopc, &data, + &len2, &offset, error) + != DW_DLV_OK)) + return DW_DLV_ERROR; + + /* Does this signal the end? */ + if (lopc == 0 && hipc == 0) + break; + + locp = data; + blkstartp = locp; + blkendp = locp + len2; + + /* Create a new Locdesc entry. */ + newdesc = (struct locdesclist *) alloca (sizeof (struct locdesclist)); + newdesc->lopc = lopc; + newdesc->hipc = hipc; + newdesc->cents = 0; + newdesc->s = NULL; + newdesc->next = locdesclist; + locdesclist = newdesc; + ++n; + + /* Decode the opcodes. It is possible in some situations to + have a block of size zero. */ + while (locp < blkendp) + { + struct loclist *newloc; + + newloc = (struct loclist *) alloca (sizeof (struct loclist)); + newloc->number = 0; + newloc->number2 = 0; + newloc->offset = locp - blkstartp; + newloc->next = newdesc->s; + newdesc->s = newloc; + ++newdesc->cents; + + newloc->atom = *locp; + switch (*locp++) + { + case DW_OP_addr: + /* Address, depends on address size of CU. */ + if (cu->address_size == 4) + { + if (unlikely (locp + 4 > blkendp)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + newloc->number = read_4ubyte_unaligned (dbg, locp); + locp += 4; + } + else + { + if (unlikely (locp + 8 > blkendp)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + newloc->number = read_8ubyte_unaligned (dbg, locp); + locp += 8; + } + break; + + case DW_OP_deref: + case DW_OP_dup: + case DW_OP_drop: + case DW_OP_over: + case DW_OP_swap: + case DW_OP_rot: + case DW_OP_xderef: + case DW_OP_abs: + case DW_OP_and: + case DW_OP_div: + case DW_OP_minus: + case DW_OP_mod: + case DW_OP_mul: + case DW_OP_neg: + case DW_OP_not: + case DW_OP_or: + case DW_OP_plus: + case DW_OP_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + case DW_OP_eq: + case DW_OP_ge: + case DW_OP_gt: + case DW_OP_le: + case DW_OP_lt: + case DW_OP_ne: + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + case DW_OP_nop: + case DW_OP_push_object_address: + case DW_OP_call_ref: + /* No operand. */ + break; + + case DW_OP_const1u: + case DW_OP_pick: + case DW_OP_deref_size: + case DW_OP_xderef_size: + if (unlikely (locp >= blkendp)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + newloc->number = *((uint8_t *) locp)++; + break; + + case DW_OP_const1s: + if (unlikely (locp >= blkendp)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + newloc->number = *((int8_t *) locp)++; + break; + + case DW_OP_const2u: + if (unlikely (locp + 2 > blkendp)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + newloc->number = read_2ubyte_unaligned (dbg, locp); + locp += 2; + break; + + case DW_OP_const2s: + case DW_OP_skip: + case DW_OP_bra: + case DW_OP_call2: + if (unlikely (locp + 2 > blkendp)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + newloc->number = read_2sbyte_unaligned (dbg, locp); + locp += 2; + break; + + case DW_OP_const4u: + if (unlikely (locp + 4 > blkendp)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + newloc->number = read_4ubyte_unaligned (dbg, locp); + locp += 4; + break; + + case DW_OP_const4s: + case DW_OP_call4: + if (unlikely (locp + 4 > blkendp)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + newloc->number = read_4sbyte_unaligned (dbg, locp); + locp += 4; + break; + + case DW_OP_const8u: + if (unlikely (locp + 8 > blkendp)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + newloc->number = read_8ubyte_unaligned (dbg, locp); + locp += 8; + break; + + case DW_OP_const8s: + if (unlikely (locp + 8 > blkendp)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + newloc->number = read_8sbyte_unaligned (dbg, locp); + locp += 8; + break; + + case DW_OP_constu: + case DW_OP_plus_uconst: + case DW_OP_regx: + case DW_OP_piece: + /* XXX Check size. */ + get_uleb128 (newloc->number, locp); + break; + + case DW_OP_consts: + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + case DW_OP_fbreg: + /* XXX Check size. */ + get_sleb128 (newloc->number, locp); + break; + + case DW_OP_bregx: + /* XXX Check size. */ + get_uleb128 (newloc->number, locp); + get_sleb128 (newloc->number2, locp); + break; + + default: + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + } + } + + if (unlikely (n == 0)) + { + /* This is not allowed. + + XXX Is it? */ + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Allocate the array. */ + result = (Dwarf_Locdesc *) malloc (n * sizeof (Dwarf_Locdesc)); + if (result == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + /* Store the result. */ + *llbuf = result; + *listlen = n; + + do + { + unsigned int cents; + struct loclist *s; + + /* We populate the array from the back since the list is + backwards. */ + --n; + + result[n].ld_lopc = locdesclist->lopc; + result[n].ld_hipc = locdesclist->hipc; + result[n].ld_cents = cents = locdesclist->cents; + result[n].ld_s = (Dwarf_Loc *) malloc (cents * sizeof (Dwarf_Loc)); + if (result == NULL) + { + /* XXX Should be bother freeing memory? */ + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + s = locdesclist->s; + while (cents-- > 0) + { + /* This list is also backwards. */ + result[n].ld_s[cents].lr_atom = s->atom; + result[n].ld_s[cents].lr_number = s->number; + result[n].ld_s[cents].lr_number2 = s->number2; + result[n].ld_s[cents].lr_offset = s->offset; + s = s->next; + } + + locdesclist = locdesclist->next; + } + while (n > 0); + + /* We did it. */ + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_lowpc.c b/libdwarf/dwarf_lowpc.c new file mode 100644 index 00000000..c21edc92 --- /dev/null +++ b/libdwarf/dwarf_lowpc.c @@ -0,0 +1,108 @@ +/* Return low program counter value associated with die. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_lowpc (die, return_lowpc, error) + Dwarf_Die die; + Dwarf_Addr *return_lowpc; + Dwarf_Error *error; +{ + Dwarf_Debug dbg = die->cu->dbg; + Dwarf_Small *die_addr; + Dwarf_Word u128; + Dwarf_Abbrev abbrev; + Dwarf_Small *attrp; + + /* Address of the given die. */ + die_addr = die->addr; + + /* Get abbrev code. */ + get_uleb128 (u128, die_addr); + /* And get the abbreviation itself. */ + abbrev = __libdwarf_get_abbrev (dbg, die->cu, u128, error); + if (abbrev == NULL) + return DW_DLV_ERROR; + + /* This is where the attributes start. */ + attrp = abbrev->attrp; + + /* Search the name attribute. */ + while (1) + { + Dwarf_Word attr_name; + Dwarf_Word attr_form; + + /* Are we still in bounds? */ + if (unlikely (attrp + >= ((Dwarf_Small *) dbg->sections[IDX_debug_abbrev].addr + + dbg->sections[IDX_debug_abbrev].size))) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Get attribute name and form. + + XXX We don't check whether this reads beyond the end of the + section. */ + get_uleb128 (attr_name, attrp); + get_uleb128 (attr_form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* Is this the name attribute? */ + if (unlikely (attr_name == DW_AT_low_pc)) + { + if (unlikely (attr_form != DW_FORM_addr)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + if (die->cu->address_size == 4) + *return_lowpc = read_4ubyte_unaligned (dbg, die_addr); + else + *return_lowpc = read_8ubyte_unaligned (dbg, die_addr); + + return DW_DLV_OK; + } + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len; + + if (unlikely (__libdwarf_form_val_len (dbg, die->cu, attr_form, + die_addr, &len, error) + != DW_DLV_OK)) + return DW_DLV_ERROR; + + die_addr += len; + } + } + + /* No such attribute present. */ + return DW_DLV_NO_ENTRY; +} diff --git a/libdwarf/dwarf_next_cu_header.c b/libdwarf/dwarf_next_cu_header.c new file mode 100644 index 00000000..54bb39e3 --- /dev/null +++ b/libdwarf/dwarf_next_cu_header.c @@ -0,0 +1,234 @@ +/* Get offset of next compilation unit. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +/* A good initial size for the abbreviation hashing table. */ +#define DEFAULT_ABBREV_HASH_SIZE 257 + + +int +internal_function +__libdwarf_get_cu_at_offset (Dwarf_Debug dbg, Dwarf_Unsigned offset, + Dwarf_CU_Info *result_cu, Dwarf_Error *error) +{ + Dwarf_CU_Info cu; + Dwarf_Small *cu_bytes; + Dwarf_Unsigned length; + Dwarf_Half offset_size; + + /* Make sure there is enough space in the .debug_info section for at + least the initial word. We cannot test the rest since we don't + know yet whether this is a 64-bit object or not. */ + if (unlikely (offset + 4 >= dbg->sections[IDX_debug_info].size)) + { + dbg->cu_list_current = NULL; + return DW_DLV_NO_ENTRY; + } + + /* This points into the .debug_info section to the beginning of the + CU entry. */ + cu_bytes = (Dwarf_Small *) dbg->sections[IDX_debug_info].addr + offset; + + /* The format of the CU header is described in dwarf2p1 7.5.1: + + 1. A 4-byte or 12-byte unsigned integer representing the length + of the .debug_info contribution for that compilation unit, not + including the length field itself. In the 32-bit DWARF format, + this is a 4-byte unsigned integer (which must be less than + 0xffffff00); in the 64-bit DWARF format, this consists of the + 4-byte value 0xffffffff followed by an 8-byte unsigned integer + that gives the actual length (see Section 7.4). + + 2. A 2-byte unsigned integer representing the version of the + DWARF information for that compilation unit. For DWARF Version + 2.1, the value in this field is 2. + + 3. A 4-byte or 8-byte unsigned offset into the .debug_abbrev + section. This offset associates the compilation unit with a + particular set of debugging information entry abbreviations. In + the 32-bit DWARF format, this is a 4-byte unsigned length; in + the 64-bit DWARF format, this is an 8-byte unsigned length (see + Section 7.4). + + 4. A 1-byte unsigned integer representing the size in bytes of + an address on the target architecture. If the system uses + segmented addressing, this value represents the size of the + offset portion of an address. */ + length = read_4ubyte_unaligned (dbg, cu_bytes); + cu_bytes += 4; + offset_size = 4; + if (length == 0xffffffff) + offset_size = 8; + + /* Now we know how large the header is. Note the trick in the + computation. If the offset_size is 4 the '- 4' term undoes the + '2 *'. If offset_size is 8 this term computes the size of the + escape value plus the 8 byte offset. */ + if (unlikely (offset + 2 * offset_size - 4 + sizeof (Dwarf_Half) + + offset_size + sizeof (Dwarf_Small) + >= dbg->sections[IDX_debug_info].size)) + { + dbg->cu_list_current = NULL; + return DW_DLV_NO_ENTRY; + } + + if (length == 0xffffffff) + { + /* This is a 64-bit DWARF format. */ + length = read_8ubyte_unaligned (dbg, cu_bytes); + cu_bytes += 8; + } + + /* We know we have enough room in the .debug_section. Allocate the + result data structure. */ + cu = (Dwarf_CU_Info) malloc (sizeof (struct Dwarf_CU_Info_s)); + if (cu == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + /* Store the values in the data structure. */ + cu->offset = offset; + cu->offset_size = offset_size; + cu->length = length; + + /* Store the version stamp. Always a 16-bit value. */ + cu->version_stamp = read_2ubyte_unaligned (dbg, cu_bytes); + cu_bytes += 2; + + /* Get offset in .debug_abbrev. Note that the size of the entry + depends on whether this is a 32-bit or 64-bit DWARF definition. */ + if (offset_size == 4) + cu->abbrev_offset = read_4ubyte_unaligned (dbg, cu_bytes); + else + cu->abbrev_offset = read_8ubyte_unaligned (dbg, cu_bytes); + cu_bytes += offset_size; + cu->last_abbrev_offset = cu->abbrev_offset; + + /* The address size. Always an 8-bit value. */ + cu->address_size = *cu_bytes++; + + /* Store the header length. */ + cu->header_length = (cu_bytes + - ((Dwarf_Small *) dbg->sections[IDX_debug_info].addr + + offset)); + + /* Initilize a few more members. */ + if (unlikely (Dwarf_Abbrev_Hash_init (&cu->abbrev_hash, + DEFAULT_ABBREV_HASH_SIZE) != 0)) + { + free (cu); + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + /* Remember the debugging handle. */ + cu->dbg = dbg; + + /* There is no other entry yet. */ + cu->next = NULL; + + /* Enqueue the new entry. */ + if (dbg->cu_list == NULL) + dbg->cu_list = dbg->cu_list_tail = cu; + else + { + dbg->cu_list_tail->next = cu; + dbg->cu_list_tail = cu; + } + *result_cu = cu; + + return DW_DLV_OK; +} + + +int +dwarf_next_cu_header (dbg, cu_header_length, version_stamp, abbrev_offset, + address_size, next_cu_header, error) + Dwarf_Debug dbg; + Dwarf_Unsigned *cu_header_length; + Dwarf_Half *version_stamp; + Dwarf_Unsigned *abbrev_offset; + Dwarf_Half *address_size; + Dwarf_Unsigned *next_cu_header; + Dwarf_Error *error; +{ + Dwarf_Unsigned offset_next_cu; + Dwarf_CU_Info cu; + + if (dbg == NULL) + return DW_DLV_ERROR; + + /* Determine offset of next CU header. If we don't have a current + CU this is the first call and we start right at the beginning. */ + if (dbg->cu_list_current == NULL) + { + offset_next_cu = 0; + cu = dbg->cu_list; + } + else + { + /* We can compute the offset from the information we read from + the last CU header. */ + cu = dbg->cu_list_current; + + offset_next_cu = cu->offset + 2 * cu->offset_size - 4 + cu->length; + + /* See whether the next entry entry is available. */ + cu = cu->next; + } + + /* If the entry is not yet available get it. */ + if (cu == NULL) + { + int res = __libdwarf_get_cu_at_offset (dbg, offset_next_cu, &cu, error); + + /* If it still does not exist, fail. Note that this can mean an + error or that we reached the end. */ + if (res != DW_DLV_OK) + return res; + + dbg->cu_list_current = cu; + assert (cu != NULL); + } + + /* See get_cu_at_offset for an explanation of the trick in this + formula. */ + *next_cu_header = offset_next_cu + 2 * cu->offset_size - 4 + cu->length; + + /* Extract the information and put it where the user wants it. */ + if (cu_header_length != NULL) + *cu_header_length = cu->header_length; + + if (version_stamp != NULL) + *version_stamp = cu->version_stamp; + + if (abbrev_offset != NULL) + *abbrev_offset = cu->abbrev_offset; + + if (address_size != NULL) + *address_size = cu->address_size; + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_offdie.c b/libdwarf/dwarf_offdie.c new file mode 100644 index 00000000..2e94d2ea --- /dev/null +++ b/libdwarf/dwarf_offdie.c @@ -0,0 +1,123 @@ +/* Return die at given offset. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +/* XXX This function will have to be optimized. The search is too linear + to be performed too often -> O(n²). */ +static Dwarf_CU_Info +find_cu (Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Error *error) +{ + Dwarf_CU_Info cu; + Dwarf_Word cu_offset; + + /* Search in the CUs already known. */ + for (cu = dbg->cu_list; cu != NULL; cu = cu->next) + if (cu->offset <= offset + && cu->offset + 2 * cu->offset_size - 4 + cu->length > offset) + return cu; + + /* The CU is not yet loaded. Do this now. */ + if (dbg->cu_list_tail == NULL) + cu_offset = 0; + else + cu_offset = (dbg->cu_list_tail->offset + + 2 * dbg->cu_list_tail->offset_size - 4 + + dbg->cu_list_tail->length); + + while (1) + { + /* Get next CU and add it to the end of the list. */ + if (__libdwarf_get_cu_at_offset (dbg, cu_offset, &cu, error) + != DW_DLV_OK) + return NULL; + + /* Offset of next CU. */ + cu_offset += 2 * cu->offset_size - 4 + cu->length; + + /* If this the CU we are looking for? */ + if (offset < cu_offset) + return cu; + } +} + + +int +dwarf_offdie (dbg, offset, return_die, error) + Dwarf_Debug dbg; + Dwarf_Off offset; + Dwarf_Die *return_die; + Dwarf_Error *error; +{ + Dwarf_CU_Info cu; + Dwarf_Die new_die; + Dwarf_Small *die_addr; + Dwarf_Word u128; + + if (offset >= dbg->sections[IDX_debug_info].size) + { + /* Completely out of bounds. */ + __libdwarf_error (dbg, error, DW_E_INVALID_OFFSET); + return DW_DLV_ERROR; + } + + /* Find the compile unit this address belongs to. */ + cu = find_cu (dbg, offset, error); + if (cu == NULL) + return DW_DLV_ERROR; + + /* Creata a new die. */ + new_die = (Dwarf_Die) malloc (sizeof (struct Dwarf_Die_s)); + if (new_die == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + +#ifdef DWARF_DEBUG + new_die->memtag = DW_DLA_DIE; +#endif + + /* Remember the address. */ + die_addr = (Dwarf_Small *) dbg->sections[IDX_debug_info].addr + offset; + new_die->addr = die_addr; + + /* And the compile unit. */ + new_die->cu = cu; + + /* 7.5.2 Debugging Information Entry + + Each debugging information entry begins with an unsigned LEB128 + number containing the abbreviation code for the entry. */ + get_uleb128 (u128, die_addr); + + /* Find the abbreviation. */ + new_die->abbrev = __libdwarf_get_abbrev (dbg, cu, u128, error); + if (new_die->abbrev == NULL) + { + free (new_die); + return DW_DLV_ERROR; + } + + *return_die = new_die; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_seterrarg.c b/libdwarf/dwarf_seterrarg.c new file mode 100644 index 00000000..8b52d24a --- /dev/null +++ b/libdwarf/dwarf_seterrarg.c @@ -0,0 +1,30 @@ +/* Set new error handler argument. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +Dwarf_Ptr +dwarf_seterrarg (dbg, errarg) + Dwarf_Debug dbg; + Dwarf_Ptr errarg; +{ + Dwarf_Ptr old = dbg->dbg_errarg; + dbg->dbg_errarg = errarg; + return old; +} diff --git a/libdwarf/dwarf_seterrhand.c b/libdwarf/dwarf_seterrhand.c new file mode 100644 index 00000000..199a2504 --- /dev/null +++ b/libdwarf/dwarf_seterrhand.c @@ -0,0 +1,30 @@ +/* Set new error handler. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +Dwarf_Handler +dwarf_seterrhand (dbg, errhand) + Dwarf_Debug dbg; + Dwarf_Handler errhand; +{ + Dwarf_Handler old = dbg->dbg_errhand; + dbg->dbg_errhand = errhand; + return old; +} diff --git a/libdwarf/dwarf_siblingof.c b/libdwarf/dwarf_siblingof.c new file mode 100644 index 00000000..04a3ab6d --- /dev/null +++ b/libdwarf/dwarf_siblingof.c @@ -0,0 +1,257 @@ +/* Return descriptor for sibling of die. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +int +dwarf_siblingof (dbg, die, return_sub, error) + Dwarf_Debug dbg; + Dwarf_Die die; + Dwarf_Die *return_sub; + Dwarf_Error *error; +{ + Dwarf_Small *die_addr; + Dwarf_CU_Info cu; + Dwarf_Unsigned u128; + Dwarf_Die new_die; + + if (dbg == NULL) + return DW_DLV_ERROR; + + if (die == NULL) + { + Dwarf_Unsigned die_offset; + + /* We are supposed to return the DW_TAG_compile_unit die for the + current compile unit. For this to succeed the user must have + looked for the compile unit before. */ + if (dbg->cu_list_current == NULL) + { + __libdwarf_error (dbg, error, DW_E_NO_CU); + return DW_DLV_ERROR; + } + + cu = dbg->cu_list_current; + + die_offset = (cu->offset + 2 * cu->offset_size - 4 + sizeof (Dwarf_Half) + + cu->offset_size + 1); + + /* Check whether this is withing the debug section. */ + if (die_offset >= dbg->sections[IDX_debug_info].size) + return DW_DLV_NO_ENTRY; + + /* Compute the pointer. */ + die_addr = ((Dwarf_Small *) dbg->sections[IDX_debug_info].addr + + die_offset); + } + else + { + unsigned int level = 0; + + /* We start from the given die. */ + cu = die->cu; + + /* Address of the given die. */ + die_addr = die->addr; + + /* Search for the beginning of the next die on this level. We + must not return the dies for children of the given die. */ + do + { + Dwarf_Abbrev abbrev; + Dwarf_Small *attrp; + Dwarf_Word attr_name; + Dwarf_Word attr_form; + + /* Get abbrev code. */ + get_uleb128 (u128, die_addr); + /* And get the abbreviation itself. */ + abbrev = __libdwarf_get_abbrev (dbg, cu, u128, error); + if (abbrev == NULL) + return DW_DLV_ERROR; + + /* This is where the attributes start. */ + attrp = abbrev->attrp; + + /* Does this abbreviation have children? */ + if (abbrev->has_children) + ++level; + + while (1) + { + /* Are we still in bounds? */ + if (attrp >= ((Dwarf_Small *)dbg->sections[IDX_debug_abbrev].addr + + dbg->sections[IDX_debug_abbrev].size)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Get attribute name and form. + + XXX We don't check whether this reads beyond the end of + the section. */ + get_uleb128 (attr_name, attrp); + get_uleb128 (attr_form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* See whether this is an sibling attribute which would help + us to skip ahead. */ + if (attr_name == DW_AT_sibling) + { + /* Cool. We just have to decode the parameter and we know + the offset. */ + Dwarf_Unsigned offset; + + switch (attr_form) + { + case DW_FORM_ref1: + offset = *die_addr; + break; + + case DW_FORM_ref2: + offset = read_2ubyte_unaligned (dbg, die_addr); + break; + + case DW_FORM_ref4: + offset = read_4ubyte_unaligned (dbg, die_addr); + break; + + case DW_FORM_ref8: + offset = read_8ubyte_unaligned (dbg, die_addr); + break; + + case DW_FORM_ref_udata: + get_uleb128 (offset, die_addr); + break; + + default: + /* The above are all legal forms. Everything else is + an error. */ + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Compute the new address. Some sanity check first, + though. */ + if (unlikely (offset > 2 * cu->offset_size - 4 + cu->length)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + die_addr = + ((Dwarf_Small *) dbg->sections[IDX_debug_info].addr + + cu->offset + offset); + + /* Even if the abbreviation has children we have stepped + over them now. */ + if (abbrev->has_children) + --level; + break; + } + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len; + + if (unlikely (__libdwarf_form_val_len (dbg, cu, attr_form, + die_addr, &len, error) + != DW_DLV_OK)) + return DW_DLV_ERROR; + + die_addr += len; + } + } + + /* Check that we are not yet at the end. */ + if (*die_addr == 0) + { + if (level == 0) + return DW_DLV_NO_ENTRY; + + do + ++die_addr; + while (--level > 0 && *die_addr == 0); + } + } + while (level > 0); + } + + /* Are we at the end. */ + if (die != NULL + && die_addr >= ((Dwarf_Small *) dbg->sections[IDX_debug_info].addr + + cu->offset + cu->length + 2 * cu->offset_size - 4)) + return DW_DLV_NO_ENTRY; + + /* See whether there is another sibling available or whether this is + the end. */ + if (*die_addr == 0) + return DW_DLV_NO_ENTRY; + + /* There is more data. Create the data structure. */ + new_die = (Dwarf_Die) malloc (sizeof (struct Dwarf_Die_s)); + if (new_die == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + +#ifdef DWARF_DEBUG + new_die->memtag = DW_DLA_DIE; +#endif + + /* Remember the address. */ + new_die->addr = die_addr; + + /* And the compile unit. */ + new_die->cu = cu; + + /* 7.5.2 Debugging Information Entry + + Each debugging information entry begins with an unsigned LEB128 + number containing the abbreviation code for the entry. */ + get_uleb128 (u128, die_addr); + + /* Find the abbreviation. */ + new_die->abbrev = __libdwarf_get_abbrev (dbg, cu, u128, error); + if (new_die->abbrev == NULL) + { + free (new_die); + return DW_DLV_ERROR; + } + + /* If we are looking for the first entry this must be a compile unit. */ + if (die == NULL && unlikely (new_die->abbrev->tag != DW_TAG_compile_unit)) + { + free (new_die); + __libdwarf_error (dbg, error, DW_E_1ST_NO_CU); + return DW_DLV_ERROR; + } + + *return_sub = new_die; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_srcfiles.c b/libdwarf/dwarf_srcfiles.c new file mode 100644 index 00000000..1090d837 --- /dev/null +++ b/libdwarf/dwarf_srcfiles.c @@ -0,0 +1,344 @@ +/* Return source files of compilation unit. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include + + +struct dirlist +{ + char *dir; + size_t len; + struct dirlist *next; +}; + +struct filelist +{ + char *name; + Dwarf_Unsigned mtime; + Dwarf_Unsigned length; + struct filelist *next; +}; + + +static int +read_file_names (Dwarf_Debug dbg, char *comp_dir, Dwarf_Small **linepp, + char ***result, Dwarf_Signed *nresult, Dwarf_Error *error) +{ + Dwarf_Small *linep = *linepp; + struct dirlist comp_dir_elem; + struct dirlist *dirlist; + unsigned int ndirlist; + struct dirlist **dirarray; + struct filelist *filelist = NULL; + unsigned int nfilelist = 0; + + /* First comes the list of directories. Add the compilation directory + first since the index zero is used for it. */ + comp_dir_elem.dir = comp_dir; + comp_dir_elem.len = comp_dir ? strlen (comp_dir) : 0; + comp_dir_elem.next = NULL; + dirlist = &comp_dir_elem; + ndirlist = 1; + + while (*linep != 0) + { + struct dirlist *new_dir = (struct dirlist *) alloca (sizeof (*new_dir)); + + new_dir->dir = (char *) linep; + new_dir->len = strlen ((char *) linep); + new_dir->next = dirlist; + dirlist = new_dir; + ++ndirlist; + linep += new_dir->len + 1; + } + /* Skip the final NUL byte. */ + ++linep; + + /* Rearrange the list in array form. */ + dirarray = (struct dirlist **) alloca (sizeof (*dirarray)); + while (ndirlist-- > 0) + { + dirarray[ndirlist] = dirlist; + dirlist = dirlist->next; + } + + /* Now read the files. */ + while (*linep != 0) + { + struct filelist *new_file = + (struct filelist *) alloca (sizeof (*new_file)); + char *fname; + size_t fnamelen; + Dwarf_Unsigned diridx; + + /* First comes the file name. */ + fname = (char *) linep; + fnamelen = strlen (fname); + linep += fnamelen + 1; + + /* Then the index. */ + get_uleb128 (diridx, linep); + if (unlikely (diridx >= ndirlist)) + { + __libdwarf_error (dbg, error, DW_E_INVALID_DIR_IDX); + return DW_DLV_ERROR; + } + + if (*fname == '/') + /* It's an absolute path. */ + new_file->name = strdup (fname); + else + { + new_file->name = (char *) malloc (dirarray[diridx]->len + 1 + + fnamelen + 1); + if (new_file->name != NULL) + { + char *cp = new_file->name; + + if (dirarray[diridx]->dir != NULL) + /* This value could be NULL in case the DW_AT_comp_dir + was not present. We cannot do much in this case. + The easiest thing is to convert the path in an + absolute path. */ + cp = stpcpy (cp, dirarray[diridx]->dir); + *cp++ = '/'; + strcpy (cp, fname); + } + } + if (new_file->name == NULL) + { + /* XXX Should we bother to free all the memory? */ + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + /* Next comes the modification time. */ + get_uleb128 (new_file->mtime, linep); + + /* Finally the length of the file. */ + get_uleb128 (new_file->length, linep); + + new_file->next = filelist; + filelist = new_file; + ++nfilelist; + } + + /* Put all the files in an array. */ + *result = (char **) malloc (nfilelist * sizeof (char *)); + if (*result == NULL) + { + /* XXX Should we bother to free all the memory? */ + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + *nresult = nfilelist; + while (nfilelist-- > 0) + { + (*result)[nfilelist] = filelist->name; + filelist = filelist->next; + } + + /* Provide caller address of next byte. */ + *linepp = linep + 1; + + return DW_DLV_OK; +} + + +int +dwarf_srcfiles (die, srcfiles, srcfilecount, error) + Dwarf_Die die; + char ***srcfiles; + Dwarf_Signed *srcfilecount; + Dwarf_Error *error; +{ + Dwarf_CU_Info cu = die->cu; + Dwarf_Debug dbg = cu->dbg; + Dwarf_Attribute stmt_list; + Dwarf_Attribute comp_dir_attr; + char *comp_dir; + Dwarf_Unsigned offset; + Dwarf_Small *linep; + Dwarf_Small *lineendp; + Dwarf_Small *header_start; + Dwarf_Unsigned header_length; + unsigned int unit_length; + unsigned int version; + unsigned int opcode_base; + int length; + int res; + + /* For now we haven't found anything. */ + *srcfilecount = 0; + + /* The die must be for a compilation unit. */ + if (die->abbrev->tag != DW_TAG_compile_unit) + { + __libdwarf_error (die->cu->dbg, error, DW_E_NO_CU); + return DW_DLV_ERROR; + } + + /* The die must have a statement list associated. */ + res = dwarf_attr (die, DW_AT_stmt_list, &stmt_list, error); + if (res != DW_DLV_OK) + return res; + + /* Get the offset into the .debug_line section. */ + res = dwarf_formudata (stmt_list, &offset, error); + if (res != DW_DLV_OK) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + return res; + } + + /* We need a .debug_line section. */ + if (dbg->sections[IDX_debug_line].addr == NULL) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_NO_DEBUG_LINE); + return DW_DLV_ERROR; + } + + linep = (Dwarf_Small *) dbg->sections[IDX_debug_line].addr + offset; + lineendp = ((Dwarf_Small *) dbg->sections[IDX_debug_line].addr + + dbg->sections[IDX_debug_line].size); + + /* Test whether at least the first 4 bytes are available. */ + if (unlikely (linep + 4 > lineendp)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Get the compilation directory. */ + res = dwarf_attr (die, DW_AT_comp_dir, &comp_dir_attr, error); + if (unlikely (res == DW_DLV_ERROR) + || (res == DW_DLV_OK + && unlikely (dwarf_formstring (comp_dir_attr, &comp_dir, error) + == DW_DLV_ERROR))) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + else if (res == DW_DLV_OK) + dwarf_dealloc (dbg, comp_dir_attr, DW_DLA_ATTR); + else + comp_dir = NULL; + + /* Read the unit_length. */ + unit_length = read_4ubyte_unaligned (dbg, linep); + linep += 4; + length = 4; + if (unit_length == 0xffffffff) + { + if (unlikely (linep + 8 > lineendp)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + unit_length = read_8ubyte_unaligned (dbg, linep); + linep += 8; + length = 8; + } + + /* Check whether we have enough room in the section. */ + if (unlikely (linep + unit_length > lineendp)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + lineendp = linep + unit_length; + + /* The next element of the header is the version identifier. */ + version = read_2ubyte_unaligned (dbg, linep); + if (unlikely (version != DWARF_VERSION)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_VERSION_ERROR); + return DW_DLV_ERROR; + } + linep += 2; + + /* Next comes the header length. */ + if (length == 4) + { + header_length = read_4ubyte_unaligned (dbg, linep); + linep += 4; + } + else + { + header_length = read_8ubyte_unaligned (dbg, linep); + linep += 8; + } + header_start = linep; + + /* Next the minimum instruction length. Skip it. */ + ++linep; + + /* Then the flag determining the default value of the is_stmt + register. Skip it. */ + ++linep; + + /* Now the line base. Skip it. */ + ++linep; + + /* And the line range. Skip it. */ + ++linep; + + /* The opcode base. */ + opcode_base = *linep++; + + /* Skip the array with the standard opcode length. */ + linep += opcode_base - 1; + + /* Next the include directories and the file names. */ + if (unlikely (read_file_names (dbg, comp_dir, &linep, srcfiles, srcfilecount, + error) != DW_DLV_OK)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + return DW_DLV_ERROR; + } + + /* Consistency check. */ + if (unlikely (linep != header_start + header_length)) + { + int i; + + for (i = 0; i < *srcfilecount; ++i) + dwarf_dealloc (dbg, (*srcfiles)[i], DW_DLA_STRING); + dwarf_dealloc (dbg, *srcfiles, DW_DLA_LIST); + + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_srclang.c b/libdwarf/dwarf_srclang.c new file mode 100644 index 00000000..45140633 --- /dev/null +++ b/libdwarf/dwarf_srclang.c @@ -0,0 +1,31 @@ +/* Return source language associated with die. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + + +int +dwarf_srclang (die, return_lang, error) + Dwarf_Die die; + Dwarf_Unsigned *return_lang; + Dwarf_Error *error; +{ + return __libdwarf_getconstant (die, DW_AT_language, return_lang, error); +} diff --git a/libdwarf/dwarf_srclines.c b/libdwarf/dwarf_srclines.c new file mode 100644 index 00000000..796b7900 --- /dev/null +++ b/libdwarf/dwarf_srclines.c @@ -0,0 +1,745 @@ +/* Return source lines of compilation unit. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include + + +struct dirlist +{ + char *dir; + size_t len; + struct dirlist *next; +}; + +struct filelist +{ + char *name; + Dwarf_Unsigned mtime; + Dwarf_Unsigned length; + struct filelist *next; +}; + +struct linelist +{ + Dwarf_Line line; + struct linelist *next; +}; + + +/* Adds a new line to the matrix. We cannot definte a function because + we want to use alloca. */ +#define NEW_LINE(end_seq) \ + do { \ + /* Add the new line. */ \ + new_line = (struct linelist *) alloca (sizeof (struct linelist)); \ + new_line->line = (Dwarf_Line) malloc (sizeof (struct Dwarf_Line_s)); \ + if (new_line == NULL) \ + { \ + /* XXX Should we bother to free the memory? */ \ + __libdwarf_error (dbg, error, DW_E_NOMEM); \ + return DW_DLV_ERROR; \ + } \ + \ + /* Set the line information. */ \ + new_line->line->addr = address; \ + new_line->line->file = file; \ + new_line->line->line = line; \ + new_line->line->column = column; \ + new_line->line->is_stmt = is_stmt; \ + new_line->line->basic_block = basic_block; \ + new_line->line->end_sequence = end_seq; \ + new_line->line->prologue_end = prologue_end; \ + new_line->line->epilogue_begin = epilogue_begin; \ + \ + new_line->next = linelist; \ + linelist = new_line; \ + ++nlinelist; \ + } while (0) + + +int +dwarf_srclines (die, linebuf, linecount, error) + Dwarf_Die die; + Dwarf_Line **linebuf; + Dwarf_Signed *linecount; + Dwarf_Error *error; +{ + Dwarf_CU_Info cu = die->cu; + Dwarf_Debug dbg = cu->dbg; + Dwarf_Attribute stmt_list; + Dwarf_Attribute comp_dir_attr; + char *comp_dir; + Dwarf_Unsigned offset; + Dwarf_Small *linep; + Dwarf_Small *lineendp; + Dwarf_Small *header_start; + Dwarf_Unsigned header_length; + Dwarf_File files; + Dwarf_Line *lines; + unsigned int unit_length; + unsigned int version; + unsigned int opcode_base; + Dwarf_Small *standard_opcode_lengths; + unsigned int minimum_instruction_length; + unsigned int default_is_stmt; + int line_base; + unsigned int line_range; + int length; + struct dirlist comp_dir_elem; + struct dirlist *dirlist; + unsigned int ndirlist; + struct dirlist **dirarray; + struct filelist *filelist; + unsigned int nfilelist; + struct filelist null_file; + Dwarf_Unsigned address; + size_t file; + size_t line; + size_t column; + int is_stmt; + int basic_block; + int prologue_end; + int epilogue_begin; + struct linelist *linelist; + unsigned int nlinelist; + int res; + + /* The die must be for a compilation unit. */ + if (unlikely (die->abbrev->tag != DW_TAG_compile_unit)) + { + __libdwarf_error (die->cu->dbg, error, DW_E_NO_CU); + return DW_DLV_ERROR; + } + + /* The die must have a statement list associated. */ + res = dwarf_attr (die, DW_AT_stmt_list, &stmt_list, error); + if (unlikely (res != DW_DLV_OK)) + return res; + + /* Get the offset into the .debug_line section. */ + res = dwarf_formudata (stmt_list, &offset, error); + if (unlikely (res != DW_DLV_OK)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + return res; + } + + /* We need a .debug_line section. */ + if (dbg->sections[IDX_debug_line].addr == NULL) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_NO_DEBUG_LINE); + return DW_DLV_ERROR; + } + + linep = (Dwarf_Small *) dbg->sections[IDX_debug_line].addr + offset; + lineendp = ((Dwarf_Small *) dbg->sections[IDX_debug_line].addr + + dbg->sections[IDX_debug_line].size); + + /* Test whether at least the first 4 bytes are available. */ + if (unlikely (linep + 4 > lineendp)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Get the compilation directory. */ + res = dwarf_attr (die, DW_AT_comp_dir, &comp_dir_attr, error); + if (unlikely (res == DW_DLV_ERROR) + || (res == DW_DLV_OK + && unlikely (dwarf_formstring (comp_dir_attr, &comp_dir, error) + == DW_DLV_ERROR))) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + else if (res == DW_DLV_OK) + dwarf_dealloc (dbg, comp_dir_attr, DW_DLA_ATTR); + else + comp_dir = NULL; + + /* Read the unit_length. */ + unit_length = read_4ubyte_unaligned (dbg, linep); + linep += 4; + length = 4; + if (unit_length == 0xffffffff) + { + if (unlikely (linep + 8 > lineendp)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + unit_length = read_8ubyte_unaligned (dbg, linep); + linep += 8; + length = 8; + } + + /* Check whether we have enough room in the section. */ + if (unlikely (linep + unit_length > lineendp)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + lineendp = linep + unit_length; + + /* The next element of the header is the version identifier. */ + version = read_2ubyte_unaligned (dbg, linep); + if (unlikely (version != DWARF_VERSION)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_VERSION_ERROR); + return DW_DLV_ERROR; + } + linep += 2; + + /* Next comes the header length. */ + if (length == 4) + { + header_length = read_4ubyte_unaligned (dbg, linep); + linep += 4; + } + else + { + header_length = read_8ubyte_unaligned (dbg, linep); + linep += 8; + } + header_start = linep; + + /* Next the minimum instruction length. */ + minimum_instruction_length = *linep++; + + /* Then the flag determining the default value of the is_stmt + register. */ + default_is_stmt = *linep++; + + /* Now the line base. */ + line_base = *((signed char *) linep)++; + + /* And the line range. */ + line_range = *linep++; + + /* The opcode base. */ + opcode_base = *linep++; + + /* Remember array with the standard opcode length (-1 to account for + the opcode with value zero not being mentioned). */ + standard_opcode_lengths = linep - 1; + linep += opcode_base - 1; + + /* First comes the list of directories. Add the compilation directory + first since the index zero is used for it. */ + comp_dir_elem.dir = comp_dir; + comp_dir_elem.len = comp_dir ? strlen (comp_dir) : 0; + comp_dir_elem.next = NULL; + dirlist = &comp_dir_elem; + ndirlist = 1; + + while (*linep != 0) + { + struct dirlist *new_dir = (struct dirlist *) alloca (sizeof (*new_dir)); + + new_dir->dir = (char *) linep; + new_dir->len = strlen ((char *) linep); + new_dir->next = dirlist; + dirlist = new_dir; + ++ndirlist; + linep += new_dir->len + 1; + } + /* Skip the final NUL byte. */ + ++linep; + + /* Rearrange the list in array form. */ + dirarray = (struct dirlist **) alloca (sizeof (*dirarray)); + while (ndirlist-- > 0) + { + dirarray[ndirlist] = dirlist; + dirlist = dirlist->next; + } + + comp_dir_elem.dir = comp_dir; + comp_dir_elem.len = comp_dir ? strlen (comp_dir) : 0; + comp_dir_elem.next = NULL; + dirlist = &comp_dir_elem; + ndirlist = 1; + + /* Now read the files. */ + null_file.name = "???"; + null_file.mtime = 0; + null_file.length = 0; + null_file.next = NULL; + filelist = &null_file; + nfilelist = 1; + + while (*linep != 0) + { + struct filelist *new_file = + (struct filelist *) alloca (sizeof (*new_file)); + char *fname; + size_t fnamelen; + Dwarf_Unsigned diridx; + + /* First comes the file name. */ + fname = (char *) linep; + fnamelen = strlen (fname); + linep += fnamelen + 1; + + /* Then the index. */ + get_uleb128 (diridx, linep); + if (unlikely (diridx >= ndirlist)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DIR_IDX); + return DW_DLV_ERROR; + } + + if (*fname == '/') + /* It's an absolute path. */ + new_file->name = strdup (fname); + else + { + new_file->name = (char *) malloc (dirarray[diridx]->len + 1 + + fnamelen + 1); + if (new_file->name != NULL) + { + char *cp = new_file->name; + + if (dirarray[diridx]->dir != NULL) + /* This value could be NULL in case the DW_AT_comp_dir + was not present. We cannot do much in this case. + The easiest thing is to convert the path in an + absolute path. */ + cp = stpcpy (cp, dirarray[diridx]->dir); + *cp++ = '/'; + strcpy (cp, fname); + } + } + if (new_file->name == NULL) + { + /* XXX Should we bother to free all the memory? */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + /* Next comes the modification time. */ + get_uleb128 (new_file->mtime, linep); + + /* Finally the length of the file. */ + get_uleb128 (new_file->length, linep); + + new_file->next = filelist; + filelist = new_file; + ++nfilelist; + } + ++linep; + + /* Consistency check. */ + if (unlikely (linep != header_start + header_length)) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* We are about to process the statement program. Initialize the + state machine registers (see 6.2.2 in the v2.1 specification). */ + address = 0; + file = 1; + line = 1; + column = 0; + is_stmt = default_is_stmt; + basic_block = 0; + prologue_end = 0; + epilogue_begin = 0; + + /* Process the instructions. */ + linelist = NULL; + nlinelist = 0; + while (linep < lineendp) + { + struct linelist *new_line; + unsigned int opcode; + unsigned int u128; + int s128; + + /* Read the opcode. */ + opcode = *linep++; + + /* Is this a special opcode? */ + if (likely (opcode >= opcode_base)) + { + /* Yes. Handling this is quite easy since the opcode value + is computed with + + opcode = (desired line increment - line_base) + + (line_range * address advance) + opcode_base + */ + int line_increment = line_base + (opcode - opcode_base) % line_range; + unsigned int address_increment = (minimum_instruction_length + * ((opcode - opcode_base) + / line_range)); + + /* Perform the increments. */ + line += line_increment; + address += address_increment; + + /* Add a new line with the current state machine values. */ + NEW_LINE (0); + + /* Reset the flags. */ + basic_block = 0; + prologue_end = 0; + epilogue_begin = 0; + } + else if (opcode == 0) + { + /* This an extended opcode. */ + unsigned int len; + + /* The length. */ + len = *linep++; + + /* The sub-opecode. */ + opcode = *linep++; + + switch (opcode) + { + case DW_LNE_end_sequence: + /* Add a new line with the current state machine values. + The is the end of the sequence. */ + NEW_LINE (1); + + /* Reset the registers. */ + address = 0; + file = 1; + line = 1; + column = 0; + is_stmt = default_is_stmt; + basic_block = 0; + prologue_end = 0; + epilogue_begin = 0; + break; + + case DW_LNE_set_address: + if (cu->address_size == 4) + address = read_4ubyte_unaligned (dbg, linep); + else + address = read_8ubyte_unaligned (dbg, linep); + linep += cu->address_size; + break; + + case DW_LNE_define_file: + { + struct filelist *new_file; + char *fname; + size_t fnamelen; + unsigned int diridx; + Dwarf_Unsigned mtime; + Dwarf_Unsigned length; + + fname = (char *) linep; + fnamelen = strlen (fname); + linep += fnamelen + 1; + + get_uleb128 (diridx, linep); + get_uleb128 (mtime, linep); + get_uleb128 (length, linep); + + new_file = (struct filelist *) alloca (sizeof (*new_file)); + if (fname[0] == '/') + new_file->name = strdup (fname); + else + { + + new_file->name = (char *) malloc (dirarray[diridx]->len + 1 + + fnamelen + 1); + if (new_file->name != NULL) + { + char *cp = new_file->name; + + if (dirarray[diridx]->dir != NULL) + /* This value could be NULL in case the + DW_AT_comp_dir was not present. We + cannot do much in this case. The easiest + thing is to convert the path in an + absolute path. */ + cp = stpcpy (cp, dirarray[diridx]->dir); + *cp++ = '/'; + strcpy (cp, fname); + } + } + if (new_file->name == NULL) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + new_file->mtime = mtime; + new_file->length = length; + new_file->next = filelist; + filelist = new_file; + ++nfilelist; + } + break; + + default: + /* Unknown, ignore it. */ + linep += len - 1; + break; + } + } + else if (opcode <= DW_LNS_set_epilog_begin) + { + /* This is a known standard opcode. */ + switch (opcode) + { + case DW_LNS_copy: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + { + /* XXX Free memory. */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + /* Add a new line with the current state machine values. */ + NEW_LINE (0); + + /* Reset the flags. */ + basic_block = 0; + /* XXX Whether the following two lines are necessary is + unclear. I guess the current v2.1 specification has + a bug in that it says clearing these two registers is + not necessary. */ + prologue_end = 0; + epilogue_begin = 0; + break; + + case DW_LNS_advance_pc: + /* Takes one uleb128 parameter which is added to the address. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + { + /* XXX Free memory. */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + get_uleb128 (u128, linep); + address += minimum_instruction_length * u128; + break; + + case DW_LNS_advance_line: + /* Takes one sleb128 parameter which is added to the line. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + { + /* XXX Free memory. */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + get_sleb128 (s128, linep); + line += s128; + break; + + case DW_LNS_set_file: + /* Takes one uleb128 parameter which is stored in file. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + { + /* XXX Free memory. */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + get_uleb128 (u128, linep); + file = u128; + break; + + case DW_LNS_set_column: + /* Takes one uleb128 parameter which is stored in column. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + { + /* XXX Free memory. */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + get_uleb128 (u128, linep); + column = u128; + break; + + case DW_LNS_negate_stmt: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + { + /* XXX Free memory. */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + is_stmt = 1 - is_stmt; + break; + + case DW_LNS_set_basic_block: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + { + /* XXX Free memory. */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + basic_block = 1; + break; + + case DW_LNS_const_add_pc: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + { + /* XXX Free memory. */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + address += (minimum_instruction_length + * ((255 - opcode_base) / line_range)); + break; + + case DW_LNS_fixed_advance_pc: + /* Takes one 16 bit parameter which is added to the address. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + { + /* XXX Free memory. */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + address += read_2ubyte_unaligned (dbg, linep); + linep += 2; + break; + + case DW_LNS_set_prologue_end: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + { + /* XXX Free memory. */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + prologue_end = 1; + break; + + case DW_LNS_set_epilog_begin: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + { + /* XXX Free memory. */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_INVALID_DWARF); + return DW_DLV_ERROR; + } + + epilogue_begin = 1; + break; + } + } + else + { + /* This is a new opcode the generator but not we know about. + Read the parameters associated with it but then discard + everything. */ + int n; + + /* Read all the parameters for this opcode. */ + for (n = standard_opcode_lengths[opcode]; n > 0; --n) + { + Dwarf_Unsigned u128; + get_uleb128 (u128, linep); + } + + /* Next round, ignore this opcode. */ + continue; + } + } + + /* Put all the files in an array. */ + files = (Dwarf_File) malloc (sizeof (struct Dwarf_File_s) + + nfilelist * sizeof (Dwarf_Fileinfo)); + if (files == NULL) + { + /* XXX Should we bother to free all the memory? */ + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + files->nfiles = nfilelist; + while (nfilelist-- > 0) + { + files->info[nfilelist].name = filelist->name; + files->info[nfilelist].mtime = filelist->mtime; + files->info[nfilelist].length = filelist->length; + filelist = filelist->next; + } + + /* Remember the debugging descriptor. */ + files->dbg = dbg; + + /* Now put the lines in an array. */ + lines = (Dwarf_Line *) malloc (nlinelist * sizeof (Dwarf_Line)); + if (lines == NULL) + { + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + *linebuf = lines; + *linecount = nlinelist; + + while (nlinelist--) + { + lines[nlinelist] = linelist->line; + linelist->line->files = files; + linelist = linelist->next; + } + + dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR); + + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_tag.c b/libdwarf/dwarf_tag.c new file mode 100644 index 00000000..3c4d36ec --- /dev/null +++ b/libdwarf/dwarf_tag.c @@ -0,0 +1,30 @@ +/* Return tag of die. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_tag (die, tagval, error) + Dwarf_Die die; + Dwarf_Half *tagval; + Dwarf_Error *error; +{ + *tagval = die->abbrev->tag; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_whatattr.c b/libdwarf/dwarf_whatattr.c new file mode 100644 index 00000000..9887f2e1 --- /dev/null +++ b/libdwarf/dwarf_whatattr.c @@ -0,0 +1,30 @@ +/* Return code of attribute. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_whatattr (attr, return_attr, error) + Dwarf_Attribute attr; + Dwarf_Half *return_attr; + Dwarf_Error *error; +{ + *return_attr = attr->code; + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_whatform.c b/libdwarf/dwarf_whatform.c new file mode 100644 index 00000000..5cb67b3d --- /dev/null +++ b/libdwarf/dwarf_whatform.c @@ -0,0 +1,30 @@ +/* Return form of attribute. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +dwarf_whatform (attr, return_form, error) + Dwarf_Attribute attr; + Dwarf_Half *return_form; + Dwarf_Error *error; +{ + *return_form = attr->form; + return DW_DLV_OK; +} diff --git a/libdwarf/libdwarf.h b/libdwarf/libdwarf.h new file mode 100644 index 00000000..37c958ca --- /dev/null +++ b/libdwarf/libdwarf.h @@ -0,0 +1,514 @@ +/* Interface for libdwarf. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBDWARF_H +#define _LIBDWARF_H 1 + +#include +#include + +/* Basic data types. */ + +/* Used for boolean values. */ +typedef int Dwarf_Bool; + +/* Numeric values of different sizes. */ +typedef uint8_t Dwarf_Small; +typedef uint16_t Dwarf_Half; +typedef uint64_t Dwarf_Unsigned; +typedef int64_t Dwarf_Signed; + +/* Offsets in the debugging sections. */ +typedef uint64_t Dwarf_Off; + +/* Program counter value in the target object file. */ +typedef uint64_t Dwarf_Addr; + +/* Address in the host process. */ +typedef void *Dwarf_Ptr; + + +/* Location record. */ +typedef struct + { + Dwarf_Small lr_atom; /* Operation */ + Dwarf_Unsigned lr_number; /* Operand */ + Dwarf_Unsigned lr_number2; /* Possible second operand */ + Dwarf_Unsigned lr_offset; /* Offset in location expression */ + } Dwarf_Loc; + + +/* Location description. */ +typedef struct + { + Dwarf_Addr ld_lopc; /* Beginning of range */ + Dwarf_Addr ld_hipc; /* End of range */ + Dwarf_Half ld_cents; /* Number of location records */ + Dwarf_Loc *ld_s; /* Array of location records */ + } Dwarf_Locdesc; + + +/* Error handler function. */ +typedef struct Dwarf_Error_s *Dwarf_Error; /* Forward declaration. */ +typedef void (*Dwarf_Handler) (Dwarf_Error *, Dwarf_Ptr); + +/* Descriptor for block of uninterpreted data. */ +typedef struct + { + Dwarf_Unsigned bl_len; + Dwarf_Ptr bl_data; + } Dwarf_Block; + + +/* Descriptor for libdwarf session. */ +typedef struct Dwarf_Debug_s *Dwarf_Debug; + +/* Descriptor for DWARF DIE. */ +typedef struct Dwarf_Die_s *Dwarf_Die; + +/* Descriptor for DWARF attribute list. */ +typedef struct Dwarf_Attribute_s *Dwarf_Attribute; + +/* Descriptor for source lines. */ +typedef struct Dwarf_Line_s *Dwarf_Line; + +/* Descriptor for global name. */ +typedef struct Dwarf_Global_s *Dwarf_Global; + +/* Descriptor for address range. */ +typedef struct Dwarf_Arange_s *Dwarf_Arange; + +/* Descriptor for common information entry. */ +typedef struct Dwarf_Cie_s *Dwarf_Cie; + +/* Descriptor for frame descriptor entry. */ +typedef struct Dwarf_Fde_s *Dwarf_Fde; + +/* Descriptor for abbreviations. */ +typedef struct Dwarf_Abbrev_s *Dwarf_Abbrev; + + +/* Return values. */ +enum + { + DW_DLV_NO_ENTRY = -1, /* No error, but no entry. */ + DW_DLV_OK = 0, /* Success. */ + DW_DLV_ERROR = 1, /* Failure. */ + }; + + +/* Values for ACCESS parameter of 'dwarf_init' and 'dwarf_elf_init'. */ +enum + { + DW_DLC_READ = 0, /* Read-only access. */ + DW_DLC_WRITE = 1, /* Write-only access. */ + DW_DLC_RDWR = 2 /* Read-write access. */ + }; + + +/* Open file associates with FD for use with the other functions of + this library. Set the error handler and the parameter passed. */ +extern int dwarf_init (int fd, Dwarf_Unsigned access, + Dwarf_Handler errhand, Dwarf_Ptr errarg, + Dwarf_Debug *dbg, Dwarf_Error *errdesc); + +/* Similar to `dwarf_init' but instead of a file descriptor of ELF + descriptor is passed. */ +extern int dwarf_elf_init (Elf *elf, Dwarf_Unsigned access, + Dwarf_Handler errhand, Dwarf_Ptr errarg, + Dwarf_Debug *dbg, Dwarf_Error *errdesc); + +/* Return ELF handle. */ +extern int dwarf_get_elf_init (Dwarf_Debug dbg, Elf **elf, + Dwarf_Error *errdesc); + +/* Free resources allocated for debug handle. */ +extern int dwarf_finish (Dwarf_Debug dbg, Dwarf_Error *errdesc); + + +/* Return information about current and find new compile unit header. */ +extern int dwarf_next_cu_header (Dwarf_Debug dbg, + Dwarf_Unsigned *cu_header_length, + Dwarf_Half *version_stamp, + Dwarf_Unsigned *abbrev_offset, + Dwarf_Half *address_size, + Dwarf_Unsigned *next_cu_header, + Dwarf_Error *errdesc); + +/* Return sibling of given DIE. */ +extern int dwarf_siblingof (Dwarf_Debug dbg, Dwarf_Die die, + Dwarf_Die *return_sub, Dwarf_Error *errdesc); + +/* Return child of DIE. */ +extern int dwarf_child (Dwarf_Die die, Dwarf_Die *return_kid, + Dwarf_Error *errdesc); + +/* Return DIE at given offset. */ +extern int dwarf_offdie (Dwarf_Debug dbg, Dwarf_Off offset, + Dwarf_Die *return_die, Dwarf_Error *errdesc); + + +/* Return tag of DIE. */ +extern int dwarf_tag (Dwarf_Die die, Dwarf_Half *tagval, Dwarf_Error *errdesc); + +/* Return offset of DIE in .debug_info section. */ +extern int dwarf_dieoffset (Dwarf_Die die, Dwarf_Off *return_offset, + Dwarf_Error *errdesc); + +/* Return offset of DIE in compile unit data. */ +extern int dwarf_die_CU_offset (Dwarf_Die die, Dwarf_Off *return_offset, + Dwarf_Error *errdesc); + +/* Return name attribute of DIE. */ +extern int dwarf_diename (Dwarf_Die die, char **return_name, + Dwarf_Error *errdesc); + +/* Return list of attributes for DIE. */ +extern int dwarf_attrlist (Dwarf_Die die, Dwarf_Attribute **attrbuf, + Dwarf_Signed *attrcount, Dwarf_Error *errdesc); + +/* Determine whether DIE has attribute specified of given type. */ +extern int dwarf_hasattr (Dwarf_Die die, Dwarf_Half attr, + Dwarf_Bool *return_bool, Dwarf_Error *errdesc); + +/* Return DIE attribute with specified of given type. */ +extern int dwarf_attr (Dwarf_Die die, Dwarf_Half attr, + Dwarf_Attribute *return_attr, Dwarf_Error *errdesc); + +/* Return low program counter value associated with die. */ +extern int dwarf_lowpc (Dwarf_Die die, Dwarf_Addr *return_lowpc, + Dwarf_Error *errdesc); + +/* Return high program counter value associated with die. */ +extern int dwarf_highpc (Dwarf_Die die, Dwarf_Addr *return_lowpc, + Dwarf_Error *errdesc); + +/* Return byte size value associated with die. */ +extern int dwarf_bytesize (Dwarf_Die die, Dwarf_Unsigned *return_size, + Dwarf_Error *errdesc); + +/* Return bit size value associated with die. */ +extern int dwarf_bitsize (Dwarf_Die die, Dwarf_Unsigned *return_size, + Dwarf_Error *errdesc); + +/* Return bit offset value associated with die. */ +extern int dwarf_bitoffset (Dwarf_Die die, Dwarf_Unsigned *return_size, + Dwarf_Error *errdesc); + +/* Return source language associated with die. */ +extern int dwarf_srclang (Dwarf_Die die, Dwarf_Unsigned *return_lang, + Dwarf_Error *errdesc); + +/* Return source language associated with die. */ +extern int dwarf_arrayorder (Dwarf_Die die, Dwarf_Unsigned *return_order, + Dwarf_Error *errdesc); + + +/* Determine whether attribute has given form. */ +extern int dwarf_hasform (Dwarf_Attribute attr, Dwarf_Half form, + Dwarf_Bool *return_hasform, Dwarf_Error *errdesc); + +/* Return form of attribute. */ +extern int dwarf_whatform (Dwarf_Attribute attr, Dwarf_Half *return_form, + Dwarf_Error *errdesc); + +/* Return code of attribute. */ +extern int dwarf_whatattr (Dwarf_Attribute attr, Dwarf_Half *return_attr, + Dwarf_Error *errdesc); + +/* Return compile-unit relative offset of reference associated with form. */ +extern int dwarf_formref (Dwarf_Attribute attr, Dwarf_Off *return_offset, + Dwarf_Error *errdesc); + +/* Return .debug_info section global offset of reference associated + with form. */ +extern int dwarf_global_formref (Dwarf_Attribute attr, + Dwarf_Off *return_offset, + Dwarf_Error *errdesc); + +/* Return address represented by attribute. */ +extern int dwarf_formaddr (Dwarf_Attribute attr, Dwarf_Addr *return_addr, + Dwarf_Error *errdesc); + +/* Return flag represented by attribute. */ +extern int dwarf_formflag (Dwarf_Attribute attr, Dwarf_Bool *return_bool, + Dwarf_Error *errdesc); + +/* Return unsigned constant represented by attribute. */ +extern int dwarf_formudata (Dwarf_Attribute attr, Dwarf_Unsigned *return_uval, + Dwarf_Error *errdesc); + +/* Return signed constant represented by attribute. */ +extern int dwarf_formsdata (Dwarf_Attribute attr, Dwarf_Signed *return_uval, + Dwarf_Error *errdesc); + +/* Return block of uninterpreted data represented by attribute. */ +extern int dwarf_formblock (Dwarf_Attribute attr, Dwarf_Block **return_block, + Dwarf_Error *errdesc); + +/* Return string represented by attribute. */ +extern int dwarf_formstring (Dwarf_Attribute attr, char **return_string, + Dwarf_Error *errdesc); + +/* Return location expression list. */ +extern int dwarf_loclist (Dwarf_Attribute attr, Dwarf_Locdesc **llbuf, + Dwarf_Signed *listlen, Dwarf_Error *errdesc); + + +/* Return source lines of compilation unit. */ +extern int dwarf_srclines (Dwarf_Die die, Dwarf_Line **linebuf, + Dwarf_Signed *linecount, Dwarf_Error *errdesc); + +/* Return files used in compilation unit. */ +extern int dwarf_srcfiles (Dwarf_Die die, char ***srcfiles, + Dwarf_Signed *srcfilecount, Dwarf_Error *errdesc); + +/* Determine whether line is the beginning of a statement. */ +extern int dwarf_linebeginstatement (Dwarf_Line line, Dwarf_Bool *return_bool, + Dwarf_Error *errdesc); + +/* Determine whether line is marked as ending a text sequence. */ +extern int dwarf_lineendsequence (Dwarf_Line line, Dwarf_Bool *return_bool, + Dwarf_Error *errdesc); + +/* Return source statement line number. */ +extern int dwarf_lineno (Dwarf_Line line, Dwarf_Unsigned *return_lineno, + Dwarf_Error *errdesc); + +/* Return address associate with line. */ +extern int dwarf_lineaddr (Dwarf_Line line, Dwarf_Addr *return_lineaddr, + Dwarf_Error *errdesc); + +/* Return column at which the statement begins. */ +extern int dwarf_lineoff (Dwarf_Line line, Dwarf_Signed *return_lineoff, + Dwarf_Error *errdesc); + +/* Return source file for line. */ +extern int dwarf_linesrc (Dwarf_Line line, char **return_linesrc, + Dwarf_Error *errdesc); + +/* Determine whether line is marked as beginning a basic block. */ +extern int dwarf_lineblock (Dwarf_Line line, Dwarf_Bool *return_bool, + Dwarf_Error *errdesc); + +/* Determine whether line is marked as ending the prologue. */ +extern int dwarf_lineprologueend (Dwarf_Line line, Dwarf_Bool *return_bool, + Dwarf_Error *errdesc); + +/* Determine whether line is marked as beginning the epilogue. */ +extern int dwarf_lineepiloguebegin (Dwarf_Line line, Dwarf_Bool *return_bool, + Dwarf_Error *errdesc); + + +/* Return list of global definitions. */ +extern int dwarf_get_globals (Dwarf_Debug dbg, Dwarf_Global **globals, + Dwarf_Signed *return_count, + Dwarf_Error *errdesc); + +/* Return name for global definition. */ +extern int dwarf_globname (Dwarf_Global global, char **return_name, + Dwarf_Error *errdesc); + +/* Return DIE offset for global definition. */ +extern int dwarf_global_die_offset (Dwarf_Global global, + Dwarf_Off *return_offset, + Dwarf_Error *errdesc); + +/* Return offset of header of compile unit containing the global definition. */ +extern int dwarf_global_cu_offset (Dwarf_Global global, + Dwarf_Off *return_offset, + Dwarf_Error *errdesc); + +/* Return name, DIE offset, and offset of the compile unit DIE for the + global definition. */ +extern int dwarf_global_name_offsets (Dwarf_Global global, char **return_name, + Dwarf_Off *die_offset, + Dwarf_Off *cu_offset, + Dwarf_Error *errdesc); + + +/* Find start of macro value. */ +extern char *dwarf_find_macro_value_start (char *macro_string); + + +/* Return string from debug string section. */ +extern int dwarf_get_str (Dwarf_Debug dbg, Dwarf_Off offset, char **string, + Dwarf_Signed *returned_str_len, + Dwarf_Error *errdesc); + + +/* Return list address ranges. */ +extern int dwarf_get_aranges (Dwarf_Debug dbg, Dwarf_Arange **aranges, + Dwarf_Signed *return_count, + Dwarf_Error *errdesc); + +/* Find matching range for address. */ +extern int dwarf_get_arange (Dwarf_Arange *aranges, + Dwarf_Unsigned arange_count, Dwarf_Addr address, + Dwarf_Arange *return_arange, + Dwarf_Error *errdesc); + +/* Return offset of compile unit DIE containing the range. */ +extern int dwarf_get_cu_die_offset (Dwarf_Arange arange, + Dwarf_Off *return_offset, + Dwarf_Error *errdesc); + +/* Return start, length, and CU DIE offset of range. */ +extern int dwarf_get_arange_info (Dwarf_Arange arange, Dwarf_Addr *start, + Dwarf_Unsigned *length, + Dwarf_Off *cu_die_offset, + Dwarf_Error *errdesc); + + +/* Frame descriptor handling. */ + +/* Get frame descriptions. GCC version using .eh_frame. */ +extern int dwarf_get_fde_list_eh (Dwarf_Debug dbg, Dwarf_Cie **cie_data, + Dwarf_Signed *cie_element_count, + Dwarf_Fde **fde_data, + Dwarf_Signed *fde_element_count, + Dwarf_Error *errdesc); + +/* Get CIE of FDE. */ +extern int dwarf_get_cie_of_fde (Dwarf_Fde fde, Dwarf_Cie *return_cie, + Dwarf_Error *errdesc); + +/* Get information about the function range. */ +extern int dwarf_get_fde_range (Dwarf_Fde fde, Dwarf_Addr *low_pc, + Dwarf_Unsigned *func_length, + Dwarf_Ptr *fde_bytes, + Dwarf_Unsigned *fde_byte_length, + Dwarf_Off *cie_offset, Dwarf_Signed *cie_index, + Dwarf_Off *fde_offset, Dwarf_Error *errdesc); + +/* Get information about CIE. */ +extern int dwarf_get_cie_info (Dwarf_Cie cie, Dwarf_Unsigned *bytes_in_cie, + Dwarf_Small *version, char **augmenter, + Dwarf_Unsigned *code_alignment_factor, + Dwarf_Signed *data_alignment_factor, + Dwarf_Half *return_address_register, + Dwarf_Ptr *initial_instructions, + Dwarf_Unsigned *initial_instructions_length, + Dwarf_Error *errdesc); + +/* Get frame construction instructions of FDE. */ +extern int dwarf_get_fde_instr_bytes (Dwarf_Fde fde, Dwarf_Ptr *outinstrs, + Dwarf_Unsigned *outlen, + Dwarf_Error *errdesc); + +/* Get nth frame descriptions. */ +extern int dwarf_get_fde_n (Dwarf_Fde *fde_data, Dwarf_Unsigned fde_index, + Dwarf_Fde *returned_fde, Dwarf_Error *errdesc); + +/* Find FDE for given address. */ +extern int dwarf_get_fde_at_pc (Dwarf_Fde *fde_data, Dwarf_Addr pc_of_interest, + Dwarf_Fde *returned_fde, Dwarf_Addr *lopc, + Dwarf_Addr *hipc, Dwarf_Error *errdesc); + + +/* Return location list entry. */ +extern int dwarf_get_loclist_entry (Dwarf_Debug dbg, Dwarf_Unsigned offset, + Dwarf_Addr *hipc_offset, + Dwarf_Addr *lopc_offset, Dwarf_Ptr *data, + Dwarf_Unsigned *entry_len, + Dwarf_Unsigned *next_entry, + Dwarf_Error *errdesc); + + +/* Get abbreviation record. */ +extern int dwarf_get_abbrev (Dwarf_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_Abbrev *returned_abbrev, + Dwarf_Unsigned *length, + Dwarf_Unsigned *attr_count, Dwarf_Error *errdesc); + +/* Get tag of abbreviation record. */ +extern int dwarf_get_abbrev_tag (Dwarf_Abbrev abbrev, Dwarf_Half *return_tag, + Dwarf_Error *errdesc); + +/* Get code of abbreviation record. */ +extern int dwarf_get_abbrev_code (Dwarf_Abbrev abbrev, + Dwarf_Unsigned *return_code, + Dwarf_Error *errdesc); + +/* Get children flag of abbreviation record. */ +extern int dwarf_get_abbrev_children_flag (Dwarf_Abbrev abbrev, + Dwarf_Signed *return_flag, + Dwarf_Error *errdesc); + +/* Get attribute from abbreviation record. */ +extern int dwarf_get_abbrev_entry (Dwarf_Abbrev abbrev, Dwarf_Signed idx, + Dwarf_Half *attr_num, Dwarf_Signed *form, + Dwarf_Off *offset, Dwarf_Error *errdesc); + + +/* Memory handling. */ + +/* Values for ALLOC_TYPE parameter of 'dwarf_dealloc'. */ +enum + { + DW_DLA_NONE = 0, + DW_DLA_STRING, /* char* */ + DW_DLA_LOC, /* Dwarf_Loc */ + DW_DLA_LOCDESC, /* Dwarf_Locdesc */ + DW_DLA_ELLIST, /* Dwarf_Ellist */ + DW_DLA_BOUNDS, /* Dwarf_Bounds */ + DW_DLA_BLOCK, /* Dwarf_Block */ + DW_DLA_DEBUG, /* Dwarf_Debug */ + DW_DLA_DIE, /* Dwarf_Die */ + DW_DLA_LINE, /* Dwarf_Line */ + DW_DLA_ATTR, /* Dwarf_Attribute */ + DW_DLA_TYPE, /* Dwarf_Type */ + DW_DLA_SUBSCR, /* Dwarf_Subscr */ + DW_DLA_GLOBAL, /* Dwarf_Global */ + DW_DLA_ERROR, /* Dwarf_Error */ + DW_DLA_LIST, /* a list */ + DW_DLA_LINEBUF, /* Dwarf_Line* */ + DW_DLA_ARANGE, /* Dwarf_Arange */ + DW_DLA_ABBREV, /* Dwarf_Abbrev */ + DW_DLA_FRAME_OP, /* Dwarf_Frame_Op */ + DW_DLA_CIE, /* Dwarf_Cie */ + DW_DLA_FDE, /* Dwarf_Fde */ + DW_DLA_LOC_BLOCK, /* Dwarf_Loc Block */ + DW_DLA_FRAME_BLOCK, /* Dwarf_Frame Block */ + DW_DLA_FUNC, /* Dwarf_Func */ + DW_DLA_TYPENAME, /* Dwarf_Type */ + DW_DLA_VAR, /* Dwarf_Var */ + DW_DLA_WEAK, /* Dwarf_Weak */ + DW_DLA_ADDR, /* Dwarf_Addr sized entries */ + }; + +/* Deallocate memory. */ +extern void dwarf_dealloc (Dwarf_Debug dbg, Dwarf_Ptr space, + Dwarf_Unsigned alloc_type); + + +/* Determine size of address of the binary. */ +extern int dwarf_get_address_size (Dwarf_Debug dbg, Dwarf_Half *addr_size, + Dwarf_Error *errdesc); + + +/* Return error number. */ +extern Dwarf_Unsigned dwarf_errno (Dwarf_Error errdesc); + +/* Return string corresponding to error. */ +extern const char *dwarf_errmsg (Dwarf_Error errdesc); + + +/* Set new error handler. */ +extern Dwarf_Handler dwarf_seterrhand (Dwarf_Debug dbg, Dwarf_Handler errhand); + +/* Set new error handler argument. */ +extern Dwarf_Ptr dwarf_seterrarg (Dwarf_Debug dbg, Dwarf_Ptr errarg); + +#endif /* libdwarf.h */ diff --git a/libdwarf/libdwarf.map b/libdwarf/libdwarf.map new file mode 100644 index 00000000..ec0e805e --- /dev/null +++ b/libdwarf/libdwarf.map @@ -0,0 +1,81 @@ +ELFUTILS_1.0 { + global: + dwarf_arrayorder; + dwarf_attr; + dwarf_attrlist; + dwarf_bitoffset; + dwarf_bitsize; + dwarf_bytesize; + dwarf_child; + dwarf_dealloc; + dwarf_die_CU_offset; + dwarf_diename; + dwarf_dieoffset; + dwarf_elf_init; + dwarf_errmsg; + dwarf_errno; + dwarf_find_macro_value_start; + dwarf_finish; + dwarf_formaddr; + dwarf_formblock; + dwarf_formflag; + dwarf_formref; + dwarf_formsdata; + dwarf_formstring; + dwarf_formudata; + dwarf_get_abbrev; + dwarf_get_abbrev_children_flag; + dwarf_get_abbrev_code; + dwarf_get_abbrev_entry; + dwarf_get_abbrev_tag; + dwarf_get_address_size; + dwarf_get_arange; + dwarf_get_arange_info; + dwarf_get_aranges; + dwarf_get_cie_info; + dwarf_get_cie_of_fde; + dwarf_get_cu_die_offset; + dwarf_get_elf_init; + dwarf_get_fde_at_pc; + dwarf_get_fde_instr_bytes; + dwarf_get_fde_list_eh; + dwarf_get_fde_n; + dwarf_get_fde_range; + dwarf_get_globals; + dwarf_get_loclist_entry; + dwarf_get_str; + dwarf_global_cu_offset; + dwarf_global_die_offset; + dwarf_global_formref; + dwarf_global_name_offsets; + dwarf_globname; + dwarf_hasattr; + dwarf_hasform; + dwarf_highpc; + dwarf_init; + dwarf_lineaddr; + dwarf_linebeginstatement; + dwarf_lineblock; + dwarf_lineendsequence; + dwarf_lineepiloguebegin; + dwarf_lineno; + dwarf_lineoff; + dwarf_lineprologueend; + dwarf_linesrc; + dwarf_loclist; + dwarf_lowpc; + dwarf_next_cu_header; + dwarf_offdie; + dwarf_seterrarg; + dwarf_seterrhand; + dwarf_siblingof; + dwarf_srcfiles; + dwarf_srclang; + dwarf_srclines; + dwarf_tag; + dwarf_whatattr; + dwarf_whatform; + + local: + *; +}; diff --git a/libdwarf/libdwarfP.h b/libdwarf/libdwarfP.h new file mode 100644 index 00000000..c6162eee --- /dev/null +++ b/libdwarf/libdwarfP.h @@ -0,0 +1,319 @@ +/* Internal definitions for libdwarf. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBDWARFP_H +#define _LIBDWARFP_H 1 + +#include +#include +#include + +#include + + +/* Version of the DWARF specification we support. */ +#define DWARF_VERSION 2 + +/* Version of the CIE format. */ +#define CIE_VERSION 1 + +/* Some additional basic types. */ +typedef unsigned int Dwarf_Word; + + +/* Valid indeces for the section data. */ +enum + { + IDX_debug_info = 0, + IDX_debug_abbrev, + IDX_debug_aranges, + IDX_debug_line, + IDX_debug_frame, + IDX_eh_frame, + IDX_debug_loc, + IDX_debug_pubnames, + IDX_debug_str, + IDX_debug_funcnames, + IDX_debug_typenames, + IDX_debug_varnames, + IDX_debug_weaknames, + IDX_debug_macinfo, + IDX_last + }; + + +/* This is the structure representing the debugging state. */ +struct Dwarf_Debug_s + { +#ifdef DWARF_DEBUG + int memtag; +#endif + + Dwarf_Handler dbg_errhand; + Dwarf_Ptr dbg_errarg; + + Elf *elf; + int other_byte_order; + + Dwarf_Unsigned access; + + /* The section data. */ + struct + { + Dwarf_Small *addr; + Dwarf_Unsigned size; + } sections[IDX_last]; + + /* Compilation unit handling. To enable efficient searching we + keep track of the unit we already found. */ + struct Dwarf_CU_Info_s + { + /* This is the information the 'dwarf_next_cu_header' function + is supposed to return. */ + Dwarf_Unsigned header_length; + Dwarf_Unsigned length; + Dwarf_Unsigned abbrev_offset; + Dwarf_Half version_stamp; + Dwarf_Half address_size; + + Dwarf_Unsigned offset; /* In .debug_info section. */ + + /* Used to distinguish between 32-bit and 64-bit DWARF. */ + Dwarf_Half offset_size; + + /* Hash table for the abbreviations. */ + Dwarf_Abbrev_Hash abbrev_hash; + Dwarf_Unsigned last_abbrev_offset; + + Dwarf_Debug dbg; + + struct Dwarf_CU_Info_s *next; + } *cu_list; + struct Dwarf_CU_Info_s *cu_list_current; + struct Dwarf_CU_Info_s *cu_list_tail; + + Dwarf_Unsigned cie_cnt; + Dwarf_Unsigned fde_cnt; + }; +typedef struct Dwarf_CU_Info_s *Dwarf_CU_Info; + + +/* Memory access macros. We have to define it here since code in the + header needs to know the structure of Dwarf_Debug. */ +#include "memory-access.h" + + +/* DWARF die representation. */ +struct Dwarf_Die_s + { +#ifdef DWARF_DEBUG + int memtag; +#endif + + Dwarf_Small *addr; + Dwarf_Abbrev abbrev; + Dwarf_CU_Info cu; + }; + + +/* Abbreviation list. */ +struct Dwarf_Abbrev_s + { + Dwarf_Unsigned code; /* The code. */ + Dwarf_Half tag; /* The tag. */ + Dwarf_Small *attrp; /* Pointer to beginning of attributes. */ + Dwarf_Unsigned attrcnt; /* Number of attributes. */ + int has_children; /* Nonzero of abbreviation has children. */ + Dwarf_Unsigned offset; /* Offset in the .debug_abbrev section. */ + }; + + +/* Attribute list. */ +struct Dwarf_Attribute_s + { + Dwarf_Half code; /* DWARF attribute code. */ + Dwarf_Half form; /* DWARF form. */ + Dwarf_Small *valp; + Dwarf_CU_Info cu; + }; + + +/* Structure for error values. */ +struct Dwarf_Error_s + { + unsigned int de_error; + }; + + +/* Files in line information records. */ +typedef struct Dwarf_File_s + { + Dwarf_Debug dbg; + unsigned int nfiles; + struct Dwarf_Fileinfo_s + { + char *name; + Dwarf_Unsigned mtime; + Dwarf_Unsigned length; + } info[0]; + } *Dwarf_File; +typedef struct Dwarf_Fileinfo_s Dwarf_Fileinfo; + + +/* Representation of a row in the line table. */ +struct Dwarf_Line_s + { + Dwarf_Addr addr; + unsigned int file; + int line; + unsigned short int column; + unsigned int is_stmt:1; + unsigned int basic_block:1; + unsigned int end_sequence:1; + unsigned int prologue_end:1; + unsigned int epilogue_begin:1; + + Dwarf_File files; + }; + + +/* Additional, shared information required for Dwarf_Global handling. */ +typedef struct Dwarf_Global_Info_s + { + Dwarf_Debug dbg; + Dwarf_Unsigned offset; + } *Dwarf_Global_Info; + +/* Representation of a global name entry. */ +struct Dwarf_Global_s + { + Dwarf_Unsigned offset; + char *name; + Dwarf_Global_Info info; + }; + + +/* Additional, shared information required for Dwarf_Arange handling. */ +typedef struct Dwarf_Arange_Info_s + { + Dwarf_Debug dbg; + Dwarf_Unsigned offset; + } *Dwarf_Arange_Info; + +/* Representation of an address range entry. */ +struct Dwarf_Arange_s + { + Dwarf_Addr address; + Dwarf_Unsigned length; + Dwarf_Arange_Info info; + }; + + +/* Representation of a common information entry. */ +struct Dwarf_Cie_s + { + Dwarf_Debug dbg; + Dwarf_Unsigned length; + char *augmentation; + Dwarf_Unsigned code_alignment_factor; + Dwarf_Signed data_alignment_factor; + Dwarf_Small *initial_instructions; + Dwarf_Unsigned initial_instructions_length; + Dwarf_Small return_address_register; + Dwarf_Unsigned offset; + Dwarf_Signed index; + }; + + +/* Representation of a frame descriptor entry. */ +struct Dwarf_Fde_s + { + Dwarf_Cie cie; + Dwarf_Addr initial_location; + Dwarf_Unsigned address_range; + Dwarf_Small *instructions; + Dwarf_Unsigned instructions_length; + Dwarf_Unsigned offset; + Dwarf_Small *fde_bytes; + Dwarf_Unsigned fde_byte_length; + }; + + +/* Internal error values. */ +enum + { + DW_E_NOERROR = 0, + DW_E_INVALID_ACCESS, + DW_E_NO_REGFILE, + DW_E_IO_ERROR, + DW_E_NOMEM, + DW_E_NOELF, + DW_E_GETEHDR_ERROR, + DW_E_INVALID_ELF, + DW_E_INVALID_DWARF, + DW_E_NO_DWARF, + DW_E_NO_CU, + DW_E_1ST_NO_CU, + DW_E_INVALID_OFFSET, + DW_E_INVALID_REFERENCE, + DW_E_NO_REFERENCE, + DW_E_NO_ADDR, + DW_E_NO_FLAG, + DW_E_NO_CONSTANT, + DW_E_NO_BLOCK, + DW_E_NO_STRING, + DW_E_WRONG_ATTR, + DW_E_NO_DATA, + DW_E_NO_DEBUG_LINE, + DW_E_VERSION_ERROR, + DW_E_INVALID_DIR_IDX, + DW_E_INVALID_ADDR, + DW_E_NO_ABBR, + }; + + +/* Handle error according to user's wishes. */ +extern void __libdwarf_error (Dwarf_Debug dbg, Dwarf_Error *err, int errval) + internal_function; + + +/* Find CU at given offset. */ +extern int __libdwarf_get_cu_at_offset (Dwarf_Debug dbg, Dwarf_Unsigned offset, + Dwarf_CU_Info *result_cu, + Dwarf_Error *err) internal_function; + +/* Find abbreviation. */ +extern Dwarf_Abbrev __libdwarf_get_abbrev (Dwarf_Debug dbg, + Dwarf_CU_Info cu, + Dwarf_Word code, + Dwarf_Error *err) + internal_function; + +/* Get constant type attribute value. */ +extern int __libdwarf_getconstant (Dwarf_Die die, Dwarf_Half name, + Dwarf_Unsigned *return_size, + Dwarf_Error *err) internal_function; + +/* Determine length of form parameters. */ +extern int __libdwarf_form_val_len (Dwarf_Debug dbg, Dwarf_CU_Info cu, + Dwarf_Word form, Dwarf_Small *valp, + size_t *len, Dwarf_Error *err) + internal_function; + + +/* gettext helper macros. */ +#define _(Str) dgettext ("libdwarf", Str) +#define N_(Str) Str + +#endif /* libdwarfP.h */ diff --git a/libdwarf/memory-access.h b/libdwarf/memory-access.h new file mode 100644 index 00000000..dcd52b5b --- /dev/null +++ b/libdwarf/memory-access.h @@ -0,0 +1,207 @@ +/* Unaligned memory access functionality. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _MEMORY_ACCESS_H +#define _MEMORY_ACCESS_H 1 + +#include +#include + + +/* Number decoding macros. See 7.6 Variable Length Data. */ +#define get_uleb128(var, addr) \ + do { \ + Dwarf_Small __b = *addr++; \ + var = __b & 0x7f; \ + if (__b & 0x80) \ + { \ + __b = *addr++; \ + var |= (__b & 0x7f) << 7; \ + if (__b & 0x80) \ + { \ + __b = *addr++; \ + var |= (__b & 0x7f) << 14; \ + if (__b & 0x80) \ + { \ + __b = *addr++; \ + var |= (__b & 0x7f) << 21; \ + if (__b & 0x80) \ + /* Other implementation set VALUE to UINT_MAX in this \ + case. So we better do this as well. */ \ + var = UINT_MAX; \ + } \ + } \ + } \ + } while (0) + +/* The signed case is a big more complicated. */ +#define get_sleb128(var, addr) \ + do { \ + Dwarf_Small __b = *addr++; \ + int32_t __res = __b & 0x7f; \ + if ((__b & 0x80) == 0) \ + { \ + if (__b & 0x40) \ + __res |= 0xffffff80; \ + } \ + else \ + { \ + __b = *addr++; \ + __res |= (__b & 0x7f) << 7; \ + if ((__b & 0x80) == 0) \ + { \ + if (__b & 0x40) \ + __res |= 0xffffc000; \ + } \ + else \ + { \ + __b = *addr++; \ + __res |= (__b & 0x7f) << 14; \ + if ((__b & 0x80) == 0) \ + { \ + if (__b & 0x40) \ + __res |= 0xffe00000; \ + } \ + else \ + { \ + __b = *addr++; \ + __res |= (__b & 0x7f) << 21; \ + if ((__b & 0x80) == 0) \ + { \ + if (__b & 0x40) \ + __res |= 0xf0000000; \ + } \ + else \ + /* Other implementation set VALUE to INT_MAX in this \ + case. So we better do this as well. */ \ + __res = INT_MAX; \ + } \ + } \ + } \ + var = __res; \ + } while (0) + + +/* We use simple memory access functions in case the hardware allows it. + The caller has to make sure we don't have alias problems. */ +#if ALLOW_UNALIGNED + +# define read_2ubyte_unaligned(Dbg, Addr) \ + ((Dbg)->other_byte_order \ + ? bswap_16 (*((uint16_t *) (Addr))) \ + : *((uint16_t *) (Addr))) +# define read_2sbyte_unaligned(Dbg, Addr) \ + ((Dbg)->other_byte_order \ + ? (int16_t) bswap_16 (*((int16_t *) (Addr))) \ + : *((int16_t *) (Addr))) + +# define read_4ubyte_unaligned_noncvt(Addr) \ + *((uint32_t *) (Addr)) +# define read_4ubyte_unaligned(Dbg, Addr) \ + ((Dbg)->other_byte_order \ + ? bswap_32 (*((uint32_t *) (Addr))) \ + : *((uint32_t *) (Addr))) +# define read_4sbyte_unaligned(Dbg, Addr) \ + ((Dbg)->other_byte_order \ + ? (int32_t) bswap_32 (*((int32_t *) (Addr))) \ + : *((int32_t *) (Addr))) + +# define read_8ubyte_unaligned(Dbg, Addr) \ + ((Dbg)->other_byte_order \ + ? bswap_64 (*((uint64_t *) (Addr))) \ + : *((uint64_t *) (Addr))) +# define read_8sbyte_unaligned(Dbg, Addr) \ + ((Dbg)->other_byte_order \ + ? (int64_t) bswap_64 (*((int64_t *) (Addr))) \ + : *((int64_t *) (Addr))) + +#else + +# if __GNUC__ + +union unaligned + { + void *p; + uint16_t u2; + uint32_t u4; + uint64_t u8; + int16_t s2; + int32_t s4; + int64_t s8; + } __attribute__ ((packed)); + +static inline uint16_t +read_2ubyte_unaligned (Dwarf_Debug dbg, void *p) +{ + union unaligned *up = p; + if (dbg->other_byte_order) + return bswap_16 (up->u2); + return up->u2; +} +static inline int16_t +read_2sbyte_unaligned (Dwarf_Debug dbg, void *p) +{ + union unaligned *up = p; + if (dbg->other_byte_order) + return (int16_t) bswap_16 (up->u2); + return up->s2; +} + +static inline uint32_t +read_4ubyte_unaligned_noncvt (void *p) +{ + union unaligned *up = p; + return up->u4; +} +static inline uint32_t +read_4ubyte_unaligned (Dwarf_Debug dbg, void *p) +{ + union unaligned *up = p; + if (dbg->other_byte_order) + return bswap_32 (up->u4); + return up->u4; +} +static inline int32_t +read_4sbyte_unaligned (Dwarf_Debug dbg, void *p) +{ + union unaligned *up = p; + if (dbg->other_byte_order) + return (int32_t) bswap_32 (up->u4); + return up->s4; +} + +static inline uint64_t +read_8ubyte_unaligned (Dwarf_Debug dbg, void *p) +{ + union unaligned *up = p; + if (dbg->other_byte_order) + return bswap_64 (up->u8); + return up->u8; +} +static inline int64_t +read_8sbyte_unaligned (Dwarf_Debug dbg, void *p) +{ + union unaligned *up = p; + if (dbg->other_byte_order) + return (int64_t) bswap_64 (up->u8); + return up->s8; +} + +# else +# error "TODO" +# endif + +#endif + +#endif /* memory-access.h */ diff --git a/libdwfl/.cvsignore b/libdwfl/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/libdwfl/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog new file mode 100644 index 00000000..a4b8732b --- /dev/null +++ b/libdwfl/ChangeLog @@ -0,0 +1,13 @@ +2005-07-23 Ulrich Drepper + + * Makefile.am: Fix rules to allow building with mudflap. + +2005-07-21 Roland McGrath + + * Makefile.am (noinst_HEADERS): Add loc2c.c. + + * test2.c (main): Check sscanf result to quiet warning. + +2005-07-20 Roland McGrath + + * libdwfl-branch merged, creating this direcotry. diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am new file mode 100644 index 00000000..de4507f2 --- /dev/null +++ b/libdwfl/Makefile.am @@ -0,0 +1,114 @@ +## Makefile.am for libdwfl library subdirectory in elfutils. +## +## Process this file with automake to create Makefile.in +## +## Copyright (C) 2005 Red Hat, Inc. +## +## This program is Open Source software; you can redistribute it and/or +## modify it under the terms of the Open Software License version 1.0 as +## published by the Open Source Initiative. +## +## You should have received a copy of the Open Software License along +## with this program; if not, you may obtain a copy of the Open Software +## License version 1.0 from http://www.opensource.org/licenses/osl.php or +## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +## 3001 King Ranch Road, Ukiah, CA 95482. +## +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H +if MUDFLAP +AM_CFLAGS = -fmudflap +else +AM_CFLAGS = +endif +AM_CFLAGS += -Wall -Werror -Wshadow -Wunused -Wformat=2 -Wextra -std=gnu99 +INCLUDES = -I. -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl \ + -I$(srcdir)/../libdw -I.. -I$(srcdir)/../lib +VERSION = 1 + +noinst_PROGRAMS = ptest test2 + +test2_SOURCES = test2.c loc2c.c + +lib_LIBRARIES = libdwfl.a +if !MUDFLAP +noinst_LIBRARIES = libdwfl_pic.a +noinst_PROGRAMS += $(noinst_LIBRARIES:_pic.a=.so) +endif + +euincludedir = ${includedir}/elfutils +euinclude_HEADERS = libdwfl.h + +libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c \ + dwfl_module.c dwfl_report_elf.c relocate.c \ + dwfl_module_info.c dwfl_getmodules.c \ + dwfl_module_getdwarf.c dwfl_getdwarf.c \ + argp-std.c find-debuginfo.c \ + linux-kernel-modules.c linux-proc-maps.c \ + dwfl_addrmodule.c dwfl_addrdwarf.c \ + cu.c dwfl_module_nextcu.c dwfl_nextcu.c dwfl_cumodule.c \ + dwfl_module_addrdie.c dwfl_addrdie.c \ + lines.c dwfl_lineinfo.c dwfl_linemodule.c \ + dwfl_module_getsrc.c dwfl_getsrc.c \ + dwfl_module_getsrc_file.c \ + elf-from-memory.c + + +if MUDFLAP +libdwfl = libdwfl.a $(libdw) $(libebl) $(libelf) $(libeu) +libdw = ../libdw/libdw.a +libelf = ../libelf/libelf.a +libmudflap = -lmudflap +else +libdwfl = libdwfl.so +libdw = ../libdw/libdw.so +libelf = ../libelf/libelf.so +endif +libebl = ../libebl/libebl.a +libeu = ../lib/libeu.a + + +if !MUDFLAP +libdwfl_pic_a_SOURCES = +am_libdwfl_pic_a_OBJECTS = $(libdwfl_a_SOURCES:.c=.os) + +libdwfl_so_SOURCES = +libdwfl_LIBS = $(libeu) $(libdw) $(libebl) $(libelf) +libdwfl_so_LDADD = -ldl +libdwfl.so: libdwfl_pic.a $(srcdir)/libdwfl.map $(libdwfl_LIBS) + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libdwfl.map,--no-undefined \ + -Wl,--soname,$@.$(VERSION),-z,defs \ + $(libdwfl_LIBS) $(libdwfl_so_LDADD) + if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi + ln -fs $@ $@.$(VERSION) + + +%.os: %.c %.o + if $(COMPILE) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \ + -MF "$(DEPDIR)/$*.Tpo" `test -f '$<' || echo '$(srcdir)/'`$<; \ + then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ + rm -f "$(DEPDIR)/$*.Tpo"; \ + else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ + fi + +install: install-am libdwfl.so + $(mkinstalldirs) $(DESTDIR)$(libdir) + $(INSTALL_PROGRAM) libdwfl.so $(DESTDIR)$(libdir)/libdwfl-$(PACKAGE_VERSION).so + ln -fs libdwfl-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libdwfl.so.$(VERSION) + ln -fs libdwfl.so.$(VERSION) $(DESTDIR)$(libdir)/libdwfl.so + +uninstall: uninstall-am + rm -f $(DESTDIR)$(libdir)/libdwfl-$(PACKAGE_VERSION).so + rm -f $(DESTDIR)$(libdir)/libdwfl.so.$(VERSION) + rm -f $(DESTDIR)$(libdir)/libdwfl.so + rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils +endif + +noinst_HEADERS = libdwflP.h loc2c.h + +EXTRA_DIST = libdwfl.map + +CLEANFILES = $(am_libdwfl_pic_a_OBJECTS) + +ptest_LDADD = $(libdwfl) $(libdw) $(libmudflap) +test2_LDADD = $(libdwfl) $(libdw) $(libmudflap) diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c new file mode 100644 index 00000000..ebddcfb1 --- /dev/null +++ b/libdwfl/argp-std.c @@ -0,0 +1,164 @@ +/* Standard argp argument parsers for tools using libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" +#include +#include +#include +#include + +/* gettext helper macros. */ +#define _(Str) dgettext ("elfutils", Str) + + +#define OPT_DEBUGINFO 0x100 + +static const struct argp_option options[] = +{ + { NULL, 0, NULL, 0, N_("Input Selection:"), 0 }, + { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 }, + { "pid", 'p', "PID", 0, + N_("Find addresses in files mapped into process PID"), 0 }, + { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 }, + { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0, + N_("Search path for separate debuginfo files"), 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +static char *debuginfo_path; + +static const Dwfl_Callbacks proc_callbacks = + { + .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo), + .debuginfo_path = &debuginfo_path, + + .find_elf = INTUSE(dwfl_linux_proc_find_elf), + }; + +static const Dwfl_Callbacks kernel_callbacks = + { + .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo), + .debuginfo_path = &debuginfo_path, + + .find_elf = INTUSE(dwfl_linux_kernel_find_elf), + .section_address = INTUSE(dwfl_linux_kernel_module_section_address), + }; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + inline void failure (int errnum, const char *msg) + { + if (errnum == -1) + argp_failure (state, EXIT_FAILURE, 0, "%s: %s", + msg, INTUSE(dwfl_errmsg) (-1)); + else + argp_failure (state, EXIT_FAILURE, errnum, "%s", msg); + } + inline error_t fail (int errnum, const char *msg) + { + failure (errnum, msg); + return errnum == -1 ? EIO : errnum; + } + + switch (key) + { + case OPT_DEBUGINFO: + debuginfo_path = arg; + break; + + case 'e': + if (state->hook == NULL) + { + Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks); + if (INTUSE(dwfl_report_elf) (dwfl, "", arg, -1, 0) == NULL) + return fail (-1, arg); + state->hook = dwfl; + } + else + { + toomany: + argp_error (state, "%s", _("only one -e, -p, or -k option allowed")); + return EINVAL; + } + break; + + case 'p': + if (state->hook == NULL) + { + Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks); + int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg)); + if (result != 0) + return fail (result, arg); + state->hook = dwfl; + } + else + goto toomany; + break; + + case 'k': + if (state->hook == NULL) + { + Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks); + int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl); + if (result != 0) + return fail (result, _("cannot load kernel symbols")); + result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl); + if (result != 0) + /* Non-fatal to have no modules since we do have the kernel. */ + failure (result, _("cannot find kernel modules")); + state->hook = dwfl; + } + else + goto toomany; + break; + + case ARGP_KEY_SUCCESS: + { + Dwfl *dwfl = state->hook; + + if (dwfl == NULL) + { + /* Default if no -e, -p, or -k, is "-e a.out". */ + arg = "a.out"; + dwfl = INTUSE(dwfl_begin) (&proc_callbacks); + if (INTUSE(dwfl_report_elf) (dwfl, "", arg, -1, 0) == NULL) + return fail (-1, arg); + state->hook = dwfl; + } + + /* One of the three flavors has done dwfl_begin and some reporting + if we got here. Tie up the Dwfl and return it to the caller of + argp_parse. */ + + int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL); + assert (result == 0); + + *(Dwfl **) state->input = dwfl; + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static const struct argp libdwfl_argp = + { .options = options, .parser = parse_opt }; + +const struct argp * +dwfl_standard_argp (void) +{ + return &libdwfl_argp; +} diff --git a/libdwfl/cu.c b/libdwfl/cu.c new file mode 100644 index 00000000..44207097 --- /dev/null +++ b/libdwfl/cu.c @@ -0,0 +1,275 @@ +/* Keeping track of DWARF compilation units in libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" +#include "../libdw/libdwP.h" +#include "../libdw/memory-access.h" +#include + + +static inline Dwarf_Arange * +dwar (Dwfl_Module *mod, unsigned int idx) +{ + return &mod->dw->aranges->info[mod->aranges[idx].arange]; +} + + +static Dwfl_Error +addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange) +{ + if (mod->aranges == NULL) + { + Dwarf_Aranges *dwaranges; + if (dwarf_getaranges (mod->dw, &dwaranges, NULL) != 0) + return DWFL_E_LIBDW; + + struct dwfl_arange *aranges = malloc (dwaranges->naranges + * sizeof *aranges); + if (unlikely (aranges == NULL)) + return DWFL_E_NOMEM; + + /* libdw has sorted its list by address, which is how we want it. + But the sorted list is full of not-quite-contiguous runs pointing + to the same CU. We don't care about the little gaps inside the + module, we'll consider them part of the surrounding CU anyway. + Collect our own array with just one record for each run of ranges + pointing to one CU. */ + + size_t naranges = 0; + Dwarf_Off lastcu = 0; + for (size_t i = 0; i < dwaranges->naranges; ++i) + if (i == 0 || dwaranges->info[i].offset != lastcu) + { + aranges[naranges].arange = i; + aranges[naranges].cu = NULL; + ++naranges; + lastcu = dwaranges->info[i].offset; + } + + /* Store the final array, which is probably much smaller than before. */ + mod->naranges = naranges; + mod->aranges = (realloc (aranges, naranges * sizeof aranges[0]) + ?: aranges); + mod->lazycu += naranges; + } + + /* The address must be inside the module to begin with. */ + addr -= mod->debug.bias; + + /* The ranges are sorted by address, so we can use binary search. */ + size_t l = 0, u = mod->naranges; + while (l < u) + { + size_t idx = (l + u) / 2; + Dwarf_Addr start = dwar (mod, idx)->addr; + if (addr < start) + { + u = idx; + continue; + } + else if (addr > start) + { + if (idx + 1 < mod->naranges) + { + if (addr >= dwar (mod, idx + 1)->addr) + { + l = idx + 1; + continue; + } + } + else + { + /* It might be in the last range. */ + const Dwarf_Arange *last + = &mod->dw->aranges->info[mod->dw->aranges->naranges - 1]; + if (addr > last->addr + last->length) + break; + } + } + + *arange = &mod->aranges[idx]; + return DWFL_E_NOERROR; + } + + return DWFL_E_ADDR_OUTOFRANGE; +} + + +static void +nofree (void *arg) +{ + struct dwfl_cu *cu = arg; + if (cu == (void *) -1l) + return; + + assert (cu->mod->lazycu == 0); +} + +/* One reason fewer to keep the lazy lookup table for CUs. */ +static inline void +less_lazy (Dwfl_Module *mod) +{ + if (--mod->lazycu > 0) + return; + + /* We know about all the CUs now, we don't need this table. */ + tdestroy (mod->lazy_cu_root, nofree); + mod->lazy_cu_root = NULL; +} + +static inline Dwarf_Off +cudie_offset (const struct dwfl_cu *cu) +{ + return cu->die.cu->start + 3 * cu->die.cu->offset_size - 4 + 3; +} + +static int +compare_cukey (const void *a, const void *b) +{ + return cudie_offset (a) - cudie_offset (b); +} + +/* Intern the CU if necessary. */ +static Dwfl_Error +intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result) +{ + struct Dwarf_CU dwkey; + struct dwfl_cu key; + key.die.cu = &dwkey; + dwkey.offset_size = 0; + dwkey.start = cuoff - (3 * 0 - 4 + 3); + struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey); + if (unlikely (found == NULL)) + return DWFL_E_NOMEM; + + if (*found == &key || *found == NULL) + { + if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size)) + { + /* This is the EOF marker. Now we have interned all the CUs. + One increment in MOD->lazycu counts not having hit EOF yet. */ + *found = (void *) -1l; + less_lazy (mod); + } + else + { + /* This is a new entry, meaning we haven't looked at this CU. */ + + *found = NULL; + + struct dwfl_cu *cu = malloc (sizeof *cu); + if (unlikely (cu == NULL)) + return DWFL_E_NOMEM; + + cu->mod = mod; + cu->next = NULL; + cu->lines = NULL; + + /* XXX use non-searching lookup */ + Dwarf_Die *die = dwarf_offdie (mod->dw, cuoff, &cu->die); + if (die == NULL) + return DWFL_E_LIBDW; + assert (die == &cu->die); + + struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1) + * sizeof (mod->cu[0]))); + if (newvec == NULL) + { + free (cu); + return DWFL_E_NOMEM; + } + mod->cu = newvec; + + mod->cu[mod->ncu++] = cu; + if (cu->die.cu->start == 0) + mod->first_cu = cu; + + *found = cu; + } + } + + *result = *found; + return DWFL_E_NOERROR; +} + + +/* Traverse all the CUs in the module. */ + +Dwfl_Error +internal_function_def +__libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu, + struct dwfl_cu **cu) +{ + Dwarf_Off cuoff; + struct dwfl_cu **nextp; + + if (lastcu == NULL) + { + /* Start the traversal. */ + cuoff = 0; + nextp = &mod->first_cu; + } + else + { + /* Continue following LASTCU. */ + cuoff = lastcu->die.cu->end; + nextp = &lastcu->next; + } + + if (*nextp == NULL) + { + size_t cuhdrsz; + Dwarf_Off nextoff; + if (dwarf_nextcu (mod->dw, cuoff, &nextoff, &cuhdrsz, + NULL, NULL, NULL) != 0) + return DWFL_E_LIBDW; + + Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp); + if (result != DWFL_E_NOERROR) + return result; + + if ((*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l) + (*nextp)->next = (void *) -1l; + } + + *cu = *nextp == (void *) -1l ? NULL : *nextp; + return DWFL_E_NOERROR; +} + + +/* Intern the CU arange points to, if necessary. */ + +static Dwfl_Error +arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu) +{ + if (arange->cu == NULL) + { + const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange]; + Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu); + if (result != DWFL_E_NOERROR) + return result; + assert (arange->cu != NULL && arange->cu != (void *) -1l); + less_lazy (mod); /* Each arange with null ->cu counts once. */ + } + + *cu = arange->cu; + return DWFL_E_NOERROR; +} + +Dwfl_Error +internal_function_def +__libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu) +{ + struct dwfl_arange *arange; + return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu); +} diff --git a/libdwfl/dwfl_addrdie.c b/libdwfl/dwfl_addrdie.c new file mode 100644 index 00000000..4aba9c3e --- /dev/null +++ b/libdwfl/dwfl_addrdie.c @@ -0,0 +1,21 @@ +/* Fetch CU DIE from address. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +Dwarf_Die * +dwfl_addrdie (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Addr *bias) +{ + return INTUSE(dwfl_module_addrdie) (INTUSE(dwfl_addrmodule) (dwfl, addr), + addr, bias); +} diff --git a/libdwfl/dwfl_addrdwarf.c b/libdwfl/dwfl_addrdwarf.c new file mode 100644 index 00000000..33eaec62 --- /dev/null +++ b/libdwfl/dwfl_addrdwarf.c @@ -0,0 +1,22 @@ +/* Fetch libdw handle from address. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +Dwarf * +dwfl_addrdwarf (Dwfl *dwfl, Dwarf_Addr address, Dwarf_Addr *bias) +{ + return INTUSE(dwfl_module_getdwarf) (INTUSE(dwfl_addrmodule) (dwfl, address), + bias); +} +INTDEF (dwfl_addrdwarf) diff --git a/libdwfl/dwfl_addrmodule.c b/libdwfl/dwfl_addrmodule.c new file mode 100644 index 00000000..69aab57c --- /dev/null +++ b/libdwfl/dwfl_addrmodule.c @@ -0,0 +1,38 @@ +/* Find module containing address. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +Dwfl_Module * +dwfl_addrmodule (Dwfl *dwfl, Dwarf_Addr address) +{ + if (dwfl == NULL) + return NULL; + + /* Do binary search on the array indexed by module load address. */ + size_t l = 0, u = dwfl->nmodules; + while (l < u) + { + size_t idx = (l + u) / 2; + Dwfl_Module *m = dwfl->modules[idx]; + if (address < m->low_addr) + u = idx; + else if (address >= m->high_addr) + l = idx + 1; + else + return m; + } + + return NULL; +} +INTDEF (dwfl_addrmodule) diff --git a/libdwfl/dwfl_begin.c b/libdwfl/dwfl_begin.c new file mode 100644 index 00000000..e7130a4a --- /dev/null +++ b/libdwfl/dwfl_begin.c @@ -0,0 +1,33 @@ +/* Set up a session using libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +Dwfl * +dwfl_begin (const Dwfl_Callbacks *callbacks) +{ + if (elf_version (EV_CURRENT) == EV_NONE) + { + __libdwfl_seterrno (DWFL_E_LIBELF); + return NULL; + } + + Dwfl *dwfl = calloc (1, sizeof *dwfl); + if (dwfl == NULL) + __libdwfl_seterrno (DWFL_E_NOMEM); + else + dwfl->callbacks = callbacks; + + return dwfl; +} +INTDEF (dwfl_begin) diff --git a/libdwfl/dwfl_cumodule.c b/libdwfl/dwfl_cumodule.c new file mode 100644 index 00000000..69b5c0fb --- /dev/null +++ b/libdwfl/dwfl_cumodule.c @@ -0,0 +1,21 @@ +/* Find the module for a CU DIE previously returned by libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +Dwfl_Module * +dwfl_cumodule (Dwarf_Die *cudie) +{ + struct dwfl_cu *cu = (struct dwfl_cu *) cudie; + return cu->mod; +} diff --git a/libdwfl/dwfl_end.c b/libdwfl/dwfl_end.c new file mode 100644 index 00000000..b2836d30 --- /dev/null +++ b/libdwfl/dwfl_end.c @@ -0,0 +1,26 @@ +/* Finish a session using libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +void +dwfl_end (Dwfl *dwfl) +{ + if (dwfl != NULL) + { + for (size_t i = 0; i < dwfl->nmodules; ++i) + if (dwfl->modules[i] != NULL) + __libdwfl_module_free (dwfl->modules[i]); + free (dwfl->modules); + } +} diff --git a/libdwfl/dwfl_error.c b/libdwfl/dwfl_error.c new file mode 100644 index 00000000..4bd1a50f --- /dev/null +++ b/libdwfl/dwfl_error.c @@ -0,0 +1,222 @@ +/* Error handling in libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include "libdwflP.h" + + +#ifdef USE_TLS +/* The error number. */ +static __thread int global_error; +#else +/* This is the key for the thread specific memory. */ +static tls_key_t key; + +/* The error number. Used in non-threaded programs. */ +static int global_error; +static bool threaded; +/* We need to initialize the thread-specific data. */ +once_define (static, once); + +/* The initialization and destruction functions. */ +static void init (void); +static void free_key_mem (void *mem); +#endif /* TLS */ + + +int +dwfl_errno (void) +{ + int result; + +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if (threaded) + { + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + result = (intptr_t) getspecific (key); + + setspecific (key, (void *) (intptr_t) DWFL_E_NOERROR); + return result; + } +#endif /* TLS */ + + result = global_error; + global_error = DWFL_E_NOERROR; + return result; +} + + +static const struct msgtable +{ +#define DWFL_ERROR(name, text) char msg_##name[sizeof text]; + DWFL_ERRORS +#undef DWFL_ERROR +} msgtable = + { +#define DWFL_ERROR(name, text) text, + DWFL_ERRORS +#undef DWFL_ERROR + }; +#define msgstr (&msgtable.msg_NOERROR[0]) + +static const uint_fast16_t msgidx[] = +{ +#define DWFL_ERROR(name, text) \ + [DWFL_E_##name] = offsetof (struct msgtable, msg_##name), + DWFL_ERRORS +#undef DWFL_ERROR +}; +#define nmsgidx (sizeof msgidx / sizeof msgidx[0]) + + +static inline int +canonicalize (Dwfl_Error error) +{ + unsigned int value; + + switch (error) + { + default: + value = error; + if ((value &~ 0xffff) != 0) + break; + assert (value < nmsgidx); + break; + case DWFL_E_ERRNO: + value = DWFL_E (ERRNO, errno); + break; + case DWFL_E_LIBELF: + value = DWFL_E (LIBELF, elf_errno ()); + break; + case DWFL_E_LIBDW: + value = DWFL_E (LIBDW, dwarf_errno ()); + break; +#if 0 + DWFL_E_LIBEBL: + value = DWFL_E (LIBEBL, ebl_errno ()); + break; +#endif + } + + return value; +} + +int +internal_function_def +__libdwfl_canon_error (Dwfl_Error error) +{ + return canonicalize (error); +} + +void +internal_function_def +__libdwfl_seterrno (Dwfl_Error error) +{ + int value = canonicalize (error); + +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if (threaded) + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + setspecific (key, (void *) (intptr_t) value); +#endif /* TLS */ + + global_error = value; +} + + +const char * +dwfl_errmsg (error) + int error; +{ + if (error == 0 || error == -1) + { + int last_error; + +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if (threaded) + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + last_error = (intptr_t) getspecific (key); + else +#endif /* TLS */ + last_error = global_error; + + if (error == 0 && last_error == 0) + return NULL; + + error = last_error; + global_error = DWFL_E_NOERROR; + } + + switch (error &~ 0xffff) + { + case OTHER_ERROR (ERRNO): + return strerror_r (error & 0xffff, "bad", 0); + case OTHER_ERROR (LIBELF): + return elf_errmsg (error & 0xffff); + case OTHER_ERROR (LIBDW): + return dwarf_errmsg (error & 0xffff); +#if 0 + case OTHER_ERROR (LIBEBL): + return ebl_errmsg (error & 0xffff); +#endif + } + + return _(&msgstr[msgidx[(unsigned int) error < nmsgidx + ? error : DWFL_E_UNKNOWN_ERROR]]); +} +INTDEF (dwfl_errmsg) + + +#ifndef USE_TLS +/* Free the thread specific data, this is done if a thread terminates. */ +static void +free_key_mem (void *mem __attribute__ ((unused))) +{ + setspecific (key, NULL); +} + + +/* Initialize the key for the global variable. */ +static void +init (void) +{ + // XXX Screw you, gcc4, the unused function attribute does not work. + __asm ("" :: "r" (free_key_mem)); + + if (key_create (&key, free_key_mem) == 0) + /* Creating the key succeeded. */ + threaded = true; +} +#endif /* TLS */ diff --git a/libdwfl/dwfl_getdwarf.c b/libdwfl/dwfl_getdwarf.c new file mode 100644 index 00000000..cae49dab --- /dev/null +++ b/libdwfl/dwfl_getdwarf.c @@ -0,0 +1,40 @@ +/* Iterate through modules to fetch Dwarf information. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +ptrdiff_t +dwfl_getdwarf (Dwfl *dwfl, + int (*callback) (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + Dwarf *, Dwarf_Addr, void *), + void *arg, + ptrdiff_t offset) +{ + if (dwfl == NULL) + return -1; + + if ((size_t) offset > dwfl->nmodules) + return -1; + + while ((size_t) offset < dwfl->nmodules) + { + Dwfl_Module *mod = dwfl->modules[offset++]; + Dwarf_Addr bias = 0; + Dwarf *dw = INTUSE(dwfl_module_getdwarf) (mod, &bias); + if ((*callback) (MODCB_ARGS (mod), dw, bias, arg) != DWARF_CB_OK) + return offset; + } + + return 0; +} diff --git a/libdwfl/dwfl_getmodules.c b/libdwfl/dwfl_getmodules.c new file mode 100644 index 00000000..4fc14880 --- /dev/null +++ b/libdwfl/dwfl_getmodules.c @@ -0,0 +1,37 @@ +/* Iterate through modules. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +ptrdiff_t +dwfl_getmodules (Dwfl *dwfl, + int (*callback) (Dwfl_Module *, void **, + const char *, Dwarf_Addr, void *), + void *arg, + ptrdiff_t offset) +{ + if (dwfl == NULL) + return -1; + + if ((size_t) offset > dwfl->nmodules) + return -1; + + while ((size_t) offset < dwfl->nmodules) + { + Dwfl_Module *mod = dwfl->modules[offset++]; + if ((*callback) (MODCB_ARGS (mod), arg) != DWARF_CB_OK) + return offset; + } + + return 0; +} diff --git a/libdwfl/dwfl_getsrc.c b/libdwfl/dwfl_getsrc.c new file mode 100644 index 00000000..3ceb6329 --- /dev/null +++ b/libdwfl/dwfl_getsrc.c @@ -0,0 +1,21 @@ +/* Find source location for PC address. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +Dwfl_Line * +dwfl_getsrc (Dwfl *dwfl, Dwarf_Addr addr) +{ + return INTUSE(dwfl_module_getsrc) (INTUSE(dwfl_addrmodule) (dwfl, addr), + addr); +} diff --git a/libdwfl/dwfl_lineinfo.c b/libdwfl/dwfl_lineinfo.c new file mode 100644 index 00000000..4771e003 --- /dev/null +++ b/libdwfl/dwfl_lineinfo.c @@ -0,0 +1,40 @@ +/* Get information from a source line record returned by libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" +#include "../libdw/libdwP.h" + +extern const char * +dwfl_lineinfo (Dwfl_Line *line, Dwarf_Addr *addr, int *linep, int *colp, + Dwarf_Word *mtime, Dwarf_Word *length) +{ + if (line == NULL) + return NULL; + + struct dwfl_cu *cu = dwfl_linecu (line); + const Dwarf_Line *info = &cu->die.cu->lines->info[line->idx]; + + if (addr != NULL) + *addr = info->addr - cu->mod->debug.bias; + if (linep != NULL) + *linep = info->line; + if (colp != NULL) + *colp = info->column; + + struct Dwarf_Fileinfo_s *file = &info->files->info[info->file]; + if (mtime != NULL) + *mtime = file->mtime; + if (length != NULL) + *length = file->length; + return file->name; +} diff --git a/libdwfl/dwfl_linemodule.c b/libdwfl/dwfl_linemodule.c new file mode 100644 index 00000000..233dbd41 --- /dev/null +++ b/libdwfl/dwfl_linemodule.c @@ -0,0 +1,23 @@ +/* Fetch the module containing a source line record returned by libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +Dwfl_Module * +dwfl_linemodule (Dwfl_Line *line) +{ + if (line == NULL) + return NULL; + + return dwfl_linecu (line)->mod; +} diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c new file mode 100644 index 00000000..a6d9f41f --- /dev/null +++ b/libdwfl/dwfl_module.c @@ -0,0 +1,188 @@ +/* Maintenance of module list in libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" +#include + +static void +free_cu (struct dwfl_cu *cu) +{ + if (cu->lines != NULL) + free (cu->lines); + free (cu); +} + +static void +nofree (void *arg __attribute__ ((unused))) +{ +} + +void +internal_function_def +__libdwfl_module_free (Dwfl_Module *mod) +{ + if (mod->lazy_cu_root != NULL) + tdestroy (mod->lazy_cu_root, nofree); + + if (mod->aranges != NULL) + free (mod->aranges); + + if (mod->cu != NULL) + { + for (size_t i = 0; i < mod->ncu; ++i) + free_cu (mod->cu[i]); + free (mod->cu); + } + + if (mod->dw != NULL) + dwarf_end (mod->dw); + + if (mod->ebl != NULL) + ebl_closebackend (mod->ebl); + + if (mod->debug.elf != mod->main.elf && mod->debug.elf != NULL) + elf_end (mod->debug.elf); + if (mod->main.elf != NULL) + elf_end (mod->main.elf); + + free (mod->name); +} + +void +dwfl_report_begin (Dwfl *dwfl) +{ + for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next) + m->gc = true; + + if (dwfl->modules != NULL) + free (dwfl->modules); + dwfl->modules = NULL; + dwfl->nmodules = 0; +} +INTDEF (dwfl_report_begin) + +/* Report that a module called NAME pans addresses [START, END). + Returns the module handle, either existing or newly allocated, + or returns a null pointer for an allocation error. */ +Dwfl_Module * +dwfl_report_module (Dwfl *dwfl, const char *name, + GElf_Addr start, GElf_Addr end) +{ + Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp; + for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next)) + { + if (m->low_addr == start && m->high_addr == end + && !strcmp (m->name, name)) + { + /* This module is still here. Move it to the place in the list + after the last module already reported. */ + + *prevp = m->next; + m->next = *tailp; + m->gc = false; + *tailp = m; + return m; + } + + if (! m->gc) + tailp = &m->next; + } + + Dwfl_Module *mod = calloc (1, sizeof *mod); + if (mod == NULL) + goto nomem; + + mod->name = strdup (name); + if (mod->name == NULL) + { + free (mod); + nomem: + __libdwfl_seterrno (DWFL_E_NOMEM); + return NULL; + } + + mod->low_addr = start; + mod->high_addr = end; + mod->dwfl = dwfl; + + mod->next = *tailp; + *tailp = mod; + ++dwfl->nmodules; + + return mod; +} +INTDEF (dwfl_report_module) + +static int +compare_modules (const void *a, const void *b) +{ + Dwfl_Module *const *p1 = a, *const *p2 = b; + const Dwfl_Module *m1 = *p1, *m2 = *p2; + if (m1 == NULL) + return -1; + if (m2 == NULL) + return 1; + return (GElf_Sxword) (m1->low_addr - m2->low_addr); +} + + +/* Finish reporting the current set of modules to the library. + If REMOVED is not null, it's called for each module that + existed before but was not included in the current report. + Returns a nonzero return value from the callback. + DWFL cannot be used until this function has returned zero. */ +int dwfl_report_end (Dwfl *dwfl, + int (*removed) (Dwfl_Module *, void *, + const char *, Dwarf_Addr, + void *arg), + void *arg) +{ + assert (dwfl->modules == NULL); + + Dwfl_Module **tailp = &dwfl->modulelist; + while (*tailp != NULL) + { + Dwfl_Module *m = *tailp; + if (m->gc && removed != NULL) + { + int result = (*removed) (MODCB_ARGS (m), arg); + if (result != 0) + return result; + } + if (m->gc) + { + *tailp = m->next; + __libdwfl_module_free (m); + } + else + tailp = &m->next; + } + + dwfl->modules = malloc (dwfl->nmodules * sizeof dwfl->modules[0]); + if (dwfl->modules == NULL && dwfl->nmodules != 0) + return -1; + + size_t i = 0; + for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next) + { + assert (! m->gc); + dwfl->modules[i++] = m; + } + assert (i == dwfl->nmodules); + + qsort (dwfl->modules, dwfl->nmodules, sizeof dwfl->modules[0], + &compare_modules); + + return 0; +} +INTDEF (dwfl_report_end) diff --git a/libdwfl/dwfl_module_addrdie.c b/libdwfl/dwfl_module_addrdie.c new file mode 100644 index 00000000..29e2dfe8 --- /dev/null +++ b/libdwfl/dwfl_module_addrdie.c @@ -0,0 +1,30 @@ +/* Fetch the CU DIE for a PC address in a given module. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +Dwarf_Die * +dwfl_module_addrdie (Dwfl_Module *mod, Dwarf_Addr addr, Dwarf_Addr *bias) +{ + if (INTUSE(dwfl_module_getdwarf) (mod, bias) == NULL) + return NULL; + + struct dwfl_cu *cu; + Dwfl_Error error = __libdwfl_addrcu (mod, addr, &cu); + if (likely (error == DWFL_E_NOERROR)) + return &cu->die; + + __libdwfl_seterrno (error); + return NULL; +} +INTDEF (dwfl_module_addrdie) diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c new file mode 100644 index 00000000..03cf8f05 --- /dev/null +++ b/libdwfl/dwfl_module_getdwarf.c @@ -0,0 +1,480 @@ +/* Find debugging and symbol information for a module in libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" +#include +#include +#include "../libdw/libdwP.h" /* DWARF_E_* values are here. */ + + +/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD. + When we return success, FILE->elf and FILE->bias are set up. */ +static inline Dwfl_Error +open_elf (Dwfl_Module *mod, struct dwfl_file *file) +{ + if (file->elf == NULL) + { + if (file->fd < 0) + return CBFAIL; + + file->elf = elf_begin (file->fd, ELF_C_READ_MMAP_PRIVATE, NULL); + } + + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem); + if (ehdr == NULL) + return DWFL_E (LIBELF, elf_errno ()); + + mod->isrel = ehdr->e_type == ET_REL; + + file->bias = 0; + for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i) + { + GElf_Phdr ph_mem; + GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem); + if (ph == NULL) + return DWFL_E_LIBELF; + if (ph->p_type == PT_LOAD) + { + file->bias = ((mod->low_addr & -ph->p_align) + - (ph->p_vaddr & -ph->p_align)); + break; + } + } + + return DWFL_E_NOERROR; +} + +/* Find the main ELF file for this module and open libelf on it. + When we return success, MOD->main.elf and MOD->main.bias are set up. */ +static void +find_file (Dwfl_Module *mod) +{ + if (mod->main.elf != NULL /* Already done. */ + || mod->elferr != DWFL_E_NOERROR) /* Cached failure. */ + return; + + mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod), + &mod->main.name, + &mod->main.elf); + mod->elferr = open_elf (mod, &mod->main); +} + +/* Find the separate debuginfo file for this module and open libelf on it. + When we return success, MOD->debug is set up. */ +static Dwfl_Error +find_debuginfo (Dwfl_Module *mod) +{ + size_t shstrndx; + if (elf_getshstrndx (mod->main.elf, &shstrndx) < 0) + return DWFL_E_LIBELF; + + Elf_Scn *scn = elf_getscn (mod->main.elf, 0); + if (scn == NULL) + return DWFL_E_LIBELF; + do + { + GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + return DWFL_E_LIBELF; + + const char *name = elf_strptr (mod->main.elf, shstrndx, shdr->sh_name); + if (name == NULL) + return DWFL_E_LIBELF; + + if (!strcmp (name, ".gnu_debuglink")) + break; + + scn = elf_nextscn (mod->main.elf, scn); + } while (scn != NULL); + + const char *debuglink_file = NULL; + GElf_Word debuglink_crc = 0; + if (scn != NULL) + { + /* Found the .gnu_debuglink section. Extract its contents. */ + Elf_Data *rawdata = elf_rawdata (scn, NULL); + if (rawdata == NULL) + return DWFL_E_LIBELF; + + Elf_Data crcdata = + { + .d_type = ELF_T_WORD, + .d_buf = &debuglink_crc, + .d_size = sizeof debuglink_crc, + .d_version = EV_CURRENT, + }; + Elf_Data conv = + { + .d_type = ELF_T_WORD, + .d_buf = rawdata->d_buf + rawdata->d_size - sizeof debuglink_crc, + .d_size = sizeof debuglink_crc, + .d_version = EV_CURRENT, + }; + + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem); + if (ehdr == NULL) + return DWFL_E_LIBELF; + + Elf_Data *d = gelf_xlatetom (mod->main.elf, &crcdata, &conv, + ehdr->e_ident[EI_DATA]); + if (d == NULL) + return DWFL_E_LIBELF; + assert (d == &crcdata); + + debuglink_file = rawdata->d_buf; + } + + mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod), + mod->main.name, + debuglink_file, + debuglink_crc, + &mod->debug.name); + return open_elf (mod, &mod->debug); +} + + +/* Try to find a symbol table in FILE. */ +static Dwfl_Error +load_symtab (struct dwfl_file *file, struct dwfl_file **symfile, + Elf_Scn **symscn, Elf_Scn **xndxscn, + size_t *syments, GElf_Word *strshndx) +{ + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (file->elf, scn)) != NULL) + { + GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr != NULL) + switch (shdr->sh_type) + { + case SHT_SYMTAB: + *symscn = scn; + *symfile = file; + *strshndx = shdr->sh_link; + *syments = shdr->sh_size / shdr->sh_entsize; + if (*symscn != NULL && *xndxscn != NULL) + return DWFL_E_NOERROR; + break; + + case SHT_DYNSYM: + /* Use this if need be, but keep looking for SHT_SYMTAB. */ + *symscn = scn; + *symfile = file; + *strshndx = shdr->sh_link; + *syments = shdr->sh_size / shdr->sh_entsize; + break; + + case SHT_SYMTAB_SHNDX: + *xndxscn = scn; + break; + + default: + break; + } + } + return DWFL_E_NO_SYMTAB; +} + +/* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf. */ +static void +find_symtab (Dwfl_Module *mod) +{ + if (mod->symdata != NULL /* Already done. */ + || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure. */ + return; + + find_file (mod); + mod->symerr = mod->elferr; + if (mod->symerr != DWFL_E_NOERROR) + return; + + /* First see if the main ELF file has the debugging information. */ + Elf_Scn *symscn = NULL, *xndxscn = NULL; + GElf_Word strshndx; + mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn, + &xndxscn, &mod->syments, &strshndx); + switch (mod->symerr) + { + default: + return; + + case DWFL_E_NOERROR: + break; + + case DWFL_E_NO_SYMTAB: + /* Now we have to look for a separate debuginfo file. */ + mod->symerr = find_debuginfo (mod); + switch (mod->symerr) + { + default: + return; + + case DWFL_E_NOERROR: + mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn, + &xndxscn, &mod->syments, &strshndx); + break; + + case DWFL_E_CB: /* The find_debuginfo hook failed. */ + mod->symerr = DWFL_E_NO_SYMTAB; + break; + } + + switch (mod->symerr) + { + default: + return; + + case DWFL_E_NOERROR: + break; + + case DWFL_E_NO_SYMTAB: + if (symscn == NULL) + return; + /* We still have the dynamic symbol table. */ + mod->symerr = DWFL_E_NOERROR; + break; + } + break; + } + + /* This does some sanity checks on the string table section. */ + if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL) + { + elferr: + mod->symerr = DWFL_E (LIBELF, elf_errno ()); + return; + } + + /* Cache the data; MOD->syments was set above. */ + + mod->symstrdata = elf_rawdata (elf_getscn (mod->symfile->elf, strshndx), + NULL); + if (mod->symstrdata == NULL) + goto elferr; + + if (xndxscn == NULL) + mod->symxndxdata = NULL; + else + { + mod->symxndxdata = elf_rawdata (xndxscn, NULL); + if (mod->symxndxdata == NULL) + goto elferr; + } + + mod->symdata = elf_rawdata (symscn, NULL); + if (mod->symdata == NULL) + goto elferr; +} + + +/* Try to start up libdw on DEBUGFILE. */ +static Dwfl_Error +load_dw (Dwfl_Module *mod, Elf *debugfile) +{ + if (mod->isrel) + { + const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; + + /* The debugging sections have to be relocated. */ + if (cb->section_address == NULL) + return DWFL_E_NOREL; + + if (mod->ebl == NULL) + { + mod->ebl = ebl_openbackend (mod->main.elf); + if (mod->ebl == NULL) + return DWFL_E_LIBEBL; + } + + find_symtab (mod); + Dwfl_Error result = mod->symerr; + if (result == DWFL_E_NOERROR) + result = __libdwfl_relocate (mod); + if (result != DWFL_E_NOERROR) + return result; + } + + mod->dw = dwarf_begin_elf (debugfile, DWARF_C_READ, NULL); + if (mod->dw == NULL) + { + int err = dwarf_errno (); + return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err); + } + + /* Until we have iterated through all CU's, we might do lazy lookups. */ + mod->lazycu = 1; + + return DWFL_E_NOERROR; +} + +/* Try to start up libdw on either the main file or the debuginfo file. */ +static void +find_dw (Dwfl_Module *mod) +{ + if (mod->dw != NULL /* Already done. */ + || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure. */ + return; + + find_file (mod); + mod->dwerr = mod->elferr; + if (mod->dwerr != DWFL_E_NOERROR) + return; + + /* First see if the main ELF file has the debugging information. */ + mod->dwerr = load_dw (mod, mod->main.elf); + switch (mod->dwerr) + { + case DWFL_E_NOERROR: + mod->debug.elf = mod->main.elf; + mod->debug.bias = mod->main.bias; + return; + + case DWFL_E_NO_DWARF: + break; + + default: + goto canonicalize; + } + + /* Now we have to look for a separate debuginfo file. */ + mod->dwerr = find_debuginfo (mod); + switch (mod->dwerr) + { + case DWFL_E_NOERROR: + mod->dwerr = load_dw (mod, mod->debug.elf); + break; + + case DWFL_E_CB: /* The find_debuginfo hook failed. */ + mod->dwerr = DWFL_E_NO_DWARF; + return; + + default: + break; + } + + canonicalize: + mod->dwerr = __libdwfl_canon_error (mod->dwerr); +} + + +Elf * +dwfl_module_getelf (Dwfl_Module *mod, GElf_Addr *loadbase) +{ + if (mod == NULL) + return NULL; + + find_file (mod); + if (mod->elferr == DWFL_E_NOERROR) + { + *loadbase = mod->main.bias; + return mod->main.elf; + } + + __libdwfl_seterrno (mod->elferr); + return NULL; +} +INTDEF (dwfl_module_getelf) + + +Dwarf * +dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias) +{ + if (mod == NULL) + return NULL; + + find_dw (mod); + if (mod->dwerr == DWFL_E_NOERROR) + { + *bias = mod->debug.bias; + return mod->dw; + } + + __libdwfl_seterrno (mod->dwerr); + return NULL; +} +INTDEF (dwfl_module_getdwarf) + + +const char * +dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr addr) +{ + if (mod == NULL) + return NULL; + + find_symtab (mod); + if (mod->symerr != DWFL_E_NOERROR) + { + __libdwfl_seterrno (mod->symerr); + return NULL; + } + + addr -= mod->symfile->bias; + + /* Look through the symbol table for a matching symbol. */ + size_t symshstrndx = SHN_UNDEF; + for (size_t i = 1; i < mod->syments; ++i) + { + GElf_Sym sym_mem; + GElf_Word shndx; + GElf_Sym *sym = gelf_getsymshndx (mod->symdata, mod->symxndxdata, + i, &sym_mem, &shndx); + if (sym != NULL) + { + GElf_Addr symaddr = sym->st_value; + + if (sym->st_shndx != SHN_XINDEX) + shndx = sym->st_shndx; + + if (mod->isrel) + /* In an ET_REL file, the symbol table values are relative + to the section, not to the module's load base. */ + switch (shndx) + { + case SHN_UNDEF: /* Undefined symbol can't match an address. */ + case SHN_COMMON: /* Nor can a common defn. */ + continue; + + case SHN_ABS: /* Symbol value is already absolute. */ + break; + + default: + { + Dwfl_Error result = DWFL_E_LIBELF; + if (likely (symshstrndx != SHN_UNDEF) + || elf_getshstrndx (mod->symfile->elf, + &symshstrndx) == 0) + result = __libdwfl_relocate_value (mod, symshstrndx, + shndx, &symaddr); + if (unlikely (result != DWFL_E_NOERROR)) + { + __libdwfl_seterrno (result); + return NULL; + } + break; + } + } + + if (symaddr <= addr && addr < symaddr + sym->st_size) + { + if (unlikely (sym->st_name >= mod->symstrdata->d_size)) + { + __libdwfl_seterrno (DWFL_E_BADSTROFF); + return NULL; + } + return (const char *) mod->symstrdata->d_buf + sym->st_name; + } + } + } + + return NULL; +} diff --git a/libdwfl/dwfl_module_getsrc.c b/libdwfl/dwfl_module_getsrc.c new file mode 100644 index 00000000..3b341b92 --- /dev/null +++ b/libdwfl/dwfl_module_getsrc.c @@ -0,0 +1,60 @@ +/* Find source location for PC address in module. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" +#include "../libdw/libdwP.h" + +Dwfl_Line * +dwfl_module_getsrc (Dwfl_Module *mod, Dwarf_Addr addr) +{ + Dwarf_Addr bias; + if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL) + return NULL; + + struct dwfl_cu *cu; + Dwfl_Error error = __libdwfl_addrcu (mod, addr, &cu); + if (likely (error == DWFL_E_NOERROR)) + error = __libdwfl_cu_getsrclines (cu); + if (likely (error == DWFL_E_NOERROR)) + { + /* The lines are sorted by address, so we can use binary search. */ + size_t l = 0, u = cu->die.cu->lines->nlines; + while (l < u) + { + size_t idx = (l + u) / 2; + if (addr < cu->die.cu->lines->info[idx].addr) + u = idx; + else if (addr > cu->die.cu->lines->info[idx].addr) + l = idx + 1; + else + return &cu->lines->idx[idx]; + } + + if (cu->die.cu->lines->nlines > 0) + assert (cu->die.cu->lines->info + [cu->die.cu->lines->nlines - 1].end_sequence); + + /* If none were equal, the closest one below is what we want. + We never want the last one, because it's the end-sequence + marker with an address at the high bound of the CU's code. */ + if (u > 0 && u < cu->die.cu->lines->nlines + && addr > cu->die.cu->lines->info[u - 1].addr) + return &cu->lines->idx[u - 1]; + + error = DWFL_E_ADDR_OUTOFRANGE; + } + + __libdwfl_seterrno (error); + return NULL; +} +INTDEF (dwfl_module_getsrc) diff --git a/libdwfl/dwfl_module_getsrc_file.c b/libdwfl/dwfl_module_getsrc_file.c new file mode 100644 index 00000000..81f57ed6 --- /dev/null +++ b/libdwfl/dwfl_module_getsrc_file.c @@ -0,0 +1,144 @@ +/* Find matching source locations in a module. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" +#include "../libdw/libdwP.h" + + +int +dwfl_module_getsrc_file (Dwfl_Module *mod, + const char *fname, int lineno, int column, + Dwfl_Line ***srcsp, size_t *nsrcs) +{ + if (mod == NULL) + return -1; + + bool is_basename = strchr (fname, '/') == NULL; + + size_t max_match = *nsrcs ?: ~0u; + size_t act_match = *nsrcs; + size_t cur_match = 0; + Dwfl_Line **match = *nsrcs == 0 ? NULL : *srcsp; + + struct dwfl_cu *cu = NULL; + Dwfl_Error error; + while ((error = __libdwfl_nextcu (mod, cu, &cu)) == DWFL_E_NOERROR + && cu != NULL + && (error = __libdwfl_cu_getsrclines (cu)) == DWFL_E_NOERROR) + { + inline const char *dwarf_line_file (const Dwarf_Line *line) + { + return line->files->info[line->file].name; + } + inline Dwarf_Line *dwfl_line (const Dwfl_Line *line) + { + return &dwfl_linecu (line)->die.cu->lines->info[line->idx]; + } + inline const char *dwfl_line_file (const Dwfl_Line *line) + { + return dwarf_line_file (dwfl_line (line)); + } + + /* Search through all the line number records for a matching + file and line/column number. If any of the numbers is zero, + no match is performed. */ + const char *lastfile = NULL; + bool lastmatch = false; + for (size_t cnt = 0; cnt < cu->die.cu->lines->nlines; ++cnt) + { + Dwarf_Line *line = &cu->die.cu->lines->info[cnt]; + + if (unlikely (line->file >= line->files->nfiles)) + { + __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF)); + return -1; + } + else + { + const char *file = dwarf_line_file (line); + if (file != lastfile) + { + /* Match the name with the name the user provided. */ + lastfile = file; + lastmatch = !strcmp (is_basename ? basename (file) : file, + fname); + } + } + if (!lastmatch) + continue; + + /* See whether line and possibly column match. */ + if (lineno != 0 + && (lineno > line->line + || (column != 0 && column > line->column))) + /* Cannot match. */ + continue; + + /* Determine whether this is the best match so far. */ + size_t inner; + for (inner = 0; inner < cur_match; ++inner) + if (dwfl_line_file (match[inner]) == dwarf_line_file (line)) + break; + if (inner < cur_match + && (dwfl_line (match[inner])->line != line->line + || dwfl_line (match[inner])->line != lineno + || (column != 0 + && (dwfl_line (match[inner])->column != line->column + || dwfl_line (match[inner])->column != column)))) + { + /* We know about this file already. If this is a better + match for the line number, use it. */ + if (dwfl_line (match[inner])->line >= line->line + && (dwfl_line (match[inner])->line != line->line + || dwfl_line (match[inner])->column >= line->column)) + /* Use the new line. Otherwise the old one. */ + match[inner] = &cu->lines->idx[cnt]; + continue; + } + + if (cur_match < max_match) + { + if (cur_match == act_match) + { + /* Enlarge the array for the results. */ + act_match += 10; + Dwfl_Line **newp = realloc (match, + act_match + * sizeof (Dwfl_Line *)); + if (newp == NULL) + { + free (match); + __libdwfl_seterrno (DWFL_E_NOMEM); + return -1; + } + match = newp; + } + + match[cur_match++] = &cu->lines->idx[cnt]; + } + } + } + + if (cur_match > 0) + { + assert (*nsrcs == 0 || *srcsp == match); + + *nsrcs = cur_match; + *srcsp = match; + + return 0; + } + + __libdwfl_seterrno (DWFL_E_NO_MATCH); + return -1; +} diff --git a/libdwfl/dwfl_module_info.c b/libdwfl/dwfl_module_info.c new file mode 100644 index 00000000..e8c27b9d --- /dev/null +++ b/libdwfl/dwfl_module_info.c @@ -0,0 +1,44 @@ +/* Return information about a module. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +const char * +dwfl_module_info (Dwfl_Module *mod, void ***userdata, + Dwarf_Addr *start, Dwarf_Addr *end, + Dwarf_Addr *dwbias, Dwarf_Addr *symbias, + const char **mainfile, const char **debugfile) +{ + if (mod == NULL) + return NULL; + + if (userdata) + *userdata = &mod->userdata; + if (start) + *start = mod->low_addr; + if (end) + *end = mod->high_addr; + + if (dwbias) + *dwbias = mod->debug.elf == NULL ? (Dwarf_Addr) -1 : mod->debug.bias; + if (symbias) + *symbias = mod->symfile == NULL ? (Dwarf_Addr) -1 : mod->symfile->bias; + + if (mainfile) + *mainfile = mod->main.name; + + if (debugfile) + *debugfile = mod->debug.name; + + return mod->name; +} diff --git a/libdwfl/dwfl_module_nextcu.c b/libdwfl/dwfl_module_nextcu.c new file mode 100644 index 00000000..c089047f --- /dev/null +++ b/libdwfl/dwfl_module_nextcu.c @@ -0,0 +1,29 @@ +/* Iterate through DWARF compilation units in a module. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +Dwarf_Die * +dwfl_module_nextcu (Dwfl_Module *mod, Dwarf_Die *lastcu, Dwarf_Addr *bias) +{ + if (INTUSE(dwfl_module_getdwarf) (mod, bias) == NULL) + return NULL; + + struct dwfl_cu *cu; + Dwfl_Error error = __libdwfl_nextcu (mod, (struct dwfl_cu *) lastcu, &cu); + if (likely (error == DWFL_E_NOERROR)) + return &cu->die; /* Same as a cast, so ok for null too. */ + + __libdwfl_seterrno (error); + return NULL; +} diff --git a/libdwfl/dwfl_nextcu.c b/libdwfl/dwfl_nextcu.c new file mode 100644 index 00000000..a5565c69 --- /dev/null +++ b/libdwfl/dwfl_nextcu.c @@ -0,0 +1,52 @@ +/* Iterate through DWARF compilation units across all modules. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +Dwarf_Die * +dwfl_nextcu (Dwfl *dwfl, Dwarf_Die *lastcu, Dwarf_Addr *bias) +{ + if (dwfl == NULL) + return NULL; + + struct dwfl_cu *cu = (struct dwfl_cu *) lastcu; + Dwfl_Module *mod; + + if (cu == NULL) + { + mod = dwfl->modulelist; + goto nextmod; + } + else + mod = cu->mod; + + Dwfl_Error error; + while ((error = __libdwfl_nextcu (mod, cu, &cu)) == DWFL_E_NOERROR) + { + if (cu != NULL) + { + *bias = mod->debug.bias; + return &cu->die; + } + + mod = mod->next; + + nextmod: + if (mod == NULL || INTUSE(dwfl_module_getdwarf) (mod, bias) == NULL) + return NULL; + } + + __libdwfl_seterrno (error); + return NULL; +} +INTDEF (dwfl_nextcu) diff --git a/libdwfl/dwfl_report_elf.c b/libdwfl/dwfl_report_elf.c new file mode 100644 index 00000000..21c9e846 --- /dev/null +++ b/libdwfl/dwfl_report_elf.c @@ -0,0 +1,117 @@ +/* Report a module to libdwfl based on ELF program headers. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" +#include +#include + + +Dwfl_Module * +dwfl_report_elf (Dwfl *dwfl, const char *name, + const char *file_name, int fd, GElf_Addr base) +{ + bool closefd = false; + + if (fd < 0) + { + fd = open64 (file_name, O_RDONLY); + if (fd < 0) + { + __libdwfl_seterrno (DWFL_E_ERRNO); + return NULL; + } + closefd = true; + } + + Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL); + + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + elf_error: + __libdwfl_seterrno (DWFL_E_LIBELF); + if (closefd) + close (fd); + return NULL; + } + + GElf_Addr start = 0, end = 0; + for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i) + { + GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem); + if (ph == NULL) + goto elf_error; + if (ph->p_type == PT_LOAD) + { + start = base + (ph->p_vaddr & -ph->p_align); + break; + } + } + + for (uint_fast16_t i = ehdr->e_phnum; i-- > 0;) + { + GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem); + if (ph == NULL) + goto elf_error; + if (ph->p_type == PT_LOAD) + { + end = base + (ph->p_vaddr + ph->p_memsz); + break; + } + } + + if (end == 0) + { + __libdwfl_seterrno (DWFL_E_NO_PHDR); + if (closefd) + close (fd); + return NULL; + } + + Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name, + base + start, base + end); + if (m != NULL) + { + if (m->main.name == NULL) + { + m->main.name = strdup (file_name); + m->main.fd = fd; + } + else if ((fd >= 0 && m->main.fd != fd) + || strcmp (m->main.name, file_name)) + { + elf_end (elf); + overlap: + if (closefd) + close (fd); + m->gc = true; + __libdwfl_seterrno (DWFL_E_OVERLAP); + m = NULL; + } + + /* Preinstall the open ELF handle for the module. */ + if (m->main.elf == NULL) + { + m->main.elf = elf; + m->main.bias = base; + } + else + { + elf_end (elf); + if (m->main.bias != base) + goto overlap; + } + } + return m; +} +INTDEF (dwfl_report_elf) diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c new file mode 100644 index 00000000..3175ab16 --- /dev/null +++ b/libdwfl/elf-from-memory.c @@ -0,0 +1,328 @@ +/* Reconstruct an ELF file by reading the segments out of remote memory. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include "../libelf/libelfP.h" +#undef _ + +#include "libdwflP.h" + +#include +#include +#include +#include +#include + +/* Reconstruct an ELF file by reading the segments out of remote memory + based on the ELF file header at EHDR_VMA and the ELF program headers it + points to. If not null, *LOADBASEP is filled in with the difference + between the addresses from which the segments were read, and the + addresses the file headers put them at. + + The function READ_MEMORY is called to copy at least MINREAD and at most + MAXREAD bytes from the remote memory at target address ADDRESS into the + local buffer at DATA; it should return -1 for errors (with code in + `errno'), 0 if it failed to read at least MINREAD bytes due to EOF, or + the number of bytes read if >= MINREAD. ARG is passed through. */ + +Elf * +elf_from_remote_memory (GElf_Addr ehdr_vma, + GElf_Addr *loadbasep, + ssize_t (*read_memory) (void *arg, void *data, + GElf_Addr address, + size_t minread, + size_t maxread), + void *arg) +{ + /* First read in the file header and check its sanity. */ + + const size_t initial_bufsize = 256; + unsigned char *buffer = malloc (initial_bufsize); + if (buffer == NULL) + { + no_memory: + __libdwfl_seterrno (DWFL_E_NOMEM); + return NULL; + } + + ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma, + sizeof (Elf32_Ehdr), initial_bufsize); + if (nread <= 0) + { + read_error: + free (buffer); + __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED); + return NULL; + } + + if (memcmp (buffer, ELFMAG, SELFMAG) != 0) + { + bad_elf: + __libdwfl_seterrno (DWFL_E_BADELF); + return NULL; + } + + /* Extract the information we need from the file header. */ + + union + { + Elf32_Ehdr e32; + Elf64_Ehdr e64; + } ehdr; + Elf_Data xlatefrom = + { + .d_type = ELF_T_EHDR, + .d_buf = buffer, + .d_version = EV_CURRENT, + }; + Elf_Data xlateto = + { + .d_type = ELF_T_EHDR, + .d_buf = &ehdr, + .d_size = sizeof ehdr, + .d_version = EV_CURRENT, + }; + + GElf_Off phoff; + uint_fast16_t phnum; + uint_fast16_t phentsize; + GElf_Off shdrs_end; + + switch (buffer[EI_CLASS]) + { + case ELFCLASS32: + xlatefrom.d_size = sizeof (Elf32_Ehdr); + if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL) + { + libelf_error: + __libdwfl_seterrno (DWFL_E_LIBELF); + return NULL; + } + phoff = ehdr.e32.e_phoff; + phnum = ehdr.e32.e_phnum; + phentsize = ehdr.e32.e_phentsize; + if (phentsize != sizeof (Elf32_Phdr) || phnum == 0) + goto bad_elf; + shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize; + break; + + case ELFCLASS64: + xlatefrom.d_size = sizeof (Elf64_Ehdr); + if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL) + goto libelf_error; + phoff = ehdr.e64.e_phoff; + phnum = ehdr.e64.e_phnum; + phentsize = ehdr.e64.e_phentsize; + if (phentsize != sizeof (Elf64_Phdr) || phnum == 0) + goto bad_elf; + shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize; + break; + + default: + goto bad_elf; + } + + + /* The file header tells where to find the program headers. + These are what we use to actually choose what to read. */ + + xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR; + xlatefrom.d_size = phnum * phentsize; + + if ((size_t) nread >= phoff + phnum * phentsize) + /* We already have all the phdrs from the initial read. */ + xlatefrom.d_buf = buffer + phoff; + else + { + /* Read in the program headers. */ + + if (initial_bufsize < phnum * phentsize) + { + unsigned char *newbuf = realloc (buffer, phnum * phentsize); + if (newbuf == NULL) + { + free (buffer); + goto no_memory; + } + buffer = newbuf; + } + nread = (*read_memory) (arg, buffer, ehdr_vma + phoff, + phnum * phentsize, phnum * phentsize); + if (nread <= 0) + goto read_error; + + xlatefrom.d_buf = buffer; + } + + union + { + Elf32_Phdr p32[phnum]; + Elf64_Phdr p64[phnum]; + } phdrs; + + xlateto.d_buf = &phdrs; + xlateto.d_size = sizeof phdrs; + + /* Scan for PT_LOAD segments to find the total size of the file image. */ + size_t contents_size = 0; + GElf_Off segments_end = 0; + GElf_Addr loadbase = ehdr_vma; + switch (ehdr.e32.e_ident[EI_CLASS]) + { + inline void handle_segment (GElf_Addr vaddr, GElf_Off offset, + GElf_Xword filesz, GElf_Xword align) + { + GElf_Off segment_end = ((offset + filesz + align - 1) & -align); + + if (segment_end > (GElf_Off) contents_size) + contents_size = segment_end; + + if ((offset & -align) == 0 && loadbase == ehdr_vma) + loadbase = ehdr_vma - (vaddr & -align); + + segments_end = offset + filesz; + } + + case ELFCLASS32: + if (elf32_xlatetom (&xlateto, &xlatefrom, + ehdr.e32.e_ident[EI_DATA]) == NULL) + goto libelf_error; + for (uint_fast16_t i = 0; i < phnum; ++i) + if (phdrs.p32[i].p_type == PT_LOAD) + handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset, + phdrs.p32[i].p_filesz, phdrs.p32[i].p_align); + break; + + case ELFCLASS64: + if (elf32_xlatetom (&xlateto, &xlatefrom, + ehdr.e32.e_ident[EI_DATA]) == NULL) + goto libelf_error; + for (uint_fast16_t i = 0; i < phnum; ++i) + if (phdrs.p32[i].p_type == PT_LOAD) + handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset, + phdrs.p64[i].p_filesz, phdrs.p64[i].p_align); + break; + + default: + abort (); + break; + } + + /* Trim the last segment so we don't bother with zeros in the last page + that are off the end of the file. However, if the extra bit in that + page includes the section headers, keep them. */ + if ((GElf_Off) contents_size > segments_end + && (GElf_Off) contents_size >= shdrs_end) + { + contents_size = segments_end; + if ((GElf_Off) contents_size < shdrs_end) + contents_size = shdrs_end; + } + else + contents_size = segments_end; + + free (buffer); + + /* Now we know the size of the whole image we want read in. */ + buffer = calloc (1, contents_size); + if (buffer == NULL) + goto no_memory; + + switch (ehdr.e32.e_ident[EI_CLASS]) + { + inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset, + GElf_Xword filesz, GElf_Xword align) + { + GElf_Off start = offset & -align; + GElf_Off end = (offset + filesz + align - 1) & -align; + if (end > (GElf_Off) contents_size) + end = contents_size; + nread = (*read_memory) (arg, buffer + start, + (loadbase + vaddr) & -align, + end - start, end - start); + return nread <= 0; + } + + case ELFCLASS32: + for (uint_fast16_t i = 0; i < phnum; ++i) + if (phdrs.p32[i].p_type == PT_LOAD) + if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset, + phdrs.p32[i].p_filesz, phdrs.p32[i].p_align)) + goto read_error; + + /* If the segments visible in memory didn't include the section + headers, then clear them from the file header. */ + if (contents_size < shdrs_end) + { + ehdr.e32.e_shoff = 0; + ehdr.e32.e_shnum = 0; + ehdr.e32.e_shstrndx = 0; + } + + /* This will normally have been in the first PT_LOAD segment. But it + conceivably could be missing, and we might have just changed it. */ + xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR; + xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32; + xlatefrom.d_buf = &ehdr.e32; + xlateto.d_buf = buffer; + if (elf32_xlatetof (&xlateto, &xlatefrom, + ehdr.e32.e_ident[EI_DATA]) == NULL) + goto libelf_error; + break; + + case ELFCLASS64: + for (uint_fast16_t i = 0; i < phnum; ++i) + if (phdrs.p32[i].p_type == PT_LOAD) + if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset, + phdrs.p64[i].p_filesz, phdrs.p64[i].p_align)) + goto read_error; + + /* If the segments visible in memory didn't include the section + headers, then clear them from the file header. */ + if (contents_size < shdrs_end) + { + ehdr.e64.e_shoff = 0; + ehdr.e64.e_shnum = 0; + ehdr.e64.e_shstrndx = 0; + } + + /* This will normally have been in the first PT_LOAD segment. But it + conceivably could be missing, and we might have just changed it. */ + xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR; + xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64; + xlatefrom.d_buf = &ehdr.e64; + xlateto.d_buf = buffer; + if (elf32_xlatetof (&xlateto, &xlatefrom, + ehdr.e64.e_ident[EI_DATA]) == NULL) + goto libelf_error; + break; + + default: + abort (); + break; + } + + /* Now we have the image. Open libelf on it. */ + + Elf *elf = elf_memory ((char *) buffer, contents_size); + if (elf == NULL) + { + free (buffer); + return NULL; + } + + elf->flags |= ELF_F_MALLOCED; + if (loadbasep != NULL) + *loadbasep = loadbase; + return elf; +} diff --git a/libdwfl/find-debuginfo.c b/libdwfl/find-debuginfo.c new file mode 100644 index 00000000..c9e640dd --- /dev/null +++ b/libdwfl/find-debuginfo.c @@ -0,0 +1,157 @@ +/* Standard find_debuginfo callback for libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" +#include +#include +#include +#include "system.h" + + +#define DEFAULT_DEBUGINFO_PATH ":.debug:/usr/lib/debug" + + +/* Try to open64 [DIR/][SUBDIR/]DEBUGLINK, return file descriptor or -1. + On success, *DEBUGINFO_FILE_NAME has the malloc'd name of the open file. */ +static int +try_open (const char *dir, const char *subdir, const char *debuglink, + char **debuginfo_file_name) +{ + char *fname = NULL; + if (dir == NULL && subdir == NULL) + fname = strdup (debuglink); + else if (subdir == NULL) + asprintf (&fname, "%s/%s", dir, debuglink); + else if (dir == NULL) + asprintf (&fname, "%s/%s", subdir, debuglink); + else + asprintf (&fname, "%s/%s/%s", dir, subdir, debuglink); + + if (fname == NULL) + return -1; + + int fd = open64 (fname, O_RDONLY); + if (fd < 0) + free (fname); + else + *debuginfo_file_name = fname; + + return fd; +} + +/* Return true iff the FD's contents CRC matches DEBUGLINK_CRC. */ +static inline bool +check_crc (int fd, GElf_Word debuglink_crc) +{ + uint32_t file_crc; + return crc32_file (fd, &file_crc) == 0 && file_crc == debuglink_crc; +} + +int +dwfl_standard_find_debuginfo (Dwfl_Module *mod __attribute__ ((unused)), + void **userdata __attribute__ ((unused)), + const char *modname __attribute__ ((unused)), + GElf_Addr base __attribute__ ((unused)), + const char *file_name, + const char *debuglink_file, + GElf_Word debuglink_crc, + char **debuginfo_file_name) +{ + bool cancheck = true; + + const char *file_basename = file_name == NULL ? NULL : basename (file_name); + if (debuglink_file == NULL) + { + if (file_basename == NULL) + { + errno = 0; + return -1; + } + + size_t len = strlen (file_basename); + char *localname = alloca (len + sizeof ".debug"); + memcpy (localname, file_basename, len); + memcpy (&localname[len], ".debug", sizeof ".debug"); + debuglink_file = localname; + cancheck = false; + } + + /* Look for a file named DEBUGLINK_FILE in the directories + indicated by the debug directory path setting. */ + + const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; + char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL) + ?: DEFAULT_DEBUGINFO_PATH); + + /* A leading - or + in the whole path sets whether to check file CRCs. */ + bool defcheck = true; + if (path[0] == '-' || path[0] == '+') + { + defcheck = path[0] == '+'; + ++path; + } + + char *file_dirname = (file_basename == file_name ? NULL + : strndupa (file_name, file_basename - 1 - file_name)); + char *p; + while ((p = strsep (&path, ":")) != NULL) + { + /* A leading - or + says whether to check file CRCs for this element. */ + bool check = defcheck; + if (*p == '+' || *p == '-') + check = *p++ == '+'; + check = check && cancheck; + + const char *dir, *subdir; + switch (p[0]) + { + case '\0': + /* An empty entry says to try the main file's directory. */ + dir = file_dirname; + subdir = NULL; + break; + case '/': + /* An absolute path says to look there for a subdirectory + named by the main file's absolute directory. + This cannot be applied to a relative file name. */ + if (file_dirname == NULL || file_dirname[0] != '/') + continue; + dir = p; + subdir = file_dirname + 1; + break; + default: + /* A relative path says to try a subdirectory of that name + in the main file's directory. */ + dir = file_dirname; + subdir = p; + break; + } + + char *fname; + int fd = try_open (dir, subdir, debuglink_file, &fname); + if (fd < 0) + continue; + if (!check || check_crc (fd, debuglink_crc)) + { + *debuginfo_file_name = fname; + return fd; + } + free (fname); + close (fd); + } + + /* No dice. */ + errno = 0; + return -1; +} +INTDEF (dwfl_standard_find_debuginfo) diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h new file mode 100644 index 00000000..8fb9fdac --- /dev/null +++ b/libdwfl/libdwfl.h @@ -0,0 +1,262 @@ +/* Interfaces for libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBDWFL_H +#define _LIBDWFL_H 1 + +#include + +/* Handle for a session using the library. */ +typedef struct Dwfl Dwfl; + +/* Handle for a module. */ +typedef struct Dwfl_Module Dwfl_Module; + +/* Handle describing a line record. */ +typedef struct Dwfl_Line Dwfl_Line; + +/* Callbacks. */ +typedef struct +{ + int (*find_elf) (Dwfl_Module *mod, void **userdata, + const char *modname, Dwarf_Addr base, + char **file_name, Elf **elfp); + + int (*find_debuginfo) (Dwfl_Module *mod, void **userdata, + const char *modname, Dwarf_Addr base, + const char *file_name, + const char *debuglink_file, GElf_Word debuglink_crc, + char **debuginfo_file_name); + + /* Fill *ADDR with the loaded address of the + section called SECNAME in the given module. */ + int (*section_address) (Dwfl_Module *mod, void **userdata, + const char *modname, Dwarf_Addr base, + const char *secname, Dwarf_Addr *addr); + + char **debuginfo_path; /* See dwfl_standard_find_debuginfo. */ +} Dwfl_Callbacks; + + +/* Start a new session with the library. */ +Dwfl *dwfl_begin (const Dwfl_Callbacks *callbacks); + +/* End a session. */ +void dwfl_end (Dwfl *); + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int dwfl_errno (void); + +/* Return error string for ERROR. If ERROR is zero, return error string + for most recent error or NULL if none occurred. If ERROR is -1 the + behaviour is similar to the last case except that not NULL but a legal + string is returned. */ +extern const char *dwfl_errmsg (int err); + + +/* Start reporting the current set of modules to the library. No calls but + dwfl_report_module can be made on DWFL until dwfl_report_end is called. */ +extern void dwfl_report_begin (Dwfl *dwfl); + +/* Report that a module called NAME spans addresses [START, END). + Returns the module handle, either existing or newly allocated, + or returns a null pointer for an allocation error. */ +extern Dwfl_Module *dwfl_report_module (Dwfl *dwfl, const char *name, + Dwarf_Addr start, Dwarf_Addr end); + +/* Report a module with start and end addresses computed from the ELF + program headers in the given file, plus BASE. FD may be -1 to open + FILE_NAME. On success, FD is consumed by the library, and the + `find_elf' callback will not be used for this module. */ +extern Dwfl_Module *dwfl_report_elf (Dwfl *dwfl, const char *name, + const char *file_name, int fd, + GElf_Addr base); + +/* Finish reporting the current set of modules to the library. + If REMOVED is not null, it's called for each module that + existed before but was not included in the current report. + Returns a nonzero return value from the callback. + The callback may call dwfl_report_module; doing so with the + details of the module being removed prevents its removal. + DWFL cannot be used until this function has returned zero. */ +extern int dwfl_report_end (Dwfl *dwfl, + int (*removed) (Dwfl_Module *, void *, + const char *, Dwarf_Addr, + void *arg), + void *arg); + +/* Return the name of the module, and for each non-null argument store + interesting details: *USERDATA is a location for storing your own + pointer, **USERDATA is initially null; *START and *END give the address + range covered by the module; *DWBIAS is the address bias for debugging + information, and *SYMBIAS for symbol table entries (either is -1 if not + yet accessed); *MAINFILE is the name of the ELF file, and *DEBUGFILE the + name of the debuginfo file (might be equal to *MAINFILE; either is null + if not yet accessed). */ +extern const char *dwfl_module_info (Dwfl_Module *mod, void ***userdata, + Dwarf_Addr *start, Dwarf_Addr *end, + Dwarf_Addr *dwbias, Dwarf_Addr *symbias, + const char **mainfile, + const char **debugfile); + +/* Iterate through the modules, starting the walk with OFFSET == 0. + Calls *CALLBACK for each module as long as it returns DWARF_CB_OK. + When *CALLBACK returns another value, the walk stops and the + return value can be passed as OFFSET to resume it. Returns 0 when + there are no more modules, or -1 for errors. */ +extern ptrdiff_t dwfl_getmodules (Dwfl *dwfl, + int (*callback) (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + void *arg), + void *arg, + ptrdiff_t offset); + + +/*** Standard callbacks ***/ + +/* Standard find_debuginfo callback function. + This is controlled by a string specifying directories to look in. + If `debuginfo_path' is set in the Dwfl_Callbacks structure + and the char * it points to is not null, that supplies the string. + Otherwise a default path is used. + + If the first character of the string is + or - that says to check or to + ignore (respectively) the CRC32 checksum from the .gnu_debuglink + section. The default is to check it. The remainder of the string is + composed of elements separated by colons. Each element can start with + + or - to override the global checksum behavior. If the remainder of the + element is empty, the directory containing the main file is tried; if + it's an absolute path name, the absolute directory path containing the + main file is taken as a subdirectory of this path; a relative path name + is taken as a subdirectory of the directory containing the main file. + Hence for /bin/ls, string ":.debug:/usr/lib/debug" says to look in /bin, + then /bin/.debug, then /usr/lib/debug/bin, for the file name in the + .gnu_debuglink section (or "ls.debug" if none was found). */ + +extern int dwfl_standard_find_debuginfo (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + const char *, const char *, + GElf_Word, char **); + + +/* Callbacks for working with kernel modules in the running Linux kernel. */ +extern int dwfl_linux_kernel_find_elf (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + char **, Elf **); +extern int dwfl_linux_kernel_module_section_address (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + const char *, + Dwarf_Addr *addr); + +/* Call dwfl_report_elf for the running Linux kernel. + Returns zero on success, -1 if dwfl_report_module failed, + or an errno code if opening the kernel binary failed. */ +extern int dwfl_linux_kernel_report_kernel (Dwfl *dwfl); + +/* Call dwfl_report_module for each kernel module in the running Linux kernel. + Returns zero on success, -1 if dwfl_report_module failed, + or an errno code if reading the list of modules failed. */ +extern int dwfl_linux_kernel_report_modules (Dwfl *dwfl); + + +/* Call dwfl_report_module for each file mapped into the address space of PID. + Returns zero on success, -1 if dwfl_report_module failed, + or an errno code if opening the kernel binary failed. */ +int dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid); + +/* Trivial find_elf callback for use with dwfl_linux_proc_report. + This uses the module name as a file name directly and tries to open it + if it begin with a slash, or handles the magic string "[vdso]". */ +int dwfl_linux_proc_find_elf (Dwfl_Module *mod, void **userdata, + const char *module_name, Dwarf_Addr base, + char **file_name, Elf **); + +/* Standard argument parsing for using a standard callback set. */ +struct argp; +extern const struct argp *dwfl_standard_argp (void) __attribute__ ((const)); + + +/*** Dwarf access functions ***/ + +/* Find the module containing the given address. */ +extern Dwfl_Module *dwfl_addrmodule (Dwfl *dwfl, Dwarf_Addr address); + +/* Fetch the module main ELF file (where the allocated sections + are found) for use with libelf. If successful, fills in *BIAS + with the difference between addresses within the loaded module + and those in symbol tables or Dwarf information referring to it. */ +extern Elf *dwfl_module_getelf (Dwfl_Module *, GElf_Addr *bias); + +/* Fetch the module's debug information for use with libdw. + If successful, fills in *BIAS with the difference between + addresses within the loaded module and those to use with libdw. */ +extern Dwarf *dwfl_module_getdwarf (Dwfl_Module *, Dwarf_Addr *bias) + __nonnull_attribute__ (2); + +/* Get the libdw handle for each module. */ +extern ptrdiff_t dwfl_getdwarf (Dwfl *, + int (*callback) (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + Dwarf *, Dwarf_Addr, void *), + void *arg, ptrdiff_t offset); + +/* Look up the module containing ADDR and return its debugging information, + loading it if necessary. */ +extern Dwarf *dwfl_addrdwarf (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Addr *bias) + __nonnull_attribute__ (3); + + +/* Find the CU containing ADDR and return its DIE. */ +extern Dwarf_Die *dwfl_addrdie (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Addr *bias) + __nonnull_attribute__ (3); +extern Dwarf_Die *dwfl_module_addrdie (Dwfl_Module *mod, + Dwarf_Addr addr, Dwarf_Addr *bias) + __nonnull_attribute__ (3); + +/* Iterate through the CUs, start with null for LASTCU. */ +extern Dwarf_Die *dwfl_nextcu (Dwfl *dwfl, Dwarf_Die *lastcu, Dwarf_Addr *bias) + __nonnull_attribute__ (3); +extern Dwarf_Die *dwfl_module_nextcu (Dwfl_Module *mod, + Dwarf_Die *lastcu, Dwarf_Addr *bias) + __nonnull_attribute__ (3); + +/* Return the module containing the CU DIE. */ +extern Dwfl_Module *dwfl_cumodule (Dwarf_Die *cudie); + + +/* Get source for address. */ +extern Dwfl_Line *dwfl_module_getsrc (Dwfl_Module *mod, Dwarf_Addr addr); +extern Dwfl_Line *dwfl_getsrc (Dwfl *dwfl, Dwarf_Addr addr); + +/* Get address for source. */ +extern int dwfl_module_getsrc_file (Dwfl_Module *mod, + const char *fname, int lineno, int column, + Dwfl_Line ***srcsp, size_t *nsrcs); + +/* Return the module containing this line record. */ +extern Dwfl_Module *dwfl_linemodule (Dwfl_Line *line); + +/* Return the source file name and fill in other information. + Arguments may be null for unneeded fields. */ +extern const char *dwfl_lineinfo (Dwfl_Line *line, Dwarf_Addr *addr, + int *linep, int *colp, + Dwarf_Word *mtime, Dwarf_Word *length); + + +/* Find the symbol that ADDRESS lies inside, and return its name. */ +const char *dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr address); + + + +#endif /* libdwfl.h */ diff --git a/libdwfl/libdwfl.map b/libdwfl/libdwfl.map new file mode 100644 index 00000000..1cf3d3fe --- /dev/null +++ b/libdwfl/libdwfl.map @@ -0,0 +1,39 @@ +ELFUTILS_1.0 { + global: + dwfl_addrdie; + dwfl_addrdwarf; + dwfl_addrmodule; + dwfl_begin; + dwfl_end; + dwfl_errmsg; + dwfl_errno; + dwfl_getdwarf; + dwfl_getsrc; + dwfl_linecu; + dwfl_lineinfo; + dwfl_linemodule; + dwfl_linux_kernel_find_elf; + dwfl_linux_kernel_module_section_address; + dwfl_linux_kernel_report_kernel; + dwfl_linux_kernel_report_modules; + dwfl_linux_proc_find_elf; + dwfl_linux_proc_report; + dwfl_module_addrdie; + dwfl_module_addrname; + dwfl_module_getdwarf; + dwfl_module_getelf; + dwfl_module_getsrc; + dwfl_module_getsrc_file; + dwfl_module_info; + dwfl_module_nextcu; + dwfl_nextcu; + dwfl_report_begin; + dwfl_report_elf; + dwfl_report_end; + dwfl_report_module; + dwfl_standard_argp; + dwfl_standard_find_debuginfo; + + local: + *; +}; diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h new file mode 100644 index 00000000..ccf6ba5c --- /dev/null +++ b/libdwfl/libdwflP.h @@ -0,0 +1,237 @@ +/* Internal definitions for libdwfl. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBDWFLP_H +#define _LIBDWFLP_H 1 + +#ifndef PACKAGE +# include +#endif +#include +#include +#include +#include +#include +#include +#include + +/* gettext helper macros. */ +#define _(Str) dgettext ("elfutils", Str) + +#define DWFL_ERRORS \ + DWFL_ERROR (NOERROR, N_("no error")) \ + DWFL_ERROR (UNKNOWN_ERROR, N_("unknown error")) \ + DWFL_ERROR (NOMEM, N_("out of memory")) \ + DWFL_ERROR (ERRNO, N_("See errno")) \ + DWFL_ERROR (LIBELF, N_("See elf_errno")) \ + DWFL_ERROR (LIBDW, N_("See dwarf_errno")) \ + DWFL_ERROR (LIBEBL, N_("See ebl_errno (XXX missing)")) \ + DWFL_ERROR (NOREL, N_("Callbacks missing for ET_REL file")) \ + DWFL_ERROR (BADRELTYPE, N_("Unsupported relocation type")) \ + DWFL_ERROR (BADRELOFF, N_("r_offset is bogus")) \ + DWFL_ERROR (BADSTROFF, N_("offset out of range")) \ + DWFL_ERROR (RELUNDEF, N_("relocation refers to undefined symbol")) \ + DWFL_ERROR (CB, N_("Callback returned failure")) \ + DWFL_ERROR (NO_DWARF, N_("No DWARF information found")) \ + DWFL_ERROR (NO_SYMTAB, N_("No symbol table found")) \ + DWFL_ERROR (NO_PHDR, N_("No ELF program headers")) \ + DWFL_ERROR (OVERLAP, N_("address range overlaps an existing module")) \ + DWFL_ERROR (ADDR_OUTOFRANGE, N_("address out of range")) \ + DWFL_ERROR (NO_MATCH, N_("no matching address range")) \ + DWFL_ERROR (TRUNCATED, N_("image truncated")) \ + DWFL_ERROR (BADELF, N_("not a valid ELF file")) + +#define DWFL_ERROR(name, text) DWFL_E_##name, +typedef enum { DWFL_ERRORS DWFL_E_NUM } Dwfl_Error; +#undef DWFL_ERROR + +#define OTHER_ERROR(name) ((unsigned int) DWFL_E_##name << 16) +#define DWFL_E(name, errno) (OTHER_ERROR (name) | (errno)) + +extern int __libdwfl_canon_error (Dwfl_Error error) internal_function; +extern void __libdwfl_seterrno (Dwfl_Error error) internal_function; + +struct Dwfl +{ + const Dwfl_Callbacks *callbacks; + + Dwfl_Module *modulelist; /* List in order used by full traversals. */ + + Dwfl_Module **modules; + size_t nmodules; +}; + +struct dwfl_file +{ + char *name; + int fd; + + Elf *elf; + GElf_Addr bias; /* Actual load address - p_vaddr. */ +}; + +struct Dwfl_Module +{ + Dwfl *dwfl; + struct Dwfl_Module *next; /* Link on Dwfl.moduelist. */ + + void *userdata; + + char *name; /* Iterator name for this module. */ + GElf_Addr low_addr, high_addr; + + struct dwfl_file main, debug; + Ebl *ebl; + bool isrel; /* True iff this is an ET_REL file. */ + Dwfl_Error elferr; /* Previous failure to open main file. */ + + struct dwfl_file *symfile; /* Either main or debug. */ + Elf_Data *symdata; /* Data in the ELF symbol table section. */ + size_t syments; /* sh_size / sh_entsize of that section. */ + const Elf_Data *symstrdata; /* Data for its string table. */ + Elf_Data *symxndxdata; /* Data in the extended section index table. */ + Dwfl_Error symerr; /* Previous failure to load symbols. */ + + Dwarf *dw; /* libdw handle for its debugging info. */ + Dwfl_Error dwerr; /* Previous failure to load info. */ + + /* Known CU's in this module. */ + struct dwfl_cu *first_cu, **cu; + unsigned int ncu; + + void *lazy_cu_root; /* Table indexed by Dwarf_Off of CU. */ + unsigned int lazycu; /* Possible users, deleted when none left. */ + + struct dwfl_arange *aranges; /* Mapping of addresses in module to CUs. */ + unsigned int naranges; + + bool gc; /* Mark/sweep flag. */ +}; + + + +/* Information cached about each CU in Dwfl_Module.dw. */ +struct dwfl_cu +{ + /* This caches libdw information about the CU. It's also the + address passed back to users, so we take advantage of the + fact that it's placed first to cast back. */ + Dwarf_Die die; + + Dwfl_Module *mod; /* Pointer back to containing module. */ + + struct dwfl_cu *next; /* CU immediately following in the file. */ + + struct Dwfl_Lines *lines; +}; + +struct Dwfl_Lines +{ + struct dwfl_cu *cu; + + /* This is what the opaque Dwfl_Line * pointers we pass to users are. + We need to recover pointers to our struct dwfl_cu and a record in + libdw's Dwarf_Line table. To minimize the memory used in addition + to libdw's Dwarf_Lines buffer, we just point to our own index in + this table, and have one pointer back to the CU. The indices here + match those in libdw's Dwarf_CU.lines->info table. */ + struct Dwfl_Line + { + unsigned int idx; /* My index in the dwfl_cu.lines table. */ + } idx[0]; +}; + +static inline struct dwfl_cu * +dwfl_linecu (const Dwfl_Line *line) +{ + const struct Dwfl_Lines *lines = ((const void *) line + - offsetof (struct Dwfl_Lines, + idx[line->idx])); + return lines->cu; +} + +/* This describes a contiguous address range that lies in a single CU. + We condense runs of Dwarf_Arange entries for the same CU into this. */ +struct dwfl_arange +{ + struct dwfl_cu *cu; + size_t arange; /* Index in Dwarf_Aranges. */ +}; + + + + +extern void __libdwfl_module_free (Dwfl_Module *mod) internal_function; + + +/* Process relocations in debugging sections in an ET_REL file. + MOD->debug.elf must be opened with ELF_C_READ_MMAP_PRIVATE or ELF_C_READ, + to make it possible to relocate the data in place (or ELF_C_RDWR or + ELF_C_RDWR_MMAP if you intend to modify the Elf file on disk). After + this, dwarf_begin_elf on MOD->debug.elf will read the relocated data. */ +extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *) internal_function; + +/* Adjust *VALUE from section-relative to absolute. + MOD->dwfl->callbacks->section_address is called to determine the actual + address of a loaded section. */ +extern Dwfl_Error __libdwfl_relocate_value (Dwfl_Module *mod, + size_t m_shstrndx, + Elf32_Word shndx, + GElf_Addr *value) + internal_function; + +/* Iterate through all the CU's in the module. Start by passing a null + LASTCU, and then pass the last *CU returned. Success return with null + *CU no more CUs. */ +extern Dwfl_Error __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu, + struct dwfl_cu **cu) internal_function; + +/* Find the CU by address. */ +extern Dwfl_Error __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, + struct dwfl_cu **cu) internal_function; + +/* Ensure that CU->lines (and CU->cu->lines) is set up. */ +extern Dwfl_Error __libdwfl_cu_getsrclines (struct dwfl_cu *cu) + internal_function; + + + + +/* Avoid PLT entries. */ +INTDECL (dwfl_begin) +INTDECL (dwfl_errmsg) +INTDECL (dwfl_addrmodule) +INTDECL (dwfl_addrdwarf) +INTDECL (dwfl_addrdie) +INTDECL (dwfl_module_addrdie) +INTDECL (dwfl_module_getdwarf) +INTDECL (dwfl_module_getelf) +INTDECL (dwfl_module_getsrc) +INTDECL (dwfl_report_elf) +INTDECL (dwfl_report_begin) +INTDECL (dwfl_report_module) +INTDECL (dwfl_report_end) +INTDECL (dwfl_standard_find_debuginfo) +INTDECL (dwfl_linux_kernel_find_elf) +INTDECL (dwfl_linux_kernel_module_section_address) +INTDECL (dwfl_linux_proc_report) +INTDECL (dwfl_linux_proc_find_elf) +INTDECL (dwfl_linux_kernel_report_kernel) +INTDECL (dwfl_linux_kernel_report_modules) + +/* Leading arguments standard to callbacks passed a Dwfl_Module. */ +#define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr +#define CBFAIL (errno ? DWFL_E (ERRNO, errno) : DWFL_E_CB); + + +#endif /* libdwflP.h */ diff --git a/libdwfl/lines.c b/libdwfl/lines.c new file mode 100644 index 00000000..3eb4c195 --- /dev/null +++ b/libdwfl/lines.c @@ -0,0 +1,37 @@ +/* Fetch source line info for CU. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" +#include "../libdw/libdwP.h" + +Dwfl_Error +internal_function_def +__libdwfl_cu_getsrclines (struct dwfl_cu *cu) +{ + if (cu->lines == NULL) + { + Dwarf_Lines *lines; + size_t nlines; + if (dwarf_getsrclines (&cu->die, &lines, &nlines) != 0) + return DWFL_E_LIBDW; + + cu->lines = malloc (offsetof (struct Dwfl_Lines, idx[nlines])); + if (cu->lines == NULL) + return DWFL_E_NOMEM; + cu->lines->cu = cu; + for (unsigned int i = 0; i < nlines; ++i) + cu->lines->idx[i].idx = i; + } + + return DWFL_E_NOERROR; +} diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c new file mode 100644 index 00000000..65e5ca2d --- /dev/null +++ b/libdwfl/linux-kernel-modules.c @@ -0,0 +1,243 @@ +/* Standard libdwfl callbacks for debugging the running Linux kernel. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#undef _FILE_OFFSET_BITS /* Doesn't jibe with fts. */ + +#include "libdwflP.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MODULEDIRFMT "/lib/modules/%s" + +#define MODULELIST "/proc/modules" +#define SECADDRFMT "/sys/module/%s/sections/%s" + + +static inline const char * +kernel_release (void) +{ + /* Cache the `uname -r` string we'll use. */ + static struct utsname utsname; + if (utsname.release[0] == '\0' && uname (&utsname) != 0) + return NULL; + return utsname.release; +} + +/* Find the ELF file for the running kernel and dwfl_report_elf it. */ +int +dwfl_linux_kernel_report_kernel (Dwfl *dwfl) +{ + if (dwfl == NULL) + return -1; + + const char *release = kernel_release (); + if (release == NULL) + return errno; + + char *fname = NULL; + asprintf (&fname, "/boot/vmlinux-%s", release); + if (fname == NULL) + return -1; + int fd = open64 (fname, O_RDONLY); + if (fd < 0) + { + free (fname); + fname = NULL; + asprintf (&fname, "/usr/lib/debug" MODULEDIRFMT "/vmlinux", release); + if (fname == NULL) + return -1; + fd = open64 (fname, O_RDONLY); + } + + int result = 0; + if (fd < 0) + result = errno; + else if (INTUSE(dwfl_report_elf) (dwfl, "kernel", fname, fd, 0) == NULL) + { + close (fd); + result = -1; + } + + free (fname); + + return result; +} +INTDEF (dwfl_linux_kernel_report_kernel) + +/* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules. */ + +int +dwfl_linux_kernel_find_elf (Dwfl_Module *mod __attribute__ ((unused)), + void **userdata __attribute__ ((unused)), + const char *module_name, + Dwarf_Addr base __attribute__ ((unused)), + char **file_name, + Elf **elfp __attribute__ ((unused))) +{ + const char *release = kernel_release (); + if (release == NULL) + return -1; + + /* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko". */ + + char *modulesdir[] = { NULL, NULL }; + asprintf (&modulesdir[0], MODULEDIRFMT "/kernel", release); + if (modulesdir[0] == NULL) + return -1; + + FTS *fts = fts_open (modulesdir, FTS_LOGICAL | FTS_NOSTAT, NULL); + if (fts == NULL) + { + free (modulesdir[0]); + return -1; + } + + size_t namelen = strlen (module_name); + FTSENT *f; + int error = ENOENT; + while ((f = fts_read (fts)) != NULL) + { + error = ENOENT; + switch (f->fts_info) + { + case FTS_F: + case FTS_NSOK: + /* See if this file name is "MODULE_NAME.ko". */ + if (f->fts_namelen == namelen + 3 + && !memcmp (f->fts_name, module_name, namelen) + && !memcmp (f->fts_name + namelen, ".ko", 4)) + { + int fd = open64 (f->fts_accpath, O_RDONLY); + *file_name = strdup (f->fts_path); + fts_close (fts); + if (fd < 0) + free (*file_name); + else if (*file_name == NULL) + { + close (fd); + fd = -1; + } + return fd; + } + break; + + case FTS_ERR: + case FTS_DNR: + case FTS_NS: + error = f->fts_errno; + break; + + default: + break; + } + } + + errno = error; + return -1; +} +INTDEF (dwfl_linux_kernel_find_elf) + +/* Dwfl_Callbacks.section_address for kernel modules in the running Linux. + We read the information from /sys/module directly. */ + +int +dwfl_linux_kernel_module_section_address +(Dwfl_Module *mod __attribute__ ((unused)), + void **userdata __attribute__ ((unused)), + const char *modname, Dwarf_Addr base __attribute__ ((unused)), + const char *secname, Dwarf_Addr *addr) +{ + char *sysfile = NULL; + asprintf (&sysfile, SECADDRFMT, modname, secname); + if (sysfile == NULL) + return ENOMEM; + + FILE *f = fopen (sysfile, "r"); + if (f == NULL) + { + if (errno == ENOENT) + { + /* The .modinfo and .data.percpu sections are never kept + loaded in the kernel. If the kernel was compiled without + CONFIG_MODULE_UNLOAD, the .exit.* sections are not + actually loaded at all. + + Just relocate these bogusly to zero. This part of the + debug information will not be of any use. */ + + if (!strcmp (secname, ".modinfo") + || !strcmp (secname, ".data.percpu") + || !strncmp (secname, ".exit", 5)) + { + *addr = 0; + return DWARF_CB_OK; + } + } + + return DWARF_CB_ABORT; + } + + (void) __fsetlocking (f, FSETLOCKING_BYCALLER); + + int result = (fscanf (f, "%" PRIi64 "\n", addr) == 1 ? 0 + : ferror_unlocked (f) ? errno : ENOEXEC); + fclose (f); + + if (result == 0) + return DWARF_CB_OK; + + errno = result; + return DWARF_CB_ABORT; +} +INTDEF (dwfl_linux_kernel_module_section_address) + +int +dwfl_linux_kernel_report_modules (Dwfl *dwfl) +{ + FILE *f = fopen (MODULELIST, "r"); + if (f == NULL) + return errno; + + (void) __fsetlocking (f, FSETLOCKING_BYCALLER); + + int result = 0; + Dwarf_Addr modaddr; + unsigned long int modsz; + char modname[128]; + while (fscanf (f, "%128s %lu %*s %*s %*s %" PRIi64 "\n", + modname, &modsz, &modaddr) == 3) + if (INTUSE(dwfl_report_module) (dwfl, modname, + modaddr, modaddr + modsz) == NULL) + { + result = -1; + break; + } + + if (result == 0) + result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC; + + fclose (f); + + return result; +} +INTDEF (dwfl_linux_kernel_report_modules) diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c new file mode 100644 index 00000000..2611c73a --- /dev/null +++ b/libdwfl/linux-proc-maps.c @@ -0,0 +1,285 @@ +/* Standard libdwfl callbacks for debugging a live Linux process. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PROCMAPSFMT "/proc/%d/maps" +#define PROCMEMFMT "/proc/%d/mem" +#define PROCAUXVFMT "/proc/%d/auxv" + + +/* Search /proc/PID/auxv for the AT_SYSINFO_EHDR tag. */ + +static int +find_sysinfo_ehdr (pid_t pid, GElf_Addr *sysinfo_ehdr) +{ + char *fname = NULL; + asprintf (&fname, PROCAUXVFMT, pid); + if (fname == NULL) + return ENOMEM; + + int fd = open64 (fname, O_RDONLY); + free (fname); + if (fd < 0) + return errno == ENOENT ? 0 : errno; + + ssize_t nread; + do + { + union + { + char buffer[sizeof (long int) * 2 * 64]; + Elf64_auxv_t a64[sizeof (long int) * 2 * 64 / sizeof (Elf64_auxv_t)]; + Elf32_auxv_t a32[sizeof (long int) * 2 * 32 / sizeof (Elf32_auxv_t)]; + } d; + nread = read (fd, &d, sizeof d); + if (nread > 0) + { + switch (sizeof (long int)) + { + case 4: + for (size_t i = 0; (char *) &d.a32[i] < &d.buffer[nread]; ++i) + if (d.a32[i].a_type == AT_SYSINFO_EHDR) + { + *sysinfo_ehdr = d.a32[i].a_un.a_val; + nread = 0; + break; + } + break; + case 8: + for (size_t i = 0; (char *) &d.a64[i] < &d.buffer[nread]; ++i) + if (d.a64[i].a_type == AT_SYSINFO_EHDR) + { + *sysinfo_ehdr = d.a64[i].a_un.a_val; + nread = 0; + break; + } + break; + default: + abort (); + break; + } + } + } + while (nread > 0); + + close (fd); + + return nread < 0 ? errno : 0; +} + +int +dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid) +{ + if (dwfl == NULL) + return -1; + + /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it. */ + GElf_Addr sysinfo_ehdr = 0; + int result = find_sysinfo_ehdr (pid, &sysinfo_ehdr); + if (result != 0) + return result; + + char *fname = NULL; + asprintf (&fname, PROCMAPSFMT, pid); + if (fname == NULL) + return ENOMEM; + + FILE *f = fopen (fname, "r"); + free (fname); + if (f == NULL) + return errno; + + (void) __fsetlocking (f, FSETLOCKING_BYCALLER); + + unsigned int last_dmajor = -1, last_dminor = -1; + uint64_t last_ino = -1; + char *last_file = NULL; + Dwarf_Addr low = 0, high = 0; + + inline bool report (void) + { + if (last_file != NULL) + { + if (INTUSE(dwfl_report_module) (dwfl, last_file, low, high) == NULL) + { + free (last_file); + return true; + } + last_file = NULL; + } + return false; + } + + char *line = NULL; + size_t linesz; + ssize_t len; + while ((len = getline (&line, &linesz, f)) > 0) + { + if (line[len - 1] == '\n') + line[len - 1] = '\0'; + + Dwarf_Addr start, end, offset; + unsigned int dmajor, dminor; + uint64_t ino; + int nread = -1; + if (sscanf (line, "%" PRIx64 "-%" PRIx64 " %*s %" PRIx64 + " %x:%x %" PRIi64 " %n", + &start, &end, &offset, &dmajor, &dminor, &ino, &nread) < 6 + || nread <= 0) + { + free (line); + return ENOEXEC; + } + + /* If this is the special mapping AT_SYSINFO_EHDR pointed us at, + report the last one and then this special one. */ + if (start == sysinfo_ehdr && start != 0) + { + if (report ()) + { + bad_report: + free (line); + fclose (f); + return -1; + } + + low = start; + high = end; + if (asprintf (&last_file, "[vdso: %d]", (int) pid) < 0 + || report ()) + goto bad_report; + } + + char *file = line + nread + strspn (line + nread, " \t"); + if (file[0] == '\0' || (ino == 0 && dmajor == 0 && dminor == 0)) + /* This line doesn't indicate a file mapping. */ + continue; + + if (last_file != NULL + && ino == last_ino && dmajor == last_dmajor && dminor == last_dminor) + { + /* This is another portion of the same file's mapping. */ + assert (!strcmp (last_file, file)); + high = end; + } + else + { + /* This is a different file mapping. Report the last one. */ + if (report ()) + goto bad_report; + low = start; + high = end; + last_file = strdup (file); + last_ino = ino; + last_dmajor = dmajor; + last_dminor = dminor; + } + } + free (line); + + result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC; + fclose (f); + + /* Report the final one. */ + bool lose = report (); + + return result != 0 ? result : lose ? -1 : 0; +} +INTDEF (dwfl_linux_proc_report) + + +static ssize_t +read_proc_memory (void *arg, void *data, GElf_Addr address, + size_t minread, size_t maxread) +{ + const int fd = *(const int *) arg; + ssize_t nread = pread64 (fd, data, maxread, (off64_t) address); + if (nread > 0 && (size_t) nread < minread) + nread = 0; + return nread; +} + +extern Elf *elf_from_remote_memory (GElf_Addr ehdr_vma, + GElf_Addr *loadbasep, + ssize_t (*read_memory) (void *arg, + void *data, + GElf_Addr address, + size_t minread, + size_t maxread), + void *arg); + + +/* Dwfl_Callbacks.find_elf */ + +int +dwfl_linux_proc_find_elf (Dwfl_Module *mod __attribute__ ((unused)), + void **userdata __attribute__ ((unused)), + const char *module_name, Dwarf_Addr base, + char **file_name, Elf **elfp) +{ + if (module_name[0] == '/') + { + int fd = open64 (module_name, O_RDONLY); + if (fd >= 0) + { + *file_name = strdup (module_name); + if (*file_name == NULL) + { + close (fd); + return ENOMEM; + } + } + return fd; + } + + int pid; + if (sscanf (module_name, "[vdso: %d]", &pid) == 1) + { + /* Special case for in-memory ELF image. */ + + char *fname = NULL; + asprintf (&fname, PROCMEMFMT, pid); + if (fname == NULL) + return -1; + + int fd = open64 (fname, O_RDONLY); + free (fname); + if (fd < 0) + return -1; + + *elfp = elf_from_remote_memory (base, NULL, &read_proc_memory, &fd); + + close (fd); + + *file_name = NULL; + return -1; + } + + abort (); + return -1; +} +INTDEF (dwfl_linux_proc_find_elf) diff --git a/libdwfl/loc2c-runtime.h b/libdwfl/loc2c-runtime.h new file mode 100644 index 00000000..af27f791 --- /dev/null +++ b/libdwfl/loc2c-runtime.h @@ -0,0 +1,125 @@ +/* target operations */ + +#include +#define intptr_t long +#define uintptr_t unsigned long + + +/* These three macro definitions are generic, just shorthands + used by the generated code. */ + +#define op_abs(x) (x < 0 ? -x : x) + +#define fetch_bitfield(target, base, higherbits, nbits) \ + target = (((base) >> (sizeof (base) * 8 - (higherbits) - (nbits))) \ + & (((__typeof (base)) 1 << (nbits)) - 1)) + +#define store_bitfield(target, base, higherbits, nbits) \ + target = (target \ + &~ ((((__typeof (base)) 1 << (nbits)) - 1) \ + << (sizeof (base) * 8 - (higherbits) - (nbits))) \ + | ((__typeof (base)) (value) \ + << (sizeof (base) * 8 - (higherbits) - (nbits)))) + + +/* These operations are target-specific. */ +#include + +#define fetch_register(regno) ((intptr_t) regs->dwarf_register_##regno) + +#if defined __i386__ + +#define dwarf_register_0 eax +#define dwarf_register_1 ecx +#define dwarf_register_2 edx +#define dwarf_register_3 ebx +#define dwarf_register_4 esp +#define dwarf_register_5 ebp +#define dwarf_register_6 esi +#define dwarf_register_7 edi + +#elif defined __x86_64__ + +#define dwarf_register_0 eax +#define dwarf_register_1 edx +#define dwarf_register_2 ecx +#define dwarf_register_3 ebx +#define dwarf_register_4 esi +#define dwarf_register_5 edi +#define dwarf_register_6 ebp +#define dwarf_register_7 esp +#define dwarf_register_8 r8 +#define dwarf_register_9 r9 +#define dwarf_register_10 r10 +#define dwarf_register_11 r11 +#define dwarf_register_12 r12 +#define dwarf_register_13 r13 +#define dwarf_register_14 r14 +#define dwarf_register_15 r15 + +#elif defined __powerpc__ + +#undef fetch_register +#define fetch_register(regno) ((intptr_t) regs->gpr[regno]) + +#endif + +#if defined __i386__ || defined __x86_64__ + +#define deref(size, addr) \ + ({ \ + int _bad = 0; \ + u8 _b; u16 _w; u32 _l; u64 _q; \ + intptr_t _v; \ + switch (size) \ + { \ + case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ + case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ + case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ + case 8: __get_user_asm(_q,addr,_bad,"q","","=r",1); _v = _q; break; \ + default: _v = __get_user_bad(); \ + } \ + if (_bad) \ + goto deref_fault; \ + _v; \ + }) + +#elif defined __powerpc64__ + +#define deref(size, addr) \ + ({ \ + int _bad = 0; \ + intptr_t _v; \ + switch (size) \ + { \ + case 1: __get_user_asm(_v,addr,_bad,"lbz",1); break; \ + case 2: __get_user_asm(_v,addr,_bad,"lhz",1); break; \ + case 4: __get_user_asm(_v,addr,_bad,"lwz",1); break; \ + case 8: __get_user_asm(_v,addr,_bad,"ld",1); break; \ + default: _v = __get_user_bad(); \ + } \ + if (_bad) \ + goto deref_fault; \ + _v; \ + }) + +#elif defined __powerpc__ + +#define deref(size, addr) \ + ({ \ + int _bad = 0; \ + intptr_t _v; \ + switch (size) \ + { \ + case 1: __get_user_asm(_v,addr,_bad,"lbz"); break; \ + case 2: __get_user_asm(_v,addr,_bad,"lhz"); break; \ + case 4: __get_user_asm(_v,addr,_bad,"lwz"); break; \ + case 8: __get_user_asm(_v,addr,_bad,"ld"); break; \ + default: _v = __get_user_bad(); \ + } \ + if (_bad) \ + goto deref_fault; \ + _v; \ + }) + +#endif diff --git a/libdwfl/loc2c.c b/libdwfl/loc2c.c new file mode 100644 index 00000000..816eb06a --- /dev/null +++ b/libdwfl/loc2c.c @@ -0,0 +1,1398 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _(x) x + +#define STACK_TYPE "intptr_t" /* Must be the signed type. */ +#define UTYPE "uintptr_t" /* Must be the unsigned type. */ +#define SFORMAT "%" PRId64 "L" +#define UFORMAT "%" PRIu64 "UL" +#define AFORMAT "%#" PRIx64 "UL" +#define STACKFMT "s%u" + +struct location +{ + struct location *next; + + const Dwarf_Loc *ops; + size_t nops; + + Dwarf_Word byte_size; + + enum { loc_address, loc_register, loc_noncontiguous, loc_final } type; + union + { + struct /* loc_address or loc_final */ + { + char *program; /* C fragment, leaves address in s0. */ + unsigned int stack_depth; /* Temporaries "s0.." used by it. */ + struct location *frame_base; + bool used_deref; /* Program uses "deref" macro. */ + } address; + unsigned int regno; /* loc_register */ + struct location *pieces; /* loc_noncontiguous */ + }; +}; + + +static const char * +dwarf_diename_integrate (Dwarf_Die *die) +{ + Dwarf_Attribute attr_mem; + return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem)); +} + +/* Synthesize a new loc_address using the program on the obstack. */ +static struct location * +new_synthetic_loc (struct obstack *pool, struct location *origin, bool deref) +{ + obstack_1grow (pool, '\0'); + char *program = obstack_finish (pool); + + struct location *loc = obstack_alloc (pool, sizeof *loc); + loc->next = NULL; + loc->byte_size = 0; + loc->type = loc_address; + loc->address.program = program; + loc->address.stack_depth = 0; + loc->address.frame_base = NULL; + loc->address.used_deref = deref; + + if (origin->type == loc_register) + { + loc->ops = origin->ops; + loc->nops = origin->nops; + } + else + { + loc->ops = NULL; + loc->nops = 0; + } + + return loc; +} + + +/* Die in the middle of an expression. */ +static struct location * +lose (const char *failure, const Dwarf_Loc *lexpr, size_t i) +{ + error (2, 0, _("%s in DWARF expression [%Zu] at %" PRIu64 + " (%#x: %" PRId64 ", %" PRId64 ")"), + failure, i, lexpr[i].offset, + lexpr[i].atom, lexpr[i].number, lexpr[i].number2); + return NULL; +} + +/* Translate a (constrained) DWARF expression into C code + emitted to the obstack POOL. INDENT is the number of indentation levels. + ADDRBIAS is the difference between runtime and Dwarf info addresses. + INPUT is null or an expression to be initially pushed on the stack. + If NEED_FB is null, fail on DW_OP_fbreg, else set *NEED_FB to true + and emit "frame_base" for it. On success, set *MAX_STACK to the number + of stack slots required. On failure, set *LOSER to the index in EXPR + of the operation we could not handle. + + Returns a failure message or null for success. */ + +static const char * +translate (struct obstack *pool, int indent, Dwarf_Addr addrbias, + const Dwarf_Loc *expr, const size_t len, + struct location *input, + bool *need_fb, size_t *loser, + struct location *loc) +{ + loc->ops = expr; + loc->nops = len; + +#define DIE(msg) return (*loser = i, _(msg)) + +#define emit(fmt, ...) obstack_printf (pool, fmt, ## __VA_ARGS__) + + unsigned int stack_depth = 0, max_stack = 0; + inline void deepen (void) + { + if (stack_depth == max_stack) + ++max_stack; + } + +#define POP(var) \ + if (stack_depth > 0) \ + --stack_depth; \ + else if (tos_register != -1) \ + fetch_tos_register (); \ + else \ + goto underflow; \ + int var = stack_depth +#define PUSH (deepen (), stack_depth++) +#define STACK(idx) (stack_depth - 1 - (idx)) + + /* Don't put stack operations in the arguments to this. */ +#define push(fmt, ...) \ + emit ("%*s" STACKFMT " = " fmt ";\n", indent * 2, "", PUSH, ## __VA_ARGS__) + + int tos_register = -1; + inline void fetch_tos_register (void) + { + deepen (); + emit ("%*s" STACKFMT " = fetch_register (%d);\n", + indent * 2, "", stack_depth, tos_register); + tos_register = -1; + } + + if (input != NULL) + switch (input->type) + { + case loc_address: + push ("addr"); + break; + + case loc_register: + tos_register = input->regno; + break; + + default: + abort (); + break; + } + + size_t i; + + inline const char *finish (struct location *piece) + { + if (stack_depth > 1) + DIE ("multiple values left on stack"); + if (stack_depth == 1) + { + obstack_1grow (pool, '\0'); + char *program = obstack_finish (pool); + piece->type = loc_address; + piece->address.program = program; + piece->address.stack_depth = max_stack; + piece->address.frame_base = NULL; + } + else if (tos_register == -1) + DIE ("stack underflow"); + else if (obstack_object_size (pool) != 0) + DIE ("register value must stand alone in location expression"); + else + { + piece->type = loc_register; + piece->regno = tos_register; + } + return NULL; + } + + struct location *pieces = NULL, **tailpiece = &pieces; + size_t piece_expr_start = 0; + for (i = 0; i < len; ++i) + { + unsigned int reg; + uint_fast8_t sp; + Dwarf_Word value; + + switch (expr[i].atom) + { + /* Basic stack operations. */ + case DW_OP_nop: + break; + + case DW_OP_dup: + if (stack_depth < 1) + goto underflow; + else + { + unsigned int tos = STACK (0); + push (STACKFMT, tos); + } + break; + + case DW_OP_drop: + POP (ignore); + emit ("%*s/* drop " STACKFMT "*/\n", indent * 2, "", ignore); + break; + + case DW_OP_pick: + sp = expr[i].number; + op_pick: + if (sp >= stack_depth) + goto underflow; + sp = STACK (sp); + push (STACKFMT, sp); + break; + + case DW_OP_over: + sp = 1; + goto op_pick; + + case DW_OP_swap: + if (stack_depth < 2) + goto underflow; + deepen (); /* Use a temporary slot. */ + emit ("%*s" + STACKFMT " = " STACKFMT ", " + STACKFMT " = " STACKFMT ", " + STACKFMT " = " STACKFMT ";\n", + indent * 2, "", + STACK (-1), STACK (0), + STACK (0), STACK (1), + STACK (1), STACK (-1)); + break; + + case DW_OP_rot: + if (stack_depth < 3) + goto underflow; + deepen (); /* Use a temporary slot. */ + emit ("%*s" + STACKFMT " = " STACKFMT ", " + STACKFMT " = " STACKFMT ", " + STACKFMT " = " STACKFMT ", " + STACKFMT " = " STACKFMT ";\n", + indent * 2, "", + STACK (-1), STACK (0), + STACK (0), STACK (1), + STACK (1), STACK (2), + STACK (3), STACK (-1)); + break; + + + /* Control flow operations. */ + case DW_OP_skip: + { + Dwarf_Off target = expr[i].offset + 3 + expr[i].number; + while (i + 1 < len && expr[i + 1].offset < target) + ++i; + if (expr[i + 1].offset != target) + DIE ("invalid skip target"); + break; + } + + case DW_OP_bra: + DIE ("conditional branches not supported"); + break; + + + /* Memory access. */ + case DW_OP_deref: + { + POP (addr); + push ("deref (sizeof (void *), " STACKFMT ")", addr); + loc->address.used_deref = true; + } + break; + + case DW_OP_deref_size: + { + POP (addr); + push ("deref (" UFORMAT ", " STACKFMT ")", + expr[i].number, addr); + loc->address.used_deref = true; + } + break; + + case DW_OP_xderef: + { + POP (addr); + POP (as); + push ("xderef (sizeof (void *), " STACKFMT ", " STACKFMT ")", + addr, as); + loc->address.used_deref = true; + } + break; + + case DW_OP_xderef_size: + { + POP (addr); + POP (as); + push ("xderef (" UFORMAT ", " STACKFMT ", " STACKFMT ")", + expr[i].number, addr, as); + loc->address.used_deref = true; + } + break; + + /* Constant-value operations. */ + + case DW_OP_addr: + push (AFORMAT, addrbias + expr[i].number); + break; + + case DW_OP_lit0 ... DW_OP_lit31: + value = expr[i].atom - DW_OP_lit0; + goto op_const; + + case DW_OP_const1u: + case DW_OP_const1s: + case DW_OP_const2u: + case DW_OP_const2s: + case DW_OP_const4u: + case DW_OP_const4s: + case DW_OP_const8u: + case DW_OP_const8s: + case DW_OP_constu: + case DW_OP_consts: + value = expr[i].number; + op_const: + push (SFORMAT, value); + break; + + /* Arithmetic operations. */ +#define UNOP(dw_op, c_op) \ + case DW_OP_##dw_op: \ + { \ + POP (tos); \ + push ("%s (" STACKFMT ")", #c_op, tos); \ + } \ + break +#define BINOP(dw_op, c_op) \ + case DW_OP_##dw_op: \ + { \ + POP (b); \ + POP (a); \ + push (STACKFMT " %s " STACKFMT, a, #c_op, b); \ + } \ + break + + UNOP (abs, op_abs); + BINOP (and, &); + BINOP (div, /); + BINOP (minus, -); + BINOP (mod, %); + BINOP (mul, *); + UNOP (neg, -); + UNOP (not, ~); + BINOP (or, |); + BINOP (plus, +); + BINOP (shl, <<); + BINOP (shra, >>); + BINOP (xor, ^); + + /* Comparisons are binary operators too. */ + BINOP (le, <=); + BINOP (ge, >=); + BINOP (eq, ==); + BINOP (lt, <); + BINOP (gt, >); + BINOP (ne, !=); + +#undef UNOP +#undef BINOP + + case DW_OP_shr: + { + POP (b); + POP (a); + push ("(%s) " STACKFMT " >> (%s)" STACKFMT, + UTYPE, a, UTYPE, b); + break; + } + + case DW_OP_plus_uconst: + { + POP (x); + push (STACKFMT " + " UFORMAT, x, expr[i].number); + } + break; + + + /* Register-relative addressing. */ + case DW_OP_breg0 ... DW_OP_breg31: + reg = expr[i].atom - DW_OP_breg0; + value = expr[i].number; + goto op_breg; + + case DW_OP_bregx: + reg = expr[i].number; + value = expr[i].number2; + op_breg: + push ("fetch_register (%u) + " SFORMAT, reg, value); + break; + + case DW_OP_fbreg: + if (need_fb == NULL) + DIE ("DW_OP_fbreg from DW_AT_frame_base"); + *need_fb = true; + push ("frame_base + " SFORMAT, expr[i].number); + break; + + /* Direct register contents. */ + case DW_OP_reg0 ... DW_OP_reg31: + reg = expr[i].atom - DW_OP_reg0; + goto op_reg; + + case DW_OP_regx: + reg = expr[i].number; + op_reg: + tos_register = reg; + break; + + /* Special magic. */ + case DW_OP_piece: + if (stack_depth > 1) + /* If this ever happens we could copy the program. */ + DIE ("DW_OP_piece left multiple values on stack"); + else + { + struct location *piece = obstack_alloc (pool, sizeof *piece); + const char *failure = finish (piece); + if (unlikely (failure != NULL)) + return failure; + + piece->ops = &expr[piece_expr_start]; + piece->nops = i - piece_expr_start; + piece_expr_start = i + 1; + + piece->byte_size = expr[i].number; + + *tailpiece = piece; + tailpiece = &piece->next; + piece->next = NULL; + } + break; + + case DW_OP_push_object_address: + DIE ("XXX DW_OP_push_object_address"); + break; + + default: + DIE ("unrecognized operation"); + break; + } + } + + if (likely (pieces == NULL)) + return finish (loc); + + if (piece_expr_start != i) + DIE ("extra operations after last DW_OP_piece"); + + loc->type = loc_noncontiguous; + loc->pieces = pieces; + + return NULL; + + underflow: + DIE ("stack underflow"); + +#undef emit +#undef push +#undef PUSH +#undef POP +#undef STACK +#undef DIE +} + +/* Translate a location starting from an address or nothing. */ +static struct location * +location_from_address (struct obstack *pool, + int indent, Dwarf_Addr dwbias, + const Dwarf_Loc *expr, size_t len, Dwarf_Addr address, + struct location **input, Dwarf_Attribute *fb_attr) +{ + bool need_fb = false; + size_t loser; + struct location *loc = obstack_alloc (pool, sizeof *loc); + const char *failure = translate (pool, indent + 1, dwbias, expr, len, + *input, &need_fb, &loser, loc); + if (unlikely (failure != NULL)) + return lose (failure, expr, loser); + + loc->next = NULL; + if (need_fb) + { + /* The main expression uses DW_OP_fbreg, so we need to compute + the DW_AT_frame_base attribute expression's value first. */ + + Dwarf_Loc *fb_expr; + size_t fb_len; + switch (dwarf_addrloclists (fb_attr, address - dwbias, + &fb_expr, &fb_len, 1)) + { + case 1: /* Should always happen. */ + if (fb_len == 0) + goto fb_inaccessible; + break; + + default: /* Shouldn't happen. */ + case -1: + error (2, 0, "dwarf_addrloclists (form %#x): %s", + dwarf_whatform (fb_attr), dwarf_errmsg (-1)); + return NULL; + + case 0: /* Shouldn't happen. */ + fb_inaccessible: + error (2, 0, "DW_AT_frame_base not accessible at this address"); + return NULL; + } + + loc->address.frame_base = obstack_alloc (pool, sizeof *loc); + failure = translate (pool, indent + 1, dwbias, fb_expr, fb_len, NULL, + NULL, &loser, loc->address.frame_base); + if (unlikely (failure != NULL)) + return lose (failure, fb_expr, loser); + } + + if (*input != NULL) + (*input)->next = loc; + *input = loc; + + return loc; +} + +/* Translate a location starting from a non-address "on the top of the + stack". The *INPUT location is a register name or noncontiguous + object specification, and this expression wants to find the "address" + of an object relative to that "address". */ + +static struct location * +location_relative (struct obstack *pool, + int indent, Dwarf_Addr dwbias, + const Dwarf_Loc *expr, size_t len, Dwarf_Addr address, + struct location **input, Dwarf_Attribute *fb_attr) +{ + Dwarf_Sword *stack; + unsigned int stack_depth = 0, max_stack = 0; + inline void deepen (void) + { + if (stack_depth == max_stack) + { + ++max_stack; + obstack_blank (pool, sizeof stack[0]); + stack = (void *) obstack_base (pool); + } + } + +#define POP(var) \ + if (stack_depth > 0) \ + --stack_depth; \ + else \ + goto underflow; \ + int var = stack_depth +#define PUSH (deepen (), stack_depth++) +#define STACK(idx) (stack_depth - 1 - (idx)) +#define STACKWORD(idx) stack[STACK (idx)] + + /* Don't put stack operations in the arguments to this. */ +#define push(value) (stack[PUSH] = (value)) + + const char *failure = NULL; +#define DIE(msg) do { failure = _(msg); goto fail; } while (0) + + struct location *head = NULL; + size_t i; + for (i = 0; i < len; ++i) + { + uint_fast8_t sp; + Dwarf_Word value; + + switch (expr[i].atom) + { + /* Basic stack operations. */ + case DW_OP_nop: + break; + + case DW_OP_dup: + if (stack_depth < 1) + goto underflow; + else + { + unsigned int tos = STACK (0); + push (stack[tos]); + } + break; + + case DW_OP_drop: + if (stack_depth > 0) + --stack_depth; + else if (*input != NULL) + /* Mark that we have consumed the input. */ + *input = NULL; + else + /* Hits if cleared above, or if we had no input at all. */ + goto underflow; + break; + + case DW_OP_pick: + sp = expr[i].number; + op_pick: + if (sp >= stack_depth) + goto underflow; + sp = STACK (sp); + push (stack[sp]); + break; + + case DW_OP_over: + sp = 1; + goto op_pick; + + case DW_OP_swap: + if (stack_depth < 2) + goto underflow; + deepen (); /* Use a temporary slot. */ + STACKWORD (-1) = STACKWORD (0); + STACKWORD (0) = STACKWORD (1); + STACKWORD (1) = STACKWORD (-1); + break; + + case DW_OP_rot: + if (stack_depth < 3) + goto underflow; + deepen (); /* Use a temporary slot. */ + STACKWORD (-1) = STACKWORD (0); + STACKWORD (0) = STACKWORD (1); + STACKWORD (2) = STACKWORD (2); + STACKWORD (2) = STACKWORD (-1); + break; + + + /* Control flow operations. */ + case DW_OP_bra: + { + POP (taken); + if (stack[taken] == 0) + break; + } + /*FALLTHROUGH*/ + + case DW_OP_skip: + { + Dwarf_Off target = expr[i].offset + 3 + expr[i].number; + while (i + 1 < len && expr[i + 1].offset < target) + ++i; + if (expr[i + 1].offset != target) + DIE ("invalid skip target"); + break; + } + + /* Memory access. */ + case DW_OP_deref: + case DW_OP_deref_size: + case DW_OP_xderef: + case DW_OP_xderef_size: + + /* Register-relative addressing. */ + case DW_OP_breg0 ... DW_OP_breg31: + case DW_OP_bregx: + case DW_OP_fbreg: + + /* This started from a register, but now it's following a pointer. + So we can do the translation starting from address here. */ + return location_from_address (pool, indent, dwbias, + expr, len, address, input, fb_attr); + + + /* Constant-value operations. */ + case DW_OP_addr: + push (dwbias + expr[i].number); + break; + + case DW_OP_lit0 ... DW_OP_lit31: + value = expr[i].atom - DW_OP_lit0; + goto op_const; + + case DW_OP_const1u: + case DW_OP_const1s: + case DW_OP_const2u: + case DW_OP_const2s: + case DW_OP_const4u: + case DW_OP_const4s: + case DW_OP_const8u: + case DW_OP_const8s: + case DW_OP_constu: + case DW_OP_consts: + value = expr[i].number; + op_const: + push (value); + break; + + /* Arithmetic operations. */ +#define UNOP(dw_op, c_op) \ + case DW_OP_##dw_op: \ + { \ + POP (tos); \ + push (c_op (stack[tos])); \ + } \ + break +#define BINOP(dw_op, c_op) \ + case DW_OP_##dw_op: \ + { \ + POP (b); \ + POP (a); \ + push (stack[a] c_op stack[b]); \ + } \ + break + +#define op_abs(x) (x < 0 ? -x : x) + UNOP (abs, op_abs); + BINOP (and, &); + BINOP (div, /); + BINOP (mod, %); + BINOP (mul, *); + UNOP (neg, -); + UNOP (not, ~); + BINOP (or, |); + BINOP (shl, <<); + BINOP (shra, >>); + BINOP (xor, ^); + + /* Comparisons are binary operators too. */ + BINOP (le, <=); + BINOP (ge, >=); + BINOP (eq, ==); + BINOP (lt, <); + BINOP (gt, >); + BINOP (ne, !=); + +#undef UNOP +#undef BINOP + + case DW_OP_shr: + { + POP (b); + POP (a); + push ((Dwarf_Word) stack[a] >> (Dwarf_Word) stack[b]); + break; + } + + /* Simple addition we may be able to handle relative to + the starting register name. */ + case DW_OP_minus: + { + POP (tos); + value = -stack[tos]; + goto plus; + } + case DW_OP_plus: + { + POP (tos); + value = stack[tos]; + goto plus; + } + case DW_OP_plus_uconst: + value = expr[i].number; + plus: + if (stack_depth > 0) + { + /* It's just private diddling after all. */ + POP (a); + push (stack[a] + value); + break; + } + if (*input == NULL) + goto underflow; + + /* This is the primary real-world case: the expression takes + the input address and adds a constant offset. */ + + while ((*input)->type == loc_noncontiguous) + { + /* We are starting from a noncontiguous object (DW_OP_piece). + Find the piece we want. */ + + struct location *piece = (*input)->pieces; + while (piece != NULL && value >= piece->byte_size) + { + value -= piece->byte_size; + piece = piece->next; + } + if (piece == NULL) + DIE ("offset outside available pieces"); + + *input = piece; + } + + switch ((*input)->type) + { + case loc_address: + { + /* The piece we want is actually in memory. Use the same + program to compute the address from the preceding input. */ + + struct location *loc = obstack_alloc (pool, sizeof *loc); + *loc = **input; + if (head == NULL) + head = loc; + (*input)->next = loc; + if (value == 0) + { + /* The piece addresses exactly where we want to go. */ + loc->next = NULL; + *input = loc; + } + else + { + /* Add a second fragment to offset the piece address. */ + obstack_printf (pool, "%*saddr += " SFORMAT "\n", + indent * 2, "", value); + *input = loc->next = new_synthetic_loc (pool, *input, + false); + } + + if (i + 1 < len) + { + /* This expression keeps going, but further + computations now have an address to start with. + So we can punt to the address computation generator. */ + loc = location_from_address (pool, indent, dwbias, + &expr[i + 1], len - i - 1, + address, input, fb_attr); + if (loc == NULL) + return NULL; + } + + /* That's all she wrote. */ + return head; + } + + case loc_register: + // XXX + + default: + abort (); + } + break; + + /* Direct register contents. */ + case DW_OP_reg0 ... DW_OP_reg31: + case DW_OP_regx: + DIE ("register"); + break; + + /* Special magic. */ + case DW_OP_piece: + DIE ("DW_OP_piece"); + break; + + case DW_OP_push_object_address: + DIE ("XXX DW_OP_push_object_address"); + break; + + default: + DIE ("unrecognized operation"); + break; + } + } + + if (stack_depth > 1) + DIE ("multiple values left on stack"); + + if (stack_depth > 0) /* stack_depth == 1 */ + { + if (*input != NULL) + DIE ("multiple values left on stack"); + + /* Could handle this if it ever actually happened. */ + DIE ("relative expression computed constant"); + } + + return head; + + underflow: + if (*input == NULL) + DIE ("stack underflow"); + else + DIE ("cannot handle location expression"); + + fail: + return lose (failure, expr, i); +} + + +/* Translate a C fragment for the location expression, using *INPUT + as the starting location, begin from scratch if *INPUT is null. + If DW_OP_fbreg is used, it may have a subfragment computing from + the FB_ATTR location expression. + + On errors, exit and never return (XXX ?). On success, return the + first fragment created, which is also chained onto (*INPUT)->next. + *INPUT is then updated with the new tail of that chain. */ + +struct location * +c_translate_location (struct obstack *pool, + int indent, Dwarf_Addr dwbias, + Dwarf_Attribute *loc_attr, Dwarf_Addr address, + struct location **input, Dwarf_Attribute *fb_attr) +{ + Dwarf_Loc *expr; + size_t len; + switch (dwarf_addrloclists (loc_attr, address - dwbias, &expr, &len, 1)) + { + case 1: /* Should always happen. */ + if (len == 0) + goto inaccessible; + break; + + default: /* Shouldn't happen. */ + case -1: + error (2, 0, "dwarf_addrloclists (form %#x): %s", + dwarf_whatform (fb_attr), dwarf_errmsg (-1)); + return NULL; + + case 0: /* Shouldn't happen. */ + inaccessible: + error (2, 0, "not accessible at this address"); + return NULL; + } + + ++indent; + switch (*input == NULL ? loc_address : (*input)->type) + { + case loc_address: + /* We have a previous address computation. + This expression will compute starting with that on the stack. */ + return location_from_address (pool, indent, dwbias, expr, len, address, + input, fb_attr); + + case loc_noncontiguous: + case loc_register: + /* The starting point is not an address computation, but a + register. We can only handle limited computations from here. */ + return location_relative (pool, indent, dwbias, expr, len, address, + input, fb_attr); + + case loc_final: /* Bogus caller. */ + default: + abort (); + break; + } + + return NULL; +} + + +/* Emit "uintNN_t TARGET = ...;". */ +static bool +emit_base_fetch (struct obstack *pool, Dwarf_Word byte_size, + const char *target, bool decl, struct location *loc) +{ + if (decl) + obstack_printf (pool, "uint%" PRIu64 "_t ", byte_size * 8); + + switch (loc->type) + { + case loc_address: + if (byte_size != 0 && byte_size != (Dwarf_Word) -1) + obstack_printf (pool, "%s = deref (%" PRIu64 ", addr); ", + target, byte_size); + else + obstack_printf (pool, "%s = deref (sizeof %s, addr); ", + target, target); + return true; + + case loc_register: + obstack_printf (pool, "%s = fetch_register (%u);", target, loc->regno); + break; + + case loc_noncontiguous: + /* Could be handled if it ever happened. */ + error (2, 0, _("noncontiguous locations not supported")); + break; + + default: + abort (); + break; + } + + return false; +} + +/* Translate a fragment to dereference the given pointer type, + where *INPUT is the location of the pointer with that type. + + We chain on a loc_address program that yields this pointer value + (i.e. the location of what it points to). */ + +void +c_translate_pointer (struct obstack *pool, int indent, + Dwarf_Addr dwbias __attribute__ ((unused)), + Dwarf_Die *typedie, struct location **input) +{ + obstack_printf (pool, "%*s{ ", (indent + 2) * 2, ""); + + bool deref = false; + Dwarf_Attribute attr_mem; + Dwarf_Word byte_size; + if (dwarf_attr_integrate (typedie, DW_AT_byte_size, &attr_mem) == NULL) + { + obstack_printf (pool, "uintptr_t "); + emit_base_fetch (pool, 0, "tmp", false, *input); + } + else if (dwarf_formudata (&attr_mem, &byte_size) != 0) + error (2, 0, + _("cannot get byte_size attribute for type %s: %s"), + dwarf_diename_integrate (typedie) ?: "", + dwarf_errmsg (-1)); + else + deref = emit_base_fetch (pool, byte_size, "tmp", true, *input); + + obstack_printf (pool, " addr = tmp; }\n"); + + struct location *loc = new_synthetic_loc (pool, *input, deref); + (*input)->next = loc; + *input = loc; +} + +/* Determine the byte size of a base type. */ +static Dwarf_Word +base_byte_size (Dwarf_Die *typedie) +{ + Dwarf_Attribute attr_mem; + Dwarf_Word size; + if (dwarf_attr_integrate (typedie, DW_AT_byte_size, &attr_mem) != NULL + && dwarf_formudata (&attr_mem, &size) == 0) + return size; + + error (2, 0, + _("cannot get byte_size attribute for type %s: %s"), + dwarf_diename_integrate (typedie) ?: "", + dwarf_errmsg (-1)); + return -1; +} + +/* Emit a code fragment like: + { uintNN_t tmp = ...; S1 S2 S3, tmp, B0, Bn); } +*/ +static void +emit_bitfield (struct obstack *pool, int indent, + Dwarf_Die *die, Dwarf_Word byte_size, struct location *loc, + const char *s1, const char *s2, const char *s3) +{ + Dwarf_Word bit_offset, bit_size; + Dwarf_Attribute attr_mem; + if (dwarf_attr_integrate (die, DW_AT_bit_offset, &attr_mem) == NULL + || dwarf_formudata (&attr_mem, &bit_offset) != 0 + || dwarf_attr_integrate (die, DW_AT_bit_size, &attr_mem) == NULL + || dwarf_formudata (&attr_mem, &bit_size) != 0) + error (2, 0, _("cannot get bit field parameters: %s"), + dwarf_errmsg (-1)); + + /* Emit "{ uintNN_t tmp = ...;" to fetch the base type. */ + + obstack_printf (pool, "%*s{ ", indent * 2, ""); + emit_base_fetch (pool, byte_size, "tmp", true, loc); + + obstack_printf (pool, "%s%s%s, tmp, %" PRIu64 ", %" PRIu64 "); }\n", + s1, s2, s3, bit_offset, bit_size); +} + +/* Translate a fragment to fetch the value of variable or member DIE + at the *INPUT location and store it in variable TARGET. */ + +void +c_translate_fetch (struct obstack *pool, int indent, + Dwarf_Addr dwbias __attribute__ ((unused)), + Dwarf_Die *die, Dwarf_Attribute *typeattr, + struct location **input, const char *target) +{ + ++indent; + + Dwarf_Attribute size_attr; + Dwarf_Word byte_size; + if (dwarf_attr_integrate (die, DW_AT_byte_size, &size_attr) == NULL + || dwarf_formudata (&size_attr, &byte_size) != 0) + { + Dwarf_Die basedie; + if (dwarf_formref_die (typeattr, &basedie) == NULL) + error (2, 0, _("cannot get type of field: %s"), dwarf_errmsg (-1)); + byte_size = base_byte_size (&basedie); + } + + bool deref = false; + if (dwarf_hasattr_integrate (die, DW_AT_bit_offset)) + /* This is a bit field. */ + emit_bitfield (pool, indent, die, byte_size, *input, + "fetch_bitfield (", target, ""); + else + switch (byte_size) + { + case 1: + case 2: + case 4: + case 8: + obstack_printf (pool, "%*s", indent * 2, ""); + deref = emit_base_fetch (pool, byte_size, target, false, *input); + obstack_printf (pool, "\n"); + break; + + default: + /* Could handle this generating call to memcpy equivalent. */ + error (2, 0, _("fetch is larger than base integer types")); + break; + } + + struct location *loc = new_synthetic_loc (pool, *input, deref); + loc->type = loc_final; + (*input)->next = loc; + *input = loc; +} + +void +c_translate_addressof (struct obstack *pool, int indent, + Dwarf_Addr dwbias __attribute__ ((unused)), + Dwarf_Die *die, + Dwarf_Attribute *typeattr __attribute__ ((unused)), + struct location **input, const char *target) +{ + ++indent; + + if (dwarf_hasattr_integrate (die, DW_AT_bit_offset)) + error (2, 0, _("cannot take the address of a bit field")); + + switch ((*input)->type) + { + case loc_address: + obstack_printf (pool, "%*s%s = addr;\n", indent * 2, "", target); + (*input)->next = new_synthetic_loc (pool, *input, false); + (*input)->next->type = loc_final; + break; + + case loc_register: + error (2, 0, _("cannot take address of object in register")); + break; + case loc_noncontiguous: + error (2, 0, _("cannot take address of noncontiguous object")); + break; + + default: + abort(); + break; + } +} + + +/* Determine the element stride of an array type. */ +static Dwarf_Word +array_stride (Dwarf_Die *typedie) +{ + Dwarf_Attribute attr_mem; + if (dwarf_attr_integrate (typedie, DW_AT_stride_size, &attr_mem) != NULL) + { + Dwarf_Word stride; + if (dwarf_formudata (&attr_mem, &stride) == 0) + return stride; + error (2, 0, _("cannot get stride_size attribute array type %s: %s"), + dwarf_diename_integrate (typedie) ?: "", + dwarf_errmsg (-1)); + } + + Dwarf_Die die_mem; + if (dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem) == NULL + || dwarf_formref_die (&attr_mem, &die_mem) == NULL) + error (2, 0, _("cannot get element type of array type %s: %s"), + dwarf_diename_integrate (typedie) ?: "", + dwarf_errmsg (-1)); + + if (dwarf_attr_integrate (&die_mem, DW_AT_byte_size, &attr_mem) != NULL) + { + Dwarf_Word stride; + if (dwarf_formudata (&attr_mem, &stride) == 0) + return stride; + error (2, 0, + _("cannot get byte_size attribute for array element type %s: %s"), + dwarf_diename_integrate (&die_mem) ?: "", + dwarf_errmsg (-1)); + } + + error (2, 0, _("confused about array element size")); + return 0; +} + +void +c_translate_array (struct obstack *pool, int indent, + Dwarf_Addr dwbias __attribute__ ((unused)), + Dwarf_Die *typedie, struct location **input, + const char *idx, Dwarf_Word const_idx) +{ + ++indent; + + Dwarf_Word stride = array_stride (typedie); + + struct location *loc = *input; + while (loc->type == loc_noncontiguous) + { + if (idx != NULL) + error (2, 0, _("cannot dynamically index noncontiguous array")); + else + { + Dwarf_Word offset = const_idx * stride; + struct location *piece = loc->pieces; + while (piece != NULL && offset >= piece->byte_size) + { + offset -= piece->byte_size; + piece = piece->next; + } + if (piece == NULL) + error (2, 0, _("constant index is outside noncontiguous array")); + if (offset % stride != 0) + error (2, 0, _("noncontiguous array splits elements")); + const_idx = offset / stride; + loc = piece; + } + } + + switch (loc->type) + { + case loc_address: + ++indent; + if (idx != NULL) + obstack_printf (pool, "%*saddr += %s * " UFORMAT ";\n", + indent * 2, "", idx, stride); + else + obstack_printf (pool, "%*saddr += " UFORMAT " * " UFORMAT ";\n", + indent * 2, "", const_idx, stride); + loc = new_synthetic_loc (pool, loc, false); + break; + + case loc_register: + error (2, 0, _("cannot index array stored in a register")); + break; + + default: + abort(); + break; + } + + (*input)->next = loc; + *input = (*input)->next; +} + + +/* Emitting C code for finalized fragments. */ + + +#define emit(fmt, ...) fprintf (out, fmt, ## __VA_ARGS__) + +/* Open a block with a comment giving the original DWARF expression. */ +static void +emit_header (FILE *out, struct location *loc, unsigned int hindent) +{ + if (loc->ops == NULL) + emit ("%*s{ // synthesized\n", hindent * 2, ""); + else + { + emit ("%*s{ // DWARF expression:", hindent * 2, ""); + for (size_t i = 0; i < loc->nops; ++i) + { + emit (" %#x", loc->ops[i].atom); + if (loc->ops[i].number2 == 0) + { + if (loc->ops[i].number != 0) + emit ("(%" PRId64 ")", loc->ops[i].number); + } + else + emit ("(%" PRId64 ",%" PRId64 ")", + loc->ops[i].number, loc->ops[i].number2); + } + emit ("\n"); + } +} + +/* Emit a code fragment to assign the target variable to a register value. */ +static void +emit_loc_register (FILE *out, struct location *loc, unsigned int indent, + const char *target) +{ + assert (loc->type == loc_register); + + emit ("%*s%s = fetch_register (%u);\n", + indent * 2, "", target, loc->regno); +} + +/* Emit a code fragment to assign the target variable to an address. */ +static void +emit_loc_address (FILE *out, struct location *loc, unsigned int indent, + const char *target) +{ + assert (loc->type == loc_address); + + if (loc->address.stack_depth == 0) + /* Synthetic program. */ + emit ("%s", loc->address.program); + else + { + emit ("%*s%s " STACKFMT, (indent + 1) * 2, "", STACK_TYPE, 0); + for (unsigned int i = 1; i < loc->address.stack_depth; ++i) + emit (", " STACKFMT, i); + emit (";\n"); + + emit ("%s%*s%s = " STACKFMT ";\n", loc->address.program, + (indent + 1) * 2, "", target, 0); + } +} + +/* Emit a code fragment to declare the target variable and + assign it to an address-sized value. */ +static void +emit_loc_value (FILE *out, struct location *loc, unsigned int indent, + const char *target, bool declare) +{ + if (declare) + emit ("%*s%s %s;\n", indent * 2, "", STACK_TYPE, target); + + emit_header (out, loc, indent); + + switch (loc->type) + { + default: + abort (); + break; + + case loc_register: + emit_loc_register (out, loc, indent, target); + break; + + case loc_address: + if (loc->address.frame_base != NULL) + emit_loc_value (out, loc->address.frame_base, indent, + "frame_base", true); + emit_loc_address (out, loc, indent, target); + break; + } + + emit ("%*s}\n", indent * 2, ""); +} + +bool +c_emit_location (FILE *out, struct location *loc, int indent) +{ + emit ("%*s{\n", indent * 2, ""); + + bool deref = false; + for (bool declare_addr = true; loc->next != NULL; loc = loc->next) + switch (loc->type) + { + case loc_address: + /* Emit the program fragment to calculate the address. */ + emit_loc_value (out, loc, indent + 1, "addr", declare_addr); + declare_addr = false; + deref = deref || loc->address.used_deref; + break; + + case loc_register: + case loc_noncontiguous: + /* These don't produce any code directly. + The next address/final record incorporates the value. */ + break; + + case loc_final: /* Should be last in chain! */ + default: + abort (); + break; + } + + if (loc->type != loc_final) /* Unfinished chain. */ + abort (); + + emit ("%s%*s}\n", loc->address.program, indent * 2, ""); + + return deref; +} + +#undef emit diff --git a/libdwfl/loc2c.h b/libdwfl/loc2c.h new file mode 100644 index 00000000..15d89280 --- /dev/null +++ b/libdwfl/loc2c.h @@ -0,0 +1,63 @@ +#include + +struct obstack; /* Use */ +struct location; /* Opaque */ + + +/* Translate a C fragment for the location expression, using *INPUT + as the starting location, begin from scratch if *INPUT is null. + If DW_OP_fbreg is used, it may have a subfragment computing from + the FB_ATTR location expression. + + On errors, exit and never return (XXX ?). On success, return the + first fragment created, which is also chained onto (*INPUT)->next. + *INPUT is then updated with the new tail of that chain. + *USED_DEREF is set to true iff the "deref" runtime operation + was used, otherwise it is not modified. */ +struct location *c_translate_location (struct obstack *, int indent, + Dwarf_Addr bias, + Dwarf_Attribute *loc_attr, + Dwarf_Addr address, + struct location **input, + Dwarf_Attribute *fb_attr); + +/* Translate a fragment to dereference the given pointer type, + where *INPUT is the location of the pointer with that type. */ +void c_translate_pointer (struct obstack *pool, int indent, + Dwarf_Addr dwbias, Dwarf_Die *typedie, + struct location **input); + +/* Translate a fragment to index an array (turning the location + of the array into the location of an element). If IDX is non-null, + it's a string of C code to emit in the fragment as the array index. + If the index is a known constant, IDX should be null and CONST_IDX + is used instead (this case can handle local arrays in registers). */ +void c_translate_array (struct obstack *pool, int indent, + Dwarf_Addr dwbias, Dwarf_Die *typedie, + struct location **input, + const char *idx, Dwarf_Word const_idx); + +/* Translate a fragment to compute the address of the input location + and assign it to the variable TARGET. This doesn't really do anything + (it always emits "TARGET = addr;"), but it will barf if the location + is a register or noncontiguous object. */ +void c_translate_addressof (struct obstack *pool, int indent, + Dwarf_Addr dwbias, Dwarf_Die *die, + Dwarf_Attribute *typeattr, + struct location **input, const char *target); + +/* Translate a fragment to fetch the value of variable or member DIE + at the *INPUT location and store it in variable TARGET. + This handles base integer types and bit fields. */ +void c_translate_fetch (struct obstack *pool, int indent, + Dwarf_Addr dwbias __attribute__ ((unused)), + Dwarf_Die *die, Dwarf_Attribute *typeattr, + struct location **input, const char *target); + +/* Emit the C fragment built up at LOC (i.e., the return value from the + first c_translate_location call made). INDENT should match that + passed to c_translate_* previously. + + Writes complete lines of C99, code forming a complete C block, to STREAM. + Return value is true iff that code uses the `deref' runtime macros. */ +bool c_emit_location (FILE *stream, struct location *loc, int indent); diff --git a/libdwfl/ptest.c b/libdwfl/ptest.c new file mode 100644 index 00000000..948e971a --- /dev/null +++ b/libdwfl/ptest.c @@ -0,0 +1,117 @@ +/* Test program for libdwfl basic module tracking, relocation. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static int +print_func (Dwarf_Func *func, void *arg) +{ + const Dwarf_Addr dwbias = *(Dwarf_Addr *) arg; + + const char *file = dwarf_func_file (func); + int line = -1; + dwarf_func_line (func, &line); + const char *fct = dwarf_func_name (func); + + printf (" %s:%d: %s:", file, line, fct); + + Dwarf_Addr lo = -1, hi = -1, entry = -1; + if (dwarf_func_lowpc (func, &lo) == 0) + lo += dwbias; + else + printf (" (lowpc => %s)", dwarf_errmsg (-1)); + if (dwarf_func_highpc (func, &hi) == 0) + hi += dwbias; + else + printf (" (highpc => %s)", dwarf_errmsg (-1)); + if (dwarf_func_entrypc (func, &entry) == 0) + entry += dwbias; + else + printf (" (entrypc => %s)", dwarf_errmsg (-1)); + + if (lo != (Dwarf_Addr) -1 || hi != (Dwarf_Addr) -1 + || entry != (Dwarf_Addr) -1) + printf (" %#" PRIx64 "..%#" PRIx64 " => %#" PRIx64 "\n", + lo, hi, entry); + else + puts (""); + + return DWARF_CB_OK; +} + +static int +print_module (Dwfl_Module *mod __attribute__ ((unused)), + void **userdata __attribute__ ((unused)), + const char *name, Dwarf_Addr base, + Dwarf *dw, Dwarf_Addr bias, + void *arg __attribute__ ((unused))) +{ + printf ("module: %30s %08" PRIx64 " %12p %" PRIx64 " (%s)\n", + name, base, dw, bias, dwfl_errmsg (-1)); + + if (dw != NULL) + { + Dwarf_Off off = 0; + size_t cuhl; + Dwarf_Off noff; + + while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0) + { + Dwarf_Die die_mem; + Dwarf_Die *die = dwarf_offdie (dw, off + cuhl, &die_mem); + + (void) dwarf_getfuncs (die, print_func, &bias, 0); + + off = noff; + } + } + + return DWARF_CB_OK; +} + +int +main (int argc, char **argv) +{ + /* We use no threads here which can interfere with handling a stream. */ + (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); + + /* Set locale. */ + (void) setlocale (LC_ALL, ""); + + Dwfl *dwfl = NULL; + (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, NULL, &dwfl); + assert (dwfl != NULL); + + ptrdiff_t p = 0; + do + p = dwfl_getdwarf (dwfl, &print_module, NULL, p); + while (p > 0); + if (p < 0) + error (2, 0, "dwfl_getdwarf: %s", dwfl_errmsg (-1)); + + dwfl_end (dwfl); + + return 0; +} diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c new file mode 100644 index 00000000..41de6d18 --- /dev/null +++ b/libdwfl/relocate.c @@ -0,0 +1,293 @@ +/* Relocate debug information. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + +typedef uint8_t GElf_Byte; + +/* Adjust *VALUE to add the load address of the SHNDX section. + We update the section header in place to cache the result. */ + +Dwfl_Error +internal_function_def +__libdwfl_relocate_value (Dwfl_Module *mod, size_t symshstrndx, + Elf32_Word shndx, GElf_Addr *value) +{ + Elf_Scn *refscn = elf_getscn (mod->symfile->elf, shndx); + GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem); + if (refshdr == NULL) + return DWFL_E_LIBELF; + + if ((refshdr->sh_flags & SHF_ALLOC) && refshdr->sh_addr == 0) + { + /* This is a loaded section. Find its actual + address and update the section header. */ + const char *name = elf_strptr (mod->symfile->elf, symshstrndx, + refshdr->sh_name); + if (name == NULL) + return DWFL_E_LIBELF; + + if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod), name, + &refshdr->sh_addr)) + return CBFAIL; + + if (refshdr->sh_addr == 0) + /* The callback resolved this to zero, indicating it wasn't + really loaded but we don't really care. Mark it so we + don't check it again for the next relocation. */ + refshdr->sh_flags &= ~SHF_ALLOC; + + /* Update the in-core file's section header to show the final + load address (or unloadedness). This serves as a cache, + so we won't get here again for the same section. */ + if (! gelf_update_shdr (refscn, refshdr)) + return DWFL_E_LIBELF; + } + + /* Apply the adjustment. */ + *value += refshdr->sh_addr; + return DWFL_E_NOERROR; +} + +Dwfl_Error +internal_function_def +__libdwfl_relocate (Dwfl_Module *mod) +{ + assert (mod->isrel); + + GElf_Ehdr ehdr_mem; + const GElf_Ehdr *ehdr = gelf_getehdr (mod->debug.elf, &ehdr_mem); + if (ehdr == NULL) + return DWFL_E_LIBELF; + + size_t symshstrndx, d_shstrndx; + if (elf_getshstrndx (mod->symfile->elf, &symshstrndx) < 0) + return DWFL_E_LIBELF; + if (mod->symfile == &mod->debug) + d_shstrndx = symshstrndx; + else if (elf_getshstrndx (mod->debug.elf, &d_shstrndx) < 0) + return DWFL_E_LIBELF; + + /* Look at each section in the debuginfo file, and process the + relocation sections for debugging sections. */ + Dwfl_Error result = DWFL_E_NO_DWARF; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (mod->debug.elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) + { + /* It's a relocation section. First, fetch the name of the + section these relocations apply to. */ + + Elf_Scn *tscn = elf_getscn (mod->debug.elf, shdr->sh_info); + if (tscn == NULL) + return DWFL_E_LIBELF; + + GElf_Shdr tshdr_mem; + GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem); + const char *tname = elf_strptr (mod->debug.elf, d_shstrndx, + tshdr->sh_name); + if (tname == NULL) + return DWFL_E_LIBELF; + + if (! ebl_debugscn_p (mod->ebl, tname)) + /* This relocation section is not for a debugging section. + Nothing to do here. */ + continue; + + /* Fetch the section data that needs the relocations applied. */ + Elf_Data *tdata = elf_rawdata (tscn, NULL); + if (tdata == NULL) + return DWFL_E_LIBELF; + + /* Apply one relocation. Returns true for any invalid data. */ + Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend, + int rtype, int symndx) + { + /* First, resolve the symbol to an absolute value. */ + GElf_Addr value; + inline Dwfl_Error adjust (GElf_Word shndx) + { + return __libdwfl_relocate_value (mod, symshstrndx, + shndx, &value); + } + + if (symndx == STN_UNDEF) + /* When strip removes a section symbol referring to a + section moved into the debuginfo file, it replaces + that symbol index in relocs with STN_UNDEF. We + don't actually need the symbol, because those relocs + are always references relative to the nonallocated + debugging sections, which start at zero. */ + value = 0; + else + { + GElf_Sym sym_mem; + GElf_Word shndx; + GElf_Sym *sym = gelf_getsymshndx (mod->symdata, + mod->symxndxdata, + symndx, &sym_mem, + &shndx); + if (sym == NULL) + return DWFL_E_LIBELF; + + value = sym->st_value; + if (sym->st_shndx != SHN_XINDEX) + shndx = sym->st_shndx; + switch (shndx) + { + case SHN_ABS: + break; + + case SHN_UNDEF: + case SHN_COMMON: + return DWFL_E_RELUNDEF; + + default: + { + Dwfl_Error error = adjust (shndx); + if (error != DWFL_E_NOERROR) + return error; + break; + } + } + } + + /* These are the types we can relocate. */ +#define TYPES DO_TYPE (BYTE, Byte) DO_TYPE (HALF, Half) \ + DO_TYPE (WORD, Word) DO_TYPE (SWORD, Sword) \ + DO_TYPE (XWORD, Xword) DO_TYPE (SXWORD, Sxword) + size_t size; + Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype); + switch (type) + { +#define DO_TYPE(NAME, Name) \ + case ELF_T_##NAME: \ + size = sizeof (GElf_##Name); \ + break; + TYPES +#undef DO_TYPE + default: + return DWFL_E_BADRELTYPE; + } + + if (offset + size >= tdata->d_size) + return DWFL_E_BADRELOFF; + +#define DO_TYPE(NAME, Name) GElf_##Name Name; + union { TYPES } tmpbuf; +#undef DO_TYPE + Elf_Data tmpdata = + { + .d_type = type, + .d_buf = &tmpbuf, + .d_size = size, + .d_version = EV_CURRENT, + }; + Elf_Data rdata = + { + .d_type = type, + .d_buf = tdata->d_buf + offset, + .d_size = size, + .d_version = EV_CURRENT, + }; + + /* XXX check for overflow? */ + if (addend) + { + /* For the addend form, we have the value already. */ + value += *addend; + switch (type) + { +#define DO_TYPE(NAME, Name) \ + case ELF_T_##NAME: \ + tmpbuf.Name = value; \ + break; + TYPES +#undef DO_TYPE + default: + abort (); + } + } + else + { + /* Extract the original value and apply the reloc. */ + Elf_Data *d = gelf_xlatetom (mod->main.elf, &tmpdata, &rdata, + ehdr->e_ident[EI_DATA]); + if (d == NULL) + return DWFL_E_LIBELF; + assert (d == &tmpdata); + switch (type) + { +#define DO_TYPE(NAME, Name) \ + case ELF_T_##NAME: \ + tmpbuf.Name += (GElf_##Name) value; \ + break; + TYPES +#undef DO_TYPE + default: + abort (); + } + } + + /* Now convert the relocated datum back to the target + format. This will write into rdata.d_buf, which + points into the raw section data being relocated. */ + Elf_Data *s = gelf_xlatetof (mod->main.elf, &rdata, &tmpdata, + ehdr->e_ident[EI_DATA]); + if (s == NULL) + return DWFL_E_LIBELF; + assert (s == &rdata); + + /* We have applied this relocation! */ + return DWFL_E_NOERROR; + } + + /* Fetch the relocation section and apply each reloc in it. */ + Elf_Data *reldata = elf_getdata (scn, NULL); + if (reldata == NULL) + return DWFL_E_LIBELF; + + result = DWFL_E_NOERROR; + size_t nrels = shdr->sh_size / shdr->sh_entsize; + if (shdr->sh_type == SHT_REL) + for (size_t relidx = 0; !result && relidx < nrels; ++relidx) + { + GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem); + if (r == NULL) + return DWFL_E_LIBELF; + result = relocate (r->r_offset, NULL, + GELF_R_TYPE (r->r_info), + GELF_R_SYM (r->r_info)); + } + else + for (size_t relidx = 0; !result && relidx < nrels; ++relidx) + { + GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx, + &rela_mem); + if (r == NULL) + return DWFL_E_LIBELF; + result = relocate (r->r_offset, &r->r_addend, + GELF_R_TYPE (r->r_info), + GELF_R_SYM (r->r_info)); + } + if (result != DWFL_E_NOERROR) + break; + } + } + + return result; +} diff --git a/libdwfl/test2.c b/libdwfl/test2.c new file mode 100644 index 00000000..4c1e7ade --- /dev/null +++ b/libdwfl/test2.c @@ -0,0 +1,268 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../libdw/libdwP.h" +#include + +#include "loc2c.h" + +static const char * +dwarf_diename_integrate (Dwarf_Die *die) +{ + Dwarf_Attribute attr_mem; + return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem)); +} + + + +static void +handle_variable (Dwarf_Die *scopes, int nscopes, int out, + Dwarf_Addr cubias, Dwarf_Die *vardie, Dwarf_Addr pc, + char **fields) +{ +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + struct obstack pool; + obstack_init (&pool); + + /* Figure out the appropriate frame base for accessing this variable. + XXX not handling nested functions + XXX inlines botched + */ + Dwarf_Attribute fb_attr_mem, *fb_attr = NULL; + for (int inner = 0; inner < nscopes; ++inner) + { + switch (dwarf_tag (&scopes[inner])) + { + default: + continue; + case DW_TAG_subprogram: + case DW_TAG_entry_point: + case DW_TAG_inlined_subroutine: /* XXX */ + if (inner >= out) + fb_attr = dwarf_attr_integrate (&scopes[inner], + DW_AT_frame_base, + &fb_attr_mem); + break; + } + break; + } + + Dwarf_Attribute attr_mem; + + if (dwarf_attr_integrate (vardie, DW_AT_location, &attr_mem) == NULL) + error (2, 0, _("cannot get location of variable: %s"), + dwarf_errmsg (-1)); + +#define FIELD "addr" +#define emit(fmt, ...) printf (" addr = " fmt "\n", ## __VA_ARGS__) + + struct location *head, *tail = NULL; + head = c_translate_location (&pool, 1, cubias, &attr_mem, pc, + &tail, fb_attr); + + if (dwarf_attr_integrate (vardie, DW_AT_type, &attr_mem) == NULL) + error (2, 0, _("cannot get type of variable: %s"), + dwarf_errmsg (-1)); + + Dwarf_Die die_mem, *die = vardie; + while (*fields != NULL) + { + die = dwarf_formref_die (&attr_mem, &die_mem); + + const int typetag = dwarf_tag (die); + switch (typetag) + { + case DW_TAG_typedef: + /* Just iterate on the referent type. */ + break; + + case DW_TAG_pointer_type: + if (**fields == '+') + goto subscript; + /* A "" field means explicit pointer dereference and we consume it. + Otherwise the next field implicitly gets the dereference. */ + if (**fields == '\0') + ++fields; + c_translate_pointer (&pool, 1, cubias, die, &tail); + break; + + case DW_TAG_array_type: + if (**fields == '+') + { + subscript:; + char *endp = *fields + 1; + uintmax_t idx = strtoumax (*fields + 1, &endp, 0); + if (endp == NULL || endp == *fields || *endp != '\0') + c_translate_array (&pool, 1, cubias, die, &tail, + *fields + 1, 0); + else + c_translate_array (&pool, 1, cubias, die, &tail, + NULL, idx); + ++fields; + } + else + error (2, 0, _("bad field for array type: %s"), *fields); + break; + + case DW_TAG_structure_type: + case DW_TAG_union_type: + switch (dwarf_child (die, &die_mem)) + { + case 1: /* No children. */ + error (2, 0, _("empty struct %s"), + dwarf_diename_integrate (die) ?: ""); + break; + case -1: /* Error. */ + default: /* Shouldn't happen */ + error (2, 0, _("%s %s: %s"), + typetag == DW_TAG_union_type ? "union" : "struct", + dwarf_diename_integrate (die) ?: "", + dwarf_errmsg (-1)); + break; + + case 0: + break; + } + while (dwarf_tag (die) != DW_TAG_member + || ({ const char *member = dwarf_diename_integrate (die); + member == NULL || strcmp (member, *fields); })) + if (dwarf_siblingof (die, &die_mem) != 0) + error (2, 0, _("field name %s not found"), *fields); + + if (dwarf_attr_integrate (die, DW_AT_data_member_location, + &attr_mem) == NULL) + { + /* Union members don't usually have a location, + but just use the containing union's location. */ + if (typetag != DW_TAG_union_type) + error (2, 0, _("no location for field %s: %s"), + *fields, dwarf_errmsg (-1)); + } + else + c_translate_location (&pool, 1, cubias, &attr_mem, pc, + &tail, NULL); + ++fields; + break; + + case DW_TAG_base_type: + error (2, 0, _("field %s vs base type %s"), + *fields, dwarf_diename_integrate (die) ?: ""); + break; + + case -1: + error (2, 0, _("cannot find type: %s"), dwarf_errmsg (-1)); + break; + + default: + error (2, 0, _("%s: unexpected type tag %#x"), + dwarf_diename_integrate (die) ?: "", + dwarf_tag (die)); + break; + } + + /* Now iterate on the type in DIE's attribute. */ + if (dwarf_attr_integrate (die, DW_AT_type, &attr_mem) == NULL) + error (2, 0, _("cannot get type of field: %s"), dwarf_errmsg (-1)); + } + + c_translate_fetch (&pool, 1, cubias, die, &attr_mem, &tail, "value"); + + printf ("#define PROBEADDR %#" PRIx64 "ULL\n", pc); + puts ("static void print_value(struct pt_regs *regs)\n" + "{\n" + " intptr_t value;"); + + bool deref = c_emit_location (stdout, head, 1); + + puts (" printk (\" ---> %ld\\n\", (unsigned long) value);\n" + " return;"); + + if (deref) + puts ("\n" + " deref_fault:\n" + " printk (\" => BAD FETCH\\n\");"); + + puts ("}"); +} + +int +main (int argc, char **argv) +{ + /* We use no threads here which can interfere with handling a stream. */ + (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); + + /* Set locale. */ + (void) setlocale (LC_ALL, ""); + + Dwfl *dwfl = NULL; + int argi; + (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &argi, &dwfl); + assert (dwfl != NULL); + + if (argi == argc) + error (2, 0, "need address argument"); + + char *endp; + uintmax_t pc = strtoumax (argv[argi], &endp, 0); + if (endp == argv[argi]) + error (2, 0, "bad address argument"); + + Dwarf_Addr cubias; + Dwarf_Die *cudie = dwfl_addrdie (dwfl, pc, &cubias); + if (cudie == NULL) + error (EXIT_FAILURE, 0, "dwfl_addrdie: %s", dwfl_errmsg (-1)); + + Dwarf_Die *scopes; + int n = dwarf_getscopes (cudie, pc - cubias, &scopes); + if (n < 0) + error (EXIT_FAILURE, 0, "dwarf_getscopes: %s", dwarf_errmsg (-1)); + else if (n == 0) + error (EXIT_FAILURE, 0, "%#" PRIx64 ": not in any scope\n", pc); + + if (++argi == argc) + error (2, 0, "need variable arguments"); + + char *spec = argv[argi++]; + + int lineno = 0, colno = 0, shadow = 0; + char *at = strchr (spec, '@'); + if (at != NULL) + { + *at++ = '\0'; + if (sscanf (at, "%*[^:]:%i:%i", &lineno, &colno) < 1) + lineno = 0; + } + else + { + int len; + if (sscanf (spec, "%*[^+]%n+%i", &len, &shadow) == 2) + spec[len] = '\0'; + } + + Dwarf_Die vardie; + int out = dwarf_getscopevar (scopes, n, spec, shadow, at, lineno, colno, + &vardie); + if (out == -2) + error (0, 0, "no match for %s (+%d, %s:%d:%d)", + spec, shadow, at, lineno, colno); + else if (out < 0) + error (0, 0, "dwarf_getscopevar: %s (+%d, %s:%d:%d): %s", + spec, shadow, at, lineno, colno, dwarf_errmsg (-1)); + else + handle_variable (scopes, n, out, cubias, &vardie, pc, &argv[argi]); + + dwfl_end (dwfl); + + return 0; +} diff --git a/libebl/.cvsignore b/libebl/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/libebl/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/libebl/ChangeLog b/libebl/ChangeLog new file mode 100644 index 00000000..a14572c0 --- /dev/null +++ b/libebl/ChangeLog @@ -0,0 +1,281 @@ +2005-07-23 Ulrich Drepper + + * eblsectionstripp.c: New file. + * Makefile.am (gen_SOURCES): Add eblsectionstripp.c. + * i386_init.c (i386_init): Install specific debugscn_p callback. + * i386_symbol.c (i386_debugscn_p): New function. + * libebl.h: Declare ebl_section_strip_p. + * libebl_i386.h: Declare i386_debugscn_p. + + * libebl.h: Move Ebl definition to... + * libeblP.h: ...here. + +2005-07-21 Roland McGrath + + * Makefile.am (install-ebl-modules): New target, commands from ... + (install): ... here. Make this depend on it. + (LIBEBL_SUBDIR): New variable, substituted by configure. + (install-ebl-modules): Install in $(libdir)/$(LIBEBL_SUBDIR). + * eblopenbackend.c (openbackend): Use LIBEBL_SUBDIR in module name. + +2005-07-21 Ulrich Drepper + + * eblcopyrelocp.c: New file. + * Makefile.am (gen_SOURCES): Add eblcopyrelocp.c. + * libebl.h: Declare ebl_copy_reloc_p. + * eblopenbackend.c (fill_defaults): Fill in copy_reloc_p. + (default_copy_reloc_p): New function. + * alpha_init.c: Define and use arch-specific copy_reloc_p function. + * alpha_symbol.c: Likewise. + * arm_init.c: Likewise. + * arm_symbol.c: Likewise. + * i386_init.c: Likewise. + * i386_symbol.c: Likewise. + * ia64_init.c: Likewise. + * ia64_symbol.c: Likewise. + * ppc64_init.c: Likewise. + * ppc64_symbol.c: Likewise. + * ppc_init.c: Likewise. + * ppc_symbol.c: Likewise. + * sh_init.c: Likewise. + * sh_symbol.c: Likewise. + * sparc_init.c: Likewise. + * sparc_symbol.c: Likewise. + * x86_64_init.c: Likewise. + * x86_64_symbol.c: Likewise. + * libebl_alpha.h: Declare the copy_reloc_p function. + * libebl_arm.h: Likewise. + * libebl_i386.h: Likewise. + * libebl_ia64.h: Likewise. + * libebl_ppc.h: Likewise. + * libebl_ppc64.h: Likewise. + * libebl_sh.h: Likewise. + * libebl_sparc.h: Likewise. + * libebl_x86_64.h: Likewise. + +2005-05-31 Roland McGrath + + * Makefile.am (libebl_*_so_SOURCES): Set to $(*_SRCS) so dependency + tracking works right. + +2005-05-21 Ulrich Drepper + + * libebl_x86_64.map: Add x86_64_core_note. + +2005-05-19 Roland McGrath + + * libebl_i386.map: Add i386_reloc_valid_use, i386_reloc_simple_type. + * libebl_ppc.map: Add ppc_reloc_simple_type. + * libebl_ppc64.map: Add ppc64_reloc_simple_type. + * libebl_x86_64.map: Add x86_64_reloc_simple_type. + +2005-05-11 Ulrich Drepper + + * eblcorenote.c: Handle new AT_* values and files with different + endianess. + * Makefile.am (x86_64_SRCS): Add x86_64_corenote.c. + * x86-64_corenote.c: New file. + * x86_64_init.c: Hook in x86_64_corenote. + * i386_corenote.c: Make file usable on 64-bit platforms. + + * eblopenbackend.c: If modules version comparison fails, reinitialize + hooks. + +2005-05-10 Ulrich Drepper + + * eblopenbackend.c: Require the init function to return a string. + Compare it with MODVERSION from config.h. + * alpha_init.c: Change return type. Return MODVERSION or NULL. + * arm_init.c: Likewise. + * eblopenbackend.c: Likewise. + * i386_init.c: Likewise. + * ia64_init.c: Likewise. + * ppc64_init.c: Likewise. + * ppc_init.c: Likewise. + * sh_init.c: Likewise. + * sparc_init.c: Likewise. + * x86_64_init.c: Likewise. + * libeblP.h: Adjust ebl_bhinit_t. + * libebl_alpha.h: Adjust init function prototype. + * libebl_arm.h: Likewise. + * libebl_i386.h: Likewise. + * libebl_ia64.h: Likewise. + * libebl_ppc.h: Likewise. + * libebl_ppc64.h: Likewise. + * libebl_sh.h: Likewise. + * libebl_sparc.h: Likewise. + * libebl_x86_64.h: Likewise. + + * mips_destr.c: Removed. + * mips_init.c: Removed. + * mips_symbol.c: Removed. + * libebl_mips.h: Removed. + * libebl_mips.map: Removed. + +2005-05-03 Roland McGrath + + * libebl.h (Ebl): Add `reloc_simple_type' member. + * eblopenbackend.c (default_reloc_simple_type): New function. + (openbackend): Use that as default reloc_simple_type callback. + * eblrelocsimpletype.c: New file. + * Makefile.am (gen_SOURCES): Add it. + * i386_symbol.c (i386_reloc_simple_type): New function. + * libebl_i386.h: Declare it. + * i386_init.c (i386_init): Use it. + * x86_64_symbol.c (x86_64_reloc_simple_type): New function. + * libebl_x86_64.h: Declare it. + * x86_64_init.c (x86_64_init): Use it. + * ppc_symbol.c (ppc_reloc_simple_type): New function. + * libebl_ppc.h: Declare it. + * ppc_init.c (ppc_init): Use it. + * ppc64_symbol.c (ppc64_reloc_simple_type): New function. + * libebl_ppc64.h: Declare it. + * ppc64_init.c (ppc64_init): Use it. + +2005-03-17 Ulrich Drepper + + * eblcorenote.c (ebl_core_note): Add support for AT_SECURE. + +2005-02-15 Ulrich Drepper + + * Makefile.am (AM_CFLAGS): Add -Wformat=2. + +2005-02-14 Ulrich Drepper + + * alpha_destr.c: Add __attribute__((unused)) where needed. + * alpha_init.c: Likewise. + * alpha_symbol.c: Likewise. + * arm_destr.c: Likewise. + * arm_init.c: Likewise. + * arm_symbol.c: Likewise. + * i386_corenote.c: Likewise. + * i386_destr.c: Likewise. + * i386_init.c: Likewise. + * i386_symbol.c: Likewise. + * ia64_destr.c: Likewise. + * ia64_init.c: Likewise. + * ia64_symbol.c: Likewise. + * mips_destr.c: Likewise. + * mips_init.c: Likewise. + * mips_symbol.c: Likewise. + * ppc64_destr.c: Likewise. + * ppc64_init.c: Likewise. + * ppc64_symbol.c: Likewise. + * ppc_destr.c: Likewise. + * ppc_init.c: Likewise. + * ppc_symbol.c: Likewise. + * sh_destr.c: Likewise. + * sh_init.c: Likewise. + * sh_symbol.c: Likewise. + * sparc_destr.c: Likewise. + * sparc_init.c: Likewise. + * sparc_symbol.c: Likewise. + * x86_64_destr.c: Likewise. + * x86_64_init.c: Likewise. + * x86_64_symbol.c: Likewise. + + * x86_64_symbol.c (reloc_map_table): Fix entries for R_X86_64_64 + and R_X86_64_32.. + +2005-02-06 Ulrich Drepper + + * eblstrtab.c: A few cleanups. + + * eblopenbackend.c: Mark unused parameters. + + * eblgstrtab.c: Cleanups a few printf format strings. + + * Makefile.am: Cleanup AM_CFLAGS handling. Add -Wunused -Wextra. + +2005-02-05 Ulrich Drepper + + * Makefile.am: Check for text relocations in constructed DSOs. + + * eblstrtab.c: Minor cleanups. + + * Makefile.am (AM_CFLAGS): Add -std=gnu99 and -fmudflap for MUDFLAP. + +2004-08-16 Ulrich Drepper + + * Makefile.am (AM_CFLAGS): Add LIBSTR definition with base name of + the lib directory. + * eblopenbackend.c (openbackend): Use LIBSTR instead of hardcoded + lib in path to ebl modules. + +2004-04-01 Ulrich Drepper + + * Makefile.am: Add rules for ppc and ppc64 ebl module. + * ppc_init..c: New file. + * ppc_destr.c: New file. + * ppc_symbol.c: New file. + * libebl_ppc.h: New file. + * libebl_ppc.map: New file. + * ppc64_init..c: New file. + * ppc64_destr.c: New file. + * ppc64_symbol.c: New file. + * libebl_ppc64.h: New file. + * libebl_ppc64.map: New file. + +2004-01-20 Ulrich Drepper + + * Makefile.am: Support building with mudflap. + +2004-01-18 Ulrich Drepper + + * libeblP.h (_): Use elfutils domain. + +2004-01-16 Ulrich Drepper + + * eblsectionname.c: Add support for SHN_BEFORE and SHN_AFTER. + +2004-01-13 Ulrich Drepper + + * eblsegmenttypename.c ((ebl_segment_type_name): Add support for + PT_GNU_RELRO. + +2004-01-08 Ulrich Drepper + + * libebl.h: Remove last traces of libtool. + +2004-01-05 Ulrich Drepper + + * elf-knowledge.h: Move to libelf subdir. + + * Makefile.am (EXTRA_DIST): Remove libebl.map. + * libebl.map: Removed. + +2003-12-08 Ulrich Drepper + + * eblsectiontypename.c (ebl_section_type_name): Add support for + SHT_SUNW_move, SHT_CHECKSUM, and SHT_GNU_LIBLIST. + +2003-11-19 Ulrich Drepper + + * ia64_symbol.c (ia64_dynamic_tag_name): New function. + * libebl_ia64.h (ia64_dynamic_tag_name): Declare. + * ia64_init.c (ia64_init): Register i164_dynamic_tag_name. + +2003-09-24 Ulrich Drepper + + * ia64_init.c (ia64_init): Initialize segment_type_name callback. + * ia64_symbol.c (ia64_segment_type_name): Define. + * libebl_ia64.h (ia64_segment_type_name): Declare. + +2003-09-22 Ulrich Drepper + + * Makefile.am (AM_CFLAGS): Add -fpic. + +2003-08-14 Ulrich Drepper + + * Makefile.am (install): Remove dependency on libebl.so. + +2003-08-13 Ulrich Drepper + + * eblopenbackend.c: Adjust relative path to arch-specific DSOs + assuming the code ends up in the application. Add second dlopen() + try without any path, just the filename. + * Makefile.in: Remove rules to build and install libebl.so. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/libebl/Makefile.am b/libebl/Makefile.am new file mode 100644 index 00000000..5f7be50b --- /dev/null +++ b/libebl/Makefile.am @@ -0,0 +1,201 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. +## +## This program is Open Source software; you can redistribute it and/or +## modify it under the terms of the Open Software License version 1.0 as +## published by the Open Source Initiative. +## +## You should have received a copy of the Open Software License along +## with this program; if not, you may obtain a copy of the Open Software +## License version 1.0 from http://www.opensource.org/licenses/osl.php or +## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +## 3001 King Ranch Road, Ukiah, CA 95482. +## +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -DOBJDIR=\"$(shell pwd)\" +if MUDFLAP +AM_CFLAGS = -fmudflap +else +AM_CFLAGS = +endif +AM_CFLAGS += -fpic -Wall -Wshadow -Werror -Wunused -Wextra -Wformat=2 \ + -std=gnu99 + +INCLUDES = -I$(srcdir) -I$(top_srcdir)/libelf -I$(top_srcdir)/lib -I.. +VERSION = 1 +PACKAGE_VERSION = @PACKAGE_VERSION@ +LIBEBL_SUBDIR = @LIBEBL_SUBDIR@ + +lib_LIBRARIES = libebl.a +modules = i386 sh x86_64 ia64 alpha arm sparc ppc ppc64 +noinst_LIBRARIES = libebl_i386_pic.a libebl_sh_pic.a \ + libebl_x86_64_pic.a libebl_ia64_pic.a libebl_alpha_pic.a \ + libebl_arm_pic.a libebl_sparc_pic.a libebl_ppc_pic.a \ + libebl_ppc64_pic.a +noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so) + +euincludedir = $(includedir)/elfutils +euinclude_HEADERS = libebl.h + +gen_SOURCES = eblopenbackend.c eblclosebackend.c eblstrtab.c \ + eblreloctypename.c eblsegmenttypename.c \ + eblsectiontypename.c eblmachineflagname.c \ + eblsymboltypename.c ebldynamictagname.c eblsectionname.c \ + eblobjecttypename.c eblsymbolbindingname.c \ + eblbackendname.c eblshflagscombine.c eblwstrtab.c \ + eblgstrtab.c eblosabiname.c eblmachineflagcheck.c \ + eblreloctypecheck.c eblrelocvaliduse.c eblrelocsimpletype.c \ + ebldynamictagcheck.c eblcorenotetypename.c eblobjnotetypename.c \ + eblcorenote.c eblobjnote.c ebldebugscnp.c \ + eblgotpcreloccheck.c eblcopyrelocp.c eblsectionstripp.c + +libebl_a_SOURCES = $(gen_SOURCES) + +i386_SRCS = i386_init.c i386_destr.c i386_symbol.c i386_corenote.c +libebl_i386_pic_a_SOURCES = $(i386_SRCS) +am_libebl_i386_pic_a_OBJECTS = $(i386_SRCS:.c=.os) + +if MUDFLAP +libelf = ../libelf/libelf.a +libmudflap = -lmudflap +else +libelf = ../libelf/libelf.so +libmudflap = +endif + +textrel_check = if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi + +libebl_i386_so_SOURCES = +libebl_i386.so: libebl_i386_pic.a libebl_i386.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libebl_i386.map \ + -Wl,-z,defs $(libelf) $(libmudflap) + $(textrel_check) + + +sh_SRCS = sh_init.c sh_destr.c sh_symbol.c +libebl_sh_pic_a_SOURCES = $(sh_SRCS) +am_libebl_sh_pic_a_OBJECTS = $(sh_SRCS:.c=.os) + +libebl_sh_so_SOURCES = +libebl_sh.so: libebl_sh_pic.a libebl_sh.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libebl_sh.map \ + -Wl,-z,defs $(libmudflap) + $(textrel_check) + + +x86_64_SRCS = x86_64_init.c x86_64_destr.c x86_64_symbol.c x86_64_corenote.c +libebl_x86_64_pic_a_SOURCES = $(x86_64_SRCS) +am_libebl_x86_64_pic_a_OBJECTS = $(x86_64_SRCS:.c=.os) + +libebl_x86_64_so_SOURCES = +libebl_x86_64.so: libebl_x86_64_pic.a libebl_x86_64.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libebl_x86_64.map \ + -Wl,-z,defs $(libelf) $(libmudflap) + $(textrel_check) + + +ia64_SRCS = ia64_init.c ia64_destr.c ia64_symbol.c +libebl_ia64_pic_a_SOURCES = $(ia64_SRCS) +am_libebl_ia64_pic_a_OBJECTS = $(ia64_SRCS:.c=.os) + +libebl_ia64_so_SOURCES = +libebl_ia64.so: libebl_ia64_pic.a libebl_ia64.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libebl_ia64.map \ + -Wl,-z,defs $(libmudflap) + $(textrel_check) + + +alpha_SRCS = alpha_init.c alpha_destr.c alpha_symbol.c +libebl_alpha_pic_a_SOURCES = $(alpha_SRCS) +am_libebl_alpha_pic_a_OBJECTS = $(alpha_SRCS:.c=.os) + +libebl_alpha_so_SOURCES = +libebl_alpha.so: libebl_alpha_pic.a libebl_alpha.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libebl_alpha.map \ + -Wl,-z,defs $(libmudflap) + $(textrel_check) + + +arm_SRCS = arm_init.c arm_destr.c arm_symbol.c +libebl_arm_pic_a_SOURCES = $(arm_SRCS) +am_libebl_arm_pic_a_OBJECTS = $(arm_SRCS:.c=.os) + +libebl_arm_so_SOURCES = +libebl_arm.so: libebl_arm_pic.a libebl_arm.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libebl_arm.map \ + -Wl,-z,defs $(libmudflap) + $(textrel_check) + + +sparc_SRCS = sparc_init.c sparc_destr.c sparc_symbol.c +libebl_sparc_pic_a_SOURCES = $(sparc_SRCS) +am_libebl_sparc_pic_a_OBJECTS = $(sparc_SRCS:.c=.os) + +libebl_sparc_so_SOURCES = +libebl_sparc.so: libebl_sparc_pic.a libebl_sparc.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libebl_sparc.map \ + -Wl,-z,defs $(libmudflap) + $(textrel_check) + + +ppc_SRCS = ppc_init.c ppc_destr.c ppc_symbol.c +libebl_ppc_pic_a_SOURCES = $(ppc_SRCS) +am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os) + +libebl_ppc_so_SOURCES = +libebl_ppc.so: libebl_ppc_pic.a libebl_ppc.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libebl_ppc.map \ + -Wl,-z,defs $(libelf) $(libmudflap) + $(textrel_check) + + +ppc64_SRCS = ppc64_init.c ppc64_destr.c ppc64_symbol.c +libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS) +am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os) + +libebl_ppc64_so_SOURCES = +libebl_ppc64.so: libebl_ppc64_pic.a libebl_ppc64.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libebl_ppc64.map \ + -Wl,-z,defs $(libelf) $(libmudflap) + $(textrel_check) + + +%.os: %.c %.o + if $(COMPILE) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \ + -MF "$(DEPDIR)/$*.Tpo" `test -f '$<' || echo '$(srcdir)/'`$<; \ + then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ + rm -f "$(DEPDIR)/$*.Tpo"; \ + else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ + fi + +install: install-am install-ebl-modules +install-ebl-modules: + $(mkinstalldirs) $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR) + for m in $(modules); do \ + $(INSTALL_PROGRAM) libebl_$${m}.so $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}-$(PACKAGE_VERSION).so; \ + ln -fs libebl_$${m}-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}.so; \ + done + +uninstall: uninstall-am + for m in $(modules); do \ + rm -f $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}-$(PACKAGE_VERSION).so; \ + rm -f $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}.so; \ + done + rmdir --ignore-fail-on-non-empty $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR) + rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils + +noinst_HEADERS = libeblP.h $(noinst_LIBRARIES:%_pic.a=%.h) +EXTRA_DIST = $(noinst_LIBRARIES:%_pic.a=%.map) \ + $(foreach m,$(modules),$($(m)_SRCS)) + +CLEANFILES = $(am_libebl_pic_a_OBJECTS) \ + $(foreach m,$(modules),$(am_libebl_$(m)_pic_a_OBJECTS)) diff --git a/libebl/alpha_destr.c b/libebl/alpha_destr.c new file mode 100644 index 00000000..4fc5cf85 --- /dev/null +++ b/libebl/alpha_destr.c @@ -0,0 +1,27 @@ +/* Destructor for Alpha specific backend library. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +void +alpha_destr (bh) + Ebl *bh __attribute__ ((unused)); +{ + /* Nothing to do so far. */ +} diff --git a/libebl/alpha_init.c b/libebl/alpha_init.c new file mode 100644 index 00000000..17eff373 --- /dev/null +++ b/libebl/alpha_init.c @@ -0,0 +1,41 @@ +/* Initialization of Alpha specific backend library. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +const char * +alpha_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Alpha"; + eh->reloc_type_name = alpha_reloc_type_name; + eh->reloc_type_check = alpha_reloc_type_check; + eh->copy_reloc_p = alpha_copy_reloc_p; + eh->destr = alpha_destr; + + return MODVERSION; +} diff --git a/libebl/alpha_symbol.c b/libebl/alpha_symbol.c new file mode 100644 index 00000000..49e7c72f --- /dev/null +++ b/libebl/alpha_symbol.c @@ -0,0 +1,101 @@ +/* Alpha specific symbolic name handling. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +/* Return of the backend. */ +const char * +alpha_backend_name (void) +{ + return "alpha"; +} + + +/* Relocation mapping table. */ +static const char *reloc_map_table[] = + { + [R_ALPHA_NONE] = "R_ALPHA_NONE", + [R_ALPHA_REFLONG] = "R_ALPHA_REFLONG", + [R_ALPHA_REFQUAD] = "R_ALPHA_REFQUAD", + [R_ALPHA_GPREL32] = "R_ALPHA_GPREL32", + [R_ALPHA_LITERAL] = "R_ALPHA_LITERAL", + [R_ALPHA_LITUSE] = "R_ALPHA_LITUSE", + [R_ALPHA_GPDISP] = "R_ALPHA_GPDISP", + [R_ALPHA_BRADDR] = "R_ALPHA_BRADDR", + [R_ALPHA_HINT] = "R_ALPHA_HINT", + [R_ALPHA_SREL16] = "R_ALPHA_SREL16", + [R_ALPHA_SREL32] = "R_ALPHA_SREL32", + [R_ALPHA_SREL64] = "R_ALPHA_SREL64", + [R_ALPHA_GPRELHIGH] = "R_ALPHA_GPRELHIGH", + [R_ALPHA_GPRELLOW] = "R_ALPHA_GPRELLOW", + [R_ALPHA_GPREL16] = "R_ALPHA_GPREL16", + [R_ALPHA_COPY] = "R_ALPHA_COPY", + [R_ALPHA_GLOB_DAT] = "R_ALPHA_GLOB_DAT", + [R_ALPHA_JMP_SLOT] = "R_ALPHA_JMP_SLOT", + [R_ALPHA_RELATIVE] = "R_ALPHA_RELATIVE", + [R_ALPHA_TLS_GD_HI] = "R_ALPHA_TLS_GD_HI", + [R_ALPHA_TLSGD] = "R_ALPHA_TLSGD", + [R_ALPHA_TLS_LDM] = "R_ALPHA_TLS_LDM", + [R_ALPHA_DTPMOD64] = "R_ALPHA_DTPMOD64", + [R_ALPHA_GOTDTPREL] = "R_ALPHA_GOTDTPREL", + [R_ALPHA_DTPREL64] = "R_ALPHA_DTPREL64", + [R_ALPHA_DTPRELHI] = "R_ALPHA_DTPRELHI", + [R_ALPHA_DTPRELLO] = "R_ALPHA_DTPRELLO", + [R_ALPHA_DTPREL16] = "R_ALPHA_DTPREL16", + [R_ALPHA_GOTTPREL] = "R_ALPHA_GOTTPREL", + [R_ALPHA_TPREL64] = "R_ALPHA_TPREL64", + [R_ALPHA_TPRELHI] = "R_ALPHA_TPRELHI", + [R_ALPHA_TPRELLO] = "R_ALPHA_TPRELLO", + [R_ALPHA_TPREL16] = "R_ALPHA_TPREL16" + }; + + +/* Determine relocation type string for Alpha. */ +const char * +alpha_reloc_type_name (int type, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + if (type < 0 + || ((size_t) type + >= sizeof (reloc_map_table) / sizeof (reloc_map_table[0]))) + return NULL; + + return reloc_map_table[type]; +} + + +/* Check for correct relocation type. */ +bool +alpha_reloc_type_check (int type) +{ + return (type >= R_ALPHA_NONE + && ((size_t) type + < sizeof (reloc_map_table) / sizeof (reloc_map_table[0])) + && reloc_map_table[type] != NULL) ? true : false; +} + +/* Check whether given relocation is a copy relocation. */ +bool +alpha_copy_reloc_p (int reloc) +{ + return reloc == R_ALPHA_COPY; +} diff --git a/libebl/arm_destr.c b/libebl/arm_destr.c new file mode 100644 index 00000000..2675720a --- /dev/null +++ b/libebl/arm_destr.c @@ -0,0 +1,27 @@ +/* Destructor for Arm specific backend library. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +void +arm_destr (bh) + Ebl *bh __attribute__ ((unused)); +{ + /* Nothing to do so far. */ +} diff --git a/libebl/arm_init.c b/libebl/arm_init.c new file mode 100644 index 00000000..a0a65f83 --- /dev/null +++ b/libebl/arm_init.c @@ -0,0 +1,41 @@ +/* Initialization of Arm specific backend library. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +const char * +arm_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Arm"; + eh->reloc_type_name = arm_reloc_type_name; + eh->reloc_type_check = arm_reloc_type_check; + eh->copy_reloc_p = arm_copy_reloc_p; + eh->destr = arm_destr; + + return MODVERSION; +} diff --git a/libebl/arm_symbol.c b/libebl/arm_symbol.c new file mode 100644 index 00000000..f4de8be9 --- /dev/null +++ b/libebl/arm_symbol.c @@ -0,0 +1,121 @@ +/* Arm specific symbolic name handling. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +/* Return of the backend. */ +const char * +arm_backend_name (void) +{ + return "arm"; +} + + +/* Relocation mapping table. */ +static const char *reloc_map_table[] = + { + [R_ARM_NONE] = "R_ARM_NONE", + [R_ARM_PC24] = "R_ARM_PC24", + [R_ARM_ABS32] = "R_ARM_ABS32", + [R_ARM_REL32] = "R_ARM_REL32", + [R_ARM_PC13] = "R_ARM_PC13", + [R_ARM_ABS16] = "R_ARM_ABS16", + [R_ARM_ABS12] = "R_ARM_ABS12", + [R_ARM_THM_ABS5] = "R_ARM_THM_ABS5", + [R_ARM_ABS8] = "R_ARM_ABS8", + [R_ARM_SBREL32] = "R_ARM_SBREL32", + [R_ARM_THM_PC22] = "R_ARM_THM_PC22", + [R_ARM_THM_PC8] = "R_ARM_THM_PC8", + [R_ARM_AMP_VCALL9] = "R_ARM_AMP_VCALL9", + [R_ARM_SWI24] = "R_ARM_SWI24", + [R_ARM_THM_SWI8] = "R_ARM_THM_SWI8", + [R_ARM_XPC25] = "R_ARM_XPC25", + [R_ARM_THM_XPC22] = "R_ARM_THM_XPC22", + [R_ARM_COPY] = "R_ARM_COPY", + [R_ARM_GLOB_DAT] = "R_ARM_GLOB_DAT", + [R_ARM_JUMP_SLOT] = "R_ARM_JUMP_SLOT", + [R_ARM_RELATIVE] = "R_ARM_RELATIVE", + [R_ARM_GOTOFF] = "R_ARM_GOTOFF", + [R_ARM_GOTPC] = "R_ARM_GOTPC", + [R_ARM_GOT32] = "R_ARM_GOT32", + [R_ARM_PLT32] = "R_ARM_PLT32", + [R_ARM_ALU_PCREL_7_0] = "R_ARM_ALU_PCREL_7_0", + [R_ARM_ALU_PCREL_15_8] = "R_ARM_ALU_PCREL_15_8", + [R_ARM_ALU_PCREL_23_15] = "R_ARM_ALU_PCREL_23_15", + [R_ARM_LDR_SBREL_11_0] = "R_ARM_LDR_SBREL_11_0", + [R_ARM_ALU_SBREL_19_12] = "R_ARM_ALU_SBREL_19_12", + [R_ARM_ALU_SBREL_27_20] = "R_ARM_ALU_SBREL_27_20" + }; + +static const char *reloc_map_table2[] = + { + [R_ARM_GNU_VTENTRY] = "R_ARM_GNU_VTENTRY", + [R_ARM_GNU_VTINHERIT] = "R_ARM_GNU_VTINHERIT", + [R_ARM_THM_PC11] = "R_ARM_THM_PC11", + [R_ARM_THM_PC9] = "R_ARM_THM_PC9" + }; + +static const char *reloc_map_table3[] = + { + [R_ARM_RXPC25] = "R_ARM_RXPC25", + [R_ARM_RSBREL32] = "R_ARM_RSBREL32", + [R_ARM_THM_RPC22] = "R_ARM_THM_RPC22", + [R_ARM_RREL32] = "R_ARM_RREL32", + [R_ARM_RABS22] = "R_ARM_RABS22", + [R_ARM_RPC24] = "R_ARM_RPC24", + [R_ARM_RBASE] = "R_ARM_RBASE" + }; + + +/* Determine relocation type string for Alpha. */ +const char * +arm_reloc_type_name (int type, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + if (type >= R_ARM_NONE && type <= R_ARM_ALU_SBREL_27_20) + return reloc_map_table[type]; + + if (type >= R_ARM_GNU_VTENTRY && type <= R_ARM_THM_PC9) + return reloc_map_table2[type - R_ARM_GNU_VTENTRY]; + + if (type >= R_ARM_RXPC25 && type <= R_ARM_RBASE) + return reloc_map_table3[type - R_ARM_RXPC25]; + + return NULL; +} + + +/* Check for correct relocation type. */ +bool +arm_reloc_type_check (int type) +{ + return ((type >= R_ARM_NONE && type <= R_ARM_ALU_SBREL_27_20) + || (type >= R_ARM_GNU_VTENTRY && type <= R_ARM_THM_PC9) + || (type >= R_ARM_RXPC25 && type <= R_ARM_RBASE)) ? true : false; +} + +/* Check whether given relocation is a copy relocation. */ +bool +arm_copy_reloc_p (int reloc) +{ + return reloc == R_ARM_COPY; +} diff --git a/libebl/eblbackendname.c b/libebl/eblbackendname.c new file mode 100644 index 00000000..03830ebe --- /dev/null +++ b/libebl/eblbackendname.c @@ -0,0 +1,28 @@ +/* Return backend name. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +const char * +ebl_backend_name (ebl) + Ebl *ebl; +{ + return ebl != NULL ? ebl->emulation : gettext ("No backend"); +} diff --git a/libebl/eblclosebackend.c b/libebl/eblclosebackend.c new file mode 100644 index 00000000..c5579612 --- /dev/null +++ b/libebl/eblclosebackend.c @@ -0,0 +1,39 @@ +/* Free ELF backend handle. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +void +ebl_closebackend (Ebl *ebl) +{ + if (ebl != NULL) + { + /* Run the destructor. */ + ebl->destr (ebl); + + /* Close the dynamically loaded object. */ + if (ebl->dlhandle != NULL) + (void) dlclose (ebl->dlhandle); + + /* Free the resources. */ + free (ebl); + } +} diff --git a/libebl/eblcopyrelocp.c b/libebl/eblcopyrelocp.c new file mode 100644 index 00000000..2d3362a2 --- /dev/null +++ b/libebl/eblcopyrelocp.c @@ -0,0 +1,28 @@ +/* Check whether given relocation is a copy relocation. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +bool +ebl_copy_reloc_p (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl->copy_reloc_p (reloc); +} diff --git a/libebl/eblcorenote.c b/libebl/eblcorenote.c new file mode 100644 index 00000000..725d3a1b --- /dev/null +++ b/libebl/eblcorenote.c @@ -0,0 +1,191 @@ +/* Print contents of core note. + Copyright (C) 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + + +void +ebl_core_note (ebl, name, type, descsz, desc) + Ebl *ebl; + const char *name; + uint32_t type; + uint32_t descsz; + const char *desc; +{ + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (ebl->elf, &ehdr_mem); + assert (ehdr != NULL); + int class = ehdr->e_ident[EI_CLASS]; + int endian = ehdr->e_ident[EI_DATA]; + + if (! ebl->core_note (name, type, descsz, desc)) + /* The machine specific function did not know this type. */ + switch (type) + { + case NT_PLATFORM: + printf (gettext (" Platform: %.*s\n"), (int) descsz, desc); + break; + + case NT_AUXV: + ; + size_t elsize = (class == ELFCLASS32 + ? sizeof (Elf32_auxv_t) : sizeof (Elf64_auxv_t)); + + for (size_t cnt = 0; (cnt + 1) * elsize <= descsz; ++cnt) + { + uintmax_t atype; + uintmax_t val; + + if (class == ELFCLASS32) + { + Elf32_auxv_t *auxv = &((Elf32_auxv_t *) desc)[cnt]; + + if ((endian == ELFDATA2LSB && __BYTE_ORDER == __LITTLE_ENDIAN) + || (endian == ELFDATA2MSB && __BYTE_ORDER == __BIG_ENDIAN)) + { + atype = auxv->a_type; + val = auxv->a_un.a_val; + } + else + { + atype = bswap_32 (auxv->a_type); + val = bswap_32 (auxv->a_un.a_val); + } + } + else + { + Elf64_auxv_t *auxv = &((Elf64_auxv_t *) desc)[cnt]; + + if ((endian == ELFDATA2LSB && __BYTE_ORDER == __LITTLE_ENDIAN) + || (endian == ELFDATA2MSB && __BYTE_ORDER == __BIG_ENDIAN)) + { + atype = auxv->a_type; + val = auxv->a_un.a_val; + } + else + { + atype = bswap_64 (auxv->a_type); + val = bswap_64 (auxv->a_un.a_val); + } + } + + /* XXX Do we need the auxiliary vector info anywhere + else? If yes, move code into a separate function. */ + const char *at; + + switch (atype) + { +#define NEW_AT(name) case AT_##name: at = #name; break + NEW_AT (NULL); + NEW_AT (IGNORE); + NEW_AT (EXECFD); + NEW_AT (PHDR); + NEW_AT (PHENT); + NEW_AT (PHNUM); + NEW_AT (PAGESZ); + NEW_AT (BASE); + NEW_AT (FLAGS); + NEW_AT (ENTRY); + NEW_AT (NOTELF); + NEW_AT (UID); + NEW_AT (EUID); + NEW_AT (GID); + NEW_AT (EGID); + NEW_AT (CLKTCK); + NEW_AT (PLATFORM); + NEW_AT (HWCAP); + NEW_AT (FPUCW); + NEW_AT (DCACHEBSIZE); + NEW_AT (ICACHEBSIZE); + NEW_AT (UCACHEBSIZE); + NEW_AT (IGNOREPPC); + NEW_AT (SECURE); + NEW_AT (SYSINFO); + NEW_AT (SYSINFO_EHDR); + NEW_AT (L1I_CACHESHAPE); + NEW_AT (L1D_CACHESHAPE); + NEW_AT (L2_CACHESHAPE); + NEW_AT (L3_CACHESHAPE); + + default:; + static char buf[30]; + sprintf (buf, "%ju (AT_?""?""?)", atype); + at = buf; + break; + } + + switch (atype) + { + case AT_NULL: + case AT_IGNORE: + case AT_IGNOREPPC: + case AT_NOTELF: + default: + printf (" %s\n", at); + break; + + case AT_EXECFD: + case AT_PHENT: + case AT_PHNUM: + case AT_PAGESZ: + case AT_UID: + case AT_EUID: + case AT_GID: + case AT_EGID: + case AT_CLKTCK: + case AT_FPUCW: + case AT_DCACHEBSIZE: + case AT_ICACHEBSIZE: + case AT_UCACHEBSIZE: + case AT_SECURE: + case AT_L1I_CACHESHAPE: + case AT_L1D_CACHESHAPE: + case AT_L2_CACHESHAPE: + case AT_L3_CACHESHAPE: + printf (" %s: %jd\n", at, val); + break; + + case AT_PHDR: + case AT_BASE: + case AT_FLAGS: /* XXX Print flags? */ + case AT_ENTRY: + case AT_PLATFORM: /* XXX Get string? */ + case AT_HWCAP: /* XXX Print flags? */ + case AT_SYSINFO: + case AT_SYSINFO_EHDR: + printf (" %s: %#jx\n", at, val); + break; + } + + if (atype == AT_NULL) + /* Reached the end. */ + break; + } + break; + + default: + /* Unknown type. */ + break; + } +} diff --git a/libebl/eblcorenotetypename.c b/libebl/eblcorenotetypename.c new file mode 100644 index 00000000..4a94d2ba --- /dev/null +++ b/libebl/eblcorenotetypename.c @@ -0,0 +1,68 @@ +/* Return note type name. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + + +const char * +ebl_core_note_type_name (ebl, type, buf, len) + Ebl *ebl; + uint32_t type; + char *buf; + size_t len; +{ + const char *res = ebl->core_note_type_name (type, buf, len); + + if (res == NULL) + { + static const char *knowntypes[] = + { +#define KNOWNSTYPE(name) [NT_##name] = #name + KNOWNSTYPE (PRSTATUS), + KNOWNSTYPE (FPREGSET), + KNOWNSTYPE (PRPSINFO), + KNOWNSTYPE (TASKSTRUCT), + KNOWNSTYPE (PLATFORM), + KNOWNSTYPE (AUXV), + KNOWNSTYPE (GWINDOWS), + KNOWNSTYPE (ASRS), + KNOWNSTYPE (PSTATUS), + KNOWNSTYPE (PSINFO), + KNOWNSTYPE (PRCRED), + KNOWNSTYPE (UTSNAME), + KNOWNSTYPE (LWPSTATUS), + KNOWNSTYPE (LWPSINFO), + KNOWNSTYPE (PRFPXREG) + }; + + /* Handle standard names. */ + if (type < sizeof (knowntypes) / sizeof (knowntypes[0]) + && knowntypes[type] != NULL) + res = knowntypes[type]; + else + { + snprintf (buf, len, "%s: %" PRIu32, gettext (""), type); + + res = buf; + } + } + + return res; +} diff --git a/libebl/ebldebugscnp.c b/libebl/ebldebugscnp.c new file mode 100644 index 00000000..59310b51 --- /dev/null +++ b/libebl/ebldebugscnp.c @@ -0,0 +1,29 @@ +/* Check section name for being that of a debug informatino section. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +bool +ebl_debugscn_p (ebl, name) + Ebl *ebl; + const char *name; +{ + return ebl->debugscn_p (name); +} diff --git a/libebl/ebldynamictagcheck.c b/libebl/ebldynamictagcheck.c new file mode 100644 index 00000000..68b41691 --- /dev/null +++ b/libebl/ebldynamictagcheck.c @@ -0,0 +1,41 @@ +/* Check dynamic tag. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +bool +ebl_dynamic_tag_check (ebl, tag) + Ebl *ebl; + int64_t tag; +{ + bool res = ebl != NULL ? ebl->dynamic_tag_check (tag) : false; + + if (!res + && ((tag >= 0 && tag < DT_NUM) + || (tag >= DT_GNU_PRELINKED && tag <= DT_SYMINENT) + || (tag >= DT_GNU_CONFLICT && tag <= DT_SYMINFO) + || tag == DT_VERSYM + || (tag >= DT_RELACOUNT && tag <= DT_VERNEEDNUM) + || tag == DT_AUXILIARY + || tag == DT_FILTER)) + res = true; + + return res; +} diff --git a/libebl/ebldynamictagname.c b/libebl/ebldynamictagname.c new file mode 100644 index 00000000..464c1e2a --- /dev/null +++ b/libebl/ebldynamictagname.c @@ -0,0 +1,97 @@ +/* Return dynamic tag name. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + + +const char * +ebl_dynamic_tag_name (ebl, tag, buf, len) + Ebl *ebl; + int64_t tag; + char *buf; + size_t len; +{ + const char *res = ebl != NULL ? ebl->dynamic_tag_name (tag, buf, len) : NULL; + + if (res == NULL) + { + if (tag >= 0 && tag < DT_NUM) + { + static const char *stdtags[] = + { + "NULL", "NEEDED", "PLTRELSZ", "PLTGOT", "HASH", "STRTAB", + "SYMTAB", "RELA", "RELASZ", "RELAENT", "STRSZ", "SYMENT", + "INIT", "FINI", "SONAME", "RPATH", "SYMBOLIC", "REL", "RELSZ", + "RELENT", "PLTREL", "DEBUG", "TEXTREL", "JMPREL", "BIND_NOW", + "INIT_ARRAY", "FINI_ARRAY", "INIT_ARRAYSZ", "FINI_ARRAYSZ", + "RUNPATH", "FLAGS", "ENCODING", "PREINIT_ARRAY", + "PREINIT_ARRAYSZ" + }; + + res = stdtags[tag]; + } + else if (tag == DT_VERSYM) + res = "VERSYM"; + else if (tag >= DT_GNU_PRELINKED && tag <= DT_SYMINENT) + { + static const char *valrntags[] = + { + "GNU_PRELINKED", "GNU_CONFLICTSZ", "GNU_LIBLISTSZ", + "CHECKSUM", "PLTPADSZ", "MOVEENT", "MOVESZ", "FEATURE_1", + "POSFLAG_1", "SYMINSZ", "SYMINENT" + }; + + res = valrntags[tag - DT_GNU_PRELINKED]; + } + else if (tag >= DT_GNU_CONFLICT && tag <= DT_SYMINFO) + { + static const char *addrrntags[] = + { + "GNU_CONFLICT", "GNU_LIBLIST", "CONFIG", "DEPAUDIT", "AUDIT", + "PLTPAD", "MOVETAB", "SYMINFO" + }; + + res = addrrntags[tag - DT_GNU_CONFLICT]; + } + else if (tag >= DT_RELACOUNT && tag <= DT_VERNEEDNUM) + { + static const char *suntags[] = + { + "RELACOUNT", "RELCOUNT", "FLAGS_1", "VERDEF", "VERDEFNUM", + "VERNEED", "VERNEEDNUM" + }; + + res = suntags[tag - DT_RELACOUNT]; + } + else if (tag == DT_AUXILIARY) + res = "AUXILIARY"; + else if (tag == DT_FILTER) + res = "FILTER"; + else + { + snprintf (buf, len, gettext (": %" PRId64), tag); + + res = buf; + + } + } + + return res; +} diff --git a/libebl/eblgotpcreloccheck.c b/libebl/eblgotpcreloccheck.c new file mode 100644 index 00000000..8ae8b7b8 --- /dev/null +++ b/libebl/eblgotpcreloccheck.c @@ -0,0 +1,29 @@ +/* Return true if the symbol type is that referencing the GOT. E.g., + R_386_GOTPC. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +bool +ebl_gotpc_reloc_check (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl != NULL ? ebl->gotpc_reloc_check (ebl->elf, reloc) : false; +} diff --git a/libebl/eblgstrtab.c b/libebl/eblgstrtab.c new file mode 100644 index 00000000..57cb2d8f --- /dev/null +++ b/libebl/eblgstrtab.c @@ -0,0 +1,350 @@ +/* Generic string table handling. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libebl.h" + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + + +struct Ebl_GStrent +{ + const char *string; + size_t len; + struct Ebl_GStrent *next; + struct Ebl_GStrent *left; + struct Ebl_GStrent *right; + size_t offset; + unsigned int width; + char reverse[0]; +}; + + +struct memoryblock +{ + struct memoryblock *next; + char memory[0]; +}; + + +struct Ebl_GStrtab +{ + struct Ebl_GStrent *root; + struct memoryblock *memory; + char *backp; + size_t left; + size_t total; + unsigned int width; + bool nullstr; + + struct Ebl_GStrent null; +}; + + +/* Cache for the pagesize. We correct this value a bit so that `malloc' + is not allocating more than a page. */ +static size_t ps; + + +struct Ebl_GStrtab * +ebl_gstrtabinit (unsigned int width, bool nullstr) +{ + struct Ebl_GStrtab *ret; + + if (ps == 0) + { + ps = sysconf (_SC_PAGESIZE) - 2 * sizeof (void *); + assert (sizeof (struct memoryblock) < ps); + } + + ret = (struct Ebl_GStrtab *) calloc (1, sizeof (struct Ebl_GStrtab)); + if (ret != NULL) + { + ret->width = width; + ret->nullstr = nullstr; + + if (nullstr) + { + ret->null.len = 1; + ret->null.string = (char *) calloc (1, width); + } + } + + return ret; +} + + +static void +morememory (struct Ebl_GStrtab *st, size_t len) +{ + struct memoryblock *newmem; + + if (len < ps) + len = ps; + newmem = (struct memoryblock *) malloc (len); + if (newmem == NULL) + abort (); + + newmem->next = st->memory; + st->memory = newmem; + st->backp = newmem->memory; + st->left = len - offsetof (struct memoryblock, memory); +} + + +void +ebl_gstrtabfree (struct Ebl_GStrtab *st) +{ + struct memoryblock *mb = st->memory; + + while (mb != NULL) + { + void *old = mb; + mb = mb->next; + free (old); + } + + if (st->null.string != NULL) + free ((char *) st->null.string); + + free (st); +} + + +static struct Ebl_GStrent * +newstring (struct Ebl_GStrtab *st, const char *str, size_t len) +{ + /* Compute the amount of padding needed to make the structure aligned. */ + size_t align = ((__alignof__ (struct Ebl_GStrent) + - (((uintptr_t) st->backp) + & (__alignof__ (struct Ebl_GStrent) - 1))) + & (__alignof__ (struct Ebl_GStrent) - 1)); + + /* Make sure there is enough room in the memory block. */ + if (st->left < align + sizeof (struct Ebl_GStrent) + len * st->width) + { + morememory (st, sizeof (struct Ebl_GStrent) + len * st->width); + align = 0; + } + + /* Create the reserved string. */ + struct Ebl_GStrent *newstr = (struct Ebl_GStrent *) (st->backp + align); + newstr->string = str; + newstr->len = len; + newstr->width = st->width; + newstr->next = NULL; + newstr->left = NULL; + newstr->right = NULL; + newstr->offset = 0; + for (int i = len - 2; i >= 0; --i) + for (int j = st->width - 1; j >= 0; --j) + newstr->reverse[i * st->width + j] = str[(len - 2 - i) * st->width + j]; + for (size_t j = 0; j < st->width; ++j) + newstr->reverse[(len - 1) * st->width + j] = '\0'; + st->backp += align + sizeof (struct Ebl_GStrent) + len * st->width; + st->left -= align + sizeof (struct Ebl_GStrent) + len * st->width; + + return newstr; +} + + +/* XXX This function should definitely be rewritten to use a balancing + tree algorith (AVL, red-black trees). For now a simple, correct + implementation is enough. */ +static struct Ebl_GStrent ** +searchstring (struct Ebl_GStrent **sep, struct Ebl_GStrent *newstr) +{ + int cmpres; + + /* More strings? */ + if (*sep == NULL) + { + *sep = newstr; + return sep; + } + + /* Compare the strings. */ + cmpres = memcmp ((*sep)->reverse, newstr->reverse, + (MIN ((*sep)->len, newstr->len) - 1) * (*sep)->width); + if (cmpres == 0) + /* We found a matching string. */ + return sep; + else if (cmpres > 0) + return searchstring (&(*sep)->left, newstr); + else + return searchstring (&(*sep)->right, newstr); +} + + +/* Add new string. The actual string is assumed to be permanent. */ +struct Ebl_GStrent * +ebl_gstrtabadd (struct Ebl_GStrtab *st, const char *str, size_t len) +{ + struct Ebl_GStrent *newstr; + struct Ebl_GStrent **sep; + + /* Compute the string length if the caller doesn't know it. */ + if (len == 0) + { + size_t j; + + do + for (j = 0; j < st->width; ++j) + if (str[len * st->width + j] != '\0') + break; + while (j == st->width && ++len); + } + + /* Make sure all "" strings get offset 0 but only if the table was + created with a special null entry in mind. */ + if (len == 1 && st->null.string != NULL) + return &st->null; + + /* Allocate memory for the new string and its associated information. */ + newstr = newstring (st, str, len); + + /* Search in the array for the place to insert the string. If there + is no string with matching prefix and no string with matching + leading substring, create a new entry. */ + sep = searchstring (&st->root, newstr); + if (*sep != newstr) + { + /* This is not the same entry. This means we have a prefix match. */ + if ((*sep)->len > newstr->len) + { + struct Ebl_GStrent *subs; + + /* Check whether we already know this string. */ + for (subs = (*sep)->next; subs != NULL; subs = subs->next) + if (subs->len == newstr->len) + { + /* We have an exact match with a substring. Free the memory + we allocated. */ + st->left += (st->backp - (char *) newstr) * st->width; + st->backp = (char *) newstr; + + return subs; + } + + /* We have a new substring. This means we don't need the reverse + string of this entry anymore. */ + st->backp -= newstr->len; + st->left += newstr->len; + + newstr->next = (*sep)->next; + (*sep)->next = newstr; + } + else if ((*sep)->len != newstr->len) + { + /* When we get here it means that the string we are about to + add has a common prefix with a string we already have but + it is longer. In this case we have to put it first. */ + st->total += newstr->len - (*sep)->len; + newstr->next = *sep; + newstr->left = (*sep)->left; + newstr->right = (*sep)->right; + *sep = newstr; + } + else + { + /* We have an exact match. Free the memory we allocated. */ + st->left += (st->backp - (char *) newstr) * st->width; + st->backp = (char *) newstr; + + newstr = *sep; + } + } + else + st->total += newstr->len; + + return newstr; +} + + +static void +copystrings (struct Ebl_GStrent *nodep, char **freep, size_t *offsetp) +{ + struct Ebl_GStrent *subs; + + if (nodep->left != NULL) + copystrings (nodep->left, freep, offsetp); + + /* Process the current node. */ + nodep->offset = *offsetp; + *freep = (char *) mempcpy (*freep, nodep->string, nodep->len * nodep->width); + *offsetp += nodep->len * nodep->width; + + for (subs = nodep->next; subs != NULL; subs = subs->next) + { + assert (subs->len < nodep->len); + subs->offset = nodep->offset + (nodep->len - subs->len) * nodep->width; + assert (subs->offset != 0 || subs->string[0] == '\0'); + } + + if (nodep->right != NULL) + copystrings (nodep->right, freep, offsetp); +} + + +void +ebl_gstrtabfinalize (struct Ebl_GStrtab *st, Elf_Data *data) +{ + size_t copylen; + char *endp; + size_t nulllen = st->nullstr ? st->width : 0; + + /* Fill in the information. */ + data->d_buf = malloc (st->total + nulllen); + if (data->d_buf == NULL) + abort (); + + /* The first byte must always be zero if we created the table with a + null string. */ + if (st->nullstr) + memset (data->d_buf, '\0', st->width); + + data->d_type = ELF_T_BYTE; + data->d_size = st->total + nulllen; + data->d_off = 0; + data->d_align = 1; + data->d_version = EV_CURRENT; + + /* Now run through the tree and add all the string while also updating + the offset members of the elfstrent records. */ + endp = (char *) data->d_buf + nulllen; + copylen = nulllen; + copystrings (st->root, &endp, ©len); + assert (copylen == st->total * st->width + nulllen); +} + + +size_t +ebl_gstrtaboffset (struct Ebl_GStrent *se) +{ + return se->offset; +} diff --git a/libebl/eblmachineflagcheck.c b/libebl/eblmachineflagcheck.c new file mode 100644 index 00000000..abc8d302 --- /dev/null +++ b/libebl/eblmachineflagcheck.c @@ -0,0 +1,28 @@ +/* Check machine flag. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +bool +ebl_machine_flag_check (ebl, flags) + Ebl *ebl; + Elf64_Word flags; +{ + return ebl != NULL ? ebl->machine_flag_check (flags) : (flags == 0); +} diff --git a/libebl/eblmachineflagname.c b/libebl/eblmachineflagname.c new file mode 100644 index 00000000..228a9945 --- /dev/null +++ b/libebl/eblmachineflagname.c @@ -0,0 +1,76 @@ +/* Return machine flag names. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + + +const char * +ebl_machine_flag_name (ebl, flags, buf, len) + Ebl *ebl; + Elf64_Word flags; + char *buf; + size_t len; +{ + const char *res; + + if (flags == 0) + res = ""; + else + { + char *cp = buf; + int first = 1; + const char *machstr; + size_t machstrlen; + + do + { + if (! first) + { + if (cp + 1 >= buf + len) + break; + *cp++ = ','; + } + + machstr = ebl != NULL ? ebl->machine_flag_name (&flags) : NULL; + if (machstr == NULL) + { + /* No more known flag. */ + snprintf (cp, buf + len - cp, "%#x", flags); + break; + } + + machstrlen = strlen (machstr) + 1; + if ((size_t) (buf + len - cp) < machstrlen) + { + *((char *) mempcpy (cp, machstr, buf + len - cp - 1)) = '\0'; + break; + } + + cp = mempcpy (cp, machstr, machstrlen); + + first = 0; + } + while (flags != 0); + + res = buf; + } + + return res; +} diff --git a/libebl/eblobjecttypename.c b/libebl/eblobjecttypename.c new file mode 100644 index 00000000..c099c71d --- /dev/null +++ b/libebl/eblobjecttypename.c @@ -0,0 +1,48 @@ +/* Return object file type name. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +const char * +ebl_object_type_name (ebl, object, buf, len) + Ebl *ebl; + int object; + char *buf; + size_t len; +{ + const char *res; + + res = ebl != NULL ? ebl->object_type_name (object, buf, len) : NULL; + if (res == NULL) + { + /* Handle OS-specific section names. */ + if (object >= ET_LOOS && object <= ET_HIOS) + snprintf (buf, len, "LOOS+%x", object - ET_LOOS); + /* Handle processor-specific section names. */ + else if (object >= ET_LOPROC && object <= ET_HIPROC) + snprintf (buf, len, "LOPROC+%x", object - ET_LOPROC); + else + snprintf (buf, len, "%s: %d", gettext (""), object); + + res = buf; + } + + return res; +} diff --git a/libebl/eblobjnote.c b/libebl/eblobjnote.c new file mode 100644 index 00000000..5adff18e --- /dev/null +++ b/libebl/eblobjnote.c @@ -0,0 +1,87 @@ +/* Print contents of object file note. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + + +void +ebl_object_note (ebl, name, type, descsz, desc) + Ebl *ebl; + const char *name; + uint32_t type; + uint32_t descsz; + const char *desc; +{ + if (! ebl->object_note (name, type, descsz, desc)) + /* The machine specific function did not know this type. */ + switch (type) + { + case NT_VERSION: + if (strcmp (name, "GNU") == 0 && descsz >= 8) + { + struct + { + uint32_t os; + uint32_t version[descsz / 4 - 1]; + } *tag = (__typeof (tag)) desc; + + const char *os; + switch (tag->os) + { + case ELF_NOTE_OS_LINUX: + os = "Linux"; + break; + + case ELF_NOTE_OS_GNU: + os = "GNU"; + break; + + case ELF_NOTE_OS_SOLARIS2: + os = "Solaris"; + break; + + case ELF_NOTE_OS_FREEBSD: + os = "FreeBSD"; + break; + + default: + os = "???"; + break; + } + + printf (gettext (" OS: %s, ABI: "), os); + size_t cnt; + for (cnt = 0; cnt < descsz / 4 - 1; ++cnt) + { + if (cnt != 0) + putchar_unlocked ('.'); + printf ("%" PRIu32, tag->version[cnt]); + } + putchar_unlocked ('\n'); + break; + } + /* FALLTHROUGH */ + + default: + /* Unknown type. */ + break; + } +} diff --git a/libebl/eblobjnotetypename.c b/libebl/eblobjnotetypename.c new file mode 100644 index 00000000..a963cefb --- /dev/null +++ b/libebl/eblobjnotetypename.c @@ -0,0 +1,54 @@ +/* Return note type name. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + + +const char * +ebl_object_note_type_name (ebl, type, buf, len) + Ebl *ebl; + uint32_t type; + char *buf; + size_t len; +{ + const char *res = ebl->object_note_type_name (type, buf, len); + + if (res == NULL) + { + static const char *knowntypes[] = + { +#define KNOWNSTYPE(name) [NT_##name] = #name + KNOWNSTYPE (VERSION), + }; + + /* Handle standard names. */ + if (type < sizeof (knowntypes) / sizeof (knowntypes[0]) + && knowntypes[type] != NULL) + res = knowntypes[type]; + else + { + snprintf (buf, len, "%s: %" PRIu32, gettext (""), type); + + res = buf; + } + } + + return res; +} diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c new file mode 100644 index 00000000..dc2f7c30 --- /dev/null +++ b/libebl/eblopenbackend.c @@ -0,0 +1,551 @@ +/* Generate ELF backend handle. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include + + +/* This table should contain the complete list of architectures as far + as the ELF specification is concerned. */ +/* XXX When things are stable replace the string pointers with char + arrays to avoid relocations. */ +static const struct +{ + const char *dsoname; + const char *emulation; + const char *prefix; + int prefix_len; + int em; +} machines[] = +{ + { "i386", "elf_i386", "i386", 4, EM_386 }, + { "ia64", "elf_ia64", "ia64", 4, EM_IA_64 }, + { "alpha", "elf_alpha", "alpha", 5, EM_ALPHA }, + { "x86_64", "elf_x86_64", "x86_64", 6, EM_X86_64 }, + { "sh", "elf_sh", "sh", 2, EM_SH }, + { "arm", "ebl_arm", "arm", 3, EM_ARM }, + { "sparc", "elf_sparcv9", "sparc", 5, EM_SPARCV9 }, + { "sparc", "elf_sparc", "sparc", 5, EM_SPARC }, + { "sparc", "elf_sparcv8plus", "sparc", 5, EM_SPARC32PLUS }, + + { "m32", "elf_m32", "m32", 3, EM_M32 }, + { "m68k", "elf_m68k", "m68k", 4, EM_68K }, + { "m88k", "elf_m88k", "m88k", 4, EM_88K }, + { "i860", "elf_i860", "i860", 4, EM_860 }, + { "mips", "elf_mips", "mips", 4, EM_MIPS }, + { "s370", "ebl_s370", "s370", 4, EM_S370 }, + { "mips", "elf_mipsel", "mips", 4, EM_MIPS_RS3_LE }, + { "parisc", "elf_parisc", "parisc", 6, EM_PARISC }, + { "vpp500", "elf_vpp500", "vpp500", 5, EM_VPP500 }, + { "sparc", "elf_v8plus", "v8plus", 6, EM_SPARC32PLUS }, + { "i960", "elf_i960", "i960", 4, EM_960 }, + { "ppc", "elf_ppc", "ppc", 3, EM_PPC }, + { "ppc64", "elf_ppc64", "ppc64", 5, EM_PPC64 }, + { "s390", "ebl_s390", "s390", 4, EM_S390 }, + { "v800", "ebl_v800", "v800", 4, EM_V800 }, + { "fr20", "ebl_fr20", "fr20", 4, EM_FR20 }, + { "rh32", "ebl_rh32", "rh32", 4, EM_RH32 }, + { "rce", "ebl_rce", "rce", 3, EM_RCE }, + { "tricore", "elf_tricore", "tricore", 7, EM_TRICORE }, + { "arc", "elf_arc", "arc", 3, EM_ARC }, + { "h8", "elf_h8_300", "h8_300", 6, EM_H8_300 }, + { "h8", "elf_h8_300h", "h8_300h", 6, EM_H8_300H }, + { "h8", "elf_h8s", "h8s", 6, EM_H8S }, + { "h8", "elf_h8_500", "h8_500", 6, EM_H8_500 }, + { "mips_x", "elf_mips_x", "mips_x", 6, EM_MIPS_X }, + { "coldfire", "elf_coldfire", "coldfire", 8, EM_COLDFIRE }, + { "m68k", "elf_68hc12", "68hc12", 6, EM_68HC12 }, + { "mma", "elf_mma", "mma", 3, EM_MMA }, + { "pcp", "elf_pcp", "pcp", 3, EM_PCP }, + { "ncpu", "elf_ncpu", "ncpu", 4, EM_NCPU }, + { "ndr1", "elf_ndr1", "ndr1", 4, EM_NDR1 }, + { "starcore", "elf_starcore", "starcore", 8, EM_STARCORE }, + { "me16", "elf_me16", "em16", 4, EM_ME16 }, + { "st100", "elf_st100", "st100", 5, EM_ST100 }, + { "tinyj", "elf_tinyj", "tinyj", 5, EM_TINYJ }, + { "pdsp", "elf_pdsp", "pdsp", 4, EM_PDSP }, + { "fx66", "elf_fx66", "fx66", 4, EM_FX66 }, + { "st9plus", "elf_st9plus", "st9plus", 7, EM_ST9PLUS }, + { "st7", "elf_st7", "st7", 3, EM_ST7 }, + { "m68k", "elf_68hc16", "68hc16", 6, EM_68HC16 }, + { "m68k", "elf_68hc11", "68hc11", 6, EM_68HC11 }, + { "m68k", "elf_68hc08", "68hc08", 6, EM_68HC08 }, + { "m68k", "elf_68hc05", "68hc05", 6, EM_68HC05 }, + { "svx", "elf_svx", "svx", 3, EM_SVX }, + { "st19", "elf_st19", "st19", 4, EM_ST19 }, + { "vax", "elf_vax", "vax", 3, EM_VAX }, + { "cris", "elf_cris", "cris", 4, EM_CRIS }, + { "javelin", "elf_javelin", "javelin", 7, EM_JAVELIN }, + { "firepath", "elf_firepath", "firepath", 8, EM_FIREPATH }, + { "zsp", "elf_zsp", "zsp", 3, EM_ZSP}, + { "mmix", "elf_mmix", "mmix", 4, EM_MMIX }, + { "hunay", "elf_huany", "huany", 5, EM_HUANY }, + { "prism", "elf_prism", "prism", 5, EM_PRISM }, + { "avr", "elf_avr", "avr", 3, EM_AVR }, + { "fr30", "elf_fr30", "fr30", 4, EM_FR30 }, + { "dv10", "elf_dv10", "dv10", 4, EM_D10V }, + { "dv30", "elf_dv30", "dv30", 4, EM_D30V }, + { "v850", "elf_v850", "v850", 4, EM_V850 }, + { "m32r", "elf_m32r", "m32r", 4, EM_M32R }, + { "mn10300", "elf_mn10300", "mn10300", 7, EM_MN10300 }, + { "mn10200", "elf_mn10200", "mn10200", 7, EM_MN10200 }, + { "pj", "elf_pj", "pj", 2, EM_PJ }, + { "openrisc", "elf_openrisc", "openrisc", 8, EM_OPENRISC }, + { "arc", "elf_arc_a5", "arc_a5", 6, EM_ARC_A5 }, + { "xtensa", "elf_xtensa", "xtensa", 6, EM_XTENSA }, +}; +#define nmachines (sizeof (machines) / sizeof (machines[0])) + + +/* Default callbacks. Mostly they just return the error value. */ +static const char *default_object_type_name (int ignore, char *buf, + size_t len); +static const char *default_reloc_type_name (int ignore, char *buf, size_t len); +static bool default_reloc_type_check (int ignore); +static bool default_reloc_valid_use (Elf *elf, int ignore); +static Elf_Type default_reloc_simple_type (Elf *elf, int ignore); +static bool default_gotpc_reloc_check (Elf *elf, int ignore); +static const char *default_segment_type_name (int ignore, char *buf, + size_t len); +static const char *default_section_type_name (int ignore, char *buf, + size_t len); +static const char *default_section_name (int ignore, int ignore2, char *buf, + size_t len); +static const char *default_machine_flag_name (Elf64_Word *ignore); +static bool default_machine_flag_check (Elf64_Word flags); +static const char *default_symbol_type_name (int ignore, char *buf, + size_t len); +static const char *default_symbol_binding_name (int ignore, char *buf, + size_t len); +static const char *default_dynamic_tag_name (int64_t ignore, char *buf, + size_t len); +static bool default_dynamic_tag_check (int64_t ignore); +static GElf_Word default_sh_flags_combine (GElf_Word flags1, GElf_Word flags2); +static const char *default_osabi_name (int ignore, char *buf, size_t len); +static void default_destr (struct ebl *ignore); +static const char *default_core_note_type_name (uint32_t, char *buf, + size_t len); +static const char *default_object_note_type_name (uint32_t, char *buf, + size_t len); +static bool default_core_note (const char *name, uint32_t type, + uint32_t descsz, const char *desc); +static bool default_object_note (const char *name, uint32_t type, + uint32_t descsz, const char *desc); +static bool default_debugscn_p (const char *name); +static bool default_copy_reloc_p (int reloc); + + +static void +fill_defaults (Ebl *result) +{ + result->object_type_name = default_object_type_name; + result->reloc_type_name = default_reloc_type_name; + result->reloc_type_check = default_reloc_type_check; + result->reloc_valid_use = default_reloc_valid_use; + result->reloc_simple_type = default_reloc_simple_type; + result->gotpc_reloc_check = default_gotpc_reloc_check; + result->segment_type_name = default_segment_type_name; + result->section_type_name = default_section_type_name; + result->section_name = default_section_name; + result->machine_flag_name = default_machine_flag_name; + result->machine_flag_check = default_machine_flag_check; + result->symbol_type_name = default_symbol_type_name; + result->symbol_binding_name = default_symbol_binding_name; + result->dynamic_tag_name = default_dynamic_tag_name; + result->dynamic_tag_check = default_dynamic_tag_check; + result->sh_flags_combine = default_sh_flags_combine; + result->osabi_name = default_osabi_name; + result->core_note_type_name = default_core_note_type_name; + result->object_note_type_name = default_object_note_type_name; + result->core_note = default_core_note; + result->object_note = default_object_note; + result->debugscn_p = default_debugscn_p; + result->copy_reloc_p = default_copy_reloc_p; + result->destr = default_destr; +} + + +/* Find an appropriate backend for the file associated with ELF. */ +static Ebl * +openbackend (elf, emulation, machine) + Elf *elf; + const char *emulation; + GElf_Half machine; +{ + Ebl *result; + size_t cnt; + + /* First allocate the data structure for the result. We do this + here since this assures that the structure is always large + enough. */ + result = (Ebl *) calloc (1, sizeof (Ebl)); + if (result == NULL) + { + // XXX uncomment + // __libebl_seterror (ELF_E_NOMEM); + return NULL; + } + + /* Fill in the default callbacks. The initializer for the machine + specific module can overwrite the values. */ + fill_defaults (result); + + /* XXX Currently all we do is to look at 'e_machine' value in the + ELF header. With an internal mapping table from EM_* value to + DSO name we try to load the appropriate module to handle this + binary type. + + Multiple modules for the same machine type are possible and they + will be tried in sequence. The lookup process will only stop + when a module which can handle the machine type is found or all + available matching modules are tried. */ + for (cnt = 0; cnt < nmachines; ++cnt) + if ((emulation != NULL && strcmp (emulation, machines[cnt].emulation) == 0) + || (emulation == NULL && machines[cnt].em == machine)) + { + /* Well, we know the emulation name now. */ + result->emulation = machines[cnt].emulation; + +#ifndef LIBEBL_SUBDIR +# define LIBEBL_SUBDIR PACKAGE +#endif +#define ORIGINDIR "$ORIGIN/../$LIB/" LIBEBL_SUBDIR "/" + + /* Give it a try. At least the machine type matches. First + try to load the module. */ + char dsoname[100]; + strcpy (stpcpy (stpcpy (dsoname, ORIGINDIR "libebl_"), + machines[cnt].dsoname), + ".so"); + + void *h = dlopen (dsoname, RTLD_LAZY); + if (h == NULL) + { + strcpy (stpcpy (stpcpy (dsoname, "libebl_"), + machines[cnt].dsoname), + ".so"); + h = dlopen (dsoname, RTLD_LAZY); + } + + /* Try without an explicit path. */ + if (h != NULL) + { + /* We managed to load the object. Now see whether the + initialization function likes our file. */ + static const char version[] = MODVERSION; + const char *modversion; + ebl_bhinit_t initp; + char symname[machines[cnt].prefix_len + sizeof "_init"]; + + strcpy (mempcpy (symname, machines[cnt].prefix, + machines[cnt].prefix_len), "_init"); + + initp = (ebl_bhinit_t) dlsym (h, symname); + if (initp != NULL + && (modversion = initp (elf, machine, result, sizeof (Ebl))) + && strcmp (version, modversion) == 0) + { + /* We found a module to handle our file. */ + result->dlhandle = h; + result->elf = elf; + + /* A few entries are mandatory. */ + assert (result->name != NULL); + assert (result->destr != NULL); + + return result; + } + + /* Not the module we need. */ + (void) dlclose (h); + } + + /* We cannot find a DSO but the emulation/machine ID matches. + Return that information. */ + result->dlhandle = NULL; + result->elf = elf; + result->name = machines[cnt].prefix; + fill_defaults (result); + + return result; + } + + /* Nothing matched. We use only the default callbacks. */ + result->dlhandle = NULL; + result->elf = elf; + result->emulation = ""; + result->name = ""; + fill_defaults (result); + + return result; +} + + +/* Find an appropriate backend for the file associated with ELF. */ +Ebl * +ebl_openbackend (elf) + Elf *elf; +{ + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + + /* Get the ELF header of the object. */ + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + // XXX uncomment + // __libebl_seterror (elf_errno ()); + return NULL; + } + + return openbackend (elf, NULL, ehdr->e_machine); +} + + +/* Find backend without underlying ELF file. */ +Ebl * +ebl_openbackend_machine (machine) + GElf_Half machine; +{ + return openbackend (NULL, NULL, machine); +} + + +/* Find backend with given emulation name. */ +Ebl * +ebl_openbackend_emulation (const char *emulation) +{ + return openbackend (NULL, emulation, EM_NONE); +} + + +/* Default callbacks. Mostly they just return the error value. */ +static const char * +default_object_type_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_reloc_type_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static bool +default_reloc_type_check (int ignore __attribute__ ((unused))) +{ + return false; +} + +static bool +default_reloc_valid_use (Elf *elf __attribute__ ((unused)), + int ignore __attribute__ ((unused))) +{ + return false; +} + +static Elf_Type +default_reloc_simple_type (Elf *elf __attribute__ ((unused)), + int ignore __attribute__ ((unused))) +{ + return ELF_T_NUM; +} + +static bool +default_gotpc_reloc_check (Elf *elf __attribute__ ((unused)), + int ignore __attribute__ ((unused))) +{ + return false; +} + +static const char * +default_segment_type_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_section_type_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_section_name (int ignore __attribute__ ((unused)), + int ignore2 __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_machine_flag_name (Elf64_Word *ignore __attribute__ ((unused))) +{ + return NULL; +} + +static bool +default_machine_flag_check (Elf64_Word flags __attribute__ ((unused))) +{ + return flags == 0; +} + +static const char * +default_symbol_type_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_symbol_binding_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_dynamic_tag_name (int64_t ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static bool +default_dynamic_tag_check (int64_t ignore __attribute__ ((unused))) +{ + return false; +} + +static GElf_Word +default_sh_flags_combine (GElf_Word flags1, GElf_Word flags2) +{ + return SH_FLAGS_COMBINE (flags1, flags2); +} + +static void +default_destr (struct ebl *ignore __attribute__ ((unused))) +{ +} + +static const char * +default_osabi_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_core_note_type_name (uint32_t ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_object_note_type_name (uint32_t ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static bool +default_core_note (const char *name __attribute__ ((unused)), + uint32_t type __attribute__ ((unused)), + uint32_t descsz __attribute__ ((unused)), + const char *desc __attribute__ ((unused))) +{ + return NULL; +} + +static bool +default_object_note (const char *name __attribute__ ((unused)), + uint32_t type __attribute__ ((unused)), + uint32_t descsz __attribute__ ((unused)), + const char *desc __attribute__ ((unused))) +{ + return NULL; +} + +static bool +default_debugscn_p (const char *name) +{ + /* We know by default only about the DWARF debug sections which have + fixed names. */ + static const char *dwarf_scn_names[] = + { + /* DWARF 1 */ + ".debug", + ".line", + /* GNU DWARF 1 extensions */ + ".debug_srcinfo", + ".debug_sfnames", + /* DWARF 1.1 and DWARF 2 */ + ".debug_aranges", + ".debug_pubnames", + /* DWARF 2 */ + ".debug_info", + ".debug_abbrev", + ".debug_line", + ".debug_frame", + ".debug_str", + ".debug_loc", + ".debug_macinfo", + /* DWARF 3 */ + ".debug_ranges", + /* SGI/MIPS DWARF 2 extensions */ + ".debug_weaknames", + ".debug_funcnames", + ".debug_typenames", + ".debug_varnames" + }; + const size_t ndwarf_scn_names = (sizeof (dwarf_scn_names) + / sizeof (dwarf_scn_names[0])); + for (size_t cnt = 0; cnt < ndwarf_scn_names; ++cnt) + if (strcmp (name, dwarf_scn_names[cnt]) == 0) + return true; + + return false; +} + +static bool +default_copy_reloc_p (int reloc __attribute__ ((unused))) +{ + return false; +} diff --git a/libebl/eblosabiname.c b/libebl/eblosabiname.c new file mode 100644 index 00000000..9a1e6534 --- /dev/null +++ b/libebl/eblosabiname.c @@ -0,0 +1,69 @@ +/* Return OS ABI name + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +const char * +ebl_osabi_name (ebl, osabi, buf, len) + Ebl *ebl; + int osabi; + char *buf; + size_t len; +{ + const char *res = ebl != NULL ? ebl->osabi_name (osabi, buf, len) : NULL; + + if (res == NULL) + { + if (osabi == ELFOSABI_NONE) + res = "UNIX - System V"; + else if (osabi == ELFOSABI_HPUX) + res = "HP/UX"; + else if (osabi == ELFOSABI_NETBSD) + res = "NetBSD"; + else if (osabi == ELFOSABI_LINUX) + res = "Linux"; + else if (osabi == ELFOSABI_SOLARIS) + res = "Solaris"; + else if (osabi == ELFOSABI_AIX) + res = "AIX"; + else if (osabi == ELFOSABI_IRIX) + res = "Irix"; + else if (osabi == ELFOSABI_FREEBSD) + res = "FreeBSD"; + else if (osabi == ELFOSABI_TRU64) + res = "TRU64"; + else if (osabi == ELFOSABI_MODESTO) + res = "Modesto"; + else if (osabi == ELFOSABI_OPENBSD) + res = "OpenBSD"; + else if (osabi == ELFOSABI_ARM) + res = "Arm"; + else if (osabi == ELFOSABI_STANDALONE) + res = gettext ("Stand alone"); + else + { + snprintf (buf, len, "%s: %d", gettext (""), osabi); + + res = buf; + } + } + + return res; +} diff --git a/libebl/eblrelocsimpletype.c b/libebl/eblrelocsimpletype.c new file mode 100644 index 00000000..3e048d1f --- /dev/null +++ b/libebl/eblrelocsimpletype.c @@ -0,0 +1,27 @@ +/* Check relocation type for simple types. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +Elf_Type +ebl_reloc_simple_type (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl != NULL ? ebl->reloc_simple_type (ebl->elf, reloc) : ELF_T_NUM; +} diff --git a/libebl/eblreloctypecheck.c b/libebl/eblreloctypecheck.c new file mode 100644 index 00000000..cafbc611 --- /dev/null +++ b/libebl/eblreloctypecheck.c @@ -0,0 +1,28 @@ +/* Check relocation type. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +bool +ebl_reloc_type_check (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl != NULL ? ebl->reloc_type_check (reloc) : false; +} diff --git a/libebl/eblreloctypename.c b/libebl/eblreloctypename.c new file mode 100644 index 00000000..5fa95608 --- /dev/null +++ b/libebl/eblreloctypename.c @@ -0,0 +1,38 @@ +/* Return relocation type name. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +const char * +ebl_reloc_type_name (ebl, reloc, buf, len) + Ebl *ebl; + int reloc; + char *buf; + size_t len; +{ + const char *res; + + res = ebl != NULL ? ebl->reloc_type_name (reloc, buf, len) : NULL; + if (res == NULL) + /* There are no generic relocation type names. */ + res = "???"; + + return res; +} diff --git a/libebl/eblrelocvaliduse.c b/libebl/eblrelocvaliduse.c new file mode 100644 index 00000000..74889861 --- /dev/null +++ b/libebl/eblrelocvaliduse.c @@ -0,0 +1,28 @@ +/* Check relocation type use. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +bool +ebl_reloc_valid_use (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl != NULL ? ebl->reloc_valid_use (ebl->elf, reloc) : false; +} diff --git a/libebl/eblsectionname.c b/libebl/eblsectionname.c new file mode 100644 index 00000000..6c801db6 --- /dev/null +++ b/libebl/eblsectionname.c @@ -0,0 +1,81 @@ +/* Return section name. + Copyright (C) 2001, 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +const char * +ebl_section_name (ebl, section, xsection, buf, len, scnnames, shnum) + Ebl *ebl; + int section; + int xsection; + char *buf; + size_t len; + const char *scnnames[]; + size_t shnum; +{ + const char *res = ebl != NULL ? ebl->section_name (section, xsection, + buf, len) : NULL; + + if (res == NULL) + { + if (section == SHN_UNDEF) + res = "UNDEF"; + else if (section == SHN_ABS) + res = "ABS"; + else if (section == SHN_COMMON) + res = "COMMON"; + else if (section == SHN_BEFORE) + res = "BEFORE"; + else if (section == SHN_AFTER) + res = "AFTER"; + else if ((section < SHN_LORESERVE || section == SHN_XINDEX) + && (size_t) section < shnum) + { + int idx = section != SHN_XINDEX ? section : xsection; + + if (scnnames != NULL) + res = scnnames[idx]; + else + { + snprintf (buf, len, "%d", idx); + res = buf; + } + } + else + { + /* Handle OS-specific section names. */ + if (section == SHN_XINDEX) + snprintf (buf, len, "%s: %d", "XINDEX", xsection); + else if (section >= SHN_LOOS && section <= SHN_HIOS) + snprintf (buf, len, "LOOS+%x", section - SHN_LOOS); + /* Handle processor-specific section names. */ + else if (section >= SHN_LOPROC && section <= SHN_HIPROC) + snprintf (buf, len, "LOPROC+%x", section - SHN_LOPROC); + else if (section >= SHN_LORESERVE && section <= SHN_HIRESERVE) + snprintf (buf, len, "LORESERVE+%x", section - SHN_LORESERVE); + else + snprintf (buf, len, "%s: %d", gettext (""), section); + + res = buf; + } + } + + return res; +} diff --git a/libebl/eblsectionstripp.c b/libebl/eblsectionstripp.c new file mode 100644 index 00000000..77a22cac --- /dev/null +++ b/libebl/eblsectionstripp.c @@ -0,0 +1,52 @@ +/* Check whether section can be stripped. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libeblP.h" + + +bool +ebl_section_strip_p (Ebl *ebl, const GElf_Ehdr *ehdr, const GElf_Shdr *shdr, + const char *name, bool remove_comment, + bool only_remove_debug) +{ + /* If only debug information should be removed check the name. There + is unfortunately no other way. */ + if (unlikely (only_remove_debug)) + { + if (ebl_debugscn_p (ebl, name)) + return true; + + if (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL) + { + Elf_Scn *scn_l = elf_getscn (ebl->elf, (shdr)->sh_info); + GElf_Shdr shdr_mem_l; + GElf_Shdr *shdr_l = gelf_getshdr (scn_l, &shdr_mem_l); + if (shdr_l == NULL) + { + const char *s_l = elf_strptr (ebl->elf, ehdr->e_shstrndx, + shdr_l->sh_name); + if (s_l != NULL && ebl_debugscn_p (ebl, s_l)) + return true; + } + } + + return false; + } + + return SECTION_STRIP_P (shdr, name, remove_comment); +} diff --git a/libebl/eblsectiontypename.c b/libebl/eblsectiontypename.c new file mode 100644 index 00000000..e6857acd --- /dev/null +++ b/libebl/eblsectiontypename.c @@ -0,0 +1,103 @@ +/* Return section type name. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +const char * +ebl_section_type_name (ebl, section, buf, len) + Ebl *ebl; + int section; + char *buf; + size_t len; +{ + const char *res = ebl->section_type_name (section, buf, len); + + if (res == NULL) + { + static const char *knowntypes[] = + { +#define KNOWNSTYPE(name) [SHT_##name] = #name + KNOWNSTYPE (NULL), + KNOWNSTYPE (PROGBITS), + KNOWNSTYPE (SYMTAB), + KNOWNSTYPE (STRTAB), + KNOWNSTYPE (RELA), + KNOWNSTYPE (HASH), + KNOWNSTYPE (DYNAMIC), + KNOWNSTYPE (NOTE), + KNOWNSTYPE (NOBITS), + KNOWNSTYPE (REL), + KNOWNSTYPE (SHLIB), + KNOWNSTYPE (DYNSYM), + KNOWNSTYPE (INIT_ARRAY), + KNOWNSTYPE (FINI_ARRAY), + KNOWNSTYPE (PREINIT_ARRAY), + KNOWNSTYPE (GROUP), + KNOWNSTYPE (SYMTAB_SHNDX) + }; + + /* Handle standard names. */ + if ((size_t) section < sizeof (knowntypes) / sizeof (knowntypes[0]) + && knowntypes[section] != NULL) + res = knowntypes[section]; + /* The symbol versioning/Sun extensions. */ + else if (section >= SHT_LOSUNW && section <= SHT_HISUNW) + { + static const char *sunwtypes[] = + { +#undef KNOWNSTYPE +#define KNOWNSTYPE(name) [SHT_##name - SHT_LOSUNW] = #name + KNOWNSTYPE (SUNW_move), + KNOWNSTYPE (SUNW_COMDAT), + KNOWNSTYPE (SUNW_syminfo), + KNOWNSTYPE (GNU_verdef), + KNOWNSTYPE (GNU_verneed), + KNOWNSTYPE (GNU_versym) + }; + res = sunwtypes[section - SHT_LOSUNW]; + } + else + { + /* A few GNU additions. */ + if (section == SHT_CHECKSUM) + res = "CHECKSUM"; + else if (section == SHT_GNU_LIBLIST) + res = "GNU_LIBLIST"; + /* Handle OS-specific section names. */ + else + { + if (section >= SHT_LOOS && section <= SHT_HIOS) + snprintf (buf, len, "SHT_LOOS+%x", section - SHT_LOOS); + /* Handle processor-specific section names. */ + else if (section >= SHT_LOPROC && section <= SHT_HIPROC) + snprintf (buf, len, "SHT_LOPROC+%x", section - SHT_LOPROC); + else if ((unsigned int) section >= SHT_LOUSER + && (unsigned int) section <= SHT_HIUSER) + snprintf (buf, len, "SHT_LOUSER+%x", section - SHT_LOUSER); + else + snprintf (buf, len, "%s: %d", gettext (""), section); + + res = buf; + } + } + } + + return res; +} diff --git a/libebl/eblsegmenttypename.c b/libebl/eblsegmenttypename.c new file mode 100644 index 00000000..c59f037d --- /dev/null +++ b/libebl/eblsegmenttypename.c @@ -0,0 +1,75 @@ +/* Return segment type name. + Copyright (C) 2001, 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +const char * +ebl_segment_type_name (ebl, segment, buf, len) + Ebl *ebl; + int segment; + char *buf; + size_t len; +{ + const char *res; + + res = ebl != NULL ? ebl->segment_type_name (segment, buf, len) : NULL; + if (res == NULL) + { + static const char *ptypes[PT_NUM] = + { +#define PTYPE(name) [PT_##name] = #name + PTYPE (NULL), + PTYPE (LOAD), + PTYPE (DYNAMIC), + PTYPE (INTERP), + PTYPE (NOTE), + PTYPE (SHLIB), + PTYPE (PHDR), + PTYPE (TLS) + }; + + /* Is it one of the standard segment types? */ + if (segment >= PT_NULL && segment < PT_NUM) + res = ptypes[segment]; + else if (segment == PT_GNU_EH_FRAME) + res = "GNU_EH_FRAME"; + else if (segment == PT_GNU_STACK) + res = "GNU_STACK"; + else if (segment == PT_GNU_RELRO) + res = "GNU_RELRO"; + else if (segment == PT_SUNWBSS) + res = "SUNWBSS"; + else if (segment == PT_SUNWSTACK) + res = "SUNWSTACK"; + else + { + if (segment >= PT_LOOS && segment <= PT_HIOS) + snprintf (buf, len, "LOOS+%d", segment - PT_LOOS); + else if (segment >= PT_LOPROC && segment <= PT_HIPROC) + snprintf (buf, len, "LOPROC+%d", segment - PT_LOPROC); + else + snprintf (buf, len, "%s: %d", gettext (""), segment); + + res = buf; + } + } + + return res; +} diff --git a/libebl/eblshflagscombine.c b/libebl/eblshflagscombine.c new file mode 100644 index 00000000..7edcf4e7 --- /dev/null +++ b/libebl/eblshflagscombine.c @@ -0,0 +1,29 @@ +/* Return combines section header flags value. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +GElf_Word +ebl_sh_flags_combine (ebl, flags1, flags2) + Ebl *ebl; + GElf_Word flags1; + GElf_Word flags2; +{ + return ebl->sh_flags_combine (flags1, flags2); +} diff --git a/libebl/eblstrtab.c b/libebl/eblstrtab.c new file mode 100644 index 00000000..165909f4 --- /dev/null +++ b/libebl/eblstrtab.c @@ -0,0 +1,337 @@ +/* ELF string table handling. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libebl.h" +#include + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + + +struct Ebl_Strent +{ + const char *string; + size_t len; + struct Ebl_Strent *next; + struct Ebl_Strent *left; + struct Ebl_Strent *right; + size_t offset; + char reverse[0]; +}; + + +struct memoryblock +{ + struct memoryblock *next; + char memory[0]; +}; + + +struct Ebl_Strtab +{ + struct Ebl_Strent *root; + struct memoryblock *memory; + char *backp; + size_t left; + size_t total; + bool nullstr; + + struct Ebl_Strent null; +}; + + +/* Cache for the pagesize. We correct this value a bit so that `malloc' + is not allocating more than a page. */ +static size_t ps; + + +struct Ebl_Strtab * +ebl_strtabinit (bool nullstr) +{ + if (ps == 0) + { + ps = sysconf (_SC_PAGESIZE) - 2 * sizeof (void *); + assert (sizeof (struct memoryblock) < ps); + } + + struct Ebl_Strtab *ret + = (struct Ebl_Strtab *) calloc (1, sizeof (struct Ebl_Strtab)); + if (ret != NULL) + { + ret->nullstr = nullstr; + + if (nullstr) + { + ret->null.len = 1; + ret->null.string = ""; + } + } + + return ret; +} + + +static int +morememory (struct Ebl_Strtab *st, size_t len) +{ + if (len < ps) + len = ps; + + struct memoryblock *newmem = (struct memoryblock *) malloc (len); + if (newmem == NULL) + return 1; + + newmem->next = st->memory; + st->memory = newmem; + st->backp = newmem->memory; + st->left = len - offsetof (struct memoryblock, memory); + + return 0; +} + + +void +ebl_strtabfree (struct Ebl_Strtab *st) +{ + struct memoryblock *mb = st->memory; + + while (mb != NULL) + { + void *old = mb; + mb = mb->next; + free (old); + } + + free (st); +} + + +static struct Ebl_Strent * +newstring (struct Ebl_Strtab *st, const char *str, size_t len) +{ + /* Compute the amount of padding needed to make the structure aligned. */ + size_t align = ((__alignof__ (struct Ebl_Strent) + - (((uintptr_t) st->backp) + & (__alignof__ (struct Ebl_Strent) - 1))) + & (__alignof__ (struct Ebl_Strent) - 1)); + + /* Make sure there is enough room in the memory block. */ + if (st->left < align + sizeof (struct Ebl_Strent) + len) + { + if (morememory (st, sizeof (struct Ebl_Strent) + len)) + return NULL; + + align = 0; + } + + /* Create the reserved string. */ + struct Ebl_Strent *newstr = (struct Ebl_Strent *) (st->backp + align); + newstr->string = str; + newstr->len = len; + newstr->next = NULL; + newstr->left = NULL; + newstr->right = NULL; + newstr->offset = 0; + for (int i = len - 2; i >= 0; --i) + newstr->reverse[i] = str[len - 2 - i]; + newstr->reverse[len - 1] = '\0'; + st->backp += align + sizeof (struct Ebl_Strent) + len; + st->left -= align + sizeof (struct Ebl_Strent) + len; + + return newstr; +} + + +/* XXX This function should definitely be rewritten to use a balancing + tree algorith (AVL, red-black trees). For now a simple, correct + implementation is enough. */ +static struct Ebl_Strent ** +searchstring (struct Ebl_Strent **sep, struct Ebl_Strent *newstr) +{ + /* More strings? */ + if (*sep == NULL) + { + *sep = newstr; + return sep; + } + + /* Compare the strings. */ + int cmpres = memcmp ((*sep)->reverse, newstr->reverse, + MIN ((*sep)->len, newstr->len) - 1); + if (cmpres == 0) + /* We found a matching string. */ + return sep; + else if (cmpres > 0) + return searchstring (&(*sep)->left, newstr); + else + return searchstring (&(*sep)->right, newstr); +} + + +/* Add new string. The actual string is assumed to be permanent. */ +struct Ebl_Strent * +ebl_strtabadd (struct Ebl_Strtab *st, const char *str, size_t len) +{ + /* Compute the string length if the caller doesn't know it. */ + if (len == 0) + len = strlen (str) + 1; + + /* Make sure all "" strings get offset 0 but only if the table was + created with a special null entry in mind. */ + if (len == 1 && st->null.string != NULL) + return &st->null; + + /* Allocate memory for the new string and its associated information. */ + struct Ebl_Strent *newstr = newstring (st, str, len); + if (newstr == NULL) + return NULL; + + /* Search in the array for the place to insert the string. If there + is no string with matching prefix and no string with matching + leading substring, create a new entry. */ + struct Ebl_Strent **sep = searchstring (&st->root, newstr); + if (*sep != newstr) + { + /* This is not the same entry. This means we have a prefix match. */ + if ((*sep)->len > newstr->len) + { + /* Check whether we already know this string. */ + for (struct Ebl_Strent *subs = (*sep)->next; subs != NULL; + subs = subs->next) + if (subs->len == newstr->len) + { + /* We have an exact match with a substring. Free the memory + we allocated. */ + st->left += st->backp - (char *) newstr; + st->backp = (char *) newstr; + + return subs; + } + + /* We have a new substring. This means we don't need the reverse + string of this entry anymore. */ + st->backp -= newstr->len; + st->left += newstr->len; + + newstr->next = (*sep)->next; + (*sep)->next = newstr; + } + else if ((*sep)->len != newstr->len) + { + /* When we get here it means that the string we are about to + add has a common prefix with a string we already have but + it is longer. In this case we have to put it first. */ + st->total += newstr->len - (*sep)->len; + newstr->next = *sep; + newstr->left = (*sep)->left; + newstr->right = (*sep)->right; + *sep = newstr; + } + else + { + /* We have an exact match. Free the memory we allocated. */ + st->left += st->backp - (char *) newstr; + st->backp = (char *) newstr; + + newstr = *sep; + } + } + else + st->total += newstr->len; + + return newstr; +} + + +static void +copystrings (struct Ebl_Strent *nodep, char **freep, size_t *offsetp) +{ + if (nodep->left != NULL) + copystrings (nodep->left, freep, offsetp); + + /* Process the current node. */ + nodep->offset = *offsetp; + *freep = (char *) mempcpy (*freep, nodep->string, nodep->len); + *offsetp += nodep->len; + + for (struct Ebl_Strent *subs = nodep->next; subs != NULL; subs = subs->next) + { + assert (subs->len < nodep->len); + subs->offset = nodep->offset + nodep->len - subs->len; + assert (subs->offset != 0 || subs->string[0] == '\0'); + } + + if (nodep->right != NULL) + copystrings (nodep->right, freep, offsetp); +} + + +void +ebl_strtabfinalize (struct Ebl_Strtab *st, Elf_Data *data) +{ + size_t nulllen = st->nullstr ? 1 : 0; + + /* Fill in the information. */ + data->d_buf = malloc (st->total + nulllen); + if (data->d_buf == NULL) + abort (); + + /* The first byte must always be zero if we created the table with a + null string. */ + if (st->nullstr) + *((char *) data->d_buf) = '\0'; + + data->d_type = ELF_T_BYTE; + data->d_size = st->total + nulllen; + data->d_off = 0; + data->d_align = 1; + data->d_version = EV_CURRENT; + + /* Now run through the tree and add all the string while also updating + the offset members of the elfstrent records. */ + char *endp = (char *) data->d_buf + nulllen; + size_t copylen = nulllen; + copystrings (st->root, &endp, ©len); + assert (copylen == st->total + nulllen); +} + + +size_t +ebl_strtaboffset (struct Ebl_Strent *se) +{ + return se->offset; +} + + +const char * +ebl_string (struct Ebl_Strent *se) +{ + assert (se->string != NULL); + + return se->string; +} diff --git a/libebl/eblsymbolbindingname.c b/libebl/eblsymbolbindingname.c new file mode 100644 index 00000000..efcd250e --- /dev/null +++ b/libebl/eblsymbolbindingname.c @@ -0,0 +1,57 @@ +/* Return symbol binding name. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +const char * +ebl_symbol_binding_name (ebl, binding, buf, len) + Ebl *ebl; + int binding; + char *buf; + size_t len; +{ + const char *res; + + res = ebl != NULL ? ebl->symbol_type_name (binding, buf, len) : NULL; + if (res == NULL) + { + static const char *stb_names[STB_NUM] = + { + "LOCAL", "GLOBAL", "WEAK" + }; + + /* Standard binding? */ + if (binding < STB_NUM) + res = stb_names[binding]; + else + { + if (binding >= STB_LOPROC && binding <= STB_HIPROC) + snprintf (buf, len, "LOPROC+%d", binding - STB_LOPROC); + else if (binding >= STB_LOOS && binding <= STB_HIOS) + snprintf (buf, len, "LOOS+%d", binding - STB_LOOS); + else + snprintf (buf, len, gettext (": %d"), binding); + + res = buf; + } + } + + return res; +} diff --git a/libebl/eblsymboltypename.c b/libebl/eblsymboltypename.c new file mode 100644 index 00000000..d11aec1a --- /dev/null +++ b/libebl/eblsymboltypename.c @@ -0,0 +1,63 @@ +/* Return symbol type name. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +const char * +ebl_symbol_type_name (ebl, symbol, buf, len) + Ebl *ebl; + int symbol; + char *buf; + size_t len; +{ + const char *res; + + res = ebl != NULL ? ebl->symbol_type_name (symbol, buf, len) : NULL; + if (res == NULL) + { + static const char *stt_names[STT_NUM] = + { + [STT_NOTYPE] = "NOTYPE", + [STT_OBJECT] = "OBJECT", + [STT_FUNC] = "FUNC", + [STT_SECTION] = "SECTION", + [STT_FILE] = "FILE", + [STT_COMMON] = "COMMON", + [STT_TLS] = "TLS" + }; + + /* Standard type? */ + if (symbol < STT_NUM) + res = stt_names[symbol]; + else + { + if (symbol >= STT_LOPROC && symbol <= STT_HIPROC) + snprintf (buf, len, "LOPROC+%d", symbol - STT_LOPROC); + else if (symbol >= STT_LOOS && symbol <= STT_HIOS) + snprintf (buf, len, "LOOS+%d", symbol - STT_LOOS); + else + snprintf (buf, len, gettext (": %d"), symbol); + + res = buf; + } + } + + return res; +} diff --git a/libebl/eblwstrtab.c b/libebl/eblwstrtab.c new file mode 100644 index 00000000..8320cb58 --- /dev/null +++ b/libebl/eblwstrtab.c @@ -0,0 +1,344 @@ +/* ELF string table handling. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libebl.h" +#include + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + + +struct Ebl_WStrent +{ + const wchar_t *string; + size_t len; + struct Ebl_WStrent *next; + struct Ebl_WStrent *left; + struct Ebl_WStrent *right; + size_t offset; + wchar_t reverse[0]; +}; + + +struct memoryblock +{ + struct memoryblock *next; + char memory[0]; +}; + + +struct Ebl_WStrtab +{ + struct Ebl_WStrent *root; + struct memoryblock *memory; + char *backp; + size_t left; + size_t total; + bool nullstr; + + struct Ebl_WStrent null; +}; + + +/* Cache for the pagesize. We correct this value a bit so that `malloc' + is not allocating more than a page. */ +static size_t ps; + + +struct Ebl_WStrtab * +ebl_wstrtabinit (bool nullstr) +{ + struct Ebl_WStrtab *ret; + + if (ps == 0) + { + ps = sysconf (_SC_PAGESIZE) - 2 * sizeof (void *); + assert (sizeof (struct memoryblock) < ps); + } + + ret = (struct Ebl_WStrtab *) calloc (1, sizeof (struct Ebl_WStrtab)); + if (ret != NULL) + { + ret->nullstr = nullstr; + if (nullstr) + { + ret->null.len = 1; + ret->null.string = L""; + } + } + return ret; +} + + +static int +morememory (struct Ebl_WStrtab *st, size_t len) +{ + struct memoryblock *newmem; + + if (len < ps) + len = ps; + newmem = (struct memoryblock *) malloc (len); + if (newmem == NULL) + return 1; + + newmem->next = st->memory; + st->memory = newmem; + st->backp = newmem->memory; + st->left = len - offsetof (struct memoryblock, memory); + + return 0; +} + + +void +ebl_wstrtabfree (struct Ebl_WStrtab *st) +{ + struct memoryblock *mb = st->memory; + + while (mb != NULL) + { + void *old = mb; + mb = mb->next; + free (old); + } + + free (st); +} + + +static struct Ebl_WStrent * +newstring (struct Ebl_WStrtab *st, const wchar_t *str, size_t len) +{ + struct Ebl_WStrent *newstr; + size_t align; + int i; + + /* Compute the amount of padding needed to make the structure aligned. */ + align = ((__alignof__ (struct Ebl_WStrent) + - (((uintptr_t) st->backp) + & (__alignof__ (struct Ebl_WStrent) - 1))) + & (__alignof__ (struct Ebl_WStrent) - 1)); + + /* Make sure there is enough room in the memory block. */ + if (st->left < align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t)) + { + if (morememory (st, + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t))) + return NULL; + + align = 0; + } + + /* Create the reserved string. */ + newstr = (struct Ebl_WStrent *) (st->backp + align); + newstr->string = str; + newstr->len = len; + newstr->next = NULL; + newstr->left = NULL; + newstr->right = NULL; + newstr->offset = 0; + for (i = len - 2; i >= 0; --i) + newstr->reverse[i] = str[len - 2 - i]; + newstr->reverse[len - 1] = L'\0'; + st->backp += align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t); + st->left -= align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t); + + return newstr; +} + + +/* XXX This function should definitely be rewritten to use a balancing + tree algorith (AVL, red-black trees). For now a simple, correct + implementation is enough. */ +static struct Ebl_WStrent ** +searchstring (struct Ebl_WStrent **sep, struct Ebl_WStrent *newstr) +{ + int cmpres; + + /* More strings? */ + if (*sep == NULL) + { + *sep = newstr; + return sep; + } + + /* Compare the strings. */ + cmpres = wmemcmp ((*sep)->reverse, newstr->reverse, + MIN ((*sep)->len, newstr->len) - 1); + if (cmpres == 0) + /* We found a matching string. */ + return sep; + else if (cmpres > 0) + return searchstring (&(*sep)->left, newstr); + else + return searchstring (&(*sep)->right, newstr); +} + + +/* Add new string. The actual string is assumed to be permanent. */ +struct Ebl_WStrent * +ebl_wstrtabadd (struct Ebl_WStrtab *st, const wchar_t *str, size_t len) +{ + struct Ebl_WStrent *newstr; + struct Ebl_WStrent **sep; + + /* Compute the string length if the caller doesn't know it. */ + if (len == 0) + len = wcslen (str) + 1; + + /* Make sure all "" strings get offset 0 but only if the table was + created with a special null entry in mind. */ + if (len == 1 && st->null.string != NULL) + return &st->null; + + /* Allocate memory for the new string and its associated information. */ + newstr = newstring (st, str, len); + if (newstr == NULL) + return NULL; + + /* Search in the array for the place to insert the string. If there + is no string with matching prefix and no string with matching + leading substring, create a new entry. */ + sep = searchstring (&st->root, newstr); + if (*sep != newstr) + { + /* This is not the same entry. This means we have a prefix match. */ + if ((*sep)->len > newstr->len) + { + struct Ebl_WStrent *subs; + + /* Check whether we already know this string. */ + for (subs = (*sep)->next; subs != NULL; subs = subs->next) + if (subs->len == newstr->len) + { + /* We have an exact match with a substring. Free the memory + we allocated. */ + st->left += st->backp - (char *) newstr; + st->backp = (char *) newstr; + + return subs; + } + + /* We have a new substring. This means we don't need the reverse + string of this entry anymore. */ + st->backp -= newstr->len; + st->left += newstr->len; + + newstr->next = (*sep)->next; + (*sep)->next = newstr; + } + else if ((*sep)->len != newstr->len) + { + /* When we get here it means that the string we are about to + add has a common prefix with a string we already have but + it is longer. In this case we have to put it first. */ + st->total += newstr->len - (*sep)->len; + newstr->next = *sep; + newstr->left = (*sep)->left; + newstr->right = (*sep)->right; + *sep = newstr; + } + else + { + /* We have an exact match. Free the memory we allocated. */ + st->left += st->backp - (char *) newstr; + st->backp = (char *) newstr; + + newstr = *sep; + } + } + else + st->total += newstr->len; + + return newstr; +} + + +static void +copystrings (struct Ebl_WStrent *nodep, wchar_t **freep, size_t *offsetp) +{ + struct Ebl_WStrent *subs; + + if (nodep->left != NULL) + copystrings (nodep->left, freep, offsetp); + + /* Process the current node. */ + nodep->offset = *offsetp; + *freep = wmempcpy (*freep, nodep->string, nodep->len); + *offsetp += nodep->len * sizeof (wchar_t); + + for (subs = nodep->next; subs != NULL; subs = subs->next) + { + assert (subs->len < nodep->len); + subs->offset = nodep->offset + nodep->len - subs->len; + assert (subs->offset != 0 || subs->string[0] == '\0'); + } + + if (nodep->right != NULL) + copystrings (nodep->right, freep, offsetp); +} + + +void +ebl_wstrtabfinalize (struct Ebl_WStrtab *st, Elf_Data *data) +{ + size_t copylen; + wchar_t *endp; + size_t nulllen = st->nullstr ? 1 : 0; + + /* Fill in the information. */ + data->d_buf = malloc ((st->total + nulllen) * sizeof (wchar_t)); + if (data->d_buf == NULL) + abort (); + + /* The first byte must always be zero if we created the table with a + null string. */ + if (st->nullstr) + *((wchar_t *) data->d_buf) = L'\0'; + + data->d_type = ELF_T_BYTE; + data->d_size = st->total + nulllen; + data->d_off = 0; + data->d_align = 1; + data->d_version = EV_CURRENT; + + /* Now run through the tree and add all the string while also updating + the offset members of the elfstrent records. */ + endp = (wchar_t *) data->d_buf + nulllen; + copylen = sizeof (wchar_t) * nulllen; + copystrings (st->root, &endp, ©len); + assert (copylen == (st->total + nulllen) * sizeof (wchar_t)); +} + + +size_t +ebl_wstrtaboffset (struct Ebl_WStrent *se) +{ + return se->offset; +} diff --git a/libebl/i386_corenote.c b/libebl/i386_corenote.c new file mode 100644 index 00000000..3a123e92 --- /dev/null +++ b/libebl/i386_corenote.c @@ -0,0 +1,162 @@ +/* i386 specific core note handling. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + + +/* We cannot include since the definition would be for + the host platform and not always x86 as required here. */ +struct elf_prstatus + { + struct + { + int32_t si_signo; /* Signal number. */ + int32_t si_code; /* Extra code. */ + int32_t si_errno; /* Errno. */ + } pr_info; /* Info associated with signal. */ + int16_t pr_cursig; /* Current signal. */ + uint32_t pr_sigpend; /* Set of pending signals. */ + uint32_t pr_sighold; /* Set of held signals. */ + int32_t pr_pid; + int32_t pr_ppid; + int32_t pr_pgrp; + int32_t pr_sid; + struct i386_timeval + { + int32_t tv_sec; + int32_t tv_usec; + } pr_utime; /* User time. */ + struct i386_timeval pr_stime; /* System time. */ + struct i386_timeval pr_cutime; /* Cumulative user time. */ + struct i386_timeval pr_cstime; /* Cumulative system time. */ + uint32_t pr_reg[17]; /* GP registers. */ + int32_t pr_fpvalid; /* True if math copro being used. */ + }; + + +struct elf_prpsinfo + { + char pr_state; /* Numeric process state. */ + char pr_sname; /* Char for pr_state. */ + char pr_zomb; /* Zombie. */ + char pr_nice; /* Nice val. */ + uint32_t pr_flag; /* Flags. */ + uint16_t pr_uid; + uint16_t pr_gid; + int32_t pr_pid; + int32_t pr_ppid; + int32_t pr_pgrp; + int32_t pr_sid; + /* Lots missing */ + char pr_fname[16]; /* Filename of executable. */ + char pr_psargs[80]; /* Initial part of arg list. */ + }; + + +bool +i386_core_note (name, type, descsz, desc) + const char *name __attribute__ ((unused)); + uint32_t type; + uint32_t descsz; + const char *desc; +{ + bool result = false; + + switch (type) + { + case NT_PRSTATUS: + if (descsz < sizeof (struct elf_prstatus)) + /* Not enough data. */ + break; + + struct elf_prstatus *stat = (struct elf_prstatus *) desc; + + printf (" SIGINFO: signo: %" PRId32 ", code = %" PRId32 + ", errno = %" PRId32 "\n" + " signal: %" PRId16 ", pending: %08" PRIx32 + ", holding: %8" PRIx32 "\n" + " pid: %" PRId32 ", ppid = %" PRId32 ", pgrp = %" PRId32 + ", sid = %" PRId32 "\n" + " utime: %6" PRId32 ".%06" PRId32 + "s, stime: %6" PRId32 ".%06" PRId32 "s\n" + " cutime: %6" PRId32 ".%06" PRId32 + "s, cstime: %6" PRId32 ".%06" PRId32 "s\n" + " eax: %08" PRIx32 " ebx: %08" PRIx32 " ecx: %08" PRIx32 + " edx: %08" PRIx32 "\n" + " esi: %08" PRIx32 " edi: %08" PRIx32 " ebp: %08" PRIx32 + " esp: %08" PRIx32 "\n" + " eip: %08" PRIx32 " eflags: %08" PRIx32 + " original eax: %08" PRIx32 "\n" + " cs: %04" PRIx32 " ds: %04" PRIx32 " es: %04" PRIx32 + " fs: %04" PRIx32 " gs: %04" PRIx32 " ss: %04" PRIx32 "\n\n", + stat->pr_info.si_signo, + stat->pr_info.si_code, + stat->pr_info.si_errno, + stat->pr_cursig, + stat->pr_sigpend, stat->pr_sighold, + stat->pr_pid, stat->pr_ppid, stat->pr_pgrp, stat->pr_sid, + stat->pr_utime.tv_sec, stat->pr_utime.tv_usec, + stat->pr_stime.tv_sec, stat->pr_stime.tv_usec, + stat->pr_cutime.tv_sec, stat->pr_cutime.tv_usec, + stat->pr_cstime.tv_sec, stat->pr_cstime.tv_usec, + stat->pr_reg[6], stat->pr_reg[0], stat->pr_reg[1], + stat->pr_reg[2], stat->pr_reg[3], stat->pr_reg[4], + stat->pr_reg[5], stat->pr_reg[15], stat->pr_reg[12], + stat->pr_reg[14], stat->pr_reg[11], stat->pr_reg[13] & 0xffff, + stat->pr_reg[7] & 0xffff, stat->pr_reg[8] & 0xffff, + stat->pr_reg[9] & 0xffff, stat->pr_reg[10] & 0xffff, + stat->pr_reg[16]); + + /* We handled this entry. */ + result = true; + break; + + case NT_PRPSINFO: + if (descsz < sizeof (struct elf_prpsinfo)) + /* Not enough data. */ + break; + + struct elf_prpsinfo *info = (struct elf_prpsinfo *) desc; + + printf (" state: %c (%hhd), zombie: %hhd, nice: %hhd\n" + " flags: %08" PRIx32 ", uid: %" PRId16 ", gid: %" PRId16"\n" + " pid: %" PRId32 ", ppid: %" PRId32 ", pgrp: %" PRId32 + ", sid: %" PRId32 "\n" + " fname: %.16s\n" + " args: %.80s\n\n", + info->pr_sname, info->pr_state, info->pr_zomb, info->pr_nice, + info->pr_flag, info->pr_uid, info->pr_gid, + info->pr_pid, info->pr_ppid, info->pr_pgrp, info->pr_sid, + info->pr_fname, info->pr_psargs); + + /* We handled this entry. */ + result = true; + break; + + default: + break; + } + + return result; +} diff --git a/libebl/i386_destr.c b/libebl/i386_destr.c new file mode 100644 index 00000000..50c0fd48 --- /dev/null +++ b/libebl/i386_destr.c @@ -0,0 +1,27 @@ +/* Destructor for i386 specific backend library. + Copyright (C) 2000, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +void +i386_destr (bh) + Ebl *bh __attribute__ ((unused)); +{ + /* Nothing to do so far. */ +} diff --git a/libebl/i386_init.c b/libebl/i386_init.c new file mode 100644 index 00000000..264f3ef7 --- /dev/null +++ b/libebl/i386_init.c @@ -0,0 +1,47 @@ +/* Initialization of i386 specific backend library. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +const char * +i386_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Intel 80386"; + eh->reloc_type_name = i386_reloc_type_name; + eh->reloc_type_check = i386_reloc_type_check; + eh->reloc_valid_use = i386_reloc_valid_use; + eh->reloc_simple_type = i386_reloc_simple_type; + eh->gotpc_reloc_check = i386_gotpc_reloc_check; + eh->core_note = i386_core_note; + generic_debugscn_p = eh->debugscn_p; + eh->debugscn_p = i386_debugscn_p; + eh->copy_reloc_p = i386_copy_reloc_p; + eh->destr = i386_destr; + + return MODVERSION; +} diff --git a/libebl/i386_symbol.c b/libebl/i386_symbol.c new file mode 100644 index 00000000..e9eded23 --- /dev/null +++ b/libebl/i386_symbol.c @@ -0,0 +1,163 @@ +/* i386 specific symbolic name handling. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + + +/* Return of the backend. */ +const char * +i386_backend_name (void) +{ + return "i386"; +} + + +/* Relocation mapping table. */ +static struct +{ + const char *name; + enum { both = 0, rel = 1, exec = 2 } appear; +} reloc_map_table[] = + { + [R_386_NONE] = { "R_386_NONE", both }, + [R_386_32] = { "R_386_32", both }, + [R_386_PC32] = { "R_386_PC32", rel }, + [R_386_GOT32] = { "R_386_GOT32", rel }, + [R_386_PLT32] = { "R_386_PLT32", rel }, + [R_386_COPY] = { "R_386_COPY", exec }, + [R_386_GLOB_DAT] = { "R_386_GLOB_DAT", exec }, + [R_386_JMP_SLOT] = { "R_386_JMP_SLOT", exec }, + [R_386_RELATIVE] = { "R_386_RELATIVE", exec }, + [R_386_GOTOFF] = { "R_386_GOTOFF", rel }, + [R_386_GOTPC] = { "R_386_GOTPC", rel }, + [R_386_32PLT] = { "R_386_32PLT", rel }, + [R_386_TLS_TPOFF] = { "R_386_TLS_TPOFF", rel }, + [R_386_TLS_IE] = { "R_386_TLS_IE", rel }, + [R_386_TLS_GOTIE] = { "R_386_TLS_GOTIE", rel }, + [R_386_TLS_LE] = { "R_386_TLS_LE", rel }, + [R_386_TLS_GD] = { "R_386_TLS_GD", rel }, + [R_386_TLS_LDM] = { "R_386_TLS_LDM", rel }, + [R_386_16] = { "R_386_16", rel }, + [R_386_PC16] = { "R_386_PC16", rel }, + [R_386_8] = { "R_386_8", rel }, + [R_386_PC8] = { "R_386_PC8", rel }, + [R_386_TLS_GD_32] = { "R_386_TLS_GD_32", rel }, + [R_386_TLS_GD_PUSH] = { "R_386_TLS_GD_PUSH", rel }, + [R_386_TLS_GD_CALL] = { "R_386_TLS_GD_CALL", rel }, + [R_386_TLS_GD_POP] = { "R_386_TLS_GD_POP", rel }, + [R_386_TLS_LDM_32] = { "R_386_TLS_LDM_32", rel }, + [R_386_TLS_LDM_PUSH] = { "R_386_TLS_LDM_PUSH", rel }, + [R_386_TLS_LDM_CALL] = { "R_386_TLS_LDM_CALL", rel }, + [R_386_TLS_LDM_POP] = { "R_386_TLS_LDM_POP", rel }, + [R_386_TLS_LDO_32] = { "R_386_TLS_LDO_32", rel }, + [R_386_TLS_IE_32] = { "R_386_TLS_IE_32", rel }, + [R_386_TLS_LE_32] = { "R_386_TLS_LE_32", rel }, + [R_386_TLS_DTPMOD32] = { "R_386_TLS_DTPMOD32", rel }, + [R_386_TLS_DTPOFF32] = { "R_386_TLS_DTPOFF32", rel }, + [R_386_TLS_TPOFF32] = { "R_386_TLS_TPOFF32", rel } + }; + + +/* Determine relocation type string for x86. */ +const char * +i386_reloc_type_name (int type, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + if (type < 0 || type >= R_386_NUM) + return NULL; + + return reloc_map_table[type].name; +} + + +/* Check for correct relocation type. */ +bool +i386_reloc_type_check (int type) +{ + return (type >= R_386_NONE && type < R_386_NUM + && reloc_map_table[type].name != NULL) ? true : false; +} + + +/* Check for correct relocation type use. */ +bool +i386_reloc_valid_use (Elf *elf, int type) +{ + if (type < R_386_NONE || type >= R_386_NUM + || reloc_map_table[type].name == NULL) + return false; + + Elf32_Ehdr *ehdr = elf32_getehdr (elf); + assert (ehdr != NULL); + + if (reloc_map_table[type].appear == rel) + return ehdr->e_type == ET_REL; + + if (reloc_map_table[type].appear == exec) + return ehdr->e_type != ET_REL; + + assert (reloc_map_table[type].appear == both); + return true; +} + + +/* Return true if the symbol type is that referencing the GOT. */ +bool +i386_gotpc_reloc_check (Elf *elf __attribute__ ((unused)), int type) +{ + return type == R_386_GOTPC; +} + +/* Check for the simple reloc types. */ +Elf_Type +i386_reloc_simple_type (Elf *elf __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_386_32: + return ELF_T_SWORD; + case R_386_16: + return ELF_T_HALF; + case R_386_8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} + +/* Check section name for being that of a debug informatino section. */ +bool (*generic_debugscn_p) (const char *); +bool +i386_debugscn_p (const char *name) +{ + return (generic_debugscn_p (name) + || strcmp (name, ".stab") == 0 + || strcmp (name, ".stabstr") == 0); +} + +/* Check whether given relocation is a copy relocation. */ +bool +i386_copy_reloc_p (int reloc) +{ + return reloc == R_386_COPY; +} diff --git a/libebl/ia64_destr.c b/libebl/ia64_destr.c new file mode 100644 index 00000000..cb105f64 --- /dev/null +++ b/libebl/ia64_destr.c @@ -0,0 +1,27 @@ +/* Destructor for IA-64 specific backend library. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +void +ia64_destr (bh) + Ebl *bh __attribute__ ((unused)); +{ + /* Nothing to do so far. */ +} diff --git a/libebl/ia64_init.c b/libebl/ia64_init.c new file mode 100644 index 00000000..3cafe5de --- /dev/null +++ b/libebl/ia64_init.c @@ -0,0 +1,43 @@ +/* Initialization of IA-64 specific backend library. + Copyright (C) 2002, 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +const char * +ia64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Intel IA-64"; + eh->reloc_type_name = ia64_reloc_type_name; + eh->reloc_type_check = ia64_reloc_type_check; + eh->segment_type_name = ia64_segment_type_name; + eh->dynamic_tag_name = ia64_dynamic_tag_name; + eh->copy_reloc_p = ia64_copy_reloc_p; + eh->destr = ia64_destr; + + return MODVERSION; +} diff --git a/libebl/ia64_symbol.c b/libebl/ia64_symbol.c new file mode 100644 index 00000000..77ced76d --- /dev/null +++ b/libebl/ia64_symbol.c @@ -0,0 +1,187 @@ +/* IA-64 specific symbolic name handling. + Copyright (C) 2002, 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +/* Return of the backend. */ +const char * +ia64_backend_name (void) +{ + return "ia64"; +} + + +/* Relocation mapping table. */ +static const char *reloc_map_table[] = + { + [R_IA64_NONE] = "R_IA64_NONE", + [R_IA64_IMM14] = "R_IA64_IMM14", + [R_IA64_IMM22] = "R_IA64_IMM22", + [R_IA64_IMM64] = "R_IA64_IMM64", + [R_IA64_DIR32MSB] = "R_IA64_DIR32MSB", + [R_IA64_DIR32LSB] = "R_IA64_DIR32LSB", + [R_IA64_DIR64MSB] = "R_IA64_DIR64MSB", + [R_IA64_DIR64LSB] = "R_IA64_DIR64LSB", + [R_IA64_GPREL22] = "R_IA64_GPREL22", + [R_IA64_GPREL64I] = "R_IA64_GPREL64I", + [R_IA64_GPREL32MSB] = "R_IA64_GPREL32MSB", + [R_IA64_GPREL32LSB] = "R_IA64_GPREL32LSB", + [R_IA64_GPREL64MSB] = "R_IA64_GPREL64MSB", + [R_IA64_GPREL64LSB] = "R_IA64_GPREL64LSB", + [R_IA64_LTOFF22] = "R_IA64_LTOFF22", + [R_IA64_LTOFF64I] = "R_IA64_LTOFF64I", + [R_IA64_PLTOFF22] = "R_IA64_PLTOFF22", + [R_IA64_PLTOFF64I] = "R_IA64_PLTOFF64I", + [R_IA64_PLTOFF64MSB] = "R_IA64_PLTOFF64MSB", + [R_IA64_PLTOFF64LSB] = "R_IA64_PLTOFF64LSB", + [R_IA64_FPTR64I] = "R_IA64_FPTR64I", + [R_IA64_FPTR32MSB] = "R_IA64_FPTR32MSB", + [R_IA64_FPTR32LSB] = "R_IA64_FPTR32LSB", + [R_IA64_FPTR64MSB] = "R_IA64_FPTR64MSB", + [R_IA64_FPTR64LSB] = "R_IA64_FPTR64LSB", + [R_IA64_PCREL60B] = "R_IA64_PCREL60B", + [R_IA64_PCREL21B] = "R_IA64_PCREL21B", + [R_IA64_PCREL21M] = "R_IA64_PCREL21M", + [R_IA64_PCREL21F] = "R_IA64_PCREL21F", + [R_IA64_PCREL32MSB] = "R_IA64_PCREL32MSB", + [R_IA64_PCREL32LSB] = "R_IA64_PCREL32LSB", + [R_IA64_PCREL64MSB] = "R_IA64_PCREL64MSB", + [R_IA64_PCREL64LSB] = "R_IA64_PCREL64LSB", + [R_IA64_LTOFF_FPTR22] = "R_IA64_LTOFF_FPTR22", + [R_IA64_LTOFF_FPTR64I] = "R_IA64_LTOFF_FPTR64I", + [R_IA64_LTOFF_FPTR32MSB] = "R_IA64_LTOFF_FPTR32MSB", + [R_IA64_LTOFF_FPTR32LSB] = "R_IA64_LTOFF_FPTR32LSB", + [R_IA64_LTOFF_FPTR64MSB] = "R_IA64_LTOFF_FPTR64MSB", + [R_IA64_LTOFF_FPTR64LSB] = "R_IA64_LTOFF_FPTR64LSB", + [R_IA64_SEGREL32MSB] = "R_IA64_SEGREL32MSB", + [R_IA64_SEGREL32LSB] = "R_IA64_SEGREL32LSB", + [R_IA64_SEGREL64MSB] = "R_IA64_SEGREL64MSB", + [R_IA64_SEGREL64LSB] = "R_IA64_SEGREL64LSB", + [R_IA64_SECREL32MSB] = "R_IA64_SECREL32MSB", + [R_IA64_SECREL32LSB] = "R_IA64_SECREL32LSB", + [R_IA64_SECREL64MSB] = "R_IA64_SECREL64MSB", + [R_IA64_SECREL64LSB] = "R_IA64_SECREL64LSB", + [R_IA64_REL32MSB] = "R_IA64_REL32MSB", + [R_IA64_REL32LSB] = "R_IA64_REL32LSB", + [R_IA64_REL64MSB] = "R_IA64_REL64MSB", + [R_IA64_REL64LSB] = "R_IA64_REL64LSB", + [R_IA64_LTV32MSB] = "R_IA64_LTV32MSB", + [R_IA64_LTV32LSB] = "R_IA64_LTV32LSB", + [R_IA64_LTV64MSB] = "R_IA64_LTV64MSB", + [R_IA64_LTV64LSB] = "R_IA64_LTV64LSB", + [R_IA64_PCREL21BI] = "R_IA64_PCREL21BI", + [R_IA64_PCREL22] = "R_IA64_PCREL22", + [R_IA64_PCREL64I] = "R_IA64_PCREL64I", + [R_IA64_IPLTMSB] = "R_IA64_IPLTMSB", + [R_IA64_IPLTLSB] = "R_IA64_IPLTLSB", + [R_IA64_COPY] = "R_IA64_COPY", + [R_IA64_SUB] = "R_IA64_SUB", + [R_IA64_LTOFF22X] = "R_IA64_LTOFF22X", + [R_IA64_LDXMOV] = "R_IA64_LDXMOV", + [R_IA64_TPREL14] = "R_IA64_TPREL14", + [R_IA64_TPREL22] = "R_IA64_TPREL22", + [R_IA64_TPREL64I] = "R_IA64_TPREL64I", + [R_IA64_TPREL64MSB] = "R_IA64_TPREL64MSB", + [R_IA64_TPREL64LSB] = "R_IA64_TPREL64LSB", + [R_IA64_LTOFF_TPREL22] = "R_IA64_LTOFF_TPREL22", + [R_IA64_DTPMOD64MSB] = "R_IA64_DTPMOD64MSB", + [R_IA64_DTPMOD64LSB] = "R_IA64_DTPMOD64LSB", + [R_IA64_LTOFF_DTPMOD22] = "R_IA64_LTOFF_DTPMOD22", + [R_IA64_DTPREL14] = "R_IA64_DTPREL14", + [R_IA64_DTPREL22] = "R_IA64_DTPREL22", + [R_IA64_DTPREL64I] = "R_IA64_DTPREL64I", + [R_IA64_DTPREL32MSB] = "R_IA64_DTPREL32MSB", + [R_IA64_DTPREL32LSB] = "R_IA64_DTPREL32LSB", + [R_IA64_DTPREL64MSB] = "R_IA64_DTPREL64MSB", + [R_IA64_DTPREL64LSB] = "R_IA64_DTPREL64LSB", + [R_IA64_LTOFF_DTPREL22] = "R_IA64_LTOFF_DTPREL22" + }; + + +/* Determine relocation type string for IA-64. */ +const char * +ia64_reloc_type_name (int type, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + if (type < 0 + || ((size_t) type + >= sizeof (reloc_map_table) / sizeof (reloc_map_table[0]))) + return NULL; + + return reloc_map_table[type]; +} + + +/* Check for correct relocation type. */ +bool +ia64_reloc_type_check (int type) +{ + return (type >= R_IA64_NONE + && ((size_t) type + < sizeof (reloc_map_table) / sizeof (reloc_map_table[0])) + && reloc_map_table[type] != NULL) ? true : false; +} + + +const char * +ia64_segment_type_name (int segment, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (segment) + { + case PT_IA_64_ARCHEXT: + return "IA_64_ARCHEXT"; + case PT_IA_64_UNWIND: + return "IA_64_UNWIND"; + case PT_IA_64_HP_OPT_ANOT: + return "IA_64_HP_OPT_ANOT"; + case PT_IA_64_HP_HSL_ANOT: + return "IA_64_HP_HSL_ANOT"; + case PT_IA_64_HP_STACK: + return "IA_64_HP_STACK"; + default: + break; + } + return NULL; +} + + +const char * +ia64_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_IA_64_PLT_RESERVE: + return "IA_64_PLT_RESERVE"; + default: + break; + } + return NULL; +} + +/* Check whether given relocation is a copy relocation. */ +bool +ia64_copy_reloc_p (int reloc) +{ + return reloc == R_IA64_COPY; +} diff --git a/libebl/libebl.h b/libebl/libebl.h new file mode 100644 index 00000000..aff9ca5e --- /dev/null +++ b/libebl/libebl.h @@ -0,0 +1,208 @@ +/* Interface for libebl. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBEBL_H +#define _LIBEBL_H 1 + +#include +#include +#include +#include + +#include + + +/* Opaque type for the handle. */ +typedef struct ebl Ebl; + + +/* Get backend handle for object associated with ELF handle. */ +extern Ebl *ebl_openbackend (Elf *elf); +/* Similar but without underlying ELF file. */ +extern Ebl *ebl_openbackend_machine (GElf_Half machine); +/* Similar but with emulation name given. */ +extern Ebl *ebl_openbackend_emulation (const char *emulation); + +/* Free resources allocated for backend handle. */ +extern void ebl_closebackend (Ebl *bh); + + +/* Function to call the callback functions including default ELF + handling. */ + +/* Return backend name. */ +extern const char *ebl_backend_name (Ebl *ebl); + +/* Return relocation type name. */ +extern const char *ebl_object_type_name (Ebl *ebl, int object, + char *buf, size_t len); + +/* Return relocation type name. */ +extern const char *ebl_reloc_type_name (Ebl *ebl, int reloc, + char *buf, size_t len); + +/* Check relocation type. */ +extern bool ebl_reloc_type_check (Ebl *ebl, int reloc); + +/* Check relocation type use. */ +extern bool ebl_reloc_valid_use (Ebl *ebl, int reloc); + +/* Check if relocation type is for simple absolute relocations. + Return ELF_T_{BYTE,HALF,SWORD,SXWORD} for a simple type, else ELF_T_NUM. */ +extern Elf_Type ebl_reloc_simple_type (Ebl *ebl, int reloc); + +/* Return true if the symbol type is that referencing the GOT. E.g., + R_386_GOTPC. */ +extern bool ebl_gotpc_reloc_check (Ebl *ebl, int reloc); + +/* Return segment type name. */ +extern const char *ebl_segment_type_name (Ebl *ebl, int segment, + char *buf, size_t len); + +/* Return section type name. */ +extern const char *ebl_section_type_name (Ebl *ebl, int section, + char *buf, size_t len); + +/* Return section name. */ +extern const char *ebl_section_name (Ebl *ebl, int section, int xsection, + char *buf, size_t len, + const char *scnnames[], size_t shnum); + +/* Return machine flag names. */ +extern const char *ebl_machine_flag_name (Ebl *ebl, GElf_Word flags, + char *buf, size_t len); + +/* Check whether machine flag is valid. */ +extern bool ebl_machine_flag_check (Ebl *ebl, GElf_Word flags); + +/* Return symbol type name. */ +extern const char *ebl_symbol_type_name (Ebl *ebl, int symbol, + char *buf, size_t len); + +/* Return symbol binding name. */ +extern const char *ebl_symbol_binding_name (Ebl *ebl, int binding, + char *buf, size_t len); + +/* Return dynamic tag name. */ +extern const char *ebl_dynamic_tag_name (Ebl *ebl, int64_t tag, + char *buf, size_t len); + +/* Check dynamic tag. */ +extern bool ebl_dynamic_tag_check (Ebl *ebl, int64_t tag); + +/* Return combined section header flags value. */ +extern GElf_Word ebl_sh_flags_combine (Ebl *ebl, GElf_Word flags1, + GElf_Word flags2); + +/* Return symbolic representation of OS ABI. */ +extern const char *ebl_osabi_name (Ebl *ebl, int osabi, char *buf, size_t len); + + +/* Return name of the note section type for a core file. */ +extern const char *ebl_core_note_type_name (Ebl *ebl, uint32_t type, char *buf, + size_t len); + +/* Return name of the note section type for an object file. */ +extern const char *ebl_object_note_type_name (Ebl *ebl, uint32_t type, + char *buf, size_t len); + +/* Print information about core note if available. */ +extern void ebl_core_note (Ebl *ebl, const char *name, uint32_t type, + uint32_t descsz, const char *desc); + +/* Print information about object note if available. */ +extern void ebl_object_note (Ebl *ebl, const char *name, uint32_t type, + uint32_t descsz, const char *desc); + +/* Check section name for being that of a debug informatino section. */ +extern bool ebl_debugscn_p (Ebl *ebl, const char *name); + +/* Check whether given relocation is a copy relocation. */ +extern bool ebl_copy_reloc_p (Ebl *ebl, int reloc); + + +/* CHeck whether section should be stripped. */ +extern bool ebl_section_strip_p (Ebl *ebl, const GElf_Ehdr *ehdr, + const GElf_Shdr *shdr, const char *name, + bool remove_comment, bool only_remove_debug); + + +/* ELF string table handling. */ +struct Ebl_Strtab; +struct Ebl_Strent; + +/* Create new ELF string table object in memory. */ +extern struct Ebl_Strtab *ebl_strtabinit (bool nullstr); + +/* Free resources allocated for ELF string table ST. */ +extern void ebl_strtabfree (struct Ebl_Strtab *st); + +/* Add string STR (length LEN is != 0) to ELF string table ST. */ +extern struct Ebl_Strent *ebl_strtabadd (struct Ebl_Strtab *st, + const char *str, size_t len); + +/* Finalize string table ST and store size and memory location information + in DATA. */ +extern void ebl_strtabfinalize (struct Ebl_Strtab *st, Elf_Data *data); + +/* Get offset in string table for string associated with SE. */ +extern size_t ebl_strtaboffset (struct Ebl_Strent *se); + +/* Return the string associated with SE. */ +extern const char *ebl_string (struct Ebl_Strent *se); + + +/* ELF wide char string table handling. */ +struct Ebl_WStrtab; +struct Ebl_WStrent; + +/* Create new ELF wide char string table object in memory. */ +extern struct Ebl_WStrtab *ebl_wstrtabinit (bool nullstr); + +/* Free resources allocated for ELF wide char string table ST. */ +extern void ebl_wstrtabfree (struct Ebl_WStrtab *st); + +/* Add string STR (length LEN is != 0) to ELF string table ST. */ +extern struct Ebl_WStrent *ebl_wstrtabadd (struct Ebl_WStrtab *st, + const wchar_t *str, size_t len); + +/* Finalize string table ST and store size and memory location information + in DATA. */ +extern void ebl_wstrtabfinalize (struct Ebl_WStrtab *st, Elf_Data *data); + +/* Get offset in wide char string table for string associated with SE. */ +extern size_t ebl_wstrtaboffset (struct Ebl_WStrent *se); + + +/* Generic string table handling. */ +struct Ebl_GStrtab; +struct Ebl_GStrent; + +/* Create new string table object in memory. */ +extern struct Ebl_GStrtab *ebl_gstrtabinit (unsigned int width, bool nullstr); + +/* Free resources allocated for string table ST. */ +extern void ebl_gstrtabfree (struct Ebl_GStrtab *st); + +/* Add string STR (length LEN is != 0) to string table ST. */ +extern struct Ebl_GStrent *ebl_gstrtabadd (struct Ebl_GStrtab *st, + const char *str, size_t len); + +/* Finalize string table ST and store size and memory location information + in DATA. */ +extern void ebl_gstrtabfinalize (struct Ebl_GStrtab *st, Elf_Data *data); + +/* Get offset in wide char string table for string associated with SE. */ +extern size_t ebl_gstrtaboffset (struct Ebl_GStrent *se); + +#endif /* libebl.h */ diff --git a/libebl/libeblP.h b/libebl/libeblP.h new file mode 100644 index 00000000..21bb8fff --- /dev/null +++ b/libebl/libeblP.h @@ -0,0 +1,118 @@ +/* Internal definitions for interface for libebl. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBEBLP_H +#define _LIBEBLP_H 1 + +#include +#include +#include + + +/* Backend handle. */ +struct ebl +{ + /* Machine name. */ + const char *name; + + /* Emulation name. */ + const char *emulation; + + /* The libelf handle (if known). */ + Elf *elf; + + /* Return symbol representaton of object file type. */ + const char *(*object_type_name) (int, char *, size_t); + + /* Return symbolic representation of relocation type. */ + const char *(*reloc_type_name) (int, char *, size_t); + + /* Check relocation type. */ + bool (*reloc_type_check) (int); + + /* Check if relocation type is for simple absolute relocations. */ + Elf_Type (*reloc_simple_type) (Elf *, int); + + /* Check relocation type use. */ + bool (*reloc_valid_use) (Elf *, int); + + /* Return true if the symbol type is that referencing the GOT. */ + bool (*gotpc_reloc_check) (Elf *, int); + + /* Return symbolic representation of segment type. */ + const char *(*segment_type_name) (int, char *, size_t); + + /* Return symbolic representation of section type. */ + const char *(*section_type_name) (int, char *, size_t); + + /* Return section name. */ + const char *(*section_name) (int, int, char *, size_t); + + /* Return next machine flag name. */ + const char *(*machine_flag_name) (GElf_Word *); + + /* Check whether machine flags are valid. */ + bool (*machine_flag_check) (GElf_Word); + + /* Return symbolic representation of symbol type. */ + const char *(*symbol_type_name) (int, char *, size_t); + + /* Return symbolic representation of symbol binding. */ + const char *(*symbol_binding_name) (int, char *, size_t); + + /* Return symbolic representation of dynamic tag. */ + const char *(*dynamic_tag_name) (int64_t, char *, size_t); + + /* Check dynamic tag. */ + bool (*dynamic_tag_check) (int64_t); + + /* Combine section header flags values. */ + GElf_Word (*sh_flags_combine) (GElf_Word, GElf_Word); + + /* Return symbolic representation of OS ABI. */ + const char *(*osabi_name) (int, char *, size_t); + + /* Name of a note entry type for core files. */ + const char *(*core_note_type_name) (uint32_t, char *, size_t); + + /* Name of a note entry type for object files. */ + const char *(*object_note_type_name) (uint32_t, char *, size_t); + + /* Handle core note. */ + bool (*core_note) (const char *, uint32_t, uint32_t, const char *); + + /* Handle object file note. */ + bool (*object_note) (const char *, uint32_t, uint32_t, const char *); + + /* Check section name for being that of a debug informatino section. */ + bool (*debugscn_p) (const char *); + + /* Check whether given relocation is a copy relocation. */ + bool (*copy_reloc_p) (int); + + /* Destructor for ELF backend handle. */ + void (*destr) (struct ebl *); + + /* Internal data. */ + void *dlhandle; +}; + + +/* Type of the initialization functions in the backend modules. */ +typedef const char *(*ebl_bhinit_t) (Elf *, GElf_Half, Ebl *, size_t); + + +/* gettext helper macros. */ +#define _(Str) dgettext ("elfutils", Str) + +#endif /* libeblP.h */ diff --git a/libebl/libebl_alpha.h b/libebl/libebl_alpha.h new file mode 100644 index 00000000..7990d995 --- /dev/null +++ b/libebl/libebl_alpha.h @@ -0,0 +1,37 @@ +/* Interface for libebl_alpha module. + Copyright (C) 2002, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBEBL_ALPHA_H +#define _LIBEBL_ALPHA_H 1 + +#include + + +/* Constructor. */ +extern const char *alpha_init (Elf *elf, GElf_Half machine, Ebl *eh, + size_t ehlen); + +/* Destructor. */ +extern void alpha_destr (Ebl *bh); + + +/* Function to get relocation type name. */ +extern const char *alpha_reloc_type_name (int type, char *buf, size_t len); + +/* Check relocation type. */ +extern bool alpha_reloc_type_check (int type); + +/* Check whether given relocation is a copy relocation. */ +extern bool alpha_copy_reloc_p (int reloc); + +#endif /* libebl_alpha.h */ diff --git a/libebl/libebl_alpha.map b/libebl/libebl_alpha.map new file mode 100644 index 00000000..aa66ad75 --- /dev/null +++ b/libebl/libebl_alpha.map @@ -0,0 +1,11 @@ +ELFUTILS_1.0 { + global: + alpha_backend_name; + alpha_destr; + alpha_init; + alpha_reloc_type_check; + alpha_reloc_type_name; + + local: + *; +}; diff --git a/libebl/libebl_arm.h b/libebl/libebl_arm.h new file mode 100644 index 00000000..18bb99c4 --- /dev/null +++ b/libebl/libebl_arm.h @@ -0,0 +1,37 @@ +/* Interface for libebl_arm module. + Copyright (C) 2002, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBEBL_ARM_H +#define _LIBEBL_ARM_H 1 + +#include + + +/* Constructor. */ +extern const char *arm_init (Elf *elf, GElf_Half machine, Ebl *eh, + size_t ehlen); + +/* Destructor. */ +extern void arm_destr (Ebl *bh); + + +/* Function to get relocation type name. */ +extern const char *arm_reloc_type_name (int type, char *buf, size_t len); + +/* Check relocation type. */ +extern bool arm_reloc_type_check (int type); + +/* Check whether given relocation is a copy relocation. */ +extern bool arm_copy_reloc_p (int reloc); + +#endif /* libebl_arm.h */ diff --git a/libebl/libebl_arm.map b/libebl/libebl_arm.map new file mode 100644 index 00000000..d389526c --- /dev/null +++ b/libebl/libebl_arm.map @@ -0,0 +1,11 @@ +ELFUTILS_1.0 { + global: + arm_backend_name; + arm_destr; + arm_init; + arm_reloc_type_check; + arm_reloc_type_name; + + local: + *; +}; diff --git a/libebl/libebl_i386.h b/libebl/libebl_i386.h new file mode 100644 index 00000000..ef2b3199 --- /dev/null +++ b/libebl/libebl_i386.h @@ -0,0 +1,54 @@ +/* Interface for libebl_i386 module. + Copyright (C) 2000, 2001, 2002, 2003, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBEBL_I386_H +#define _LIBEBL_I386_H 1 + +#include + + +/* Constructor. */ +extern const char *i386_init (Elf *elf, GElf_Half machine, Ebl *eh, + size_t ehlen); + +/* Destructor. */ +extern void i386_destr (Ebl *bh); + + +/* Function to get relocation type name. */ +extern const char *i386_reloc_type_name (int type, char *buf, size_t len); + +/* Check relocation type. */ +extern bool i386_reloc_type_check (int type); + +/* Check relocation type use. */ +extern bool i386_reloc_valid_use (Elf *elf, int type); + +/* Check for the simple reloc types. */ +extern Elf_Type i386_reloc_simple_type (Elf *elf, int type); + +/* Check relocation type use. */ +extern bool i386_gotpc_reloc_check (Elf *elf, int type); + +/* Code note handling. */ +extern bool i386_core_note (const char *name, uint32_t type, uint32_t descsz, + const char *desc); + +/* Check section name for being that of a debug informatino section. */ +extern bool i386_debugscn_p (const char *name); +extern bool (*generic_debugscn_p) (const char *); + +/* Check whether given relocation is a copy relocation. */ +extern bool i386_copy_reloc_p (int reloc); + +#endif /* libebl_i386.h */ diff --git a/libebl/libebl_i386.map b/libebl/libebl_i386.map new file mode 100644 index 00000000..d0c910c7 --- /dev/null +++ b/libebl/libebl_i386.map @@ -0,0 +1,14 @@ +ELFUTILS_1.0 { + global: + i386_backend_name; + i386_core_note; + i386_destr; + i386_init; + i386_reloc_type_check; + i386_reloc_type_name; + i386_reloc_valid_use; + i386_reloc_simple_type; + + local: + *; +}; diff --git a/libebl/libebl_ia64.h b/libebl/libebl_ia64.h new file mode 100644 index 00000000..8dea6500 --- /dev/null +++ b/libebl/libebl_ia64.h @@ -0,0 +1,43 @@ +/* Interface for libebl_ia64 module. + Copyright (C) 2002, 2003, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBEBL_IA64_H +#define _LIBEBL_IA64_H 1 + +#include + + +/* Constructor. */ +extern const char *ia64_init (Elf *elf, GElf_Half machine, Ebl *eh, + size_t ehlen); + +/* Destructor. */ +extern void ia64_destr (Ebl *bh); + + +/* Function to get relocation type name. */ +extern const char *ia64_reloc_type_name (int type, char *buf, size_t len); + +/* Check relocation type. */ +extern bool ia64_reloc_type_check (int type); + +/* Name of segment type. */ +extern const char *ia64_segment_type_name (int segment, char *buf, size_t len); + +/* Name of dynamic tag. */ +extern const char *ia64_dynamic_tag_name (int64_t tag, char *buf, size_t len); + +/* Check whether given relocation is a copy relocation. */ +extern bool ia64_copy_reloc_p (int reloc); + +#endif /* libebl_ia64.h */ diff --git a/libebl/libebl_ia64.map b/libebl/libebl_ia64.map new file mode 100644 index 00000000..f67042c6 --- /dev/null +++ b/libebl/libebl_ia64.map @@ -0,0 +1,11 @@ +ELFUTILS_1.0 { + global: + ia64_backend_name; + ia64_destr; + ia64_init; + ia64_reloc_type_check; + ia64_reloc_type_name; + + local: + *; +}; diff --git a/libebl/libebl_ppc.h b/libebl/libebl_ppc.h new file mode 100644 index 00000000..1e646d4f --- /dev/null +++ b/libebl/libebl_ppc.h @@ -0,0 +1,47 @@ +/* Interface for libebl_PPC module. + Copyright (C) 2004, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBEBL_PPC_H +#define _LIBEBL_PPC_H 1 + +#include + + +/* Constructor. */ +extern const char *ppc_init (Elf *elf, GElf_Half machine, Ebl *eh, + size_t ehlen); + +/* Destructor. */ +extern void ppc_destr (Ebl *bh); + + +/* Function to get relocation type name. */ +extern const char *ppc_reloc_type_name (int type, char *buf, size_t len); + +/* Check relocation type. */ +extern bool ppc_reloc_type_check (int type); + +/* Check relocation type use. */ +extern bool ppc_reloc_valid_use (Elf *elf, int type); + +/* Check for the simple reloc types. */ +extern Elf_Type ppc_reloc_simple_type (Elf *elf, int type); + +/* Code note handling. */ +extern bool ppc_core_note (const char *name, uint32_t type, uint32_t descsz, + const char *desc); + +/* Check whether given relocation is a copy relocation. */ +extern bool ppc_copy_reloc_p (int reloc); + +#endif /* libebl_ppc.h */ diff --git a/libebl/libebl_ppc.map b/libebl/libebl_ppc.map new file mode 100644 index 00000000..3d49c0b3 --- /dev/null +++ b/libebl/libebl_ppc.map @@ -0,0 +1,12 @@ +ELFUTILS_1.0 { + global: + ppc_backend_name; + ppc_destr; + ppc_init; + ppc_reloc_type_check; + ppc_reloc_type_name; + ppc_reloc_simple_type; + + local: + *; +}; diff --git a/libebl/libebl_ppc64.h b/libebl/libebl_ppc64.h new file mode 100644 index 00000000..e737c56a --- /dev/null +++ b/libebl/libebl_ppc64.h @@ -0,0 +1,50 @@ +/* Interface for libebl_PPC64 module. + Copyright (C) 2004, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBEBL_PPC64_H +#define _LIBEBL_PPC64_H 1 + +#include + + +/* Constructor. */ +extern const char *ppc64_init (Elf *elf, GElf_Half machine, Ebl *eh, + size_t ehlen); + +/* Destructor. */ +extern void ppc64_destr (Ebl *bh); + + +/* Function to get relocation type name. */ +extern const char *ppc64_reloc_type_name (int type, char *buf, size_t len); + +/* Check relocation type. */ +extern bool ppc64_reloc_type_check (int type); + +/* Check relocation type use. */ +extern bool ppc64_reloc_valid_use (Elf *elf, int type); + +/* Check for the simple reloc types. */ +extern Elf_Type ppc64_reloc_simple_type (Elf *elf, int type); + +/* Code note handling. */ +extern bool ppc64_core_note (const char *name, uint32_t type, uint32_t descsz, + const char *desc); + +/* Name of dynamic tag. */ +extern const char *ppc64_dynamic_tag_name (int64_t tag, char *buf, size_t len); + +/* Check whether given relocation is a copy relocation. */ +extern bool ppc64_copy_reloc_p (int reloc); + +#endif /* libebl_ppc.h */ diff --git a/libebl/libebl_ppc64.map b/libebl/libebl_ppc64.map new file mode 100644 index 00000000..260805d4 --- /dev/null +++ b/libebl/libebl_ppc64.map @@ -0,0 +1,12 @@ +ELFUTILS_1.0 { + global: + ppc64_backend_name; + ppc64_destr; + ppc64_init; + ppc64_reloc_type_check; + ppc64_reloc_type_name; + ppc64_reloc_simple_type; + + local: + *; +}; diff --git a/libebl/libebl_sh.h b/libebl/libebl_sh.h new file mode 100644 index 00000000..32b029a7 --- /dev/null +++ b/libebl/libebl_sh.h @@ -0,0 +1,34 @@ +/* Interface for libebl_sh module. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBEBL_SH_H +#define _LIBEBL_SH_H 1 + +#include + + +/* Constructor. */ +extern const char *sh_init (Elf *elf, GElf_Half machine, Ebl *eh, + size_t ehlen); + +/* Destructor. */ +extern void sh_destr (Ebl *bh); + + +/* Function to get relocation type name. */ +extern const char *sh_reloc_type_name (int type, char *buf, size_t len); + +/* Check whether given relocation is a copy relocation. */ +extern bool sh_copy_reloc_p (int reloc); + +#endif /* libebl_sh.h */ diff --git a/libebl/libebl_sh.map b/libebl/libebl_sh.map new file mode 100644 index 00000000..252720a9 --- /dev/null +++ b/libebl/libebl_sh.map @@ -0,0 +1,10 @@ +ELFUTILS_1.0 { + global: + sh_backend_name; + sh_destr; + sh_init; + sh_reloc_type_name; + + local: + *; +}; diff --git a/libebl/libebl_sparc.h b/libebl/libebl_sparc.h new file mode 100644 index 00000000..077db170 --- /dev/null +++ b/libebl/libebl_sparc.h @@ -0,0 +1,41 @@ +/* Interface for libebl_sparc module. + Copyright (C) 2002, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBEBL_SPARC_H +#define _LIBEBL_SPARC_H 1 + +#include + + +/* Constructor. */ +extern const char *sparc_init (Elf *elf, GElf_Half machine, Ebl *eh, + size_t ehlen); + +/* Destructor. */ +extern void sparc_destr (Ebl *bh); + + +/* Function to get relocation type name. */ +extern const char *sparc_reloc_type_name (int type, char *buf, size_t len); + +/* Check relocation type. */ +extern bool sparc_reloc_type_check (int type); + +/* Code note handling. */ +extern bool sparc_core_note (const char *name, uint32_t type, uint32_t descsz, + const char *desc); + +/* Check whether given relocation is a copy relocation. */ +extern bool sparc_copy_reloc_p (int reloc); + +#endif /* libebl_sparc.h */ diff --git a/libebl/libebl_sparc.map b/libebl/libebl_sparc.map new file mode 100644 index 00000000..7ca60383 --- /dev/null +++ b/libebl/libebl_sparc.map @@ -0,0 +1,11 @@ +ELFUTILS_1.0 { + global: + sparc_backend_name; + sparc_destr; + sparc_init; + sparc_reloc_type_check; + sparc_reloc_type_name; + + local: + *; +}; diff --git a/libebl/libebl_x86_64.h b/libebl/libebl_x86_64.h new file mode 100644 index 00000000..025edb63 --- /dev/null +++ b/libebl/libebl_x86_64.h @@ -0,0 +1,47 @@ +/* Interface for libebl_x86_64 module. + Copyright (C) 2002, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBEBL_X86_64_H +#define _LIBEBL_X86_64_H 1 + +#include + + +/* Constructor. */ +extern const char *x86_64_init (Elf *elf, GElf_Half machine, Ebl *eh, + size_t ehlen); + +/* Destructor. */ +extern void x86_64_destr (Ebl *bh); + + +/* Function to get relocation type name. */ +extern const char *x86_64_reloc_type_name (int type, char *buf, size_t len); + +/* Check relocation type. */ +extern bool x86_64_reloc_type_check (int type); + +/* Check relocation type use. */ +extern bool x86_64_reloc_valid_use (Elf *elf, int type); + +/* Check for the simple reloc types. */ +extern Elf_Type x86_64_reloc_simple_type (Elf *elf, int type); + +/* Code note handling. */ +extern bool x86_64_core_note (const char *name, uint32_t type, uint32_t descsz, + const char *desc); + +/* Check whether given relocation is a copy relocation. */ +extern bool x86_64_copy_reloc_p (int reloc); + +#endif /* libebl_x86_64.h */ diff --git a/libebl/libebl_x86_64.map b/libebl/libebl_x86_64.map new file mode 100644 index 00000000..e6d1c7bd --- /dev/null +++ b/libebl/libebl_x86_64.map @@ -0,0 +1,13 @@ +ELFUTILS_1.0 { + global: + x86_64_backend_name; + x86_64_core_note; + x86_64_destr; + x86_64_init; + x86_64_reloc_type_check; + x86_64_reloc_type_name; + x86_64_reloc_simple_type; + + local: + *; +}; diff --git a/libebl/ppc64_destr.c b/libebl/ppc64_destr.c new file mode 100644 index 00000000..8da6a8fd --- /dev/null +++ b/libebl/ppc64_destr.c @@ -0,0 +1,27 @@ +/* Destructor for PPC64 specific backend library. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +void +ppc64_destr (bh) + Ebl *bh __attribute__ ((unused)); +{ + /* Nothing to do so far. */ +} diff --git a/libebl/ppc64_init.c b/libebl/ppc64_init.c new file mode 100644 index 00000000..8231a32d --- /dev/null +++ b/libebl/ppc64_init.c @@ -0,0 +1,44 @@ +/* Initialization of PPC64 specific backend library. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +const char * +ppc64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "PowerPC 64-bit"; + eh->reloc_type_name = ppc64_reloc_type_name; + eh->reloc_type_check = ppc64_reloc_type_check; + eh->reloc_valid_use = ppc64_reloc_valid_use; + eh->reloc_simple_type = ppc64_reloc_simple_type; + eh->dynamic_tag_name = ppc64_dynamic_tag_name; + eh->copy_reloc_p = ppc64_copy_reloc_p; + eh->destr = ppc64_destr; + + return MODVERSION; +} diff --git a/libebl/ppc64_symbol.c b/libebl/ppc64_symbol.c new file mode 100644 index 00000000..f844816b --- /dev/null +++ b/libebl/ppc64_symbol.c @@ -0,0 +1,235 @@ +/* PPC64 specific symbolic name handling. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include + + +/* Return of the backend. */ +const char * +ppc64_backend_name (void) +{ + return "ppc64"; +} + + +/* Relocation mapping table. */ +static struct +{ + const char *name; + enum { both = 0, rel = 1, exec = 2 } appear; +} reloc_map_table[] = + { + // XXX Check all the appear values. + [R_PPC64_NONE] = { "R_PPC64_NONE", both }, + [R_PPC64_ADDR32] = { "R_PPC64_ADDR32", both }, + [R_PPC64_ADDR24] = { "R_PPC64_ADDR24", both }, + [R_PPC64_ADDR16] = { "R_PPC64_ADDR16", both }, + [R_PPC64_ADDR16_LO] = { "R_PPC64_ADDR16_LO", both }, + [R_PPC64_ADDR16_HI] = { "R_PPC64_ADDR16_HI", both }, + [R_PPC64_ADDR16_HA] = { "R_PPC64_ADDR16_HA", both }, + [R_PPC64_ADDR14] = { "R_PPC64_ADDR14", both }, + [R_PPC64_ADDR14_BRTAKEN] = { "R_PPC64_ADDR14_BRTAKEN", exec }, + [R_PPC64_ADDR14_BRNTAKEN] = { "R_PPC64_ADDR14_BRNTAKEN", exec }, + [R_PPC64_REL24] = { "R_PPC64_REL24", both }, + [R_PPC64_REL14] = { "R_PPC64_REL14", both }, + [R_PPC64_REL14_BRTAKEN] = { "R_PPC64_REL14_BRTAKEN", exec }, + [R_PPC64_REL14_BRNTAKEN] = { "R_PPC64_REL14_BRNTAKEN", exec }, + [R_PPC64_GOT16] = { "R_PPC64_GOT16", rel }, + [R_PPC64_GOT16_LO] = { "R_PPC64_GOT16_LO", rel }, + [R_PPC64_GOT16_HI] = { "R_PPC64_GOT16_HI", rel }, + [R_PPC64_GOT16_HA] = { "R_PPC64_GOT16_HA", rel }, + [R_PPC64_COPY] = { "R_PPC64_COPY", exec }, + [R_PPC64_GLOB_DAT] = { "R_PPC64_GLOB_DAT", exec }, + [R_PPC64_JMP_SLOT] = { "R_PPC64_JMP_SLOT", exec }, + [R_PPC64_RELATIVE] = { "R_PPC64_RELATIVE", exec }, + [R_PPC64_UADDR32] = { "R_PPC64_UADDR32", exec }, + [R_PPC64_UADDR16] = { "R_PPC64_UADDR16", exec }, + [R_PPC64_REL32] = { "R_PPC64_REL32", exec }, + [R_PPC64_PLT32] = { "R_PPC64_PLT32", exec }, + [R_PPC64_PLTREL32] = { "R_PPC64_PLTREL32", both }, + [R_PPC64_PLT16_LO] = { "R_PPC64_PLT16_LO", both }, + [R_PPC64_PLT16_HI] = { "R_PPC64_PLT16_HI", both }, + [R_PPC64_PLT16_HA] = { "R_PPC64_PLT16_HA", both }, + [R_PPC64_SECTOFF] = { "R_PPC64_SECTOFF", both }, + [R_PPC64_SECTOFF_LO] = { "R_PPC64_SECTOFF_LO", both }, + [R_PPC64_SECTOFF_HI] = { "R_PPC64_SECTOFF_HI", both }, + [R_PPC64_SECTOFF_HA] = { "R_PPC64_SECTOFF_HA", both }, + [R_PPC64_ADDR30] = { "R_PPC64_ADDR30", both }, + [R_PPC64_ADDR64] = { "R_PPC64_ADDR64", both }, + [R_PPC64_ADDR16_HIGHER] = { "R_PPC64_ADDR16_HIGHER", both }, + [R_PPC64_ADDR16_HIGHERA] = { "R_PPC64_ADDR16_HIGHERA", both }, + [R_PPC64_ADDR16_HIGHEST] = { "R_PPC64_ADDR16_HIGHEST", both }, + [R_PPC64_ADDR16_HIGHESTA] = { "R_PPC64_ADDR16_HIGHESTA", both }, + [R_PPC64_UADDR64] = { "R_PPC64_UADDR64", both }, + [R_PPC64_REL64] = { "R_PPC64_REL64", both }, + [R_PPC64_PLT64] = { "R_PPC64_PLT64", both }, + [R_PPC64_PLTREL64] = { "R_PPC64_PLTREL64", both }, + [R_PPC64_TOC16] = { "R_PPC64_TOC16", both }, + [R_PPC64_TOC16_LO] = { "R_PPC64_TOC16_LO", both }, + [R_PPC64_TOC16_HI] = { "R_PPC64_TOC16_HI", both }, + [R_PPC64_TOC16_HA] = { "R_PPC64_TOC16_HA", both }, + [R_PPC64_TOC] = { "R_PPC64_TOC", both }, + [R_PPC64_PLTGOT16] = { "R_PPC64_PLTGOT16", both }, + [R_PPC64_PLTGOT16_LO] = { "R_PPC64_PLTGOT16_LO", both }, + [R_PPC64_PLTGOT16_HI] = { "R_PPC64_PLTGOT16_HI", both }, + [R_PPC64_PLTGOT16_HA] = { "R_PPC64_PLTGOT16_HA", both }, + [R_PPC64_ADDR16_DS] = { "R_PPC64_ADDR16_DS", both }, + [R_PPC64_ADDR16_LO_DS] = { "R_PPC64_ADDR16_LO_DS", both }, + [R_PPC64_GOT16_DS] = { "R_PPC64_GOT16_DS", both }, + [R_PPC64_GOT16_LO_DS] = { "R_PPC64_GOT16_LO_DS", both }, + [R_PPC64_PLT16_LO_DS] = { "R_PPC64_PLT16_LO_DS", both }, + [R_PPC64_SECTOFF_DS] = { "R_PPC64_SECTOFF_DS", both }, + [R_PPC64_SECTOFF_LO_DS] = { "R_PPC64_SECTOFF_LO_DS", both }, + [R_PPC64_TOC16_DS] = { "R_PPC64_TOC16_DS", both }, + [R_PPC64_TOC16_LO_DS] = { "R_PPC64_TOC16_LO_DS", both }, + [R_PPC64_PLTGOT16_DS] = { "R_PPC64_PLTGOT16_DS", both }, + [R_PPC64_PLTGOT16_LO_DS] = { "R_PPC64_PLTGOT16_LO_DS", both }, + [R_PPC64_TLS] = { "R_PPC64_TLS", both }, + [R_PPC64_DTPMOD64] = { "R_PPC64_DTPMOD64", both }, + [R_PPC64_TPREL16] = { "R_PPC64_TPREL16", both }, + [R_PPC64_TPREL16_LO] = { "R_PPC64_TPREL16_LO", both }, + [R_PPC64_TPREL16_HI] = { "R_PPC64_TPREL16_HI", both }, + [R_PPC64_TPREL16_HA] = { "R_PPC64_TPREL16_HA", both }, + [R_PPC64_TPREL64] = { "R_PPC64_TPREL64", both }, + [R_PPC64_DTPREL16] = { "R_PPC64_DTPREL16", both }, + [R_PPC64_DTPREL16_LO] = { "R_PPC64_DTPREL16_LO", both }, + [R_PPC64_DTPREL16_HI] = { "R_PPC64_DTPREL16_HI", both }, + [R_PPC64_DTPREL16_HA] = { "R_PPC64_DTPREL16_HA", both }, + [R_PPC64_DTPREL64] = { "R_PPC64_DTPREL64", both }, + [R_PPC64_GOT_TLSGD16] = { "R_PPC64_GOT_TLSGD16", both }, + [R_PPC64_GOT_TLSGD16_LO] = { "R_PPC64_GOT_TLSGD16_LO", both }, + [R_PPC64_GOT_TLSGD16_HI] = { "R_PPC64_GOT_TLSGD16_HI", both }, + [R_PPC64_GOT_TLSGD16_HA] = { "R_PPC64_GOT_TLSGD16_HA", both }, + [R_PPC64_GOT_TLSLD16] = { "R_PPC64_GOT_TLSLD16", both }, + [R_PPC64_GOT_TLSLD16_LO] = { "R_PPC64_GOT_TLSLD16_LO", both }, + [R_PPC64_GOT_TLSLD16_HI] = { "R_PPC64_GOT_TLSLD16_HI", both }, + [R_PPC64_GOT_TLSLD16_HA] = { "R_PPC64_GOT_TLSLD16_HA", both }, + [R_PPC64_GOT_TPREL16_DS] = { "R_PPC64_GOT_TPREL16_DS", both }, + [R_PPC64_GOT_TPREL16_LO_DS] = { "R_PPC64_GOT_TPREL16_LO_DS", both }, + [R_PPC64_GOT_TPREL16_HI] = { "R_PPC64_GOT_TPREL16_HI", both }, + [R_PPC64_GOT_TPREL16_HA] = { "R_PPC64_GOT_TPREL16_HA", both }, + [R_PPC64_GOT_DTPREL16_DS] = { "R_PPC64_GOT_DTPREL16_DS", both }, + [R_PPC64_GOT_DTPREL16_LO_DS] = { "R_PPC64_GOT_DTPREL16_LO_DS", both }, + [R_PPC64_GOT_DTPREL16_HI] = { "R_PPC64_GOT_DTPREL16_HI", both }, + [R_PPC64_GOT_DTPREL16_HA] = { "R_PPC64_GOT_DTPREL16_HA", both }, + [R_PPC64_TPREL16_DS] = { "R_PPC64_TPREL16_DS", both }, + [R_PPC64_TPREL16_LO_DS] = { "R_PPC64_TPREL16_LO_DS", both }, + [R_PPC64_TPREL16_HIGHER] = { "R_PPC64_TPREL16_HIGHER", both }, + [R_PPC64_TPREL16_HIGHERA] = { "R_PPC64_TPREL16_HIGHERA", both }, + [R_PPC64_TPREL16_HIGHEST] = { "R_PPC64_TPREL16_HIGHEST", both }, + [R_PPC64_TPREL16_HIGHESTA] = { "R_PPC64_TPREL16_HIGHESTA", both }, + [R_PPC64_DTPREL16_DS] = { "R_PPC64_DTPREL16_DS", both }, + [R_PPC64_DTPREL16_LO_DS] = { "R_PPC64_DTPREL16_LO_DS", both }, + [R_PPC64_DTPREL16_HIGHER] = { "R_PPC64_DTPREL16_HIGHER", both }, + [R_PPC64_DTPREL16_HIGHERA] = { "R_PPC64_DTPREL16_HIGHERA", both }, + [R_PPC64_DTPREL16_HIGHEST] = { "R_PPC64_DTPREL16_HIGHEST", both }, + [R_PPC64_DTPREL16_HIGHESTA] = { "R_PPC64_DTPREL16_HIGHESTA", both } + }; + + +/* Determine relocation type string for PPC. */ +const char * +ppc64_reloc_type_name (int type, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + if (type < R_PPC64_NONE || type >= R_PPC64_NUM) + return NULL; + + return reloc_map_table[type].name; +} + + +/* Check for correct relocation type. */ +bool +ppc64_reloc_type_check (int type) +{ + return (type >= R_PPC64_NONE && type < R_PPC64_NUM + && reloc_map_table[type].name != NULL) ? true : false; +} + + +/* Check for correct relocation type use. */ +bool +ppc64_reloc_valid_use (Elf *elf, int type) +{ + if (type < R_PPC64_NONE || type >= R_PPC64_NUM + || reloc_map_table[type].name == NULL) + return false; + + Elf64_Ehdr *ehdr = elf64_getehdr (elf); + assert (ehdr != NULL); + + if (reloc_map_table[type].appear == rel) + return ehdr->e_type == ET_REL; + + if (reloc_map_table[type].appear == exec) + return ehdr->e_type != ET_REL; + + assert (reloc_map_table[type].appear == both); + return true; +} + + +/* Check for the simple reloc types. */ +Elf_Type +ppc64_reloc_simple_type (Elf *elf __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_PPC64_ADDR64: + case R_PPC64_UADDR64: + return ELF_T_XWORD; + case R_PPC64_ADDR32: + case R_PPC64_UADDR32: + return ELF_T_WORD; + case R_PPC64_UADDR16: + return ELF_T_HALF; + default: + return ELF_T_NUM; + } +} + + +const char * +ppc64_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_PPC64_GLINK: + return "PPC64_GLINK"; + case DT_PPC64_OPD: + return "PPC64_OPD"; + case DT_PPC64_OPDSZ: + return "PPC64_OPDSZ"; + default: + break; + } + return NULL; +} + +/* Check whether given relocation is a copy relocation. */ +bool +ppc64_copy_reloc_p (int reloc) +{ + return reloc == R_PPC64_COPY; +} diff --git a/libebl/ppc_destr.c b/libebl/ppc_destr.c new file mode 100644 index 00000000..65bb81cc --- /dev/null +++ b/libebl/ppc_destr.c @@ -0,0 +1,27 @@ +/* Destructor for PPC specific backend library. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +void +ppc_destr (bh) + Ebl *bh __attribute__ ((unused)); +{ + /* Nothing to do so far. */ +} diff --git a/libebl/ppc_init.c b/libebl/ppc_init.c new file mode 100644 index 00000000..4d72c46d --- /dev/null +++ b/libebl/ppc_init.c @@ -0,0 +1,43 @@ +/* Initialization of PPC specific backend library. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +const char * +ppc_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "PowerPC"; + eh->reloc_type_name = ppc_reloc_type_name; + eh->reloc_type_check = ppc_reloc_type_check; + eh->reloc_valid_use = ppc_reloc_valid_use; + eh->reloc_simple_type = ppc_reloc_simple_type; + eh->copy_reloc_p = ppc_copy_reloc_p; + eh->destr = ppc_destr; + + return MODVERSION; +} diff --git a/libebl/ppc_symbol.c b/libebl/ppc_symbol.c new file mode 100644 index 00000000..20beae31 --- /dev/null +++ b/libebl/ppc_symbol.c @@ -0,0 +1,174 @@ +/* PPC specific symbolic name handling. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include + + +/* Return of the backend. */ +const char * +ppc_backend_name (void) +{ + return "ppc"; +} + + +/* Relocation mapping table. */ +static struct +{ + const char *name; + enum { both = 0, rel = 1, exec = 2 } appear; +} reloc_map_table[] = + { + // XXX Check all the appear values. + [R_PPC_NONE] = { "R_PPC_NONE", both }, + [R_PPC_ADDR32] = { "R_PPC_ADDR32", both }, + [R_PPC_ADDR24] = { "R_PPC_ADDR24", both }, + [R_PPC_ADDR16] = { "R_PPC_ADDR16", both }, + [R_PPC_ADDR16_LO] = { "R_PPC_ADDR16_LO", both }, + [R_PPC_ADDR16_HI] = { "R_PPC_ADDR16_HI", both }, + [R_PPC_ADDR16_HA] = { "R_PPC_ADDR16_HA", both }, + [R_PPC_ADDR14] = { "R_PPC_ADDR14", exec }, + [R_PPC_ADDR14_BRTAKEN] = { "R_PPC_ADDR14_BRTAKEN", exec }, + [R_PPC_ADDR14_BRNTAKEN] = { "R_PPC_ADDR14_BRNTAKEN", exec }, + [R_PPC_REL24] = { "R_PPC_REL24", both }, + [R_PPC_REL14] = { "R_PPC_REL14", both }, + [R_PPC_REL14_BRTAKEN] = { "R_PPC_REL14_BRTAKEN", exec }, + [R_PPC_REL14_BRNTAKEN] = { "R_PPC_REL14_BRNTAKEN", exec }, + [R_PPC_GOT16] = { "R_PPC_GOT16", rel }, + [R_PPC_GOT16_LO] = { "R_PPC_GOT16_LO", rel }, + [R_PPC_GOT16_HI] = { "R_PPC_GOT16_HI", rel }, + [R_PPC_GOT16_HA] = { "R_PPC_GOT16_HA", rel }, + [R_PPC_PLTREL24] = { "R_PPC_PLTREL24", rel }, + [R_PPC_COPY] = { "R_PPC_COPY", exec }, + [R_PPC_GLOB_DAT] = { "R_PPC_GLOB_DAT", exec }, + [R_PPC_JMP_SLOT] = { "R_PPC_JMP_SLOT", exec }, + [R_PPC_RELATIVE] = { "R_PPC_RELATIVE", exec }, + [R_PPC_LOCAL24PC] = { "R_PPC_LOCAL24PC", rel }, + [R_PPC_UADDR32] = { "R_PPC_UADDR32", exec }, + [R_PPC_UADDR16] = { "R_PPC_UADDR16", exec }, + [R_PPC_REL32] = { "R_PPC_REL32", exec }, + [R_PPC_PLT32] = { "R_PPC_PLT32", exec }, + [R_PPC_PLTREL32] = { "R_PPC_PLTREL32", both }, + [R_PPC_PLT16_LO] = { "R_PPC_PLT16_LO", both }, + [R_PPC_PLT16_HI] = { "R_PPC_PLT16_HI", both }, + [R_PPC_PLT16_HA] = { "R_PPC_PLT16_HA", both }, + [R_PPC_SDAREL16] = { "R_PPC_SDAREL16", both }, + [R_PPC_SECTOFF] = { "R_PPC_SECTOFF", both }, + [R_PPC_SECTOFF_LO] = { "R_PPC_SECTOFF_LO", both }, + [R_PPC_SECTOFF_HI] = { "R_PPC_SECTOFF_HI", both }, + [R_PPC_SECTOFF_HA] = { "R_PPC_SECTOFF_HA", both }, + [R_PPC_TLS] = { "R_PPC_TLS", both }, + [R_PPC_DTPMOD32] = { "R_PPC_DTPMOD32", exec }, + [R_PPC_TPREL16] = { "R_PPC_TPREL16", rel }, + [R_PPC_TPREL16_LO] = { "R_PPC_TPREL16_LO", rel }, + [R_PPC_TPREL16_HI] = { "R_PPC_TPREL16_HI", rel }, + [R_PPC_TPREL16_HA] = { "R_PPC_TPREL16_HA", rel }, + [R_PPC_TPREL32] = { "R_PPC_TPREL32", exec }, + [R_PPC_DTPREL16] = { "R_PPC_DTPREL16", rel }, + [R_PPC_DTPREL16_LO] = { "R_PPC_DTPREL16_LO", rel }, + [R_PPC_DTPREL16_HI] = { "R_PPC_DTPREL16_HI", rel }, + [R_PPC_DTPREL16_HA] = { "R_PPC_DTPREL16_HA", rel }, + [R_PPC_DTPREL32] = { "R_PPC_DTPREL32", exec }, + [R_PPC_GOT_TLSGD16] = { "R_PPC_GOT_TLSGD16", exec }, + [R_PPC_GOT_TLSGD16_LO] = { "R_PPC_GOT_TLSGD16_LO", exec }, + [R_PPC_GOT_TLSGD16_HI] = { "R_PPC_GOT_TLSGD16_HI", exec }, + [R_PPC_GOT_TLSGD16_HA] = { "R_PPC_GOT_TLSGD16_HA", exec }, + [R_PPC_GOT_TLSLD16] = { "R_PPC_GOT_TLSLD16", exec }, + [R_PPC_GOT_TLSLD16_LO] = { "R_PPC_GOT_TLSLD16_LO", exec }, + [R_PPC_GOT_TLSLD16_HI] = { "R_PPC_GOT_TLSLD16_HI", exec }, + [R_PPC_GOT_TLSLD16_HA] = { "R_PPC_GOT_TLSLD16_HA", exec }, + [R_PPC_GOT_TPREL16] = { "R_PPC_GOT_TPREL16", exec }, + [R_PPC_GOT_TPREL16_LO] = { "R_PPC_GOT_TPREL16_LO", exec }, + [R_PPC_GOT_TPREL16_HI] = { "R_PPC_GOT_TPREL16_HI", exec }, + [R_PPC_GOT_TPREL16_HA] = { "R_PPC_GOT_TPREL16_HA", exec }, + [R_PPC_GOT_DTPREL16] = { "R_PPC_GOT_DTPREL16", exec }, + [R_PPC_GOT_DTPREL16_LO] = { "R_PPC_GOT_DTPREL16_LO", exec }, + [R_PPC_GOT_DTPREL16_HI] = { "R_PPC_GOT_DTPREL16_HI", exec }, + [R_PPC_GOT_DTPREL16_HA] = { "R_PPC_GOT_DTPREL16_HA", exec } + }; + + +/* Determine relocation type string for PPC. */ +const char * +ppc_reloc_type_name (int type, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + if (type < 0 || type >= R_PPC_NUM) + return NULL; + + return reloc_map_table[type].name; +} + + +/* Check for correct relocation type. */ +bool +ppc_reloc_type_check (int type) +{ + return (type >= R_PPC_NONE && type < R_PPC_NUM + && reloc_map_table[type].name != NULL) ? true : false; +} + + +/* Check for correct relocation type use. */ +bool +ppc_reloc_valid_use (Elf *elf, int type) +{ + if (type < R_PPC_NONE || type >= R_PPC_NUM + || reloc_map_table[type].name == NULL) + return false; + + Elf32_Ehdr *ehdr = elf32_getehdr (elf); + assert (ehdr != NULL); + + if (reloc_map_table[type].appear == rel) + return ehdr->e_type == ET_REL; + + if (reloc_map_table[type].appear == exec) + return ehdr->e_type != ET_REL; + + assert (reloc_map_table[type].appear == both); + return true; +} + + +/* Check for the simple reloc types. */ +Elf_Type +ppc_reloc_simple_type (Elf *elf __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_PPC_ADDR32: + case R_PPC_UADDR32: + return ELF_T_WORD; + case R_PPC_UADDR16: + return ELF_T_HALF; + default: + return ELF_T_NUM; + } +} + +/* Check whether given relocation is a copy relocation. */ +bool +ppc_copy_reloc_p (int reloc) +{ + return reloc == R_PPC_COPY; +} diff --git a/libebl/sh_destr.c b/libebl/sh_destr.c new file mode 100644 index 00000000..4f065343 --- /dev/null +++ b/libebl/sh_destr.c @@ -0,0 +1,27 @@ +/* Destructor for SH specific backend library. + Copyright (C) 2000. 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +void +sh_destr (bh) + Ebl *bh __attribute__ ((unused)); +{ + /* Nothing to do so far. */ +} diff --git a/libebl/sh_init.c b/libebl/sh_init.c new file mode 100644 index 00000000..bb6c9040 --- /dev/null +++ b/libebl/sh_init.c @@ -0,0 +1,40 @@ +/* Initialization of SH specific backend library. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +const char * +sh_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Hitachi SH"; + eh->reloc_type_name = sh_reloc_type_name; + eh->copy_reloc_p = sh_copy_reloc_p; + eh->destr = sh_destr; + + return MODVERSION; +} diff --git a/libebl/sh_symbol.c b/libebl/sh_symbol.c new file mode 100644 index 00000000..e24fff15 --- /dev/null +++ b/libebl/sh_symbol.c @@ -0,0 +1,99 @@ +/* SH specific relocation handling. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +/* Return of the backend. */ +const char * +sh_backend_name (void) +{ + return "sh"; +} + + +/* Determine relocation type string for SH. */ +const char * +sh_reloc_type_name (int type, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + static const char *map_table1[] = + { + [R_SH_NONE] = "R_SH_NONE", + [R_SH_DIR32] = "R_SH_DIR32", + [R_SH_REL32] = "R_SH_REL32", + [R_SH_DIR8WPN] = "R_SH_DIR8WPN", + [R_SH_IND12W] = "R_SH_IND12W", + [R_SH_DIR8WPL] = "R_SH_DIR8WPL", + [R_SH_DIR8WPZ] = "R_SH_DIR8WPZ", + [R_SH_DIR8BP] = "R_SH_DIR8BP", + [R_SH_DIR8W] = "R_SH_DIR8W", + [R_SH_DIR8L] = "R_SH_DIR8L", + [R_SH_SWITCH16] = "R_SH_SWITCH16", + [R_SH_SWITCH32] = "R_SH_SWITCH32", + [R_SH_USES] = "R_SH_USES", + [R_SH_COUNT] = "R_SH_COUNT", + [R_SH_ALIGN] = "R_SH_ALIGN", + [R_SH_CODE] = "R_SH_CODE", + [R_SH_DATA] = "R_SH_DATA", + [R_SH_LABEL] = "R_SH_LABEL", + [R_SH_SWITCH8] = "R_SH_SWITCH8", + [R_SH_GNU_VTINHERIT] ="R_SH_GNU_VTINHERIT", + [R_SH_GNU_VTENTRY] = "R_SH_GNU_VTENTRY" + }; + static const char *map_table2[] = + { + [R_SH_TLS_GD_32] = "R_SH_TLS_GD_32", + [R_SH_TLS_LD_32] = "R_SH_TLS_LD_32", + [R_SH_TLS_LDO_32] = "R_SH_TLS_LDO_32", + [R_SH_TLS_IE_32] = "R_SH_TLS_IE_32", + [R_SH_TLS_LE_32] = "R_SH_TLS_LE_32", + [R_SH_TLS_DTPMOD32] = "R_SH_TLS_DTPMOD32", + [R_SH_TLS_DTPOFF32] = "R_SH_TLS_DTPOFF32", + [R_SH_TLS_TPOFF32] = "R_SH_TLS_TPOFF32", + [R_SH_GOT32 - R_SH_GOT32] = "R_SH_GOT32", + [R_SH_PLT32 - R_SH_GOT32] = "R_SH_PLT32", + [R_SH_COPY - R_SH_GOT32] = "R_SH_COPY", + [R_SH_GLOB_DAT - R_SH_GOT32] = "R_SH_GLOB_DAT", + [R_SH_JMP_SLOT - R_SH_GOT32] = "R_SH_JMP_SLOT", + [R_SH_RELATIVE - R_SH_GOT32] = "R_SH_RELATIVE", + [R_SH_GOTOFF - R_SH_GOT32] = "R_SH_GOTOFF", + [R_SH_GOTPC - R_SH_GOT32] = "R_SH_GOTPC" + }; + + if (type >= 0 + && (size_t) type < sizeof (map_table1) / sizeof (map_table1[0])) + return map_table1[type]; + + if ((type - R_SH_TLS_GD_32) >= 0 + && ((size_t) (type - R_SH_TLS_GD_32) + < sizeof (map_table2) / sizeof (map_table2[0]))) + return map_table2[type - R_SH_TLS_GD_32]; + + return NULL; +} + +/* Check whether given relocation is a copy relocation. */ +bool +sh_copy_reloc_p (int reloc) +{ + return reloc == R_SH_COPY; +} diff --git a/libebl/sparc_destr.c b/libebl/sparc_destr.c new file mode 100644 index 00000000..819f3616 --- /dev/null +++ b/libebl/sparc_destr.c @@ -0,0 +1,26 @@ +/* Destructor for SPARC specific backend library. + Copyright (C) 2002, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +void +sparc_destr (bh) + Ebl *bh __attribute__ ((unused)); +{ + /* Nothing to do so far. */ +} diff --git a/libebl/sparc_init.c b/libebl/sparc_init.c new file mode 100644 index 00000000..ac461a10 --- /dev/null +++ b/libebl/sparc_init.c @@ -0,0 +1,46 @@ +/* Initialization of SPARC specific backend library. + Copyright (C) 2002, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +const char * +sparc_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + if (machine == EM_SPARCV9) + eh->name = "SPARC v9"; + else if (machine == EM_SPARC32PLUS) + eh->name = "SPARC v8+"; + else + eh->name = "SPARC"; + eh->reloc_type_name = sparc_reloc_type_name; + eh->reloc_type_check = sparc_reloc_type_check; + //eh->core_note = sparc_core_note; + eh->copy_reloc_p = sparc_copy_reloc_p; + eh->destr = sparc_destr; + + return MODVERSION; +} diff --git a/libebl/sparc_symbol.c b/libebl/sparc_symbol.c new file mode 100644 index 00000000..f33ed537 --- /dev/null +++ b/libebl/sparc_symbol.c @@ -0,0 +1,149 @@ +/* SPARC specific symbolic name handling. + Copyright (C) 2002, 2003, 2005 Red Hat, Inc. + Written by Jakub Jelinek , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + + +/* Return of the backend. */ +const char * +sparc_backend_name (void) +{ + return "sparc"; +} + + +/* Relocation mapping table. */ +static const char *reloc_map_table[] = + { + [R_SPARC_NONE] = "R_SPARC_NONE", + [R_SPARC_8] = "R_SPARC_8", + [R_SPARC_16] = "R_SPARC_16", + [R_SPARC_32] = "R_SPARC_32", + [R_SPARC_DISP8] = "R_SPARC_DISP8", + [R_SPARC_DISP16] = "R_SPARC_DISP16", + [R_SPARC_DISP32] = "R_SPARC_DISP32", + [R_SPARC_WDISP30] = "R_SPARC_WDISP30", + [R_SPARC_WDISP22] = "R_SPARC_WDISP22", + [R_SPARC_HI22] = "R_SPARC_HI22", + [R_SPARC_22] = "R_SPARC_22", + [R_SPARC_13] = "R_SPARC_13", + [R_SPARC_LO10] = "R_SPARC_LO10", + [R_SPARC_GOT10] = "R_SPARC_GOT10", + [R_SPARC_GOT13] = "R_SPARC_GOT13", + [R_SPARC_GOT22] = "R_SPARC_GOT22", + [R_SPARC_PC10] = "R_SPARC_PC10", + [R_SPARC_PC22] = "R_SPARC_PC22", + [R_SPARC_WPLT30] = "R_SPARC_WPLT30", + [R_SPARC_COPY] = "R_SPARC_COPY", + [R_SPARC_GLOB_DAT] = "R_SPARC_GLOB_DAT", + [R_SPARC_JMP_SLOT] = "R_SPARC_JMP_SLOT", + [R_SPARC_RELATIVE] = "R_SPARC_RELATIVE", + [R_SPARC_UA32] = "R_SPARC_UA32", + [R_SPARC_PLT32] = "R_SPARC_PLT32", + [R_SPARC_HIPLT22] = "R_SPARC_HIPLT22", + [R_SPARC_LOPLT10] = "R_SPARC_LOPLT10", + [R_SPARC_PCPLT32] = "R_SPARC_PCPLT32", + [R_SPARC_PCPLT22] = "R_SPARC_PCPLT22", + [R_SPARC_PCPLT10] = "R_SPARC_PCPLT10", + [R_SPARC_10] = "R_SPARC_10", + [R_SPARC_11] = "R_SPARC_11", + [R_SPARC_64] = "R_SPARC_64", + [R_SPARC_OLO10] = "R_SPARC_OLO10", + [R_SPARC_HH22] = "R_SPARC_HH22", + [R_SPARC_HM10] = "R_SPARC_HM10", + [R_SPARC_LM22] = "R_SPARC_LM22", + [R_SPARC_PC_HH22] = "R_SPARC_PC_HH22", + [R_SPARC_PC_HM10] = "R_SPARC_PC_HM10", + [R_SPARC_PC_LM22] = "R_SPARC_PC_LM22", + [R_SPARC_WDISP16] = "R_SPARC_WDISP16", + [R_SPARC_WDISP19] = "R_SPARC_WDISP19", + [R_SPARC_7] = "R_SPARC_7", + [R_SPARC_5] = "R_SPARC_5", + [R_SPARC_6] = "R_SPARC_6", + [R_SPARC_DISP64] = "R_SPARC_DISP64", + [R_SPARC_PLT64] = "R_SPARC_PLT64", + [R_SPARC_HIX22] = "R_SPARC_HIX22", + [R_SPARC_LOX10] = "R_SPARC_LOX10", + [R_SPARC_H44] = "R_SPARC_H44", + [R_SPARC_M44] = "R_SPARC_M44", + [R_SPARC_L44] = "R_SPARC_L44", + [R_SPARC_REGISTER] = "R_SPARC_REGISTER", + [R_SPARC_UA64] = "R_SPARC_UA64", + [R_SPARC_UA16] = "R_SPARC_UA16", + [R_SPARC_TLS_GD_HI22] = "R_SPARC_TLS_GD_HI22", + [R_SPARC_TLS_GD_LO10] = "R_SPARC_TLS_GD_LO10", + [R_SPARC_TLS_GD_ADD] = "R_SPARC_TLS_GD_ADD", + [R_SPARC_TLS_GD_CALL] = "R_SPARC_TLS_GD_CALL", + [R_SPARC_TLS_LDM_HI22] = "R_SPARC_TLS_LDM_HI22", + [R_SPARC_TLS_LDM_LO10] = "R_SPARC_TLS_LDM_LO10", + [R_SPARC_TLS_LDM_ADD] = "R_SPARC_TLS_LDM_ADD", + [R_SPARC_TLS_LDM_CALL] = "R_SPARC_TLS_LDM_CALL", + [R_SPARC_TLS_LDO_HIX22] = "R_SPARC_TLS_LDO_HIX22", + [R_SPARC_TLS_LDO_LOX10] = "R_SPARC_TLS_LDO_LOX10", + [R_SPARC_TLS_LDO_ADD] = "R_SPARC_TLS_LDO_ADD", + [R_SPARC_TLS_IE_HI22] = "R_SPARC_TLS_IE_HI22", + [R_SPARC_TLS_IE_LO10] = "R_SPARC_TLS_IE_LO10", + [R_SPARC_TLS_IE_LD] = "R_SPARC_TLS_IE_LD", + [R_SPARC_TLS_IE_LDX] = "R_SPARC_TLS_IE_LDX", + [R_SPARC_TLS_IE_ADD] = "R_SPARC_TLS_IE_ADD", + [R_SPARC_TLS_LE_HIX22] = "R_SPARC_TLS_LE_HIX22", + [R_SPARC_TLS_LE_LOX10] = "R_SPARC_TLS_LE_LOX10", + [R_SPARC_TLS_DTPMOD32] = "R_SPARC_TLS_DTPMOD32", + [R_SPARC_TLS_DTPMOD64] = "R_SPARC_TLS_DTPMOD64", + [R_SPARC_TLS_DTPOFF32] = "R_SPARC_TLS_DTPOFF32", + [R_SPARC_TLS_DTPOFF64] = "R_SPARC_TLS_DTPOFF64", + [R_SPARC_TLS_TPOFF32] = "R_SPARC_TLS_TPOFF32", + [R_SPARC_TLS_TPOFF64] = "R_SPARC_TLS_TPOFF64" + }; + + +/* Determine relocation type string for sparc. */ +const char * +sparc_reloc_type_name (int type, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + /* High 24 bits of r_type are used for second addend in R_SPARC_OLO10. */ + if ((type & 0xff) == R_SPARC_OLO10) + return reloc_map_table[type & 0xff]; + + if (type < 0 || type >= R_SPARC_NUM) + return NULL; + + return reloc_map_table[type]; +} + + +/* Check for correct relocation type. */ +bool +sparc_reloc_type_check (int type) +{ + if ((type & 0xff) == R_SPARC_OLO10) + return true; + return (type >= R_SPARC_NONE && type < R_SPARC_NUM + && reloc_map_table[type] != NULL) ? true : false; +} + +/* Check whether given relocation is a copy relocation. */ +bool +sparc_copy_reloc_p (int reloc) +{ + return reloc == R_SPARC_COPY; +} diff --git a/libebl/x86_64_corenote.c b/libebl/x86_64_corenote.c new file mode 100644 index 00000000..0ee7ceae --- /dev/null +++ b/libebl/x86_64_corenote.c @@ -0,0 +1,171 @@ +/* x86-64 specific core note handling. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + + +/* We cannot include since the definition would be for + the host platform and not always x86-64 as required here. */ +struct elf_prstatus + { + struct + { + int32_t si_signo; /* Signal number. */ + int32_t si_code; /* Extra code. */ + int32_t si_errno; /* Errno. */ + } pr_info; /* Info associated with signal. */ + int16_t pr_cursig; /* Current signal. */ + uint64_t pr_sigpend; /* Set of pending signals. */ + uint64_t pr_sighold; /* Set of held signals. */ + int32_t pr_pid; + int32_t pr_ppid; + int32_t pr_pgrp; + int32_t pr_sid; + struct x86_64_timeval + { + int64_t tv_sec; + int32_t tv_usec; + } pr_utime; /* User time. */ + struct x86_64_timeval pr_stime; /* System time. */ + struct x86_64_timeval pr_cutime; /* Cumulative user time. */ + struct x86_64_timeval pr_cstime; /* Cumulative system time. */ + uint64_t pr_reg[27]; /* GP registers. */ + int32_t pr_fpvalid; /* True if math copro being used. */ + }; + + +struct elf_prpsinfo + { + char pr_state; /* Numeric process state. */ + char pr_sname; /* Char for pr_state. */ + char pr_zomb; /* Zombie. */ + char pr_nice; /* Nice val. */ + uint64_t pr_flag; /* Flags. */ + uint32_t pr_uid; + uint32_t pr_gid; + int32_t pr_pid; + int32_t pr_ppid; + int32_t pr_pgrp; + int32_t pr_sid; + /* Lots missing */ + char pr_fname[16]; /* Filename of executable. */ + char pr_psargs[80]; /* Initial part of arg list. */ + }; + + +bool +x86_64_core_note (name, type, descsz, desc) + const char *name __attribute__ ((unused)); + uint32_t type; + uint32_t descsz; + const char *desc; +{ + bool result = false; + + switch (type) + { + case NT_PRSTATUS: + if (descsz < sizeof (struct elf_prstatus)) + /* Not enough data. */ + break; + + struct elf_prstatus *stat = (struct elf_prstatus *) desc; + + printf (" SIGINFO: signo: %" PRId32 ", code = %" PRId32 + ", errno = %" PRId32 "\n" + " signal: %" PRId16 ", pending: %#08" PRIx64 ", holding: %#08" + PRIx64 "\n" + " pid: %" PRId32 ", ppid = %" PRId32 ", pgrp = %" PRId32 + ", sid = %" PRId32 "\n" + " utime: %6" PRId64 ".%06" PRId32 + "s, stime: %6" PRId64 ".%06" PRId32 "s\n" + " cutime: %6" PRId64 ".%06" PRId32 + "s, cstime: %6" PRId64 ".%06" PRId32 "s\n" + " rax: %016" PRIx64 " rbx: %016" PRIx64 "\n" + " rcx: %016" PRIx64 " rdx: %016" PRIx64 "\n" + " rsi: %016" PRIx64 " rdi: %016" PRIx64 "\n" + " rbp: %016" PRIx64 " rsp: %016" PRIx64 "\n" + " r8: %016" PRIx64 " r9: %016" PRIx64 "\n" + " r10: %016" PRIx64 " r11: %016" PRIx64 "\n" + " r12: %016" PRIx64 " r13: %016" PRIx64 "\n" + " r14: %016" PRIx64 " r15: %016" PRIx64 "\n" + " rip: %016" PRIx64 " eflags: %08" PRIx64 "\n" + " original rax: %016" PRIx64 "\n" + " cs: %04" PRIx64 " ds: %04" PRIx64 " es: %04" PRIx64 + " ss: %04" PRIx64 "\n" + " fs: %04" PRIx64 " fs_base: %016" PRIx64 + " gs: %04" PRIx64 " gs_base: %016" PRIx64 "\n\n", + stat->pr_info. si_signo, + stat->pr_info. si_code, + stat->pr_info. si_errno, + stat->pr_cursig, + stat->pr_sigpend, stat->pr_sighold, + stat->pr_pid, stat->pr_ppid, stat->pr_pgrp, stat->pr_sid, + stat->pr_utime.tv_sec, stat->pr_utime.tv_usec, + stat->pr_stime.tv_sec, stat->pr_stime.tv_usec, + stat->pr_cutime.tv_sec, stat->pr_cutime.tv_usec, + stat->pr_cstime.tv_sec, stat->pr_cstime.tv_usec, + stat->pr_reg[10], stat->pr_reg[5], stat->pr_reg[11], + stat->pr_reg[12], stat->pr_reg[13], stat->pr_reg[14], + stat->pr_reg[4], stat->pr_reg[10], stat->pr_reg[9], + stat->pr_reg[7], stat->pr_reg[6], stat->pr_reg[5], + stat->pr_reg[3], stat->pr_reg[2], stat->pr_reg[1], + stat->pr_reg[0], stat->pr_reg[16], stat->pr_reg[18], + stat->pr_reg[15], stat->pr_reg[17], stat->pr_reg[23], + stat->pr_reg[24], stat->pr_reg[20], + stat->pr_reg[25], stat->pr_reg[21], + stat->pr_reg[26], stat->pr_reg[22]); + + /* We handled this entry. */ + result = true; + break; + + case NT_PRPSINFO: + if (descsz < sizeof (struct elf_prpsinfo)) + /* Not enough data. */ + break; + + struct elf_prpsinfo *info = (struct elf_prpsinfo *) desc; + + printf (" state: %c (%hhd), zombie: %hhd, nice: %hhd\n" + " flags: %08" PRIx64 " uid: %" PRIu32 " gid: %" PRIu32 "\n" + " pid: %" PRId32 " ppid: %" PRId32 " pgrp: %" PRId32 + " sid: %" PRId32 "\n" + " fname: %.16s\n" + " args: %.80s\n\n", + info->pr_sname, info->pr_state, info->pr_zomb, info->pr_nice, + info->pr_flag, info->pr_uid, info->pr_gid, + info->pr_pid, info->pr_ppid, info->pr_pgrp, info->pr_sid, + info->pr_fname, info->pr_psargs); + + /* We handled this entry. */ + result = true; + break; + + default: + break; + } + + return result; +} diff --git a/libebl/x86_64_destr.c b/libebl/x86_64_destr.c new file mode 100644 index 00000000..38058299 --- /dev/null +++ b/libebl/x86_64_destr.c @@ -0,0 +1,27 @@ +/* Destructor for x86_64 specific backend library. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +void +x86_64_destr (bh) + Ebl *bh __attribute__ ((unused)); +{ + /* Nothing to do so far. */ +} diff --git a/libebl/x86_64_init.c b/libebl/x86_64_init.c new file mode 100644 index 00000000..655a67fb --- /dev/null +++ b/libebl/x86_64_init.c @@ -0,0 +1,44 @@ +/* Initialization of x86-64 specific backend library. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +const char * +x86_64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "AMD x86-64"; + eh->reloc_type_name = x86_64_reloc_type_name; + eh->reloc_type_check = x86_64_reloc_type_check; + eh->reloc_valid_use = x86_64_reloc_valid_use; + eh->reloc_simple_type = x86_64_reloc_simple_type; + eh->core_note = x86_64_core_note; + eh->copy_reloc_p = x86_64_copy_reloc_p; + eh->destr = x86_64_destr; + + return MODVERSION; +} diff --git a/libebl/x86_64_symbol.c b/libebl/x86_64_symbol.c new file mode 100644 index 00000000..38d357cb --- /dev/null +++ b/libebl/x86_64_symbol.c @@ -0,0 +1,136 @@ +/* x86_64 specific symbolic name handling. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include + + +/* Return of the backend. */ +const char * +x86_64_backend_name (void) +{ + return "x86-64"; +} + + +/* Relocation mapping table. */ +static struct +{ + const char *name; + enum { both = 0, rel = 1, exec = 2 } appear; +} reloc_map_table[] = + { + [R_X86_64_NONE] = { "R_X86_64_NONE", both }, + [R_X86_64_64] = { "R_X86_64_64", both }, + [R_X86_64_PC32] = { "R_X86_64_PC32", rel }, + [R_X86_64_GOT32] = { "R_X86_64_GOT32", rel }, + [R_X86_64_PLT32] = { "R_X86_64_PLT32", rel }, + [R_X86_64_COPY] = { "R_X86_64_COPY", exec }, + [R_X86_64_GLOB_DAT] = { "R_X86_64_GLOB_DAT", exec }, + [R_X86_64_JUMP_SLOT] = { "R_X86_64_JUMP_SLOT", exec }, + [R_X86_64_RELATIVE] = { "R_X86_64_RELATIVE", exec }, + [R_X86_64_GOTPCREL] = { "R_X86_64_GOTPCREL", exec }, + [R_X86_64_32] = { "R_X86_64_32", both }, + [R_X86_64_32S] = { "R_X86_64_32S", rel }, + [R_X86_64_16] = { "R_X86_64_16", rel }, + [R_X86_64_PC16] = { "R_X86_64_PC16", rel }, + [R_X86_64_8] = { "R_X86_64_8", rel }, + [R_X86_64_PC8] = { "R_X86_64_PC8", rel }, + [R_X86_64_DTPMOD64] = { "R_X86_64_DTPMOD64", rel }, + [R_X86_64_DTPOFF64] = { "R_X86_64_DTPOFF64", rel }, + [R_X86_64_TPOFF64] = { "R_X86_64_TPOFF64", rel }, + [R_X86_64_TLSGD] = { "R_X86_64_TLSGD", rel }, + [R_X86_64_TLSLD] = { "R_X86_64_TLSLD", rel }, + [R_X86_64_DTPOFF32] = { "R_X86_64_DTPOFF32", rel }, + [R_X86_64_GOTTPOFF] = { "R_X86_64_GOTTPOFF", rel }, + [R_X86_64_TPOFF32] = { "R_X86_64_TPOFF32", rel } + }; + + +/* Determine relocation type string for x86-64. */ +const char * +x86_64_reloc_type_name (int type, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + if (type < 0 || type >= R_X86_64_NUM) + return NULL; + + return reloc_map_table[type].name; +} + + +/* Check for correct relocation type. */ +bool +x86_64_reloc_type_check (int type) +{ + return (type >= R_X86_64_NONE && type < R_X86_64_NUM + && reloc_map_table[type].name != NULL) ? true : false; +} + + +/* Check for correct relocation type use. */ +bool +x86_64_reloc_valid_use (Elf *elf, int type) +{ + if (type < R_X86_64_NONE || type >= R_X86_64_NUM + || reloc_map_table[type].name == NULL) + return false; + + Elf64_Ehdr *ehdr = elf64_getehdr (elf); + assert (ehdr != NULL); + + if (reloc_map_table[type].appear == rel) + return ehdr->e_type == ET_REL; + + if (reloc_map_table[type].appear == exec) + return ehdr->e_type != ET_REL; + + assert (reloc_map_table[type].appear == both); + return true; +} + +/* Check for the simple reloc types. */ +Elf_Type +x86_64_reloc_simple_type (Elf *elf __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_X86_64_64: + return ELF_T_XWORD; + case R_X86_64_32: + return ELF_T_WORD; + case R_X86_64_32S: + return ELF_T_SWORD; + case R_X86_64_16: + return ELF_T_HALF; + case R_X86_64_8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} + +/* Check whether given relocation is a copy relocation. */ +bool +x86_64_copy_reloc_p (int reloc) +{ + return reloc == R_X86_64_COPY; +} diff --git a/libelf-po/.cvsignore b/libelf-po/.cvsignore new file mode 100644 index 00000000..cdbcb6b2 --- /dev/null +++ b/libelf-po/.cvsignore @@ -0,0 +1 @@ +libelf.pot diff --git a/libelf-po/ChangeLog b/libelf-po/ChangeLog new file mode 100644 index 00000000..42f50a13 --- /dev/null +++ b/libelf-po/ChangeLog @@ -0,0 +1,15 @@ +2005-05-07 Ulrich Drepper + + * Makefile.in.in (XGETTEXT_OPTIONS): Define. + +2004-01-18 Ulrich Drepper + + * Makefile.in.in: Set PACKAGE to libelf. + +2004-01-17 Ulrich Drepper + + * Makefile.in.in: Find mkinstalldirs script in right directory. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/libelf-po/Makefile.in.in b/libelf-po/Makefile.in.in new file mode 100644 index 00000000..aae32e79 --- /dev/null +++ b/libelf-po/Makefile.in.in @@ -0,0 +1,302 @@ +# Makefile for PO directory in any package using GNU gettext. +# Copyright (C) 1995-1997, 2000-2002 by Ulrich Drepper +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU General Public +# License but which still want to provide support for the GNU gettext +# functionality. +# Please note that the actual code of GNU gettext is covered by the GNU +# General Public License and is *not* in the public domain. + +PACKAGE = libelf +VERSION = @VERSION@ + +SHELL = /bin/sh +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datadir = @datadir@ +localedir = $(datadir)/locale +gettextsrcdir = $(datadir)/gettext/po +top_builddir = .. + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +mkinstalldirs = $(SHELL) `case "$(MKINSTALLDIRS)" in /*) echo "$(MKINSTALLDIRS)" ;; *) echo "$(top_builddir)/$(MKINSTALLDIRS)" ;; esac` + +GMSGFMT = @GMSGFMT@ +MSGFMT = @MSGFMT@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_OPTIONS = --flag=error:3:c-format +MSGMERGE = msgmerge +MSGMERGE_UPDATE = @MSGMERGE@ --update +MSGINIT = msginit +MSGCONV = msgconv +MSGFILTER = msgfilter + +POFILES = @POFILES@ +GMOFILES = @GMOFILES@ +UPDATEPOFILES = @UPDATEPOFILES@ +DUMMYPOFILES = @DUMMYPOFILES@ +DISTFILES.common = Makefile.in.in Makevars \ +$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) +DISTFILES = $(DISTFILES.common) POTFILES.in $(DOMAIN).pot \ +$(POFILES) $(GMOFILES) \ +$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) + +POTFILES = \ + +CATALOGS = @CATALOGS@ + +# Makevars gets inserted here. (Don't remove this line!) + +.SUFFIXES: +.SUFFIXES: .po .gmo .mo .nop .po-update + +.po.mo: + $(MSGFMT) -c -o $@ $< + +.po.gmo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ + cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po + + +all: all-@USE_NLS@ + +all-yes: $(CATALOGS) +all-no: + +# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', +# otherwise packages like GCC can not be built if only parts of the source +# have been downloaded. + +$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in + $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ + --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ + --files-from=$(srcdir)/POTFILES.in \ + --copyright-holder='$(COPYRIGHT_HOLDER)' \ + && test ! -f $(DOMAIN).po \ + || ( rm -f $(srcdir)/$(DOMAIN).pot \ + && mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot ) + +$(srcdir)/$(DOMAIN).pot: + $(MAKE) $(DOMAIN).pot-update + +$(POFILES): $(srcdir)/$(DOMAIN).pot + @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ + cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot + + +install: install-exec install-data +install-exec: +install-data: install-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + for file in $(DISTFILES.common); do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +install-data-no: all +install-data-yes: all + $(mkinstalldirs) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkinstalldirs) $(DESTDIR)$$dir; \ + if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ + $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ + echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ + fi; \ + done; \ + done + +install-strip: install + +installdirs: installdirs-exec installdirs-data +installdirs-exec: +installdirs-data: installdirs-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi +installdirs-data-no: +installdirs-data-yes: + $(mkinstalldirs) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkinstalldirs) $(DESTDIR)$$dir; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + fi; \ + done; \ + done + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: uninstall-exec uninstall-data +uninstall-exec: +uninstall-data: uninstall-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext"; then \ + for file in $(DISTFILES.common); do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +uninstall-data-no: +uninstall-data-yes: + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + done; \ + done + +check: all + +dvi info tags TAGS ID: + +mostlyclean: + rm -f core core.* $(DOMAIN).po *.new.po + rm -fr *.o + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES *.mo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f $(GMOFILES) + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: + $(MAKE) update-po + @$(MAKE) dist2 +# This is a separate target because 'update-po' must be executed before. +dist2: $(DISTFILES) + dists="$(DISTFILES)"; \ + if test -f $(srcdir)/ChangeLog; then dists="$$dists ChangeLog"; fi; \ + if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ + for file in $$dists; do \ + if test -f $$file; then \ + cp -p $$file $(distdir); \ + else \ + cp -p $(srcdir)/$$file $(distdir); \ + fi; \ + done + +update-po: Makefile + $(MAKE) $(DOMAIN).pot-update + $(MAKE) $(UPDATEPOFILES) + $(MAKE) update-gmo + +# General rule for updating PO files. + +.nop.po-update: + @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ + if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ + cd $(srcdir); \ + if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +$(DUMMYPOFILES): + +update-gmo: Makefile $(GMOFILES) + @: + +Makefile: Makefile.in.in $(top_builddir)/config.status POTFILES.in + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \ + $(SHELL) ./config.status + +force: + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libelf-po/Makevars b/libelf-po/Makevars new file mode 100644 index 00000000..0accb70a --- /dev/null +++ b/libelf-po/Makevars @@ -0,0 +1,25 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = Red Hat, Inc. + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = diff --git a/libelf-po/POTFILES.in b/libelf-po/POTFILES.in new file mode 100644 index 00000000..51d28150 --- /dev/null +++ b/libelf-po/POTFILES.in @@ -0,0 +1,5 @@ +# List of files which containing translatable strings. +# Copyright (C) 2000, 2005 Red Hat, Inc. + +# Library sources +libelf/elf_error.c diff --git a/libelf-po/Rules-quot b/libelf-po/Rules-quot new file mode 100644 index 00000000..5f46d237 --- /dev/null +++ b/libelf-po/Rules-quot @@ -0,0 +1,42 @@ +# Special Makefile rules for English message catalogs with quotation marks. + +DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot + +.SUFFIXES: .insert-header .po-update-en + +en@quot.po-update: en@quot.po-update-en +en@boldquot.po-update: en@boldquot.po-update-en + +.insert-header.po-update-en: + @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ + if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + ll=`echo $$lang | sed -e 's/@.*//'`; \ + LC_ALL=C; export LC_ALL; \ + cd $(srcdir); \ + if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "creation of $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +en@quot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header + +en@boldquot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header + +mostlyclean: mostlyclean-quot +mostlyclean-quot: + rm -f *.insert-header diff --git a/libelf-po/boldquot.sed b/libelf-po/boldquot.sed new file mode 100644 index 00000000..4b937aa5 --- /dev/null +++ b/libelf-po/boldquot.sed @@ -0,0 +1,10 @@ +s/"\([^"]*\)"/“\1â€/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“â€/""/g +s/“/“/g +s/â€/â€/g +s/‘/‘/g +s/’/’/g diff --git a/libelf-po/en@boldquot.header b/libelf-po/en@boldquot.header new file mode 100644 index 00000000..fedb6a06 --- /dev/null +++ b/libelf-po/en@boldquot.header @@ -0,0 +1,25 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# +# This catalog furthermore displays the text between the quotation marks in +# bold face, assuming the VT100/XTerm escape sequences. +# diff --git a/libelf-po/en@quot.header b/libelf-po/en@quot.header new file mode 100644 index 00000000..a9647fc3 --- /dev/null +++ b/libelf-po/en@quot.header @@ -0,0 +1,22 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# diff --git a/libelf-po/insert-header.sin b/libelf-po/insert-header.sin new file mode 100644 index 00000000..b26de01f --- /dev/null +++ b/libelf-po/insert-header.sin @@ -0,0 +1,23 @@ +# Sed script that inserts the file called HEADER before the header entry. +# +# At each occurrence of a line starting with "msgid ", we execute the following +# commands. At the first occurrence, insert the file. At the following +# occurrences, do nothing. The distinction between the first and the following +# occurrences is achieved by looking at the hold space. +/^msgid /{ +x +# Test if the hold space is empty. +s/m/m/ +ta +# Yes it was empty. First occurrence. Read the file. +r HEADER +# Output the file's contents by reading the next line. But don't lose the +# current line while doing this. +g +N +bb +:a +# The hold space was nonempty. Following occurrences. Do nothing. +x +:b +} diff --git a/libelf-po/quot.sed b/libelf-po/quot.sed new file mode 100644 index 00000000..0122c463 --- /dev/null +++ b/libelf-po/quot.sed @@ -0,0 +1,6 @@ +s/"\([^"]*\)"/“\1â€/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“â€/""/g diff --git a/libelf/.cvsignore b/libelf/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/libelf/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/libelf/ChangeLog b/libelf/ChangeLog new file mode 100644 index 00000000..caa2b5bc --- /dev/null +++ b/libelf/ChangeLog @@ -0,0 +1,141 @@ +2005-07-23 Ulrich Drepper + + * elf-knowledge.h (SECTION_STRIP_P): Don't handle removal of debug + sections here anymore. + * elf32_checksum.c: Adjust for change in SECTION_STRIP_P interface. + + * elf_update.c (elf_update): Get write lock, not read lock. + + * elf32_updatenull.c (updatenull): Get section headers if necessary + and possible. + +2005-07-22 Ulrich Drepper + + * elf32_updatenull.c (updatenull): If program header hasn't been loaded + yet, try to do it now. + Don't unnecessarily update overflow of section count in zeroth section + sh_size field. + If section content hasn't been read yet, do it before looking for the + block size. If no section data present, infer size of section header. + +2005-05-11 Ulrich Drepper + + * elf.h: Update again. + +2005-05-09 Ulrich Drepper + + * elf.h: Update from glibc. + +2005-05-08 Roland McGrath + + * elf_begin.c (read_file) [_MUDFLAP]: Don't use mmap for now. + * elf_update.c (write_file) [_MUDFLAP]: Likewise. + +2005-03-29 Ulrich Drepper + + * elf32_checksum.c: Use INTUSE and INTDEF to avoid PLTs. + * elf_end.c: Likewise. + * elf_getdata.c: Likewise. + * gelf_getehdr.c: Likewise. + * nlist.c: Likewise. + * libelfP.h: Add declarations of internal functions. + +2005-02-15 Ulrich Drepper + + * common.h (CONVERT): Make sure all values are unsigned. + (CONVERT_TO): Likewise. + + * Makefile.am (AM_CFLAGS): Add -Wformat=2. + Fix rule to build libelf.so. + +2005-02-06 Ulrich Drepper + + * Makefile.am: Cleanup AM_CFLAGS handling. Add -Wunused -Wextra. + Remove lint handling. + * elf32_getphdr.c: Minor cleanups. + * elf32_getshdr.c: Likewise. + * elf32_updatefile.c: Likewise. + * elf32_updatenull.c: Likewise. + * elf_begin.c: Likewise. + * elf_error.c: Likewise. + * elf_getarsym.c: Likewise. + * elf_getdata.c: Likewise. + * elf_update.c: Likewise. + * gelf_xlate.c: Likewise. + +2005-02-05 Ulrich Drepper + + * Makefile.am: Check for text relocations in constructed DSO. + + * Makefile.am [MUDFLAP] (AM_CFLAGS): Add -Werror -fpic -fmudflap. + +2005-02-04 Ulrich Drepper + + * gelf_getehdr.c (gelf_getehdr): Slight optimization. + + * elf32_checksum.c (checksum): Do not look at NOBITS sections. + + * gelf.h: Add gelf_checksum prototype. + +2004-09-25 Ulrich Drepper + + * elf32_checksum.c: Make compile with gcc 4.0. + * elf32_updatefile.c: Likewise. + * elf32_updatenull.c: Likewise. + * elf_begin.c: Likewise. + * elf_error.c: Likewise. + * elf_getdata.c: Likewise. + * elf_getident.c: Likewise. + +2004-04-01 Ulrich Drepper + + * elf.h: Update from glibc. + +2004-01-23 Ulrich Drepper + + * elf_update.c: Fix locking. + * elf_clone.c: Likewise. + + * libelf.h: Define ELF_T_LIB. + * gelf_getlib.c: New file. + * gelf_update_lib.c: New file. + * gelf.h: Declare the new functions. Define GElf_Lib. + * abstract.h: Define Lib, Lib32, Lib64. + * gelf_xlate.c (__elf_xfctstom): Add ELF_T_LIB entry. + * gelf_xlate.h: Add entry for ElfXX_Lib. + * elf_getdata.c: Recognize SHT_GNU_LIBLIST as a known section type. + * libelf.map: Add new symbols to ELFUTILS_1.1. + * Makefile.am (libelf_a_SOURCES): Add gelf_getlib.c and + gelf_update_lib.c. + +2004-01-17 Ulrich Drepper + + * Makefile.am: Support building with mudflap. + + * gelf_xlate.c (INLINE3): Avoid using cast as lvalue. + * dl-hash.h (_dl_elf_hash): Likewise. + +2004-01-05 Ulrich Drepper + + * elf-knowledge.h: New file. From libelf subdir. + * Makefile.am (euincludedir): Define. + (euinclude_HEADERS): Add elf-knowledge.h. + +2003-09-24 Ulrich Drepper + + * elf.h: Define some PT_IA_64_HP_* constants. + +2003-09-23 Jakub Jelinek + + * libelfP.h (struct Elf): Move state.elf64.sizestr_offset after + state.elf64.scnincr to match state.elf{,32}. + +2003-08-12 Ulrich Drepper + + * elf32_updatefile.c (__updatemmap): When writing back file where + some sections have not been read in, count their sizes based on + the section header. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/libelf/Makefile.am b/libelf/Makefile.am new file mode 100644 index 00000000..cf581902 --- /dev/null +++ b/libelf/Makefile.am @@ -0,0 +1,120 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 1996-2001, 2002, 2003, 2004, 2005 Red Hat, 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, version 2. +## +## 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, write to the Free Software Foundation, +## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H +if MUDFLAP +AM_CFLAGS = -fpic -fmudflap +else +AM_CFLAGS = +endif +AM_CFLAGS += -Wall -Wshadow -Werror -Wunused -Wextra -Wformat=2 -std=gnu99 \ + $($(*F)_CFLAGS) +INCLUDES = -I$(srcdir) -I$(top_srcdir)/lib -I.. +GCC_INCLUDE = -I$(shell $(CC) -print-file-name=include) +VERSION = 1 +PACKAGE_VERSION = @PACKAGE_VERSION@ + +lib_LIBRARIES = libelf.a +if !MUDFLAP +noinst_LIBRARIES = libelf_pic.a +noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so) +endif +include_HEADERS = libelf.h gelf.h nlist.h + +euincludedir = $(includedir)/elfutils +euinclude_HEADERS = elf-knowledge.h + +libelf_a_SOURCES = elf_version.c elf_hash.c elf_error.c elf_fill.c \ + elf_begin.c elf_next.c elf_rand.c elf_end.c elf_kind.c \ + gelf_getclass.c elf_getbase.c elf_getident.c \ + elf32_fsize.c elf64_fsize.c gelf_fsize.c \ + elf32_xlatetof.c elf32_xlatetom.c elf64_xlatetof.c \ + elf64_xlatetom.c gelf_xlate.c \ + elf32_getehdr.c elf64_getehdr.c gelf_getehdr.c \ + elf32_newehdr.c elf64_newehdr.c gelf_newehdr.c \ + gelf_update_ehdr.c \ + elf32_getphdr.c elf64_getphdr.c gelf_getphdr.c \ + elf32_newphdr.c elf64_newphdr.c gelf_newphdr.c \ + gelf_update_phdr.c \ + elf_getarhdr.c elf_getarsym.c \ + elf_rawfile.c elf_readall.c elf_cntl.c \ + elf_getscn.c elf_nextscn.c elf_ndxscn.c elf_newscn.c \ + elf32_getshdr.c elf64_getshdr.c gelf_getshdr.c \ + gelf_update_shdr.c \ + elf_strptr.c elf_rawdata.c elf_getdata.c elf_newdata.c \ + elf_flagelf.c elf_flagehdr.c elf_flagphdr.c elf_flagscn.c \ + elf_flagshdr.c elf_flagdata.c elf_memory.c \ + elf_update.c elf32_updatenull.c elf64_updatenull.c \ + elf32_updatefile.c elf64_updatefile.c \ + gelf_getsym.c gelf_update_sym.c \ + gelf_getversym.c gelf_getverneed.c gelf_getvernaux.c \ + gelf_getverdef.c gelf_getverdaux.c \ + gelf_getrel.c gelf_getrela.c \ + gelf_update_rel.c gelf_update_rela.c \ + gelf_getdyn.c gelf_update_dyn.c \ + gelf_getmove.c gelf_update_move.c \ + gelf_getsyminfo.c gelf_update_syminfo.c \ + gelf_xlatetof.c gelf_xlatetom.c \ + nlist.c \ + gelf_getsymshndx.c gelf_update_symshndx.c \ + gelf_update_versym.c gelf_update_verneed.c \ + gelf_update_vernaux.c gelf_update_verdef.c \ + gelf_update_verdaux.c \ + elf_getshnum.c elf_getshstrndx.c \ + gelf_checksum.c elf32_checksum.c elf64_checksum.c \ + gelf_rawchunk.c gelf_freechunk.c \ + libelf_crc32.c libelf_next_prime.c \ + elf_clone.c \ + gelf_getlib.c gelf_update_lib.c + +if !MUDFLAP +libelf_pic_a_SOURCES = +am_libelf_pic_a_OBJECTS = $(libelf_a_SOURCES:.c=.os) + +libelf_so_SOURCES = +libelf.so: libelf_pic.a libelf.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libelf.map,--no-undefined \ + -Wl,--soname,$@.$(VERSION),-z,-defs + if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi + ln -fs $@ $@.$(VERSION) + +%.os: %.c %.o + if $(COMPILE) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \ + -MF "$(DEPDIR)/$*.Tpo" `test -f '$<' || echo '$(srcdir)/'`$<; \ + then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ + rm -f "$(DEPDIR)/$*.Tpo"; \ + else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ + fi + +install: install-am libelf.so + $(mkinstalldirs) $(DESTDIR)$(libdir) + $(INSTALL_PROGRAM) libelf.so $(DESTDIR)$(libdir)/libelf-$(PACKAGE_VERSION).so + ln -fs libelf-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libelf.so.$(VERSION) + ln -fs libelf.so.$(VERSION) $(DESTDIR)$(libdir)/libelf.so + +uninstall: uninstall-am + rm -f $(DESTDIR)$(libdir)/libelf-$(PACKAGE_VERSION).so + rm -f $(DESTDIR)$(libdir)/libelf.so.$(VERSION) + rm -f $(DESTDIR)$(libdir)/libelf.so +endif + +noinst_HEADERS = elf.h abstract.h common.h exttypes.h gelf_xlate.h libelfP.h \ + version_xlate.h dl-hash.h +EXTRA_DIST = libelf.map + +CLEANFILES = $(am_libelf_pic_a_OBJECTS) diff --git a/libelf/abstract.h b/libelf/abstract.h new file mode 100644 index 00000000..d14034eb --- /dev/null +++ b/libelf/abstract.h @@ -0,0 +1,283 @@ +/* Abstract description of component ELF types. + Copyright (C) 1998, 1999, 2000, 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* ELF header. */ +#define Ehdr(Bits, Ext) \ +START (Bits, Ehdr, Ext##Ehdr) \ + TYPE_EXTRA (unsigned char e_ident[EI_NIDENT];) \ + TYPE_XLATE (memmove (tdest->e_ident, tsrc->e_ident, EI_NIDENT);) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_type) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_machine) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), e_version) \ + TYPE_NAME (ElfW2(Bits, Ext##Addr), e_entry) \ + TYPE_NAME (ElfW2(Bits, Ext##Off), e_phoff) \ + TYPE_NAME (ElfW2(Bits, Ext##Off), e_shoff) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), e_flags) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_ehsize) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_phentsize) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_phnum) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_shentsize) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_shnum) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_shstrndx) \ +END (Bits, Ext##Ehdr) + +#define Ehdr32(Ext) \ + Ehdr(32, Ext) +#define Ehdr64(Ext) \ + Ehdr(64, Ext) + + +/* Program header. */ +#define Phdr32(Ext) \ +START (32, Phdr, Ext##Phdr) \ + TYPE_NAME (ElfW2(32, Ext##Word), p_type) \ + TYPE_NAME (ElfW2(32, Ext##Off), p_offset) \ + TYPE_NAME (ElfW2(32, Ext##Addr), p_vaddr) \ + TYPE_NAME (ElfW2(32, Ext##Addr), p_paddr) \ + TYPE_NAME (ElfW2(32, Ext##Word), p_filesz) \ + TYPE_NAME (ElfW2(32, Ext##Word), p_memsz) \ + TYPE_NAME (ElfW2(32, Ext##Word), p_flags) \ + TYPE_NAME (ElfW2(32, Ext##Word), p_align) \ +END (32, Ext##Phdr) +#define Phdr64(Ext) \ +START (64, Phdr, Ext##Phdr) \ + TYPE_NAME (ElfW2(64, Ext##Word), p_type) \ + TYPE_NAME (ElfW2(64, Ext##Word), p_flags) \ + TYPE_NAME (ElfW2(64, Ext##Off), p_offset) \ + TYPE_NAME (ElfW2(64, Ext##Addr), p_vaddr) \ + TYPE_NAME (ElfW2(64, Ext##Addr), p_paddr) \ + TYPE_NAME (ElfW2(64, Ext##Xword), p_filesz) \ + TYPE_NAME (ElfW2(64, Ext##Xword), p_memsz) \ + TYPE_NAME (ElfW2(64, Ext##Xword), p_align) \ +END (64, Ext##Phdr) + + +/* Section header. */ +#define Shdr32(Ext) \ +START (32, Shdr, Ext##Shdr) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_name) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_type) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_flags) \ + TYPE_NAME (ElfW2(32, Ext##Addr), sh_addr) \ + TYPE_NAME (ElfW2(32, Ext##Off), sh_offset) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_size) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_link) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_info) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_addralign) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_entsize) \ +END (32, Ext##Shdr) +#define Shdr64(Ext) \ +START (64, Shdr, Ext##Shdr) \ + TYPE_NAME (ElfW2(64, Ext##Word), sh_name) \ + TYPE_NAME (ElfW2(64, Ext##Word), sh_type) \ + TYPE_NAME (ElfW2(64, Ext##Xword), sh_flags) \ + TYPE_NAME (ElfW2(64, Ext##Addr), sh_addr) \ + TYPE_NAME (ElfW2(64, Ext##Off), sh_offset) \ + TYPE_NAME (ElfW2(64, Ext##Xword), sh_size) \ + TYPE_NAME (ElfW2(64, Ext##Word), sh_link) \ + TYPE_NAME (ElfW2(64, Ext##Word), sh_info) \ + TYPE_NAME (ElfW2(64, Ext##Xword), sh_addralign) \ + TYPE_NAME (ElfW2(64, Ext##Xword), sh_entsize) \ +END (64, Ext##Shdr) + + +/* Symbol table. */ +#define Sym32(Ext) \ +START (32, Sym, Ext##Sym) \ + TYPE_NAME (ElfW2(32, Ext##Word), st_name) \ + TYPE_NAME (ElfW2(32, Ext##Addr), st_value) \ + TYPE_NAME (ElfW2(32, Ext##Word), st_size) \ + TYPE_EXTRA (unsigned char st_info;) \ + TYPE_XLATE (tdest->st_info = tsrc->st_info;) \ + TYPE_EXTRA (unsigned char st_other;) \ + TYPE_XLATE (tdest->st_other = tsrc->st_other;) \ + TYPE_NAME (ElfW2(32, Ext##Half), st_shndx) \ +END (32, Ext##Sym) +#define Sym64(Ext) \ +START (64, Sym, Ext##Sym) \ + TYPE_NAME (ElfW2(64, Ext##Word), st_name) \ + TYPE_EXTRA (unsigned char st_info;) \ + TYPE_XLATE (tdest->st_info = tsrc->st_info;) \ + TYPE_EXTRA (unsigned char st_other;) \ + TYPE_XLATE (tdest->st_other = tsrc->st_other;) \ + TYPE_NAME (ElfW2(64, Ext##Half), st_shndx) \ + TYPE_NAME (ElfW2(64, Ext##Addr), st_value) \ + TYPE_NAME (ElfW2(64, Ext##Xword), st_size) \ +END (64, Ext##Sym) + + +/* Relocation. */ +#define Rel32(Ext) \ +START (32, Rel, Ext##Rel) \ + TYPE_NAME (ElfW2(32, Ext##Addr), r_offset) \ + TYPE_NAME (ElfW2(32, Ext##Word), r_info) \ +END (32, Ext##Rel) +#define Rel64(Ext) \ +START (64, Rel, Ext##Rel) \ + TYPE_NAME (ElfW2(64, Ext##Addr), r_offset) \ + TYPE_NAME (ElfW2(64, Ext##Xword), r_info) \ +END (64, Ext##Rel) + +#define Rela32(Ext) \ +START (32, Rela, Ext##Rela) \ + TYPE_NAME (ElfW2(32, Ext##Addr), r_offset) \ + TYPE_NAME (ElfW2(32, Ext##Word), r_info) \ + TYPE_NAME (ElfW2(32, Ext##Sword), r_addend) \ +END (32, Ext##Rela) +#define Rela64(Ext) \ +START (64, Rela, Ext##Rela) \ + TYPE_NAME (ElfW2(64, Ext##Addr), r_offset) \ + TYPE_NAME (ElfW2(64, Ext##Xword), r_info) \ + TYPE_NAME (ElfW2(64, Ext##Sxword), r_addend) \ +END (64, Ext##Rela) + + +/* Note entry header. */ +#define Note(Bits, Ext) \ +START (Bits, Nhdr, Ext##Nhdr) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), n_namesz) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), n_descsz) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), n_type) \ +END (Bits, Ext##Nhdr) + +#define Note32(Ext) \ + Note (32, Ext) +#define Note64(Ext) \ + Note (64, Ext) + + +/* Dynamic section data. */ +#define Dyn32(Ext) \ +START (32, Dyn, Ext##Dyn) \ + TYPE_NAME (ElfW2(32, Ext##Sword), d_tag) \ + TYPE_EXTRA (union {) \ + TYPE_EXTRA (ElfW2(32, Ext##Word) d_val;) \ + TYPE_EXTRA (ElfW2(32, Ext##Addr) d_ptr;) \ + TYPE_XLATE (Elf32_cvt_Addr1 (&tdest->d_un.d_val, &tsrc->d_un.d_val);) \ + TYPE_EXTRA (ElfW2(32, Ext##Off) d_off;) \ + TYPE_EXTRA (} d_un;) \ +END (32, Ext##Dyn) +#define Dyn64(Ext) \ +START (64, Dyn, Ext##Dyn) \ + TYPE_NAME (ElfW2(64, Ext##Xword), d_tag) \ + TYPE_EXTRA (union {) \ + TYPE_EXTRA (ElfW2(64, Ext##Xword) d_val;) \ + TYPE_EXTRA (ElfW2(64, Ext##Addr) d_ptr;) \ + TYPE_XLATE (Elf64_cvt_Addr1 (&tdest->d_un.d_val, &tsrc->d_un.d_val);) \ + TYPE_EXTRA (} d_un;) \ +END (64, Ext##Dyn) + + +#ifndef GENERATE_CONVERSION +/* Version definitions. */ +# define Verdef(Bits, Ext) \ +START (Bits, Verdef, Ext##Verdef) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vd_version) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vd_flags) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vd_ndx) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vd_cnt) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vd_hash) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vd_aux) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vd_next) \ +END (Bits, Ext##Verdef) + +# define Verdef32(Ext) \ + Verdef (32, Ext) +# define Verdef64(Ext) \ + Verdef (64, Ext) + +# define Verdaux(Bits, Ext) \ +START (Bits, Verdaux, Ext##Verdaux) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vda_name) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vda_next) \ +END (Bits, Ext##Verdaux) + +# define Verdaux32(Ext) \ + Verdaux (32, Ext) +# define Verdaux64(Ext) \ + Verdaux (64, Ext) + +/* Required versions. */ +# define Verneed(Bits, Ext) \ +START (Bits, Verneed, Ext##Verneed) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vn_version) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vn_cnt) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vn_file) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vn_aux) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vn_next) \ +END (Bits, Ext##Verneed) + +# define Verneed32(Ext) \ + Verneed (32, Ext) +# define Verneed64(Ext) \ + Verneed (64, Ext) + +# define Vernaux(Bits, Ext) \ +START (Bits, Vernaux, Ext##Vernaux) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vna_hash) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vna_flags) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vna_other) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vna_name) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vna_next) \ +END (Bits, Ext##Vernaux) + +# define Vernaux32(Ext) \ + Vernaux (32, Ext) +# define Vernaux64(Ext) \ + Vernaux (64, Ext) +#endif + +/* Symbol information. */ +#define Syminfo(Bits, Ext) \ +START (Bits, Syminfo, Ext##Syminfo) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), si_boundto) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), si_flags) \ +END (Bits, Ext##Syminfo) + +#define Syminfo32(Ext) \ + Syminfo (32, Ext) +#define Syminfo64(Ext) \ + Syminfo (64, Ext) + +/* Move information. */ +#define Move(Bits, Ext) \ +START (Bits, Move, Ext##Move) \ + TYPE_NAME (ElfW2(Bits, Ext##Xword), m_value) \ + TYPE_NAME (ElfW2(Bits, Ext##Xword), m_info) \ + TYPE_NAME (ElfW2(Bits, Ext##Xword), m_poffset) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), m_repeat) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), m_stride) \ +END (Bits, Ext##Move) + +#define Move32(Ext) \ + Move (32, Ext) +#define Move64(Ext) \ + Move (64, Ext) + +#define Lib(Bits, Ext) \ +START (Bits, Lib, Ext##Lib) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), l_name) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), l_time_stamp) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), l_checksum) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), l_version) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), l_flags) \ +END (Bits, Ext##Lib) + +#define Lib32(Ext) \ + Lib (32, Ext) +#define Lib64(Ext) \ + Lib (64, Ext) diff --git a/libelf/common.h b/libelf/common.h new file mode 100644 index 00000000..ac1c61d6 --- /dev/null +++ b/libelf/common.h @@ -0,0 +1,146 @@ +/* Common definitions for handling files in memory or only on disk. + Copyright (C) 1998, 1999, 2000, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _COMMON_H +#define _COMMON_H 1 + +#include +#include +#include +#include +#include + + +static inline Elf_Kind +determine_kind (void *buf, size_t len) +{ + /* First test for an archive. */ + if (len >= SARMAG && memcmp (buf, ARMAG, SARMAG) == 0) + return ELF_K_AR; + + /* Next try ELF files. */ + if (len >= EI_NIDENT && memcmp (buf, ELFMAG, SELFMAG) == 0) + { + /* Could be an ELF file. */ + int eclass = (int) ((unsigned char *) buf)[EI_CLASS]; + int data = (int) ((unsigned char *) buf)[EI_DATA]; + int version = (int) ((unsigned char *) buf)[EI_VERSION]; + + if (eclass > ELFCLASSNONE && eclass < ELFCLASSNUM + && data > ELFDATANONE && data < ELFDATANUM + && version > EV_NONE && version < EV_NUM) + return ELF_K_ELF; + } + + /* We do not know this file type. */ + return ELF_K_NONE; +} + + +/* Allocate an Elf descriptor and fill in the generic information. */ +static inline Elf * +allocate_elf (int fildes, void *map_address, off_t offset, size_t maxsize, + Elf_Cmd cmd, Elf *parent, Elf_Kind kind, size_t extra) +{ + Elf *result = (Elf *) calloc (1, sizeof (Elf) + extra); + if (result == NULL) + __libelf_seterrno (ELF_E_NOMEM); + else + { + result->kind = kind; + result->ref_count = 1; + result->cmd = cmd; + result->fildes = fildes; + result->start_offset = offset; + result->maximum_size = maxsize; + result->map_address = map_address; + result->parent = parent; + + rwlock_init (result->lock); + } + + return result; +} + + +/* Acquire lock for the descriptor and all children. */ +static void +libelf_acquire_all (Elf *elf) +{ + rwlock_wrlock (elf->lock); + + if (elf->kind == ELF_K_AR) + { + Elf *child = elf->state.ar.children; + + while (child != NULL) + { + if (child->ref_count != 0) + libelf_acquire_all (child); + child = child->next; + } + } +} + +/* Release own lock and those of the children. */ +static void +libelf_release_all (Elf *elf) +{ + if (elf->kind == ELF_K_AR) + { + Elf *child = elf->state.ar.children; + + while (child != NULL) + { + if (child->ref_count != 0) + libelf_release_all (child); + child = child->next; + } + } + + rwlock_unlock (elf->lock); +} + + +/* Macro to convert endianess in place. It determines the function it + has to use itself. */ +#define CONVERT(Var) \ + (Var) = (sizeof (Var) == 1 \ + ? (unsigned char) (Var) \ + : (sizeof (Var) == 2 \ + ? bswap_16 (Var) \ + : (sizeof (Var) == 4 \ + ? bswap_32 (Var) \ + : bswap_64 (Var)))) + +#define CONVERT_TO(Dst, Var) \ + (Dst) = (sizeof (Var) == 1 \ + ? (unsigned char) (Var) \ + : (sizeof (Var) == 2 \ + ? bswap_16 (Var) \ + : (sizeof (Var) == 4 \ + ? bswap_32 (Var) \ + : bswap_64 (Var)))) + + +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define MY_ELFDATA ELFDATA2LSB +#else +# define MY_ELFDATA ELFDATA2MSB +#endif + +#endif /* common.h */ diff --git a/libelf/dl-hash.h b/libelf/dl-hash.h new file mode 100644 index 00000000..c8e89626 --- /dev/null +++ b/libelf/dl-hash.h @@ -0,0 +1,70 @@ +/* Compute hash value for given string according to ELF standard. + Copyright (C) 1995-1998, 2002, 2004 Free Software Foundation, Inc. + Written by Ulrich Drepper , 1995. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _DL_HASH_H +#define _DL_HASH_H 1 + + +/* This is the hashing function specified by the ELF ABI. In the + first five operations no overflow is possible so we optimized it a + bit. */ +static inline unsigned int +__attribute__ ((__pure__)) +_dl_elf_hash (const char *name) +{ + const unsigned char *iname = (const unsigned char *) name; + unsigned int hash = (unsigned int) *iname++; + if (*iname != '\0') + { + hash = (hash << 4) + (unsigned int) *iname++; + if (*iname != '\0') + { + hash = (hash << 4) + (unsigned int) *iname++; + if (*iname != '\0') + { + hash = (hash << 4) + (unsigned int) *iname++; + if (*iname != '\0') + { + hash = (hash << 4) + (unsigned int) *iname++; + while (*iname != '\0') + { + unsigned int hi; + hash = (hash << 4) + (unsigned int) *iname++; + hi = hash & 0xf0000000; + + /* The algorithm specified in the ELF ABI is as + follows: + + if (hi != 0) + hash ^= hi >> 24; + + hash &= ~hi; + + But the following is equivalent and a lot + faster, especially on modern processors. */ + + hash ^= hi; + hash ^= hi >> 24; + } + } + } + } + } + return hash; +} + +#endif /* dl-hash.h */ diff --git a/libelf/elf-knowledge.h b/libelf/elf-knowledge.h new file mode 100644 index 00000000..b92fd8a2 --- /dev/null +++ b/libelf/elf-knowledge.h @@ -0,0 +1,94 @@ +/* Accumulation of various pieces of knowledge about ELF. + Copyright (C) 2000, 2001, 2002, 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_KNOWLEDGE_H +#define _ELF_KNOWLEDGE_H 1 + +#include + + +/* Test whether a section can be stripped or not. */ +#define SECTION_STRIP_P(shdr, name, remove_comment) \ + /* Sections which are allocated are not removed. */ \ + (((shdr)->sh_flags & SHF_ALLOC) == 0 \ + /* We never remove .note sections. */ \ + && (shdr)->sh_type != SHT_NOTE \ + && (((shdr)->sh_type) != SHT_PROGBITS \ + /* Never remove .gnu.warning.* sections. */ \ + || (strncmp (name, ".gnu.warning.", sizeof ".gnu.warning." - 1) != 0 \ + /* We remove .comment sections only if explicitly told to do so. */\ + && (remove_comment \ + || strcmp (name, ".comment") != 0))) \ + /* So far we do not remove any of the non-standard sections. \ + XXX Maybe in future. */ \ + && (shdr)->sh_type < SHT_NUM) + + +/* Test whether `sh_info' field in section header contains a section + index. There are two kinds of sections doing this: + + - the sections containing relocation information reference in this + field the section to which the relocations apply; + + - section with the SHF_INFO_LINK flag set to signal that `sh_info' + references a section. This allows correct handling of unknown + sections. */ +#define SH_INFO_LINK_P(Shdr) \ + ((Shdr)->sh_type == SHT_REL || (Shdr)->sh_type == SHT_RELA \ + || ((Shdr)->sh_flags & SHF_INFO_LINK) != 0) + + +/* When combining ELF section flags we must distinguish two kinds: + + - flags which cause problem if not added to the result even if not + present in all input sections + + - flags which cause problem if added to the result if not present + in all input sections + + The following definition is for the general case. There might be + machine specific extensions. */ +#define SH_FLAGS_COMBINE(Flags1, Flags2) \ + (((Flags1 | Flags2) \ + & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_LINK_ORDER \ + | SHF_OS_NONCONFORMING | SHF_GROUP)) \ + | (Flags1 & Flags2 & (SHF_MERGE | SHF_STRINGS | SHF_INFO_LINK))) + +/* Similar macro: return the bits of the flags which necessarily must + match if two sections are automatically combined. Sections still + can be forcefully combined in which case SH_FLAGS_COMBINE can be + used to determine the combined flags. */ +#define SH_FLAGS_IMPORTANT(Flags) \ + ((Flags) & ~((GElf_Xword) 0 | SHF_LINK_ORDER | SHF_OS_NONCONFORMING)) + + +/* Size of an entry in the hash table. The ELF specification says all + entries are regardless of platform 32-bits in size. Early 64-bit + ports (namely Alpha for Linux) got this wrong. The wording was not + clear. + + Several years later the ABI for the 64-bit S390s was developed. + Many things were copied from the IA-64 ABI (which uses the correct + 32-bit entry size) but what do these people do? They use 64-bit + entries. It is really shocking to see what kind of morons are out + there. And even worse: they are allowed to design ABIs. */ +#define SH_ENTSIZE_HASH(Ehdr) \ + ((Ehdr)->e_machine == EM_ALPHA \ + || ((Ehdr)->e_machine == EM_S390 \ + && (Ehdr)->e_ident[EI_CLASS] == ELFCLASS64) ? 8 : 4) + +#endif /* elf-knowledge.h */ diff --git a/libelf/elf.h b/libelf/elf.h new file mode 100644 index 00000000..e246519f --- /dev/null +++ b/libelf/elf.h @@ -0,0 +1,2577 @@ +/* This file defines standard ELF types, structures, and macros. + Copyright (C) 1995-2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _ELF_H +#define _ELF_H 1 + +#include + +__BEGIN_DECLS + +/* Standard ELF types. */ + +#include + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* Type for version symbol information. */ +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_LINUX 3 /* Linux. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ + +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_NUM 95 + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +#define EM_ALPHA 0x9026 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_BEFORE 0xff00 /* Order section before all others + (Solaris). */ +#define SHN_AFTER 0xff01 /* Order section after all others + (Solaris). */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling + required */ +#define SHF_GROUP (1 << 9) /* Section is member of a group. */ +#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ +#define SHF_ORDERED (1 << 30) /* Special ordering requirement + (Solaris). */ +#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless + referenced or allocated (Solaris).*/ + +/* Section group handling. */ +#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ + +/* Symbol table entry. */ + +typedef struct +{ + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ + +typedef struct +{ + Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf32_Half si_flags; /* Per symbol flags */ +} Elf32_Syminfo; + +typedef struct +{ + Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf64_Half si_flags; /* Per symbol flags */ +} Elf64_Syminfo; + +/* Possible values for si_boundto. */ +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy + loaded */ +/* Syminfo version values. */ +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + + +/* How to extract and insert information held in the st_other field. */ + +#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) + +/* For ELF64 the definitions are the same. */ +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) + +/* Symbol visibility specification encoded in the st_other field. */ +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* I have seen two different definitions of the Elf64_Rel and + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ +/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ + Elf64_Sxword r_addend; /* Addend */ +} Elf64_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) + +/* Program segment header. */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread-local storage segment */ +#define PT_NUM 8 /* Number of defined types */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ +#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKOS 0x0ff00000 /* OS-specific */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Legal values for note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_PRXREG 4 /* Contains copy of prxregset struct */ +#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ +#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ +#define NT_AUXV 6 /* Contains copy of auxv array */ +#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ +#define NT_ASRS 8 /* Contains copy of asrset struct */ +#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ +#define NT_PSINFO 13 /* Contains copy of psinfo struct */ +#define NT_PRCRED 14 /* Contains copy of prcred struct */ +#define NT_UTSNAME 15 /* Contains copy of utsname struct */ +#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ +#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ +#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct*/ + +/* Legal values for the note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ + + +/* Dynamic section entry. */ + +typedef struct +{ + Elf32_Sword d_tag; /* Dynamic entry type */ + union + { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ +#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ + +/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's + approach. */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting + the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 10 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF 0x6ffffffc /* Address of version definition + table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED 0x6ffffffe /* Address of table with needed + versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM 3 + +/* Values of `d_un.d_val' in the DT_FLAGS entry. */ +#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ +#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ + +/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 + entry in the dynamic section. */ +#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ +#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ +#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ +#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ +#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ +#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ +#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ +#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ +#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ +#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ +#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ +#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ + +/* Flags for the feature selection in DT_FEATURE_1. */ +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ +#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ +#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not + generally available. */ + +/* Version definition sections. */ + +typedef struct +{ + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf32_Verdef; + +typedef struct +{ + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf64_Verdef; + + +/* Legal values for vd_version (version revision). */ +#define VER_DEF_NONE 0 /* No version */ +#define VER_DEF_CURRENT 1 /* Current version */ +#define VER_DEF_NUM 2 /* Given version number */ + +/* Legal values for vd_flags (version information flags). */ +#define VER_FLG_BASE 0x1 /* Version definition of file itself */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Versym symbol index values. */ +#define VER_NDX_LOCAL 0 /* Symbol is local. */ +#define VER_NDX_GLOBAL 1 /* Symbol is global. */ +#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ +#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ + +/* Auxialiary version information. */ + +typedef struct +{ + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf32_Verdaux; + +typedef struct +{ + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf64_Verdaux; + + +/* Version dependency section. */ + +typedef struct +{ + Elf32_Half vn_version; /* Version of structure */ + Elf32_Half vn_cnt; /* Number of associated aux entries */ + Elf32_Word vn_file; /* Offset of filename for this + dependency */ + Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf32_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf32_Verneed; + +typedef struct +{ + Elf64_Half vn_version; /* Version of structure */ + Elf64_Half vn_cnt; /* Number of associated aux entries */ + Elf64_Word vn_file; /* Offset of filename for this + dependency */ + Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf64_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf64_Verneed; + + +/* Legal values for vn_version (version revision). */ +#define VER_NEED_NONE 0 /* No version */ +#define VER_NEED_CURRENT 1 /* Current version */ +#define VER_NEED_NUM 2 /* Given version number */ + +/* Auxiliary needed version information. */ + +typedef struct +{ + Elf32_Word vna_hash; /* Hash value of dependency name */ + Elf32_Half vna_flags; /* Dependency specific information */ + Elf32_Half vna_other; /* Unused */ + Elf32_Word vna_name; /* Dependency name string offset */ + Elf32_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf32_Vernaux; + +typedef struct +{ + Elf64_Word vna_hash; /* Hash value of dependency name */ + Elf64_Half vna_flags; /* Dependency specific information */ + Elf64_Half vna_other; /* Unused */ + Elf64_Word vna_name; /* Dependency name string offset */ + Elf64_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf64_Vernaux; + + +/* Legal values for vna_flags. */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + + +/* Auxiliary vector. */ + +/* This vector is normally only used by the program interpreter. The + usual definition in an ABI supplement uses the name auxv_t. The + vector is not usually defined in a standard file, but it + can't hurt. We rename it to avoid conflicts. The sizes of these + types are an arrangement between the exec server and the program + interpreter, so we don't fully specify them here. */ + +typedef struct +{ + uint32_t a_type; /* Entry type */ + union + { + uint32_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf32_auxv_t; + +typedef struct +{ + uint64_t a_type; /* Entry type */ + union + { + uint64_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf64_auxv_t; + +/* Legal values for a_type (entry type). */ + +#define AT_NULL 0 /* End of vector */ +#define AT_IGNORE 1 /* Entry should be ignored */ +#define AT_EXECFD 2 /* File descriptor of program */ +#define AT_PHDR 3 /* Program headers for program */ +#define AT_PHENT 4 /* Size of program header entry */ +#define AT_PHNUM 5 /* Number of program headers */ +#define AT_PAGESZ 6 /* System page size */ +#define AT_BASE 7 /* Base address of interpreter */ +#define AT_FLAGS 8 /* Flags */ +#define AT_ENTRY 9 /* Entry point of program */ +#define AT_NOTELF 10 /* Program is not ELF */ +#define AT_UID 11 /* Real uid */ +#define AT_EUID 12 /* Effective uid */ +#define AT_GID 13 /* Real gid */ +#define AT_EGID 14 /* Effective gid */ +#define AT_CLKTCK 17 /* Frequency of times() */ + +/* Some more special a_type values describing the hardware. */ +#define AT_PLATFORM 15 /* String identifying platform. */ +#define AT_HWCAP 16 /* Machine dependent hints about + processor capabilities. */ + +/* This entry gives some information about the FPU initialization + performed by the kernel. */ +#define AT_FPUCW 18 /* Used FPU control word. */ + +/* Cache block sizes. */ +#define AT_DCACHEBSIZE 19 /* Data cache block size. */ +#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ +#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ + +/* A special ignored value for PPC, used by the kernel to control the + interpretation of the AUXV. Must be > 16. */ +#define AT_IGNOREPPC 22 /* Entry should be ignored. */ + +#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ + +/* Pointer to the global system page used for system calls and other + nice things. */ +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + +/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains + log2 of line size; mask those to get cache size. */ +#define AT_L1I_CACHESHAPE 34 +#define AT_L1D_CACHESHAPE 35 +#define AT_L2_CACHESHAPE 36 +#define AT_L3_CACHESHAPE 37 + +/* Note section contents. Each entry in the note section begins with + a header of a fixed form. */ + +typedef struct +{ + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +typedef struct +{ + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Known names of notes. */ + +/* Solaris entries in the note section have this name. */ +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +/* Note entries for GNU systems have this name. */ +#define ELF_NOTE_GNU "GNU" + + +/* Defined types of notes for Solaris. */ + +/* Value of descriptor (one word) is desired pagesize for the binary. */ +#define ELF_NOTE_PAGESIZE_HINT 1 + + +/* Defined note types for GNU systems. */ + +/* ABI information. The descriptor consists of words: + word 0: OS descriptor + word 1: major version of the ABI + word 2: minor version of the ABI + word 3: subminor version of the ABI +*/ +#define ELF_NOTE_ABI 1 + +/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI + note section entry. */ +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 +#define ELF_NOTE_OS_FREEBSD 3 + + +/* Move records. */ +typedef struct +{ + Elf32_Xword m_value; /* Symbol value. */ + Elf32_Word m_info; /* Size and index. */ + Elf32_Word m_poffset; /* Symbol offset. */ + Elf32_Half m_repeat; /* Repeat count. */ + Elf32_Half m_stride; /* Stride info. */ +} Elf32_Move; + +typedef struct +{ + Elf64_Xword m_value; /* Symbol value. */ + Elf64_Xword m_info; /* Size and index. */ + Elf64_Xword m_poffset; /* Symbol offset. */ + Elf64_Half m_repeat; /* Repeat count. */ + Elf64_Half m_stride; /* Stride info. */ +} Elf64_Move; + +/* Macro to construct move records. */ +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char) (info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM (info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) + + +/* Motorola 68k specific definitions. */ + +/* Values for Elf32_Ehdr.e_flags. */ +#define EF_CPU32 0x00810000 + +/* m68k relocs. */ + +#define R_68K_NONE 0 /* No reloc */ +#define R_68K_32 1 /* Direct 32 bit */ +#define R_68K_16 2 /* Direct 16 bit */ +#define R_68K_8 3 /* Direct 8 bit */ +#define R_68K_PC32 4 /* PC relative 32 bit */ +#define R_68K_PC16 5 /* PC relative 16 bit */ +#define R_68K_PC8 6 /* PC relative 8 bit */ +#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ +#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ +#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ +#define R_68K_GOT32O 10 /* 32 bit GOT offset */ +#define R_68K_GOT16O 11 /* 16 bit GOT offset */ +#define R_68K_GOT8O 12 /* 8 bit GOT offset */ +#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ +#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ +#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ +#define R_68K_PLT32O 16 /* 32 bit PLT offset */ +#define R_68K_PLT16O 17 /* 16 bit PLT offset */ +#define R_68K_PLT8O 18 /* 8 bit PLT offset */ +#define R_68K_COPY 19 /* Copy symbol at runtime */ +#define R_68K_GLOB_DAT 20 /* Create GOT entry */ +#define R_68K_JMP_SLOT 21 /* Create PLT entry */ +#define R_68K_RELATIVE 22 /* Adjust by program base */ +/* Keep this the last entry. */ +#define R_68K_NUM 23 + +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ +#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS + block offset */ +#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block + offset */ +#define R_386_TLS_LE 17 /* Offset relative to static TLS + block */ +#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of + general dynamic thread local data */ +#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of + local dynamic thread local data + in LE code */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic + thread local data */ +#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ +#define R_386_TLS_GD_CALL 26 /* Relocation for call to + __tls_get_addr() */ +#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ +#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic + thread local data in LE code */ +#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ +#define R_386_TLS_LDM_CALL 30 /* Relocation for call to + __tls_get_addr() in LDM code */ +#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ +#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ +#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS + block offset */ +#define R_386_TLS_LE_32 34 /* Negated offset relative to static + TLS block */ +#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ +#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +/* Keep this the last entry. */ +#define R_386_NUM 38 + +/* SUN SPARC specific definitions. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ + +/* Values for Elf64_Ehdr.e_flags. */ + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_LEDATA 0x800000 /* little endian data */ +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ +#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ +#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ +#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ + +/* SPARC relocs. */ + +#define R_SPARC_NONE 0 /* No reloc */ +#define R_SPARC_8 1 /* Direct 8 bit */ +#define R_SPARC_16 2 /* Direct 16 bit */ +#define R_SPARC_32 3 /* Direct 32 bit */ +#define R_SPARC_DISP8 4 /* PC relative 8 bit */ +#define R_SPARC_DISP16 5 /* PC relative 16 bit */ +#define R_SPARC_DISP32 6 /* PC relative 32 bit */ +#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ +#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ +#define R_SPARC_HI22 9 /* High 22 bit */ +#define R_SPARC_22 10 /* Direct 22 bit */ +#define R_SPARC_13 11 /* Direct 13 bit */ +#define R_SPARC_LO10 12 /* Truncated 10 bit */ +#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ +#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ +#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ +#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ +#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ +#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ +#define R_SPARC_COPY 19 /* Copy symbol at runtime */ +#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ +#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ +#define R_SPARC_RELATIVE 22 /* Adjust by program base */ +#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ + +/* Additional Sparc64 relocs. */ + +#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ +#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ +#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ +#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ +#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ +#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ +#define R_SPARC_10 30 /* Direct 10 bit */ +#define R_SPARC_11 31 /* Direct 11 bit */ +#define R_SPARC_64 32 /* Direct 64 bit */ +#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ +#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ +#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ +#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ +#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ +#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ +#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ +#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ +#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ +#define R_SPARC_7 43 /* Direct 7 bit */ +#define R_SPARC_5 44 /* Direct 5 bit */ +#define R_SPARC_6 45 /* Direct 6 bit */ +#define R_SPARC_DISP64 46 /* PC relative 64 bit */ +#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ +#define R_SPARC_HIX22 48 /* High 22 bit complemented */ +#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ +#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ +#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ +#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ +#define R_SPARC_REGISTER 53 /* Global register usage */ +#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ +#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 +/* Keep this the last entry. */ +#define R_SPARC_NUM 80 + +/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM 2 + +/* Bits present in AT_HWCAP, primarily for Sparc32. */ + +#define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */ +#define HWCAP_SPARC_ULTRA3 32 + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ +#define EF_MIPS_PIC 2 /* Contains PIC code */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ + +/* Legal values for MIPS architecture level. */ + +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* The following are non-official names and should not be used. */ + +#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* Special section indices. */ + +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ +#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ +#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + + +/* Symbol tables. */ + +/* MIPS specific values for `st_other'. */ +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + +/* MIPS specific values for `st_info'. */ +#define STB_MIPS_SPLIT_COMMON 13 + +/* Entries found in sections of type SHT_MIPS_GPTAB. */ + +typedef union +{ + struct + { + Elf32_Word gt_current_g_value; /* -G value used for compilation */ + Elf32_Word gt_unused; /* Not used */ + } gt_header; /* First entry in section */ + struct + { + Elf32_Word gt_g_value; /* If this value were used for -G */ + Elf32_Word gt_bytes; /* This many bytes would be used */ + } gt_entry; /* Subsequent entries in section */ +} Elf32_gptab; + +/* Entry found in sections of type SHT_MIPS_REGINFO. */ + +typedef struct +{ + Elf32_Word ri_gprmask; /* General registers used */ + Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ + Elf32_Sword ri_gp_value; /* $gp register value */ +} Elf32_RegInfo; + +/* Entries found in sections of type SHT_MIPS_OPTIONS. */ + +typedef struct +{ + unsigned char kind; /* Determines interpretation of the + variable part of descriptor. */ + unsigned char size; /* Size of descriptor, including header. */ + Elf32_Section section; /* Section header index of section affected, + 0 for global options. */ + Elf32_Word info; /* Kind-specific information. */ +} Elf_Options; + +/* Values for `kind' field in Elf_Options. */ + +#define ODK_NULL 0 /* Undefined. */ +#define ODK_REGINFO 1 /* Register usage information. */ +#define ODK_EXCEPTIONS 2 /* Exception processing options. */ +#define ODK_PAD 3 /* Section padding options. */ +#define ODK_HWPATCH 4 /* Hardware workarounds performed */ +#define ODK_FILL 5 /* record the fill value used by the linker. */ +#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ +#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ +#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ + +/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ + +#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ +#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ +#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ +#define OEX_SMM 0x20000 /* Force sequential memory mode? */ +#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ +#define OEX_PRECISEFP OEX_FPDBUG +#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ + +#define OEX_FPU_INVAL 0x10 +#define OEX_FPU_DIV0 0x08 +#define OEX_FPU_OFLO 0x04 +#define OEX_FPU_UFLO 0x02 +#define OEX_FPU_INEX 0x01 + +/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ + +#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ +#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ +#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ +#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ + +#define OPAD_PREFIX 0x1 +#define OPAD_POSTFIX 0x2 +#define OPAD_SYMBOL 0x4 + +/* Entry found in `.options' section. */ + +typedef struct +{ + Elf32_Word hwp_flags1; /* Extra flags. */ + Elf32_Word hwp_flags2; /* Extra flags. */ +} Elf_Options_Hw; + +/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ + +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA1_R4KEOP_CLEAN 0x00000002 + +/* MIPS relocs. */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ +#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ +#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ +#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ +#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ +#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ +#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ +#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ +#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ +#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ +#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ +#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ +#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ +/* Keep this the last entry. */ +#define R_MIPS_NUM 51 + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Special program header types. */ + +#define PF_MIPS_LOCAL 0x10000000 + +/* Legal values for d_tag field of Elf32_Dyn. */ + +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ +#define DT_MIPS_MSYM 0x70000007 +#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ +#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in + DT_MIPS_DELTA_CLASS. */ +#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in + DT_MIPS_DELTA_INSTANCE. */ +#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in + DT_MIPS_DELTA_RELOC. */ +#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta + relocations refer to. */ +#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in + DT_MIPS_DELTA_SYM. */ +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the + class declaration. */ +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in + DT_MIPS_DELTA_CLASSSYM. */ +#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ +#define DT_MIPS_PIXIE_INIT 0x70000023 +#define DT_MIPS_SYMBOL_LIB 0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ +#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve + function stored in GOT. */ +#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added + by rld on dlopen() calls. */ +#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ +#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ +#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ +#define DT_MIPS_NUM 0x32 + +/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +#define RHF_NONE 0 /* No flags */ +#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ +#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ +#define RHF_NO_MOVE (1 << 3) +#define RHF_SGI_ONLY (1 << 4) +#define RHF_GUARANTEE_INIT (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS (1 << 6) +#define RHF_GUARANTEE_START_INIT (1 << 7) +#define RHF_PIXIE (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD (1 << 9) +#define RHF_REQUICKSTART (1 << 10) +#define RHF_REQUICKSTARTED (1 << 11) +#define RHF_CORD (1 << 12) +#define RHF_NO_UNRES_UNDEF (1 << 13) +#define RHF_RLD_ORDER_SAFE (1 << 14) + +/* Entries found in sections of type SHT_MIPS_LIBLIST. */ + +typedef struct +{ + Elf32_Word l_name; /* Name (string table index) */ + Elf32_Word l_time_stamp; /* Timestamp */ + Elf32_Word l_checksum; /* Checksum */ + Elf32_Word l_version; /* Interface version */ + Elf32_Word l_flags; /* Flags */ +} Elf32_Lib; + +typedef struct +{ + Elf64_Word l_name; /* Name (string table index) */ + Elf64_Word l_time_stamp; /* Timestamp */ + Elf64_Word l_checksum; /* Checksum */ + Elf64_Word l_version; /* Interface version */ + Elf64_Word l_flags; /* Flags */ +} Elf64_Lib; + + +/* Legal values for l_flags. */ + +#define LL_NONE 0 +#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ +#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ +#define LL_REQUIRE_MINOR (1 << 2) +#define LL_EXPORTS (1 << 3) +#define LL_DELAY_LOAD (1 << 4) +#define LL_DELTA (1 << 5) + +/* Entries found in sections of type SHT_MIPS_CONFLICT. */ + +typedef Elf32_Addr Elf32_Conflict; + + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indeces. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + + +/* Alpha specific definitions. */ + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ +#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ + +/* Legal values for sh_type field of Elf64_Shdr. */ + +/* These two are primerily concerned with ECOFF debugging info. */ +#define SHT_ALPHA_DEBUG 0x70000001 +#define SHT_ALPHA_REGINFO 0x70000002 + +/* Legal values for sh_flags field of Elf64_Shdr. */ + +#define SHF_ALPHA_GPREL 0x10000000 + +/* Legal values for st_other field of Elf64_Sym. */ +#define STO_ALPHA_NOPV 0x80 /* No PV required. */ +#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ + +/* Alpha relocs. */ + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_TLS_GD_HI 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 +/* Keep this the last entry. */ +#define R_ALPHA_NUM 46 + +/* Magic values of the LITUSE relocation addend. */ +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLS_GD 4 +#define LITUSE_ALPHA_TLS_LDM 5 + + +/* PowerPC specific declarations */ + +/* Values for Elf32/64_Ehdr.e_flags. */ +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + +/* Cygnus local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib + flag */ + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +/* PowerPC relocations defined for the TLS access ABI. */ +#define R_PPC_TLS 67 /* none (sym+add)@tls */ +#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ +#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ +#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ +#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ +#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ +#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ +#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ +#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ +#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ + +/* Keep this the last entry. */ +#define R_PPC_NUM 95 + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ + +/* Diab tool relocations. */ +#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ +#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ +#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ +#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ +#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ +#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ +#define R_PPC_TOC16 255 + + +/* PowerPC64 relocations defined by the ABIs */ +#define R_PPC64_NONE R_PPC_NONE +#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ +#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ +#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ +#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ +#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ +#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ +#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ +#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ +#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ +#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16 R_PPC_GOT16 +#define R_PPC64_GOT16_LO R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA R_PPC_GOT16_HA + +#define R_PPC64_COPY R_PPC_COPY +#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE R_PPC_RELATIVE + +#define R_PPC64_UADDR32 R_PPC_UADDR32 +#define R_PPC64_UADDR16 R_PPC_UADDR16 +#define R_PPC64_REL32 R_PPC_REL32 +#define R_PPC64_PLT32 R_PPC_PLT32 +#define R_PPC64_PLTREL32 R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ +#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ +#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ +#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ +#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ +#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ +#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ +#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ +#define R_PPC64_PLT64 45 /* doubleword64 L + A */ +#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ +#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ +#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ +#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ +#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ +#define R_PPC64_TOC 51 /* doubleword64 .TOC */ +#define R_PPC64_PLTGOT16 52 /* half16* M + A */ +#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ +#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ +#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ + +#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ +#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ +#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ +#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ +#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ +#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ +#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ +#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ +#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ +#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ +#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ + +/* PowerPC64 relocations defined for the TLS access ABI. */ +#define R_PPC64_TLS 67 /* none (sym+add)@tls */ +#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ +#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ +#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ +#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ +#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ +#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ +#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ +#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ +#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ +#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ +#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ +#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ +#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ +#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ +#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ +#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ +#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ + +/* Keep this the last entry. */ +#define R_PPC64_NUM 107 + +/* PowerPC64 specific values for the Dyn d_tag field. */ +#define DT_PPC64_GLINK (DT_LOPROC + 0) +#define DT_PPC64_OPD (DT_LOPROC + 1) +#define DT_PPC64_OPDSZ (DT_LOPROC + 2) +#define DT_PPC64_NUM 3 + + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 + +/* Other constants defined in the ARM ELF spec. version B-01. */ +/* NB. These conflict with values defined above. */ +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + +#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 + +/* Additional symbol types for Thumb */ +#define STT_ARM_TFUNC 0xd + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined + in the input to a link step */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */ + +/* ARM relocs. */ + +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_LDR_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ +#define R_ARM_THM_PC9 103 /* thumb conditional branch */ +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ +#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) +#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) +#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +/* SH specific declarations */ + +/* SH relocs. */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +/* Keep this the last entry. */ +#define R_SH_NUM 256 + +/* Additional s390 relocs */ + +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS + block. */ +#define R_390_20 57 /* Direct 20 bit. */ +#define R_390_GOT20 58 /* 20 bit GOT offset. */ +#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ +#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS + block offset. */ +/* Keep this the last entry. */ +#define R_390_NUM 61 + + +/* CRIS relocations. */ +#define R_CRIS_NONE 0 +#define R_CRIS_8 1 +#define R_CRIS_16 2 +#define R_CRIS_32 3 +#define R_CRIS_8_PCREL 4 +#define R_CRIS_16_PCREL 5 +#define R_CRIS_32_PCREL 6 +#define R_CRIS_GNU_VTINHERIT 7 +#define R_CRIS_GNU_VTENTRY 8 +#define R_CRIS_COPY 9 +#define R_CRIS_GLOB_DAT 10 +#define R_CRIS_JUMP_SLOT 11 +#define R_CRIS_RELATIVE 12 +#define R_CRIS_16_GOT 13 +#define R_CRIS_32_GOT 14 +#define R_CRIS_16_GOTPLT 15 +#define R_CRIS_32_GOTPLT 16 +#define R_CRIS_32_GOTREL 17 +#define R_CRIS_32_PLT_GOTREL 18 +#define R_CRIS_32_PLT_PCREL 19 + +#define R_CRIS_NUM 20 + + +/* AMD x86-64 relocations. */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ +#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset + to two GOT entries for GD symbol */ +#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset + to two GOT entries for LD symbol */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset + to GOT entry for IE symbol */ +#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ + +#define R_X86_64_NUM 24 + + +/* AM33 relocations. */ +#define R_MN10300_NONE 0 /* No reloc. */ +#define R_MN10300_32 1 /* Direct 32 bit. */ +#define R_MN10300_16 2 /* Direct 16 bit. */ +#define R_MN10300_8 3 /* Direct 8 bit. */ +#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ +#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ +#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ +#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ +#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ +#define R_MN10300_24 9 /* Direct 24 bit. */ +#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ +#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ +#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ +#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ +#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ +#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ +#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ +#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ +#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ +#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ +#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ +#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ +#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ +#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ + +#define R_MN10300_NUM 24 + + +/* M32R relocs. */ +#define R_M32R_NONE 0 /* No reloc. */ +#define R_M32R_16 1 /* Direct 16 bit. */ +#define R_M32R_32 2 /* Direct 32 bit. */ +#define R_M32R_24 3 /* Direct 24 bit. */ +#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ +#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ +#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ +#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ +#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ +#define R_M32R_LO16 9 /* Low 16 bit. */ +#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ +#define R_M32R_GNU_VTINHERIT 11 +#define R_M32R_GNU_VTENTRY 12 +/* M32R relocs use SHT_RELA. */ +#define R_M32R_16_RELA 33 /* Direct 16 bit. */ +#define R_M32R_32_RELA 34 /* Direct 32 bit. */ +#define R_M32R_24_RELA 35 /* Direct 24 bit. */ +#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ +#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ +#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ +#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ +#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ +#define R_M32R_LO16_RELA 41 /* Low 16 bit */ +#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ +#define R_M32R_RELA_GNU_VTINHERIT 43 +#define R_M32R_RELA_GNU_VTENTRY 44 + +#define R_M32R_GOT24 48 /* 24 bit GOT entry */ +#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ +#define R_M32R_COPY 50 /* Copy symbol at runtime */ +#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ +#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ +#define R_M32R_RELATIVE 53 /* Adjust by program base */ +#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ +#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ +#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned + low */ +#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed + low */ +#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ +#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to + GOT with unsigned low */ +#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to + GOT with signed low */ +#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to + GOT */ +#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT + with unsigned low */ +#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT + with signed low */ +#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ +#define R_M32R_NUM 256 /* Keep this the last entry. */ + + +__END_DECLS + +#endif /* elf.h */ diff --git a/libelf/elf32_checksum.c b/libelf/elf32_checksum.c new file mode 100644 index 00000000..a54ebbc4 --- /dev/null +++ b/libelf/elf32_checksum.c @@ -0,0 +1,145 @@ +/* Compute simple checksum from permanent parts of the ELF file. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "gelf.h" +#include "libelfP.h" +#include "elf-knowledge.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +/* The SECTION_STRIP_P macro wants to call into libebl which we cannot + do and do not have to do here. Provide a dummy replacement. */ +#define ebl_debugscn_p(ebl, name) true + + +#define process_block(crc, data) \ + __libelf_crc32 (crc, data->d_buf, data->d_size) + + +long int +elfw2(LIBELFBITS,checksum) (elf) + Elf *elf; +{ + size_t shstrndx; + Elf_Scn *scn; + long int result = 0; + unsigned char *ident; + bool same_byte_order; + + if (elf == NULL) + return -1l; + + /* Find the section header string table. */ + if (INTUSE(elf_getshstrndx) (elf, &shstrndx) < 0) + { + /* This can only happen if the ELF handle is not for real. */ + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1l; + } + + /* Determine whether the byte order of the file and that of the host + is the same. */ + ident = elf->state.ELFW(elf,LIBELFBITS).ehdr->e_ident; + same_byte_order = ((ident[EI_DATA] == ELFDATA2LSB + && __BYTE_ORDER == __LITTLE_ENDIAN) + || (ident[EI_DATA] == ELFDATA2MSB + && __BYTE_ORDER == __BIG_ENDIAN)); + + /* Iterate over all sections to find those which are not strippable. */ + scn = NULL; + while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Data *data; + + /* Get the section header. */ + shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem); + if (shdr == NULL) + { + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + return -1l; + } + + if (SECTION_STRIP_P (shdr, + INTUSE(elf_strptr) (elf, shstrndx, shdr->sh_name), + true)) + /* The section can be stripped. Don't use it. */ + continue; + + /* Do not look at NOBITS sections. */ + if (shdr->sh_type == SHT_NOBITS) + continue; + + /* To compute the checksum we need to get to the data. For + repeatable results we must use the external format. The data + we get with 'elf'getdata' might be changed for endianess + reasons. Therefore we use 'elf_rawdata' if possible. But + this function can fail if the data was constructed by the + program. In this case we have to use 'elf_getdata' and + eventually convert the data to the external format. */ + data = INTUSE(elf_rawdata) (scn, NULL); + if (data != NULL) + { + /* The raw data is available. */ + result = process_block (result, data); + + /* Maybe the user added more data. These blocks cannot be + read using 'elf_rawdata'. Simply proceed with looking + for more data block with 'elf_getdata'. */ + } + + /* Iterate through the list of data blocks. */ + while ((data = INTUSE(elf_getdata) (scn, data)) != NULL) + /* If the file byte order is the same as the host byte order + process the buffer directly. If the data is just a stream + of bytes which the library will not convert we can use it + as well. */ + if (likely (same_byte_order) || data->d_type == ELF_T_BYTE) + result = process_block (result, data); + else + { + /* Convert the data to file byte order. */ + if (INTUSE(elfw2(LIBELFBITS,xlatetof)) (data, data, ident[EI_DATA]) + == NULL) + return -1l; + + result = process_block (result, data); + + /* And convert it back. */ + if (INTUSE(elfw2(LIBELFBITS,xlatetom)) (data, data, ident[EI_DATA]) + == NULL) + return -1l; + } + } + + return result; +} +INTDEF(elfw2(LIBELFBITS,checksum)) diff --git a/libelf/elf32_fsize.c b/libelf/elf32_fsize.c new file mode 100644 index 00000000..50750198 --- /dev/null +++ b/libelf/elf32_fsize.c @@ -0,0 +1,59 @@ +/* Return the size of an object file type. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +size_t +elfw2(LIBELFBITS, fsize) (type, count, version) + Elf_Type type; + size_t count; + unsigned int version; +{ + /* We do not have differences between file and memory sizes. Better + not since otherwise `mmap' would not work. */ + if (unlikely (version == EV_NONE) || unlikely (version >= EV_NUM)) + { + __libelf_seterrno (ELF_E_UNKNOWN_VERSION); + return 0; + } + + if (unlikely (type >= ELF_T_NUM)) + { + __libelf_seterrno (ELF_E_UNKNOWN_TYPE); + return 0; + } + +#if EV_NUM != 2 + return (count + * __libelf_type_sizes[version - 1][ELFW(ELFCLASS,LIBELFBITS) - 1][type]); +#else + return (count + * __libelf_type_sizes[0][ELFW(ELFCLASS,LIBELFBITS) - 1][type]); +#endif +} +#define local_strong_alias(n1, n2) strong_alias (n1, n2) +local_strong_alias (elfw2(LIBELFBITS, fsize), __elfw2(LIBELFBITS, msize)) diff --git a/libelf/elf32_getehdr.c b/libelf/elf32_getehdr.c new file mode 100644 index 00000000..efd60025 --- /dev/null +++ b/libelf/elf32_getehdr.c @@ -0,0 +1,65 @@ +/* Get ELF header. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +ElfW2(LIBELFBITS,Ehdr) * +elfw2(LIBELFBITS,getehdr) (elf) + Elf *elf; +{ + ElfW2(LIBELFBITS,Ehdr) *result; + + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_rdlock (elf->lock); + + if (elf->class == 0) + elf->class = ELFW(ELFCLASS,LIBELFBITS); + else if (unlikely (elf->class != ELFW(ELFCLASS,LIBELFBITS))) + { + __libelf_seterrno (ELF_E_INVALID_CLASS); + result = NULL; + goto out; + } + + result = elf->state.ELFW(elf,LIBELFBITS).ehdr; + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elfw2(LIBELFBITS,getehdr)) diff --git a/libelf/elf32_getphdr.c b/libelf/elf32_getphdr.c new file mode 100644 index 00000000..25693687 --- /dev/null +++ b/libelf/elf32_getphdr.c @@ -0,0 +1,198 @@ +/* Get ELF program header table. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" +#include "common.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +ElfW2(LIBELFBITS,Phdr) * +elfw2(LIBELFBITS,getphdr) (elf) + Elf *elf; +{ + ElfW2(LIBELFBITS,Phdr) *result; + + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* If the program header entry has already been filled in the code + below must already have been run. So the class is set, too. No + need to waste any more time here. */ + result = elf->state.ELFW(elf,LIBELFBITS).phdr; + if (likely (result != NULL)) + return result; + + rwlock_wrlock (elf->lock); + + if (elf->class == 0) + elf->class = ELFW(ELFCLASS,LIBELFBITS); + else if (elf->class != ELFW(ELFCLASS,LIBELFBITS)) + { + __libelf_seterrno (ELF_E_INVALID_CLASS); + result = NULL; + goto out; + } + + if (likely (result == NULL)) + { + /* Read the section header table. */ + ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; + + /* If no program header exists return NULL. */ + size_t phnum = ehdr->e_phnum; + if (phnum == 0) + { + __libelf_seterrno (ELF_E_NO_PHDR); + goto out; + } + + size_t size = phnum * sizeof (ElfW2(LIBELFBITS,Phdr)); + + if (elf->map_address != NULL) + { + /* All the data is already mapped. Use it. */ + if (ehdr->e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || (ehdr->e_phoff + & (__alignof__ (ElfW2(LIBELFBITS,Phdr)) - 1)) == 0)) + /* Simply use the mapped data. */ + elf->state.ELFW(elf,LIBELFBITS).phdr = (ElfW2(LIBELFBITS,Phdr) *) + ((char *) elf->map_address + elf->start_offset + ehdr->e_phoff); + else + { + ElfW2(LIBELFBITS,Phdr) *notcvt; + ElfW2(LIBELFBITS,Phdr) *phdr; + + /* Allocate memory for the program headers. We know the number + of entries from the ELF header. */ + phdr = elf->state.ELFW(elf,LIBELFBITS).phdr = + (ElfW2(LIBELFBITS,Phdr) *) malloc (size); + if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= + ELF_F_MALLOCED | ELF_F_DIRTY; + + /* Now copy the data and at the same time convert the + byte order. */ + if (ALLOW_UNALIGNED + || (ehdr->e_phoff + & (__alignof__ (ElfW2(LIBELFBITS,Phdr)) - 1)) == 0) + notcvt = (ElfW2(LIBELFBITS,Phdr) *) + ((char *) elf->map_address + + elf->start_offset + ehdr->e_phoff); + else + { + notcvt = (ElfW2(LIBELFBITS,Phdr) *) alloca (size); + memcpy (notcvt, ((char *) elf->map_address + + elf->start_offset + ehdr->e_phoff), + size); + } + + for (size_t cnt = 0; cnt < phnum; ++cnt) + { + CONVERT_TO (phdr[cnt].p_type, notcvt[cnt].p_type); + CONVERT_TO (phdr[cnt].p_offset, notcvt[cnt].p_offset); + CONVERT_TO (phdr[cnt].p_vaddr, notcvt[cnt].p_vaddr); + CONVERT_TO (phdr[cnt].p_paddr, notcvt[cnt].p_paddr); + CONVERT_TO (phdr[cnt].p_filesz, notcvt[cnt].p_filesz); + CONVERT_TO (phdr[cnt].p_memsz, notcvt[cnt].p_memsz); + CONVERT_TO (phdr[cnt].p_flags, notcvt[cnt].p_flags); + CONVERT_TO (phdr[cnt].p_align, notcvt[cnt].p_align); + } + } + } + else if (likely (elf->fildes != -1)) + { + /* Allocate memory for the program headers. We know the number + of entries from the ELF header. */ + elf->state.ELFW(elf,LIBELFBITS).phdr = + (ElfW2(LIBELFBITS,Phdr) *) malloc (size); + if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_MALLOCED; + + /* Read the header. */ + if ((size_t) pread (elf->fildes, + elf->state.ELFW(elf,LIBELFBITS).phdr, size, + (elf->start_offset + ehdr->e_phoff)) != size) + { + /* Severe problems. We cannot read the data. */ + __libelf_seterrno (ELF_E_READ_ERROR); + free (elf->state.ELFW(elf,LIBELFBITS).phdr); + elf->state.ELFW(elf,LIBELFBITS).phdr = NULL; + goto out; + } + + /* If the byte order of the file is not the same as the one + of the host convert the data now. */ + if (ehdr->e_ident[EI_DATA] != MY_ELFDATA) + { + ElfW2(LIBELFBITS,Phdr) *phdr + = elf->state.ELFW(elf,LIBELFBITS).phdr; + + for (size_t cnt = 0; cnt < phnum; ++cnt) + { + CONVERT (phdr[cnt].p_type); + CONVERT (phdr[cnt].p_offset); + CONVERT (phdr[cnt].p_vaddr); + CONVERT (phdr[cnt].p_paddr); + CONVERT (phdr[cnt].p_filesz); + CONVERT (phdr[cnt].p_memsz); + CONVERT (phdr[cnt].p_flags); + CONVERT (phdr[cnt].p_align); + } + } + } + else + { + /* The file descriptor was already enabled and not all data was + read. */ + __libelf_seterrno (ELF_E_FD_DISABLED); + goto out; + } + + result = elf->state.ELFW(elf,LIBELFBITS).phdr; + } + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elfw2(LIBELFBITS,getphdr)) diff --git a/libelf/elf32_getshdr.c b/libelf/elf32_getshdr.c new file mode 100644 index 00000000..1e26e854 --- /dev/null +++ b/libelf/elf32_getshdr.c @@ -0,0 +1,182 @@ +/* Return section header. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" +#include "common.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +ElfW2(LIBELFBITS,Shdr) * +elfw2(LIBELFBITS,getshdr) (scn) + Elf_Scn *scn; +{ + ElfW2(LIBELFBITS,Shdr) *result; + + if (scn == NULL) + return NULL; + + if (unlikely (scn->elf->state.elf.ehdr == NULL)) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + return NULL; + } + + if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS))) + { + __libelf_seterrno (ELF_E_INVALID_CLASS); + return NULL; + } + + result = scn->shdr.ELFW(e,LIBELFBITS); + if (result == NULL) + { + /* Read the section header table. */ + Elf *elf = scn->elf; + ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; + + rwlock_wrlock (elf->lock); + + /* Try again, maybe the data is there now. */ + result = scn->shdr.ELFW(e,LIBELFBITS); + if (result != NULL) + goto out; + + size_t shnum; + if (INTUSE (elf_getshnum) (elf, &shnum) != 0) + goto out; + size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr)); + + /* Allocate memory for the program headers. We know the number + of entries from the ELF header. */ + ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr = + (ElfW2(LIBELFBITS,Shdr) *) malloc (size); + if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1; + + if (elf->map_address != NULL) + { + ElfW2(LIBELFBITS,Shdr) *notcvt; + + /* All the data is already mapped. If we could use it + directly this would already have happened. */ + assert (ehdr->e_ident[EI_DATA] != MY_ELFDATA + || (! ALLOW_UNALIGNED + && (ehdr->e_shoff + & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0)); + + /* Now copy the data and at the same time convert the byte + order. */ + if (ALLOW_UNALIGNED + || (ehdr->e_shoff + & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) == 0) + notcvt = (ElfW2(LIBELFBITS,Shdr) *) + ((char *) elf->map_address + + elf->start_offset + ehdr->e_shoff); + else + { + notcvt = (ElfW2(LIBELFBITS,Shdr) *) alloca (size); + memcpy (notcvt, ((char *) elf->map_address + + elf->start_offset + ehdr->e_shoff), + size); + } + + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name); + CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type); + CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags); + CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr); + CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset); + CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size); + CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link); + CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info); + CONVERT_TO (shdr[cnt].sh_addralign, notcvt[cnt].sh_addralign); + CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize); + } + } + else if (elf->fildes != -1) + { + /* Read the header. */ + if ((size_t) pread (elf->fildes, + elf->state.ELFW(elf,LIBELFBITS).shdr, size, + elf->start_offset + ehdr->e_shoff) != size) + { + /* Severe problems. We cannot read the data. */ + __libelf_seterrno (ELF_E_READ_ERROR); + goto free_and_out; + } + + /* If the byte order of the file is not the same as the one + of the host convert the data now. */ + if (ehdr->e_ident[EI_DATA] != MY_ELFDATA) + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + CONVERT (shdr[cnt].sh_name); + CONVERT (shdr[cnt].sh_type); + CONVERT (shdr[cnt].sh_flags); + CONVERT (shdr[cnt].sh_addr); + CONVERT (shdr[cnt].sh_offset); + CONVERT (shdr[cnt].sh_size); + CONVERT (shdr[cnt].sh_link); + CONVERT (shdr[cnt].sh_info); + CONVERT (shdr[cnt].sh_addralign); + CONVERT (shdr[cnt].sh_entsize); + } + } + else + { + /* The file descriptor was already enabled and not all data was + read. Undo the allocation. */ + __libelf_seterrno (ELF_E_FD_DISABLED); + + free_and_out: + free (shdr); + elf->state.ELFW(elf,LIBELFBITS).shdr = NULL; + elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0; + + goto out; + } + + /* Set the pointers in the `scn's. */ + for (size_t cnt = 0; cnt < shnum; ++cnt) + elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS) + = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt]; + + result = scn->shdr.ELFW(e,LIBELFBITS); + assert (result != NULL); + + out: + rwlock_unlock (elf->lock); + } + + return result; +} +INTDEF(elfw2(LIBELFBITS,getshdr)) diff --git a/libelf/elf32_newehdr.c b/libelf/elf32_newehdr.c new file mode 100644 index 00000000..658ad462 --- /dev/null +++ b/libelf/elf32_newehdr.c @@ -0,0 +1,80 @@ +/* Create new ELF header. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +ElfW2(LIBELFBITS,Ehdr) * +elfw2(LIBELFBITS,newehdr) (elf) + Elf *elf; +{ + ElfW2(LIBELFBITS,Ehdr) *result; + + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_wrlock (elf->lock); + + if (elf->class == 0) + elf->class = ELFW(ELFCLASS,LIBELFBITS); + else if (unlikely (elf->class != ELFW(ELFCLASS,LIBELFBITS))) + { + __libelf_seterrno (ELF_E_INVALID_CLASS); + result = NULL; + goto out; + } + + /* Don't create an ELF header if one already exists. */ + if (elf->state.ELFW(elf,LIBELFBITS).ehdr == NULL) + { + /* We use the memory in the ELF descriptor. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr = + &elf->state.ELFW(elf,LIBELFBITS).ehdr_mem; + + /* We clear this memory. */ + memset (elf->state.ELFW(elf,LIBELFBITS).ehdr, '\0', + sizeof (ElfW2(LIBELFBITS,Ehdr))); + + /* Mark the ELF header has modified. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; + } + + result = elf->state.ELFW(elf,LIBELFBITS).ehdr; + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elfw2(LIBELFBITS,newehdr)) diff --git a/libelf/elf32_newphdr.c b/libelf/elf32_newphdr.c new file mode 100644 index 00000000..74a2387a --- /dev/null +++ b/libelf/elf32_newphdr.c @@ -0,0 +1,138 @@ +/* Create new ELF program header table. + Copyright (C) 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +ElfW2(LIBELFBITS,Phdr) * +elfw2(LIBELFBITS,newphdr) (elf, count) + Elf *elf; + size_t count; +{ + ElfW2(LIBELFBITS,Phdr) *result; + + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_wrlock (elf->lock); + + if (elf->class == 0) + elf->class = ELFW(ELFCLASS,LIBELFBITS); + else if (unlikely (elf->class != ELFW(ELFCLASS,LIBELFBITS))) + { + __libelf_seterrno (ELF_E_INVALID_CLASS); + result = NULL; + goto out; + } + + if (unlikely (elf->state.ELFW(elf,LIBELFBITS).ehdr == NULL)) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + result = NULL; + goto out; + } + + /* A COUNT of zero means remove existing table. */ + if (count == 0) + { + /* Free the old program header. */ + if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL) + { + if (elf->state.ELFW(elf,LIBELFBITS).phdr_flags & ELF_F_MALLOCED) + free (elf->state.ELFW(elf,LIBELFBITS).phdr); + + /* Set the pointer to NULL. */ + elf->state.ELFW(elf,LIBELFBITS).phdr = NULL; + /* Set the `e_phnum' member to the new value. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = 0; + /* Also set the size. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize = + sizeof (ElfW2(LIBELFBITS,Phdr)); + + elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY; + elf->flags |= ELF_F_DIRTY; + __libelf_seterrno (ELF_E_NOERROR); + } + + result = NULL; + } + else if (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum != count + || elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) + { + /* Allocate a new program header with the appropriate number of + elements. */ + result = (ElfW2(LIBELFBITS,Phdr) *) + realloc (elf->state.ELFW(elf,LIBELFBITS).phdr, + count * sizeof (ElfW2(LIBELFBITS,Phdr))); + if (result == NULL) + __libelf_seterrno (ELF_E_NOMEM); + else + { + /* Now set the result. */ + elf->state.ELFW(elf,LIBELFBITS).phdr = result; + /* Clear the whole memory. */ + memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr))); + /* Set the `e_phnum' member to the new value. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = count; + /* Also set the size. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize = + elf_typesize (LIBELFBITS, ELF_T_PHDR, 1); + /* Remember we allocated the array and mark the structure is + modified. */ + elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= + ELF_F_DIRTY | ELF_F_MALLOCED; + /* We have to rewrite the entire file if the size of the + program header is changed. */ + elf->flags |= ELF_F_DIRTY; + } + } + else + { + /* We have the same number of entries. Just clear the array. */ + assert (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize + == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1)); + + /* Mark the structure as modified. */ + elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY; + + result = elf->state.ELFW(elf,LIBELFBITS).phdr; + } + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elfw2(LIBELFBITS,newphdr)) diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c new file mode 100644 index 00000000..14893def --- /dev/null +++ b/libelf/elf32_updatefile.c @@ -0,0 +1,610 @@ +/* Write changed data structures. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "libelfP.h" + + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +static int +compare_sections (const void *a, const void *b) +{ + const Elf_Scn **scna = (const Elf_Scn **) a; + const Elf_Scn **scnb = (const Elf_Scn **) b; + + if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset + < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset) + return -1; + + if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset + > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset) + return 1; + + if ((*scna)->index < (*scnb)->index) + return -1; + + if ((*scna)->index > (*scnb)->index) + return 1; + + return 0; +} + + +/* Insert the sections in the list into the provided array and sort + them according to their start offsets. For sections with equal + start offsets the section index is used. */ +static void +sort_sections (Elf_Scn **scns, Elf_ScnList *list) +{ + Elf_Scn **scnp = scns; + do + for (size_t cnt = 0; cnt < list->cnt; ++cnt) + *scnp++ = &list->data[cnt]; + while ((list = list->next) != NULL); + + qsort (scns, scnp - scns, sizeof (*scns), compare_sections); +} + + +int +internal_function_def +__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) +{ + ElfW2(LIBELFBITS,Ehdr) *ehdr; + xfct_t fctp; + char *last_position; + + /* We need the ELF header several times. */ + ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; + + /* Write out the ELF header. */ + if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY) + { + /* If the type sizes should be different at some time we have to + rewrite this code. */ + assert (sizeof (ElfW2(LIBELFBITS,Ehdr)) + == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)); + + if (unlikely (change_bo)) + { + /* Today there is only one version of the ELF header. */ +#if EV_NUM != 2 + fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]; +#else +# undef fctp +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR] +#endif + + /* Do the real work. */ + (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr, + sizeof (ElfW2(LIBELFBITS,Ehdr)), 1); + } + else + memcpy (elf->map_address + elf->start_offset, ehdr, + sizeof (ElfW2(LIBELFBITS,Ehdr))); + + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY; + } + + /* Write out the program header table. */ + if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL + && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags) + & ELF_F_DIRTY)) + { + /* If the type sizes should be different at some time we have to + rewrite this code. */ + assert (sizeof (ElfW2(LIBELFBITS,Phdr)) + == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1)); + + /* Maybe the user wants a gap between the ELF header and the program + header. */ + if (ehdr->e_phoff > ehdr->e_ehsize) + memset (elf->map_address + elf->start_offset + ehdr->e_ehsize, + __libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize); + + if (unlikely (change_bo)) + { + /* Today there is only one version of the ELF header. */ +#if EV_NUM != 2 + fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]; +#else +# undef fctp +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR] +#endif + + /* Do the real work. */ + (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff, + elf->state.ELFW(elf,LIBELFBITS).phdr, + sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum, 1); + } + else + memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff, + elf->state.ELFW(elf,LIBELFBITS).phdr, + sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum); + + elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY; + } + + /* From now on we have to keep track of the last position to eventually + fill the gaps with the prescribed fill byte. */ + last_position = ((char *) elf->map_address + elf->start_offset + + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1), + ehdr->e_phoff) + + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum)); + + /* Write all the sections. Well, only those which are modified. */ + if (shnum > 0) + { + ElfW2(LIBELFBITS,Shdr) *shdr_dest; + Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns; + Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *)); + char *shdr_start = ((char *) elf->map_address + elf->start_offset + + ehdr->e_shoff); + char *shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize; + +#if EV_NUM != 2 + xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]; +#else +# undef shdr_fctp +# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR] +#endif + shdr_dest = (ElfW2(LIBELFBITS,Shdr) *) + ((char *) elf->map_address + elf->start_offset + ehdr->e_shoff); + + /* Get all sections into the array and sort them. */ + sort_sections (scns, list); + + /* Iterate over all the section in the order in which they + appear in the output file. */ + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + Elf_Scn *scn = scns[cnt]; + ElfW2(LIBELFBITS,Shdr) *shdr; + char *scn_start; + Elf_Data_List *dl; + + shdr = scn->shdr.ELFW(e,LIBELFBITS); + + scn_start = ((char *) elf->map_address + + elf->start_offset + shdr->sh_offset); + dl = &scn->data_list; + + if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL) + do + { + if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY) + { + if (scn_start + dl->data.d.d_off != last_position) + { + if (scn_start + dl->data.d.d_off > last_position) + { + /* This code assumes that the data blocks for + a section are ordered by offset. */ + size_t written = 0; + + if (last_position < shdr_start) + { + written = MIN (scn_start + dl->data.d.d_off + - last_position, + shdr_start - last_position); + + memset (last_position, __libelf_fill_byte, + written); + } + + if (last_position + written + != scn_start + dl->data.d.d_off + && shdr_end < scn_start + dl->data.d.d_off) + memset (shdr_end, __libelf_fill_byte, + scn_start + dl->data.d.d_off - shdr_end); + + last_position = scn_start + dl->data.d.d_off; + } + } + + if (unlikely (change_bo)) + { +#if EV_NUM != 2 + fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]; +#else +# undef fctp + fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]; +#endif + + /* Do the real work. */ + (*fctp) (last_position, dl->data.d.d_buf, + dl->data.d.d_size, 1); + + last_position += dl->data.d.d_size; + } + else + last_position = mempcpy (last_position, + dl->data.d.d_buf, + dl->data.d.d_size); + } + else + last_position += dl->data.d.d_size; + + dl->flags &= ~ELF_F_DIRTY; + + dl = dl->next; + } + while (dl != NULL); + else if (shdr->sh_type != SHT_NOBITS && scn->index != 0) + /* We have to trust the existing section header information. */ + last_position += shdr->sh_size; + + /* Write the section header table entry if necessary. */ + if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY) + { + if (unlikely (change_bo)) + (*shdr_fctp) (&shdr_dest[scn->index], + scn->shdr.ELFW(e,LIBELFBITS), + sizeof (ElfW2(LIBELFBITS,Shdr)), 1); + else + memcpy (&shdr_dest[scn->index], + scn->shdr.ELFW(e,LIBELFBITS), + sizeof (ElfW2(LIBELFBITS,Shdr))); + + scn->shdr_flags &= ~ELF_F_DIRTY; + } + + scn->flags &= ~ELF_F_DIRTY; + } + + /* Fill the gap between last section and section header table if + necessary. */ + if ((elf->flags & ELF_F_DIRTY) + && last_position < ((char *) elf->map_address + elf->start_offset + + ehdr->e_shoff)) + memset (last_position, __libelf_fill_byte, + (char *) elf->map_address + elf->start_offset + ehdr->e_shoff + - last_position); + } + + /* That was the last part. Clear the overall flag. */ + elf->flags &= ~ELF_F_DIRTY; + + return 0; +} + + +/* Size of the buffer we use to generate the blocks of fill bytes. */ +#define FILLBUFSIZE 4096 + +/* If we have to convert the section buffer contents we have to use + temporary buffer. Only buffers up to MAX_TMPBUF bytes are allocated + on the stack. */ +#define MAX_TMPBUF 32768 + + +/* Helper function to write out fill bytes. */ +static int +fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp) +{ + size_t filled = *filledp; + size_t fill_len = MIN (len, FILLBUFSIZE); + + if (unlikely (fill_len > filled) && filled < FILLBUFSIZE) + { + /* Initialize a few more bytes. */ + memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled); + *filledp = filled = fill_len; + } + + do + { + /* This many bytes we want to write in this round. */ + size_t n = MIN (filled, len); + + if (unlikely ((size_t) pwrite (fd, fillbuf, n, pos) != n)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + return 1; + } + + pos += n; + len -= n; + } + while (len > 0); + + return 0; +} + + +int +internal_function_def +__elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) +{ + char fillbuf[FILLBUFSIZE]; + size_t filled = 0; + xfct_t fctp; + + /* We need the ELF header several times. */ + ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; + + /* Write out the ELF header. */ + if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY) + { + ElfW2(LIBELFBITS,Ehdr) tmp_ehdr; + ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr; + + /* If the type sizes should be different at some time we have to + rewrite this code. */ + assert (sizeof (ElfW2(LIBELFBITS,Ehdr)) + == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)); + + if (unlikely (change_bo)) + { + /* Today there is only one version of the ELF header. */ +#if EV_NUM != 2 + fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]; +#else +# undef fctp +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR] +#endif + + /* Write the converted ELF header in a temporary buffer. */ + (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1); + + /* This is the buffer we want to write. */ + out_ehdr = &tmp_ehdr; + } + + /* Write out the ELF header. */ + if (unlikely (pwrite (elf->fildes, out_ehdr, + sizeof (ElfW2(LIBELFBITS,Ehdr)), 0) + != sizeof (ElfW2(LIBELFBITS,Ehdr)))) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + return 1; + } + + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY; + } + + /* If the type sizes should be different at some time we have to + rewrite this code. */ + assert (sizeof (ElfW2(LIBELFBITS,Phdr)) + == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1)); + + /* Write out the program header table. */ + if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL + && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags) + & ELF_F_DIRTY)) + { + ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL; + ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr; + + /* Maybe the user wants a gap between the ELF header and the program + header. */ + if (ehdr->e_phoff > ehdr->e_ehsize + && unlikely (fill (elf->fildes, ehdr->e_ehsize, + ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled) + != 0)) + return 1; + + if (unlikely (change_bo)) + { + /* Today there is only one version of the ELF header. */ +#if EV_NUM != 2 + fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]; +#else +# undef fctp +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR] +#endif + + /* Allocate sufficient memory. */ + tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *) + malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum); + if (tmp_phdr == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return 1; + } + + /* Write the converted ELF header in a temporary buffer. */ + (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr, + sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum, 1); + + /* This is the buffer we want to write. */ + out_phdr = tmp_phdr; + } + + /* Write out the ELF header. */ + if (unlikely ((size_t) pwrite (elf->fildes, out_phdr, + sizeof (ElfW2(LIBELFBITS,Phdr)) + * ehdr->e_phnum, ehdr->e_phoff) + != sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + return 1; + } + + /* This is a no-op we we have not allocated any memory. */ + free (tmp_phdr); + + elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY; + } + + /* From now on we have to keep track of the last position to eventually + fill the gaps with the prescribed fill byte. */ + off_t last_offset; + if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) + last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); + else + last_offset = (ehdr->e_phoff + + sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum); + + /* Write all the sections. Well, only those which are modified. */ + if (shnum > 0) + { + off_t shdr_offset = elf->start_offset + ehdr->e_shoff; +#if EV_NUM != 2 + xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]; +#else +# undef shdr_fctp +# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR] +#endif + + ElfW2(LIBELFBITS,Shdr) *shdr_data; + if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL) + shdr_data = (ElfW2(LIBELFBITS,Shdr) *) + alloca (shnum * sizeof (ElfW2(LIBELFBITS,Shdr))); + else + shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr; + int shdr_flags = elf->flags; + + /* Get all sections into the array and sort them. */ + Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns; + Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *)); + sort_sections (scns, list); + + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + Elf_Scn *scn = scns[cnt]; + + ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS); + + off_t scn_start = elf->start_offset + shdr->sh_offset; + Elf_Data_List *dl = &scn->data_list; + + if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL + && scn->index != 0) + do + { + if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY) + { + char tmpbuf[MAX_TMPBUF]; + void *buf = dl->data.d.d_buf; + + if (scn_start + dl->data.d.d_off != last_offset) + { + assert (last_offset < scn_start + dl->data.d.d_off); + + if (unlikely (fill (elf->fildes, last_offset, + (scn_start + dl->data.d.d_off) + - last_offset, fillbuf, + &filled) != 0)) + return 1; + + last_offset = scn_start + dl->data.d.d_off; + } + + if (unlikely (change_bo)) + { +#if EV_NUM != 2 + fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]; +#else +# undef fctp + fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]; +#endif + + buf = tmpbuf; + if (dl->data.d.d_size > MAX_TMPBUF) + { + buf = malloc (dl->data.d.d_size); + if (buf == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return 1; + } + } + + /* Do the real work. */ + (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1); + } + + if (unlikely ((size_t) pwrite (elf->fildes, buf, + dl->data.d.d_size, + last_offset) + != dl->data.d.d_size)) + { + if (buf != dl->data.d.d_buf && buf != tmpbuf) + free (buf); + + __libelf_seterrno (ELF_E_WRITE_ERROR); + return 1; + } + + if (buf != dl->data.d.d_buf && buf != tmpbuf) + free (buf); + } + + last_offset += dl->data.d.d_size; + + dl->flags &= ~ELF_F_DIRTY; + + dl = dl->next; + } + while (dl != NULL); + else if (shdr->sh_type != SHT_NOBITS && scn->index != 0) + last_offset = scn_start + shdr->sh_size; + + /* Collect the section header table information. */ + if (unlikely (change_bo)) + (*shdr_fctp) (&shdr_data[scn->index], + scn->shdr.ELFW(e,LIBELFBITS), + sizeof (ElfW2(LIBELFBITS,Shdr)), 1); + else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL) + memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS), + sizeof (ElfW2(LIBELFBITS,Shdr))); + + shdr_flags |= scn->shdr_flags; + scn->shdr_flags &= ~ELF_F_DIRTY; + } + + /* Fill the gap between last section and section header table if + necessary. */ + if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset + && unlikely (fill (elf->fildes, last_offset, + shdr_offset - last_offset, + fillbuf, &filled) != 0)) + return 1; + + /* Write out the section header table. */ + if (shdr_flags & ELF_F_DIRTY + && unlikely ((size_t) pwrite (elf->fildes, shdr_data, + sizeof (ElfW2(LIBELFBITS,Shdr)) + * shnum, shdr_offset) + != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + return 1; + } + } + + /* That was the last part. Clear the overall flag. */ + elf->flags &= ~ELF_F_DIRTY; + + return 0; +} diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c new file mode 100644 index 00000000..ed7242b2 --- /dev/null +++ b/libelf/elf32_updatenull.c @@ -0,0 +1,384 @@ +/* Update data structures for changes. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include "libelfP.h" +#include "elf-knowledge.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + + +static int +ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr, + size_t shnum, int *change_bop) +{ + /* Always write the magic bytes. */ + if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0) + { + memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG); + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; + } + + /* Always set the file class. */ + update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS), + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); + + /* Set the data encoding if necessary. */ + if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE)) + { + ehdr->e_ident[EI_DATA] = + BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB; + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; + } + else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM)) + { + __libelf_seterrno (ELF_E_DATA_ENCODING); + return 1; + } + else + *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN + && ehdr->e_ident[EI_DATA] != ELFDATA2LSB) + || (BYTE_ORDER == BIG_ENDIAN + && ehdr->e_ident[EI_DATA] != ELFDATA2MSB)); + + /* Unconditionally overwrite the ELF version. */ + update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT, + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); + + if (unlikely (ehdr->e_version == EV_NONE) + || unlikely (ehdr->e_version >= EV_NUM)) + { + __libelf_seterrno (ELF_E_UNKNOWN_VERSION); + return 1; + } + + if (unlikely (shnum >= SHN_LORESERVE)) + { + update_if_changed (ehdr->e_shnum, 0, + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); + } + else + update_if_changed (ehdr->e_shnum, shnum, + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); + + if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1))) + { + ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; + } + + return 0; +} + + +off_t +internal_function_def +__elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum) +{ + ElfW2(LIBELFBITS,Ehdr) *ehdr = INTUSE(elfw2(LIBELFBITS,getehdr)) (elf); + int changed = 0; + int ehdr_flags = 0; + + /* Set the default values. */ + if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0) + return -1; + + /* At least the ELF header is there. */ + off_t size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); + + /* Set the program header position. */ + if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL + && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)) + (void) INTUSE(elfw2(LIBELFBITS,getphdr)) (elf); + if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL) + { + /* Only executables or shared objects have a program header. */ + if (ehdr->e_type != ET_EXEC && unlikely (ehdr->e_type != ET_DYN)) + { + __libelf_seterrno (ELF_E_INVALID_PHDR); + return -1; + } + + if (elf->flags & ELF_F_LAYOUT) + { + /* The user is supposed to fill out e_phoff. Use it and + e_phnum to determine the maximum extend. */ + size = MAX ((size_t) size, + ehdr->e_phoff + + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum)); + } + else + { + update_if_changed (ehdr->e_phoff, + elf_typesize (LIBELFBITS, ELF_T_EHDR, 1), + ehdr_flags); + + /* We need no alignment here. */ + size += elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum); + } + } + + if (shnum > 0) + { + Elf_ScnList *list; + bool first = true; + + assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0); + + if (shnum >= SHN_LORESERVE) + { + /* We have to fill in the number of sections in the header + of the zeroth section. */ + Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0]; + + update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size, + shnum, scn0->shdr_flags); + } + + /* Go over all sections and find out how large they are. */ + list = &elf->state.ELFW(elf,LIBELFBITS).scns; + + /* Load the section headers if necessary. This loads the + headers for all sections. */ + if (list->data[1].shdr.ELFW(e,LIBELFBITS) == NULL) + (void) INTUSE(elfw2(LIBELFBITS,getshdr)) (&list->data[1]); + + do + { + for (size_t cnt = first == true; cnt < list->cnt; ++cnt) + { + Elf_Scn *scn = &list->data[cnt]; + ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS); + off_t offset = 0; + + assert (shdr != NULL); + ElfW2(LIBELFBITS,Word) sh_entsize = shdr->sh_entsize; + ElfW2(LIBELFBITS,Word) sh_align = shdr->sh_addralign ?: 1; + + /* Set the sh_entsize value if we can reliably detect it. */ + switch (shdr->sh_type) + { + case SHT_SYMTAB: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1); + break; + case SHT_RELA: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1); + break; + case SHT_GROUP: + /* Only relocatable files can contain section groups. */ + if (ehdr->e_type != ET_REL) + { + __libelf_seterrno (ELF_E_GROUP_NOT_REL); + return -1; + } + /* FALLTHROUGH */ + case SHT_SYMTAB_SHNDX: + sh_entsize = elf_typesize (32, ELF_T_WORD, 1); + break; + case SHT_HASH: + sh_entsize = SH_ENTSIZE_HASH (ehdr); + break; + case SHT_DYNAMIC: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1); + break; + case SHT_REL: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1); + break; + case SHT_DYNSYM: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1); + break; + case SHT_SUNW_move: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1); + break; + case SHT_SUNW_syminfo: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1); + break; + default: + break; + } + + /* If the section header contained the wrong entry size + correct it and mark the header as modified. */ + update_if_changed (shdr->sh_entsize, sh_entsize, + scn->shdr_flags); + + if (scn->data_read == 0 && __libelf_set_rawdata (scn) != 0) + /* Something went wrong. The error value is already set. */ + return -1; + + /* Iterate over all data blocks. */ + if (list->data[cnt].data_list_rear != NULL) + { + Elf_Data_List *dl = &scn->data_list; + + while (dl != NULL) + { + Elf_Data *data = &dl->data.d; + if (dl == &scn->data_list && data->d_buf == NULL + && scn->rawdata.d.d_buf != NULL) + data = &scn->rawdata.d; + + if (unlikely (data->d_version == EV_NONE) + || unlikely (data->d_version >= EV_NUM)) + { + __libelf_seterrno (ELF_E_UNKNOWN_VERSION); + return -1; + } + + if (unlikely (! powerof2 (data->d_align))) + { + __libelf_seterrno (ELF_E_INVALID_ALIGN); + return -1; + } + + sh_align = MAX (sh_align, data->d_align); + + if (elf->flags & ELF_F_LAYOUT) + { + /* The user specified the offset and the size. + All we have to do is check whether this block + fits in the size specified for the section. */ + if (unlikely ((GElf_Word) (data->d_off + + data->d_size) + > shdr->sh_size)) + { + __libelf_seterrno (ELF_E_SECTION_TOO_SMALL); + return -1; + } + } + else + { + /* Determine the padding. */ + offset = ((offset + data->d_align - 1) + & ~(data->d_align - 1)); + + update_if_changed (data->d_off, offset, changed); + + offset += data->d_size; + } + + /* Next data block. */ + dl = dl->next; + } + } + else + /* Get the size of the section from the raw data. If + none is available the value is zero. */ + offset += scn->rawdata.d.d_size; + + if (elf->flags & ELF_F_LAYOUT) + { + size = MAX ((GElf_Word) size, + shdr->sh_offset + + (shdr->sh_type != SHT_NOBITS + ? shdr->sh_size : 0)); + + /* The alignment must be a power of two. This is a + requirement from the ELF specification. Additionally + we test for the alignment of the section being large + enough for the largest alignment required by a data + block. */ + if (unlikely (! powerof2 (shdr->sh_addralign)) + || unlikely (shdr->sh_addralign < sh_align)) + { + __libelf_seterrno (ELF_E_INVALID_ALIGN); + return -1; + } + } + else + { + /* How much alignment do we need for this section. */ + update_if_changed (shdr->sh_addralign, sh_align, + scn->shdr_flags); + + size = (size + sh_align - 1) & ~(sh_align - 1); + update_if_changed (shdr->sh_offset, (GElf_Word) size, + changed); + + /* See whether the section size is correct. */ + update_if_changed (shdr->sh_size, (GElf_Word) offset, + changed); + + if (shdr->sh_type != SHT_NOBITS) + size += offset; + + scn->flags |= changed; + } + + /* Check that the section size is actually a multiple of + the entry size. */ + if (shdr->sh_entsize != 0 + && unlikely (shdr->sh_size % shdr->sh_entsize != 0) + && (elf->flags & ELF_F_PERMISSIVE) == 0) + { + __libelf_seterrno (ELF_E_INVALID_SHENTSIZE); + return -1; + } + } + + assert (list->next == NULL || list->cnt == list->max); + + first = false; + } + while ((list = list->next) != NULL); + + /* Store section information. */ + if (elf->flags & ELF_F_LAYOUT) + { + /* The user is supposed to fill out e_phoff. Use it and + e_phnum to determine the maximum extend. */ + size = MAX ((GElf_Word) size, + (ehdr->e_shoff + + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum)))); + } + else + { + /* Align for section header table. + + Yes, we use `sizeof' and not `__alignof__' since we do not + want to be surprised by architectures with less strict + alignment rules. */ +#define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off)) + size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1); + + update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags); + update_if_changed (ehdr->e_shentsize, + elf_typesize (LIBELFBITS, ELF_T_SHDR, 1), + ehdr_flags); + + /* Account for the section header size. */ + size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum); + } + } + + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags; + + return size; +} diff --git a/libelf/elf32_xlatetof.c b/libelf/elf32_xlatetof.c new file mode 100644 index 00000000..46b65880 --- /dev/null +++ b/libelf/elf32_xlatetof.c @@ -0,0 +1,111 @@ +/* Convert from memory to file representation. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +Elf_Data * +elfw2(LIBELFBITS, xlatetof) (dest, src, encode) + Elf_Data *dest; + const Elf_Data *src; + unsigned int encode; +{ + /* First test whether the input data is really suitable for this + type. This means, whether there is an integer number of records. + Note that for this implementation the memory and file size of the + data types are identical. */ +#if EV_NUM != 2 + size_t recsize = __libelf_type_sizes[src->d_version - 1][ELFW(ELFCLASS,LIBELFBITS) - 1][src->d_type]; +#else + size_t recsize = __libelf_type_sizes[0][ELFW(ELFCLASS,LIBELFBITS) - 1][src->d_type]; +#endif + + if (src->d_size % recsize != 0) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + return NULL; + } + + /* Next see whether the converted data fits in the output buffer. */ + if (src->d_size > dest->d_size) + { + __libelf_seterrno (ELF_E_DEST_SIZE); + return NULL; + } + + /* Test the encode parameter. */ + if (encode != ELFDATA2LSB && encode != ELFDATA2MSB) + { + __libelf_seterrno (ELF_E_INVALID_ENCODING); + return NULL; + } + + /* Determine the translation function to use. + + At this point we make an assumption which is valid for all + existing implementations so far: the memory and file sizes are + the same. This has very important consequences: + a) The requirement that the source and destination buffer can + overlap can easily be fulfilled. + b) We need only one function to convert from and memory to file + and vice versa since the function only has to copy and/or + change the byte order. + */ + if ((__BYTE_ORDER == __LITTLE_ENDIAN && encode == ELFDATA2LSB) + || (__BYTE_ORDER == __BIG_ENDIAN && encode == ELFDATA2MSB)) + { + /* We simply have to copy since the byte order is the same. */ + if (src->d_buf != dest->d_buf) + memmove (dest->d_buf, src->d_buf, src->d_size); + } + else + { + xfct_t fctp; + + /* Get a pointer to the transformation functions. The `#ifdef' is + a small optimization since we don't anticipate another ELF + version and so would waste "precious" code. */ +#if EV_NUM != 2 + fctp = __elf_xfctstom[dest->d_version - 1][src->d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][src->d_type]; +#else + fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][src->d_type]; +#endif + + /* Do the real work. */ + (*fctp) (dest->d_buf, src->d_buf, src->d_size, 1); + } + + /* Now set the real destination type and length since the operation was + successful. */ + dest->d_type = src->d_type; + dest->d_size = src->d_size; + + return dest; +} +INTDEF(elfw2(LIBELFBITS, xlatetof)) diff --git a/libelf/elf32_xlatetom.c b/libelf/elf32_xlatetom.c new file mode 100644 index 00000000..1b8c65c7 --- /dev/null +++ b/libelf/elf32_xlatetom.c @@ -0,0 +1,112 @@ +/* Convert from file to memory representation. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +Elf_Data * +elfw2(LIBELFBITS, xlatetom) (dest, src, encode) + Elf_Data *dest; + const Elf_Data *src; + unsigned int encode; +{ + /* First test whether the input data is really suitable for this + type. This means, whether there is an integer number of records. + Note that for this implementation the memory and file size of the + data types are identical. */ +#if EV_NUM != 2 + size_t recsize = __libelf_type_sizes[src->d_version - 1][ELFW(ELFCLASS,LIBELFBITS) - 1][src->d_type]; +#else + size_t recsize = __libelf_type_sizes[0][ELFW(ELFCLASS,LIBELFBITS) - 1][src->d_type]; +#endif + + + if (src->d_size % recsize != 0) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + return NULL; + } + + /* Next see whether the converted data fits in the output buffer. */ + if (src->d_size > dest->d_size) + { + __libelf_seterrno (ELF_E_DEST_SIZE); + return NULL; + } + + /* Test the encode parameter. */ + if (encode != ELFDATA2LSB && encode != ELFDATA2MSB) + { + __libelf_seterrno (ELF_E_INVALID_ENCODING); + return NULL; + } + + /* Determine the translation function to use. + + At this point we make an assumption which is valid for all + existing implementations so far: the memory and file sizes are + the same. This has very important consequences: + a) The requirement that the source and destination buffer can + overlap can easily be fulfilled. + b) We need only one function to convert from and memory to file + and vice versa since the function only has to copy and/or + change the byte order. + */ + if ((BYTE_ORDER == LITTLE_ENDIAN && encode == ELFDATA2LSB) + || (BYTE_ORDER == BIG_ENDIAN && encode == ELFDATA2MSB)) + { + /* We simply have to copy since the byte order is the same. */ + if (src->d_buf != dest->d_buf) + memmove (dest->d_buf, src->d_buf, src->d_size); + } + else + { + xfct_t fctp; + + /* Get a pointer to the transformation functions. The `#ifdef' is + a small optimization since we don't anticipate another ELF + version and so would waste "precious" code. */ +#if EV_NUM != 2 + fctp = __elf_xfctstom[src->d_version - 1][dest->d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][src->d_type]; +#else + fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][src->d_type]; +#endif + + /* Do the real work. */ + (*fctp) (dest->d_buf, src->d_buf, src->d_size, 0); + } + + /* Now set the real destination type and length since the operation was + successful. */ + dest->d_type = src->d_type; + dest->d_size = src->d_size; + + return dest; +} +INTDEF(elfw2(LIBELFBITS, xlatetom)) diff --git a/libelf/elf64_checksum.c b/libelf/elf64_checksum.c new file mode 100644 index 00000000..bdb9210c --- /dev/null +++ b/libelf/elf64_checksum.c @@ -0,0 +1,19 @@ +/* Compute simple checksum from permanent parts of the ELF file. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define LIBELFBITS 64 +#include "elf32_checksum.c" diff --git a/libelf/elf64_fsize.c b/libelf/elf64_fsize.c new file mode 100644 index 00000000..0b1f414b --- /dev/null +++ b/libelf/elf64_fsize.c @@ -0,0 +1,19 @@ +/* Return the size of an object file type. + Copyright (C) 1998, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define LIBELFBITS 64 +#include "elf32_fsize.c" diff --git a/libelf/elf64_getehdr.c b/libelf/elf64_getehdr.c new file mode 100644 index 00000000..89a69fff --- /dev/null +++ b/libelf/elf64_getehdr.c @@ -0,0 +1,19 @@ +/* Return program header table. + Copyright (C) 1998, 1999, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define LIBELFBITS 64 +#include "elf32_getehdr.c" diff --git a/libelf/elf64_getphdr.c b/libelf/elf64_getphdr.c new file mode 100644 index 00000000..d06d7c10 --- /dev/null +++ b/libelf/elf64_getphdr.c @@ -0,0 +1,19 @@ +/* Return program header table. + Copyright (C) 1998, 1999, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define LIBELFBITS 64 +#include "elf32_getphdr.c" diff --git a/libelf/elf64_getshdr.c b/libelf/elf64_getshdr.c new file mode 100644 index 00000000..1a5da574 --- /dev/null +++ b/libelf/elf64_getshdr.c @@ -0,0 +1,19 @@ +/* Return section header. + Copyright (C) 1998, 1999, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define LIBELFBITS 64 +#include "elf32_getshdr.c" diff --git a/libelf/elf64_newehdr.c b/libelf/elf64_newehdr.c new file mode 100644 index 00000000..aba6e630 --- /dev/null +++ b/libelf/elf64_newehdr.c @@ -0,0 +1,19 @@ +/* Create new program header table. + Copyright (C) 1999, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define LIBELFBITS 64 +#include "elf32_newehdr.c" diff --git a/libelf/elf64_newphdr.c b/libelf/elf64_newphdr.c new file mode 100644 index 00000000..90ff4632 --- /dev/null +++ b/libelf/elf64_newphdr.c @@ -0,0 +1,19 @@ +/* Create new program header table. + Copyright (C) 1999, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define LIBELFBITS 64 +#include "elf32_newphdr.c" diff --git a/libelf/elf64_updatefile.c b/libelf/elf64_updatefile.c new file mode 100644 index 00000000..6b604f10 --- /dev/null +++ b/libelf/elf64_updatefile.c @@ -0,0 +1,18 @@ +/* Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define LIBELFBITS 64 +#include "elf32_updatefile.c" diff --git a/libelf/elf64_updatenull.c b/libelf/elf64_updatenull.c new file mode 100644 index 00000000..ff1f0708 --- /dev/null +++ b/libelf/elf64_updatenull.c @@ -0,0 +1,18 @@ +/* Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define LIBELFBITS 64 +#include "elf32_updatenull.c" diff --git a/libelf/elf64_xlatetof.c b/libelf/elf64_xlatetof.c new file mode 100644 index 00000000..3440bbc6 --- /dev/null +++ b/libelf/elf64_xlatetof.c @@ -0,0 +1,19 @@ +/* Convert from memory to file representation. + Copyright (C) 1998, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define LIBELFBITS 64 +#include "elf32_xlatetof.c" diff --git a/libelf/elf64_xlatetom.c b/libelf/elf64_xlatetom.c new file mode 100644 index 00000000..773f04ee --- /dev/null +++ b/libelf/elf64_xlatetom.c @@ -0,0 +1,19 @@ +/* Convert from file to memory representation. + Copyright (C) 1998, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define LIBELFBITS 64 +#include "elf32_xlatetom.c" diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c new file mode 100644 index 00000000..404cbe83 --- /dev/null +++ b/libelf/elf_begin.c @@ -0,0 +1,1073 @@ +/* Create descriptor for processing file. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libelfP.h" +#include "common.h" + + +/* Create descriptor for archive in memory. */ +static inline Elf * +file_read_ar (int fildes, void *map_address, off_t offset, size_t maxsize, + Elf_Cmd cmd, Elf *parent) +{ + Elf *elf; + + /* Create a descriptor. */ + elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, + ELF_K_AR, 0); + if (elf != NULL) + { + /* We don't read all the symbol tables in advance. All this will + happen on demand. */ + elf->state.ar.offset = offset + SARMAG; + + elf->state.ar.elf_ar_hdr.ar_rawname = elf->state.ar.raw_name; + } + + return elf; +} + + +static size_t +get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset, + size_t maxsize) +{ + size_t result; + union + { + Elf32_Ehdr *e32; + Elf64_Ehdr *e64; + void *p; + } ehdr; + bool is32 = e_ident[EI_CLASS] == ELFCLASS32; + + /* Make the ELF header available. */ + if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((size_t) ((char *) map_address + offset)) + & ((is32 ? __alignof__ (Elf32_Ehdr) : __alignof__ (Elf64_Ehdr)) + - 1)) == 0)) + ehdr.p = (char *) map_address + offset; + else + { + /* We have to read the data from the file. */ + size_t len = is32 ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr); + + ehdr.p = alloca (len); + /* Fill it. */ + if ((size_t) pread (fildes, ehdr.p, len, offset) != len) + /* Failed reading. */ + return (size_t) -1l; + + if (e_ident[EI_DATA] != MY_ELFDATA) + { + if (is32) + { + CONVERT (ehdr.e32->e_shnum); + CONVERT (ehdr.e32->e_shoff); + } + else + { + CONVERT (ehdr.e64->e_shnum); + CONVERT (ehdr.e64->e_shoff); + } + } + } + + if (is32) + { + /* Get the number of sections from the ELF header. */ + result = ehdr.e32->e_shnum; + + if (unlikely (result == 0) && ehdr.e32->e_shoff != 0) + { + if (offset + ehdr.e32->e_shoff + sizeof (Elf32_Shdr) > maxsize) + /* Cannot read the first section header. */ + return (size_t) -1l; + + if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((size_t) ((char *) map_address + offset)) + & (__alignof__ (Elf32_Ehdr) - 1)) == 0)) + /* We can directly access the memory. */ + result = ((Elf32_Shdr *) ((char *) map_address + + ehdr.e32->e_shoff + + offset))->sh_size; + else + { + Elf32_Word size; + + if (pread (fildes, &size, sizeof (Elf32_Word), + offset + ehdr.e32->e_shoff + + offsetof (Elf32_Shdr, sh_size)) + != sizeof (Elf32_Word)) + return (size_t) -1l; + + if (e_ident[EI_DATA] != MY_ELFDATA) + CONVERT (size); + + result = size; + } + } + } + else + { + /* Get the number of sections from the ELF header. */ + result = ehdr.e64->e_shnum; + + if (unlikely (result == 0) && ehdr.e64->e_shoff != 0) + { + if (offset + ehdr.e64->e_shoff + sizeof (Elf64_Shdr) > maxsize) + /* Cannot read the first section header. */ + return (size_t) -1l; + + if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((size_t) ((char *) map_address + offset)) + & (__alignof__ (Elf64_Ehdr) - 1)) == 0)) + /* We can directly access the memory. */ + result = ((Elf64_Shdr *) ((char *) map_address + + ehdr.e64->e_shoff + + offset))->sh_size; + else + { + Elf64_Word size; + + if (pread (fildes, &size, sizeof (Elf64_Word), + offset + ehdr.e64->e_shoff + + offsetof (Elf64_Shdr, sh_size)) + != sizeof (Elf64_Word)) + return (size_t) -1l; + + if (e_ident[EI_DATA] != MY_ELFDATA) + CONVERT (size); + + result = size; + } + } + } + + return result; +} + + +/* Create descriptor for ELF file in memory. */ +static Elf * +file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize, + Elf_Cmd cmd, Elf *parent) +{ + /* We only read the ELF header now. */ + unsigned char *e_ident; + size_t scncnt; + Elf *elf; + + if (map_address != NULL) + /* It's right at the beginning of the file. No word access + required, just bytes. */ + e_ident = (unsigned char *) map_address + offset; + else + { + e_ident = (unsigned char *) alloca (EI_NIDENT); + + if (pread (fildes, e_ident, EI_NIDENT, offset) != EI_NIDENT) + { + __libelf_seterrno (ELF_E_READ_ERROR); + return NULL; + } + } + + /* Verify the binary is of the class we can handle. */ + if ((e_ident[EI_CLASS] != ELFCLASS32 + && e_ident[EI_CLASS] != ELFCLASS64) + /* We also can only handle two encodings. */ + || (e_ident[EI_DATA] != ELFDATA2LSB + && e_ident[EI_DATA] != ELFDATA2MSB)) + { + /* Cannot handle this. */ + __libelf_seterrno (ELF_E_INVALID_FILE); + return NULL; + } + + /* Determine the number of sections. */ + scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize); + if (scncnt == (size_t) -1l) + /* Could not determine the number of sections. */ + return NULL; + + /* We can now allocate the memory. */ + elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, + ELF_K_ELF, scncnt * sizeof (Elf_Scn)); + if (elf == NULL) + /* Not enough memory. */ + return NULL; + + /* Some more or less arbitrary value. */ + elf->state.elf.scnincr = 10; + + if (e_ident[EI_CLASS] == ELFCLASS32) + { + /* This pointer might not be directly usable if the alignment is + not sufficient for the architecture. */ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ((char *) map_address + offset); + + assert ((unsigned int) scncnt == scncnt); + elf->state.elf32.scns.cnt = elf->state.elf32.scns.max = scncnt; + + /* This is a 32-bit binary. */ + if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || ((((uintptr_t) ehdr) & (__alignof__ (Elf32_Ehdr) - 1)) == 0 + && ((uintptr_t) ((char *) ehdr + ehdr->e_shoff) + & (__alignof__ (Elf32_Shdr) - 1)) == 0 + && ((uintptr_t) ((char *) ehdr + ehdr->e_phoff) + & (__alignof__ (Elf32_Phdr) - 1)) == 0))) + { + /* We can use the mmapped memory. */ + elf->state.elf32.ehdr = + (Elf32_Ehdr *) ((char *) map_address + offset); + elf->state.elf32.shdr = + (Elf32_Shdr *) ((char *) map_address + offset + + elf->state.elf32.ehdr->e_shoff); + if (elf->state.elf32.ehdr->e_phnum) + /* Assign a value only if there really is a program + header. Otherwise the value remains NULL. */ + elf->state.elf32.phdr + = (Elf32_Phdr *) ((char *) map_address + offset + + elf->state.elf32.ehdr->e_phoff); + + for (size_t cnt = 0; cnt < scncnt; ++cnt) + { + elf->state.elf32.scns.data[cnt].index = cnt; + elf->state.elf32.scns.data[cnt].elf = elf; + elf->state.elf32.scns.data[cnt].shdr.e32 = + &elf->state.elf32.shdr[cnt]; + elf->state.elf32.scns.data[cnt].rawdata_base = + elf->state.elf32.scns.data[cnt].data_base = + ((char *) map_address + offset + + elf->state.elf32.shdr[cnt].sh_offset); + elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns; + } + } + else + { + /* Read the data. */ + if (pread (elf->fildes, &elf->state.elf32.ehdr_mem, + sizeof (Elf32_Ehdr), offset) != sizeof (Elf32_Ehdr)) + { + /* We must be able to read the ELF header. */ + __libelf_seterrno (ELF_E_INVALID_FILE); + return NULL; + } + + if (e_ident[EI_DATA] != MY_ELFDATA) + { + CONVERT (elf->state.elf32.ehdr_mem.e_type); + CONVERT (elf->state.elf32.ehdr_mem.e_machine); + CONVERT (elf->state.elf32.ehdr_mem.e_version); + CONVERT (elf->state.elf32.ehdr_mem.e_entry); + CONVERT (elf->state.elf32.ehdr_mem.e_phoff); + CONVERT (elf->state.elf32.ehdr_mem.e_shoff); + CONVERT (elf->state.elf32.ehdr_mem.e_flags); + CONVERT (elf->state.elf32.ehdr_mem.e_ehsize); + CONVERT (elf->state.elf32.ehdr_mem.e_phentsize); + CONVERT (elf->state.elf32.ehdr_mem.e_phnum); + CONVERT (elf->state.elf32.ehdr_mem.e_shentsize); + CONVERT (elf->state.elf32.ehdr_mem.e_shnum); + CONVERT (elf->state.elf32.ehdr_mem.e_shstrndx); + } + + elf->state.elf32.ehdr = &elf->state.elf32.ehdr_mem; + + for (size_t cnt = 0; cnt < scncnt; ++cnt) + { + elf->state.elf32.scns.data[cnt].index = cnt; + elf->state.elf32.scns.data[cnt].elf = elf; + elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns; + } + } + + /* So far only one block with sections. */ + elf->state.elf32.scns_last = &elf->state.elf32.scns; + } + else + { + /* This pointer might not be directly usable if the alignment is + not sufficient for the architecture. */ + Elf64_Ehdr *ehdr = (Elf64_Ehdr *) ((char *) map_address + offset); + + assert ((unsigned int) scncnt == scncnt); + elf->state.elf64.scns.cnt = elf->state.elf64.scns.max = scncnt; + + /* This is a 64-bit binary. */ + if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || ((((uintptr_t) ehdr) & (__alignof__ (Elf64_Ehdr) - 1)) == 0 + && ((uintptr_t) ((char *) ehdr + ehdr->e_shoff) + & (__alignof__ (Elf64_Shdr) - 1)) == 0 + && ((uintptr_t) ((char *) ehdr + ehdr->e_phoff) + & (__alignof__ (Elf64_Phdr) - 1)) == 0))) + { + /* We can use the mmapped memory. */ + elf->state.elf64.ehdr = + (Elf64_Ehdr *) ((char *) map_address + offset); + elf->state.elf64.shdr = + (Elf64_Shdr *) ((char *) map_address + offset + + elf->state.elf64.ehdr->e_shoff); + if (elf->state.elf64.ehdr->e_phnum) + /* Assign a value only if there really is a program + header. Otherwise the value remains NULL. */ + elf->state.elf64.phdr + = (Elf64_Phdr *) ((char *) map_address + offset + + elf->state.elf64.ehdr->e_phoff); + + for (size_t cnt = 0; cnt < scncnt; ++cnt) + { + elf->state.elf64.scns.data[cnt].index = cnt; + elf->state.elf64.scns.data[cnt].elf = elf; + elf->state.elf64.scns.data[cnt].shdr.e64 = + &elf->state.elf64.shdr[cnt]; + elf->state.elf64.scns.data[cnt].rawdata_base = + elf->state.elf64.scns.data[cnt].data_base = + ((char *) map_address + offset + + elf->state.elf64.shdr[cnt].sh_offset); + elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns; + } + } + else + { + /* Read the data. */ + if (pread (elf->fildes, &elf->state.elf64.ehdr_mem, + sizeof (Elf64_Ehdr), offset) != sizeof (Elf64_Ehdr)) + { + /* We must be able to read the ELF header. */ + __libelf_seterrno (ELF_E_INVALID_FILE); + return NULL; + } + + if (e_ident[EI_DATA] != MY_ELFDATA) + { + CONVERT (elf->state.elf64.ehdr_mem.e_type); + CONVERT (elf->state.elf64.ehdr_mem.e_machine); + CONVERT (elf->state.elf64.ehdr_mem.e_version); + CONVERT (elf->state.elf64.ehdr_mem.e_entry); + CONVERT (elf->state.elf64.ehdr_mem.e_phoff); + CONVERT (elf->state.elf64.ehdr_mem.e_shoff); + CONVERT (elf->state.elf64.ehdr_mem.e_flags); + CONVERT (elf->state.elf64.ehdr_mem.e_ehsize); + CONVERT (elf->state.elf64.ehdr_mem.e_phentsize); + CONVERT (elf->state.elf64.ehdr_mem.e_phnum); + CONVERT (elf->state.elf64.ehdr_mem.e_shentsize); + CONVERT (elf->state.elf64.ehdr_mem.e_shnum); + CONVERT (elf->state.elf64.ehdr_mem.e_shstrndx); + } + + elf->state.elf64.ehdr = &elf->state.elf64.ehdr_mem; + + for (size_t cnt = 0; cnt < scncnt; ++cnt) + { + elf->state.elf64.scns.data[cnt].index = cnt; + elf->state.elf64.scns.data[cnt].elf = elf; + elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns; + } + } + + /* So far only one block with sections. */ + elf->state.elf64.scns_last = &elf->state.elf64.scns; + } + + /* Make the class easily available. */ + elf->class = e_ident[EI_CLASS]; + + return elf; +} + + +Elf * +internal_function_def +__libelf_read_mmaped_file (int fildes, void *map_address, off_t offset, + size_t maxsize, Elf_Cmd cmd, Elf *parent) +{ + /* We have to find out what kind of file this is. We handle ELF + files and archives. To find out what we have we must look at the + header. The header for an ELF file is EI_NIDENT bytes in size, + the header for an archive file SARMAG bytes long. */ + Elf_Kind kind; + + /* See what kind of object we have here. */ + kind = determine_kind (map_address + offset, maxsize); + + switch (kind) + { + case ELF_K_ELF: + return file_read_elf (fildes, map_address, offset, maxsize, cmd, parent); + + case ELF_K_AR: + return file_read_ar (fildes, map_address, offset, maxsize, cmd, parent); + + default: + break; + } + + /* This case is easy. Since we cannot do anything with this file + create a dummy descriptor. */ + return allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, + ELF_K_NONE, 0); +} + + +static Elf * +read_unmmaped_file (int fildes, off_t offset, size_t maxsize, Elf_Cmd cmd, + Elf *parent) +{ + /* We have to find out what kind of file this is. We handle ELF + files and archives. To find out what we have we must read the + header. The header for an ELF file is EI_NIDENT bytes in size, + the header for an archive file SARMAG bytes long. Read the + maximum of these numbers. + + XXX We have to change this for the extended `ar' format some day. */ + unsigned char header[MAX (EI_NIDENT, SARMAG)]; + ssize_t nread; + Elf_Kind kind; + + /* Read the head of the file. */ + nread = pread (fildes, header, MIN (MAX (EI_NIDENT, SARMAG), maxsize), + offset); + if (nread == -1) + /* We cannot even read the head of the file. Maybe FILDES is associated + with an unseekable device. This is nothing we can handle. */ + return NULL; + + /* See what kind of object we have here. */ + kind = determine_kind (header, nread); + + switch (kind) + { + case ELF_K_AR: + return file_read_ar (fildes, NULL, offset, maxsize, cmd, parent); + + case ELF_K_ELF: + /* Make sure at least the ELF header is contained in the file. */ + if (maxsize >= (header[EI_CLASS] == ELFCLASS32 + ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))) + return file_read_elf (fildes, NULL, offset, maxsize, cmd, parent); + /* FALLTHROUGH */ + + default: + break; + } + + /* This case is easy. Since we cannot do anything with this file + create a dummy descriptor. */ + return allocate_elf (fildes, NULL, offset, maxsize, cmd, parent, + ELF_K_NONE, 0); +} + + +/* Open a file for reading. If possible we will try to mmap() the file. */ +static struct Elf * +read_file (int fildes, off_t offset, size_t maxsize, + Elf_Cmd cmd, Elf *parent) +{ + void *map_address = NULL; + int use_mmap = (cmd == ELF_C_READ_MMAP || cmd == ELF_C_RDWR_MMAP + || cmd == ELF_C_WRITE_MMAP + || cmd == ELF_C_READ_MMAP_PRIVATE); + +#if _MUDFLAP + /* Mudflap doesn't grok that our mmap'd data is ok. */ + use_mmap = 0; +#endif + + if (use_mmap) + { + if (parent == NULL) + { + if (maxsize == ~((size_t) 0)) + { + /* We don't know in the moment how large the file is. + Determine it now. */ + struct stat st; + + if (fstat (fildes, &st) == 0 + && (sizeof (size_t) >= sizeof (st.st_size) + || st.st_size <= ~((size_t) 0))) + maxsize = (size_t) st.st_size; + } + + /* We try to map the file ourself. */ + map_address = mmap (NULL, maxsize, (cmd == ELF_C_READ_MMAP + ? PROT_READ + : PROT_READ|PROT_WRITE), + cmd == ELF_C_READ_MMAP_PRIVATE + ? MAP_PRIVATE : MAP_SHARED, + fildes, offset); + + if (map_address == MAP_FAILED) + map_address = NULL; + } + else + { + /* The parent is already loaded. Use it. */ + assert (maxsize != ~((size_t) 0)); + + map_address = parent->map_address; + } + } + + /* If we have the file in memory optimize the access. */ + if (map_address != NULL) + { + struct Elf *result; + + result = __libelf_read_mmaped_file (fildes, map_address, offset, maxsize, + cmd, parent); + + /* If something went wrong during the initialization unmap the + memory if we mmaped here. */ + if (result == NULL + && (parent == NULL + || parent->map_address != map_address)) + munmap (map_address, maxsize); + else if (parent == NULL) + /* Remember that we mmap()ed the memory. */ + result->flags |= ELF_F_MMAPPED; + + return result; + } + + /* Otherwise we have to do it the hard way. We read as much as necessary + from the file whenever we need information which is not available. */ + return read_unmmaped_file (fildes, offset, maxsize, cmd, parent); +} + + +/* Find the entry with the long names for the content of this archive. */ +static const char * +read_long_names (Elf *elf) +{ + off_t offset = SARMAG; /* This is the first entry. */ + struct ar_hdr hdrm; + struct ar_hdr *hdr; + char *newp; + size_t len; + + while (1) + { + if (elf->map_address != NULL) + { + if (offset + sizeof (struct ar_hdr) > elf->maximum_size) + return NULL; + + /* The data is mapped. */ + hdr = (struct ar_hdr *) (elf->map_address + offset); + } + else + { + /* Read the header from the file. */ + if (pread (elf->fildes, &hdrm, sizeof (hdrm), + elf->start_offset + offset) != sizeof (hdrm)) + return NULL; + + hdr = &hdrm; + } + + len = atol (hdr->ar_size); + + if (memcmp (hdr->ar_name, "// ", 16) == 0) + break; + + offset += sizeof (struct ar_hdr) + ((len + 1) & ~1l); + } + + /* Due to the stupid format of the long name table entry (which are not + NUL terminted) we have to provide an appropriate representation anyhow. + Therefore we always make a copy which has the appropriate form. */ + newp = (char *) malloc (len); + if (newp != NULL) + { + char *runp; + + if (elf->map_address != NULL) + /* Simply copy it over. */ + elf->state.ar.long_names = (char *) memcpy (newp, + elf->map_address + offset + + sizeof (struct ar_hdr), + len); + else + { + if ((size_t) pread (elf->fildes, newp, len, + elf->start_offset + offset + + sizeof (struct ar_hdr)) + != len) + { + /* We were not able to read all data. */ + free (newp); + elf->state.ar.long_names = NULL; + return NULL; + } + elf->state.ar.long_names = newp; + } + + elf->state.ar.long_names_len = len; + + /* Now NUL-terminate the strings. */ + runp = newp; + while (1) + { + runp = (char *) memchr (runp, '/', newp + len - runp); + if (runp == NULL) + /* This was the last entry. */ + break; + + /* NUL-terminate the string. */ + *runp = '\0'; + + /* Skip the NUL bzte and the \012. */ + runp += 2; + + /* A sanity check. Somebody might have generated invalid + archive. */ + if (runp >= newp + len) + break; + } + } + + return newp; +} + + +/* Read the next archive header. */ +int +internal_function_def +__libelf_next_arhdr (elf) + Elf *elf; +{ + struct ar_hdr *ar_hdr; + Elf_Arhdr *elf_ar_hdr; + + if (elf->map_address != NULL) + { + /* See whether this entry is in the file. */ + if (elf->state.ar.offset + sizeof (struct ar_hdr) + > elf->start_offset + elf->maximum_size) + { + /* This record is not anymore in the file. */ + __libelf_seterrno (ELF_E_RANGE); + return -1; + } + ar_hdr = (struct ar_hdr *) (elf->map_address + elf->state.ar.offset); + } + else + { + ar_hdr = &elf->state.ar.ar_hdr; + + if (pread (elf->fildes, ar_hdr, sizeof (struct ar_hdr), + elf->state.ar.offset) + != sizeof (struct ar_hdr)) + { + /* Something went wrong while reading the file. */ + __libelf_seterrno (ELF_E_RANGE); + return -1; + } + } + + /* One little consistency check. */ + if (memcmp (ar_hdr->ar_fmag, ARFMAG, 2) != 0) + { + /* This is no valid archive. */ + __libelf_seterrno (ELF_E_ARCHIVE_FMAG); + return -1; + } + + /* Copy the raw name over to a NUL terminated buffer. */ + *((char *) __mempcpy (elf->state.ar.raw_name, ar_hdr->ar_name, 16)) = '\0'; + + elf_ar_hdr = &elf->state.ar.elf_ar_hdr; + + /* Now convert the `struct ar_hdr' into `Elf_Arhdr'. + Determine whether this is a special entry. */ + if (ar_hdr->ar_name[0] == '/') + { + if (ar_hdr->ar_name[1] == ' ' + && memcmp (ar_hdr->ar_name, "/ ", 16) == 0) + /* This is the index. */ + elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/", 2); + else if (ar_hdr->ar_name[1] == '/' + && memcmp (ar_hdr->ar_name, "// ", 16) == 0) + /* This is the array with the long names. */ + elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "//", 3); + else if (isdigit (ar_hdr->ar_name[1])) + { + size_t offset; + + /* This is a long name. First we have to read the long name + table, if this hasn't happened already. */ + if (elf->state.ar.long_names == NULL + && read_long_names (elf) == NULL) + { + /* No long name table although it is reference. The archive is + broken. */ + __libelf_seterrno (ELF_E_INVALID_ARCHIVE); + return -1; + } + + offset = atol (ar_hdr->ar_name + 1); + if (offset >= elf->state.ar.long_names_len) + { + /* The index in the long name table is larger than the table. */ + __libelf_seterrno (ELF_E_INVALID_ARCHIVE); + return -1; + } + elf_ar_hdr->ar_name = elf->state.ar.long_names + offset; + } + else + { + /* This is none of the known special entries. */ + __libelf_seterrno (ELF_E_INVALID_ARCHIVE); + return -1; + } + } + else + { + char *endp; + + /* It is a normal entry. Copy over the name. */ + endp = (char *) memccpy (elf->state.ar.ar_name, ar_hdr->ar_name, + '/', 16); + if (endp != NULL) + endp[-1] = '\0'; + else + elf->state.ar.raw_name[16] = '\0'; + + elf_ar_hdr->ar_name = elf->state.ar.ar_name; + } + + /* Since there are no specialized functions to convert ASCII to + time_t, uid_t, gid_t, mode_t, and off_t we use either atol or + atoll depending on the size of the types. We are also prepared + for the case where the whole field in the `struct ar_hdr' is + filled in which case we cannot simply use atol/l but instead have + to create a temporary copy. */ + if (ar_hdr->ar_date[sizeof (ar_hdr->ar_date) - 1] == ' ') + { + if (ar_hdr->ar_date[0] == ' ') + elf_ar_hdr->ar_date = 0; + else + elf_ar_hdr->ar_date = (sizeof (time_t) <= sizeof (long int) + ? (time_t) atol (ar_hdr->ar_date) + : (time_t) atoll (ar_hdr->ar_date)); + } + else + { + char buf[sizeof (ar_hdr->ar_date) + 1]; + *((char *) __mempcpy (buf, ar_hdr->ar_date, sizeof (ar_hdr->ar_date))) + = '\0'; + elf_ar_hdr->ar_date = (sizeof (time_t) <= sizeof (long int) + ? (time_t) atol (ar_hdr->ar_date) + : (time_t) atoll (ar_hdr->ar_date)); + } + + if (ar_hdr->ar_uid[sizeof (ar_hdr->ar_uid) - 1] == ' ') + { + if (ar_hdr->ar_uid[0] == ' ') + elf_ar_hdr->ar_uid = 0; + else + elf_ar_hdr->ar_uid = (sizeof (uid_t) <= sizeof (long int) + ? (uid_t) atol (ar_hdr->ar_uid) + : (uid_t) atoll (ar_hdr->ar_uid)); + } + else + { + char buf[sizeof (ar_hdr->ar_uid) + 1]; + *((char *) __mempcpy (buf, ar_hdr->ar_uid, sizeof (ar_hdr->ar_uid))) + = '\0'; + elf_ar_hdr->ar_uid = (sizeof (uid_t) <= sizeof (long int) + ? (uid_t) atol (ar_hdr->ar_uid) + : (uid_t) atoll (ar_hdr->ar_uid)); + } + + if (ar_hdr->ar_gid[sizeof (ar_hdr->ar_gid) - 1] == ' ') + { + if (ar_hdr->ar_gid[0] == ' ') + elf_ar_hdr->ar_gid = 0; + else + elf_ar_hdr->ar_gid = (sizeof (gid_t) <= sizeof (long int) + ? (gid_t) atol (ar_hdr->ar_gid) + : (gid_t) atoll (ar_hdr->ar_gid)); + } + else + { + char buf[sizeof (ar_hdr->ar_gid) + 1]; + *((char *) __mempcpy (buf, ar_hdr->ar_gid, sizeof (ar_hdr->ar_gid))) + = '\0'; + elf_ar_hdr->ar_gid = (sizeof (gid_t) <= sizeof (long int) + ? (gid_t) atol (ar_hdr->ar_gid) + : (gid_t) atoll (ar_hdr->ar_gid)); + } + + if (ar_hdr->ar_mode[sizeof (ar_hdr->ar_mode) - 1] == ' ') + { + if (ar_hdr->ar_mode[0] == ' ') + elf_ar_hdr->ar_mode = 0; + else + elf_ar_hdr->ar_mode = (sizeof (mode_t) <= sizeof (long int) + ? (mode_t) strtol (ar_hdr->ar_mode, NULL, 8) + : (mode_t) strtoll (ar_hdr->ar_mode, NULL, 8)); + } + else + { + char buf[sizeof (ar_hdr->ar_mode) + 1]; + *((char *) __mempcpy (buf, ar_hdr->ar_mode, sizeof (ar_hdr->ar_mode))) + = '\0'; + elf_ar_hdr->ar_mode = (sizeof (mode_t) <= sizeof (long int) + ? (mode_t) strtol (ar_hdr->ar_mode, NULL, 8) + : (mode_t) strtoll (ar_hdr->ar_mode, NULL, 8)); + } + + if (ar_hdr->ar_size[sizeof (ar_hdr->ar_size) - 1] == ' ') + { + if (ar_hdr->ar_size[0] == ' ') + /* Something is really wrong. We cannot live without a size for + the member since it will not be possible to find the next + archive member. */ + { + __libelf_seterrno (ELF_E_INVALID_ARCHIVE); + return -1; + } + else + elf_ar_hdr->ar_size = (sizeof (time_t) == sizeof (long int) + ? (off_t) atol (ar_hdr->ar_size) + : (off_t) atoll (ar_hdr->ar_size)); + } + else + { + char buf[sizeof (ar_hdr->ar_size) + 1]; + *((char *) __mempcpy (buf, ar_hdr->ar_size, sizeof (ar_hdr->ar_size))) + = '\0'; + elf_ar_hdr->ar_size = (sizeof (time_t) == sizeof (long int) + ? (off_t) atol (ar_hdr->ar_size) + : (off_t) atoll (ar_hdr->ar_size)); + } + + return 0; +} + + +/* We were asked to return a clone of an existing descriptor. This + function must be called with the lock on the parent descriptor + being held. */ +static Elf * +dup_elf (int fildes, Elf_Cmd cmd, Elf *ref) +{ + struct Elf *result; + + if (fildes == -1) + /* Allow the user to pass -1 as the file descriptor for the new file. */ + fildes = ref->fildes; + /* The file descriptor better should be the same. If it was disconnected + already (using `elf_cntl') we do not test it. */ + else if (ref->fildes != -1 && fildes != ref->fildes) + { + __libelf_seterrno (ELF_E_FD_MISMATCH); + return NULL; + } + + /* The mode must allow reading. I.e., a descriptor creating with a + command different then ELF_C_READ, ELF_C_WRITE and ELF_C_RDWR is + not allowed. */ + if (ref->cmd != ELF_C_READ && ref->cmd != ELF_C_READ_MMAP + && ref->cmd != ELF_C_WRITE && ref->cmd != ELF_C_WRITE_MMAP + && ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP + && ref->cmd != ELF_C_READ_MMAP_PRIVATE) + { + __libelf_seterrno (ELF_E_INVALID_OP); + return NULL; + } + + /* Now it is time to distinguish between reading normal files and + archives. Normal files can easily be handled be incrementing the + reference counter and return the same descriptor. */ + if (ref->kind != ELF_K_AR) + { + ++ref->ref_count; + return ref; + } + + /* This is an archive. We must create a descriptor for the archive + member the internal pointer of the archive file desriptor is + pointing to. First read the header of the next member if this + has not happened already. */ + if (ref->state.ar.elf_ar_hdr.ar_name == NULL + && __libelf_next_arhdr (ref) != 0) + /* Something went wrong. Maybe there is no member left. */ + return NULL; + + /* We have all the information we need about the next archive member. + Now create a descriptor for it. */ + result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr), + ref->state.ar.elf_ar_hdr.ar_size, cmd, ref); + + /* Enlist this new descriptor in the list of children. */ + if (result != NULL) + { + result->next = ref->state.ar.children; + ref->state.ar.children = result; + } + + return result; +} + + +/* Return desriptor for empty file ready for writing. */ +static struct Elf * +write_file (int fd, Elf_Cmd cmd) +{ + /* We simply create an empty `Elf' structure. */ +#define NSCNSALLOC 10 + Elf *result = allocate_elf (fd, NULL, 0, 0, cmd, NULL, ELF_K_ELF, + NSCNSALLOC * sizeof (Elf_Scn)); + + if (result != NULL) + { + /* We have to write to the file in any case. */ + result->flags = ELF_F_DIRTY; + + /* Some more or less arbitrary value. */ + result->state.elf.scnincr = NSCNSALLOC; + + /* We have allocated room for some sections. */ + assert (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)); + result->state.elf.scns_last = &result->state.elf32.scns; + result->state.elf32.scns.max = NSCNSALLOC; + } + + return result; +} + + +/* Return a descriptor for the file belonging to FILDES. */ +Elf * +elf_begin (fildes, cmd, ref) + int fildes; + Elf_Cmd cmd; + Elf *ref; +{ + Elf *retval; + + if (! __libelf_version_initialized) + { + /* Version wasn't set so far. */ + __libelf_seterrno (ELF_E_NO_VERSION); + return NULL; + } + + if (ref != NULL) + /* Make sure the descriptor is not suddenly going away. */ + rwlock_rdlock (ref->lock); + else if (fcntl (fildes, F_GETFL) == -1 && errno == EBADF) + { + /* We cannot do anything productive without a file descriptor. */ + __libelf_seterrno (ELF_E_INVALID_FILE); + return NULL; + } + + switch (cmd) + { + case ELF_C_NULL: + /* We simply return a NULL pointer. */ + retval = NULL; + break; + + case ELF_C_READ_MMAP_PRIVATE: + /* If we have a reference it must also be opened this way. */ + if (ref != NULL && ref->cmd != ELF_C_READ_MMAP_PRIVATE) + { + __libelf_seterrno (ELF_E_INVALID_CMD); + retval = NULL; + break; + } + /* FALLTHROUGH */ + + case ELF_C_READ: + case ELF_C_READ_MMAP: + if (ref != NULL) + /* Duplicate the descriptor. */ + retval = dup_elf (fildes, cmd, ref); + else + /* Create descriptor for existing file. */ + retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL); + break; + + case ELF_C_RDWR: + case ELF_C_RDWR_MMAP: + /* If we have a REF object it must also be opened using this + command. */ + if (ref != NULL) + { + if (ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP + && ref->cmd != ELF_C_WRITE && ref->cmd != ELF_C_WRITE_MMAP) + { + /* This is not ok. REF must also be opened for writing. */ + __libelf_seterrno (ELF_E_INVALID_CMD); + retval = NULL; + } + else + /* Duplicate this descriptor. */ + retval = dup_elf (fildes, cmd, ref); + } + else + /* Create descriptor for existing file. */ + retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL); + break; + + case ELF_C_WRITE: + case ELF_C_WRITE_MMAP: + /* We ignore REF and prepare a descriptor to write a new file. */ + retval = write_file (fildes, cmd); + break; + + default: + __libelf_seterrno (ELF_E_INVALID_CMD); + retval = NULL; + break; + } + + /* Release the lock. */ + if (ref != NULL) + rwlock_unlock (ref->lock); + + return retval; +} +INTDEF(elf_begin) diff --git a/libelf/elf_clone.c b/libelf/elf_clone.c new file mode 100644 index 00000000..516d2ae4 --- /dev/null +++ b/libelf/elf_clone.c @@ -0,0 +1,69 @@ +/* Create clone of a given descriptor. + Copyright (C) 2003, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "libelfP.h" +#include "common.h" + + +Elf * +elf_clone (Elf *elf, Elf_Cmd cmd) +{ + Elf *retval = NULL; + + if (elf == NULL) + /* Some earlier mistake. */ + return NULL; + + /* Make sure the descriptor is not suddenly going away. */ + rwlock_rdlock (elf->lock); + + if (cmd != ELF_C_EMPTY) + // XXX TODO handle ELF_C_READ/WRITE etc + goto out; + + retval = allocate_elf (elf->fildes, elf->map_address, elf->start_offset, + elf->maximum_size, elf->cmd, elf->parent, elf->kind, + elf->state.elf32.scns.max * sizeof (Elf_Scn)); + if (retval != NULL) + { + /* We have to write to the file in any case. */ + retval->flags = ELF_F_DIRTY; + + /* Some more or less arbitrary value. */ + retval->state.elf.scnincr = 10; + + /* We have allocated room for some sections. */ + assert (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)); + retval->state.elf.scns_last = &retval->state.elf32.scns; + retval->state.elf32.scns.max = elf->state.elf32.scns.max; + + retval->class = elf->class; + } + + /* Release the lock. */ + out: + rwlock_unlock (elf->lock); + + return retval; +} diff --git a/libelf/elf_cntl.c b/libelf/elf_cntl.c new file mode 100644 index 00000000..eea0f362 --- /dev/null +++ b/libelf/elf_cntl.c @@ -0,0 +1,71 @@ +/* Control an ELF file desrciptor. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "libelfP.h" + + +int +elf_cntl (elf, cmd) + Elf *elf; + Elf_Cmd cmd; +{ + int result = 0; + + if (elf == NULL) + return -1; + + if (elf->fildes == -1) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1; + } + + rwlock_wrlock (elf->lock); + + switch (cmd) + { + case ELF_C_FDREAD: + /* If not all of the file is in the memory read it now. */ + if (elf->map_address == NULL && __libelf_readall (elf) == NULL) + { + /* We were not able to read everything. */ + result = -1; + break; + } + /* FALLTHROUGH */ + + case ELF_C_FDDONE: + /* Mark the file descriptor as not usable. */ + elf->fildes = -1; + break; + + default: + __libelf_seterrno (ELF_E_INVALID_CMD); + result = -1; + break; + } + + rwlock_unlock (elf->lock); + + return result; +} diff --git a/libelf/elf_end.c b/libelf/elf_end.c new file mode 100644 index 00000000..33626f07 --- /dev/null +++ b/libelf/elf_end.c @@ -0,0 +1,203 @@ +/* Free resources associated with Elf descriptor. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "libelfP.h" + + +int +elf_end (elf) + Elf *elf; +{ + Elf *parent; + + if (elf == NULL) + /* This is allowed and is a no-op. */ + return 0; + + /* Make sure we are alone. */ + rwlock_wrlock (elf->lock); + + if (elf->ref_count != 0 && --elf->ref_count != 0) + { + /* Not yet the last activation. */ + int result = elf->ref_count; + rwlock_unlock (elf->lock); + return result; + } + + if (elf->kind == ELF_K_AR) + { + /* We cannot remove the descriptor now since we still have some + descriptors which depend on it. But we can free the archive + symbol table since this is only available via the archive ELF + descriptor. The long name table cannot be freed yet since + the archive headers for the ELF files in the archive point + into this array. */ + free (elf->state.ar.ar_sym); + elf->state.ar.ar_sym = NULL; + + if (elf->state.ar.children != NULL) + return 0; + } + + /* Remove this structure from the children list. */ + parent = elf->parent; + if (parent != NULL) + { + /* This is tricky. Lock must be acquire from the father to + the child but here we already have the child lock. We + solve this problem by giving free the child lock. The + state of REF_COUNT==0 is handled all over the library, so + this should be ok. */ + rwlock_unlock (elf->lock); + rwlock_rdlock (parent->lock); + rwlock_wrlock (elf->lock); + + if (parent->state.ar.children == elf) + parent->state.ar.children = elf->next; + else + { + struct Elf *child = parent->state.ar.children; + + while (child->next != elf) + child = child->next; + + child->next = elf->next; + } + + rwlock_unlock (parent->lock); + } + + /* This was the last activation. Free all resources. */ + switch (elf->kind) + { + case ELF_K_AR: + if (elf->state.ar.long_names != NULL) + free (elf->state.ar.long_names); + break; + + case ELF_K_ELF: + { + Elf_ScnList *list = (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)) + ? &elf->state.elf32.scns + : &elf->state.elf64.scns); + + do + { + /* Free all separately allocated section headers. */ + size_t cnt = list->max; + + while (cnt-- > 0) + { + /* These pointers can be NULL; it's safe to use + 'free' since it will check for this. */ + Elf_Scn *scn = &list->data[cnt]; + Elf_Data_List *runp; + + if ((scn->shdr_flags & ELF_F_MALLOCED) != 0) + /* It doesn't matter which pointer. */ + free (scn->shdr.e32); + + /* If the file has the same byte order and the + architecture doesn't require overly stringent + alignment the raw data buffer is the same as the + one used for presenting to the caller. */ + if (scn->data_base != scn->rawdata_base) + free (scn->data_base); + + /* The section data is allocated if we couldn't mmap + the file. */ + if (elf->map_address == NULL) + free (scn->rawdata_base); + + /* Free the list of data buffers for the section. + We don't free the buffers themselves since this + is the users job. */ + runp = scn->data_list.next; + while (runp != NULL) + { + Elf_Data_List *oldp = runp; + runp = runp->next; + if ((oldp->flags & ELF_F_MALLOCED) != 0) + free (oldp); + } + } + + /* Free the memory for the array. */ + Elf_ScnList *oldp = list; + list = list->next; + assert (list == NULL || oldp->cnt == oldp->max); + if (oldp != (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)) + ? &elf->state.elf32.scns + : &elf->state.elf64.scns)) + free (oldp); + } + while (list != NULL); + } + + /* Free the section header. */ + if (elf->state.elf.shdr_malloced != 0) + free (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.shdr) + == offsetof (struct Elf, state.elf64.shdr)) + ? (void *) elf->state.elf32.shdr + : (void *) elf->state.elf64.shdr); + + /* Free the program header. */ + if ((elf->state.elf.phdr_flags & ELF_F_MALLOCED) != 0) + free (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.phdr) + == offsetof (struct Elf, state.elf64.phdr)) + ? (void *) elf->state.elf32.phdr + : (void *) elf->state.elf64.phdr); + break; + + default: + break; + } + + if (elf->map_address != NULL && parent == NULL) + { + /* The file was read or mapped for this descriptor. */ + if ((elf->flags & ELF_F_MALLOCED) != 0) + free (elf->map_address); + else if ((elf->flags & ELF_F_MMAPPED) != 0) + munmap (elf->map_address, elf->maximum_size); + } + + rwlock_fini (elf->lock); + + /* Finally the descriptor itself. */ + free (elf); + + return (parent != NULL && parent->ref_count == 0 + ? INTUSE(elf_end) (parent) : 0); +} +INTDEF(elf_end) diff --git a/libelf/elf_error.c b/libelf/elf_error.c new file mode 100644 index 00000000..168ce113 --- /dev/null +++ b/libelf/elf_error.c @@ -0,0 +1,366 @@ +/* Error handling in libelf. + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "libelfP.h" + + +#ifdef USE_TLS +/* The error number. */ +static __thread int global_error; +#else +/* This is the key for the thread specific memory. */ +static tls_key_t key; + +/* The error number. Used in non-threaded programs. */ +static int global_error; +static bool threaded; +/* We need to initialize the thread-specific data. */ +once_define (static, once); + +/* The initialization and destruction functions. */ +static void init (void); +static void free_key_mem (void *mem); +#endif /* TLS */ + + +int +elf_errno (void) +{ + int result; + +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if (threaded) + { + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + result = (intptr_t) getspecific (key); + + setspecific (key, (void *) (intptr_t) ELF_E_NOERROR); + return result; + } +#endif /* TLS */ + + result = global_error; + global_error = ELF_E_NOERROR; + return result; +} + + +/* Return the appropriate message for the error. */ +static const char msgstr[] = +{ +#define ELF_E_NOERROR_IDX 0 + N_("no error") + "\0" +#define ELF_E_UNKNOWN_ERROR_IDX (ELF_E_NOERROR_IDX + sizeof "no error") + N_("unknown error") + "\0" +#define ELF_E_UNKNOWN_VERSION_IDX \ + (ELF_E_UNKNOWN_ERROR_IDX + sizeof "unknown error") + N_("unknown version") + "\0" +#define ELF_E_UNKNOWN_TYPE_IDX \ + (ELF_E_UNKNOWN_VERSION_IDX + sizeof "unknown version") + N_("unknown type") + "\0" +#define ELF_E_INVALID_HANDLE_IDX \ + (ELF_E_UNKNOWN_TYPE_IDX + sizeof "unknown type") + N_("invalid `Elf' handle") + "\0" +#define ELF_E_SOURCE_SIZE_IDX \ + (ELF_E_INVALID_HANDLE_IDX + sizeof "invalid `Elf' handle") + N_("invalid size of source operand") + "\0" +#define ELF_E_DEST_SIZE_IDX \ + (ELF_E_SOURCE_SIZE_IDX + sizeof "invalid size of source operand") + N_("invalid size of destination operand") + "\0" +#define ELF_E_INVALID_ENCODING_IDX \ + (ELF_E_DEST_SIZE_IDX + sizeof "invalid size of destination operand") + N_("invalid encoding") + "\0" +#define ELF_E_NOMEM_IDX \ + (ELF_E_INVALID_ENCODING_IDX + sizeof "invalid encoding") + N_("out of memory") + "\0" +#define ELF_E_INVALID_FILE_IDX \ + (ELF_E_NOMEM_IDX + sizeof "out of memory") + N_("invalid file descriptor") + "\0" +#define ELF_E_INVALID_OP_IDX \ + (ELF_E_INVALID_FILE_IDX + sizeof "invalid file descriptor") + N_("invalid operation") + "\0" +#define ELF_E_NO_VERSION_IDX \ + (ELF_E_INVALID_OP_IDX + sizeof "invalid operation") + N_("ELF version not set") + "\0" +#define ELF_E_INVALID_CMD_IDX \ + (ELF_E_NO_VERSION_IDX + sizeof "ELF version not set") + N_("invalid command") + "\0" +#define ELF_E_RANGE_IDX \ + (ELF_E_INVALID_CMD_IDX + sizeof "invalid command") + N_("offset out of range") + "\0" +#define ELF_E_ARCHIVE_FMAG_IDX \ + (ELF_E_RANGE_IDX + sizeof "offset out of range") + N_("invalid fmag field in archive header") + "\0" +#define ELF_E_INVALID_ARCHIVE_IDX \ + (ELF_E_ARCHIVE_FMAG_IDX + sizeof "invalid fmag field in archive header") + N_("invalid archive file") + "\0" +#define ELF_E_NO_ARCHIVE_IDX \ + (ELF_E_INVALID_ARCHIVE_IDX + sizeof "invalid archive file") + N_("descriptor is not for an archive") + "\0" +#define ELF_E_NO_INDEX_IDX \ + (ELF_E_NO_ARCHIVE_IDX + sizeof "descriptor is not for an archive") + N_("no index available") + "\0" +#define ELF_E_READ_ERROR_IDX \ + (ELF_E_NO_INDEX_IDX + sizeof "no index available") + N_("cannot read data from file") + "\0" +#define ELF_E_WRITE_ERROR_IDX \ + (ELF_E_READ_ERROR_IDX + sizeof "cannot read data from file") + N_("cannot write data to file") + "\0" +#define ELF_E_INVALID_CLASS_IDX \ + (ELF_E_WRITE_ERROR_IDX + sizeof "cannot write data to file") + N_("invalid binary class") + "\0" +#define ELF_E_INVALID_INDEX_IDX \ + (ELF_E_INVALID_CLASS_IDX + sizeof "invalid binary class") + N_("invalid section index") + "\0" +#define ELF_E_INVALID_OPERAND_IDX \ + (ELF_E_INVALID_INDEX_IDX + sizeof "invalid section index") + N_("invalid operand") + "\0" +#define ELF_E_INVALID_SECTION_IDX \ + (ELF_E_INVALID_OPERAND_IDX + sizeof "invalid operand") + N_("invalid section") + "\0" +#define ELF_E_INVALID_COMMAND_IDX \ + (ELF_E_INVALID_SECTION_IDX + sizeof "invalid section") + N_("invalid command") + "\0" +#define ELF_E_WRONG_ORDER_EHDR_IDX \ + (ELF_E_INVALID_COMMAND_IDX + sizeof "invalid command") + N_("executable header not created first") + "\0" +#define ELF_E_FD_DISABLED_IDX \ + (ELF_E_WRONG_ORDER_EHDR_IDX + sizeof "executable header not created first") + N_("file descriptor disabled") + "\0" +#define ELF_E_FD_MISMATCH_IDX \ + (ELF_E_FD_DISABLED_IDX + sizeof "file descriptor disabled") + N_("archive/member fildes mismatch") + "\0" +#define ELF_E_OFFSET_RANGE_IDX \ + (ELF_E_FD_MISMATCH_IDX + sizeof "archive/member fildes mismatch") + N_("offset out of range") + "\0" +#define ELF_E_NOT_NUL_SECTION_IDX \ + (ELF_E_OFFSET_RANGE_IDX + sizeof "offset out of range") + N_("cannot manipulate null section") + "\0" +#define ELF_E_DATA_MISMATCH_IDX \ + (ELF_E_NOT_NUL_SECTION_IDX + sizeof "cannot manipulate null section") + N_("data/scn mismatch") + "\0" +#define ELF_E_INVALID_SECTION_HEADER_IDX \ + (ELF_E_DATA_MISMATCH_IDX + sizeof "data/scn mismatch") + N_("invalid section header") + "\0" +#define ELF_E_INVALID_DATA_IDX \ + (ELF_E_INVALID_SECTION_HEADER_IDX + sizeof "invalid section header") + N_("invalid data") + "\0" +#define ELF_E_DATA_ENCODING_IDX \ + (ELF_E_INVALID_DATA_IDX + sizeof "invalid data") + N_("unknown data encoding") + "\0" +#define ELF_E_SECTION_TOO_SMALL_IDX \ + (ELF_E_DATA_ENCODING_IDX + sizeof "unknown data encoding") + N_("section `sh_size' too small for data") + "\0" +#define ELF_E_INVALID_ALIGN_IDX \ + (ELF_E_SECTION_TOO_SMALL_IDX + sizeof "section `sh_size' too small for data") + N_("invalid section alignment") + "\0" +#define ELF_E_INVALID_SHENTSIZE_IDX \ + (ELF_E_INVALID_ALIGN_IDX + sizeof "invalid section alignment") + N_("invalid section entry size") + "\0" +#define ELF_E_UPDATE_RO_IDX \ + (ELF_E_INVALID_SHENTSIZE_IDX + sizeof "invalid section entry size") + N_("update() for write on read-only file") + "\0" +#define ELF_E_NOFILE_IDX \ + (ELF_E_UPDATE_RO_IDX + sizeof "update() for write on read-only file") + N_("no such file") + "\0" +#define ELF_E_GROUP_NOT_REL_IDX \ + (ELF_E_NOFILE_IDX + sizeof "no such file") + N_("only relocatable files can contain section groups") + "\0" +#define ELF_E_INVALID_PHDR_IDX \ + (ELF_E_GROUP_NOT_REL_IDX \ + + sizeof "only relocatable files can contain section groups") + N_("program header only allowed in executables and shared objects") + "\0" +#define ELF_E_NO_PHDR_IDX \ + (ELF_E_INVALID_PHDR_IDX \ + + sizeof "program header only allowed in executables and shared objects") + N_("file has no program header") +}; + + +static const uint_fast16_t msgidx[ELF_E_NUM] = +{ + [ELF_E_NOERROR] = ELF_E_NOERROR_IDX, + [ELF_E_UNKNOWN_ERROR] = ELF_E_UNKNOWN_ERROR_IDX, + [ELF_E_UNKNOWN_VERSION] = ELF_E_UNKNOWN_VERSION_IDX, + [ELF_E_UNKNOWN_TYPE] = ELF_E_UNKNOWN_TYPE_IDX, + [ELF_E_INVALID_HANDLE] = ELF_E_INVALID_HANDLE_IDX, + [ELF_E_SOURCE_SIZE] = ELF_E_SOURCE_SIZE_IDX, + [ELF_E_DEST_SIZE] = ELF_E_DEST_SIZE_IDX, + [ELF_E_INVALID_ENCODING] = ELF_E_INVALID_ENCODING_IDX, + [ELF_E_NOMEM] = ELF_E_NOMEM_IDX, + [ELF_E_INVALID_FILE] = ELF_E_INVALID_FILE_IDX, + [ELF_E_INVALID_OP] = ELF_E_INVALID_OP_IDX, + [ELF_E_NO_VERSION] = ELF_E_NO_VERSION_IDX, + [ELF_E_INVALID_CMD] = ELF_E_INVALID_CMD_IDX, + [ELF_E_RANGE] = ELF_E_RANGE_IDX, + [ELF_E_ARCHIVE_FMAG] = ELF_E_ARCHIVE_FMAG_IDX, + [ELF_E_INVALID_ARCHIVE] = ELF_E_INVALID_ARCHIVE_IDX, + [ELF_E_NO_ARCHIVE] = ELF_E_NO_ARCHIVE_IDX, + [ELF_E_NO_INDEX] = ELF_E_NO_INDEX_IDX, + [ELF_E_READ_ERROR] = ELF_E_READ_ERROR_IDX, + [ELF_E_WRITE_ERROR] = ELF_E_WRITE_ERROR_IDX, + [ELF_E_INVALID_CLASS] = ELF_E_INVALID_CLASS_IDX, + [ELF_E_INVALID_INDEX] = ELF_E_INVALID_INDEX_IDX, + [ELF_E_INVALID_OPERAND] = ELF_E_INVALID_OPERAND_IDX, + [ELF_E_INVALID_SECTION] = ELF_E_INVALID_SECTION_IDX, + [ELF_E_INVALID_COMMAND] = ELF_E_INVALID_COMMAND_IDX, + [ELF_E_WRONG_ORDER_EHDR] = ELF_E_WRONG_ORDER_EHDR_IDX, + [ELF_E_FD_DISABLED] = ELF_E_FD_DISABLED_IDX, + [ELF_E_FD_MISMATCH] = ELF_E_FD_MISMATCH_IDX, + [ELF_E_OFFSET_RANGE] = ELF_E_OFFSET_RANGE_IDX, + [ELF_E_NOT_NUL_SECTION] = ELF_E_NOT_NUL_SECTION_IDX, + [ELF_E_DATA_MISMATCH] = ELF_E_DATA_MISMATCH_IDX, + [ELF_E_INVALID_SECTION_HEADER] = ELF_E_INVALID_SECTION_HEADER_IDX, + [ELF_E_INVALID_DATA] = ELF_E_INVALID_DATA_IDX, + [ELF_E_DATA_ENCODING] = ELF_E_DATA_ENCODING_IDX, + [ELF_E_SECTION_TOO_SMALL] = ELF_E_SECTION_TOO_SMALL_IDX, + [ELF_E_INVALID_ALIGN] = ELF_E_INVALID_ALIGN_IDX, + [ELF_E_INVALID_SHENTSIZE] = ELF_E_INVALID_SHENTSIZE_IDX, + [ELF_E_UPDATE_RO] = ELF_E_UPDATE_RO_IDX, + [ELF_E_NOFILE] = ELF_E_NOFILE_IDX, + [ELF_E_GROUP_NOT_REL] = ELF_E_GROUP_NOT_REL_IDX, + [ELF_E_INVALID_PHDR] = ELF_E_INVALID_PHDR_IDX, + [ELF_E_NO_PHDR] = ELF_E_NO_PHDR_IDX +}; +#define nmsgidx ((int) (sizeof (msgidx) / sizeof (msgidx[0]))) + + +void +__libelf_seterrno (value) + int value; +{ +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if (threaded) + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + setspecific (key, (void *) (intptr_t) value); +#endif /* TLS */ + + global_error = value >= 0 && value < nmsgidx ? value : ELF_E_UNKNOWN_ERROR; +} + + +const char * +elf_errmsg (error) + int error; +{ + int last_error; + +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if ((error == 0 || error == -1) && threaded) + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + last_error = (intptr_t) getspecific (key); + else +#endif /* TLS */ + last_error = global_error; + + if (error == 0) + { + assert (msgidx[last_error] < sizeof (msgstr)); + return last_error != 0 ? _(msgstr + msgidx[last_error]) : NULL; + } + else if (error < -1 || error >= nmsgidx) + return _(msgstr + ELF_E_UNKNOWN_ERROR_IDX); + + assert (msgidx[error == -1 ? last_error : error] < sizeof (msgstr)); + return _(msgstr + msgidx[error == -1 ? last_error : error]); +} + + +#ifndef USE_TLS +/* Free the thread specific data, this is done if a thread terminates. */ +static void +free_key_mem (void *mem __attribute__ ((unused))) +{ + setspecific (key, NULL); +} + + +/* Initialize the key for the global variable. */ +static void +init (void) +{ + // XXX Screw you, gcc4, the unused function attribute does not work. + __asm ("" :: "r" (free_key_mem)); + + if (key_create (&key, free_key_mem) == 0) + /* Creating the key succeeded. */ + threaded = true; +} +#endif /* TLS */ diff --git a/libelf/elf_fill.c b/libelf/elf_fill.c new file mode 100644 index 00000000..f09cc7b6 --- /dev/null +++ b/libelf/elf_fill.c @@ -0,0 +1,35 @@ +/* Set fill byte used when constructing ELF objects. + Copyright (C) 1998, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "libelfP.h" + + +int __libelf_fill_byte; + + +void +elf_fill (fill) + int fill; +{ + __libelf_fill_byte = fill; +} diff --git a/libelf/elf_flagdata.c b/libelf/elf_flagdata.c new file mode 100644 index 00000000..b5191316 --- /dev/null +++ b/libelf/elf_flagdata.c @@ -0,0 +1,59 @@ +/* Manipulate ELF data flag. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +unsigned int +elf_flagdata (data, cmd, flags) + Elf_Data *data; + Elf_Cmd cmd; + unsigned int flags; +{ + Elf_Data_Scn *data_scn; + unsigned int result; + + if (data == NULL) + return 0; + + data_scn = (Elf_Data_Scn *) data; + + if (data_scn == NULL || unlikely (data_scn->s->elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (data_scn->s->flags |= (flags & ELF_F_DIRTY)); + else if (likely (cmd == ELF_C_CLR)) + result = (data_scn->s->flags &= ~(flags & ELF_F_DIRTY)); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/libelf/elf_flagehdr.c b/libelf/elf_flagehdr.c new file mode 100644 index 00000000..2099fc51 --- /dev/null +++ b/libelf/elf_flagehdr.c @@ -0,0 +1,56 @@ +/* Manipulate ELF header flags. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +unsigned int +elf_flagehdr (elf, cmd, flags) + Elf *elf; + Elf_Cmd cmd; + unsigned int flags; +{ + unsigned int result; + + if (elf == NULL) + return 0; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (elf->state.elf.ehdr_flags |= (flags & ELF_F_DIRTY)); + else if (cmd == ELF_C_CLR) + result = (elf->state.elf.ehdr_flags &= ~(flags & ELF_F_DIRTY)); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/libelf/elf_flagelf.c b/libelf/elf_flagelf.c new file mode 100644 index 00000000..3a001f67 --- /dev/null +++ b/libelf/elf_flagelf.c @@ -0,0 +1,58 @@ +/* Manipulate ELF file flags. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +unsigned int +elf_flagelf (elf, cmd, flags) + Elf *elf; + Elf_Cmd cmd; + unsigned int flags; +{ + unsigned int result; + + if (elf == NULL) + return 0; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (elf->flags + |= (flags & (ELF_F_DIRTY | ELF_F_LAYOUT | ELF_F_PERMISSIVE))); + else if (likely (cmd == ELF_C_CLR)) + result = (elf->flags + &= ~(flags & (ELF_F_DIRTY | ELF_F_LAYOUT | ELF_F_PERMISSIVE))); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/libelf/elf_flagphdr.c b/libelf/elf_flagphdr.c new file mode 100644 index 00000000..c2f8794d --- /dev/null +++ b/libelf/elf_flagphdr.c @@ -0,0 +1,56 @@ +/* Manipulate ELF program header flags. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +unsigned int +elf_flagphdr (elf, cmd, flags) + Elf *elf; + Elf_Cmd cmd; + unsigned int flags; +{ + unsigned int result; + + if (elf == NULL) + return 0; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (elf->state.elf.phdr_flags |= (flags & ELF_F_DIRTY)); + else if (likely (cmd == ELF_C_CLR)) + result = (elf->state.elf.phdr_flags &= ~(flags & ELF_F_DIRTY)); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/libelf/elf_flagscn.c b/libelf/elf_flagscn.c new file mode 100644 index 00000000..9cd1cc40 --- /dev/null +++ b/libelf/elf_flagscn.c @@ -0,0 +1,56 @@ +/* Manipulate ELF section flags. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +unsigned int +elf_flagscn (scn, cmd, flags) + Elf_Scn *scn; + Elf_Cmd cmd; + unsigned int flags; +{ + unsigned int result; + + if (scn == NULL) + return 0; + + if (unlikely (scn->elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (scn->flags |= (flags & ELF_F_DIRTY)); + else if (likely (cmd == ELF_C_CLR)) + result = (scn->flags &= ~(flags & ELF_F_DIRTY)); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/libelf/elf_flagshdr.c b/libelf/elf_flagshdr.c new file mode 100644 index 00000000..0972d27f --- /dev/null +++ b/libelf/elf_flagshdr.c @@ -0,0 +1,56 @@ +/* Manipulate ELF section header flags. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +unsigned int +elf_flagshdr (scn, cmd, flags) + Elf_Scn *scn; + Elf_Cmd cmd; + unsigned int flags; +{ + unsigned int result; + + if (scn == NULL) + return 0; + + if (unlikely (scn->elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (scn->shdr_flags |= (flags & ELF_F_DIRTY)); + else if (likely (cmd == ELF_C_CLR)) + result = (scn->shdr_flags &= ~(flags & ELF_F_DIRTY)); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/libelf/elf_getarhdr.c b/libelf/elf_getarhdr.c new file mode 100644 index 00000000..da0b4a42 --- /dev/null +++ b/libelf/elf_getarhdr.c @@ -0,0 +1,53 @@ +/* Read header of next archive member. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +Elf_Arhdr * +elf_getarhdr (elf) + Elf *elf; +{ + Elf *parent = elf->parent; + + /* Calling this function is not ok for any file type but archives. */ + if (parent == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OP); + return NULL; + } + + /* Make sure we have read the archive header. */ + if (parent->state.ar.elf_ar_hdr.ar_name == NULL + && __libelf_next_arhdr (parent) != 0) + /* Something went wrong. Maybe there is no member left. */ + return NULL; + + + /* We can be sure the parent is an archive. */ + assert (parent->kind == ELF_K_AR); + + return &parent->state.ar.elf_ar_hdr; +} diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c new file mode 100644 index 00000000..1dafa9ac --- /dev/null +++ b/libelf/elf_getarsym.c @@ -0,0 +1,241 @@ +/* Return symbol table of archive. + Copyright (C) 1998, 1999, 2000, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "libelfP.h" + + +Elf_Arsym * +elf_getarsym (elf, ptr) + Elf *elf; + size_t *ptr; +{ + if (elf->kind != ELF_K_AR) + { + /* This is no archive. */ + __libelf_seterrno (ELF_E_NO_ARCHIVE); + return NULL; + } + + if (ptr != NULL) + /* In case of an error or when we know the value store the expected + value now. Doing this allows us easier exits in an error case. */ + *ptr = elf->state.ar.ar_sym_num; + + if (elf->state.ar.ar_sym == (Elf_Arsym *) -1l) + { + /* There is no index. */ + __libelf_seterrno (ELF_E_NO_INDEX); + return NULL; + } + + Elf_Arsym *result = elf->state.ar.ar_sym; + if (result == NULL) + { + /* We have not yet read the index. */ + rwlock_wrlock (elf->lock); + + /* In case we find no index remember this for the next call. */ + elf->state.ar.ar_sym = (Elf_Arsym *) -1l; + + struct ar_hdr *index_hdr; + if (elf->map_address == NULL) + { + /* We must read index from the file. */ + assert (elf->fildes != -1); + if (pread (elf->fildes, &elf->state.ar.ar_hdr, + sizeof (struct ar_hdr), elf->start_offset + SARMAG) + != sizeof (struct ar_hdr)) + { + /* It is not possible to read the index. Maybe it does not + exist. */ + __libelf_seterrno (ELF_E_READ_ERROR); + goto out; + } + + index_hdr = &elf->state.ar.ar_hdr; + } + else + { + if (SARMAG + sizeof (struct ar_hdr) > elf->maximum_size) + { + /* There is no room for the full archive. */ + __libelf_seterrno (ELF_E_NO_INDEX); + goto out; + } + + index_hdr = (struct ar_hdr *) (elf->map_address + + elf->start_offset + SARMAG); + } + + /* Now test whether this really is an archive. */ + if (memcmp (index_hdr->ar_fmag, ARFMAG, 2) != 0) + { + /* Invalid magic bytes. */ + __libelf_seterrno (ELF_E_ARCHIVE_FMAG); + goto out; + } + + /* Now test whether this is the index. It is denoted by the + name being "/ ". + XXX This is not entirely true. There are some more forms. + Which of them shall we handle? */ + if (memcmp (index_hdr->ar_name, "/ ", 16) != 0) + { + /* If the index is not the first entry, there is no index. + + XXX Is this true? */ + __libelf_seterrno (ELF_E_NO_INDEX); + goto out; + } + + /* We have an archive. The first word in there is the number of + entries in the table. */ + uint32_t n; + if (elf->map_address == NULL) + { + if (pread (elf->fildes, &n, sizeof (n), + elf->start_offset + SARMAG + sizeof (struct ar_hdr)) + != sizeof (n)) + { + /* Cannot read the number of entries. */ + __libelf_seterrno (ELF_E_NO_INDEX); + goto out; + } + } + else + n = *(uint32_t *) (elf->map_address + elf->start_offset + + SARMAG + sizeof (struct ar_hdr)); + + if (__BYTE_ORDER == __LITTLE_ENDIAN) + n = bswap_32 (n); + + /* Now we can perform some first tests on whether all the data + needed for the index is available. */ + char tmpbuf[17]; + memcpy (tmpbuf, index_hdr->ar_size, 10); + tmpbuf[10] = '\0'; + size_t index_size = atol (tmpbuf); + + if (SARMAG + sizeof (struct ar_hdr) + index_size > elf->maximum_size + || n * sizeof (uint32_t) > index_size) + { + /* This index table cannot be right since it does not fit into + the file. */ + __libelf_seterrno (ELF_E_NO_INDEX); + goto out; + } + + /* Now we can allocate the arrays needed to store the index. */ + size_t ar_sym_len = (n + 1) * sizeof (Elf_Arsym); + elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len); + if (elf->state.ar.ar_sym != NULL) + { + uint32_t *file_data; + char *str_data; + + if (elf->map_address == NULL) + { + file_data = (uint32_t *) alloca (n * sizeof (uint32_t)); + + ar_sym_len += index_size - n * sizeof (uint32_t); + Elf_Arsym *newp = (Elf_Arsym *) realloc (elf->state.ar.ar_sym, + ar_sym_len); + if (newp == NULL) + { + free (elf->state.ar.ar_sym); + elf->state.ar.ar_sym = NULL; + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + elf->state.ar.ar_sym = newp; + + char *new_str = (char *) (elf->state.ar.ar_sym + n + 1); + + /* Now read the data from the file. */ + if ((size_t) pread (elf->fildes, file_data, + n * sizeof (uint32_t), elf->start_offset + + SARMAG + sizeof (struct ar_hdr) + + sizeof (uint32_t)) != n * sizeof (uint32_t) + || ((size_t) pread (elf->fildes, new_str, + index_size - n * sizeof (uint32_t), + elf->start_offset + + SARMAG + sizeof (struct ar_hdr) + + (n + 1) * sizeof (uint32_t)) + != index_size - n * sizeof (uint32_t))) + { + /* We were not able to read the data. */ + free (elf->state.ar.ar_sym); + elf->state.ar.ar_sym = NULL; + __libelf_seterrno (ELF_E_NO_INDEX); + goto out; + } + + str_data = (char *) new_str; + } + else + { + file_data = (uint32_t *) (elf->map_address + elf->start_offset + + SARMAG + sizeof (struct ar_hdr) + + sizeof (uint32_t)); + str_data = (char *) &file_data[n]; + } + + /* Now we can build the data structure. */ + Elf_Arsym *arsym = elf->state.ar.ar_sym; + for (size_t cnt = 0; cnt < n; ++cnt) + { + arsym[cnt].as_name = str_data; + if (__BYTE_ORDER == __LITTLE_ENDIAN) + arsym[cnt].as_off = bswap_32 (file_data[cnt]); + else + arsym[cnt].as_off = file_data[cnt]; + arsym[cnt].as_hash = _dl_elf_hash (str_data); + str_data = rawmemchr (str_data, '\0') + 1; + } + /* At the end a special entry. */ + arsym[n].as_name = NULL; + arsym[n].as_off = 0; + arsym[n].as_hash = ~0UL; + + /* Tell the caller how many entries we have. */ + elf->state.ar.ar_sym_num = n + 1; + } + + result = elf->state.ar.ar_sym; + + out: + rwlock_unlock (elf->lock); + } + + if (ptr != NULL) + *ptr = elf->state.ar.ar_sym_num; + + return result; +} diff --git a/libelf/elf_getbase.c b/libelf/elf_getbase.c new file mode 100644 index 00000000..ea76f416 --- /dev/null +++ b/libelf/elf_getbase.c @@ -0,0 +1,33 @@ +/* Return offset of first byte for the object. + Copyright (C) 1998, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +off_t +elf_getbase (elf) + Elf *elf; +{ + return elf == NULL ? (off_t) -1 : elf->start_offset; +} diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c new file mode 100644 index 00000000..20e8e624 --- /dev/null +++ b/libelf/elf_getdata.c @@ -0,0 +1,454 @@ +/* Return the next data element from the section after possibly converting it. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" +#include "common.h" +#include "elf-knowledge.h" + + +#if _STRING_ARCH_unaligned +# define ALLOW_ALIGNED 1 +#else +# define ALLOW_ALIGNED 0 +#endif + + +#define TYPEIDX(Sh_Type) \ + (Sh_Type >= SHT_NULL && Sh_Type < SHT_NUM \ + ? Sh_Type \ + : (Sh_Type >= SHT_GNU_LIBLIST && Sh_Type <= SHT_HISUNW \ + ? SHT_NUM + Sh_Type - SHT_GNU_LIBLIST \ + : 0)) + +static const struct +{ + Elf_Type type; + size_t size; +#if ALLOW_ALIGNED +# define AL(val) +#else + size_t align; +# define AL(val), val +#endif +} shtype_map[EV_NUM - 1][ELFCLASSNUM - 1][TYPEIDX (SHT_HISUNW) + 1] = +{ + [EV_CURRENT - 1] = + { + [ELFCLASS32 - 1] = + { + /* Associate section types with libelf types, their sizes and + alignment. SHT_GNU_verdef is special since the section does + not contain entries of only one size. */ +#define DEFINE(Bits) \ + [SHT_SYMTAB] = { ELF_T_SYM, sizeof (ElfW2(Bits,Sym)) \ + AL (__alignof__ (ElfW2(Bits,Sym))) }, \ + [SHT_RELA] = { ELF_T_RELA, sizeof (ElfW2(Bits,Rela)) \ + AL (__alignof__ (ElfW2(Bits,Rela))) }, \ + [SHT_HASH] = { ELF_T_WORD, sizeof (ElfW2(Bits,Word)) \ + AL (__alignof__ (ElfW2(Bits,Word))) }, \ + [SHT_DYNAMIC] = { ELF_T_DYN, sizeof (ElfW2(Bits,Dyn)) \ + AL (__alignof__ (ElfW2(Bits,Dyn))) }, \ + [SHT_REL] = { ELF_T_REL, sizeof (ElfW2(Bits,Rel)) \ + AL (__alignof__ (ElfW2(Bits,Rel))) }, \ + [SHT_DYNSYM] = { ELF_T_SYM, sizeof (ElfW2(Bits,Sym)) \ + AL (__alignof__ (ElfW2(Bits,Sym))) }, \ + [SHT_INIT_ARRAY] = { ELF_T_ADDR, sizeof (ElfW2(Bits,Addr)) \ + AL (__alignof__ (ElfW2(Bits,Addr))) }, \ + [SHT_FINI_ARRAY] = { ELF_T_ADDR, sizeof (ElfW2(Bits,Addr)) \ + AL (__alignof__ (ElfW2(Bits,Addr))) }, \ + [SHT_PREINIT_ARRAY] = { ELF_T_ADDR, sizeof (ElfW2(Bits,Addr)) \ + AL (__alignof__ (ElfW2(Bits,Addr))) }, \ + [SHT_GROUP] = { ELF_T_WORD, sizeof (Elf32_Word) \ + AL (__alignof__ (Elf32_Word)) }, \ + [SHT_SYMTAB_SHNDX] = { ELF_T_WORD, sizeof (Elf32_Word) \ + AL (__alignof__ (Elf32_Word)) }, \ + [TYPEIDX (SHT_GNU_verdef)] = { ELF_T_VDEF, 1 AL (1) }, \ + [TYPEIDX (SHT_GNU_verneed)] = { ELF_T_VNEED, \ + sizeof (ElfW2(Bits,Verneed)) \ + AL (__alignof__ (ElfW2(Bits,Verneed)))},\ + [TYPEIDX (SHT_GNU_versym)] = { ELF_T_HALF, sizeof (ElfW2(Bits,Versym)) \ + AL (__alignof__ (ElfW2(Bits,Versym))) }, \ + [TYPEIDX (SHT_SUNW_syminfo)] = { ELF_T_SYMINFO, \ + sizeof (ElfW2(Bits,Syminfo)) \ + AL(__alignof__ (ElfW2(Bits,Syminfo)))},\ + [TYPEIDX (SHT_SUNW_move)] = { ELF_T_MOVE, sizeof (ElfW2(Bits,Move)) \ + AL (__alignof__ (ElfW2(Bits,Move))) }, \ + [TYPEIDX (SHT_GNU_LIBLIST)] = { ELF_T_LIB, sizeof (ElfW2(Bits,Lib)) \ + AL (__alignof__ (ElfW2(Bits,Lib))) } + DEFINE (32) + }, + [ELFCLASS64 - 1] = + { + DEFINE (64) + } + } +}; + + +/* Convert the data in the current section. */ +static void +convert_data (Elf_Scn *scn, int version __attribute__ ((unused)), int eclass, + int data, size_t size, size_t type) +{ +#if ALLOW_ALIGNED + /* No need to compute the alignment requirement of the host. */ + const size_t align = 1; +#else +# if EV_NUM != 2 + size_t align = shtype_map[version - 1][eclass - 1][type].align; +# else + size_t align = shtype_map[0][eclass - 1][type].align; +# endif +#endif + + if (data == MY_ELFDATA) + { + if (ALLOW_ALIGNED + || (((size_t) ((char *) scn->rawdata_base)) & (align - 1)) == 0) + /* No need to copy, we can use the raw data. */ + scn->data_base = scn->rawdata_base; + else + { + scn->data_base = (char *) malloc (size); + if (scn->data_base == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return; + } + + /* The copy will be appropriately aligned for direct access. */ + memcpy (scn->data_base, scn->rawdata_base, size); + } + } + else + { + xfct_t fp; + + scn->data_base = (char *) malloc (size); + if (scn->data_base == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return; + } + + /* Get the conversion function. */ +#if EV_NUM != 2 + fp = __elf_xfctstom[version - 1][__libelf_version - 1][eclass - 1][type]; +#else + fp = __elf_xfctstom[0][0][eclass - 1][type]; +#endif + + fp (scn->data_base, scn->rawdata_base, size, 0); + } + + scn->data_list.data.d.d_buf = scn->data_base; + scn->data_list.data.d.d_size = size; + scn->data_list.data.d.d_type = type; + scn->data_list.data.d.d_off = scn->rawdata.d.d_off; + scn->data_list.data.d.d_align = scn->rawdata.d.d_align; + scn->data_list.data.d.d_version = scn->rawdata.d.d_version; + + scn->data_list.data.s = scn; +} + + +/* Store the information for the raw data in the `rawdata' element. */ +int +internal_function_def +__libelf_set_rawdata (Elf_Scn *scn) +{ + size_t offset; + size_t size; + size_t align; + int type; + Elf *elf = scn->elf; + + if (elf->class == ELFCLASS32) + { + Elf32_Shdr *shdr = scn->shdr.e32 ?: INTUSE(elf32_getshdr) (scn); + + if (shdr == NULL) + /* Something went terribly wrong. */ + return 1; + + offset = shdr->sh_offset; + size = shdr->sh_size; + type = shdr->sh_type; + align = shdr->sh_addralign; + } + else + { + Elf64_Shdr *shdr = scn->shdr.e64 ?: INTUSE(elf64_getshdr) (scn); + + if (shdr == NULL) + /* Something went terribly wrong. */ + return 1; + + offset = shdr->sh_offset; + size = shdr->sh_size; + type = shdr->sh_type; + align = shdr->sh_addralign; + } + + /* If the section has no data (for whatever reason), leave the `d_buf' + pointer NULL. */ + if (size != 0 && type != SHT_NOBITS) + { + /* First a test whether the section is valid at all. */ + size_t entsize; + + if (type == SHT_HASH) + { + GElf_Ehdr ehdr_mem; + + entsize = SH_ENTSIZE_HASH (INTUSE(gelf_getehdr) (elf, &ehdr_mem)); + } + else + { +#if EV_NUM != 2 + entsize = shtype_map[__libelf_version - 1][elf->class - 1][TYPEIDX (type)].size; +#else + entsize = shtype_map[0][elf->class - 1][TYPEIDX (type)].size; +#endif + } + + /* We assume it is an array of bytes if it is none of the structured + sections we know of. */ + if (entsize == 0) + entsize = 1; + + if (size % entsize != 0) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + return 1; + } + + /* We can use the mapped or loaded data if available. */ + if (elf->map_address != NULL) + { + /* First see whether the information in the section header is + valid and it does not ask for too much. */ + if (offset + size > elf->maximum_size) + { + /* Something is wrong. */ + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + return 1; + } + + scn->rawdata_base = scn->rawdata.d.d_buf + = (char *) elf->map_address + elf->start_offset + offset; + } + else if (elf->fildes != -1) + { + /* We have to read the data from the file. Allocate the needed + memory. */ + scn->rawdata_base = scn->rawdata.d.d_buf + = (char *) malloc (size); + if (scn->rawdata.d.d_buf == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return 1; + } + + if ((size_t) pread (elf->fildes, scn->rawdata.d.d_buf, size, + elf->start_offset + offset) != size) + { + /* Cannot read the data. */ + free (scn->rawdata.d.d_buf); + scn->rawdata_base = scn->rawdata.d.d_buf = NULL; + __libelf_seterrno (ELF_E_READ_ERROR); + return 1; + } + } + else + { + /* The file descriptor is already closed, we cannot get the data + anymore. */ + __libelf_seterrno (ELF_E_FD_DISABLED); + return 1; + } + } + + scn->rawdata.d.d_size = size; + /* Some broken ELF ABI for 64-bit machines use the wrong hash table + entry size. See elf-knowledge.h for more information. */ + if (type == SHT_HASH && elf->class == ELFCLASS64) + { + GElf_Ehdr ehdr_mem; + + scn->rawdata.d.d_type + = (SH_ENTSIZE_HASH (INTUSE(gelf_getehdr) (elf, &ehdr_mem)) + == 4 ? ELF_T_WORD : ELF_T_XWORD); + } + else + { +#if EV_NUM != 2 + scn->rawdata.d.d_type = + shtype_map[__libelf_version - 1][elf->class - 1][TYPEIDX (type)].type; +#else + scn->rawdata.d.d_type = + shtype_map[0][elf->class - 1][TYPEIDX (type)].type; +#endif + } + scn->rawdata.d.d_off = 0; + scn->rawdata.d.d_align = align; + if (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.ehdr) + == offsetof (struct Elf, state.elf64.ehdr))) + scn->rawdata.d.d_version = + elf->state.elf32.ehdr->e_ident[EI_VERSION]; + else + scn->rawdata.d.d_version = + elf->state.elf64.ehdr->e_ident[EI_VERSION]; + + scn->rawdata.s = scn; + + scn->data_read = 1; + + /* We actually read data from the file. At least we tried. */ + scn->flags |= ELF_F_FILEDATA; + + return 0; +} + + +Elf_Data * +elf_getdata (scn, data) + Elf_Scn *scn; + Elf_Data *data; +{ + Elf_Data *result = NULL; + Elf *elf; + + if (scn == NULL) + return NULL; + + if (unlikely (scn->elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* We will need this multiple times later on. */ + elf = scn->elf; + + rwlock_rdlock (elf->lock); + + /* If `data' is not NULL this means we are not addressing the initial + data in the file. But this also means this data is already read + (since otherwise it is not possible to have a valid `data' pointer) + and all the data structures are initialized as well. In this case + we can simply walk the list of data records. */ + if (data != NULL) + { + Elf_Data_List *runp; + + /* It is not possible that if DATA is not NULL the first entry is + returned. But this also means that there must be a first data + entry. */ + if (scn->data_list_rear == NULL + /* The section the reference data is for must match the section + parameter. */ + || unlikely (((Elf_Data_Scn *) data)->s != scn)) + { + __libelf_seterrno (ELF_E_DATA_MISMATCH); + goto out; + } + + /* We start searching with the first entry. */ + runp = &scn->data_list; + + while (1) + { + /* If `data' does not match any known record punt. */ + if (runp == NULL) + { + __libelf_seterrno (ELF_E_DATA_MISMATCH); + goto out; + } + + if (&runp->data.d == data) + /* Found the entry. */ + break; + + runp = runp->next; + } + + /* Return the data for the next data record. */ + result = runp->next ? &runp->next->data.d : NULL; + goto out; + } + + /* If the data for this section was not yet initialized do it now. */ + if (scn->data_read == 0) + { + /* We cannot acquire a write lock while we are holding a read + lock. Therefore give up the read lock and then get the write + lock. But this means that the data could meanwhile be + modified, therefore start the tests again. */ + rwlock_unlock (elf->lock); + rwlock_wrlock (elf->lock); + + /* Read the data from the file. There is always a file (or + memory region) associated with this descriptor since + otherwise the `data_read' flag would be set. */ + if (scn->data_read == 0 && __libelf_set_rawdata (scn) != 0) + /* Something went wrong. The error value is already set. */ + goto out; + } + + /* At this point we know the raw data is available. But it might be + empty in case the section has size zero (for whatever reason). + Now create the converted data in case this is necessary. */ + if (scn->data_list_rear == NULL) + { + if (scn->rawdata.d.d_buf != NULL && scn->rawdata.d.d_size > 0) + /* Convert according to the version and the type. */ + convert_data (scn, __libelf_version, elf->class, + (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.ehdr) + == offsetof (struct Elf, state.elf64.ehdr)) + ? elf->state.elf32.ehdr->e_ident[EI_DATA] + : elf->state.elf64.ehdr->e_ident[EI_DATA]), + scn->rawdata.d.d_size, scn->rawdata.d.d_type); + else + /* This is an empty or NOBITS section. There is no buffer but + the size information etc is important. */ + scn->data_list.data.d = scn->rawdata.d; + + scn->data_list_rear = &scn->data_list; + } + + /* If no data is present we cannot return any. */ + if (scn->data_list_rear != NULL) + /* Return the first data element in the list. */ + result = &scn->data_list.data.d; + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elf_getdata) diff --git a/libelf/elf_getident.c b/libelf/elf_getident.c new file mode 100644 index 00000000..b673b5c6 --- /dev/null +++ b/libelf/elf_getident.c @@ -0,0 +1,51 @@ +/* Retrieve file identification data. + Copyright (C) 1998, 1999, 2000, 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "libelfP.h" + + +char * +elf_getident (elf, ptr) + Elf *elf; + size_t *ptr; +{ + /* In case this is no ELF file, the handle is invalid and we return + NULL. */ + if (elf == NULL || elf->kind != ELF_K_ELF) + { + if (ptr != NULL) + *ptr = 0; + return NULL; + } + + /* We already read the ELF header. Return a pointer to it and store + the length in *PTR. */ + if (ptr != NULL) + *ptr = EI_NIDENT; + + return (char *) (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.ehdr) + == offsetof (struct Elf, state.elf64.ehdr)) + ? elf->state.elf32.ehdr->e_ident + : elf->state.elf64.ehdr->e_ident); +} diff --git a/libelf/elf_getscn.c b/libelf/elf_getscn.c new file mode 100644 index 00000000..a6b4767c --- /dev/null +++ b/libelf/elf_getscn.c @@ -0,0 +1,77 @@ +/* Get section at specific index. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +Elf_Scn * +elf_getscn (elf, idx) + Elf *elf; + size_t idx; +{ + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_rdlock (elf->lock); + + Elf_Scn *result = NULL; + + /* Find the section in the list. */ + Elf_ScnList *runp = (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)) + ? &elf->state.elf32.scns : &elf->state.elf64.scns); + while (1) + { + if (idx < runp->max) + { + if (idx < runp->cnt) + result = &runp->data[idx]; + else + __libelf_seterrno (ELF_E_INVALID_INDEX); + break; + } + + idx -= runp->max; + + runp = runp->next; + if (runp == NULL) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + break; + } + } + + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elf_getscn) diff --git a/libelf/elf_getshnum.c b/libelf/elf_getshnum.c new file mode 100644 index 00000000..52d6a056 --- /dev/null +++ b/libelf/elf_getshnum.c @@ -0,0 +1,64 @@ +/* Return number of sections in the ELF file. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +int +elf_getshnum (elf, dst) + Elf *elf; + size_t *dst; +{ + int result = 0; + int idx; + + if (elf == NULL) + return -1; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1; + } + + rwlock_rdlock (elf->lock); + + idx = elf->state.elf.scns_last->cnt; + if (idx != 0 + || (elf->state.elf.scns_last + != (elf->class == ELFCLASS32 + || (offsetof (Elf, state.elf32.scns) + == offsetof (Elf, state.elf64.scns)) + ? &elf->state.elf32.scns : &elf->state.elf64.scns))) + /* There is at least one section. */ + *dst = 1 + elf->state.elf.scns_last->data[idx - 1].index; + else + *dst = 0; + + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elf_getshnum) diff --git a/libelf/elf_getshstrndx.c b/libelf/elf_getshstrndx.c new file mode 100644 index 00000000..706092b7 --- /dev/null +++ b/libelf/elf_getshstrndx.c @@ -0,0 +1,168 @@ +/* Return section index of section header string table. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "libelfP.h" +#include "common.h" + + +int +elf_getshstrndx (elf, dst) + Elf *elf; + size_t *dst; +{ + int result = 0; + + if (elf == NULL) + return -1; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1; + } + + rwlock_rdlock (elf->lock); + + /* We rely here on the fact that the `elf' element is a common prefix + of `elf32' and `elf64'. */ + assert (offsetof (struct Elf, state.elf.ehdr) + == offsetof (struct Elf, state.elf32.ehdr)); + assert (sizeof (elf->state.elf.ehdr) + == sizeof (elf->state.elf32.ehdr)); + assert (offsetof (struct Elf, state.elf.ehdr) + == offsetof (struct Elf, state.elf64.ehdr)); + assert (sizeof (elf->state.elf.ehdr) + == sizeof (elf->state.elf64.ehdr)); + + if (unlikely (elf->state.elf.ehdr == NULL)) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + result = -1; + } + else + { + Elf32_Word num; + + num = (elf->class == ELFCLASS32 + ? elf->state.elf32.ehdr->e_shstrndx + : elf->state.elf64.ehdr->e_shstrndx); + + /* Determine whether the index is too big to fit in the ELF + header. */ + if (unlikely (num == SHN_XINDEX)) + { + /* Yes. Search the zeroth section header. */ + if (elf->class == ELFCLASS32) + { + size_t offset; + + if (elf->state.elf32.scns.data[0].shdr.e32 != NULL) + { + num = elf->state.elf32.scns.data[0].shdr.e32->sh_link; + goto success; + } + + offset = elf->state.elf32.ehdr->e_shoff; + + if (elf->map_address != NULL + && elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((size_t) ((char *) elf->map_address + offset)) + & (__alignof__ (Elf32_Shdr) - 1)) == 0)) + /* We can directly access the memory. */ + num = ((Elf32_Shdr *) (elf->map_address + offset))->sh_link; + else + { + /* We avoid reading in all the section headers. Just read + the first one. */ + Elf32_Shdr shdr_mem; + + if (pread (elf->fildes, &shdr_mem, sizeof (Elf32_Shdr), + offset) != sizeof (Elf32_Shdr)) + { + /* We must be able to read this ELF section header. */ + __libelf_seterrno (ELF_E_INVALID_FILE); + result = -1; + goto out; + } + + if (elf->state.elf32.ehdr->e_ident[EI_DATA] != MY_ELFDATA) + CONVERT (shdr_mem.sh_link); + num = shdr_mem.sh_link; + } + } + else + { + size_t offset; + + if (elf->state.elf64.scns.data[0].shdr.e64 != NULL) + { + num = elf->state.elf64.scns.data[0].shdr.e64->sh_link; + goto success; + } + + offset = elf->state.elf64.ehdr->e_shoff; + + if (elf->map_address != NULL + && elf->state.elf64.ehdr->e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((size_t) ((char *) elf->map_address + offset)) + & (__alignof__ (Elf64_Shdr) - 1)) == 0)) + /* We can directly access the memory. */ + num = ((Elf64_Shdr *) (elf->map_address + offset))->sh_link; + else + { + /* We avoid reading in all the section headers. Just read + the first one. */ + Elf64_Shdr shdr_mem; + + if (pread (elf->fildes, &shdr_mem, sizeof (Elf64_Shdr), + offset) != sizeof (Elf64_Shdr)) + { + /* We must be able to read this ELF section header. */ + __libelf_seterrno (ELF_E_INVALID_FILE); + result = -1; + goto out; + } + + if (elf->state.elf64.ehdr->e_ident[EI_DATA] != MY_ELFDATA) + CONVERT (shdr_mem.sh_link); + num = shdr_mem.sh_link; + } + } + } + + /* Store the result. */ + success: + *dst = num; + } + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elf_getshstrndx) diff --git a/libelf/elf_hash.c b/libelf/elf_hash.c new file mode 100644 index 00000000..38f4ae06 --- /dev/null +++ b/libelf/elf_hash.c @@ -0,0 +1,33 @@ +/* Hash function used in ELF implementations. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* Get the implementation. */ +#include + +unsigned long int +elf_hash (string) + const char *string; +{ + return _dl_elf_hash (string); +} +INTDEF(elf_hash) diff --git a/libelf/elf_kind.c b/libelf/elf_kind.c new file mode 100644 index 00000000..a67ebe72 --- /dev/null +++ b/libelf/elf_kind.c @@ -0,0 +1,33 @@ +/* Return the kind of file associated with the descriptor. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +Elf_Kind +elf_kind (elf) + Elf *elf; +{ + return elf == NULL ? ELF_K_NONE : elf->kind; +} diff --git a/libelf/elf_memory.c b/libelf/elf_memory.c new file mode 100644 index 00000000..57221f99 --- /dev/null +++ b/libelf/elf_memory.c @@ -0,0 +1,40 @@ +/* Create descriptor for memory region. + Copyright (C) 1999, 2000, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +Elf * +elf_memory (image, size) + char *image; + size_t size; +{ + if (image == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + return NULL; + } + + return __libelf_read_mmaped_file (-1, image, 0, size, ELF_C_READ, NULL); +} diff --git a/libelf/elf_ndxscn.c b/libelf/elf_ndxscn.c new file mode 100644 index 00000000..edd6bdae --- /dev/null +++ b/libelf/elf_ndxscn.c @@ -0,0 +1,36 @@ +/* Get index of section. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +size_t +elf_ndxscn (scn) + Elf_Scn *scn; +{ + if (scn == NULL) + return SHN_UNDEF; + + return scn->index; +} diff --git a/libelf/elf_newdata.c b/libelf/elf_newdata.c new file mode 100644 index 00000000..bae3b3f5 --- /dev/null +++ b/libelf/elf_newdata.c @@ -0,0 +1,97 @@ +/* Create new, empty section data. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +Elf_Data * +elf_newdata (Elf_Scn *scn) +{ + Elf_Data_List *result = NULL; + + if (scn == NULL) + return NULL; + + if (unlikely (scn->index == 0)) + { + /* It is not allowed to add something to the 0th section. */ + __libelf_seterrno (ELF_E_NOT_NUL_SECTION); + return NULL; + } + + if (scn->elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.ehdr) + == offsetof (struct Elf, state.elf64.ehdr)) + ? scn->elf->state.elf32.ehdr == NULL + : scn->elf->state.elf64.ehdr == NULL) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + return NULL; + } + + rwlock_wrlock (scn->elf->lock); + + if (scn->data_read && scn->data_list_rear == NULL) + { + /* This means the section was created by the user and this is the + first data. */ + result = &scn->data_list; + result->flags = ELF_F_DIRTY; + } + else + { + /* Create a new, empty data descriptor. */ + result = (Elf_Data_List *) calloc (1, sizeof (Elf_Data_List)); + if (result == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + + result->flags = ELF_F_DIRTY | ELF_F_MALLOCED; + + if (scn->data_list_rear == NULL) + /* We create new data without reading/converting the data from the + file. That is fine but we have to remember this. */ + scn->data_list_rear = &scn->data_list; + } + + /* Set the predefined values. */ + result->data.d.d_version = __libelf_version; + + result->data.s = scn; + + /* Add to the end of the list. */ + if (scn->data_list_rear != NULL) + scn->data_list_rear->next = result; + + scn->data_list_rear = result; + + out: + rwlock_unlock (scn->elf->lock); + + /* Please note that the following is thread safe and is also defined + for RESULT == NULL since it still return NULL. */ + return &result->data.d; +} diff --git a/libelf/elf_newscn.c b/libelf/elf_newscn.c new file mode 100644 index 00000000..f3ea0d80 --- /dev/null +++ b/libelf/elf_newscn.c @@ -0,0 +1,143 @@ +/* Append new section. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "libelfP.h" + + +Elf_Scn * +elf_newscn (elf) + Elf *elf; +{ + Elf_Scn *result = NULL; + bool first = false; + + if (elf == NULL) + return NULL; + + /* We rely on the prefix of the `elf', `elf32', and `elf64' element + being the same. */ + assert (offsetof (Elf, state.elf.scns_last) + == offsetof (Elf, state.elf32.scns_last)); + assert (offsetof (Elf, state.elf.scns_last) + == offsetof (Elf, state.elf64.scns_last)); + assert (offsetof (Elf, state.elf32.scns) + == offsetof (Elf, state.elf64.scns)); + + rwlock_wrlock (elf->lock); + + again: + if (elf->state.elf.scns_last->cnt < elf->state.elf.scns_last->max) + { + result = &elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt]; + + if (++elf->state.elf.scns_last->cnt == 1 + && (elf->state.elf.scns_last + == (elf->class == ELFCLASS32 + || (offsetof (Elf, state.elf32.scns) + == offsetof (Elf, state.elf64.scns)) + ? &elf->state.elf32.scns : &elf->state.elf64.scns))) + /* This is zeroth section. */ + first = true; + else + { + assert (elf->state.elf.scns_last->cnt > 1); + result->index = result[-1].index + 1; + } + } + else + { + /* We must allocate a new element. */ + Elf_ScnList *newp; + + assert (elf->state.elf.scnincr > 0); + + newp = (Elf_ScnList *) calloc (sizeof (Elf_ScnList) + + ((elf->state.elf.scnincr *= 2) + * sizeof (Elf_Scn)), 1); + if (newp == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + + result = &newp->data[0]; + + /* One section used. */ + ++newp->cnt; + + /* This is the number of sections we allocated. */ + newp->max = elf->state.elf.scnincr; + + /* Remember the index for the first section in this block. */ + newp->data[0].index + = 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->max - 1].index; + + /* Enqueue the new list element. */ + elf->state.elf.scns_last = elf->state.elf.scns_last->next = newp; + } + + /* Create a section header for this section. */ + if (elf->class == ELFCLASS32) + { + result->shdr.e32 = (Elf32_Shdr *) calloc (1, sizeof (Elf32_Shdr)); + if (result->shdr.e32 == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + } + else + { + result->shdr.e64 = (Elf64_Shdr *) calloc (1, sizeof (Elf64_Shdr)); + if (result->shdr.e64 == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + } + + result->elf = elf; + result->shdr_flags = ELF_F_DIRTY | ELF_F_MALLOCED; + result->list = elf->state.elf.scns_last; + + /* Initialize the data part. */ + result->data_read = 1; + if (unlikely (first)) + { + /* For the first section we mark the data as already available. */ + //result->data_list_rear = &result->data_list; + first = false; + goto again; + } + + result->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/libelf/elf_next.c b/libelf/elf_next.c new file mode 100644 index 00000000..58a07753 --- /dev/null +++ b/libelf/elf_next.c @@ -0,0 +1,53 @@ +/* Advance in archive to next element. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +Elf_Cmd +elf_next (elf) + Elf *elf; +{ + Elf *parent; + + /* Be gratious, the specs demand it. */ + if (elf == NULL || elf->parent == NULL) + return ELF_C_NULL; + + /* We can be sure the parent is an archive. */ + parent = elf->parent; + assert (parent->kind == ELF_K_AR); + + /* Now advance the offset. */ + parent->state.ar.offset += (sizeof (struct ar_hdr) + + ((parent->state.ar.elf_ar_hdr.ar_size + 1) + & ~1l)); + + /* Get the next archive header. */ + if (__libelf_next_arhdr (parent) != 0) + return ELF_C_NULL; + + return elf->cmd; +} diff --git a/libelf/elf_nextscn.c b/libelf/elf_nextscn.c new file mode 100644 index 00000000..de9df64b --- /dev/null +++ b/libelf/elf_nextscn.c @@ -0,0 +1,77 @@ +/* Get next section. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +Elf_Scn * +elf_nextscn (elf, scn) + Elf *elf; + Elf_Scn *scn; +{ + Elf_Scn *result = NULL; + + if (elf == NULL) + return NULL; + + rwlock_rdlock (elf->lock); + + if (scn == NULL) + { + /* If no section handle is given return the first (not 0th) section. */ + if (elf->class == ELFCLASS32 + || (offsetof (Elf, state.elf32.scns) + == offsetof (Elf, state.elf64.scns))) + { + if (elf->state.elf32.scns.cnt > 1) + result = &elf->state.elf32.scns.data[1]; + } + else + { + if (elf->state.elf64.scns.cnt > 1) + result = &elf->state.elf64.scns.data[1]; + } + } + else + { + Elf_ScnList *list = scn->list; + + if (scn + 1 < &list->data[list->cnt]) + result = scn + 1; + else if (scn + 1 == &list->data[list->max] + && (list = list->next) != NULL) + { + /* If there is another element in the section list it must + have at least one entry. */ + assert (list->cnt > 0); + result = &list->data[0]; + } + } + + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elf_nextscn) diff --git a/libelf/elf_rand.c b/libelf/elf_rand.c new file mode 100644 index 00000000..76c3862f --- /dev/null +++ b/libelf/elf_rand.c @@ -0,0 +1,49 @@ +/* Select specific element in archive. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +size_t +elf_rand (elf, offset) + Elf *elf; + size_t offset; +{ + /* Be gratious, the specs demand it. */ + if (elf == NULL || elf->kind != ELF_K_AR) + return 0; + + /* Save the old offset and set the offset. */ + elf->state.ar.offset = elf->start_offset + offset; + + /* Get the next archive header. */ + if (__libelf_next_arhdr (elf) != 0) + { + /* Mark the archive header as unusable. */ + elf->state.ar.elf_ar_hdr.ar_name = NULL; + return 0; + } + + return offset; +} diff --git a/libelf/elf_rawdata.c b/libelf/elf_rawdata.c new file mode 100644 index 00000000..547c37f4 --- /dev/null +++ b/libelf/elf_rawdata.c @@ -0,0 +1,66 @@ +/* Return raw section content. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "libelfP.h" + + +Elf_Data * +elf_rawdata (scn, data) + Elf_Scn *scn; + Elf_Data *data; +{ + if (scn == NULL || scn->elf->kind != ELF_K_ELF) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* If `data' is not NULL this means we are not addressing the initial + data in the file. But this also means this data is already read + (since otherwise it is not possible to have a valid `data' pointer) + and all the data structures are initialized as well. In this case + we can simply walk the list of data records. */ + if (data != NULL + || (scn->data_read != 0 && (scn->flags & ELF_F_FILEDATA) == 0)) + { + /* We don't allow accessing any but the data read from the file + as raw. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return NULL; + } + + /* If the data for this section was not yet initialized do it now. */ + if (scn->data_read == 0) + { + /* First thing we do is to read the data from the file. There is + always a file (or memory region) associated with this descriptor + since otherwise the `data_read' flag would be set. */ + if (__libelf_set_rawdata (scn) != 0) + /* Something went wrong. The error value is already set. */ + return NULL; + } + + /* Return the first data element in the list. */ + return &scn->rawdata.d; +} +INTDEF(elf_rawdata) diff --git a/libelf/elf_rawfile.c b/libelf/elf_rawfile.c new file mode 100644 index 00000000..3f6dc3c8 --- /dev/null +++ b/libelf/elf_rawfile.c @@ -0,0 +1,51 @@ +/* Retrieve uninterpreted file contents. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +char * +elf_rawfile (elf, ptr) + Elf *elf; + size_t *ptr; +{ + if (elf == NULL) + { + /* No valid descriptor. */ + __libelf_seterrno (ELF_E_INVALID_HANDLE); + error_out: + if (ptr != NULL) + *ptr = 0; + return NULL; + } + + /* If the file is not mmap'ed and not previously loaded, do it now. */ + if (elf->map_address == NULL && __libelf_readall (elf) == NULL) + goto error_out; + + if (ptr != NULL) + *ptr = elf->maximum_size; + + return (char *) elf->map_address + elf->start_offset; +} diff --git a/libelf/elf_readall.c b/libelf/elf_readall.c new file mode 100644 index 00000000..d36da270 --- /dev/null +++ b/libelf/elf_readall.c @@ -0,0 +1,116 @@ +/* Read all of the file associated with the descriptor. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "libelfP.h" +#include "common.h" + + +static void +set_address (Elf *elf, size_t offset) +{ + if (elf->kind == ELF_K_AR) + { + Elf *child = elf->state.ar.children; + + while (child != NULL) + { + if (child->map_address == NULL) + { + child->map_address = elf->map_address; + child->start_offset -= offset; + if (child->kind == ELF_K_AR) + child->state.ar.offset -= offset; + + set_address (child, offset); + } + + child = child->next; + } + } +} + + +char * +__libelf_readall (elf) + Elf *elf; +{ + /* Get the file. */ + rwlock_wrlock (elf->lock); + + if (elf->map_address == NULL && unlikely (elf->fildes == -1)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + rwlock_unlock (elf->lock); + return NULL; + } + + /* If the file is not mmap'ed and not previously loaded, do it now. */ + if (elf->map_address == NULL) + { + char *mem; + + /* If this is an archive and we have derived descriptors get the + locks for all of them. */ + libelf_acquire_all (elf); + + /* Allocate all the memory we need. */ + mem = (char *) malloc (elf->maximum_size); + if (mem != NULL) + { + /* Read the file content. */ + if ((size_t) pread (elf->fildes, mem, elf->maximum_size, + elf->start_offset) != elf->maximum_size) + { + /* Something went wrong. */ + __libelf_seterrno (ELF_E_READ_ERROR); + free (mem); + } + else + { + /* Remember the address. */ + elf->map_address = mem; + + /* Also remember that we allocated the memory. */ + elf->flags |= ELF_F_MALLOCED; + + /* Propagate the information down to all children and + their children. */ + set_address (elf, elf->start_offset); + + /* Correct the own offsets. */ + if (elf->kind == ELF_K_AR) + elf->state.ar.offset -= elf->start_offset; + elf->start_offset = 0; + } + } + else + __libelf_seterrno (ELF_E_NOMEM); + + /* Free the locks on the children. */ + libelf_release_all (elf); + } + + rwlock_unlock (elf->lock); + + return (char *) elf->map_address; +} diff --git a/libelf/elf_strptr.c b/libelf/elf_strptr.c new file mode 100644 index 00000000..327adfd1 --- /dev/null +++ b/libelf/elf_strptr.c @@ -0,0 +1,122 @@ +/* Return string pointer from string section. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +char * +elf_strptr (elf, idx, offset) + Elf *elf; + size_t idx; + size_t offset; +{ + if (elf == NULL) + return NULL; + + if (elf->kind != ELF_K_ELF) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_rdlock (elf->lock); + + char *result = NULL; + Elf_Scn *strscn; + + /* Find the section in the list. */ + Elf_ScnList *runp = (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)) + ? &elf->state.elf32.scns : &elf->state.elf64.scns); + while (1) + { + if (idx < runp->max) + { + if (idx < runp->cnt) + strscn = &runp->data[idx]; + else + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + break; + } + + idx -= runp->max; + + runp = runp->next; + if (runp == NULL) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + } + + if (elf->class == ELFCLASS32) + { + if (unlikely (strscn->shdr.e32->sh_type != SHT_STRTAB)) + { + /* This is no string section. */ + __libelf_seterrno (ELF_E_INVALID_SECTION); + goto out; + } + + if (unlikely (offset >= strscn->shdr.e32->sh_size)) + { + /* The given offset is too big, it is beyond this section. */ + __libelf_seterrno (ELF_E_OFFSET_RANGE); + goto out; + } + } + else + { + if (unlikely (strscn->shdr.e64->sh_type != SHT_STRTAB)) + { + /* This is no string section. */ + __libelf_seterrno (ELF_E_INVALID_SECTION); + goto out; + } + + if (unlikely (offset >= strscn->shdr.e64->sh_size)) + { + /* The given offset is too big, it is beyond this section. */ + __libelf_seterrno (ELF_E_OFFSET_RANGE); + goto out; + } + } + + if (strscn->rawdata_base == NULL + /* Read the section data. */ + && __libelf_set_rawdata (strscn) != 0) + goto out; + + result = &strscn->rawdata_base[offset]; + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elf_strptr) diff --git a/libelf/elf_update.c b/libelf/elf_update.c new file mode 100644 index 00000000..5d6c6b7a --- /dev/null +++ b/libelf/elf_update.c @@ -0,0 +1,178 @@ +/* Update data structures for changes and write them out. + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Contributed by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +static off_t +write_file (Elf *elf, off_t size, int change_bo, size_t shnum) +{ + int class = elf->class; + + /* Adjust the size in any case. We do this even if we use `write'. + We cannot do this if this file is in an archive. We also don't + do it *now* if we are shortening the file since this would + prevent programs to use the data of the file in generating the + new file. We truncate the file later in this case. */ + if (elf->parent == NULL + && (elf->maximum_size == ~((size_t) 0) + || (size_t) size > elf->maximum_size) + && unlikely (ftruncate (elf->fildes, size) != 0)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + return -1; + } + + /* Try to map the file if this isn't done yet. */ + if (elf->map_address == NULL && elf->cmd == ELF_C_WRITE_MMAP) + { +#if _MUDFLAP + /* Mudflap doesn't grok that our mmap'd data is ok. */ +#else + elf->map_address = mmap (NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED, elf->fildes, 0); + if (unlikely (elf->map_address == MAP_FAILED)) + elf->map_address = NULL; +#endif + } + + if (elf->map_address != NULL) + { + /* The file is mmaped. */ + if ((class == ELFCLASS32 + ? __elf32_updatemmap (elf, change_bo, shnum) + : __elf64_updatemmap (elf, change_bo, shnum)) != 0) + /* Some problem while writing. */ + size = -1; + } + else + { + /* The file is not mmaped. */ + if ((class == ELFCLASS32 + ? __elf32_updatefile (elf, change_bo, shnum) + : __elf64_updatefile (elf, change_bo, shnum)) != 0) + /* Some problem while writing. */ + size = -1; + } + + if (size != -1 + && elf->parent == NULL + && elf->maximum_size != ~((size_t) 0) + && (size_t) size < elf->maximum_size + && unlikely (ftruncate (elf->fildes, size) != 0)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + size = -1; + } + + if (size != -1 && elf->parent == NULL) + elf->maximum_size = size; + + return size; +} + + +off_t +elf_update (elf, cmd) + Elf *elf; + Elf_Cmd cmd; +{ + size_t shnum; + off_t size; + int change_bo = 0; + + if (cmd != ELF_C_NULL + && cmd != ELF_C_WRITE + && unlikely (cmd != ELF_C_WRITE_MMAP)) + { + __libelf_seterrno (ELF_E_INVALID_CMD); + return -1; + } + + if (elf == NULL) + return -1; + + if (elf->kind != ELF_K_ELF) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1; + } + + rwlock_wrlock (elf->lock); + + /* Make sure we have an ELF header. */ + if (elf->state.elf.ehdr == NULL) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + size = -1; + goto out; + } + + /* Determine the number of sections. */ + shnum = (elf->state.elf.scns_last->cnt == 0 + ? 0 + : 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt - 1].index); + + /* Update the ELF descriptor. First, place the program header. It + will come right after the ELF header. The count the size of all + sections and finally place the section table. */ + size = (elf->class == ELFCLASS32 + ? __elf32_updatenull (elf, &change_bo, shnum) + : __elf64_updatenull (elf, &change_bo, shnum)); + if (likely (size != -1) + /* See whether we actually have to write out the data. */ + && (cmd == ELF_C_WRITE || cmd == ELF_C_WRITE_MMAP)) + { + if (elf->cmd != ELF_C_RDWR + && elf->cmd != ELF_C_RDWR_MMAP + && elf->cmd != ELF_C_WRITE + && unlikely (elf->cmd != ELF_C_WRITE_MMAP)) + { + __libelf_seterrno (ELF_E_UPDATE_RO); + size = -1; + } + else if (unlikely (elf->fildes == -1)) + { + /* We closed the file already. */ + __libelf_seterrno (ELF_E_FD_DISABLED); + size = -1; + } + else + { + if (elf->parent != NULL) + { + extern int puts (const char *); + puts ("this is an archive member"); + } + + size = write_file (elf, size, change_bo, shnum); + } + } + + out: + rwlock_unlock (elf->lock); + + return size; +} diff --git a/libelf/elf_version.c b/libelf/elf_version.c new file mode 100644 index 00000000..16bfce10 --- /dev/null +++ b/libelf/elf_version.c @@ -0,0 +1,58 @@ +/* Coordinate ELF library and application versions. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +/* Is the version initialized? */ +int __libelf_version_initialized; + +/* Currently selected version. */ +unsigned int __libelf_version = EV_CURRENT; + + +unsigned int +elf_version (version) + unsigned int version; +{ + if (version == EV_NONE) + return __libelf_version; + + if (likely (version < EV_NUM)) + { + /* Phew, we know this version. */ + unsigned int last_version = __libelf_version; + + /* Store the new version. */ + __libelf_version = version; + + /* Signal that the version is now initialized. */ + __libelf_version_initialized = 1; + + /* And return the last version. */ + return last_version; + } + + /* We cannot handle this version. */ + __libelf_seterrno (ELF_E_UNKNOWN_VERSION); + return EV_NONE; +} +INTDEF(elf_version) diff --git a/libelf/exttypes.h b/libelf/exttypes.h new file mode 100644 index 00000000..b6bde829 --- /dev/null +++ b/libelf/exttypes.h @@ -0,0 +1,86 @@ +/* External ELF types. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _EXTTYPES_H +#define _EXTTYPES_H 1 + +/* Integral types. */ +typedef char Elf32_Ext_Addr[ELF32_FSZ_ADDR]; +typedef char Elf32_Ext_Off[ELF32_FSZ_OFF]; +typedef char Elf32_Ext_Half[ELF32_FSZ_HALF]; +typedef char Elf32_Ext_Sword[ELF32_FSZ_SWORD]; +typedef char Elf32_Ext_Word[ELF32_FSZ_WORD]; +typedef char Elf32_Ext_Sxword[ELF32_FSZ_SXWORD]; +typedef char Elf32_Ext_Xword[ELF32_FSZ_XWORD]; + +typedef char Elf64_Ext_Addr[ELF64_FSZ_ADDR]; +typedef char Elf64_Ext_Off[ELF64_FSZ_OFF]; +typedef char Elf64_Ext_Half[ELF64_FSZ_HALF]; +typedef char Elf64_Ext_Sword[ELF64_FSZ_SWORD]; +typedef char Elf64_Ext_Word[ELF64_FSZ_WORD]; +typedef char Elf64_Ext_Sxword[ELF64_FSZ_SXWORD]; +typedef char Elf64_Ext_Xword[ELF64_FSZ_XWORD]; + + +/* Define the composed types. */ +#define START(Bits, Name, EName) typedef struct { +#define END(Bits, Name) } ElfW2(Bits, Name) +#define TYPE_NAME(Type, Name) Type Name; +#define TYPE_EXTRA(Text) Text +#define TYPE_XLATE(Text) + +/* Get the abstract definitions. */ +#include "abstract.h" + +/* And define the types. */ +Ehdr32 (Ext_); +Phdr32 (Ext_); +Shdr32 (Ext_); +Sym32 (Ext_); +Rel32 (Ext_); +Rela32 (Ext_); +Note32 (Ext_); +Dyn32 (Ext_); +Verdef32 (Ext_); +Verdaux32 (Ext_); +Verneed32 (Ext_); +Vernaux32 (Ext_); +Syminfo32 (Ext_); +Move32 (Ext_); + +Ehdr64 (Ext_); +Phdr64 (Ext_); +Shdr64 (Ext_); +Sym64 (Ext_); +Rel64 (Ext_); +Rela64 (Ext_); +Note64 (Ext_); +Dyn64 (Ext_); +Verdef64 (Ext_); +Verdaux64 (Ext_); +Verneed64 (Ext_); +Vernaux64 (Ext_); +Syminfo64 (Ext_); +Move64 (Ext_); + +#undef START +#undef END +#undef TYPE_NAME +#undef TYPE_EXTRA +#undef TYPE_XLATE + +#endif /* exttypes.h */ diff --git a/libelf/gelf.h b/libelf/gelf.h new file mode 100644 index 00000000..299d6c83 --- /dev/null +++ b/libelf/gelf.h @@ -0,0 +1,308 @@ +/* This file defines generic ELF types, structures, and macros. + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005 Red Hat, 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _GELF_H +#define _GELF_H 1 + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Class independent type definitions. Correctly speaking this is not + true. We assume that 64-bit binaries are the largest class and + therefore all other classes can be represented without loss. */ + +/* Type for a 16-bit quantity. */ +typedef Elf64_Half GElf_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef Elf64_Word GElf_Word; +typedef Elf64_Sword GElf_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef Elf64_Xword GElf_Xword; +typedef Elf64_Sxword GElf_Sxword; + +/* Type of addresses. */ +typedef Elf64_Addr GElf_Addr; + +/* Type of file offsets. */ +typedef Elf64_Off GElf_Off; + + +/* The ELF file header. This appears at the start of every ELF file. */ +typedef Elf64_Ehdr GElf_Ehdr; + +/* Section header. */ +typedef Elf64_Shdr GElf_Shdr; + +/* Section index. */ +/* XXX This should probably be a larger type in preparation of times when + regular section indices can be larger. */ +typedef Elf64_Section GElf_Section; + +/* Symbol table entry. */ +typedef Elf64_Sym GElf_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ +typedef Elf64_Syminfo GElf_Syminfo; + +/* Relocation table entry without addend (in section of type SHT_REL). */ +typedef Elf64_Rel GElf_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ +typedef Elf64_Rela GElf_Rela; + +/* Program segment header. */ +typedef Elf64_Phdr GElf_Phdr; + +/* Dynamic section entry. */ +typedef Elf64_Dyn GElf_Dyn; + + +/* Version definition sections. */ +typedef Elf64_Verdef GElf_Verdef; + +/* Auxialiary version information. */ +typedef Elf64_Verdaux GElf_Verdaux; + +/* Version dependency section. */ +typedef Elf64_Verneed GElf_Verneed; + +/* Auxiliary needed version information. */ +typedef Elf64_Vernaux GElf_Vernaux; + + +/* Type for version symbol information. */ +typedef Elf64_Versym GElf_Versym; + + +/* Auxiliary vector. */ +typedef Elf64_auxv_t GElf_auxv_t; + + +/* Note section contents. */ +typedef Elf64_Nhdr GElf_Nhdr; + + +/* Move structure. */ +typedef Elf64_Move GElf_Move; + + +/* Library list structure. */ +typedef Elf64_Lib GElf_Lib; + + +/* How to extract and insert information held in the st_info field. */ + +#define GELF_ST_BIND(val) ELF64_ST_BIND (val) +#define GELF_ST_TYPE(val) ELF64_ST_TYPE (val) +#define GELF_ST_INFO(bind, type) ELF64_ST_INFO (bind, type) + +/* How to extract information held in the st_other field. */ + +#define GELF_ST_VISIBILITY(val) ELF64_ST_VISIBILITY (val) + + +/* How to extract and insert information held in the r_info field. */ + +#define GELF_R_SYM(info) ELF64_R_SYM (info) +#define GELF_R_TYPE(info) ELF64_R_TYPE (info) +#define GELF_R_INFO(sym, type) ELF64_R_INFO (sym, type) + + +/* How to extract and insert information held in the m_info field. */ +#define GELF_M_SYM(info) ELF64_M_SYM (info) +#define GELF_M_SIZE(info) ELF64_M_SIZE (info) +#define GELF_M_INFO(sym, size) ELF64_M_INFO (sym, size) + + +/* Get class of the file associated with ELF. */ +extern int gelf_getclass (Elf *__elf); + + +/* Return size of array of COUNT elemeents of the type denoted by TYPE + in the external representation. The binary class is taken from ELF. + The result is based on version VERSION of the ELF standard. */ +extern size_t gelf_fsize (Elf *__elf, Elf_Type __type, size_t __count, + unsigned int __version); + +/* Retrieve object file header. */ +extern GElf_Ehdr *gelf_getehdr (Elf *__elf, GElf_Ehdr *__dest); + +/* Update the ELF header. */ +extern int gelf_update_ehdr (Elf *__elf, GElf_Ehdr *__src); + +/* Create new ELF header if none exists. */ +extern unsigned long int gelf_newehdr (Elf *__elf, int __class); + +/* Retrieve section header. */ +extern GElf_Shdr *gelf_getshdr (Elf_Scn *__scn, GElf_Shdr *__dst); + +/* Update section header. */ +extern int gelf_update_shdr (Elf_Scn *__scn, GElf_Shdr *__src); + +/* Retrieve program header table entry. */ +extern GElf_Phdr *gelf_getphdr (Elf *__elf, int __ndx, GElf_Phdr *__dst); + +/* Update the program header. */ +extern int gelf_update_phdr (Elf *__elf, int __ndx, GElf_Phdr *__src); + +/* Create new program header with PHNUM entries. */ +extern unsigned long int gelf_newphdr (Elf *__elf, size_t __phnum); + + +/* Convert data structure from the representation in the file represented + by ELF to their memory representation. */ +extern Elf_Data *gelf_xlatetom (Elf *__elf, Elf_Data *__dest, + const Elf_Data *__src, unsigned int __encode); + +/* Convert data structure from to the representation in memory + represented by ELF file representation. */ +extern Elf_Data *gelf_xlatetof (Elf *__elf, Elf_Data *__dest, + const Elf_Data *__src, unsigned int __encode); + + +/* Retrieve REL relocation info at the given index. */ +extern GElf_Rel *gelf_getrel (Elf_Data *__data, int __ndx, GElf_Rel *__dst); + +/* Retrieve RELA relocation info at the given index. */ +extern GElf_Rela *gelf_getrela (Elf_Data *__data, int __ndx, GElf_Rela *__dst); + +/* Update REL relocation information at given index. */ +extern int gelf_update_rel (Elf_Data *__dst, int __ndx, GElf_Rel *__src); + +/* Update RELA relocation information at given index. */ +extern int gelf_update_rela (Elf_Data *__dst, int __ndx, GElf_Rela *__src); + + +/* Retrieve symbol information from the symbol table at the given index. */ +extern GElf_Sym *gelf_getsym (Elf_Data *__data, int __ndx, GElf_Sym *__dst); + +/* Update symbol information in the symbol table at the given index. */ +extern int gelf_update_sym (Elf_Data *__data, int __ndx, GElf_Sym *__src); + + +/* Retrieve symbol information and separate section index from the + symbol table at the given index. */ +extern GElf_Sym *gelf_getsymshndx (Elf_Data *__symdata, Elf_Data *__shndxdata, + int __ndx, GElf_Sym *__sym, + Elf32_Word *__xshndx); + +/* Update symbol information and separate section index in the symbol + table at the given index. */ +extern int gelf_update_symshndx (Elf_Data *__symdata, Elf_Data *__shndxdata, + int __ndx, GElf_Sym *__sym, + Elf32_Word __xshndx); + + +/* Retrieve additional symbol information from the symbol table at the + given index. */ +extern GElf_Syminfo *gelf_getsyminfo (Elf_Data *__data, int __ndx, + GElf_Syminfo *__dst); + +/* Update additional symbol information in the symbol table at the + given index. */ +extern int gelf_update_syminfo (Elf_Data *__data, int __ndx, + GElf_Syminfo *__src); + + +/* Get information from dynamic table at the given index. */ +extern GElf_Dyn *gelf_getdyn (Elf_Data *__data, int __ndx, GElf_Dyn *__dst); + +/* Update information in dynamic table at the given index. */ +extern int gelf_update_dyn (Elf_Data *__dst, int __ndx, GElf_Dyn *__src); + + +/* Get move structure at the given index. */ +extern GElf_Move *gelf_getmove (Elf_Data *__data, int __ndx, GElf_Move *__dst); + +/* Update move structure at the given index. */ +extern int gelf_update_move (Elf_Data *__data, int __ndx, + GElf_Move *__src); + + +/* Get library from table at the given index. */ +extern GElf_Lib *gelf_getlib (Elf_Data *__data, int __ndx, GElf_Lib *__dst); + +/* Update library in table at the given index. */ +extern int gelf_update_lib (Elf_Data *__data, int __ndx, GElf_Lib *__src); + + + +/* Retrieve symbol version information at given index. */ +extern GElf_Versym *gelf_getversym (Elf_Data *__data, int __ndx, + GElf_Versym *__dst); + +/* Update symbol version information. */ +extern int gelf_update_versym (Elf_Data *__data, int __ndx, + GElf_Versym *__src); + + +/* Retrieve required symbol version information at given offset. */ +extern GElf_Verneed *gelf_getverneed (Elf_Data *__data, int __offset, + GElf_Verneed *__dst); + +/* Update required symbol version information. */ +extern int gelf_update_verneed (Elf_Data *__data, int __offset, + GElf_Verneed *__src); + +/* Retrieve additional required symbol version information at given offset. */ +extern GElf_Vernaux *gelf_getvernaux (Elf_Data *__data, int __offset, + GElf_Vernaux *__dst); + +/* Update additional required symbol version information. */ +extern int gelf_update_vernaux (Elf_Data *__data, int __offset, + GElf_Vernaux *__src); + + +/* Retrieve symbol version definition information at given offset. */ +extern GElf_Verdef *gelf_getverdef (Elf_Data *__data, int __offset, + GElf_Verdef *__dst); + +/* Update symbol version definition information. */ +extern int gelf_update_verdef (Elf_Data *__data, int __offset, + GElf_Verdef *__src); + +/* Retrieve additional symbol version definition information at given + offset. */ +extern GElf_Verdaux *gelf_getverdaux (Elf_Data *__data, int __offset, + GElf_Verdaux *__dst); + +/* Update additional symbol version definition information. */ +extern int gelf_update_verdaux (Elf_Data *__data, int __offset, + GElf_Verdaux *__src); + + +/* Retrieve uninterpreted chunk of the file contents. */ +extern char *gelf_rawchunk (Elf *__elf, GElf_Off __offset, GElf_Word __size); + +/* Release uninterpreted chunk of the file contents. */ +extern void gelf_freechunk (Elf *__elf, char *__ptr); + + +/* Compute simple checksum from permanent parts of the ELF file. */ +extern long int gelf_checksum (Elf *__elf); + +#ifdef __cplusplus +} +#endif + +#endif /* gelf.h */ diff --git a/libelf/gelf_checksum.c b/libelf/gelf_checksum.c new file mode 100644 index 00000000..bbd04df9 --- /dev/null +++ b/libelf/gelf_checksum.c @@ -0,0 +1,37 @@ +/* Convert from file to memory representation. Generic ELF version. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +long int +gelf_checksum (elf) + Elf *elf; +{ + if (elf == NULL) + return -1l; + + return (elf->class == ELFCLASS32 + ? INTUSE(elf32_checksum) (elf) : INTUSE(elf64_checksum) (elf)); +} diff --git a/libelf/gelf_freechunk.c b/libelf/gelf_freechunk.c new file mode 100644 index 00000000..c47ec9aa --- /dev/null +++ b/libelf/gelf_freechunk.c @@ -0,0 +1,45 @@ +/* Release uninterpreted chunk of the file contents. + Copyright (C) 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 2002. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +void +gelf_freechunk (elf, ptr) + Elf *elf; + char *ptr; +{ + if (elf == NULL) + /* No valid descriptor. */ + return; + + /* We do not have to do anything if the pointer returned by + gelf_rawchunk points into the memory allocated for the ELF + descriptor. */ + if (ptr < (char *) elf->map_address + elf->start_offset + || ptr >= ((char *) elf->map_address + elf->start_offset + + elf->maximum_size)) + free (ptr); +} diff --git a/libelf/gelf_fsize.c b/libelf/gelf_fsize.c new file mode 100644 index 00000000..0432ba0b --- /dev/null +++ b/libelf/gelf_fsize.c @@ -0,0 +1,96 @@ +/* Return the size of an object file type. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +/* These are the sizes for all the known types. */ +const size_t __libelf_type_sizes[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] = +{ + /* We have no entry for EV_NONE siince we have to set an error. */ + [EV_CURRENT - 1] = { + [ELFCLASS32 - 1] = { +#define TYPE_SIZES(LIBELFBITS) \ + [ELF_T_ADDR] = ELFW2(LIBELFBITS, FSZ_ADDR), \ + [ELF_T_OFF] = ELFW2(LIBELFBITS, FSZ_OFF), \ + [ELF_T_BYTE] = 1, \ + [ELF_T_HALF] = ELFW2(LIBELFBITS, FSZ_HALF), \ + [ELF_T_WORD] = ELFW2(LIBELFBITS, FSZ_WORD), \ + [ELF_T_SWORD] = ELFW2(LIBELFBITS, FSZ_SWORD), \ + [ELF_T_XWORD] = ELFW2(LIBELFBITS, FSZ_XWORD), \ + [ELF_T_SXWORD] = ELFW2(LIBELFBITS, FSZ_SXWORD), \ + [ELF_T_EHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Ehdr)), \ + [ELF_T_SHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Shdr)), \ + [ELF_T_SYM] = sizeof (ElfW2(LIBELFBITS, Ext_Sym)), \ + [ELF_T_REL] = sizeof (ElfW2(LIBELFBITS, Ext_Rel)), \ + [ELF_T_RELA] = sizeof (ElfW2(LIBELFBITS, Ext_Rela)), \ + [ELF_T_PHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Phdr)), \ + [ELF_T_DYN] = sizeof (ElfW2(LIBELFBITS, Ext_Dyn)), \ + [ELF_T_VDEF] = sizeof (ElfW2(LIBELFBITS, Ext_Verdef)), \ + [ELF_T_VDAUX] = sizeof (ElfW2(LIBELFBITS, Ext_Verdaux)), \ + [ELF_T_VNEED] = sizeof (ElfW2(LIBELFBITS, Ext_Verneed)), \ + [ELF_T_VNAUX] = sizeof (ElfW2(LIBELFBITS, Ext_Vernaux)), \ + [ELF_T_NHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Nhdr)), \ + [ELF_T_SYMINFO] = sizeof (ElfW2(LIBELFBITS, Ext_Syminfo)), \ + [ELF_T_MOVE] = sizeof (ElfW2(LIBELFBITS, Ext_Move)) + TYPE_SIZES (32) + }, + [ELFCLASS64 - 1] = { + TYPE_SIZES (64) + } + } +}; + + +size_t +gelf_fsize (elf, type, count, version) + Elf *elf; + Elf_Type type; + size_t count; + unsigned int version; +{ + /* We do not have differences between file and memory sizes. Better + not since otherwise `mmap' would not work. */ + if (elf == NULL) + return 0; + + if (version == EV_NONE || version >= EV_NUM) + { + __libelf_seterrno (ELF_E_UNKNOWN_VERSION); + return 0; + } + + if (type >= ELF_T_NUM) + { + __libelf_seterrno (ELF_E_UNKNOWN_TYPE); + return 0; + } + +#if EV_NUM != 2 + return count * __libelf_type_sizes[version - 1][elf->class - 1][type]; +#else + return count * __libelf_type_sizes[0][elf->class - 1][type]; +#endif +} +INTDEF(gelf_fsize) diff --git a/libelf/gelf_getclass.c b/libelf/gelf_getclass.c new file mode 100644 index 00000000..2ae1b329 --- /dev/null +++ b/libelf/gelf_getclass.c @@ -0,0 +1,33 @@ +/* Return the class of file associated with the descriptor. + Copyright (C) 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +int +gelf_getclass (elf) + Elf *elf; +{ + return elf == NULL || elf->kind != ELF_K_ELF ? ELFCLASSNONE : elf->class; +} diff --git a/libelf/gelf_getdyn.c b/libelf/gelf_getdyn.c new file mode 100644 index 00000000..d75744ea --- /dev/null +++ b/libelf/gelf_getdyn.c @@ -0,0 +1,99 @@ +/* Get information from dynamic table at the given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_Dyn * +gelf_getdyn (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Dyn *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + GElf_Dyn *result = NULL; + Elf *elf; + + if (data_scn == NULL) + return NULL; + + if (unlikely (data_scn->d.d_type != ELF_T_DYN)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + elf = data_scn->s->elf; + + rwlock_rdlock (elf->lock); + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + if (elf->class == ELFCLASS32) + { + Elf32_Dyn *src; + + /* Here it gets a bit more complicated. The format of the symbol + table entries has to be adopted. The user better has provided + a buffer where we can store the information. While copying the + data we are converting the format. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_Dyn) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + src = &((Elf32_Dyn *) data_scn->d.d_buf)[ndx]; + + /* This might look like a simple copy operation but it's + not. There are zero- and sign-extensions going on. */ + dst->d_tag = src->d_tag; + /* It OK to copy `d_val' since `d_ptr' has the same size. */ + dst->d_un.d_val = src->d_un.d_val; + } + else + { + /* If this is a 64 bit object it's easy. */ + assert (sizeof (GElf_Dyn) == sizeof (Elf64_Dyn)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely ((ndx + 1) * sizeof (GElf_Dyn) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + *dst = ((GElf_Dyn *) data_scn->d.d_buf)[ndx]; + } + + result = dst; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/libelf/gelf_getehdr.c b/libelf/gelf_getehdr.c new file mode 100644 index 00000000..5c323dc5 --- /dev/null +++ b/libelf/gelf_getehdr.c @@ -0,0 +1,88 @@ +/* Get ELF header. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "libelfP.h" + + +GElf_Ehdr * +gelf_getehdr (elf, dest) + Elf *elf; + GElf_Ehdr *dest; +{ + GElf_Ehdr *result = NULL; + + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_rdlock (elf->lock); + + /* The following is an optimization: the ehdr element is at the same + position in both the elf32 and elf64 structure. */ + if (offsetof (struct Elf, state.elf32.ehdr) + != offsetof (struct Elf, state.elf64.ehdr)) + abort (); + /* Just pick one of the values. */ + if (unlikely (elf->state.elf64.ehdr == NULL)) + /* Maybe no ELF header was created yet. */ + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + else if (elf->class == ELFCLASS32) + { + Elf32_Ehdr *ehdr = elf->state.elf32.ehdr; + + /* Convert the 32-bit struct to an 64-bit one. */ + memcpy (dest->e_ident, ehdr->e_ident, EI_NIDENT); +#define COPY(name) \ + dest->name = ehdr->name + COPY (e_type); + COPY (e_machine); + COPY (e_version); + COPY (e_entry); + COPY (e_phoff); + COPY (e_shoff); + COPY (e_flags); + COPY (e_ehsize); + COPY (e_phentsize); + COPY (e_phnum); + COPY (e_shentsize); + COPY (e_shnum); + COPY (e_shstrndx); + + result = dest; + } + else + result = memcpy (dest, elf->state.elf64.ehdr, sizeof (*dest)); + + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(gelf_getehdr) diff --git a/libelf/gelf_getlib.c b/libelf/gelf_getlib.c new file mode 100644 index 00000000..9366c79a --- /dev/null +++ b/libelf/gelf_getlib.c @@ -0,0 +1,68 @@ +/* Get library from table at the given index. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_Lib * +gelf_getlib (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Lib *dst; +{ + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_LIB)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + rwlock_rdlock (data_scn->s->elf->lock); + + /* The on disk format of Elf32_Lib and Elf64_Lib is identical. So + we can simplify things significantly. */ + assert (sizeof (GElf_Lib) == sizeof (Elf32_Lib)); + assert (sizeof (GElf_Lib) == sizeof (Elf64_Lib)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + GElf_Lib *result = NULL; + if (unlikely ((ndx + 1) * sizeof (GElf_Lib) > data->d_size)) + __libelf_seterrno (ELF_E_INVALID_INDEX); + else + { + *dst = ((GElf_Lib *) data->d_buf)[ndx]; + + result = dst; + } + + rwlock_unlock (data_scn->s->elf->lock); + + return result; +} diff --git a/libelf/gelf_getmove.c b/libelf/gelf_getmove.c new file mode 100644 index 00000000..a3b96bbc --- /dev/null +++ b/libelf/gelf_getmove.c @@ -0,0 +1,70 @@ +/* Get move structure at the given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_Move * +gelf_getmove (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Move *dst; +{ + GElf_Move *result = NULL; + Elf *elf; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_MOVE)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Move) == sizeof (Elf32_Move)); + assert (sizeof (GElf_Move) == sizeof (Elf64_Move)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely ((ndx + 1) * sizeof (GElf_Move) > data->d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + elf = ((Elf_Data_Scn *) data)->s->elf; + rwlock_rdlock (elf->lock); + + *dst = ((GElf_Move *) data->d_buf)[ndx]; + + rwlock_unlock (elf->lock); + + result = dst; + + out: + return result; +} diff --git a/libelf/gelf_getphdr.c b/libelf/gelf_getphdr.c new file mode 100644 index 00000000..fd033e56 --- /dev/null +++ b/libelf/gelf_getphdr.c @@ -0,0 +1,117 @@ +/* Return program header table entry. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +GElf_Phdr * +gelf_getphdr (elf, ndx, dst) + Elf *elf; + int ndx; + GElf_Phdr *dst; +{ + GElf_Phdr *result = NULL; + + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + if (dst == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + return NULL; + } + + rwlock_rdlock (elf->lock); + + if (elf->class == ELFCLASS32) + { + /* Copy the elements one-by-one. */ + Elf32_Phdr *phdr = elf->state.elf32.phdr; + + if (phdr == NULL) + { + phdr = INTUSE(elf32_getphdr) (elf); + if (phdr == NULL) + /* The error number is already set. */ + goto out; + } + + /* Test whether the index is ok. */ + if (ndx >= elf->state.elf32.ehdr->e_phnum) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + /* We know the result now. */ + result = dst; + + /* Now correct the pointer to point to the correct element. */ + phdr += ndx; + +#define COPY(Name) result->Name = phdr->Name + COPY (p_type); + COPY (p_offset); + COPY (p_vaddr); + COPY (p_paddr); + COPY (p_filesz); + COPY (p_memsz); + COPY (p_flags); + COPY (p_align); + } + else + { + /* Copy the elements one-by-one. */ + Elf64_Phdr *phdr = elf->state.elf64.phdr; + + if (phdr == NULL) + { + phdr = INTUSE(elf64_getphdr) (elf); + if (phdr == NULL) + /* The error number is already set. */ + goto out; + } + + /* Test whether the index is ok. */ + if (ndx >= elf->state.elf64.ehdr->e_phnum) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + /* We only have to copy the data. */ + result = memcpy (dst, phdr + ndx, sizeof (GElf_Phdr)); + } + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/libelf/gelf_getrel.c b/libelf/gelf_getrel.c new file mode 100644 index 00000000..7dc78a7e --- /dev/null +++ b/libelf/gelf_getrel.c @@ -0,0 +1,96 @@ +/* Get REL relocation information at given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +GElf_Rel * +gelf_getrel (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Rel *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + GElf_Rel *result; + + if (data_scn == NULL) + return NULL; + + if (unlikely (ndx < 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return NULL; + } + + if (unlikely (data_scn->d.d_type != ELF_T_REL)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + scn = data_scn->s; + + rwlock_rdlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + /* We have to convert the data. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_Rel) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + result = NULL; + } + else + { + Elf32_Rel *src = &((Elf32_Rel *) data_scn->d.d_buf)[ndx]; + + dst->r_offset = src->r_offset; + dst->r_info = GELF_R_INFO (ELF32_R_SYM (src->r_info), + ELF32_R_TYPE (src->r_info)); + + result = dst; + } + } + else + { + /* Simply copy the data after we made sure we are actually getting + correct data. */ + if (unlikely ((ndx + 1) * sizeof (Elf64_Rel) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + result = NULL; + } + else + result = memcpy (dst, &((Elf64_Rel *) data_scn->d.d_buf)[ndx], + sizeof (Elf64_Rel)); + } + + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/libelf/gelf_getrela.c b/libelf/gelf_getrela.c new file mode 100644 index 00000000..fb94b008 --- /dev/null +++ b/libelf/gelf_getrela.c @@ -0,0 +1,97 @@ +/* Get RELA relocation information at given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +GElf_Rela * +gelf_getrela (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Rela *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + GElf_Rela *result; + + if (data_scn == NULL) + return NULL; + + if (unlikely (ndx < 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return NULL; + } + + if (unlikely (data_scn->d.d_type != ELF_T_RELA)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + scn = data_scn->s; + + rwlock_rdlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + /* We have to convert the data. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_Rela) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + result = NULL; + } + else + { + Elf32_Rela *src = &((Elf32_Rela *) data_scn->d.d_buf)[ndx]; + + dst->r_offset = src->r_offset; + dst->r_info = GELF_R_INFO (ELF32_R_SYM (src->r_info), + ELF32_R_TYPE (src->r_info)); + dst->r_addend = src->r_addend; + + result = dst; + } + } + else + { + /* Simply copy the data after we made sure we are actually getting + correct data. */ + if (unlikely ((ndx + 1) * sizeof (Elf64_Rela) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + result = NULL; + } + else + result = memcpy (dst, &((Elf64_Rela *) data_scn->d.d_buf)[ndx], + sizeof (Elf64_Rela)); + } + + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/libelf/gelf_getshdr.c b/libelf/gelf_getshdr.c new file mode 100644 index 00000000..4ea5886d --- /dev/null +++ b/libelf/gelf_getshdr.c @@ -0,0 +1,91 @@ +/* Return section header. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +GElf_Shdr * +gelf_getshdr (scn, dst) + Elf_Scn *scn; + GElf_Shdr *dst; +{ + GElf_Shdr *result = NULL; + + if (scn == NULL) + return NULL; + + if (dst == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + return NULL; + } + + rwlock_rdlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + /* Copy the elements one-by-one. */ + Elf32_Shdr *shdr = scn->shdr.e32 ?: INTUSE(elf32_getshdr) (scn); + + if (shdr == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + goto out; + } + +#define COPY(name) \ + dst->name = shdr->name + COPY (sh_name); + COPY (sh_type); + COPY (sh_flags); + COPY (sh_addr); + COPY (sh_offset); + COPY (sh_size); + COPY (sh_link); + COPY (sh_info); + COPY (sh_addralign); + COPY (sh_entsize); + + result = dst; + } + else + { + Elf64_Shdr *shdr = scn->shdr.e64 ?: INTUSE(elf64_getshdr) (scn); + + if (shdr == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + goto out; + } + + /* We only have to copy the data. */ + result = memcpy (dst, shdr, sizeof (GElf_Shdr)); + } + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} +INTDEF(gelf_getshdr) diff --git a/libelf/gelf_getsym.c b/libelf/gelf_getsym.c new file mode 100644 index 00000000..90536c60 --- /dev/null +++ b/libelf/gelf_getsym.c @@ -0,0 +1,105 @@ +/* Get symbol information from symbol table at the given index. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_Sym * +gelf_getsym (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Sym *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + GElf_Sym *result = NULL; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_SYM)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_rdlock (data_scn->s->elf->lock); + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + if (data_scn->s->elf->class == ELFCLASS32) + { + Elf32_Sym *src; + + /* Here it gets a bit more complicated. The format of the symbol + table entries has to be adopted. The user better has provided + a buffer where we can store the information. While copying the + data we are converting the format. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_Sym) > data->d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + src = &((Elf32_Sym *) data->d_buf)[ndx]; + + /* This might look like a simple copy operation but it's + not. There are zero- and sign-extensions going on. */ +#define COPY(name) \ + dst->name = src->name + COPY (st_name); + /* Please note that we can simply copy the `st_info' element since + the definitions of ELFxx_ST_BIND and ELFxx_ST_TYPE are the same + for the 64 bit variant. */ + COPY (st_info); + COPY (st_other); + COPY (st_shndx); + COPY (st_value); + COPY (st_size); + } + else + { + /* If this is a 64 bit object it's easy. */ + assert (sizeof (GElf_Sym) == sizeof (Elf64_Sym)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely ((ndx + 1) * sizeof (GElf_Sym) > data->d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + *dst = ((GElf_Sym *) data->d_buf)[ndx]; + } + + result = dst; + + out: + rwlock_unlock (data_scn->s->elf->lock); + + return result; +} +INTDEF(gelf_getsym) diff --git a/libelf/gelf_getsyminfo.c b/libelf/gelf_getsyminfo.c new file mode 100644 index 00000000..70cfdcd3 --- /dev/null +++ b/libelf/gelf_getsyminfo.c @@ -0,0 +1,68 @@ +/* Get additional symbol information from symbol table at the given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_Syminfo * +gelf_getsyminfo (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Syminfo *dst; +{ + GElf_Syminfo *result = NULL; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_SYMINFO)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Syminfo) == sizeof (Elf32_Syminfo)); + assert (sizeof (GElf_Syminfo) == sizeof (Elf64_Syminfo)); + + rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely ((ndx + 1) * sizeof (GElf_Syminfo) > data->d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + *dst = ((GElf_Syminfo *) data->d_buf)[ndx]; + + result = dst; + + out: + rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); + + return result; +} diff --git a/libelf/gelf_getsymshndx.c b/libelf/gelf_getsymshndx.c new file mode 100644 index 00000000..856f4919 --- /dev/null +++ b/libelf/gelf_getsymshndx.c @@ -0,0 +1,128 @@ +/* Get symbol information and separate section index from symbol table + at the given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_Sym * +gelf_getsymshndx (symdata, shndxdata, ndx, dst, dstshndx) + Elf_Data *symdata; + Elf_Data *shndxdata; + int ndx; + GElf_Sym *dst; + Elf32_Word *dstshndx; +{ + Elf_Data_Scn *symdata_scn = (Elf_Data_Scn *) symdata; + Elf_Data_Scn *shndxdata_scn = (Elf_Data_Scn *) shndxdata; + GElf_Sym *result = NULL; + Elf32_Word shndx = 0; + + if (symdata == NULL) + return NULL; + + if (unlikely (symdata->d_type != ELF_T_SYM) + || (likely (shndxdata_scn != NULL) + && unlikely (shndxdata->d_type != ELF_T_WORD))) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_rdlock (symdata_scn->s->elf->lock); + + /* The user is not required to pass a data descriptor for an extended + section index table. */ + if (likely (shndxdata_scn != NULL)) + { + if (unlikely ((ndx + 1) * sizeof (Elf32_Word) > shndxdata_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + shndx = ((Elf32_Word *) shndxdata_scn->d.d_buf)[ndx]; + } + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + if (symdata_scn->s->elf->class == ELFCLASS32) + { + Elf32_Sym *src; + + /* Here it gets a bit more complicated. The format of the symbol + table entries has to be adopted. The user better has provided + a buffer where we can store the information. While copying the + data we are converting the format. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_Sym) > symdata->d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + src = &((Elf32_Sym *) symdata->d_buf)[ndx]; + + /* This might look like a simple copy operation but it's + not. There are zero- and sign-extensions going on. */ +#define COPY(name) \ + dst->name = src->name + COPY (st_name); + /* Please note that we can simply copy the `st_info' element since + the definitions of ELFxx_ST_BIND and ELFxx_ST_TYPE are the same + for the 64 bit variant. */ + COPY (st_info); + COPY (st_other); + COPY (st_shndx); + COPY (st_value); + COPY (st_size); + } + else + { + /* If this is a 64 bit object it's easy. */ + assert (sizeof (GElf_Sym) == sizeof (Elf64_Sym)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely ((ndx + 1) * sizeof (GElf_Sym) > symdata->d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + *dst = ((GElf_Sym *) symdata->d_buf)[ndx]; + } + + /* Now we can store the section index. */ + if (dstshndx != NULL) + *dstshndx = shndx; + + result = dst; + + out: + rwlock_unlock (symdata_scn->s->elf->lock); + + return result; +} diff --git a/libelf/gelf_getverdaux.c b/libelf/gelf_getverdaux.c new file mode 100644 index 00000000..0a14b121 --- /dev/null +++ b/libelf/gelf_getverdaux.c @@ -0,0 +1,70 @@ +/* Get additional symbol version definition information at the given offset. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_Verdaux * +gelf_getverdaux (data, offset, dst) + Elf_Data *data; + int offset; + GElf_Verdaux *dst; +{ + GElf_Verdaux *result; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_VDEF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* It's easy to handle this type. It has the same size for 32 and + 64 bit objects. */ + assert (sizeof (GElf_Verdaux) == sizeof (Elf32_Verdaux)); + assert (sizeof (GElf_Verdaux) == sizeof (Elf64_Verdaux)); + + rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely (offset < 0) + || unlikely (offset + sizeof (GElf_Verdaux) > data->d_size) + || unlikely (offset % __alignof__ (GElf_Verdaux) != 0)) + { + __libelf_seterrno (ELF_E_OFFSET_RANGE); + result = NULL; + } + else + result = (GElf_Verdaux *) memcpy (dst, (char *) data->d_buf + offset, + sizeof (GElf_Verdaux)); + + + rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); + + return result; +} diff --git a/libelf/gelf_getverdef.c b/libelf/gelf_getverdef.c new file mode 100644 index 00000000..b9492ef7 --- /dev/null +++ b/libelf/gelf_getverdef.c @@ -0,0 +1,69 @@ +/* Get symbol version definition information at the given offset. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_Verdef * +gelf_getverdef (data, offset, dst) + Elf_Data *data; + int offset; + GElf_Verdef *dst; +{ + GElf_Verdef *result; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_VDEF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* It's easy to handle this type. It has the same size for 32 and + 64 bit objects. */ + assert (sizeof (GElf_Verdef) == sizeof (Elf32_Verdef)); + assert (sizeof (GElf_Verdef) == sizeof (Elf64_Verdef)); + + rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely (offset < 0) + || unlikely (offset + sizeof (GElf_Verdef) > data->d_size) + || unlikely (offset % __alignof__ (GElf_Verdef) != 0)) + { + __libelf_seterrno (ELF_E_OFFSET_RANGE); + result = NULL; + } + else + result = (GElf_Verdef *) memcpy (dst, (char *) data->d_buf + offset, + sizeof (GElf_Verdef)); + + rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); + + return result; +} diff --git a/libelf/gelf_getvernaux.c b/libelf/gelf_getvernaux.c new file mode 100644 index 00000000..fbaa109a --- /dev/null +++ b/libelf/gelf_getvernaux.c @@ -0,0 +1,72 @@ +/* Get additional required symbol version information at the given offset. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_Vernaux * +gelf_getvernaux (data, offset, dst) + Elf_Data *data; + int offset; + GElf_Vernaux *dst; +{ + GElf_Vernaux *result; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_VNEED)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* It's easy to handle this type. It has the same size for 32 and + 64 bit objects. And fortunately the `ElfXXX_Vernaux' records + also have the same size. */ + assert (sizeof (GElf_Vernaux) == sizeof (Elf32_Verneed)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf64_Verneed)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf32_Vernaux)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf64_Vernaux)); + + rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely (offset < 0) + || unlikely (offset + sizeof (GElf_Vernaux) > data->d_size) + || unlikely (offset % sizeof (GElf_Vernaux) != 0)) + { + __libelf_seterrno (ELF_E_OFFSET_RANGE); + result = NULL; + } + else + result = (GElf_Vernaux *) memcpy (dst, (char *) data->d_buf + offset, + sizeof (GElf_Verneed)); + + rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); + + return result; +} diff --git a/libelf/gelf_getverneed.c b/libelf/gelf_getverneed.c new file mode 100644 index 00000000..573e116a --- /dev/null +++ b/libelf/gelf_getverneed.c @@ -0,0 +1,72 @@ +/* Get required symbol version information at the given offset. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_Verneed * +gelf_getverneed (data, offset, dst) + Elf_Data *data; + int offset; + GElf_Verneed *dst; +{ + GElf_Verneed *result; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_VNEED)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* It's easy to handle this type. It has the same size for 32 and + 64 bit objects. And fortunately the `ElfXXX_Vernaux' records + also have the same size. */ + assert (sizeof (GElf_Verneed) == sizeof (Elf32_Verneed)); + assert (sizeof (GElf_Verneed) == sizeof (Elf64_Verneed)); + assert (sizeof (GElf_Verneed) == sizeof (Elf32_Vernaux)); + assert (sizeof (GElf_Verneed) == sizeof (Elf64_Vernaux)); + + rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely (offset < 0) + || unlikely (offset + sizeof (GElf_Verneed) > data->d_size) + || unlikely (offset % sizeof (GElf_Verneed) != 0)) + { + __libelf_seterrno (ELF_E_OFFSET_RANGE); + result = NULL; + } + else + result = (GElf_Verneed *) memcpy (dst, (char *) data->d_buf + offset, + sizeof (GElf_Verneed)); + + rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); + + return result; +} diff --git a/libelf/gelf_getversym.c b/libelf/gelf_getversym.c new file mode 100644 index 00000000..9274b142 --- /dev/null +++ b/libelf/gelf_getversym.c @@ -0,0 +1,77 @@ +/* Get symbol version information at the given index. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_Versym * +gelf_getversym (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Versym *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + GElf_Versym *result; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_HALF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + scn = data_scn->s; + + /* It's easy to handle this type. It has the same size for 32 and + 64 bit objects. */ + assert (sizeof (GElf_Versym) == sizeof (Elf32_Versym)); + assert (sizeof (GElf_Versym) == sizeof (Elf64_Versym)); + + rwlock_rdlock (scn->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely ((ndx + 1) * sizeof (GElf_Versym) > data->d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + result = NULL; + } + else + { + *dst = ((GElf_Versym *) data->d_buf)[ndx]; + + result = dst; + } + + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/libelf/gelf_newehdr.c b/libelf/gelf_newehdr.c new file mode 100644 index 00000000..587283f4 --- /dev/null +++ b/libelf/gelf_newehdr.c @@ -0,0 +1,36 @@ +/* Create new ELF header. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +unsigned long int +gelf_newehdr (elf, class) + Elf *elf; + int class; +{ + return (class == ELFCLASS32 + ? (unsigned long int) INTUSE(elf32_newehdr) (elf) + : (unsigned long int) INTUSE(elf64_newehdr) (elf)); +} diff --git a/libelf/gelf_newphdr.c b/libelf/gelf_newphdr.c new file mode 100644 index 00000000..d1d433e8 --- /dev/null +++ b/libelf/gelf_newphdr.c @@ -0,0 +1,36 @@ +/* Create new ELF program header. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +unsigned long int +gelf_newphdr (elf, phnum) + Elf *elf; + size_t phnum; +{ + return (elf->class == ELFCLASS32 + ? (unsigned long int) INTUSE(elf32_newphdr) (elf, phnum) + : (unsigned long int) INTUSE(elf64_newphdr) (elf, phnum)); +} diff --git a/libelf/gelf_rawchunk.c b/libelf/gelf_rawchunk.c new file mode 100644 index 00000000..667f3013 --- /dev/null +++ b/libelf/gelf_rawchunk.c @@ -0,0 +1,71 @@ +/* Retrieve uninterpreted chunk of the file contents. + Copyright (C) 2002 Red Hat, Inc. + Contributed by Ulrich Drepper , 2002. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "libelfP.h" + + +char * +gelf_rawchunk (elf, offset, size) + Elf *elf; + GElf_Off offset; + GElf_Word size; +{ + if (elf == NULL) + { + /* No valid descriptor. */ + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + if (offset >= elf->maximum_size + || offset + size >= elf->maximum_size + || offset + size < offset) + { + /* Invalid request. */ + __libelf_seterrno (ELF_E_INVALID_OP); + return NULL; + } + + /* If the file is mmap'ed return an appropriate pointer. */ + if (elf->map_address != NULL) + return (char *) elf->map_address + elf->start_offset + offset; + + /* We allocate the memory and read the data from the file. */ + char *result = (char *) malloc (size); + if (result == NULL) + __libelf_seterrno (ELF_E_NOMEM); + else + /* Read the file content. */ + if ((size_t) pread (elf->fildes, result, size, elf->start_offset + offset) + != size) + { + /* Something went wrong. */ + __libelf_seterrno (ELF_E_READ_ERROR); + free (result); + } + + return result; +} diff --git a/libelf/gelf_update_dyn.c b/libelf/gelf_update_dyn.c new file mode 100644 index 00000000..b066fd62 --- /dev/null +++ b/libelf/gelf_update_dyn.c @@ -0,0 +1,104 @@ +/* Update information in dynamic table at the given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +int +gelf_update_dyn (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Dyn *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + int result = 0; + + if (data == NULL) + return 0; + + if (unlikely (ndx < 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_DYN)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + Elf32_Dyn *dyn; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->d_tag < -0x80000000ll) + || unlikely (src->d_tag > 0x7fffffffll) + || unlikely (src->d_un.d_val > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_Dyn) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + dyn = &((Elf32_Dyn *) data_scn->d.d_buf)[ndx]; + + dyn->d_tag = src->d_tag; + dyn->d_un.d_val = src->d_un.d_val; + } + else + { + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf64_Dyn) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_Dyn *) data_scn->d.d_buf)[ndx] = *src; + } + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/libelf/gelf_update_ehdr.c b/libelf/gelf_update_ehdr.c new file mode 100644 index 00000000..e13121d0 --- /dev/null +++ b/libelf/gelf_update_ehdr.c @@ -0,0 +1,103 @@ +/* Update ELF header. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +int +gelf_update_ehdr (Elf *elf, GElf_Ehdr *src) +{ + int result = 0; + + if (elf == NULL) + return 0; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + rwlock_wrlock (elf->lock); + + if (elf->class == ELFCLASS32) + { + Elf32_Ehdr *ehdr = elf->state.elf32.ehdr; + + if (ehdr == NULL) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + goto out; + } + + /* We have to convert the data to the 32 bit format. This might + overflow some fields so we have to test for this case before + copying. */ + if (unlikely (src->e_entry > 0xffffffffull) + || unlikely (src->e_phoff > 0xffffffffull) + || unlikely (src->e_shoff > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Copy the data. */ + memcpy (ehdr->e_ident, src->e_ident, EI_NIDENT); +#define COPY(name) \ + ehdr->name = src->name + COPY (e_type); + COPY (e_machine); + COPY (e_version); + COPY (e_entry); + COPY (e_phoff); + COPY (e_shoff); + COPY (e_flags); + COPY (e_ehsize); + COPY (e_phentsize); + COPY (e_phnum); + COPY (e_shentsize); + COPY (e_shnum); + COPY (e_shstrndx); + } + else + { + Elf64_Ehdr *ehdr = elf->state.elf64.ehdr; + + if (ehdr == NULL) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + goto out; + } + + /* Just copy the data. */ + memcpy (ehdr, src, sizeof (Elf64_Ehdr)); + } + + result = 1; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/libelf/gelf_update_lib.c b/libelf/gelf_update_lib.c new file mode 100644 index 00000000..08ce2296 --- /dev/null +++ b/libelf/gelf_update_lib.c @@ -0,0 +1,72 @@ +/* Update library in table at the given index. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +int +gelf_update_lib (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Lib *src; +{ + if (data == NULL) + return 0; + + if (unlikely (ndx < 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + if (unlikely (data_scn->d.d_type != ELF_T_LIB)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + Elf_Scn *scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + /* Check whether we have to resize the data buffer. */ + int result = 0; + if (unlikely ((ndx + 1) * sizeof (Elf64_Lib) > data_scn->d.d_size)) + __libelf_seterrno (ELF_E_INVALID_INDEX); + else + { + ((Elf64_Lib *) data_scn->d.d_buf)[ndx] = *src; + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + } + + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/libelf/gelf_update_move.c b/libelf/gelf_update_move.c new file mode 100644 index 00000000..090e3975 --- /dev/null +++ b/libelf/gelf_update_move.c @@ -0,0 +1,69 @@ +/* Update move structure at the given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +int +gelf_update_move (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Move *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Move) == sizeof (Elf32_Move)); + assert (sizeof (GElf_Move) == sizeof (Elf64_Move)); + + /* Check whether we have to resize the data buffer. */ + if (unlikely (ndx < 0) + || unlikely ((ndx + 1) * sizeof (GElf_Move) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_MOVE)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + ((GElf_Move *) data_scn->d.d_buf)[ndx] = *src; + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/libelf/gelf_update_phdr.c b/libelf/gelf_update_phdr.c new file mode 100644 index 00000000..ddd4e1ee --- /dev/null +++ b/libelf/gelf_update_phdr.c @@ -0,0 +1,120 @@ +/* Update program header program header table entry. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +int +gelf_update_phdr (Elf *elf, int ndx, GElf_Phdr *src) +{ + int result = 0; + + if (elf == NULL) + return 0; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + rwlock_wrlock (elf->lock); + + if (elf->class == ELFCLASS32) + { + Elf32_Phdr *phdr = elf->state.elf32.phdr; + + /* We have to convert the data to the 32 bit format. This might + overflow some fields so we have to test for this case before + copying. */ + if (unlikely (src->p_offset > 0xffffffffull) + || unlikely (src->p_vaddr > 0xffffffffull) + || unlikely (src->p_paddr > 0xffffffffull) + || unlikely (src->p_filesz > 0xffffffffull) + || unlikely (src->p_memsz > 0xffffffffull) + || unlikely (src->p_align > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + if (phdr == NULL) + { + phdr = INTUSE(elf32_getphdr) (elf); + if (phdr == NULL) + /* The error number is already set. */ + goto out; + } + + /* Test whether the index is ok. */ + if (unlikely (ndx >= elf->state.elf32.ehdr->e_phnum)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + /* Now correct the pointer to point to the correct element. */ + phdr += ndx; + +#define COPY(name) \ + phdr->name = src->name + COPY (p_type); + COPY (p_offset); + COPY (p_vaddr); + COPY (p_paddr); + COPY (p_filesz); + COPY (p_memsz); + COPY (p_flags); + COPY (p_align); + } + else + { + Elf64_Phdr *phdr = elf->state.elf64.phdr; + + if (phdr == NULL) + { + phdr = INTUSE(elf64_getphdr) (elf); + if (phdr == NULL) + /* The error number is already set. */ + goto out; + } + + /* Test whether the index is ok. */ + if (unlikely (ndx >= elf->state.elf64.ehdr->e_phnum)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + /* Just copy the data. */ + memcpy (phdr + ndx, src, sizeof (Elf64_Phdr)); + } + + result = 1; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/libelf/gelf_update_rel.c b/libelf/gelf_update_rel.c new file mode 100644 index 00000000..c59c6dd4 --- /dev/null +++ b/libelf/gelf_update_rel.c @@ -0,0 +1,102 @@ +/* Update REL relocation information at given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +int +gelf_update_rel (Elf_Data *dst, int ndx, GElf_Rel *src) +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) dst; + Elf_Scn *scn; + int result = 0; + + if (dst == NULL) + return 0; + + if (unlikely (ndx < 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_REL)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + Elf32_Rel *rel; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->r_offset > 0xffffffffull) + || unlikely (GELF_R_SYM (src->r_info) > 0xffffff) + || unlikely (GELF_R_TYPE (src->r_info) > 0xff)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_Rel) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + rel = &((Elf32_Rel *) data_scn->d.d_buf)[ndx]; + + rel->r_offset = src->r_offset; + rel->r_info = ELF32_R_INFO (GELF_R_SYM (src->r_info), + GELF_R_TYPE (src->r_info)); + } + else + { + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf64_Rel) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_Rel *) data_scn->d.d_buf)[ndx] = *src; + } + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/libelf/gelf_update_rela.c b/libelf/gelf_update_rela.c new file mode 100644 index 00000000..f932c018 --- /dev/null +++ b/libelf/gelf_update_rela.c @@ -0,0 +1,105 @@ +/* Update RELA relocation information at given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +int +gelf_update_rela (Elf_Data *dst, int ndx, GElf_Rela *src) +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) dst; + Elf_Scn *scn; + int result = 0; + + if (dst == NULL) + return 0; + + if (unlikely (ndx < 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_RELA)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + Elf32_Rela *rel; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->r_offset > 0xffffffffull) + || unlikely (GELF_R_SYM (src->r_info) > 0xffffff) + || unlikely (GELF_R_TYPE (src->r_info) > 0xff) + || unlikely (src->r_addend < -0x80000000ll) + || unlikely (src->r_addend > 0x7fffffffll)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_Rela) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + rel = &((Elf32_Rela *) data_scn->d.d_buf)[ndx]; + + rel->r_offset = src->r_offset; + rel->r_info = ELF32_R_INFO (GELF_R_SYM (src->r_info), + GELF_R_TYPE (src->r_info)); + rel->r_addend = src->r_addend; + } + else + { + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf64_Rela) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_Rela *) data_scn->d.d_buf)[ndx] = *src; + } + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/libelf/gelf_update_shdr.c b/libelf/gelf_update_shdr.c new file mode 100644 index 00000000..c54e8c52 --- /dev/null +++ b/libelf/gelf_update_shdr.c @@ -0,0 +1,94 @@ +/* Update section header. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +int +gelf_update_shdr (Elf_Scn *scn, GElf_Shdr *src) +{ + int result = 0; + Elf *elf; + + if (scn == NULL || src == NULL) + return 0; + + elf = scn->elf; + rwlock_wrlock (elf->lock); + + if (elf->class == ELFCLASS32) + { + Elf32_Shdr *shdr = scn->shdr.e32 ?: INTUSE(elf32_getshdr) (scn); + + if (shdr == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + goto out; + } + + if (unlikely (src->sh_flags > 0xffffffffull) + || unlikely (src->sh_addr > 0xffffffffull) + || unlikely (src->sh_offset > 0xffffffffull) + || unlikely (src->sh_size > 0xffffffffull) + || unlikely (src->sh_addralign > 0xffffffffull) + || unlikely (src->sh_entsize > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + +#define COPY(name) \ + shdr->name = src->name + COPY (sh_name); + COPY (sh_type); + COPY (sh_flags); + COPY (sh_addr); + COPY (sh_offset); + COPY (sh_size); + COPY (sh_link); + COPY (sh_info); + COPY (sh_addralign); + COPY (sh_entsize); + } + else + { + Elf64_Shdr *shdr = scn->shdr.e64 ?: INTUSE(elf64_getshdr) (scn); + + if (shdr == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + goto out; + } + + /* We only have to copy the data. */ + (void) memcpy (shdr, src, sizeof (GElf_Shdr)); + } + + result = 1; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/libelf/gelf_update_sym.c b/libelf/gelf_update_sym.c new file mode 100644 index 00000000..8fc7dd66 --- /dev/null +++ b/libelf/gelf_update_sym.c @@ -0,0 +1,113 @@ +/* Update symbol information in symbol table at the given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +int +gelf_update_sym (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Sym *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + int result = 0; + + if (data == NULL) + return 0; + + if (unlikely (ndx < 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_SYM)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + Elf32_Sym *sym; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->st_value > 0xffffffffull) + || unlikely (src->st_size > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_Sym) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + sym = &((Elf32_Sym *) data_scn->d.d_buf)[ndx]; + +#define COPY(name) \ + sym->name = src->name + COPY (st_name); + COPY (st_value); + COPY (st_size); + /* Please note that we can simply copy the `st_info' element since + the definitions of ELFxx_ST_BIND and ELFxx_ST_TYPE are the same + for the 64 bit variant. */ + COPY (st_info); + COPY (st_other); + COPY (st_shndx); + } + else + { + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf64_Sym) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_Sym *) data_scn->d.d_buf)[ndx] = *src; + } + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/libelf/gelf_update_syminfo.c b/libelf/gelf_update_syminfo.c new file mode 100644 index 00000000..a60aa5c5 --- /dev/null +++ b/libelf/gelf_update_syminfo.c @@ -0,0 +1,80 @@ +/* Update additional symbol information in symbol table at the given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +int +gelf_update_syminfo (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Syminfo *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + int result = 0; + + if (data == NULL) + return 0; + + if (unlikely (ndx < 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_SYMINFO)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Syminfo) == sizeof (Elf32_Syminfo)); + assert (sizeof (GElf_Syminfo) == sizeof (Elf64_Syminfo)); + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (GElf_Syminfo) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((GElf_Syminfo *) data_scn->d.d_buf)[ndx] = *src; + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/libelf/gelf_update_symshndx.c b/libelf/gelf_update_symshndx.c new file mode 100644 index 00000000..4f376150 --- /dev/null +++ b/libelf/gelf_update_symshndx.c @@ -0,0 +1,143 @@ +/* Update symbol information and section index in symbol table at the + given index. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +int +gelf_update_symshndx (symdata, shndxdata, ndx, src, srcshndx) + Elf_Data *symdata; + Elf_Data *shndxdata; + int ndx; + GElf_Sym *src; + Elf32_Word srcshndx; +{ + Elf_Data_Scn *symdata_scn = (Elf_Data_Scn *) symdata; + Elf_Data_Scn *shndxdata_scn = (Elf_Data_Scn *) shndxdata; + Elf_Scn *scn; + Elf32_Word *shndx = NULL; + int result = 0; + + if (symdata == NULL) + return 0; + + if (unlikely (ndx < 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (symdata_scn->d.d_type != ELF_T_SYM)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = symdata_scn->s; + /* We simply have to believe the user that the two sections belong to + the same ELF file. */ + rwlock_wrlock (scn->elf->lock); + + /* The user is not required to pass a data descriptor for an extended + section index table. */ + if (shndxdata_scn != NULL) + { + if (unlikely ((ndx + 1) * sizeof (Elf32_Word) > shndxdata_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + shndx = &((Elf32_Word *) shndxdata_scn->d.d_buf)[ndx]; + } + /* But if s/he does not the extended sectio index must be zero. */ + else if (unlikely (srcshndx != 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + if (scn->elf->class == ELFCLASS32) + { + Elf32_Sym *sym; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->st_value > 0xffffffffull) + || unlikely (src->st_size > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_Sym) > symdata_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + sym = &((Elf32_Sym *) symdata_scn->d.d_buf)[ndx]; + +#define COPY(name) \ + sym->name = src->name + COPY (st_name); + COPY (st_value); + COPY (st_size); + /* Please note that we can simply copy the `st_info' element since + the definitions of ELFxx_ST_BIND and ELFxx_ST_TYPE are the same + for the 64 bit variant. */ + COPY (st_info); + COPY (st_other); + COPY (st_shndx); + } + else + { + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf64_Sym) > symdata_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_Sym *) symdata_scn->d.d_buf)[ndx] = *src; + } + + /* Now we can store the section index. */ + if (shndx != NULL) + *shndx = srcshndx; + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/libelf/gelf_update_verdaux.c b/libelf/gelf_update_verdaux.c new file mode 100644 index 00000000..e21428e0 --- /dev/null +++ b/libelf/gelf_update_verdaux.c @@ -0,0 +1,69 @@ +/* Update additional symbol version definition information. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +int +gelf_update_verdaux (data, offset, src) + Elf_Data *data; + int offset; + GElf_Verdaux *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Verdaux) == sizeof (Elf32_Verdaux)); + assert (sizeof (GElf_Verdaux) == sizeof (Elf64_Verdaux)); + + /* Check whether we have to resize the data buffer. */ + if (unlikely (offset < 0) + || unlikely ((offset + sizeof (GElf_Verdaux)) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_VDEF)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + memcpy ((char *) data_scn->d.d_buf + offset, src, sizeof (GElf_Verdaux)); + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/libelf/gelf_update_verdef.c b/libelf/gelf_update_verdef.c new file mode 100644 index 00000000..833a058b --- /dev/null +++ b/libelf/gelf_update_verdef.c @@ -0,0 +1,69 @@ +/* Update symbol version definition information. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +int +gelf_update_verdef (data, offset, src) + Elf_Data *data; + int offset; + GElf_Verdef *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Verdef) == sizeof (Elf32_Verdef)); + assert (sizeof (GElf_Verdef) == sizeof (Elf64_Verdef)); + + /* Check whether we have to resize the data buffer. */ + if (unlikely (offset < 0) + || unlikely ((offset + sizeof (GElf_Verdef)) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_VDEF)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + memcpy ((char *) data_scn->d.d_buf + offset, src, sizeof (GElf_Verdef)); + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/libelf/gelf_update_vernaux.c b/libelf/gelf_update_vernaux.c new file mode 100644 index 00000000..3f506d48 --- /dev/null +++ b/libelf/gelf_update_vernaux.c @@ -0,0 +1,69 @@ +/* Update additional required symbol version information. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +int +gelf_update_vernaux (data, offset, src) + Elf_Data *data; + int offset; + GElf_Vernaux *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Vernaux) == sizeof (Elf32_Vernaux)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf64_Vernaux)); + + /* Check whether we have to resize the data buffer. */ + if (unlikely (offset < 0) + || unlikely ((offset + sizeof (GElf_Vernaux)) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_VNEED)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + memcpy ((char *) data_scn->d.d_buf + offset, src, sizeof (GElf_Vernaux)); + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/libelf/gelf_update_verneed.c b/libelf/gelf_update_verneed.c new file mode 100644 index 00000000..6fccd937 --- /dev/null +++ b/libelf/gelf_update_verneed.c @@ -0,0 +1,69 @@ +/* Update required symbol version information. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +int +gelf_update_verneed (data, offset, src) + Elf_Data *data; + int offset; + GElf_Verneed *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Verneed) == sizeof (Elf32_Verneed)); + assert (sizeof (GElf_Verneed) == sizeof (Elf64_Verneed)); + + /* Check whether we have to resize the data buffer. */ + if (unlikely (offset < 0) + || unlikely ((offset + sizeof (GElf_Verneed)) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_VNEED)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + memcpy ((char *) data_scn->d.d_buf + offset, src, sizeof (GElf_Verneed)); + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/libelf/gelf_update_versym.c b/libelf/gelf_update_versym.c new file mode 100644 index 00000000..404d5bc3 --- /dev/null +++ b/libelf/gelf_update_versym.c @@ -0,0 +1,69 @@ +/* Update symbol version information. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +int +gelf_update_versym (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Versym *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Versym) == sizeof (Elf32_Versym)); + assert (sizeof (GElf_Versym) == sizeof (Elf64_Versym)); + + /* Check whether we have to resize the data buffer. */ + if (unlikely (ndx < 0) + || unlikely ((ndx + 1) * sizeof (GElf_Versym) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_HALF)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + ((GElf_Versym *) data_scn->d.d_buf)[ndx] = *src; + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/libelf/gelf_xlate.c b/libelf/gelf_xlate.c new file mode 100644 index 00000000..bbb133a3 --- /dev/null +++ b/libelf/gelf_xlate.c @@ -0,0 +1,182 @@ +/* Transformation functions for ELF data types. + Copyright (C) 1998, 1999, 2000, 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +/* Well, what shall I say. Nothing to do here. */ +#define elf_cvt_Byte(dest, src, n) \ + (__builtin_constant_p (n) && (n) == 1 \ + ? (void) (*((char *) (dest)) = *((char *) (src))) \ + : Elf32_cvt_Byte (dest, src, n)) +static void +(elf_cvt_Byte) (void *dest, const void *src, size_t n, + int encode __attribute__ ((unused))) +{ + memmove (dest, src, n); +} + + +/* We'll optimize the definition of the conversion functions here a + bit. We need only functions for 16, 32, and 64 bits. The + functions referenced in the table will be aliases for one of these + functions. Which one is decided by the ELFxx_FSZ_type. */ +#define LEN2_SWAP(Src) bswap_16 (*((uint16_t *) Src)) +#define word2_t uint16_t + +#define LEN4_SWAP(Src) bswap_32 (*((uint32_t *) Src)) +#define word4_t uint32_t + +#define LEN8_SWAP(Src) bswap_64 (*((uint64_t *) Src)) +#define word8_t uint64_t + + +/* Now define the conversion functions for the basic types. We use here + the fact that file and memory types are the same and that we have the + ELFxx_FSZ_* macros. + + At the same time we define inline functions which we will use to + convert the complex types. */ +#define FUNDAMENTAL(NAME, Name, Bits) \ + INLINE2 (ELFW2(Bits,FSZ_##NAME), ElfW2(Bits,cvt_##Name), ElfW2(Bits,Name)) +#define INLINE2(Bytes, FName, TName) \ + INLINE3 (Bytes, FName, TName) +#define INLINE3(Bytes, FName, TName) \ + static void FName (void *dest, const void *ptr, size_t len, \ + int encode __attribute__ ((unused))) \ + { \ + size_t n = len / sizeof (TName); \ + if (dest < ptr) \ + { \ + word##Bytes##_t *tdest = (word##Bytes##_t *) dest; \ + const word##Bytes##_t *tptr = (const word##Bytes##_t *) ptr; \ + while (n-- > 0) \ + { \ + *tdest++ = LEN##Bytes##_SWAP (tptr); \ + tptr++; \ + } \ + } \ + else \ + { \ + word##Bytes##_t *tdest = (word##Bytes##_t *) dest + n; \ + const word##Bytes##_t *tptr = (const word##Bytes##_t *) ptr + n; \ + while (n-- > 0) \ + { \ + --tptr; \ + *--tdest = LEN##Bytes##_SWAP (tptr); \ + } \ + } \ + } \ + \ + static inline void FName##1 (void *dest, const void *ptr) \ + { \ + *((word##Bytes##_t *) dest) = \ + LEN##Bytes##_SWAP ((((word##Bytes##_t *) ptr))); \ + } + + +/* Now the tricky part: define the transformation functions for the + complex types. We will use the definitions of the types in + abstract.h. */ +#define START(Bits, Name, EName) \ + static void \ + ElfW2 (Bits, cvt_##Name) (void *dest, const void *src, size_t len, \ + int encode __attribute__ ((unused))) \ + { ElfW2(Bits, Name) *tdest = (ElfW2(Bits, Name) *) dest; \ + ElfW2(Bits, Name) *tsrc = (ElfW2(Bits, Name) *) src; \ + size_t n; \ + for (n = len / sizeof (ElfW2(Bits, Name)); n > 0; ++tdest, ++tsrc, --n) { +#define END(Bits, Name) } } +#define TYPE_EXTRA(Code) +#define TYPE_XLATE(Code) Code +#define TYPE_NAME(Type, Name) TYPE_NAME2 (Type, Name) +#define TYPE_NAME2(Type, Name) Type##1 (&tdest->Name, &tsrc->Name); +#define TYPE(Name, Bits) TYPE2 (Name, Bits) +#define TYPE2(Name, Bits) TYPE3 (Name##Bits) +#define TYPE3(Name) Name (cvt_) + +/* Signal that we are generating conversion functions. */ +#define GENERATE_CONVERSION + +/* First generate the 32-bit conversion functions. */ +#define LIBELFBITS 32 +#include "gelf_xlate.h" + +/* Now generate the 64-bit conversion functions. */ +#define LIBELFBITS 64 +#include "gelf_xlate.h" + + +/* We have a few functions which we must create by hand since the sections + do not contain records of only one type. */ +#include "version_xlate.h" + + +/* Now the externally visible table with the function pointers. */ +const xfct_t __elf_xfctstom[EV_NUM - 1][EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] = +{ + [EV_CURRENT - 1] = { + [EV_CURRENT - 1] = { + [ELFCLASS32 - 1] = { +#define define_xfcts(Bits) \ + [ELF_T_BYTE] = elf_cvt_Byte, \ + [ELF_T_ADDR] = ElfW2(Bits, cvt_Addr), \ + [ELF_T_DYN] = ElfW2(Bits, cvt_Dyn), \ + [ELF_T_EHDR] = ElfW2(Bits, cvt_Ehdr), \ + [ELF_T_HALF] = ElfW2(Bits, cvt_Half), \ + [ELF_T_OFF] = ElfW2(Bits, cvt_Off), \ + [ELF_T_PHDR] = ElfW2(Bits, cvt_Phdr), \ + [ELF_T_RELA] = ElfW2(Bits, cvt_Rela), \ + [ELF_T_REL] = ElfW2(Bits, cvt_Rel), \ + [ELF_T_SHDR] = ElfW2(Bits, cvt_Shdr), \ + [ELF_T_SWORD] = ElfW2(Bits, cvt_Sword), \ + [ELF_T_SYM] = ElfW2(Bits, cvt_Sym), \ + [ELF_T_WORD] = ElfW2(Bits, cvt_Word), \ + [ELF_T_XWORD] = ElfW2(Bits, cvt_Xword), \ + [ELF_T_SXWORD] = ElfW2(Bits, cvt_Sxword), \ + [ELF_T_VDEF] = elf_cvt_Verdef, \ + [ELF_T_VDAUX] = elf_cvt_Verdef, \ + [ELF_T_VNEED] = elf_cvt_Verneed, \ + [ELF_T_VNAUX] = elf_cvt_Verneed, \ + [ELF_T_NHDR] = ElfW2(Bits, cvt_Nhdr), \ + [ELF_T_SYMINFO] = ElfW2(Bits, cvt_Syminfo), \ + [ELF_T_MOVE] = ElfW2(Bits, cvt_Move), \ + [ELF_T_LIB] = ElfW2(Bits, cvt_Lib) + define_xfcts (32) + }, + [ELFCLASS64 - 1] = { + define_xfcts (64) + } + } + } +}; +/* For now we only handle the case where the memory representation is the + same as the file representation. Should this change we have to define + separate functions. For now reuse them. */ +strong_alias (__elf_xfctstom, __elf_xfctstof) diff --git a/libelf/gelf_xlate.h b/libelf/gelf_xlate.h new file mode 100644 index 00000000..42e91c08 --- /dev/null +++ b/libelf/gelf_xlate.h @@ -0,0 +1,43 @@ +/* Helper file for type conversion function generation. + Copyright (C) 1998, 1999, 2000, 2002, 2004 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* Simple types. */ +FUNDAMENTAL (ADDR, Addr, LIBELFBITS); +FUNDAMENTAL (OFF, Off, LIBELFBITS); +FUNDAMENTAL (HALF, Half, LIBELFBITS); +FUNDAMENTAL (WORD, Word, LIBELFBITS); +FUNDAMENTAL (SWORD, Sword, LIBELFBITS); +FUNDAMENTAL (XWORD, Xword, LIBELFBITS); +FUNDAMENTAL (SXWORD, Sxword, LIBELFBITS); + +/* The structured types. */ +TYPE (Ehdr, LIBELFBITS) +TYPE (Phdr, LIBELFBITS) +TYPE (Shdr, LIBELFBITS) +TYPE (Sym, LIBELFBITS) +TYPE (Rel, LIBELFBITS) +TYPE (Rela, LIBELFBITS) +TYPE (Note, LIBELFBITS) +TYPE (Dyn, LIBELFBITS) +TYPE (Syminfo, LIBELFBITS) +TYPE (Move, LIBELFBITS) +TYPE (Lib, LIBELFBITS) + + +/* Prepare for the next round. */ +#undef LIBELFBITS diff --git a/libelf/gelf_xlatetof.c b/libelf/gelf_xlatetof.c new file mode 100644 index 00000000..53cfae2e --- /dev/null +++ b/libelf/gelf_xlatetof.c @@ -0,0 +1,41 @@ +/* Convert from memory to file representation. Generic ELF version. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +Elf_Data * +gelf_xlatetof (elf, dest, src, encode) + Elf *elf; + Elf_Data *dest; + const Elf_Data * src; + unsigned int encode; +{ + if (elf == NULL) + return NULL; + + return (elf->class == ELFCLASS32 + ? INTUSE(elf32_xlatetof) (dest, src, encode) + : INTUSE(elf64_xlatetof) (dest, src, encode)); +} diff --git a/libelf/gelf_xlatetom.c b/libelf/gelf_xlatetom.c new file mode 100644 index 00000000..9295ee09 --- /dev/null +++ b/libelf/gelf_xlatetom.c @@ -0,0 +1,41 @@ +/* Convert from file to memory representation. Generic ELF version. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +Elf_Data * +gelf_xlatetom (elf, dest, src, encode) + Elf *elf; + Elf_Data *dest; + const Elf_Data * src; + unsigned int encode; +{ + if (elf == NULL) + return NULL; + + return (elf->class == ELFCLASS32 + ? INTUSE(elf32_xlatetom) (dest, src, encode) + : INTUSE(elf64_xlatetom) (dest, src, encode)); +} diff --git a/libelf/libelf.h b/libelf/libelf.h new file mode 100644 index 00000000..5b3dc00b --- /dev/null +++ b/libelf/libelf.h @@ -0,0 +1,343 @@ +/* Interface for libelf. + Copyright (C) 1998, 1999, 2000, 2002, 2004 Red Hat, 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _LIBELF_H +#define _LIBELF_H 1 + +#include + +/* Get the ELF types. */ +#include + + +/* Known translation types. */ +typedef enum +{ + ELF_T_BYTE, /* unsigned char */ + ELF_T_ADDR, /* Elf32_Addr, Elf64_Addr, ... */ + ELF_T_DYN, /* Dynamic section record. */ + ELF_T_EHDR, /* ELF header. */ + ELF_T_HALF, /* Elf32_Half, Elf64_Half, ... */ + ELF_T_OFF, /* Elf32_Off, Elf64_Off, ... */ + ELF_T_PHDR, /* Program header. */ + ELF_T_RELA, /* Relocation entry with addend. */ + ELF_T_REL, /* Relocation entry. */ + ELF_T_SHDR, /* Section header. */ + ELF_T_SWORD, /* Elf32_Sword, Elf64_Sword, ... */ + ELF_T_SYM, /* Symbol record. */ + ELF_T_WORD, /* Elf32_Word, Elf64_Word, ... */ + ELF_T_XWORD, /* Elf32_Xword, Elf64_Xword, ... */ + ELF_T_SXWORD, /* Elf32_Sxword, Elf64_Sxword, ... */ + ELF_T_VDEF, /* Elf32_Verdef, Elf64_Verdef, ... */ + ELF_T_VDAUX, /* Elf32_Verdaux, Elf64_Verdaux, ... */ + ELF_T_VNEED, /* Elf32_Verneed, Elf64_Verneed, ... */ + ELF_T_VNAUX, /* Elf32_Vernaux, Elf64_Vernaux, ... */ + ELF_T_NHDR, /* Elf32_Nhdr, Elf64_Nhdr, ... */ + ELF_T_SYMINFO, /* Elf32_Syminfo, Elf64_Syminfo, ... */ + ELF_T_MOVE, /* Elf32_Move, Elf64_Move, ... */ + ELF_T_LIB, /* Elf32_Lib, Elf64_Lib, ... */ + /* Keep this the last entry. */ + ELF_T_NUM +} Elf_Type; + +/* Descriptor for data to be converted to or from memory format. */ +typedef struct +{ + void *d_buf; /* Pointer to the actual data. */ + Elf_Type d_type; /* Type of this piece of data. */ + unsigned int d_version; /* ELF version. */ + size_t d_size; /* Size in bytes. */ + off_t d_off; /* Offset into section. */ + size_t d_align; /* Alignment in section. */ +} Elf_Data; + + +/* Commands for `...'. */ +typedef enum +{ + ELF_C_NULL, /* Nothing, terminate, or compute only. */ + ELF_C_READ, /* Read .. */ + ELF_C_RDWR, /* Read and write .. */ + ELF_C_WRITE, /* Write .. */ + ELF_C_CLR, /* Clear flag. */ + ELF_C_SET, /* Set flag. */ + ELF_C_FDDONE, /* Signal that file descriptor will not be + used anymore. */ + ELF_C_FDREAD, /* Read rest of data so that file descriptor + is not used anymore. */ + /* The following are extensions. */ + ELF_C_READ_MMAP, /* Read, but mmap the file if possible. */ + ELF_C_RDWR_MMAP, /* Read and write, with mmap. */ + ELF_C_WRITE_MMAP, /* Write, with mmap. */ + ELF_C_READ_MMAP_PRIVATE, /* Read, but memory is writable, results are + not written to the file. */ + ELF_C_EMPTY, /* Copy basic file data but not the content. */ + /* Keep this the last entry. */ + ELF_C_NUM +} Elf_Cmd; + + +/* Flags for the ELF structures. */ +enum +{ + ELF_F_DIRTY = 0x1, +#define ELF_F_DIRTY ELF_F_DIRTY + ELF_F_LAYOUT = 0x4, +#define ELF_F_LAYOUT ELF_F_LAYOUT + ELF_F_PERMISSIVE = 0x8 +#define ELF_F_PERMISSIVE ELF_F_PERMISSIVE +}; + + +/* Identification values for recognized object files. */ +typedef enum +{ + ELF_K_NONE, /* Unknown. */ + ELF_K_AR, /* Archive. */ + ELF_K_COFF, /* Stupid old COFF. */ + ELF_K_ELF, /* ELF file. */ + /* Keep this the last entry. */ + ELF_K_NUM +} Elf_Kind; + + +/* Archive member header. */ +typedef struct +{ + char *ar_name; /* Name of archive member. */ + time_t ar_date; /* File date. */ + uid_t ar_uid; /* User ID. */ + gid_t ar_gid; /* Group ID. */ + mode_t ar_mode; /* File mode. */ + off_t ar_size; /* File size. */ + char *ar_rawname; /* Original name of archive member. */ +} Elf_Arhdr; + + +/* Archive symbol table entry. */ +typedef struct +{ + char *as_name; /* Symbol name. */ + size_t as_off; /* Offset for this file in the archive. */ + unsigned long int as_hash; /* Hash value of the name. */ +} Elf_Arsym; + + +/* Descriptor for the ELF file. */ +typedef struct Elf Elf; + +/* Descriptor for ELF file section. */ +typedef struct Elf_Scn Elf_Scn; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Return descriptor for ELF file to work according to CMD. */ +extern Elf *elf_begin (int __fildes, Elf_Cmd __cmd, Elf *__ref); + +/* Create a clone of an existing ELF descriptor. */ + extern Elf *elf_clone (Elf *__elf, Elf_Cmd __cmd); + +/* Create descriptor for memory region. */ +extern Elf *elf_memory (char *__image, size_t __size); + +/* Advance archive descriptor to next element. */ +extern Elf_Cmd elf_next (Elf *__elf); + +/* Free resources allocated for ELF. */ +extern int elf_end (Elf *__elf); + +/* Update ELF descriptor and write file to disk. */ +extern off_t elf_update (Elf *__elf, Elf_Cmd __cmd); + +/* Determine what kind of file is associated with ELF. */ +extern Elf_Kind elf_kind (Elf *__elf) __attribute__ ((__pure__)); + +/* Get the base offset for an object file. */ +extern off_t elf_getbase (Elf *__elf); + + +/* Retrieve file identification data. */ +extern char *elf_getident (Elf *__elf, size_t *__ptr); + +/* Retrieve class-dependent object file header. */ +extern Elf32_Ehdr *elf32_getehdr (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Ehdr *elf64_getehdr (Elf *__elf); + +/* Create ELF header if none exists. */ +extern Elf32_Ehdr *elf32_newehdr (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Ehdr *elf64_newehdr (Elf *__elf); + +/* Retrieve class-dependent program header table. */ +extern Elf32_Phdr *elf32_getphdr (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Phdr *elf64_getphdr (Elf *__elf); + +/* Create ELF program header. */ +extern Elf32_Phdr *elf32_newphdr (Elf *__elf, size_t __cnt); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Phdr *elf64_newphdr (Elf *__elf, size_t __cnt); + + +/* Get section at INDEX. */ +extern Elf_Scn *elf_getscn (Elf *__elf, size_t __index); + +/* Get index of section. */ +extern size_t elf_ndxscn (Elf_Scn *__scn); + +/* Get section with next section index. */ +extern Elf_Scn *elf_nextscn (Elf *__elf, Elf_Scn *__scn); + +/* Create a new section and append it at the end of the table. */ +extern Elf_Scn *elf_newscn (Elf *__elf); + +/* Get the number of sections in the ELF file. If the file uses more + sections than can be represented in the e_shnum field of the ELF + header the information from the sh_size field in the zeroth section + header is used. */ +extern int elf_getshnum (Elf *__elf, size_t *__dst); + + +/* Get the section index of the section header string table in the ELF + file. If the index cannot be represented in the e_shnum field of + the ELF header the information from the sh_link field in the zeroth + section header is used. */ +extern int elf_getshstrndx (Elf *__elf, size_t *__dst); + + +/* Retrieve section header of ELFCLASS32 binary. */ +extern Elf32_Shdr *elf32_getshdr (Elf_Scn *__scn); +/* Similar for ELFCLASS64. */ +extern Elf64_Shdr *elf64_getshdr (Elf_Scn *__scn); + + +/* Set or clear flags for ELF file. */ +extern unsigned int elf_flagelf (Elf *__elf, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the ELF header. */ +extern unsigned int elf_flagehdr (Elf *__elf, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the ELF program header. */ +extern unsigned int elf_flagphdr (Elf *__elf, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the given ELF section. */ +extern unsigned int elf_flagscn (Elf_Scn *__scn, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the given ELF data. */ +extern unsigned int elf_flagdata (Elf_Data *__data, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the given ELF section header. */ +extern unsigned int elf_flagshdr (Elf_Scn *__scn, Elf_Cmd __cmd, + unsigned int __flags); + + +/* Get data from section while translating from file representation + to memory representation. */ +extern Elf_Data *elf_getdata (Elf_Scn *__scn, Elf_Data *__data); + +/* Get uninterpreted section content. */ +extern Elf_Data *elf_rawdata (Elf_Scn *__scn, Elf_Data *__data); + +/* Create new data descriptor for section SCN. */ +extern Elf_Data *elf_newdata (Elf_Scn *__scn); + + +/* Return pointer to string at OFFSET in section INDEX. */ +extern char *elf_strptr (Elf *__elf, size_t __index, size_t __offset); + + +/* Return header of archive. */ +extern Elf_Arhdr *elf_getarhdr (Elf *__elf); + +/* Select archive element at OFFSET. */ +extern size_t elf_rand (Elf *__elf, size_t __offset); + +/* Get symbol table of archhive. */ +extern Elf_Arsym *elf_getarsym (Elf *__elf, size_t *__ptr); + + +/* Control ELF descriptor. */ +extern int elf_cntl (Elf *__elf, Elf_Cmd __cmd); + +/* Retrieve uninterpreted file contents. */ +extern char *elf_rawfile (Elf *__elf, size_t *__ptr); + + +/* Return size of array of COUNT elements of the type denoted by TYPE + in the external representation. The binary class is taken from ELF. + The result is based on version VERSION of the ELF standard. */ +extern size_t elf32_fsize (Elf_Type __type, size_t __count, + unsigned int __version) + __attribute__ ((__const__)); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern size_t elf64_fsize (Elf_Type __type, size_t __count, + unsigned int __version) + __attribute__ ((__const__)); + + +/* Convert data structure from the representation in the file represented + by ELF to their memory representation. */ +extern Elf_Data *elf32_xlatetom (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); +/* Same for 64 bit class. */ +extern Elf_Data *elf64_xlatetom (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); + +/* Convert data structure from to the representation in memory + represented by ELF file representation. */ +extern Elf_Data *elf32_xlatetof (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); +/* Same for 64 bit class. */ +extern Elf_Data *elf64_xlatetof (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); + + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int elf_errno (void); + +/* Return error string for ERROR. If ERROR is zero, return error string + for most recent error or NULL is none occurred. If ERROR is -1 the + behaviour is similar to the last case except that not NULL but a legal + string is returned. */ +extern const char *elf_errmsg (int __error); + + +/* Coordinate ELF library and application versions. */ +extern unsigned int elf_version (unsigned int __version); + +/* Set fill bytes used to fill holes in data structures. */ +extern void elf_fill (int __fill); + +/* Compute hash value. */ +extern unsigned long int elf_hash (const char *__string) + __attribute__ ((__pure__)); + + +/* Compute simple checksum from permanent parts of the ELF file. */ +extern long int elf32_checksum (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern long int elf64_checksum (Elf *__elf); + +#ifdef __cplusplus +} +#endif + +#endif /* libelf.h */ diff --git a/libelf/libelf.map b/libelf/libelf.map new file mode 100644 index 00000000..f416da7f --- /dev/null +++ b/libelf/libelf.map @@ -0,0 +1,106 @@ +ELFUTILS_1.0 { + global: + elf32_checksum; + elf32_fsize; + elf32_getehdr; + elf32_getphdr; + elf32_getshdr; + elf32_newehdr; + elf32_newphdr; + elf32_xlatetof; + elf32_xlatetom; + elf64_checksum; + elf64_fsize; + elf64_getehdr; + elf64_getphdr; + elf64_getshdr; + elf64_newehdr; + elf64_newphdr; + elf64_xlatetof; + elf64_xlatetom; + elf_begin; + elf_clone; + elf_cntl; + elf_end; + elf_errmsg; + elf_errno; + elf_fill; + elf_flagdata; + elf_flagehdr; + elf_flagelf; + elf_flagphdr; + elf_flagscn; + elf_flagshdr; + elf_getarhdr; + elf_getarsym; + elf_getbase; + elf_getdata; + elf_getident; + elf_getscn; + elf_getshnum; + elf_getshstrndx; + elf_hash; + elf_kind; + elf_memory; + elf_ndxscn; + elf_newdata; + elf_newscn; + elf_next; + elf_nextscn; + elf_rand; + elf_rawdata; + elf_rawfile; + elf_scncnt; + elf_strptr; + elf_update; + elf_version; + gelf_checksum; + gelf_freechunk; + gelf_fsize; + gelf_getclass; + gelf_getdyn; + gelf_getehdr; + gelf_getmove; + gelf_getphdr; + gelf_getrel; + gelf_getrela; + gelf_getshdr; + gelf_getsym; + gelf_getsyminfo; + gelf_getsymshndx; + gelf_getverdaux; + gelf_getverdef; + gelf_getvernaux; + gelf_getverneed; + gelf_getversym; + gelf_newehdr; + gelf_newphdr; + gelf_rawchunk; + gelf_update_dyn; + gelf_update_ehdr; + gelf_update_move; + gelf_update_phdr; + gelf_update_rel; + gelf_update_rela; + gelf_update_shdr; + gelf_update_sym; + gelf_update_syminfo; + gelf_update_symshndx; + gelf_update_verdaux; + gelf_update_verdef; + gelf_update_vernaux; + gelf_update_verneed; + gelf_update_versym; + gelf_xlatetof; + gelf_xlatetom; + nlist; + + local: + *; +}; + +ELFUTILS_1.1 { + global: + gelf_getlib; + gelf_update_lib; +} ELFUTILS_1.0; diff --git a/libelf/libelfP.h b/libelf/libelfP.h new file mode 100644 index 00000000..100f349a --- /dev/null +++ b/libelf/libelfP.h @@ -0,0 +1,534 @@ +/* Internal interfaces for libelf. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 Red Hat, Inc. + Contributed by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _LIBELFP_H +#define _LIBELFP_H 1 + +#include +#include +#include + +/* gettext helper macros. */ +#define _(Str) dgettext ("libelf", Str) + + +/* Helper Macros to write 32 bit and 64 bit functions. */ +#define __elfw2_(Bits, Name) __elf##Bits##_##Name +#define elfw2_(Bits, Name) elf##Bits##_##Name +#define ElfW2_(Bits, Name) Elf##Bits##_##Name +#define ELFW2_(Bits, Name) ELF##Bits##_##Name +#define ELFW_(Name, Bits) Name##Bits +#define __elfw2(Bits, Name) __elfw2_(Bits, Name) +#define elfw2(Bits, Name) elfw2_(Bits, Name) +#define ElfW2(Bits, Name) ElfW2_(Bits, Name) +#define ELFW2(Bits, Name) ELFW2_(Bits, Name) +#define ELFW(Name, Bits) ELFW_(Name, Bits) + + +/* Sizes of the external types, for 32 bits objects. */ +#define ELF32_FSZ_ADDR 4 +#define ELF32_FSZ_OFF 4 +#define ELF32_FSZ_HALF 2 +#define ELF32_FSZ_WORD 4 +#define ELF32_FSZ_SWORD 4 +#define ELF32_FSZ_XWORD 8 +#define ELF32_FSZ_SXWORD 8 + +/* Same for 64 bits objects. */ +#define ELF64_FSZ_ADDR 8 +#define ELF64_FSZ_OFF 8 +#define ELF64_FSZ_HALF 2 +#define ELF64_FSZ_WORD 4 +#define ELF64_FSZ_SWORD 4 +#define ELF64_FSZ_XWORD 8 +#define ELF64_FSZ_SXWORD 8 + + +/* This is an extension of the ELF_F_* enumeration. The values here are + not part of the library interface, they are only used internally. */ +enum +{ + ELF_F_MMAPPED = 0x40, + ELF_F_MALLOCED = 0x80, + ELF_F_FILEDATA = 0x100 +}; + + +/* Get definition of all the external types. */ +#include "exttypes.h" + + +/* Error values. */ +enum +{ + ELF_E_NOERROR = 0, + ELF_E_UNKNOWN_ERROR, + ELF_E_UNKNOWN_VERSION, + ELF_E_UNKNOWN_TYPE, + ELF_E_INVALID_HANDLE, + ELF_E_SOURCE_SIZE, + ELF_E_DEST_SIZE, + ELF_E_INVALID_ENCODING, + ELF_E_NOMEM, + ELF_E_INVALID_FILE, + ELF_E_INVALID_OP, + ELF_E_NO_VERSION, + ELF_E_INVALID_CMD, + ELF_E_RANGE, + ELF_E_ARCHIVE_FMAG, + ELF_E_INVALID_ARCHIVE, + ELF_E_NO_ARCHIVE, + ELF_E_NO_INDEX, + ELF_E_READ_ERROR, + ELF_E_WRITE_ERROR, + ELF_E_INVALID_CLASS, + ELF_E_INVALID_INDEX, + ELF_E_INVALID_OPERAND, + ELF_E_INVALID_SECTION, + ELF_E_INVALID_COMMAND, + ELF_E_WRONG_ORDER_EHDR, + ELF_E_FD_DISABLED, + ELF_E_FD_MISMATCH, + ELF_E_OFFSET_RANGE, + ELF_E_NOT_NUL_SECTION, + ELF_E_DATA_MISMATCH, + ELF_E_INVALID_SECTION_HEADER, + ELF_E_INVALID_DATA, + ELF_E_DATA_ENCODING, + ELF_E_SECTION_TOO_SMALL, + ELF_E_INVALID_ALIGN, + ELF_E_INVALID_SHENTSIZE, + ELF_E_UPDATE_RO, + ELF_E_NOFILE, + ELF_E_GROUP_NOT_REL, + ELF_E_INVALID_PHDR, + ELF_E_NO_PHDR, + /* Keep this as the last entry. */ + ELF_E_NUM +}; + + +/* The visible `Elf_Data' type is not sufficent for some operations due + to a misdesigned interface. Extend it for internal purposes. */ +typedef struct +{ + Elf_Data d; + Elf_Scn *s; +} Elf_Data_Scn; + + +/* List of `Elf_Data' descriptors. This is what makes up the section + contents. */ +typedef struct Elf_Data_List +{ + /* `data' *must* be the first element in the struct. */ + Elf_Data_Scn data; + struct Elf_Data_List *next; + int flags; +} Elf_Data_List; + + +/* Descriptor for ELF section. */ +struct Elf_Scn +{ + /* We have to distinguish several different situations: + + 1. the section is user created. Therefore there is no file or memory + region to read the data from. Here we have two different subcases: + + a) data was not yet added (before the first `elf_newdata' call) + + b) at least one data set is available + + 2. this is a section from a file/memory region. We have to read the + current content in one data block if we have to. But we don't + read the data until it is necessary. So we have the subcases: + + a) the section in the file has size zero (for whatever reason) + + b) the data of the file is not (yet) read + + c) the data is read and available. + + In addition to this we have different data sets, the raw and the converted + data. This distinction only exists for the data read from the file. + All user-added data set (all but the first when read from the file or + all of them for user-create sections) are the same in both formats. + We don't create the converted data before it is necessary. + + The `data_read' element signals whether data is available in the + raw format. + + If there is data from the file/memory region or if read one data + set is added the `rawdata_list_read' pointer in non-NULL and points + to the last filled data set. `raw_datalist_rear' is therefore NULL + only if there is no data set at all. + + This so far allows to distinguish all but two cases (given that the + `rawdata_list' and `data_list' entries are initialized to zero) is + between not yet loaded data from the file/memory region and a section + with zero size and type ELF_T_BYTE. */ + Elf_Data_List data_list; /* List of data buffers. */ + Elf_Data_List *data_list_rear; /* Pointer to the rear of the data list. */ + + Elf_Data_Scn rawdata; /* Uninterpreted data of the section. */ + + int data_read; /* Nonzero if the section was created by the + user or if the data from the file/memory + is read. */ + + size_t index; /* Index of this section. */ + struct Elf *elf; /* The underlying ELF file. */ + + union + { + Elf32_Shdr *e32; /* Pointer to 32bit section header. */ + Elf64_Shdr *e64; /* Pointer to 64bit section header. */ + } shdr; + + unsigned int shdr_flags; /* Section header modified? */ + unsigned int flags; /* Section changed in size? */ + + char *rawdata_base; /* The unmodified data of the section. */ + char *data_base; /* The converted data of the section. */ + + struct Elf_ScnList *list; /* Pointer the the section list element the + data is in. */ +}; + + +/* List of section. */ +typedef struct Elf_ScnList +{ + unsigned int cnt; /* Number of elements of 'data' used. */ + unsigned int max; /* Number of elements of 'data' allocated. */ + struct Elf_ScnList *next; /* Next block of sections. */ + struct Elf_Scn data[0]; /* Section data. */ +} Elf_ScnList; + + +/* The ELF descriptor. */ +struct Elf +{ + /* What kind of file is underneath (ELF file, archive...). */ + Elf_Kind kind; + + /* Command used to create this descriptor. */ + Elf_Cmd cmd; + + /* The binary class. */ + unsigned int class; + + /* The used file descriptor. -1 if not available anymore. */ + int fildes; + + /* Offset in the archive this file starts or zero. */ + off_t start_offset; + + /* Size of the file in the archive or the entire file size, or ~0 + for an (yet) unknown size. */ + size_t maximum_size; + + /* Address to which the file was mapped. NULL if not mapped. */ + void *map_address; + + /* Describes the way the memory was allocated and if the dirty bit is + signalled it means that the whole file has to be rewritten since + the layout changed. */ + int flags; + + /* When created for an archive member this points to the descriptor + for the archive. */ + Elf *parent; + + /* Lock to handle multithreaded programs. */ + rwlock_define (,lock); + + /* Reference counting for the descriptor. */ + int ref_count; + + struct Elf *next; /* Used in list of archive descriptors. */ + + union + { + struct + { + int ehdr_flags; /* Flags (dirty) for ELF header. */ + int phdr_flags; /* Flags (dirty|malloc) for program header. */ + int shdr_malloced; /* Nonzero if shdr array was allocated. */ + + /* The next fields are only useful when testing for ==/!= NULL. */ + void *ehdr; + void *shdr; + void *phdr; + + Elf_ScnList *scns_last; /* Last element in the section list. + If NULL the data has not yet been + read from the file. */ + unsigned int scnincr; /* Number of sections allocate the last + time. */ + off64_t sizestr_offset; /* Offset of the size string in the parent + if this is an archive member. */ + } elf; + + struct + { + int ehdr_flags; /* Flags (dirty) for ELF header. */ + int phdr_flags; /* Flags (dirty|malloc) for program header. */ + int shdr_malloced; /* Nonzero if shdr array was allocated. */ + + Elf32_Ehdr *ehdr; /* Pointer to the ELF header. This is + never malloced. */ + Elf32_Shdr *shdr; /* Used when reading from a file. */ + Elf32_Phdr *phdr; /* Pointer to the program header array. */ + Elf_ScnList *scns_last; /* Last element in the section list. + If NULL the data has not yet been + read from the file. */ + unsigned int scnincr; /* Number of sections allocate the last + time. */ + off64_t sizestr_offset; /* Offset of the size string in the parent + if this is an archive member. */ + Elf32_Ehdr ehdr_mem; /* Memory used for ELF header when not + mmaped. */ + char __e32scnspad[sizeof (Elf64_Ehdr) - sizeof (Elf32_Ehdr)]; + + /* The section array. */ + Elf_ScnList scns; + } elf32; + + struct + { + int ehdr_flags; /* Flags (dirty) for ELF header. */ + int phdr_flags; /* Flags (dirty|malloc) for program header. */ + int shdr_malloced; /* Nonzero if shdr array was allocated. */ + + Elf64_Ehdr *ehdr; /* Pointer to the ELF header. This is + never malloced. */ + Elf64_Shdr *shdr; /* Used when reading from a file. */ + Elf64_Phdr *phdr; /* Pointer to the program header array. */ + Elf_ScnList *scns_last; /* Last element in the section list. + If NULL the data has not yet been + read from the file. */ + unsigned int scnincr; /* Number of sections allocate the last + time. */ + off64_t sizestr_offset; /* Offset of the size string in the parent + if this is an archive member. */ + Elf64_Ehdr ehdr_mem; /* Memory used for ELF header when not + mmaped. */ + + /* The section array. */ + Elf_ScnList scns; + } elf64; + + struct + { + int has_index; /* Set when file has index. 0 means + undecided, > 0 means it has one. */ + Elf_Arsym *ar_sym; /* Symbol table returned by elf_getarsym. */ + size_t ar_sym_num; /* Number of entries in `ar_sym'. */ + char *long_names; /* If no index is available but long names + are used this elements points to the data.*/ + size_t long_names_len; /* Length of the long name table. */ + off_t offset; /* Offset in file we are currently at. + elf_next() advances this to the next + member of the archive. */ + Elf_Arhdr elf_ar_hdr; /* Structure returned by 'elf_getarhdr'. */ + struct ar_hdr ar_hdr; /* Header read from file. */ + char ar_name[16]; /* NUL terminated ar_name of elf_ar_hdr. */ + char raw_name[17]; /* This is a buffer for the NUL terminated + named raw_name used in the elf_ar_hdr. */ + struct Elf *children; /* List of all descriptors for this archive. */ + } ar; + } state; + + /* There absolutely never must be anything following the union. */ +}; + + +/* Type of the conversion functions. These functions will convert the + byte order. */ +typedef void (*xfct_t) (void *, const void *, size_t, int); + +/* The table with the function pointers. */ +extern const xfct_t __elf_xfctstom[EV_NUM - 1][EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] attribute_hidden; +extern const xfct_t __elf_xfctstof[EV_NUM - 1][EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] attribute_hidden; + + +/* Array with sizes of the external types indexed by ELF version, binary + class, and type. */ +extern const size_t __libelf_type_sizes[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] attribute_hidden; +/* We often have to access the size for a type in the current version. */ +#if EV_NUM != 2 +# define elf_typesize(class,type,n) \ + elfw2(class,fsize) (type, n, __libelf_version) +#else +# define elf_typesize(class,type,n) \ + (__libelf_type_sizes[EV_CURRENT - 1][ELFW(ELFCLASS,class) - 1][type] * n) +#endif + +/* Currently selected version of the ELF specification. */ +extern unsigned int __libelf_version attribute_hidden; + +/* The byte value used for filling gaps. */ +extern int __libelf_fill_byte attribute_hidden; + +/* Nonzero if the version was set. */ +extern int __libelf_version_initialized attribute_hidden; + + +/* The libelf API does not have such a function but it is still useful. + Get the memory size for the given type. + + These functions cannot be marked internal since they are aliases + of the export elfXX_fsize functions.*/ +extern size_t __elf32_msize (Elf_Type __type, size_t __count, + unsigned int __version); +extern size_t __elf64_msize (Elf_Type __type, size_t __count, + unsigned int __version); + + +/* Create Elf descriptor from memory image. */ +extern Elf *__libelf_read_mmaped_file (int fildes, void *map_address, + off_t offset, size_t maxsize, + Elf_Cmd cmd, Elf *parent) + internal_function; + +/* Set error value. */ +extern void __libelf_seterrno (int value) internal_function; + +/* Get the next archive header. */ +extern int __libelf_next_arhdr (Elf *elf) internal_function; + +/* Read all of the file associated with the descriptor. */ +extern char *__libelf_readall (Elf *elf) internal_function; + +/* Read the complete section table and convert the byte order if necessary. */ +extern int __libelf_readsections (Elf *elf) internal_function; + +/* Store the information for the raw data in the `rawdata_list' element. */ +extern int __libelf_set_rawdata (Elf_Scn *scn) internal_function; + + +/* Helper functions for elf_update. */ +extern off_t __elf32_updatenull (Elf *elf, int *change_bop, size_t shnum) + internal_function; +extern off_t __elf64_updatenull (Elf *elf, int *change_bop, size_t shnum) + internal_function; + +extern int __elf32_updatemmap (Elf *elf, int change_bo, size_t shnum) + internal_function; +extern int __elf64_updatemmap (Elf *elf, int change_bo, size_t shnum) + internal_function; +extern int __elf32_updatefile (Elf *elf, int change_bo, size_t shnum) + internal_function; +extern int __elf64_updatefile (Elf *elf, int change_bo, size_t shnum) + internal_function; + + +/* Alias for exported functions to avoid PLT entries. */ +extern int __elf_end_internal (Elf *__elf); +extern Elf *__elf_begin_internal (int __fildes, Elf_Cmd __cmd, Elf *__ref) + attribute_hidden; +extern Elf32_Ehdr *__elf32_getehdr_internal (Elf *__elf) attribute_hidden; +extern Elf64_Ehdr *__elf64_getehdr_internal (Elf *__elf) attribute_hidden; +extern Elf32_Ehdr *__elf32_newehdr_internal (Elf *__elf) attribute_hidden; +extern Elf64_Ehdr *__elf64_newehdr_internal (Elf *__elf) attribute_hidden; +extern Elf32_Phdr *__elf32_getphdr_internal (Elf *__elf) attribute_hidden; +extern Elf64_Phdr *__elf64_getphdr_internal (Elf *__elf) attribute_hidden; +extern Elf32_Phdr *__elf32_newphdr_internal (Elf *__elf, size_t __cnt) + attribute_hidden; +extern Elf64_Phdr *__elf64_newphdr_internal (Elf *__elf, size_t __cnt) + attribute_hidden; +extern int __elf_getshnum_internal (Elf *__elf, size_t *__dst) + attribute_hidden; +extern int __elf_getshstrndx_internal (Elf *__elf, size_t *__dst) + attribute_hidden; +extern Elf32_Shdr *__elf32_getshdr_internal (Elf_Scn *__scn) attribute_hidden; +extern Elf64_Shdr *__elf64_getshdr_internal (Elf_Scn *__scn) attribute_hidden; +extern Elf_Scn *__elf_getscn_internal (Elf *__elf, size_t __index) + attribute_hidden; +extern Elf_Scn *__elf_nextscn_internal (Elf *__elf, Elf_Scn *__scn) + attribute_hidden; +extern Elf_Data *__elf_getdata_internal (Elf_Scn *__scn, Elf_Data *__data) + attribute_hidden; +extern Elf_Data *__elf_rawdata_internal (Elf_Scn *__scn, Elf_Data *__data) + attribute_hidden; +extern char *__elf_strptr_internal (Elf *__elf, size_t __index, + size_t __offset) attribute_hidden; +extern Elf_Data *__elf32_xlatetom_internal (Elf_Data *__dest, + const Elf_Data *__src, + unsigned int __encode) + attribute_hidden; +extern Elf_Data *__elf64_xlatetom_internal (Elf_Data *__dest, + const Elf_Data *__src, + unsigned int __encode) + attribute_hidden; +extern Elf_Data *__elf32_xlatetof_internal (Elf_Data *__dest, + const Elf_Data *__src, + unsigned int __encode) + attribute_hidden; +extern Elf_Data *__elf64_xlatetof_internal (Elf_Data *__dest, + const Elf_Data *__src, + unsigned int __encode) + attribute_hidden; +extern unsigned int __elf_version_internal (unsigned int __version) + attribute_hidden; +extern unsigned long int __elf_hash_internal (const char *__string) + __attribute__ ((__pure__, visibility ("hidden"))); +extern long int __elf32_checksum_internal (Elf *__elf) attribute_hidden; +extern long int __elf64_checksum_internal (Elf *__elf) attribute_hidden; + + +extern GElf_Ehdr *__gelf_getehdr_internal (Elf *__elf, GElf_Ehdr *__dest); +extern size_t __gelf_fsize_internal (Elf *__elf, Elf_Type __type, + size_t __count, unsigned int __version) + attribute_hidden; +extern GElf_Shdr *__gelf_getshdr_internal (Elf_Scn *__scn, GElf_Shdr *__dst) + attribute_hidden; +extern GElf_Sym *__gelf_getsym_internal (Elf_Data *__data, int __ndx, + GElf_Sym *__dst) attribute_hidden; + + +extern uint32_t __libelf_crc32 (uint32_t crc, unsigned char *buf, size_t len) + attribute_hidden; + + +/* We often have to update a flag iff a value changed. Make this + convenient. None of the parameters must have a side effect. */ +#ifdef __GNUC__ +# define update_if_changed(var, exp, flag) \ + do { \ + __typeof__ (var) *_var = &(var); \ + __typeof__ (exp) _exp = (exp); \ + if (*_var != _exp) \ + { \ + *_var = _exp; \ + (flag) |= ELF_F_DIRTY; \ + } \ + } while (0) +#else +# define update_if_changed(var, exp, flag) \ + do { \ + if ((var) != (exp)) \ + { \ + (var) = (exp); \ + (flag) |= ELF_F_DIRTY; \ + } \ + } while (0) +#endif + +#endif /* libelfP.h */ diff --git a/libelf/libelf_crc32.c b/libelf/libelf_crc32.c new file mode 100644 index 00000000..6971be07 --- /dev/null +++ b/libelf/libelf_crc32.c @@ -0,0 +1,23 @@ +/* Copyright (C) 2002 Red Hat, 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#define crc32 attribute_hidden __libelf_crc32 +#define LIB_SYSTEM_H 1 +#include +#include "../lib/crc32.c" diff --git a/libelf/libelf_next_prime.c b/libelf/libelf_next_prime.c new file mode 100644 index 00000000..4a71c477 --- /dev/null +++ b/libelf/libelf_next_prime.c @@ -0,0 +1,21 @@ +/* Copyright (C) 2002 Red Hat, 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#define next_prime attribute_hidden __libelf_next_prime +#include "../lib/next_prime.c" diff --git a/libelf/nlist.c b/libelf/nlist.c new file mode 100644 index 00000000..b9ff2130 --- /dev/null +++ b/libelf/nlist.c @@ -0,0 +1,224 @@ +/* Extract symbol list from binary. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "libelfP.h" + + +struct hashentry +{ + const char *str; + GElf_Sym sym; +}; +#define TYPE struct hashentry +/* XXX Use a better hash function some day. */ +#define HASHFCT(str, len) INTUSE(elf_hash) (str) +#define COMPARE(p1, p2) strcmp ((p1)->str, (p2)->str) +#define CLASS static +#define PREFIX nlist_ +#define xcalloc(n, m) calloc (n, m) +#define next_prime(s) __libelf_next_prime (s) +#include + + +int +nlist (const char *filename, struct nlist *nl) +{ + int fd; + Elf *elf; + Elf_Scn *scn = NULL; + Elf_Scn *symscn = NULL; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = NULL; + Elf_Data *data; + struct nlist_fshash *table; + size_t nsyms; + size_t cnt; + + /* Open the file. */ + fd = open (filename, O_RDONLY); + if (fd == -1) + { + __libelf_seterrno (ELF_E_NOFILE); + goto fail; + } + + /* For compatibility reasons (`nlist' existed before ELF and libelf) + we don't expect the caller to set the ELF version. Do this here + if it hasn't happened yet. */ + if (__libelf_version_initialized == 0) + INTUSE(elf_version) (EV_CURRENT); + + /* Now get an ELF descriptor. */ + elf = INTUSE(elf_begin) (fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) + goto fail; + + /* Find a symbol table. We prefer the real symbol table but if it + does not exist use the dynamic symbol table. */ + while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL) + { + shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem); + if (shdr == NULL) + goto fail_close; + + /* That is what we are looking for. */ + if (shdr->sh_type == SHT_SYMTAB) + { + symscn = scn; + break; + } + + /* Better than nothing. Remember this section. */ + if (shdr->sh_type == SHT_DYNSYM) + symscn = scn; + } + + if (symscn == NULL) + /* We haven't found anything. Fail. */ + goto fail_close; + + /* Re-get the section header in case we found only the dynamic symbol + table. */ + if (scn == NULL) + shdr = INTUSE(gelf_getshdr) (symscn, &shdr_mem); + /* SHDR->SH_LINK now contains the index of the string section. */ + + /* Get the data for the symbol section. */ + data = INTUSE(elf_getdata) (symscn, NULL); + if (data == NULL) + goto fail_close; + + /* How many symbols are there? */ + nsyms = (shdr->sh_size + / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, data->d_version)); + + /* Create the hash table. */ + table = nlist_fshash_init (nsyms); + if (table == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto fail_close; + } + + /* Iterate over all the symbols in the section. */ + for (cnt = 0; cnt < nsyms; ++cnt) + { + struct hashentry mem; + GElf_Sym *sym; + + /* Get the symbol. */ + sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym); + if (sym == NULL) + goto fail_dealloc; + + /* Get the name of the symbol. */ + mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name); + if (mem.str == NULL) + goto fail_dealloc; + + /* Don't allow zero-length strings. */ + if (mem.str[0] == '\0') + continue; + + /* And add it to the hash table. Note that we are using the + overwrite version. This will ensure that + a) global symbols are preferred over local symbols since + they are all located at the end + b) if there are multiple local symbols with the same name + the last one is used. + */ + (void) nlist_fshash_overwrite (table, mem.str, 0, &mem); + } + + /* Now it is time to look for the symbols the user asked for. + XXX What is a `null name/null string'? This is what the + standard says terminates the list. Is it a null pointer + or a zero-length string? We test for both... */ + while (nl->n_name != NULL && nl->n_name[0] != '\0') + { + struct hashentry search; + const struct hashentry *found; + + /* Search for a matching entry in the hash table. */ + search.str = nl->n_name; + found = nlist_fshash_find (table, nl->n_name, 0, &search); + + if (found != NULL) + { + /* Found it. */ + nl->n_value = found->sym.st_value; + nl->n_scnum = found->sym.st_shndx; + nl->n_type = GELF_ST_TYPE (found->sym.st_info); + /* XXX What shall we fill in the next fields? */ + nl->n_sclass = 0; + nl->n_numaux = 0; + } + else + { + /* Not there. */ + nl->n_value = 0; + nl->n_scnum = 0; + nl->n_type = 0; + nl->n_sclass = 0; + nl->n_numaux = 0; + } + + /* Next search request. */ + ++nl; + } + + /* Free the resources. */ + nlist_fshash_fini (table); + + /* We do not need the ELF descriptor anymore. */ + (void) INTUSE(elf_end) (elf); + + return 0; + + fail_dealloc: + nlist_fshash_fini (table); + + fail_close: + /* We do not need the ELF descriptor anymore. */ + (void) INTUSE(elf_end) (elf); + + fail: + /* We have to set all entries to zero. */ + while (nl->n_name != NULL && nl->n_name[0] != '\0') + { + nl->n_value = 0; + nl->n_scnum = 0; + nl->n_type = 0; + nl->n_sclass = 0; + nl->n_numaux = 0; + + /* Next entry. */ + ++nl; + } + + return -1; +} diff --git a/libelf/nlist.h b/libelf/nlist.h new file mode 100644 index 00000000..298f9a24 --- /dev/null +++ b/libelf/nlist.h @@ -0,0 +1,44 @@ +/* Interface for nlist. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _NLIST_H +#define _NLIST_H 1 + + +/* Symbol list type. */ +struct nlist +{ + char *n_name; /* Symbol name. */ + long int n_value; /* Value of symbol. */ + short int n_scnum; /* Section number found in. */ + unsigned short int n_type; /* Type of symbol. */ + char n_sclass; /* Storage class. */ + char n_numaux; /* Number of auxiliary entries. */ +}; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Get specified entries from file. */ +extern int nlist (__const char *__filename, struct nlist *__nl); + +#ifdef __cplusplus +} +#endif + +#endif /* nlist.h */ diff --git a/libelf/version_xlate.h b/libelf/version_xlate.h new file mode 100644 index 00000000..2366cbf2 --- /dev/null +++ b/libelf/version_xlate.h @@ -0,0 +1,208 @@ +/* Conversion functions for versioning information. + Copyright (C) 1998, 1999, 2000, 2002, 2003 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + 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, version 2. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include + +#include "libelfP.h" + + +static void +elf_cvt_Verdef (void *dest, const void *src, size_t len, int encode) +{ + /* We have two different record types: ElfXX_Verndef and ElfXX_Verdaux. + To recognize them we have to walk the data structure and convert + them one after the other. The ENCODE parameter specifies whether + we are encoding or decoding. When we are encoding we can immediately + use the data in the buffer; if not, we have to decode the data before + using it. */ + size_t def_offset = 0; + GElf_Verdef *ddest; + GElf_Verdef *dsrc; + + /* We rely on the types being all the same size. */ + assert (sizeof (GElf_Verdef) == sizeof (Elf32_Verdef)); + assert (sizeof (GElf_Verdaux) == sizeof (Elf32_Verdaux)); + assert (sizeof (GElf_Verdef) == sizeof (Elf64_Verdef)); + assert (sizeof (GElf_Verdaux) == sizeof (Elf64_Verdaux)); + + if (len == 0) + return; + + do + { + size_t aux_offset; + GElf_Verdaux *asrc; + + /* Test for correct offset. */ + if (def_offset + sizeof (GElf_Verdef) > len) + return; + + /* Work the tree from the first record. */ + ddest = (GElf_Verdef *) ((char *) dest + def_offset); + dsrc = (GElf_Verdef *) ((char *) src + def_offset); + + /* Decode first if necessary. */ + if (! encode) + { + ddest->vd_version = bswap_16 (dsrc->vd_version); + ddest->vd_flags = bswap_16 (dsrc->vd_flags); + ddest->vd_ndx = bswap_16 (dsrc->vd_ndx); + ddest->vd_cnt = bswap_16 (dsrc->vd_cnt); + ddest->vd_hash = bswap_32 (dsrc->vd_hash); + ddest->vd_aux = bswap_32 (dsrc->vd_aux); + ddest->vd_next = bswap_32 (dsrc->vd_next); + + aux_offset = def_offset + ddest->vd_aux; + } + else + aux_offset = def_offset + dsrc->vd_aux; + + /* Handle all the auxiliary records belonging to this definition. */ + do + { + GElf_Verdaux *adest; + + /* Test for correct offset. */ + if (aux_offset + sizeof (GElf_Verdaux) > len) + return; + + adest = (GElf_Verdaux *) ((char *) dest + aux_offset); + asrc = (GElf_Verdaux *) ((char *) src + aux_offset); + + if (encode) + aux_offset += asrc->vda_next; + + adest->vda_name = bswap_32 (asrc->vda_name); + adest->vda_next = bswap_32 (asrc->vda_next); + + if (! encode) + aux_offset += adest->vda_next; + } + while (asrc->vda_next != 0); + + /* Encode now if necessary. */ + if (encode) + { + def_offset += dsrc->vd_next; + + ddest->vd_version = bswap_16 (dsrc->vd_version); + ddest->vd_flags = bswap_16 (dsrc->vd_flags); + ddest->vd_ndx = bswap_16 (dsrc->vd_ndx); + ddest->vd_cnt = bswap_16 (dsrc->vd_cnt); + ddest->vd_hash = bswap_32 (dsrc->vd_hash); + ddest->vd_aux = bswap_32 (dsrc->vd_aux); + ddest->vd_next = bswap_32 (dsrc->vd_next); + } + else + def_offset += ddest->vd_next; + } + while (dsrc->vd_next != 0); +} + + +static void +elf_cvt_Verneed (void *dest, const void *src, size_t len, int encode) +{ + /* We have two different record types: ElfXX_Verndef and ElfXX_Verdaux. + To recognize them we have to walk the data structure and convert + them one after the other. The ENCODE parameter specifies whether + we are encoding or decoding. When we are encoding we can immediately + use the data in the buffer; if not, we have to decode the data before + using it. */ + size_t need_offset = 0; + GElf_Verneed *ndest; + GElf_Verneed *nsrc; + + /* We rely on the types being all the same size. */ + assert (sizeof (GElf_Verneed) == sizeof (Elf32_Verneed)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf32_Vernaux)); + assert (sizeof (GElf_Verneed) == sizeof (Elf64_Verneed)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf64_Vernaux)); + + if (len == 0) + return; + + do + { + size_t aux_offset; + GElf_Vernaux *asrc; + + /* Test for correct offset. */ + if (need_offset + sizeof (GElf_Verneed) > len) + return; + + /* Work the tree from the first record. */ + ndest = (GElf_Verneed *) ((char *) dest + need_offset); + nsrc = (GElf_Verneed *) ((char *) src + need_offset); + + /* Decode first if necessary. */ + if (! encode) + { + ndest->vn_version = bswap_16 (nsrc->vn_version); + ndest->vn_cnt = bswap_16 (nsrc->vn_cnt); + ndest->vn_file = bswap_32 (nsrc->vn_file); + ndest->vn_aux = bswap_32 (nsrc->vn_aux); + ndest->vn_next = bswap_32 (nsrc->vn_next); + + aux_offset = need_offset + ndest->vn_aux; + } + else + aux_offset = need_offset + nsrc->vn_aux; + + /* Handle all the auxiliary records belonging to this requirement. */ + do + { + GElf_Vernaux *adest; + + /* Test for correct offset. */ + if (aux_offset + sizeof (GElf_Vernaux) > len) + return; + + adest = (GElf_Vernaux *) ((char *) dest + aux_offset); + asrc = (GElf_Vernaux *) ((char *) src + aux_offset); + + if (encode) + aux_offset += asrc->vna_next; + + adest->vna_hash = bswap_32 (asrc->vna_hash); + adest->vna_flags = bswap_16 (asrc->vna_flags); + adest->vna_other = bswap_16 (asrc->vna_other); + adest->vna_name = bswap_32 (asrc->vna_name); + adest->vna_next = bswap_32 (asrc->vna_next); + + if (! encode) + aux_offset += adest->vna_next; + } + while (asrc->vna_next != 0); + + /* Encode now if necessary. */ + if (encode) + { + need_offset += nsrc->vn_next; + + ndest->vn_version = bswap_16 (nsrc->vn_version); + ndest->vn_cnt = bswap_16 (nsrc->vn_cnt); + ndest->vn_file = bswap_32 (nsrc->vn_file); + ndest->vn_aux = bswap_32 (nsrc->vn_aux); + ndest->vn_next = bswap_32 (nsrc->vn_next); + } + else + need_offset += ndest->vn_next; + } + while (nsrc->vn_next != 0); +} diff --git a/m4/.cvsignore b/m4/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/m4/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/m4/ChangeLog b/m4/ChangeLog new file mode 100644 index 00000000..112c9c7b --- /dev/null +++ b/m4/ChangeLog @@ -0,0 +1,31 @@ +2005-02-15 Ulrich Drepper + + * Makefile.am (EXTRA_DIST): Remove glibc21.m4, intdiv0.m4, + inttypes.m4, inttypes_h.m4, inttypes-pri.m4, isc-posix.m4, + lib-ld.m4, lib-link.m4, lib-prefix.m4, stdint_h.m4, uintmax_t.m4, + and ulonglong.m4. + * glibc21.m4: Removed. + * inttypes_h.m4: Removed. + * inttypes.m4: Removed. + * inttypes-pri.m4: Removed. + * isc-posix.m4: Removed. + * lib-ld.m4: Removed. + * lib-link.m4: Removed. + * lib-prefix.m4: Removed. + * stdint_h.m4: Removed. + * uintmax_t.m4: Removed. + * ulonglong.m4: Removed. + +2002-03-22 gettextize + + * codeset.m4: Upgrade to gettext-0.11. + * gettext.m4: Upgrade to gettext-0.11. + * glibc21.m4: Upgrade to gettext-0.11. + * iconv.m4: Upgrade to gettext-0.11. + * isc-posix.m4: New file, from gettext-0.11. + * lcmessage.m4: Upgrade to gettext-0.11. + * lib-ld.m4: Upgrade to gettext-0.11. + * lib-link.m4: Upgrade to gettext-0.11. + * lib-prefix.m4: Upgrade to gettext-0.11. + * progtest.m4: Upgrade to gettext-0.11. + * Makefile.am (EXTRA_DIST): Add the new files. diff --git a/m4/Makefile.am b/m4/Makefile.am new file mode 100644 index 00000000..c77e3fbd --- /dev/null +++ b/m4/Makefile.am @@ -0,0 +1,20 @@ +## Process this file with automake to produce Makefile.in -*-Makefile-*- +## +## Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, 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, version 2. +## +## 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, write to the Free Software Foundation, +## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## + +##m4-files-begin +EXTRA_DIST = codeset.m4 gettext.m4 iconv.m4 lcmessage.m4 progtest.m4 diff --git a/m4/codeset.m4 b/m4/codeset.m4 new file mode 100644 index 00000000..59535ebc --- /dev/null +++ b/m4/codeset.m4 @@ -0,0 +1,23 @@ +# codeset.m4 serial AM1 (gettext-0.10.40) +dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +AC_DEFUN([AM_LANGINFO_CODESET], +[ + AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, + [AC_TRY_LINK([#include ], + [char* cs = nl_langinfo(CODESET);], + am_cv_langinfo_codeset=yes, + am_cv_langinfo_codeset=no) + ]) + if test $am_cv_langinfo_codeset = yes; then + AC_DEFINE(HAVE_LANGINFO_CODESET, 1, + [Define if you have and nl_langinfo(CODESET).]) + fi +]) diff --git a/m4/gettext.m4 b/m4/gettext.m4 new file mode 100644 index 00000000..0b758a67 --- /dev/null +++ b/m4/gettext.m4 @@ -0,0 +1,587 @@ +# gettext.m4 serial 16 (gettext-0.11.4) +dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2002. + +dnl Macro to add for using GNU gettext. + +dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). +dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The +dnl default (if it is not specified or empty) is 'no-libtool'. +dnl INTLSYMBOL should be 'external' for packages with no intl directory, +dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. +dnl If INTLSYMBOL is 'use-libtool', then a libtool library +dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, +dnl depending on --{enable,disable}-{shared,static} and on the presence of +dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library +dnl $(top_builddir)/intl/libintl.a will be created. +dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext +dnl implementations (in libc or libintl) without the ngettext() function +dnl will be ignored. If NEEDSYMBOL is specified and is +dnl 'need-formatstring-macros', then GNU gettext implementations that don't +dnl support the ISO C 99 formatstring macros will be ignored. +dnl INTLDIR is used to find the intl libraries. If empty, +dnl the value `$(top_builddir)/intl/' is used. +dnl +dnl The result of the configuration is one of three cases: +dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled +dnl and used. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 2) GNU gettext has been found in the system's C library. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 3) No internationalization, always use English msgid. +dnl Catalog format: none +dnl Catalog extension: none +dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. +dnl The use of .gmo is historical (it was needed to avoid overwriting the +dnl GNU format catalogs when building on a platform with an X/Open gettext), +dnl but we keep it in order not to force irrelevant filename changes on the +dnl maintainers. +dnl +AC_DEFUN([AM_GNU_GETTEXT], +[ + dnl Argument checking. + ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , + [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT +])])])])]) + ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , + [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT +])])])]) + define(gt_included_intl, ifelse([$1], [external], [no], [yes])) + define(gt_libtool_suffix_prefix, ifelse([$1], [use-libtool], [l], [])) + + AC_REQUIRE([AM_PO_SUBDIRS])dnl + ifelse(gt_included_intl, yes, [ + AC_REQUIRE([AM_INTL_SUBDIR])dnl + ]) + + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Sometimes libintl requires libiconv, so first search for libiconv. + dnl Ideally we would do this search only after the + dnl if test "$USE_NLS" = "yes"; then + dnl if test "$gt_cv_func_gnugettext_libc" != "yes"; then + dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT + dnl the configure script would need to contain the same shell code + dnl again, outside any 'if'. There are two solutions: + dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. + dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. + dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not + dnl documented, we avoid it. + ifelse(gt_included_intl, yes, , [ + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + ]) + + AC_MSG_CHECKING([whether NLS is requested]) + dnl Default is enabled NLS + AC_ARG_ENABLE(nls, + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) + AC_MSG_RESULT($USE_NLS) + AC_SUBST(USE_NLS) + + ifelse(gt_included_intl, yes, [ + BUILD_INCLUDED_LIBINTL=no + USE_INCLUDED_LIBINTL=no + ]) + LIBINTL= + LTLIBINTL= + POSUB= + + dnl If we use NLS figure out what method + if test "$USE_NLS" = "yes"; then + gt_use_preinstalled_gnugettext=no + ifelse(gt_included_intl, yes, [ + AC_MSG_CHECKING([whether included gettext is requested]) + AC_ARG_WITH(included-gettext, + [ --with-included-gettext use the GNU gettext library included here], + nls_cv_force_use_gnu_gettext=$withval, + nls_cv_force_use_gnu_gettext=no) + AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + ]) + dnl User does not insist on using GNU NLS library. Figure out what + dnl to use. If GNU gettext is available we use this. Else we have + dnl to fall back to GNU NLS library. + + dnl Add a version number to the cache macros. + define([gt_api_version], ifelse([$2], [need-formatstring-macros], 3, ifelse([$2], [need-ngettext], 2, 1))) + define([gt_cv_func_gnugettext_libc], [gt_cv_func_gnugettext]gt_api_version[_libc]) + define([gt_cv_func_gnugettext_libintl], [gt_cv_func_gnugettext]gt_api_version[_libintl]) + + AC_CACHE_CHECK([for GNU gettext in libc], gt_cv_func_gnugettext_libc, + [AC_TRY_LINK([#include +]ifelse([$2], [need-formatstring-macros], +[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +changequote(,)dnl +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +changequote([,])dnl +], [])[extern int _nl_msg_cat_cntr; +extern int *_nl_domain_bindings;], + [bindtextdomain ("", ""); +return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_domain_bindings], + gt_cv_func_gnugettext_libc=yes, + gt_cv_func_gnugettext_libc=no)]) + + if test "$gt_cv_func_gnugettext_libc" != "yes"; then + dnl Sometimes libintl requires libiconv, so first search for libiconv. + ifelse(gt_included_intl, yes, , [ + AM_ICONV_LINK + ]) + dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL + dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) + dnl because that would add "-liconv" to LIBINTL and LTLIBINTL + dnl even if libiconv doesn't exist. + AC_LIB_LINKFLAGS_BODY([intl]) + AC_CACHE_CHECK([for GNU gettext in libintl], + gt_cv_func_gnugettext_libintl, + [gt_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCINTL" + gt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBINTL" + dnl Now see whether libintl exists and does not depend on libiconv. + AC_TRY_LINK([#include +]ifelse([$2], [need-formatstring-macros], +[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +changequote(,)dnl +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +changequote([,])dnl +], [])[extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias ();], + [bindtextdomain ("", ""); +return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias (0)], + gt_cv_func_gnugettext_libintl=yes, + gt_cv_func_gnugettext_libintl=no) + dnl Now see whether libintl exists and depends on libiconv. + if test "$gt_cv_func_gnugettext_libintl" != yes && test -n "$LIBICONV"; then + LIBS="$LIBS $LIBICONV" + AC_TRY_LINK([#include +]ifelse([$2], [need-formatstring-macros], +[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +changequote(,)dnl +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +changequote([,])dnl +], [])[extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias ();], + [bindtextdomain ("", ""); +return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias (0)], + [LIBINTL="$LIBINTL $LIBICONV" + LTLIBINTL="$LTLIBINTL $LTLIBICONV" + gt_cv_func_gnugettext_libintl=yes + ]) + fi + CPPFLAGS="$gt_save_CPPFLAGS" + LIBS="$gt_save_LIBS"]) + fi + + dnl If an already present or preinstalled GNU gettext() is found, + dnl use it. But if this macro is used in GNU gettext, and GNU + dnl gettext is already preinstalled in libintl, we update this + dnl libintl. (Cf. the install rule in intl/Makefile.in.) + if test "$gt_cv_func_gnugettext_libc" = "yes" \ + || { test "$gt_cv_func_gnugettext_libintl" = "yes" \ + && test "$PACKAGE" != gettext; }; then + gt_use_preinstalled_gnugettext=yes + else + dnl Reset the values set by searching for libintl. + LIBINTL= + LTLIBINTL= + INCINTL= + fi + + ifelse(gt_included_intl, yes, [ + if test "$gt_use_preinstalled_gnugettext" != "yes"; then + dnl GNU gettext is not found in the C library. + dnl Fall back on included GNU gettext library. + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions used to generate GNU NLS library. + INTLOBJS="\$(GETTOBJS)" + BUILD_INCLUDED_LIBINTL=yes + USE_INCLUDED_LIBINTL=yes + LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV" + LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV" + LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` + fi + + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions to use GNU gettext tools. + CATOBJEXT=.gmo + fi + ]) + + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + AC_DEFINE(ENABLE_NLS, 1, + [Define to 1 if translation of program messages to the user's native language + is requested.]) + else + USE_NLS=no + fi + fi + + if test "$USE_NLS" = "yes"; then + + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if test "$gt_cv_func_gnugettext_libintl" = "yes"; then + AC_MSG_CHECKING([how to link with libintl]) + AC_MSG_RESULT([$LIBINTL]) + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) + fi + + dnl For backward compatibility. Some packages may be using this. + AC_DEFINE(HAVE_GETTEXT, 1, + [Define if the GNU gettext() function is already present or preinstalled.]) + AC_DEFINE(HAVE_DCGETTEXT, 1, + [Define if the GNU dcgettext() function is already present or preinstalled.]) + fi + + dnl We need to process the po/ directory. + POSUB=po + fi + + ifelse(gt_included_intl, yes, [ + dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL + dnl to 'yes' because some of the testsuite requires it. + if test "$PACKAGE" = gettext; then + BUILD_INCLUDED_LIBINTL=yes + fi + + dnl Make all variables we use known to autoconf. + AC_SUBST(BUILD_INCLUDED_LIBINTL) + AC_SUBST(USE_INCLUDED_LIBINTL) + AC_SUBST(CATOBJEXT) + AC_SUBST(INTLOBJS) + + dnl For backward compatibility. Some configure.ins may be using this. + nls_cv_header_intl= + nls_cv_header_libgt= + + dnl For backward compatibility. Some Makefiles may be using this. + DATADIRNAME=share + AC_SUBST(DATADIRNAME) + + dnl For backward compatibility. Some Makefiles may be using this. + INSTOBJEXT=.mo + AC_SUBST(INSTOBJEXT) + + dnl For backward compatibility. Some Makefiles may be using this. + GENCAT=gencat + AC_SUBST(GENCAT) + + dnl Enable libtool support if the surrounding package wishes it. + INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix + AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX) + ]) + + dnl For backward compatibility. Some Makefiles may be using this. + INTLLIBS="$LIBINTL" + AC_SUBST(INTLLIBS) + + dnl Make all documented variables known to autoconf. + AC_SUBST(LIBINTL) + AC_SUBST(LTLIBINTL) + AC_SUBST(POSUB) +]) + + +dnl Checks for all prerequisites of the po subdirectory, +dnl except for USE_NLS. +AC_DEFUN([AM_PO_SUBDIRS], +[ + AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_INSTALL])dnl + AC_REQUIRE([AM_MKINSTALLDIRS])dnl + + dnl Perform the following tests also if --disable-nls has been given, + dnl because they are needed for "make dist" to work. + + dnl Search for GNU msgfmt in the PATH. + dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. + dnl The second test excludes FreeBSD msgfmt. + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [$ac_dir/$ac_word --statistics /dev/null >/dev/null 2>&1 && + (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + + dnl Search for GNU xgettext 0.11 or newer in the PATH. + dnl The first test excludes Solaris xgettext and early GNU xgettext versions. + dnl The second test excludes FreeBSD xgettext. + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [$ac_dir/$ac_word --omit-header --copyright-holder= /dev/null >/dev/null 2>&1 && + (if $ac_dir/$ac_word --omit-header --copyright-holder= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + dnl Remove leftover from FreeBSD xgettext call. + rm -f messages.po + + dnl Search for GNU msgmerge 0.11 or newer in the PATH. + AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, + [$ac_dir/$ac_word --update -q /dev/null /dev/null >/dev/null 2>&1], :) + + dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. + dnl Test whether we really found GNU msgfmt. + if test "$GMSGFMT" != ":"; then + dnl If it is no GNU msgfmt we define it as : so that the + dnl Makefiles still can work. + if $GMSGFMT --statistics /dev/null >/dev/null 2>&1 && + (if $GMSGFMT --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + : ; + else + GMSGFMT=`echo "$GMSGFMT" | sed -e 's,^.*/,,'` + AC_MSG_RESULT( + [found $GMSGFMT program is not GNU msgfmt; ignore it]) + GMSGFMT=":" + fi + fi + + dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header --copyright-holder= /dev/null >/dev/null 2>&1 && + (if $XGETTEXT --omit-header --copyright-holder= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + : ; + else + AC_MSG_RESULT( + [found xgettext program is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + dnl Remove leftover from FreeBSD xgettext call. + rm -f messages.po + fi + + AC_OUTPUT_COMMANDS([ + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + # ALL_LINGUAS, POFILES, GMOFILES, UPDATEPOFILES, DUMMYPOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS_=`sed -e "/^#/d" "$ac_given_srcdir/$ac_dir/LINGUAS"` + # Hide the ALL_LINGUAS assigment from automake. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + fi + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + GMOFILES= + UPDATEPOFILES= + DUMMYPOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done], + [# Capture the value of obsolete $ALL_LINGUAS because we need it to compute + # POFILES, GMOFILES, UPDATEPOFILES, DUMMYPOFILES, CATALOGS. But hide it + # from automake. + eval 'ALL_LINGUAS''="$ALL_LINGUAS"' + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="${LINGUAS-%UNSET%}" + ]) +]) + + +dnl Checks for all prerequisites of the intl subdirectory, +dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, +dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. +AC_DEFUN([AM_INTL_SUBDIR], +[ + AC_REQUIRE([AC_PROG_INSTALL])dnl + AC_REQUIRE([AM_MKINSTALLDIRS])dnl + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_CANONICAL_HOST])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_ISC_POSIX])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_C_CONST])dnl + AC_REQUIRE([AC_C_INLINE])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + AC_REQUIRE([jm_GLIBC21])dnl + AC_REQUIRE([gt_INTDIV0])dnl + AC_REQUIRE([jm_AC_TYPE_UINTMAX_T])dnl + AC_REQUIRE([gt_HEADER_INTTYPES_H])dnl + AC_REQUIRE([gt_INTTYPES_PRI])dnl + + AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h stddef.h \ +stdlib.h string.h unistd.h sys/param.h]) + AC_CHECK_FUNCS([feof_unlocked fgets_unlocked getc_unlocked getcwd getegid \ +geteuid getgid getuid mempcpy munmap putenv setenv setlocale stpcpy \ +strcasecmp strdup strtoul tsearch __argz_count __argz_stringify __argz_next]) + + AM_ICONV + AM_LANGINFO_CODESET + if test $ac_cv_header_locale_h = yes; then + AM_LC_MESSAGES + fi + + dnl intl/plural.c is generated from intl/plural.y. It requires bison, + dnl because plural.y uses bison specific features. It requires at least + dnl bison-1.26 because earlier versions generate a plural.c that doesn't + dnl compile. + dnl bison is only needed for the maintainer (who touches plural.y). But in + dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put + dnl the rule in general Makefile. Now, some people carelessly touch the + dnl files or have a broken "make" program, hence the plural.c rule will + dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not + dnl present or too old. + AC_CHECK_PROGS([INTLBISON], [bison]) + if test -z "$INTLBISON"; then + ac_verc_fail=yes + else + dnl Found it, now check the version. + AC_MSG_CHECKING([version of bison]) +changequote(<<,>>)dnl + ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` + case $ac_prog_version in + '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; + 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) +changequote([,])dnl + ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; + *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; + esac + AC_MSG_RESULT([$ac_prog_version]) + fi + if test $ac_verc_fail = yes; then + INTLBISON=: + fi +]) + + +AC_DEFUN([AM_MKINSTALLDIRS], +[ + dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly + dnl find the mkinstalldirs script in another subdir but $(top_srcdir). + dnl Try to locate is. + MKINSTALLDIRS= + if test -n "$ac_aux_dir"; then + MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" + fi + if test -z "$MKINSTALLDIRS"; then + MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" + fi + AC_SUBST(MKINSTALLDIRS) +]) + + +dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) +AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) diff --git a/m4/iconv.m4 b/m4/iconv.m4 new file mode 100644 index 00000000..c5f35798 --- /dev/null +++ b/m4/iconv.m4 @@ -0,0 +1,103 @@ +# iconv.m4 serial AM4 (gettext-0.11.3) +dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], +[ + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([iconv]) +]) + +AC_DEFUN([AM_ICONV_LINK], +[ + dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and + dnl those with the standalone portable GNU libiconv installed). + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + + dnl Add $INCICONV to CPPFLAGS before performing the following checks, + dnl because if the user has installed libiconv and not disabled its use + dnl via --without-libiconv-prefix, he wants to use it. The first + dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. + am_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) + + AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + AC_TRY_LINK([#include +#include ], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + am_cv_func_iconv=yes) + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + AC_TRY_LINK([#include +#include ], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + am_cv_lib_iconv=yes + am_cv_func_iconv=yes) + LIBS="$am_save_LIBS" + fi + ]) + if test "$am_cv_func_iconv" = yes; then + AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) + fi + if test "$am_cv_lib_iconv" = yes; then + AC_MSG_CHECKING([how to link with libiconv]) + AC_MSG_RESULT([$LIBICONV]) + else + dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV + dnl either. + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + AC_SUBST(LIBICONV) + AC_SUBST(LTLIBICONV) +]) + +AC_DEFUN([AM_ICONV], +[ + AM_ICONV_LINK + if test "$am_cv_func_iconv" = yes; then + AC_MSG_CHECKING([for iconv declaration]) + AC_CACHE_VAL(am_cv_proto_iconv, [ + AC_TRY_COMPILE([ +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif +], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) + am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + AC_MSG_RESULT([$]{ac_t:- + }[$]am_cv_proto_iconv) + AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, + [Define as const if the declaration of iconv() needs const.]) + fi +]) diff --git a/m4/lcmessage.m4 b/m4/lcmessage.m4 new file mode 100644 index 00000000..ffbf915f --- /dev/null +++ b/m4/lcmessage.m4 @@ -0,0 +1,32 @@ +# lcmessage.m4 serial 2 (gettext-0.10.40) +dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995. + +# Check whether LC_MESSAGES is available in . + +AC_DEFUN([AM_LC_MESSAGES], + [if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, + [Define if your file defines LC_MESSAGES.]) + fi + fi]) diff --git a/m4/progtest.m4 b/m4/progtest.m4 new file mode 100644 index 00000000..443c8e30 --- /dev/null +++ b/m4/progtest.m4 @@ -0,0 +1,59 @@ +# progtest.m4 serial 2 (gettext-0.10.40) +dnl Copyright (C) 1996-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1996. + +# Search path for a program which passes the given test. + +dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST], +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) diff --git a/po/.cvsignore b/po/.cvsignore new file mode 100644 index 00000000..bf29bab3 --- /dev/null +++ b/po/.cvsignore @@ -0,0 +1 @@ +elfutils.pot diff --git a/po/ChangeLog b/po/ChangeLog new file mode 100644 index 00000000..020c07b7 --- /dev/null +++ b/po/ChangeLog @@ -0,0 +1,19 @@ +2005-07-21 Ulrich Drepper + + * Makefile.in.in: Add src/elfcmp. + +2005-05-07 Ulrich Drepper + + * Makefile.in.in (XGETTEXT_OPTIONS): Define. + +2005-02-05 Ulrich Drepper + + * POTFILES.in: Remove unnecessary entries. + +2004-01-18 Ulrich Drepper + + * POTFILES.in: Add files from libdw, libebl, and libasm. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/po/Makefile.in.in b/po/Makefile.in.in new file mode 100644 index 00000000..dbd78851 --- /dev/null +++ b/po/Makefile.in.in @@ -0,0 +1,302 @@ +# Makefile for PO directory in any package using GNU gettext. +# Copyright (C) 1995-1997, 2000-2002 by Ulrich Drepper +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU General Public +# License but which still want to provide support for the GNU gettext +# functionality. +# Please note that the actual code of GNU gettext is covered by the GNU +# General Public License and is *not* in the public domain. + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +SHELL = /bin/sh +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datadir = @datadir@ +localedir = $(datadir)/locale +gettextsrcdir = $(datadir)/gettext/po +top_builddir = .. + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +mkinstalldirs = $(SHELL) `case "$(MKINSTALLDIRS)" in /*) echo "$(MKINSTALLDIRS)" ;; *) echo "$(top_builddir)/$(MKINSTALLDIRS)" ;; esac` + +GMSGFMT = @GMSGFMT@ +MSGFMT = @MSGFMT@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_OPTIONS = --flag=error:3:c-format +MSGMERGE = msgmerge +MSGMERGE_UPDATE = @MSGMERGE@ --update +MSGINIT = msginit +MSGCONV = msgconv +MSGFILTER = msgfilter + +POFILES = @POFILES@ +GMOFILES = @GMOFILES@ +UPDATEPOFILES = @UPDATEPOFILES@ +DUMMYPOFILES = @DUMMYPOFILES@ +DISTFILES.common = Makefile.in.in Makevars \ +$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) +DISTFILES = $(DISTFILES.common) POTFILES.in $(DOMAIN).pot \ +$(POFILES) $(GMOFILES) \ +$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) + +POTFILES = \ + +CATALOGS = @CATALOGS@ + +# Makevars gets inserted here. (Don't remove this line!) + +.SUFFIXES: +.SUFFIXES: .po .gmo .mo .nop .po-update + +.po.mo: + $(MSGFMT) -c -o $@ $< + +.po.gmo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ + cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po + + +all: all-@USE_NLS@ + +all-yes: $(CATALOGS) +all-no: + +# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', +# otherwise packages like GCC can not be built if only parts of the source +# have been downloaded. + +$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in + $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ + --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ + --files-from=$(srcdir)/POTFILES.in \ + --copyright-holder='$(COPYRIGHT_HOLDER)' \ + && test ! -f $(DOMAIN).po \ + || ( rm -f $(srcdir)/$(DOMAIN).pot \ + && mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot ) + +$(srcdir)/$(DOMAIN).pot: + $(MAKE) $(DOMAIN).pot-update + +$(POFILES): $(srcdir)/$(DOMAIN).pot + @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ + cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot + + +install: install-exec install-data +install-exec: +install-data: install-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + for file in $(DISTFILES.common); do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +install-data-no: all +install-data-yes: all + $(mkinstalldirs) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkinstalldirs) $(DESTDIR)$$dir; \ + if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ + $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ + echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ + fi; \ + done; \ + done + +install-strip: install + +installdirs: installdirs-exec installdirs-data +installdirs-exec: +installdirs-data: installdirs-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi +installdirs-data-no: +installdirs-data-yes: + $(mkinstalldirs) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkinstalldirs) $(DESTDIR)$$dir; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + fi; \ + done; \ + done + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: uninstall-exec uninstall-data +uninstall-exec: +uninstall-data: uninstall-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext"; then \ + for file in $(DISTFILES.common); do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +uninstall-data-no: +uninstall-data-yes: + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + done; \ + done + +check: all + +dvi info tags TAGS ID: + +mostlyclean: + rm -f core core.* $(DOMAIN).po *.new.po + rm -fr *.o + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES *.mo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f $(GMOFILES) + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: + $(MAKE) update-po + @$(MAKE) dist2 +# This is a separate target because 'update-po' must be executed before. +dist2: $(DISTFILES) + dists="$(DISTFILES)"; \ + if test -f $(srcdir)/ChangeLog; then dists="$$dists ChangeLog"; fi; \ + if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ + for file in $$dists; do \ + if test -f $$file; then \ + cp -p $$file $(distdir); \ + else \ + cp -p $(srcdir)/$$file $(distdir); \ + fi; \ + done + +update-po: Makefile + $(MAKE) $(DOMAIN).pot-update + $(MAKE) $(UPDATEPOFILES) + $(MAKE) update-gmo + +# General rule for updating PO files. + +.nop.po-update: + @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ + if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ + cd $(srcdir); \ + if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +$(DUMMYPOFILES): + +update-gmo: Makefile $(GMOFILES) + @: + +Makefile: Makefile.in.in $(top_builddir)/config.status POTFILES.in + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \ + $(SHELL) ./config.status + +force: + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/po/Makevars b/po/Makevars new file mode 100644 index 00000000..0accb70a --- /dev/null +++ b/po/Makevars @@ -0,0 +1,25 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = Red Hat, Inc. + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 00000000..b92e8833 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,24 @@ +# List of files which containing translatable strings. +# Copyright (C) 2000, 2005 Red Hat, Inc. + +# Files from the compatibility library +lib/xmalloc.c +lib/xstrdup.c +lib/xstrndup.c + +# Library sources +libasm/asm_error.c +libdw/dwarf_error.c + +# Program sources +src/nm.c +src/readelf.c +src/size.c +src/strip.c +src/ld.c +src/ldgeneric.c +src/ldscript.y +src/elflint.c +src/addr2line.c +src/findtextrel.c +src/elfcmp.c diff --git a/po/Rules-quot b/po/Rules-quot new file mode 100644 index 00000000..5f46d237 --- /dev/null +++ b/po/Rules-quot @@ -0,0 +1,42 @@ +# Special Makefile rules for English message catalogs with quotation marks. + +DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot + +.SUFFIXES: .insert-header .po-update-en + +en@quot.po-update: en@quot.po-update-en +en@boldquot.po-update: en@boldquot.po-update-en + +.insert-header.po-update-en: + @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ + if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + ll=`echo $$lang | sed -e 's/@.*//'`; \ + LC_ALL=C; export LC_ALL; \ + cd $(srcdir); \ + if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "creation of $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +en@quot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header + +en@boldquot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header + +mostlyclean: mostlyclean-quot +mostlyclean-quot: + rm -f *.insert-header diff --git a/po/boldquot.sed b/po/boldquot.sed new file mode 100644 index 00000000..4b937aa5 --- /dev/null +++ b/po/boldquot.sed @@ -0,0 +1,10 @@ +s/"\([^"]*\)"/“\1â€/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“â€/""/g +s/“/“/g +s/â€/â€/g +s/‘/‘/g +s/’/’/g diff --git a/po/en@boldquot.header b/po/en@boldquot.header new file mode 100644 index 00000000..fedb6a06 --- /dev/null +++ b/po/en@boldquot.header @@ -0,0 +1,25 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# +# This catalog furthermore displays the text between the quotation marks in +# bold face, assuming the VT100/XTerm escape sequences. +# diff --git a/po/en@quot.header b/po/en@quot.header new file mode 100644 index 00000000..a9647fc3 --- /dev/null +++ b/po/en@quot.header @@ -0,0 +1,22 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# diff --git a/po/insert-header.sin b/po/insert-header.sin new file mode 100644 index 00000000..b26de01f --- /dev/null +++ b/po/insert-header.sin @@ -0,0 +1,23 @@ +# Sed script that inserts the file called HEADER before the header entry. +# +# At each occurrence of a line starting with "msgid ", we execute the following +# commands. At the first occurrence, insert the file. At the following +# occurrences, do nothing. The distinction between the first and the following +# occurrences is achieved by looking at the hold space. +/^msgid /{ +x +# Test if the hold space is empty. +s/m/m/ +ta +# Yes it was empty. First occurrence. Read the file. +r HEADER +# Output the file's contents by reading the next line. But don't lose the +# current line while doing this. +g +N +bb +:a +# The hold space was nonempty. Following occurrences. Do nothing. +x +:b +} diff --git a/po/quot.sed b/po/quot.sed new file mode 100644 index 00000000..0122c463 --- /dev/null +++ b/po/quot.sed @@ -0,0 +1,6 @@ +s/"\([^"]*\)"/“\1â€/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“â€/""/g diff --git a/src/.cvsignore b/src/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/src/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/src/ChangeLog b/src/ChangeLog new file mode 100644 index 00000000..7ebdcc46 --- /dev/null +++ b/src/ChangeLog @@ -0,0 +1,413 @@ +2005-07-24 Ulrich Drepper + + * elfcmp.c: Implement comparing gaps between sections. + +2005-07-23 Ulrich Drepper + + * elflint.c: Include libeblP.h instead of libebl.h. + * nm.c: Likewise. + * readelf.c: Likewise. + * elfcmp.c: Likewise. + + * elfcmp.c (main): Compare individual ELF header fields, excluding + e_shoff instead of the whole struct at once. + Use ebl_section_strip_p instead of SECTION_STRIP_P. + * strip.c: Use ebl_section_strip_p instead of SECTION_STRIP_P. + +2005-07-22 Ulrich Drepper + + * elfcmp.c (main): Take empty section into account when comparing + section content. + + * elflint.c (check_dynamic): Check that d_tag value is >= 0 before + using it. + +2005-07-21 Ulrich Drepper + + * elfcmp.c: New file. + * Makefile.am (bin_PROGRAMS): Add elfcmp. + (elfcmp_LDADD): Define. + + * elflint.c (check_rela): Check that copy relocations only reference + object symbols or symbols with unknown type. + (check_rel): Likewise. + +2005-06-08 Roland McGrath + + * readelf.c (print_ops): Add consts. + +2005-05-31 Roland McGrath + + * readelf.c (print_debug_abbrev_section): Don't bail after first CU's + abbreviations. Print a header line before each CU section. + + * readelf.c (print_debug_loc_section): Fix indentation for larger + address size. + +2005-05-30 Roland McGrath + + * readelf.c (print_debug_line_section): Print section offset of each + CU's table, so they are easy to find from seeing the stmt_list value. + + * readelf.c (dwarf_attr_string): Add all attributes in . + (attr_callback): Grok DW_AT_ranges and print offset in hex. + + * readelf.c (attr_callback): Add 2 to addrsize * 2 for %#0* format. + (print_debug_ranges_section, print_debug_loc_section): Likewise. + + * readelf.c (print_ops): Take different args for indentation control. + (attr_callback): Caller updated. + Grok several more block-form attributes as being location expressions. + For those same attributes with udata forms, format output differently + for location list offset. + (print_debug_loc_section): Implement it for real. + + * readelf.c (options): Mention ranges for --debug-dump. + (enum section_e): Add section_ranges. + (parse_opt): Grok "ranges" for -w/--debug-dump. + (print_debug_ranges_section): New function. + (print_debug): Handle .debug_ranges section. + +2005-05-30 Ulrich Drepper + + * readelf.c (handle_notes): At least x86-64 need not have the note + section values aligned to 8 bytes. + +2005-05-18 Ulrich Drepper + + * readelf.c (dwarf_tag_string): Add new tags. + +2005-05-08 Roland McGrath + + * strip.c (handle_elf): Don't translate hash and versym data formats, + elf_getdata already did it for us. + +2005-05-07 Ulrich Drepper + + * Makefile.am (findtextrel_LDADD): Add $(libmudflap). + (addr2line_LDADD): Likewise. + +2005-05-03 Roland McGrath + + * strip.c (handle_elf): Apply symbol table fixups to discarded + relocation sections when they are being saved in the debug file. + + * strip.c (handle_elf): Pass EHDR->e_ident[EI_DATA] to gelf_xlatetom + and gelf_xlatetof, not the native byte order. + + * strip.c (parse_opt): Give error if -f or -o is repeated. + (main): Exit if argp_parse returns nonzero. + + * strip.c (debug_fname_embed): New variable. + (options, parse_opt): New option -F to set it. + +2005-05-07 Ulrich Drepper + + * readelf.c (parse_opt): Make any_control_option variable + local. Simplify some tests. + +2005-05-03 Roland McGrath + + * strip.c (crc32_file): Function removed (now in ../lib). + +2005-05-03 Roland McGrath + + * elflint.c (is_debuginfo): New variable. + (options, parse_opt): New option --debuginfo/-d to set it. + (check_sections): If is_debuginfo, don't complain about SHT_NOBITS. + (check_note): If is_debuginfo, don't try to get note contents. + +2005-04-24 Ulrich Drepper + + * readelf.c (print_debug_abbrev_section): Don't print error when end of + section reached. + +2005-04-14 Ulrich Drepper + + * readelf.c (dwarf_encoding_string): New function. + (dwarf_inline_string): New function. + (dwarf_access_string): New function. + (dwarf_visibility_string): New function. + (dwarf_virtuality_string): New function. + (dwarf_identifier_case_string): New function. + (dwarf_calling_convention_string): New function. + (dwarf_ordering_string): New function. + (dwarf_discr_list_string): New function. + (attr_callback): Decode man more attribute values. + +2005-04-01 Ulrich Drepper + + * addr2line.c: Finish implementation of -f option. + +2005-03-29 Ulrich Drepper + + * addr2line.c: New file. + * Makefile.am (bin_PROGRAMS): Add addr2line. + Define addr2line_LDADD. + + * findtextrel.c: Use new dwarf_addrdie function. + + * findtextrel.c: Fix usage message and re-add accidentally removed + line. + +2005-03-28 Ulrich Drepper + + * findtextrel.c: New file. + * Makefile: Add rules to build findtextrel. + +2005-02-15 Ulrich Drepper + + * ldlex.l: Provide ECHO definition to avoid warning. + + * elflint.c (check_program_header): Fix typo in RELRO test. + + * Makefile.am (AM_CFLAGS): Add more warning options. + * elflint.c: Fix warnings introduced by the new warning options. + * i386_ld.c: Likewise. + * ld.c: Likewise. + * ld.h: Likewise. + * ldgeneric.c: Likewise. + * nm.c: Likewise. + * readelf.c: Likewise. + * sectionhash.c: Likewise. + * size.c: Likewise. + * string.c: Likewise. + +2005-02-05 Ulrich Drepper + + * Makefile.am: Check for text relocations in constructed DSOs. + + * Makefile.am [MUDFLAP] (AM_CFLAGS): Add -fmudflap. Link all apps + with -lmudflap. + + * ldscript.y: Add as_needed handling. + * ldlex.l: Recognize AS_NEEDED token. + * ld.h (struct filename_list): Add as_needed flag. + +2005-02-04 Ulrich Drepper + + * elflint.c (check_symtab): Correctly determine size of GOT section. + +2005-01-19 Ulrich Drepper + + * ld.c: Remove unnecessary more_help function. Print bug report + address using argp. + * strip.c: Likewise. + * size.c: Likewise. + * nm.c: Likewise. + * readelf.c: Likewise. + * elflint.c: Likewise. + + * elflint.c (main): Don't check for parameter problems here. + (parse_opt): Do it here, where we get informed about some of them + anyway. + + * readelf.c (main): Don't check for parameter problems here. + (parse_opt): Do it here, where we get informed about some of them + anyway. + +2005-01-11 Ulrich Drepper + + * strip.c: Update copyright year. + * readelf.c: Likewise. + * size.c: Likewise. + * nm.c: Likewise. + * ld.c: Likewise. + * elflint.c: Likewise. + + * elflint.c (check_symtab): Don't warn about wrong size for + _DYNAMIC and __GLOBAL_OFFSET_TABLE__ for --gnu-ld. + +2004-10-05 Ulrich Drepper + + * readelf.c (print_phdr): In section mapping, also indicate + sections in read-only segments. + +2004-09-25 Ulrich Drepper + + * readelf.c: Make compile with gcc 4.0. + * strip.c: Likewise. + +2004-08-16 Ulrich Drepper + + * strip.c (handle_elf): Rewrite dynamic memory handling to use of + allocate to work around gcc 3.4 bug. + +2004-01-25 Ulrich Drepper + + * ldlex.l (invalid_char): Better error message. + +2004-01-23 Ulrich Drepper + + * readelf.c: Print SHT_GNU_LIBLIST sections. + + * none_ld.c: New file. + +2004-01-21 Ulrich Drepper + + * Makefile.am: Enable building of machine specific linker. + +2004-01-20 Ulrich Drepper + + * Makefile.am: Support building with mudflap. + + * i386_ld.c: Fix warnings gcc 3.4 spits out. + * ldgeneric.c: Likewise. + * ldscript.y: Likewise. + * readelf.c: Likewise. + * strip.c: Likewise. + + * readelf.c (print_debug_line_section): Determine address size + correctly. + +2004-01-19 Ulrich Drepper + + * readelf.c (print_phdr): Show which sections are covered by the + PT_GNU_RELRO entry. + + * elflint.c (check_program_header): Check PT_GNU_RELRO entry. + + * readelf.c (print_debug_macinfo_section): Implement. + +2004-01-18 Ulrich Drepper + + * readelf.c (print_debug_line_section): Implement. + +2004-01-17 Ulrich Drepper + + * src/elflint.c: Use PACKAGE_NAME instead of PACKAGE. + * src/ld.c: Likewise. + * src/nm.c: Likewise. + * src/readelf.c: Likewise. + * src/size.c: Likewise. + * src/strip.c: Likewise. + + * strip.c: Add a few more unlikely. Reduce scope of some variables. + + * Makefile.am: Support building with mudflap. + +2004-01-16 Ulrich Drepper + + * readelf.c (print_debug_info_section): Free dies memory. + + * readelf.c: Print .debug_info section content. + +2004-01-13 Ulrich Drepper + + * readelf.c (print_shdr): Add support for SHF_ORDERED and SHF_EXCLUDE. + +2004-01-12 Ulrich Drepper + + * readelf.c (print_debug_aranges): Implement using libdw. + +2004-01-11 Ulrich Drepper + + * nm.c: Adjust for Dwarf_Files type and dwarf_lineno interface change. + + * readelf.c: Use libdw instead of libdwarf. Not all of the old + behavior is available yet. + * Makefile.am: Link readelf with libdw. Remove libdwarf include path. + +2004-01-09 Ulrich Drepper + + * nm.c (get_local_names): Adjust call to dwarf_nextcu. + + * nm.c: Implement getting information about local variables. + +2004-01-07 Ulrich Drepper + + * nm.c: Read also debug information for local symbols. + +2004-01-05 Ulrich Drepper + + * nm.c: Shuffle dwarf handling code around so the maximum column + width can be computed ahead of printing. Avoid collection symbols + which are not printed anyway. + + * nm.c: Rewrite dwarf handling to use libdw. + * Makefile.am (AM_CFLAGS): Add -std parameter. + (INCLUDES): Find header in libdw subdir. + (nm_LDADD): Replace libdwarf with libdw. + + * elflint.c: Update copyright year. + * readelf.c: Likewise. + * size.c: Likewise. + * strip.c: Likewise. + * nm.c: Likewise. + +2003-12-31 Ulrich Drepper + + * strip.c (process_file): Close file before returning. + +2003-11-19 Ulrich Drepper + + * readelf.c (handle_dynamic): Make column for tag name wider. + +2003-09-29 Ulrich Drepper + + * readelf.c (handle_dynamic): Always terminate tag name with a space. + +2003-09-25 Ulrich Drepper + + * strip.c (process_file): Don't mmap the input file, we modify the + data structures and don't want the change end up on disk. + +2003-09-23 Jakub Jelinek + + * unaligned.h (union u_2ubyte_unaligned, + union u_4ubyte_unaligned, union u_8ubyte_unaligned): Add + packed attribute. + (add_2ubyte_unaligned, add_4ubyte_unaligned, + add_8ubyte_unaligned): Avoid nesting bswap_NN macros. + Read/store value through _ptr->u instead of *_ptr. + +2003-09-22 Ulrich Drepper + + * size.c (show_sysv): Change type of maxlen to int. + + * strip.c (handle_elf): Handle the 64-bit archs which is 64-bit + buckets. + + * i386_ld.c: Many many fixes and extensions. + * ld.c: Likewise. + * ldgeneric.c: Likewise. + +2003-08-16 Ulrich Drepper + + * ldgeneric.c (check_definition): Don't add symbol on dso_list if + the reference is from another DSO. + +2003-08-15 Ulrich Drepper + + * ldgeneric.c (find_entry_point): It is no fatal error if no entry + point is found when creating a DSO. + +2003-08-14 Ulrich Drepper + + * ld.c (main): Always call FLAG_UNRESOLVED. + * ldgeneric.c (ld_generic_flag_unresolved): Only complain about + undefined symbols if not creating DSO or ld_state.nodefs is not set. + +2003-08-13 Ulrich Drepper + + * Makefile.in: Depend on libebl.a, not libebl.so. + + * ld.c (main): Mark stream for linker script as locked by caller. + (read_version_script): Likewise. + * ldlex.c: Define fread and fwrite to _unlocked variant. + + * i386_ld.c (elf_i386_finalize_plt): Replace #ifdefs with uses of + target_bswap_32. + * unaligned.h: Define target_bswap_16, target_bswap_32, and + target_bswap_64. + (store_2ubyte_unaligned, store_4ubyte_unaligned, + store_8ubyte_unaligned): Define using new macros. + +2003-08-12 Ulrich Drepper + + * i386_ld.c (elf_i386_finalize_plt): Use packed structs to access + possibly unaligned memory. Support use of big endian machines. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..ccb6f96c --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,144 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 1996-2002, 2003, 2004, 2005 Red Hat, Inc. +## +## This program is Open Source software; you can redistribute it and/or +## modify it under the terms of the Open Software License version 1.0 as +## published by the Open Source Initiative. +## +## You should have received a copy of the Open Software License along +## with this program; if not, you may obtain a copy of the Open Software +## License version 1.0 from http://www.opensource.org/licenses/osl.php or +## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +## 3001 King Ranch Road, Ukiah, CA 95482. +## +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H $(YYDEBUG) \ + -DSRCDIR=\"$(shell cd $(srcdir);pwd)\" -DOBJDIR=\"$(shell pwd)\" +if MUDFLAP +AM_CFLAGS = -Wall -Wshadow -Wunused -Wextra -std=gnu99 -fmudflap \ + $(native_ld_cflags) $(if $($(*F)_no_Wunused),,-Wunused) \ + $(if $($(*F)_no_Wformat),,-Wformat=2) +else +AM_CFLAGS = -Wall -Wshadow -std=gnu99 $(native_ld_cflags) \ + $(if $($(*F)_no_Werror),,-Werror) \ + $(if $($(*F)_no_Wunused),,-Wunused -Wextra) \ + $(if $($(*F)_no_Wformat),,-Wformat=2) +endif +if MUDFLAP +libmudflap = -lmudflap +endif +INCLUDES = -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl -I$(srcdir)/../lib -I$(srcdir)/../libdw -I.. + +YACC = @YACC@ -d +AM_YFLAGS = -pld +AM_LFLAGS = -Pld -olex.yy.c +## Uncomment to enable debugging of linker script parser +##YYDEBUG = -DYYDEBUG=1 + +native_ld = @native_ld@ +base_cpu = @base_cpu@ + +bin_PROGRAMS = readelf nm size strip ld elflint findtextrel addr2line \ + elfcmp + + +ld_dsos = libld_elf_i386_pic.a +if NATIVE_LD +noinst_LIBRARIES = libld_elf.a +native_ld_cflags = -DBASE_ELF_NAME=elf_$(base_cpu) +else +noinst_LIBRARIES = libld_elf.a $(ld_dsos) +noinst_PROGRAMS = $(ld_dsos:_pic.a=.so) +endif + +textrel_check = if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi + + +ld_SOURCES = ld.c ldgeneric.c ldlex.l ldscript.y symbolhash.c sectionhash.c \ + versionhash.c + +noinst_HEADERS = ld.h symbolhash.h sectionhash.h versionhash.h \ + ldscript.h xelf.h unaligned.h + +EXTRA_DIST = elf32-i386.script libld_elf_i386.map $(ld_modules) +ld_modules = i386_ld.c + +if MUDFLAP +libdw = ../libdw/libdw.a +libelf = ../libelf/libelf.a +else +libdw = ../libdw/libdw.so +libelf = ../libelf/libelf.so +endif +libebl = ../libebl/libebl.a +libeu = ../lib/libeu.a + +nm_no_Wformat = yes +size_no_Wformat = yes +# XXX While the file is not finished, don't warn about this +ldgeneric_no_Wunused = yes + +readelf_LDADD = $(libdw) $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl +nm_LDADD = $(libdw) $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl +size_LDADD = $(libelf) $(libeu) $(libmudflap) +strip_LDADD = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl +ld_LDADD = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl +if NATIVE_LD +ld_LDADD += libld_elf.a +endif +ld_LDFLAGS = -rdynamic +elflint_LDADD = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl +findtextrel_LDADD = $(libdw) $(libelf) $(libmudflap) +addr2line_LDADD = $(libdw) $(libelf) $(libmudflap) +elfcmp_LDADD = $(libebl) $(libelf) $(libmudflap) -ldl + +ldlex.o: ldscript.c +ldlex_no_Werror = yes +ldscript.h: ldscript.c + +# Machine-specific linker code. +libld_elf_a_SOURCES = $(base_cpu)_ld.c + +libld_elf_i386_pic_a_SOURCES = +am_libld_elf_i386_pic_a_OBJECTS = i386_ld.os + +libld_elf_i386_so_SOURCES = +libld_elf_i386.so: libld_elf_i386_pic.a libld_elf_i386.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + $(libelf) $(libeu) \ + -Wl,--version-script,$(srcdir)/libld_elf_i386.map + $(textrel_check) + + +%.os: %.c %.o + if $(filter-out -fmudflap,$(COMPILE)) -c -o $@ -fpic -DPIC -DSHARED \ + -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ + `test -f '$<' || echo '$(srcdir)/'`$<; \ + then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ + rm -f "$(DEPDIR)/$*.Tpo"; \ + else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ + fi + +# Special rule to make it possible to define libld_elf_a_SOURCES as we do. +# Otherwise make would complain. +.deps/none_ld.Po: none_ld.os + -: + + +installcheck-binPROGRAMS: $(bin_PROGRAMS) + bad=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \ + case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ + *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ + esac; \ + f=`echo "$$p" | \ + sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + for opt in --help --version; do \ + if LD_LIBRARY_PATH=$(DESTDIR)$(libdir) \ + $(DESTDIR)$(bindir)/$$f $$opt > c$${pid}_.out 2> c$${pid}_.err \ + && test -n "`cat c$${pid}_.out`" \ + && test -z "`cat c$${pid}_.err`"; then :; \ + else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ + done; \ + done; rm -f c$${pid}_.???; exit $$bad + +CLEANFILES = none_ld.os $(ld_modules:.c=.os) diff --git a/src/addr2line.c b/src/addr2line.c new file mode 100644 index 00000000..60fcdf63 --- /dev/null +++ b/src/addr2line.c @@ -0,0 +1,372 @@ +/* Locate source files and line information for given addresses + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Bug report address. */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + + +/* Values for the parameters which have no short form. */ +#define OPT_DEMANGLER 0x100 + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { NULL, 0, NULL, 0, N_("Input Selection:"), 0 }, + { "exe", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 }, + + { NULL, 0, NULL, 0, N_("Output Selection:"), 0 }, + { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 }, + { "functions", 'f', NULL, 0, N_("Additional show function names"), 0 }, + + { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, + /* Unsupported options. */ + { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 }, + { "demangle", 'C', "ARG", OPTION_HIDDEN | OPTION_ARG_OPTIONAL, NULL, 0 }, + { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Short description of program. */ +static const char doc[] = N_("\ +Locate source files and line information for ADDRs (in a.out by default)."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("[ADDR...]"); + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, NULL, NULL +}; + + +/* Handle ADDR. */ +static void handle_address (GElf_Addr addr, Elf *elf, Dwarf *dw); + + +/* Name of the executable. */ +static const char *executable = "a.out"; + +/* True if only base names of files should be shown. */ +static bool only_basenames; + +/* True if function names should be shown. */ +static bool show_functions; + + +int +main (int argc, char *argv[]) +{ + int remaining; + int result = 0; + + /* Make memory leak detection possible. */ + mtrace (); + + /* We use no threads here which can interfere with handling a stream. */ + (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); + + /* Set locale. */ + (void) setlocale (LC_ALL, ""); + + /* Make sure the message catalog can be found. */ + (void) bindtextdomain (PACKAGE, LOCALEDIR); + + /* Initialize the message catalog. */ + (void) textdomain (PACKAGE); + + /* Parse and process arguments. */ + (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + /* Tell the library which version we are expecting. */ + elf_version (EV_CURRENT); + + /* Open the file. */ + int fd = open64 (executable, O_RDONLY); + if (fd == -1) + error (1, errno, gettext ("cannot open '%s'"), executable); + + /* Create the ELF descriptor. */ + Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) + { + close (fd); + error (1, 0, gettext ("cannot create ELF descriptor: %s"), + elf_errmsg (-1)); + } + + /* Try to get a DWARF descriptor. If it fails, we try to locate the + debuginfo file. */ + Dwarf *dw = dwarf_begin_elf (elf, DWARF_C_READ, NULL); + int fd2 = -1; + Elf *elf2 = NULL; + if (dw == NULL) + { + char *canon = canonicalize_file_name (executable); + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + + if (canon != NULL && ehdr != NULL) + { + const char *debuginfo_dir; + if (ehdr->e_ident[EI_CLASS] == ELFCLASS32 + || ehdr->e_machine == EM_IA_64 || ehdr->e_machine == EM_ALPHA) + debuginfo_dir = "/usr/lib/debug"; + else + debuginfo_dir = "/usr/lib64/debug"; + + char *difname = alloca (strlen (debuginfo_dir) + strlen (canon) + 1); + strcpy (stpcpy (difname, debuginfo_dir), canon); + fd2 = open64 (difname, O_RDONLY); + if (fd2 != -1) + dw = dwarf_begin_elf (elf2, DWARF_C_READ, NULL); + } + + free (canon); + } + + /* Now handle the addresses. In case none are given on the command + line, read from stdin. */ + if (remaining == argc) + { + /* We use no threads here which can interfere with handling a stream. */ + (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); + + char *buf = NULL; + size_t len = 0; + while (!feof_unlocked (stdin)) + { + if (getline (&buf, &len, stdin) < 0) + break; + + char *endp; + uintmax_t addr = strtoumax (buf, &endp, 0); + if (endp != buf) + handle_address (addr, elf2 ?: elf, dw); + else + result = 1; + } + + free (buf); + } + else + { + do + { + char *endp; + uintmax_t addr = strtoumax (argv[remaining], &endp, 0); + if (endp != argv[remaining]) + handle_address (addr, elf2 ?: elf, dw); + else + result = 1; + } + while (++remaining < argc); + } + + return result; +} + + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) +{ + fprintf (stream, "addr2line (%s) %s\n", PACKAGE_NAME, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Red Hat, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2005"); + fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case 'b': + case 'C': + case OPT_DEMANGLER: + /* Ignored for compatibility. */ + break; + + case 'e': + executable = arg; + break; + + case 's': + only_basenames = true; + break; + + case 'f': + show_functions = true; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +struct func_arg +{ + GElf_Addr addr; + const char *name; +}; + + +static int +match_func (Dwarf_Func *func, void *arg) +{ + struct func_arg *func_arg = (struct func_arg *) arg; + Dwarf_Addr addr; + + if (dwarf_func_lowpc (func, &addr) == 0 && addr <= func_arg->addr + && dwarf_func_highpc (func, &addr) == 0 && func_arg->addr < addr) + { + func_arg->name = dwarf_func_name (func); + return DWARF_CB_ABORT; + } + + return DWARF_CB_OK; +} + + +static const char * +elf_getname (GElf_Addr addr, Elf *elf) +{ + /* The DWARF information is not available. Use the ELF + symbol table. */ + Elf_Scn *scn = NULL; + Elf_Scn *dynscn = NULL; + + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr != NULL) + { + if (shdr->sh_type == SHT_SYMTAB) + break; + if (shdr->sh_type == SHT_DYNSYM) + dynscn = scn; + } + } + if (scn == NULL) + scn = dynscn; + + if (scn != NULL) + { + /* Look through the symbol table for a matching symbol. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + assert (shdr != NULL); + + Elf_Data *data = elf_getdata (scn, NULL); + if (data != NULL) + for (int cnt = 1; cnt < (int) (shdr->sh_size / shdr->sh_entsize); + ++cnt) + { + GElf_Sym sym_mem; + GElf_Sym *sym = gelf_getsym (data, cnt, &sym_mem); + if (sym != NULL + && sym->st_value <= addr + && addr < sym->st_value + sym->st_size) + return elf_strptr (elf, shdr->sh_link, sym->st_name); + } + } + + return NULL; +} + + +static void +handle_address (GElf_Addr addr, Elf *elf, Dwarf *dw) +{ + Dwarf_Die die_mem; + Dwarf_Die *die = dwarf_addrdie (dw, addr, &die_mem); + + if (show_functions) + { + /* First determine the function name. Use the DWARF information if + possible. */ + struct func_arg arg; + arg.addr = addr; + arg.name = NULL; + + if (dwarf_getfuncs (die, match_func, &arg, 0) <= 0) + arg.name = elf_getname (addr, elf); + + puts (arg.name ?: "??"); + } + + + Dwarf_Line *line; + const char *src; + if ((line = dwarf_getsrc_die (die, addr)) != NULL + && (src = dwarf_linesrc (line, NULL, NULL)) != NULL) + { + if (only_basenames) + src = basename (src); + + int lineno; + if (dwarf_lineno (line, &lineno) != -1) + { + int linecol; + if (dwarf_linecol (line, &linecol) != -1 && linecol != 0) + printf ("%s:%d:%d\n", src, lineno, linecol); + else + printf ("%s:%d\n", src, lineno); + } + else + printf ("%s:0\n", src); + } + else + puts ("??:0"); +} diff --git a/src/elf32-i386.script b/src/elf32-i386.script new file mode 100644 index 00000000..d62333ac --- /dev/null +++ b/src/elf32-i386.script @@ -0,0 +1,215 @@ +ENTRY(_start); + +SEARCH_DIR(/lib); +SEARCH_DIR(/usr/lib); +SEARCH_DIR(/usr/local/lib); +SEARCH_DIR(/usr/i686-pc-linux-gnu/lib); + +INTERP(/lib/ld-linux.so.2); + +PAGESIZE(4k); + +SEGMENT [RX] +{ +#ifdef SHARED + . = SIZEOF_HEADERS; +#else + . = 0x08048000 + SIZEOF_HEADERS; +#endif + + .interp; + .hash; + .dynsym; + .dynstr; + .gnu.version; + .gnu.version_d; + .gnu.version_r; + .rel.dyn; + .rel.plt; + .init { KEEP (*(.init)) } + .plt; + .text + { + *(.text) + *(.text.*) + *(.stub) + *(.gnu.warning) + *(.gnu.linkonce.t.*) + } + .fini { KEEP (*(.fini)) } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata + { + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + } + .rodata1; + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array + { + *(.preinit_array) + } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array + { + *(.init_array) + } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array + { + *(.fini_array) + } + PROVIDE (__fini_array_end = .); +} + +SEGMENT [RW] +{ + .sdata2 + { + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + } + .sbss2 + { + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(PAGESIZE) + (. & (PAGESIZE - 1)); + .data + { + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + } + .data1; + .eh_frame + { + KEEP (*(.eh_frame)) + } + .gcc_except_table; + .ctors + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr; + .got + { + *(.got.plt) + *(.got) + } + .dynamic; + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata + { + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .bss + { + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE (end = .); +} + +SEGMENT [] +{ + /* Stabs debugging sections. */ + .stab; + .stabstr; + .stab.excl; + .stab.exclstr; + .stab.index; + .stab.indexstr; + .comment; + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug; + .line; + /* GNU DWARF 1 extensions */ + .debug_srcinfo; + .debug_sfnames; + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges; + .debug_pubnames; + /* DWARF 2 */ + .debug_info + { + *(.debug_info) + *(.gnu.linkonce.wi.*) + } + .debug_abbrev; + .debug_line; + .debug_frame; + .debug_str; + .debug_loc; + .debug_macinfo; + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames; + .debug_funcnames; + .debug_typenames; + .debug_varnames; + /* These must appear regardless of . */ +} diff --git a/src/elfcmp.c b/src/elfcmp.c new file mode 100644 index 00000000..6bf7e749 --- /dev/null +++ b/src/elfcmp.c @@ -0,0 +1,611 @@ +/* Compare relevant content of two ELF files. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../libelf/elf-knowledge.h" +#include "../libebl/libeblP.h" + + +/* Prototypes of local functions. */ +static Elf *open_file (const char *fname, int *fdp, Ebl **eblp); +static bool search_for_copy_reloc (Ebl *ebl, size_t scnndx, int symndx); +static int regioncompare (const void *p1, const void *p2); + + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Bug report address. */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + +/* Values for the parameters which have no short form. */ +#define OPT_GAPS 0x100 + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { NULL, 0, NULL, 0, N_("Control options:"), 0 }, + { "gaps", OPT_GAPS, "ACTION", 0, N_("Control treatment of gaps in loadable segments [ignore|match] (default: ignore)"), 0 }, + { "quiet", 'q', NULL, 0, N_("Output nothing; yield exit status only"), 0 }, + + { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Short description of program. */ +static const char doc[] = N_("\ +Compare relevant parts of two ELF files for equality."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("FILE1 FILE2"); + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, NULL, NULL +}; + + +/* How to treat gaps in loadable segments. */ +static enum + { + gaps_ignore = 0, + gaps_match + } + gaps; + +/* Structure to hold information about used regions. */ +struct region +{ + GElf_Addr from; + GElf_Addr to; + struct region *next; +}; + +/* Nonzero if only exit status is wanted. */ +static bool quiet; + + +int +main (int argc, char *argv[]) +{ + /* Set locale. */ + (void) setlocale (LC_ALL, ""); + + /* Make sure the message catalog can be found. */ + (void) bindtextdomain (PACKAGE, LOCALEDIR); + + /* Initialize the message catalog. */ + (void) textdomain (PACKAGE); + + /* Parse and process arguments. */ + int remaining; + (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + /* We expect exactly two non-option parameters. */ + if (remaining + 2 != argc) + { + fputs (gettext ("Invalid number of parameters.\n"), stderr); + argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name); + exit (1); + } + + /* Comparing the files is done in two phases: + 1. compare all sections. Sections which are irrelevant (i.e., if + strip would remove them) are ignored. Some section types are + handled special. + 2. all parts of the loadable segments which are not parts of any + section is compared according to the rules of the --gaps option. + */ + int result = 0; + elf_version (EV_CURRENT); + + const char *const fname1 = argv[remaining]; + int fd1; + Ebl *ebl1; + Elf *elf1 = open_file (fname1, &fd1, &ebl1); + + const char *const fname2 = argv[remaining + 1]; + int fd2; + Ebl *ebl2; + Elf *elf2 = open_file (fname2, &fd2, &ebl2); + + GElf_Ehdr ehdr1_mem; + GElf_Ehdr *ehdr1 = gelf_getehdr (elf1, &ehdr1_mem); + if (ehdr1 == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot get ELF header of \"%s\": %s"), + fname1, elf_errmsg (-1)); + GElf_Ehdr ehdr2_mem; + GElf_Ehdr *ehdr2 = gelf_getehdr (elf2, &ehdr2_mem); + if (ehdr2 == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot get ELF header of \"%s\": %s"), + fname2, elf_errmsg (-1)); + + /* Compare the ELF headers. */ + if (memcmp (ehdr1->e_ident, ehdr2->e_ident, EI_NIDENT) != 0 + || ehdr1->e_type != ehdr2->e_type + || ehdr1->e_machine != ehdr2->e_machine + || ehdr1->e_version != ehdr2->e_version + || ehdr1->e_entry != ehdr2->e_entry + || ehdr1->e_phoff != ehdr2->e_phoff + || ehdr1->e_flags != ehdr2->e_flags + || ehdr1->e_ehsize != ehdr2->e_ehsize + || ehdr1->e_phentsize != ehdr2->e_phentsize + || ehdr1->e_phnum != ehdr2->e_phnum + || ehdr1->e_shentsize != ehdr2->e_shentsize + || ehdr1->e_shnum != ehdr2->e_shnum + || ehdr1->e_shstrndx != ehdr2->e_shstrndx) + { + if (! quiet) + error (0, 0, gettext ("%s %s diff: ELF header"), fname1, fname2); + result = 1; + goto out; + } + + /* Iterate over all sections. We expect the sections in the two + files to match exactly. */ + Elf_Scn *scn1 = NULL; + Elf_Scn *scn2 = NULL; + struct region *regions = NULL; + size_t nregions = 0; + while (1) + { + GElf_Shdr shdr1_mem; + GElf_Shdr *shdr1; + const char *sname1 = NULL; + do + { + scn1 = elf_nextscn (elf1, scn1); + shdr1 = gelf_getshdr (scn1, &shdr1_mem); + if (shdr1 != NULL) + sname1 = elf_strptr (elf1, ehdr1->e_shstrndx, shdr1->sh_name); + } + while (scn1 != NULL + && ebl_section_strip_p (ebl1, ehdr1, shdr1, sname1, true, false)); + + GElf_Shdr shdr2_mem; + GElf_Shdr *shdr2; + const char *sname2 = NULL; + do + { + scn2 = elf_nextscn (elf2, scn2); + shdr2 = gelf_getshdr (scn2, &shdr2_mem); + if (shdr2 != NULL) + sname2 = elf_strptr (elf2, ehdr2->e_shstrndx, shdr2->sh_name); + } + while (scn2 != NULL + && ebl_section_strip_p (ebl2, ehdr2, shdr2, sname2, true, false)); + + if (scn1 == NULL || scn2 == NULL) + break; + + if (gaps != gaps_ignore && (shdr1->sh_flags & SHF_ALLOC) != 0) + { + struct region *newp = (struct region *) alloca (sizeof (*newp)); + newp->from = shdr1->sh_offset; + newp->to = shdr1->sh_offset + shdr1->sh_size; + newp->next = regions; + regions = newp; + + ++nregions; + } + + /* Compare the headers. We allow the name to be at a different + location. */ + if (strcmp (sname1, sname2) != 0) + { + header_mismatch: + error (0, 0, gettext ("%s %s differ: section header"), + fname1, fname2); + result = 1; + goto out; + } + + /* We ignore certain sections. */ + if (strcmp (sname1, ".gnu_debuglink") == 0 + || strcmp (sname1, ".gnu.prelink_undo") == 0) + continue; + + if (shdr1->sh_type != shdr2->sh_type + // XXX Any flags which should be ignored? + || shdr1->sh_flags != shdr2->sh_flags + || shdr1->sh_addr != shdr2->sh_addr + || shdr1->sh_offset != shdr2->sh_offset + || shdr1->sh_size != shdr2->sh_size + || shdr1->sh_link != shdr2->sh_link + || shdr1->sh_info != shdr2->sh_info + || shdr1->sh_addralign != shdr2->sh_addralign + || shdr1->sh_entsize != shdr2->sh_entsize) + goto header_mismatch; + + Elf_Data *data1 = elf_getdata (scn1, NULL); + if (data1 == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get content of section %zu in \"%s\": %s"), + elf_ndxscn (scn1), fname1, elf_errmsg (-1)); + + Elf_Data *data2 = elf_getdata (scn2, NULL); + if (data2 == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get content of section %zu in \"%s\": %s"), + elf_ndxscn (scn2), fname2, elf_errmsg (-1)); + + switch (shdr1->sh_type) + { + case SHT_DYNSYM: + case SHT_SYMTAB: + /* Iterate over the symbol table. We ignore the st_size + value of undefined symbols. */ + for (int ndx = 0; ndx < (int) (shdr1->sh_size / shdr1->sh_entsize); + ++ndx) + { + GElf_Sym sym1_mem; + GElf_Sym *sym1 = gelf_getsym (data1, ndx, &sym1_mem); + if (sym1 == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get symbol in \"%s\": %s"), + fname1, elf_errmsg (-1)); + GElf_Sym sym2_mem; + GElf_Sym *sym2 = gelf_getsym (data2, ndx, &sym2_mem); + if (sym2 == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get symbol in \"%s\": %s"), + fname2, elf_errmsg (-1)); + + const char *name1 = elf_strptr (elf1, shdr1->sh_link, + sym1->st_name); + const char *name2 = elf_strptr (elf2, shdr2->sh_link, + sym2->st_name); + if (strcmp (name1, name2) != 0 + || sym1->st_value != sym2->st_value + || (sym1->st_size != sym2->st_size + && sym1->st_shndx != SHN_UNDEF) + || sym1->st_info != sym2->st_info + || sym1->st_other != sym2->st_other + || sym1->st_shndx != sym1->st_shndx) + { + // XXX Do we want to allow reordered symbol tables? + if (! quiet) + error (0, 0, gettext ("%s %s differ: symbol table"), + fname1, fname2); + result = 1; + goto out; + } + + if (sym1->st_shndx == SHN_UNDEF + && sym1->st_size != sym2->st_size) + { + /* The size of the symbol in the object defining it + might have changed. That is OK unless the symbol + is used in a copy relocation. Look over the + sections in both files and determine which + relocation section uses this symbol table + section. Then look through the relocations to + see whether any copy relocation references this + symbol. */ + if (search_for_copy_reloc (ebl1, elf_ndxscn (scn1), ndx) + || search_for_copy_reloc (ebl2, elf_ndxscn (scn2), ndx)) + { + if (! quiet) + error (0, 0, gettext ("%s %s differ: symbol table"), + fname1, fname2); + result = 1; + goto out; + } + } + } + break; + + default: + /* Compare the section content byte for byte. */ + assert (shdr1->sh_type == SHT_NOBITS + || (data1->d_buf != NULL || data1->d_size == 0)); + assert (shdr2->sh_type == SHT_NOBITS + || (data2->d_buf != NULL || data1->d_size == 0)); + + if (data1->d_size != data2->d_size + || (shdr1->sh_type != SHT_NOBITS + && memcmp (data1->d_buf, data2->d_buf, data1->d_size) != 0)) + { + if (! quiet) + error (0, 0, gettext ("%s %s differ: section content"), + fname1, fname2); + result = 1; + goto out; + } + break; + } + } + + if (scn1 != scn2) + { + if (! quiet) + error (0, 0, + gettext ("%s %s differ: unequal amount of important sections"), + fname1, fname2); + result = 1; + goto out; + } + + /* We we look at gaps, create artificial ones for the parts of the + program which we are not in sections. */ + struct region ehdr_region; + struct region phdr_region; + if (gaps != gaps_ignore) + { + ehdr_region.from = 0; + ehdr_region.to = ehdr1->e_ehsize; + ehdr_region.next = &phdr_region; + + phdr_region.from = ehdr1->e_phoff; + phdr_region.to = ehdr1->e_phoff + ehdr1->e_phnum * ehdr1->e_phentsize; + phdr_region.next = regions; + + regions = &ehdr_region; + nregions += 2; + } + + /* If we need to look at the gaps we need access to the file data. */ + char *raw1 = NULL; + size_t size1 = 0; + char *raw2 = NULL; + size_t size2 = 0; + struct region *regionsarr = alloca (nregions * sizeof (struct region)); + if (gaps != gaps_ignore) + { + raw1 = elf_rawfile (elf1, &size1); + if (raw1 == NULL ) + error (EXIT_FAILURE, 0, gettext ("cannot load data of \"%s\": %s"), + fname1, elf_errmsg (-1)); + + raw2 = elf_rawfile (elf2, &size2); + if (raw2 == NULL ) + error (EXIT_FAILURE, 0, gettext ("cannot load data of \"%s\": %s"), + fname2, elf_errmsg (-1)); + + for (size_t cnt = 0; cnt < nregions; ++cnt) + { + regionsarr[cnt] = *regions; + regions = regions->next; + } + + qsort (regionsarr, nregions, sizeof (regionsarr[0]), regioncompare); + } + + /* Compare the program header tables. */ + for (int ndx = 0; ndx < ehdr1->e_phnum; ++ndx) + { + GElf_Phdr phdr1_mem; + GElf_Phdr *phdr1 = gelf_getphdr (elf1, ndx, &phdr1_mem); + if (ehdr1 == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get program header entry %d of \"%s\": %s"), + ndx, fname1, elf_errmsg (-1)); + GElf_Phdr phdr2_mem; + GElf_Phdr *phdr2 = gelf_getphdr (elf2, ndx, &phdr2_mem); + if (ehdr2 == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get program header entry %d of \"%s\": %s"), + ndx, fname2, elf_errmsg (-1)); + + if (memcmp (phdr1, phdr2, sizeof (GElf_Phdr)) != 0) + { + if (! quiet) + error (0, 0, gettext ("%s %s differ: program header %d"), + fname1, fname2, ndx); + result = 1; + goto out; + } + + if (gaps != gaps_ignore && phdr1->p_type == PT_LOAD) + { + size_t cnt = 0; + while (cnt < nregions && regionsarr[cnt].to < phdr1->p_offset) + ++cnt; + + GElf_Off last = phdr1->p_offset; + GElf_Off end = phdr1->p_offset + phdr1->p_filesz; + while (cnt < nregions && regionsarr[cnt].from < end) + { + if (last < regionsarr[cnt].from) + { + /* Compare the [LAST,FROM) region. */ + assert (gaps == gaps_match); + if (memcmp (raw1 + last, raw2 + last, + regionsarr[cnt].from - last) != 0) + { + gapmismatch: + if (!quiet) + error (0, 0, gettext ("%s %s differ: gap"), + fname1, fname2); + result = 1; + goto out; + } + + } + last = regionsarr[cnt].to; + ++cnt; + } + + if (cnt == nregions && last < end) + goto gapmismatch; + } + } + + out: + elf_end (elf1); + elf_end (elf2); + close (fd1); + close (fd2); + + return result; +} + + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) +{ + fprintf (stream, "elfcmp (%s) %s\n", PACKAGE_NAME, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Red Hat, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2005"); + fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case 'q': + quiet = true; + break; + + case OPT_GAPS: + if (strcasecmp (arg, "ignore") == 0) + gaps = gaps_ignore; + else if (strcasecmp (arg, "match") == 0) + gaps = gaps_match; + else + { + fprintf (stderr, + gettext ("Invalid value \"%s\" for --gaps parameter."), + arg); + argp_help (&argp, stderr, ARGP_HELP_SEE, + program_invocation_short_name); + exit (1); + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +static Elf * +open_file (const char *fname, int *fdp, Ebl **eblp) +{ + int fd = open (fname, O_RDONLY); + if (unlikely (fd == -1)) + error (EXIT_FAILURE, errno, gettext ("cannot open \"%s\""), fname); + Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create ELF descriptor for \"%s\": %s"), + fname, elf_errmsg (-1)); + Ebl *ebl = ebl_openbackend (elf); + if (ebl == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create EBL descriptor for \"%s\""), fname); + + *fdp = fd; + *eblp = ebl; + return elf; +} + + +static bool +search_for_copy_reloc (Ebl *ebl, size_t scnndx, int symndx) +{ + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header of section %zu: %s"), + elf_ndxscn (scn), elf_errmsg (-1)); + + if ((shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA) + || shdr->sh_link != scnndx) + continue; + + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get content of section %zu: %s"), + elf_ndxscn (scn), elf_errmsg (-1)); + + if (shdr->sh_type == SHT_REL) + for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize); + ++ndx) + { + GElf_Rel rel_mem; + GElf_Rel *rel = gelf_getrel (data, ndx, &rel_mem); + if (rel == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot get relocation: %s"), + elf_errmsg (-1)); + + if ((int) GELF_R_SYM (rel->r_info) == symndx + && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rel->r_info))) + return true; + } + else + for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize); + ++ndx) + { + GElf_Rela rela_mem; + GElf_Rela *rela = gelf_getrela (data, ndx, &rela_mem); + if (rela == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot get relocation: %s"), + elf_errmsg (-1)); + + if ((int) GELF_R_SYM (rela->r_info) == symndx + && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rela->r_info))) + return true; + } + } + + return false; +} + + +static int +regioncompare (const void *p1, const void *p2) +{ + const struct region *r1 = (const struct region *) p1; + const struct region *r2 = (const struct region *) p2; + + if (r1->from < r2->from) + return -1; + return 1; +} diff --git a/src/elflint.c b/src/elflint.c new file mode 100644 index 00000000..03572377 --- /dev/null +++ b/src/elflint.c @@ -0,0 +1,2617 @@ +/* Pedantic checking of ELF files compliance with gABI/psABI spec. + Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "../libebl/libeblP.h" + + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Bug report address. */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + +#define ARGP_strict 300 +#define ARGP_gnuld 301 + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + + { "strict", ARGP_strict, NULL, 0, + N_("Be extremely strict, flag level 2 features."), 0 }, + { "quiet", 'q', NULL, 0, N_("Do not print anything if successful"), 0 }, + { "debuginfo", 'd', NULL, 0, N_("Binary is a separate debuginfo file"), 0 }, + { "gnu-ld", ARGP_gnuld, NULL, 0, + N_("Binary has been created with GNU ld and is therefore known to be \ +broken in certain ways"), 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Short description of program. */ +static const char doc[] = N_("\ +Pedantic checking of ELF files compliance with gABI/psABI spec."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("FILE..."); + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, NULL, NULL +}; + + +/* Declarations of local functions. */ +static void process_file (int fd, Elf *elf, const char *prefix, + const char *suffix, const char *fname, size_t size, + bool only_one); +static void process_elf_file (Elf *elf, const char *prefix, const char *suffix, + const char *fname, size_t size, bool only_one); + +/* Report an error. */ +#define ERROR(str, args...) \ + do { \ + printf (str, ##args); \ + ++error_count; \ + } while (0) +static unsigned int error_count; + +/* True if we should perform very strict testing. */ +static bool be_strict; + +/* True if no message is to be printed if the run is succesful. */ +static bool be_quiet; + +/* True if binary is from strip -f, not a normal ELF file. */ +static bool is_debuginfo; + +/* True if binary is assumed to be generated with GNU ld. */ +static bool gnuld; + +/* Index of section header string table. */ +static uint32_t shstrndx; + +/* Array to count references in section groups. */ +static int *scnref; + + +int +main (int argc, char *argv[]) +{ + /* Set locale. */ + setlocale (LC_ALL, ""); + + /* Initialize the message catalog. */ + textdomain (PACKAGE); + + /* Parse and process arguments. */ + int remaining; + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + /* Before we start tell the ELF library which version we are using. */ + elf_version (EV_CURRENT); + + /* Now process all the files given at the command line. */ + bool only_one = remaining + 1 == argc; + do + { + /* Open the file. */ + int fd = open (argv[remaining], O_RDONLY); + if (fd == -1) + { + error (0, errno, gettext ("cannot open input file")); + continue; + } + + /* Create an `Elf' descriptor. */ + Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) + ERROR (gettext ("cannot generate Elf descriptor: %s\n"), + elf_errmsg (-1)); + else + { + unsigned int prev_error_count = error_count; + struct stat64 st; + + if (fstat64 (fd, &st) != 0) + { + printf ("cannot stat '%s': %m\n", argv[remaining]); + close (fd); + continue; + } + + process_file (fd, elf, NULL, NULL, argv[remaining], st.st_size, + only_one); + + /* Now we can close the descriptor. */ + if (elf_end (elf) != 0) + ERROR (gettext ("error while closing Elf descriptor: %s\n"), + elf_errmsg (-1)); + + if (prev_error_count == error_count && !be_quiet) + puts (gettext ("No errors")); + } + + close (fd); + } + while (++remaining < argc); + + return error_count != 0; +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg __attribute__ ((unused)), + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case ARGP_strict: + be_strict = true; + break; + + case 'q': + be_quiet = true; + break; + + case 'd': + is_debuginfo = true; + + case ARGP_gnuld: + gnuld = true; + break; + + case ARGP_KEY_NO_ARGS: + fputs (gettext ("Missing file name.\n"), stderr); + argp_help (&argp, stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR, + program_invocation_short_name); + exit (1); + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) +{ + fprintf (stream, "elflint (%s) %s\n", PACKAGE_NAME, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Red Hat, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2005"); + fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); +} + + +/* Process one file. */ +static void +process_file (int fd, Elf *elf, const char *prefix, const char *suffix, + const char *fname, size_t size, bool only_one) +{ + /* We can handle two types of files: ELF files and archives. */ + Elf_Kind kind = elf_kind (elf); + + switch (kind) + { + case ELF_K_ELF: + /* Yes! It's an ELF file. */ + process_elf_file (elf, prefix, suffix, fname, size, only_one); + break; + + case ELF_K_AR: + { + Elf *subelf; + Elf_Cmd cmd = ELF_C_READ_MMAP; + size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); + size_t fname_len = strlen (fname) + 1; + char new_prefix[prefix_len + 1 + fname_len]; + char new_suffix[(suffix == NULL ? 0 : strlen (suffix)) + 2]; + char *cp = new_prefix; + + /* Create the full name of the file. */ + if (prefix != NULL) + { + cp = mempcpy (cp, prefix, prefix_len); + *cp++ = '('; + strcpy (stpcpy (new_suffix, suffix), ")"); + } + else + new_suffix[0] = '\0'; + memcpy (cp, fname, fname_len); + + /* It's an archive. We process each file in it. */ + while ((subelf = elf_begin (fd, cmd, elf)) != NULL) + { + kind = elf_kind (subelf); + + /* Call this function recursively. */ + if (kind == ELF_K_ELF || kind == ELF_K_AR) + { + Elf_Arhdr *arhdr = elf_getarhdr (subelf); + assert (arhdr != NULL); + + process_file (fd, subelf, new_prefix, new_suffix, + arhdr->ar_name, arhdr->ar_size, false); + } + + /* Get next archive element. */ + cmd = elf_next (subelf); + if (elf_end (subelf) != 0) + ERROR (gettext (" error while freeing sub-ELF descriptor: %s\n"), + elf_errmsg (-1)); + } + } + break; + + default: + /* We cannot do anything. */ + ERROR (gettext ("\ +Not an ELF file - it has the wrong magic bytes at the start")); + break; + } +} + + +static const char * +section_name (Ebl *ebl, int idx) +{ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + shdr = gelf_getshdr (elf_getscn (ebl->elf, idx), &shdr_mem); + + return elf_strptr (ebl->elf, shstrndx, shdr->sh_name); +} + + +static const int valid_e_machine[] = + { + EM_M32, EM_SPARC, EM_386, EM_68K, EM_88K, EM_860, EM_MIPS, EM_S370, + EM_MIPS_RS3_LE, EM_PARISC, EM_VPP500, EM_SPARC32PLUS, EM_960, EM_PPC, + EM_PPC64, EM_S390, EM_V800, EM_FR20, EM_RH32, EM_RCE, EM_ARM, + EM_FAKE_ALPHA, EM_SH, EM_SPARCV9, EM_TRICORE, EM_ARC, EM_H8_300, + EM_H8_300H, EM_H8S, EM_H8_500, EM_IA_64, EM_MIPS_X, EM_COLDFIRE, + EM_68HC12, EM_MMA, EM_PCP, EM_NCPU, EM_NDR1, EM_STARCORE, EM_ME16, + EM_ST100, EM_TINYJ, EM_X86_64, EM_PDSP, EM_FX66, EM_ST9PLUS, EM_ST7, + EM_68HC16, EM_68HC11, EM_68HC08, EM_68HC05, EM_SVX, EM_ST19, EM_VAX, + EM_CRIS, EM_JAVELIN, EM_FIREPATH, EM_ZSP, EM_MMIX, EM_HUANY, EM_PRISM, + EM_AVR, EM_FR30, EM_D10V, EM_D30V, EM_V850, EM_M32R, EM_MN10300, + EM_MN10200, EM_PJ, EM_OPENRISC, EM_ARC_A5, EM_XTENSA + }; +#define nvalid_e_machine \ + (sizeof (valid_e_machine) / sizeof (valid_e_machine[0])) + + +/* Number of sections. */ +static unsigned int shnum; + + +static void +check_elf_header (Ebl *ebl, GElf_Ehdr *ehdr, size_t size) +{ + char buf[512]; + size_t cnt; + + /* Check e_ident field. */ + if (ehdr->e_ident[EI_MAG0] != ELFMAG0) + ERROR ("e_ident[%d] != '%c'\n", EI_MAG0, ELFMAG0); + if (ehdr->e_ident[EI_MAG1] != ELFMAG1) + ERROR ("e_ident[%d] != '%c'\n", EI_MAG1, ELFMAG1); + if (ehdr->e_ident[EI_MAG2] != ELFMAG2) + ERROR ("e_ident[%d] != '%c'\n", EI_MAG2, ELFMAG2); + if (ehdr->e_ident[EI_MAG3] != ELFMAG3) + ERROR ("e_ident[%d] != '%c'\n", EI_MAG3, ELFMAG3); + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS32 + && ehdr->e_ident[EI_CLASS] != ELFCLASS64) + ERROR (gettext ("e_ident[%d] == %d is no known class\n"), + EI_CLASS, ehdr->e_ident[EI_CLASS]); + + if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB + && ehdr->e_ident[EI_DATA] != ELFDATA2MSB) + ERROR (gettext ("e_ident[%d] == %d is no known data encoding\n"), + EI_DATA, ehdr->e_ident[EI_DATA]); + + if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) + ERROR (gettext ("unknown ELF header version number e_ident[%d] == %d\n"), + EI_VERSION, ehdr->e_ident[EI_VERSION]); + + /* We currently don't handle any OS ABIs. */ + if (ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) + ERROR (gettext ("unsupported OS ABI e_ident[%d] == \"%s\"\n"), + EI_OSABI, + ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf))); + + /* No ABI versions other than zero supported either. */ + if (ehdr->e_ident[EI_ABIVERSION] != 0) + ERROR (gettext ("unsupport ABI version e_ident[%d] == %d\n"), + EI_ABIVERSION, ehdr->e_ident[EI_ABIVERSION]); + + for (cnt = EI_PAD; cnt < EI_NIDENT; ++cnt) + if (ehdr->e_ident[cnt] != 0) + ERROR (gettext ("e_ident[%zu] is not zero\n"), cnt); + + /* Check the e_type field. */ + if (ehdr->e_type != ET_REL && ehdr->e_type != ET_EXEC + && ehdr->e_type != ET_DYN && ehdr->e_type != ET_CORE) + ERROR (gettext ("unknown object file type %d\n"), ehdr->e_type); + + /* Check the e_machine field. */ + for (cnt = 0; cnt < nvalid_e_machine; ++cnt) + if (valid_e_machine[cnt] == ehdr->e_machine) + break; + if (cnt == nvalid_e_machine) + ERROR (gettext ("unknown machine type %d\n"), ehdr->e_machine); + + /* Check the e_version field. */ + if (ehdr->e_version != EV_CURRENT) + ERROR (gettext ("unknown object file version\n")); + + /* Check the e_phoff and e_phnum fields. */ + if (ehdr->e_phoff == 0) + { + if (ehdr->e_phnum != 0) + ERROR (gettext ("invalid program header offset\n")); + else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN) + ERROR (gettext ("\ +executables and DSOs cannot have zero program header offset\n")); + } + else if (ehdr->e_phnum == 0) + ERROR (gettext ("invalid number of program header entries\n")); + + /* Check the e_shoff field. */ + shnum = ehdr->e_shnum; + shstrndx = ehdr->e_shstrndx; + if (ehdr->e_shoff == 0) + { + if (ehdr->e_shnum != 0) + ERROR (gettext ("invalid section header table offset\n")); + else if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN + && ehdr->e_type != ET_CORE) + ERROR (gettext ("section header table must be present\n")); + } + else + { + if (ehdr->e_shnum == 0) + { + /* Get the header of the zeroth section. The sh_size field + might contain the section number. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); + if (shdr != NULL) + { + /* The error will be reported later. */ + if (shdr->sh_size == 0) + ERROR (gettext ("\ +invalid number of section header table entries\n")); + else + shnum = shdr->sh_size; + } + } + + if (ehdr->e_shstrndx == SHN_XINDEX) + { + /* Get the header of the zeroth section. The sh_size field + might contain the section number. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); + if (shdr != NULL) + { + /* The error will be reported later. */ + if (shdr->sh_link >= shnum) + ERROR (gettext ("invalid section header index\n")); + else + shstrndx = shdr->sh_link; + } + } + else if (shstrndx >= shnum) + ERROR (gettext ("invalid section header index\n")); + } + + /* Check the e_flags field. */ + if (!ebl_machine_flag_check (ebl, ehdr->e_flags)) + ERROR (gettext ("invalid machine flags: %s\n"), + ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf))); + + /* Check e_ehsize, e_phentsize, and e_shentsize fields. */ + if (gelf_getclass (ebl->elf) == ELFCLASS32) + { + if (ehdr->e_ehsize != 0 && ehdr->e_ehsize != sizeof (Elf32_Ehdr)) + ERROR (gettext ("invalid ELF header size: %hd\n"), ehdr->e_ehsize); + + if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf32_Phdr)) + ERROR (gettext ("invalid program header size: %hd\n"), + ehdr->e_phentsize); + else if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > size) + ERROR (gettext ("invalid program header position or size\n")); + + if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf32_Shdr)) + ERROR (gettext ("invalid section header size: %hd\n"), + ehdr->e_shentsize); + else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) + ERROR (gettext ("invalid section header position or size\n")); + } + else if (gelf_getclass (ebl->elf) == ELFCLASS64) + { + if (ehdr->e_ehsize != 0 && ehdr->e_ehsize != sizeof (Elf64_Ehdr)) + ERROR (gettext ("invalid ELF header size: %hd\n"), ehdr->e_ehsize); + + if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf64_Phdr)) + ERROR (gettext ("invalid program header size: %hd\n"), + ehdr->e_phentsize); + else if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > size) + ERROR (gettext ("invalid program header position or size\n")); + + if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf64_Shdr)) + ERROR (gettext ("invalid section header size: %hd\n"), + ehdr->e_shentsize); + else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) + ERROR (gettext ("invalid section header position or size\n")); + } +} + + +/* Check that there is a section group section with index < IDX which + contains section IDX and that there is exactly one. */ +static void +check_scn_group (Ebl *ebl, int idx) +{ + if (scnref[idx] == 0) + { + /* No reference so far. Search following sections, maybe the + order is wrong. */ + size_t cnt; + + for (cnt = idx + 1; cnt < shnum; ++cnt) + { + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Data *data; + Elf32_Word *grpdata; + size_t inner; + + scn = elf_getscn (ebl->elf, cnt); + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + /* We cannot get the section header so we cannot check it. + The error to get the section header will be shown + somewhere else. */ + continue; + + if (shdr->sh_type != SHT_GROUP) + continue; + + data = elf_getdata (scn, NULL); + if (data == NULL || data->d_size < sizeof (Elf32_Word)) + /* Cannot check the section. */ + continue; + + grpdata = (Elf32_Word *) data->d_buf; + for (inner = 1; inner < data->d_size / sizeof (Elf32_Word); ++inner) + if (grpdata[inner] == (Elf32_Word) idx) + goto out; + } + + out: + if (cnt == shnum) + ERROR (gettext ("\ +section [%2d] '%s': section with SHF_GROUP flag set not part of a section group\n"), + idx, section_name (ebl, idx)); + else + ERROR (gettext ("\ +section [%2d] '%s': section group [%2zu] '%s' does not preceed group member\n"), + idx, section_name (ebl, idx), + cnt, section_name (ebl, cnt)); + } +} + + +static void +check_symtab (Ebl *ebl, GElf_Ehdr *ehdr, int idx) +{ + bool no_xndx_warned = false; + int no_pt_tls = 0; + + Elf_Scn *scn = elf_getscn (ebl->elf, idx); + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + GElf_Shdr strshdr_mem; + GElf_Shdr *strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), + &strshdr_mem); + if (shdr == NULL || strshdr == NULL) + return; + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL) + { + ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), + idx, section_name (ebl, idx)); + return; + } + + if (strshdr->sh_type != SHT_STRTAB) + ERROR (gettext ("section [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"), + shdr->sh_link, section_name (ebl, shdr->sh_link), + idx, section_name (ebl, idx)); + + /* Search for an extended section index table section. */ + size_t cnt; + GElf_Shdr xndxshdr_mem; + GElf_Shdr *xndxshdr = NULL; + Elf_Data *xndxdata = NULL; + Elf32_Word xndxscnidx = 0; + for (cnt = 1; cnt < shnum; ++cnt) + if (cnt != (size_t) idx) + { + Elf_Scn *xndxscn = elf_getscn (ebl->elf, cnt); + xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem); + xndxdata = elf_getdata (xndxscn, NULL); + xndxscnidx = elf_ndxscn (xndxscn); + + if (xndxshdr == NULL || xndxdata == NULL) + continue; + + if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX + && xndxshdr->sh_link == (GElf_Word) idx) + break; + } + if (cnt == shnum) + { + xndxshdr = NULL; + xndxdata = NULL; + } + + if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT)) + ERROR (gettext ("\ +section [%2zu] '%s': entry size is does not match ElfXX_Sym\n"), + cnt, section_name (ebl, cnt)); + + /* Test the zeroth entry. */ + GElf_Sym sym_mem; + Elf32_Word xndx; + GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, 0, &sym_mem, &xndx); + if (sym == NULL) + ERROR (gettext ("section [%2d] '%s': cannot get symbol %d: %s\n"), + idx, section_name (ebl, idx), 0, elf_errmsg (-1)); + else + { + if (sym->st_name != 0) + ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), + idx, section_name (ebl, idx), "st_name"); + if (sym->st_value != 0) + ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), + idx, section_name (ebl, idx), "st_value"); + if (sym->st_size != 0) + ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), + idx, section_name (ebl, idx), "st_size"); + if (sym->st_info != 0) + ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), + idx, section_name (ebl, idx), "st_info"); + if (sym->st_other != 0) + ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), + idx, section_name (ebl, idx), "st_other"); + if (sym->st_shndx != 0) + ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), + idx, section_name (ebl, idx), "st_shndx"); + if (xndxdata != NULL && xndx != 0) + ERROR (gettext ("\ +section [%2d] '%s': XINDEX for zeroth entry not zero\n"), + xndxscnidx, section_name (ebl, xndxscnidx)); + } + + for (cnt = 1; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) + { + sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem, &xndx); + if (sym == NULL) + { + ERROR (gettext ("section [%2d] '%s': cannot get symbol %zu: %s\n"), + idx, section_name (ebl, idx), cnt, elf_errmsg (-1)); + continue; + } + + const char *name = NULL; + if (sym->st_name >= strshdr->sh_size) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: invalid name value\n"), + idx, section_name (ebl, idx), cnt); + else + { + name = elf_strptr (ebl->elf, shdr->sh_link, sym->st_name); + assert (name != NULL); + } + + if (sym->st_shndx == SHN_XINDEX) + { + if (xndxdata == NULL) + { + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: too large section index but no extended section index section\n"), + idx, section_name (ebl, idx), cnt); + no_xndx_warned = true; + } + else if (xndx < SHN_LORESERVE) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: XINDEX used for index which would fit in st_shndx (%" PRIu32 ")\n"), + xndxscnidx, section_name (ebl, xndxscnidx), cnt, + xndx); + } + else if ((sym->st_shndx >= SHN_LORESERVE + // && sym->st_shndx <= SHN_HIRESERVE always true + && sym->st_shndx != SHN_ABS + && sym->st_shndx != SHN_COMMON) + || (sym->st_shndx >= shnum + && (sym->st_shndx < SHN_LORESERVE + /* || sym->st_shndx > SHN_HIRESERVE always false */))) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: invalid section index\n"), + idx, section_name (ebl, idx), cnt); + else + xndx = sym->st_shndx; + + if (GELF_ST_TYPE (sym->st_info) >= STT_NUM) + ERROR (gettext ("section [%2d] '%s': symbol %zu: unknown type\n"), + idx, section_name (ebl, idx), cnt); + + if (GELF_ST_BIND (sym->st_info) >= STB_NUM) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: unknown symbol binding\n"), + idx, section_name (ebl, idx), cnt); + + if (xndx == SHN_COMMON) + { + /* Common symbols can only appear in relocatable files. */ + if (ehdr->e_type != ET_REL) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: COMMON only allowed in relocatable files\n"), + idx, section_name (ebl, idx), cnt); + if (cnt < shdr->sh_info) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: local COMMON symbols are nonsense\n"), + idx, section_name (ebl, idx), cnt); + if (GELF_R_TYPE (sym->st_info) == STT_FUNC) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"), + idx, section_name (ebl, idx), cnt); + } + else if (xndx > 0 && xndx < shnum) + { + GElf_Shdr destshdr_mem; + GElf_Shdr *destshdr; + + destshdr = gelf_getshdr (elf_getscn (ebl->elf, xndx), &destshdr_mem); + if (destshdr != NULL) + { + if (GELF_ST_TYPE (sym->st_info) != STT_TLS) + { + if ((sym->st_value - destshdr->sh_addr) > destshdr->sh_size) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: st_value out of bounds\n"), + idx, section_name (ebl, idx), cnt); + else if ((sym->st_value - destshdr->sh_addr + sym->st_size) + > destshdr->sh_size) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), + idx, section_name (ebl, idx), cnt, + (int) xndx, section_name (ebl, xndx)); + } + else + { + if ((destshdr->sh_flags & SHF_TLS) == 0) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: referenced section [%2d] '%s' does not have SHF_TLS flag set\n"), + idx, section_name (ebl, idx), cnt, + (int) xndx, section_name (ebl, xndx)); + + if (ehdr->e_type == ET_REL) + { + /* For object files the symbol value must fall + into the section. */ + if (sym->st_value > destshdr->sh_size) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"), + idx, section_name (ebl, idx), cnt, + (int) xndx, section_name (ebl, xndx)); + else if (sym->st_value + sym->st_size + > destshdr->sh_size) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), + idx, section_name (ebl, idx), cnt, + (int) xndx, section_name (ebl, xndx)); + } + else + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = NULL; + int pcnt; + + for (pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt) + { + phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem); + if (phdr != NULL && phdr->p_type == PT_TLS) + break; + } + + if (pcnt == ehdr->e_phnum) + { + if (no_pt_tls++ == 0) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: TLS symbol but no TLS program header entry\n"), + idx, section_name (ebl, idx), cnt); + } + else + { + if (sym->st_value + < destshdr->sh_offset - phdr->p_offset) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: st_value short of referenced section [%2d] '%s'\n"), + idx, section_name (ebl, idx), cnt, + (int) xndx, section_name (ebl, xndx)); + else if (sym->st_value + > (destshdr->sh_offset - phdr->p_offset + + destshdr->sh_size)) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"), + idx, section_name (ebl, idx), cnt, + (int) xndx, section_name (ebl, xndx)); + else if (sym->st_value + sym->st_size + > (destshdr->sh_offset - phdr->p_offset + + destshdr->sh_size)) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), + idx, section_name (ebl, idx), cnt, + (int) xndx, section_name (ebl, xndx)); + } + } + } + } + } + + if (GELF_ST_BIND (sym->st_info) == STB_LOCAL) + { + if (cnt >= shdr->sh_info) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: local symbol outside range described in sh_info\n"), + idx, section_name (ebl, idx), cnt); + } + else + { + if (cnt < shdr->sh_info) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: non-local symbol outside range described in sh_info\n"), + idx, section_name (ebl, idx), cnt); + } + + if (GELF_ST_TYPE (sym->st_info) == STT_SECTION + && GELF_ST_BIND (sym->st_info) != STB_LOCAL) + ERROR (gettext ("\ +section [%2d] '%s': symbol %zu: non-local section symbol\n"), + idx, section_name (ebl, idx), cnt); + + if (name != NULL) + { + if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) + { + /* Check that address and size match the global offset + table. We have to locate the GOT by searching for a + section named ".got". */ + Elf_Scn *gscn = NULL; + GElf_Addr addr = 0; + GElf_Xword size = 0; + bool found = false; + + while ((gscn = elf_nextscn (ebl->elf, gscn)) != NULL) + { + GElf_Shdr gshdr_mem; + GElf_Shdr *gshdr = gelf_getshdr (gscn, &gshdr_mem); + assert (gshdr != NULL); + + const char *sname = elf_strptr (ebl->elf, ehdr->e_shstrndx, + gshdr->sh_name); + if (sname != NULL) + { + if (strcmp (sname, ".got.plt") == 0) + { + addr = gshdr->sh_addr; + size = gshdr->sh_size; + found = true; + break; + } + if (strcmp (sname, ".got") == 0) + { + addr = gshdr->sh_addr; + size = gshdr->sh_size; + found = true; + /* Do not stop looking. There might be a + .got.plt section. */ + } + } + } + + if (found) + { + /* Found it. */ + if (sym->st_value != addr) + /* This test is more strict than the psABIs which + usually allow the symbol to be in the middle of + the .got section, allowing negative offsets. */ + ERROR (gettext ("\ +section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol value %#" PRIx64 " does not match .got section address %#" PRIx64 "\n"), + idx, section_name (ebl, idx), + (uint64_t) sym->st_value, (uint64_t) addr); + + if (!gnuld && sym->st_size != size) + ERROR (gettext ("\ +section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol size %" PRIu64 " does not match .got section size %" PRIu64 "\n"), + idx, section_name (ebl, idx), + (uint64_t) sym->st_size, (uint64_t) size); + } + else + ERROR (gettext ("\ +section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol present, but no .got section\n"), + idx, section_name (ebl, idx)); + } + else if (strcmp (name, "_DYNAMIC") == 0) + { + /* Check that address and size match the dynamic + section. We locate the dynamic section via the + program header entry. */ + int pcnt; + + for (pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem); + + if (phdr != NULL && phdr->p_type == PT_DYNAMIC) + { + if (sym->st_value != phdr->p_vaddr) + ERROR (gettext ("\ +section [%2d] '%s': _DYNAMIC_ symbol value %#" PRIx64 " does not match dynamic segment address %#" PRIx64 "\n"), + idx, section_name (ebl, idx), + (uint64_t) sym->st_value, + (uint64_t) phdr->p_vaddr); + + if (!gnuld && sym->st_size != phdr->p_memsz) + ERROR (gettext ("\ +section [%2d] '%s': _DYNAMIC symbol size %" PRIu64 " does not match dynamic segment size %" PRIu64 "\n"), + idx, section_name (ebl, idx), + (uint64_t) sym->st_size, + (uint64_t) phdr->p_memsz); + + break; + } + } + } + } + } +} + + +static bool +is_rel_dyn (Ebl *ebl, GElf_Ehdr *ehdr, int idx, GElf_Shdr *shdr, bool rela) +{ + /* If this is no executable or DSO it cannot be a .rel.dyn section. */ + if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) + return false; + + /* Check the section name. Unfortunately necessary. */ + if (strcmp (section_name (ebl, idx), rela ? ".rela.dyn" : ".rel.dyn")) + return false; + + /* When a .rel.dyn section is used a DT_RELCOUNT dynamic section + entry can be present as well. */ + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + GElf_Shdr rcshdr_mem; + const GElf_Shdr *rcshdr = gelf_getshdr (scn, &rcshdr_mem); + assert (rcshdr != NULL); + + if (rcshdr->sh_type == SHT_DYNAMIC) + { + /* Found the dynamic section. Look through it. */ + Elf_Data *d = elf_getdata (scn, NULL); + size_t cnt; + + for (cnt = 1; cnt < rcshdr->sh_size / rcshdr->sh_entsize; ++cnt) + { + GElf_Dyn dyn_mem; + GElf_Dyn *dyn = gelf_getdyn (d, cnt, &dyn_mem); + assert (dyn != NULL); + + if (dyn->d_tag == DT_RELCOUNT) + { + /* Found it. One last check: does the number + specified number of relative relocations exceed + the total number of relocations? */ + if (dyn->d_un.d_val > shdr->sh_size / shdr->sh_entsize) + ERROR (gettext ("\ +section [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"), + idx, section_name (ebl, idx), + (int) dyn->d_un.d_val); + } + } + + break; + } + } + + return true; +} + + +static void +check_rela (Ebl *ebl, GElf_Ehdr *ehdr, int idx) +{ + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Data *data; + GElf_Shdr destshdr_mem; + GElf_Shdr *destshdr = NULL; + size_t cnt; + bool reldyn = false; + bool known_broken = gnuld; + + scn = elf_getscn (ebl->elf, idx); + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + return; + data = elf_getdata (scn, NULL); + if (data == NULL) + { + ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), + idx, section_name (ebl, idx)); + return; + } + + /* Check whether the link to the section we relocate is reasonable. */ + if (shdr->sh_info >= shnum) + ERROR (gettext ("section [%2d] '%s': invalid destination section index\n"), + idx, section_name (ebl, idx)); + else + { + destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info), + &destshdr_mem); + if (destshdr != NULL) + { + if(destshdr->sh_type != SHT_PROGBITS + && destshdr->sh_type != SHT_NOBITS) + { + reldyn = is_rel_dyn (ebl, ehdr, idx, shdr, true); + if (!reldyn) + ERROR (gettext ("\ +section [%2d] '%s': invalid destination section type\n"), + idx, section_name (ebl, idx)); + else + { + /* There is no standard, but we require that .rela.dyn + sections have a sh_info value of zero. */ + if (shdr->sh_info != 0) + ERROR (gettext ("\ +section [%2d] '%s': sh_info should be zero\n"), + idx, section_name (ebl, idx)); + } + } + + if ((destshdr->sh_flags & (SHF_MERGE | SHF_STRINGS)) != 0) + ERROR (gettext ("\ +section [%2d] '%s': no relocations for merge-able sections possible\n"), + idx, section_name (ebl, idx)); + } + } + + if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_RELA, 1, EV_CURRENT)) + ERROR (gettext ("\ +section [%2d] '%s': section entry size does not match ElfXX_Rela\n"), + idx, section_name (ebl, idx)); + + Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link); + GElf_Shdr symshdr_mem; + GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem); + Elf_Data *symdata = elf_getdata (symscn, NULL); + + for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) + { + GElf_Rela rela_mem; + GElf_Rela *rela; + + rela = gelf_getrela (data, cnt, &rela_mem); + if (rela == NULL) + { + ERROR (gettext ("\ +section [%2d] '%s': cannot get relocation %zu: %s\n"), + idx, section_name (ebl, idx), cnt, elf_errmsg (-1)); + continue; + } + + if (!ebl_reloc_type_check (ebl, GELF_R_TYPE (rela->r_info))) + ERROR (gettext ("section [%2d] '%s': relocation %zu: invalid type\n"), + idx, section_name (ebl, idx), cnt); + else if (!ebl_reloc_valid_use (ebl, GELF_R_TYPE (rela->r_info))) + ERROR (gettext ("\ +section [%2d] '%s': relocation %zu: relocation type invalid for the file type\n"), + idx, section_name (ebl, idx), cnt); + + if (symshdr != NULL + && ((GELF_R_SYM (rela->r_info) + 1) + * gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT) + > symshdr->sh_size)) + ERROR (gettext ("\ +section [%2d] '%s': relocation %zu: invalid symbol index\n"), + idx, section_name (ebl, idx), cnt); + + if (ebl_gotpc_reloc_check (ebl, GELF_R_TYPE (rela->r_info))) + { + const char *name; + char buf[64]; + GElf_Sym sym_mem; + GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (rela->r_info), + &sym_mem); + if (sym != NULL + /* Get the name for the symbol. */ + && (name = elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)) + && strcmp (name, "_GLOBAL_OFFSET_TABLE_") !=0 ) + ERROR (gettext ("\ +section [%2d] '%s': relocation %zu: only symbol '_GLOBAL_OFFSET_TABLE_' can be used with %s\n"), + idx, section_name (ebl, idx), cnt, + ebl_reloc_type_name (ebl, GELF_R_SYM (rela->r_info), + buf, sizeof (buf))); + } + + if (reldyn) + { + // XXX TODO Check .rel.dyn section addresses. + } + else if (!known_broken) + { + if (destshdr != NULL + && (rela->r_offset - destshdr->sh_addr) >= destshdr->sh_size) + ERROR (gettext ("\ +section [%2d] '%s': relocation %zu: offset out of bounds\n"), + idx, section_name (ebl, idx), cnt); + } + + if (symdata != NULL + && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rela->r_info))) + { + /* Make sure the referenced symbol is an object or unspecified. */ + GElf_Sym sym_mem; + GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (rela->r_info), + &sym_mem); + if (sym != NULL + && GELF_ST_TYPE (sym->st_info) != STT_NOTYPE + && GELF_ST_TYPE (sym->st_info) != STT_OBJECT) + { + char buf[64]; + ERROR (gettext ("section [%2d] '%s': relocation %zu: copy relocation against symbol of type %s\n"), + idx, section_name (ebl, idx), cnt, + ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info), + buf, sizeof (buf))); + } + } + } +} + + +static void +check_rel (Ebl *ebl, GElf_Ehdr *ehdr, int idx) +{ + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Data *data; + GElf_Shdr destshdr_mem; + GElf_Shdr *destshdr = NULL; + size_t cnt; + bool reldyn = false; + bool known_broken = gnuld; + + scn = elf_getscn (ebl->elf, idx); + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + return; + data = elf_getdata (scn, NULL); + if (data == NULL) + { + ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), + idx, section_name (ebl, idx)); + return; + } + + /* Check whether the link to the section we relocate is reasonable. */ + if (shdr->sh_info >= shnum) + ERROR (gettext ("section [%2d] '%s': invalid destination section index\n"), + idx, section_name (ebl, idx)); + else + { + destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info), + &destshdr_mem); + if (destshdr != NULL) + { + if (destshdr->sh_type != SHT_PROGBITS + && destshdr->sh_type != SHT_NOBITS) + { + reldyn = is_rel_dyn (ebl, ehdr, idx, shdr, false); + if (!reldyn) + ERROR (gettext ("\ +section [%2d] '%s': invalid destination section type\n"), + idx, section_name (ebl, idx)); + else + { + /* There is no standard, but we require that .rela.dyn + sections have a sh_info value of zero. */ + if (shdr->sh_info != 0) + ERROR (gettext ("\ +section [%2d] '%s': sh_info should be zero\n"), + idx, section_name (ebl, idx)); + } + } + + if ((destshdr->sh_flags & (SHF_MERGE | SHF_STRINGS)) != 0) + ERROR (gettext ("\ +section [%2d] '%s': no relocations for merge-able sections possible\n"), + idx, section_name (ebl, idx)); + } + } + + if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_REL, 1, EV_CURRENT)) + ERROR (gettext ("\ +section [%2d] '%s': section entry size does not match ElfXX_Rel\n"), + idx, section_name (ebl, idx)); + + Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link); + GElf_Shdr symshdr_mem; + GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem); + Elf_Data *symdata = elf_getdata (symscn, NULL); + + for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) + { + GElf_Rel rel_mem; + GElf_Rel *rel; + + rel = gelf_getrel (data, cnt, &rel_mem); + if (rel == NULL) + { + ERROR (gettext ("\ +section [%2d] '%s': cannot get relocation %zu: %s\n"), + idx, section_name (ebl, idx), cnt, elf_errmsg (-1)); + continue; + } + + if (!ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))) + ERROR (gettext ("section [%2d] '%s': relocation %zu: invalid type\n"), + idx, section_name (ebl, idx), cnt); + else if (!ebl_reloc_valid_use (ebl, GELF_R_TYPE (rel->r_info))) + ERROR (gettext ("\ +section [%2d] '%s': relocation %zu: relocation type invalid for the file type\n"), + idx, section_name (ebl, idx), cnt); + + if (symshdr != NULL + && ((GELF_R_SYM (rel->r_info) + 1) + * gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT) + > symshdr->sh_size)) + ERROR (gettext ("\ +section [%2d] '%s': relocation %zu: invalid symbol index\n"), + idx, section_name (ebl, idx), cnt); + + if (ebl_gotpc_reloc_check (ebl, GELF_R_TYPE (rel->r_info))) + { + const char *name; + char buf[64]; + GElf_Sym sym_mem; + GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (rel->r_info), + &sym_mem); + if (sym != NULL + /* Get the name for the symbol. */ + && (name = elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)) + && strcmp (name, "_GLOBAL_OFFSET_TABLE_") !=0 ) + ERROR (gettext ("\ +section [%2d] '%s': relocation %zu: only symbol '_GLOBAL_OFFSET_TABLE_' can be used with %s\n"), + idx, section_name (ebl, idx), cnt, + ebl_reloc_type_name (ebl, GELF_R_SYM (rel->r_info), + buf, sizeof (buf))); + } + + if (reldyn) + { + // XXX TODO Check .rel.dyn section addresses. + } + else if (!known_broken) + { + if (destshdr != NULL + && GELF_R_TYPE (rel->r_info) != 0 + && (rel->r_offset - destshdr->sh_addr) >= destshdr->sh_size) + ERROR (gettext ("\ +section [%2d] '%s': relocation %zu: offset out of bounds\n"), + idx, section_name (ebl, idx), cnt); + } + + if (symdata != NULL + && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rel->r_info))) + { + /* Make sure the referenced symbol is an object or unspecified. */ + GElf_Sym sym_mem; + GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (rel->r_info), + &sym_mem); + if (sym != NULL + && GELF_ST_TYPE (sym->st_info) != STT_NOTYPE + && GELF_ST_TYPE (sym->st_info) != STT_OBJECT) + { + char buf[64]; + ERROR (gettext ("section [%2d] '%s': relocation %zu: copy relocation against symbol of type %s\n"), + idx, section_name (ebl, idx), cnt, + ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info), + buf, sizeof (buf))); + } + } + } +} + + +/* Number of dynamic sections. */ +static int ndynamic; + + +static void +check_dynamic (Ebl *ebl, int idx) +{ + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Data *data; + GElf_Shdr strshdr_mem; + GElf_Shdr *strshdr; + size_t cnt; + static const bool dependencies[DT_NUM][DT_NUM] = + { + [DT_NEEDED] = { [DT_STRTAB] = true }, + [DT_PLTRELSZ] = { [DT_JMPREL] = true }, + [DT_HASH] = { [DT_SYMTAB] = true }, + [DT_STRTAB] = { [DT_STRSZ] = true }, + [DT_SYMTAB] = { [DT_STRTAB] = true, [DT_HASH] = true, + [DT_SYMENT] = true }, + [DT_RELA] = { [DT_RELASZ] = true, [DT_RELAENT] = true }, + [DT_RELASZ] = { [DT_RELA] = true }, + [DT_RELAENT] = { [DT_RELA] = true }, + [DT_STRSZ] = { [DT_STRTAB] = true }, + [DT_SYMENT] = { [DT_SYMTAB] = true }, + [DT_SONAME] = { [DT_STRTAB] = true }, + [DT_RPATH] = { [DT_STRTAB] = true }, + [DT_REL] = { [DT_RELSZ] = true, [DT_RELENT] = true }, + [DT_RELSZ] = { [DT_REL] = true }, + [DT_RELENT] = { [DT_REL] = true }, + [DT_JMPREL] = { [DT_PLTRELSZ] = true, [DT_PLTREL] = true }, + [DT_RUNPATH] = { [DT_STRTAB] = true }, + [DT_PLTREL] = { [DT_JMPREL] = true }, + [DT_PLTRELSZ] = { [DT_JMPREL] = true } + }; + bool has_dt[DT_NUM]; + static const bool level2[DT_NUM] = + { + [DT_RPATH] = true, + [DT_SYMBOLIC] = true, + [DT_TEXTREL] = true, + [DT_BIND_NOW] = true + }; + static const bool mandatory[DT_NUM] = + { + [DT_NULL] = true, + [DT_HASH] = true, + [DT_STRTAB] = true, + [DT_SYMTAB] = true, + [DT_STRSZ] = true, + [DT_SYMENT] = true + }; + GElf_Addr reladdr = 0; + GElf_Word relsz = 0; + GElf_Addr pltreladdr = 0; + GElf_Word pltrelsz = 0; + + memset (has_dt, '\0', sizeof (has_dt)); + + if (++ndynamic == 2) + ERROR (gettext ("more than one dynamic section present\n")); + + scn = elf_getscn (ebl->elf, idx); + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + return; + data = elf_getdata (scn, NULL); + if (data == NULL) + { + ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), + idx, section_name (ebl, idx)); + return; + } + + strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &strshdr_mem); + if (strshdr != NULL && strshdr->sh_type != SHT_STRTAB) + ERROR (gettext ("\ +section [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"), + shdr->sh_link, section_name (ebl, shdr->sh_link), + idx, section_name (ebl, idx)); + + if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT)) + ERROR (gettext ("\ +section [%2d] '%s': section entry size does not match ElfXX_Dyn\n"), + idx, section_name (ebl, idx)); + + if (shdr->sh_info != 0) + ERROR (gettext ("section [%2d] '%s': sh_info not zero\n"), + idx, section_name (ebl, idx)); + + bool non_null_warned = false; + for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) + { + GElf_Dyn dyn_mem; + GElf_Dyn *dyn; + + dyn = gelf_getdyn (data, cnt, &dyn_mem); + if (dyn == NULL) + { + ERROR (gettext ("\ +section [%2d] '%s': cannot get dynamic section entry %zu: %s\n"), + idx, section_name (ebl, idx), cnt, elf_errmsg (-1)); + continue; + } + + if (has_dt[DT_NULL] && dyn->d_tag != DT_NULL && ! non_null_warned) + { + ERROR (gettext ("\ +section [%2d] '%s': non-DT_NULL entries follow DT_NULL entry\n"), + idx, section_name (ebl, idx)); + non_null_warned = true; + } + + if (!ebl_dynamic_tag_check (ebl, dyn->d_tag)) + ERROR (gettext ("section [%2d] '%s': entry %zu: unknown tag\n"), + idx, section_name (ebl, idx), cnt); + + if (dyn->d_tag >= 0 && dyn->d_tag < DT_NUM) + { + if (has_dt[dyn->d_tag] + && dyn->d_tag != DT_NEEDED + && dyn->d_tag != DT_NULL + && dyn->d_tag != DT_POSFLAG_1) + { + char buf[50]; + ERROR (gettext ("\ +section [%2d] '%s': entry %zu: more than one entry with tag %s\n"), + idx, section_name (ebl, idx), cnt, + ebl_dynamic_tag_name (ebl, dyn->d_tag, + buf, sizeof (buf))); + } + + if (be_strict && level2[dyn->d_tag]) + { + char buf[50]; + ERROR (gettext ("\ +section [%2d] '%s': entry %zu: level 2 tag %s used\n"), + idx, section_name (ebl, idx), cnt, + ebl_dynamic_tag_name (ebl, dyn->d_tag, + buf, sizeof (buf))); + } + + has_dt[dyn->d_tag] = true; + } + + if (dyn->d_tag == DT_PLTREL && dyn->d_un.d_val != DT_REL + && dyn->d_un.d_val != DT_RELA) + ERROR (gettext ("\ +section [%2d] '%s': entry %zu: DT_PLTREL value must be DT_REL or DT_RELA\n"), + idx, section_name (ebl, idx), cnt); + + if (dyn->d_tag == DT_REL) + reladdr = dyn->d_un.d_ptr; + if (dyn->d_tag == DT_RELSZ) + relsz = dyn->d_un.d_val; + if (dyn->d_tag == DT_JMPREL) + pltreladdr = dyn->d_un.d_ptr; + if (dyn->d_tag == DT_PLTRELSZ) + pltrelsz = dyn->d_un.d_val; + } + + for (cnt = 1; cnt < DT_NUM; ++cnt) + if (has_dt[cnt]) + { + int inner; + + for (inner = 0; inner < DT_NUM; ++inner) + if (dependencies[cnt][inner] && ! has_dt[inner]) + { + char buf1[50]; + char buf2[50]; + + ERROR (gettext ("\ +section [%2d] '%s': contains %s entry but not %s\n"), + idx, section_name (ebl, idx), + ebl_dynamic_tag_name (ebl, cnt, buf1, sizeof (buf1)), + ebl_dynamic_tag_name (ebl, inner, buf2, sizeof (buf2))); + } + } + else + { + if (mandatory[cnt]) + { + char buf[50]; + ERROR (gettext ("\ +section [%2d] '%s': mandatory tag %s not present\n"), + idx, section_name (ebl, idx), + ebl_dynamic_tag_name (ebl, cnt, buf, sizeof (buf))); + } + } + + /* Check the rel/rela tags. At least one group must be available. */ + if ((has_dt[DT_RELA] || has_dt[DT_RELASZ] || has_dt[DT_RELAENT]) + && (!has_dt[DT_RELA] || !has_dt[DT_RELASZ] || !has_dt[DT_RELAENT])) + ERROR (gettext ("\ +section [%2d] '%s': not all of %s, %s, and %s are present\n"), + idx, section_name (ebl, idx), + "DT_RELA", "DT_RELASZ", "DT_RELAENT"); + + if ((has_dt[DT_REL] || has_dt[DT_RELSZ] || has_dt[DT_RELENT]) + && (!has_dt[DT_REL] || !has_dt[DT_RELSZ] || !has_dt[DT_RELENT])) + ERROR (gettext ("\ +section [%2d] '%s': not all of %s, %s, and %s are present\n"), + idx, section_name (ebl, idx), + "DT_REL", "DT_RELSZ", "DT_RELENT"); +} + + +static void +check_symtab_shndx (Ebl *ebl, int idx) +{ + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + GElf_Shdr symshdr_mem; + GElf_Shdr *symshdr; + Elf_Scn *symscn; + size_t cnt; + Elf_Data *data; + Elf_Data *symdata; + + scn = elf_getscn (ebl->elf, idx); + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + return; + + symscn = elf_getscn (ebl->elf, shdr->sh_link); + symshdr = gelf_getshdr (symscn, &symshdr_mem); + if (symshdr != NULL && symshdr->sh_type != SHT_SYMTAB) + ERROR (gettext ("\ +section [%2d] '%s': extended section index section not for symbol table\n"), + idx, section_name (ebl, idx)); + symdata = elf_getdata (symscn, NULL); + if (symdata == NULL) + ERROR (gettext ("cannot get data for symbol section\n")); + + if (shdr->sh_entsize != sizeof (Elf32_Word)) + ERROR (gettext ("\ +section [%2d] '%s': entry size does not match Elf32_Word\n"), + idx, section_name (ebl, idx)); + + if (symshdr != NULL + && (shdr->sh_size / shdr->sh_entsize + < symshdr->sh_size / symshdr->sh_entsize)) + ERROR (gettext ("\ +section [%2d] '%s': extended index table too small for symbol table\n"), + idx, section_name (ebl, idx)); + + if (shdr->sh_info != 0) + ERROR (gettext ("section [%2d] '%s': sh_info not zero\n"), + idx, section_name (ebl, idx)); + + for (cnt = idx + 1; cnt < shnum; ++cnt) + { + GElf_Shdr rshdr_mem; + GElf_Shdr *rshdr; + + rshdr = gelf_getshdr (elf_getscn (ebl->elf, cnt), &rshdr_mem); + if (rshdr != NULL && rshdr->sh_type == SHT_SYMTAB_SHNDX + && rshdr->sh_link == shdr->sh_link) + { + ERROR (gettext ("\ +section [%2d] '%s': extended section index in section [%2zu] '%s' refers to same symbol table\n"), + idx, section_name (ebl, idx), + cnt, section_name (ebl, cnt)); + break; + } + } + + data = elf_getdata (scn, NULL); + + if (*((Elf32_Word *) data->d_buf) != 0) + ERROR (gettext ("symbol 0 should have zero extended section index\n")); + + for (cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt) + { + Elf32_Word xndx = ((Elf32_Word *) data->d_buf)[cnt]; + + if (xndx != 0) + { + GElf_Sym sym_data; + GElf_Sym *sym = gelf_getsym (symdata, cnt, &sym_data); + if (sym == NULL) + { + ERROR (gettext ("cannot get data for symbol %zu\n"), cnt); + continue; + } + + if (sym->st_shndx != SHN_XINDEX) + ERROR (gettext ("\ +extended section index is %" PRIu32 " but symbol index is not XINDEX\n"), + (uint32_t) xndx); + } + } +} + + +static void +check_hash (Ebl *ebl, int idx) +{ + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Data *data; + Elf32_Word nbucket; + Elf32_Word nchain; + GElf_Shdr symshdr_mem; + GElf_Shdr *symshdr; + + scn = elf_getscn (ebl->elf, idx); + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + return; + data = elf_getdata (scn, NULL); + if (data == NULL) + { + ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), + idx, section_name (ebl, idx)); + return; + } + + symshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &symshdr_mem); + if (symshdr != NULL && symshdr->sh_type != SHT_DYNSYM) + ERROR (gettext ("\ +section [%2d] '%s': hash table not for dynamic symbol table\n"), + idx, section_name (ebl, idx)); + + if (shdr->sh_entsize != sizeof (Elf32_Word)) + ERROR (gettext ("\ +section [%2d] '%s': entry size does not match Elf32_Word\n"), + idx, section_name (ebl, idx)); + + if ((shdr->sh_flags & SHF_ALLOC) == 0) + ERROR (gettext ("section [%2d] '%s': not marked to be allocated\n"), + idx, section_name (ebl, idx)); + + if (shdr->sh_size < 2 * shdr->sh_entsize) + { + ERROR (gettext ("\ +section [%2d] '%s': hash table has not even room for nbucket and nchain\n"), + idx, section_name (ebl, idx)); + return; + } + + nbucket = ((Elf32_Word *) data->d_buf)[0]; + nchain = ((Elf32_Word *) data->d_buf)[1]; + + if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize) + ERROR (gettext ("\ +section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), + idx, section_name (ebl, idx), (long int) shdr->sh_size, + (long int) ((2 + nbucket + nchain) * shdr->sh_entsize)); + + if (symshdr != NULL) + { + size_t symsize = symshdr->sh_size / symshdr->sh_entsize; + size_t cnt; + + if (nchain < symshdr->sh_size / symshdr->sh_entsize) + ERROR (gettext ("section [%2d] '%s': chain array not large enough\n"), + idx, section_name (ebl, idx)); + + for (cnt = 2; cnt < 2 + nbucket; ++cnt) + if (((Elf32_Word *) data->d_buf)[cnt] >= symsize) + ERROR (gettext ("\ +section [%2d] '%s': hash bucket reference %zu out of bounds\n"), + idx, section_name (ebl, idx), cnt - 2); + + for (; cnt < 2 + nbucket + nchain; ++cnt) + if (((Elf32_Word *) data->d_buf)[cnt] >= symsize) + ERROR (gettext ("\ +section [%2d] '%s': hash chain reference %zu out of bounds\n"), + idx, section_name (ebl, idx), cnt - 2 - nbucket); + } +} + + +static void +check_null (Ebl *ebl, GElf_Shdr *shdr, int idx) +{ +#define TEST(name, extra) \ + if (extra && shdr->sh_##name != 0) \ + ERROR (gettext ("section [%2d] '%s': nonzero sh_%s for NULL section\n"), \ + idx, section_name (ebl, idx), #name) + + TEST (name, 1); + TEST (flags, 1); + TEST (addr, 1); + TEST (offset, 1); + TEST (size, idx != 0); + TEST (link, idx != 0); + TEST (info, 1); + TEST (addralign, 1); + TEST (entsize, 1); +} + + +static void +check_group (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) +{ + if (ehdr->e_type != ET_REL) + { + ERROR (gettext ("\ +section [%2d] '%s': section groups only allowed in relocatable object files\n"), + idx, section_name (ebl, idx)); + return; + } + + /* Check that sh_link is an index of a symbol table. */ + GElf_Shdr symshdr_mem; + GElf_Shdr *symshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), + &symshdr_mem); + if (symshdr == NULL) + ERROR (gettext ("section [%2d] '%s': cannot get symbol table: %s\n"), + idx, section_name (ebl, idx), elf_errmsg (-1)); + else + { + if (symshdr->sh_type != SHT_SYMTAB) + ERROR (gettext ("\ +section [%2d] '%s': section reference in sh_link is no symbol table\n"), + idx, section_name (ebl, idx)); + + if (shdr->sh_info >= symshdr->sh_size / gelf_fsize (ebl->elf, ELF_T_SYM, + 1, EV_CURRENT)) + ERROR (gettext ("\ +section [%2d] '%s': invalid symbol index in sh_info\n"), + idx, section_name (ebl, idx)); + + if (shdr->sh_flags != 0) + ERROR (gettext ("section [%2d] '%s': sh_flags not zero\n"), + idx, section_name (ebl, idx)); + + if (be_strict + && shdr->sh_entsize != elf32_fsize (ELF_T_WORD, 1, EV_CURRENT)) + ERROR (gettext ("section [%2d] '%s': sh_flags not set correctly\n"), + idx, section_name (ebl, idx)); + } + + Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); + if (data == NULL) + ERROR (gettext ("section [%2d] '%s': cannot get data: %s\n"), + idx, section_name (ebl, idx), elf_errmsg (-1)); + else + { + size_t elsize = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT); + size_t cnt; + Elf32_Word val; + + if (data->d_size % elsize != 0) + ERROR (gettext ("\ +section [%2d] '%s': section size not multiple of sizeof(Elf32_Word)\n"), + idx, section_name (ebl, idx)); + + if (data->d_size < elsize) + ERROR (gettext ("\ +section [%2d] '%s': section group without flags word\n"), + idx, section_name (ebl, idx)); + else if (be_strict) + { + if (data->d_size < 2 * elsize) + ERROR (gettext ("\ +section [%2d] '%s': section group without member\n"), + idx, section_name (ebl, idx)); + else if (data->d_size < 3 * elsize) + ERROR (gettext ("\ +section [%2d] '%s': section group with only one member\n"), + idx, section_name (ebl, idx)); + } + +#if ALLOW_UNALIGNED + val = *((Elf32_Word *) data->d_buf); +#else + memcpy (&val, data->d_buf, elsize); +#endif + if ((val & ~GRP_COMDAT) != 0) + ERROR (gettext ("section [%2d] '%s': unknown section group flags\n"), + idx, section_name (ebl, idx)); + + for (cnt = elsize; cnt < data->d_size; cnt += elsize) + { +#if ALLOW_UNALIGNED + val = *((Elf32_Word *) ((char *) data->d_buf + cnt)); +#else + memcpy (&val, (char *) data->d_buf + cnt, elsize); +#endif + + if (val > shnum) + ERROR (gettext ("\ +section [%2d] '%s': section index %Zu out of range\n"), + idx, section_name (ebl, idx), cnt / elsize); + else + { + GElf_Shdr refshdr_mem; + GElf_Shdr *refshdr; + + refshdr = gelf_getshdr (elf_getscn (ebl->elf, val), + &refshdr_mem); + if (refshdr == NULL) + ERROR (gettext ("\ +section [%2d] '%s': cannot get section header for element %zu: %s\n"), + idx, section_name (ebl, idx), cnt / elsize, + elf_errmsg (-1)); + else + { + if (refshdr->sh_type == SHT_GROUP) + ERROR (gettext ("\ +section [%2d] '%s': section group contains another group [%2d] '%s'\n"), + idx, section_name (ebl, idx), + val, section_name (ebl, val)); + + if ((refshdr->sh_flags & SHF_GROUP) == 0) + ERROR (gettext ("\ +section [%2d] '%s': element %Zu references section [%2d] '%s' without SHF_GROUP flag set\n"), + idx, section_name (ebl, idx), cnt / elsize, + val, section_name (ebl, val)); + } + + if (++scnref[val] == 2) + ERROR (gettext ("\ +section [%2d] '%s' is contained in more than one section group\n"), + val, section_name (ebl, val)); + } + } + } +} + + +static bool has_loadable_segment; +static bool has_interp_segment; + +static const struct +{ + const char *name; + size_t namelen; + GElf_Word type; + enum { unused, exact, atleast } attrflag; + GElf_Word attr; + GElf_Word attr2; +} special_sections[] = + { + /* See figure 4-14 in the gABI. */ + { ".bss", 5, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".comment", 8, SHT_PROGBITS, exact, 0, 0 }, + { ".data", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".data1", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".debug", 7, SHT_PROGBITS, exact, 0, 0 }, + { ".dynamic", 9, SHT_DYNAMIC, atleast, SHF_ALLOC, SHF_WRITE }, + { ".dynstr", 8, SHT_STRTAB, exact, SHF_ALLOC, 0 }, + { ".dynsym", 8, SHT_DYNSYM, exact, SHF_ALLOC, 0 }, + { ".fini", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 }, + { ".fini_array", 12, SHT_FINI_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".got", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more info? + { ".hash", 6, SHT_HASH, exact, SHF_ALLOC, 0 }, + { ".init", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 }, + { ".init_array", 12, SHT_INIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".interp", 8, SHT_PROGBITS, atleast, 0, SHF_ALLOC }, // XXX more tests? + { ".line", 6, SHT_PROGBITS, exact, 0, 0 }, + { ".note", 6, SHT_NOTE, exact, 0, 0 }, + { ".plt", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more tests + { ".preinit_array", 15, SHT_PREINIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".rela", 5, SHT_RELA, atleast, 0, SHF_ALLOC }, // XXX more tests + { ".rel", 4, SHT_REL, atleast, 0, SHF_ALLOC }, // XXX more tests + { ".rodata", 8, SHT_PROGBITS, exact, SHF_ALLOC, 0 }, + { ".rodata1", 9, SHT_PROGBITS, exact, SHF_ALLOC, 0 }, + { ".shstrtab", 10, SHT_STRTAB, exact, 0, 0 }, + { ".strtab", 8, SHT_STRTAB, atleast, 0, SHF_ALLOC }, // XXX more tests + { ".symtab", 8, SHT_SYMTAB, atleast, 0, SHF_ALLOC }, // XXX more tests + { ".symtab_shndx", 14, SHT_SYMTAB_SHNDX, atleast, 0, SHF_ALLOC }, // XXX more tests + { ".tbss", 6, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, + { ".tdata", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, + { ".tdata1", 8, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, + { ".text", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 } + }; +#define nspecial_sections \ + (sizeof (special_sections) / sizeof (special_sections[0])) + + +static const char * +section_flags_string (GElf_Word flags, char *buf, size_t len) +{ + static const struct + { + GElf_Word flag; + const char *name; + } known_flags[] = + { +#define NEWFLAG(name) { SHF_##name, #name } + NEWFLAG (WRITE), + NEWFLAG (ALLOC), + NEWFLAG (EXECINSTR), + NEWFLAG (MERGE), + NEWFLAG (STRINGS), + NEWFLAG (INFO_LINK), + NEWFLAG (LINK_ORDER), + NEWFLAG (OS_NONCONFORMING), + NEWFLAG (GROUP), + NEWFLAG (TLS) + }; +#undef NEWFLAG + const size_t nknown_flags = sizeof (known_flags) / sizeof (known_flags[0]); + + char *cp = buf; + size_t cnt; + + for (cnt = 0; cnt < nknown_flags; ++cnt) + if (flags & known_flags[cnt].flag) + { + if (cp != buf && len > 1) + { + *cp++ = '|'; + --len; + } + + size_t ncopy = MIN (len - 1, strlen (known_flags[cnt].name)); + cp = mempcpy (cp, known_flags[cnt].name, ncopy); + len -= ncopy; + + flags ^= known_flags[cnt].flag; + } + + if (flags != 0 || cp == buf) + snprintf (cp, len - 1, "%" PRIx64, (uint64_t) flags); + + *cp = '\0'; + + return buf; +} + + +static void +check_versym (Ebl *ebl, GElf_Shdr *shdr, int idx) +{ + /* The number of elements in the version symbol table must be the + same as the number of symbols. */ + GElf_Shdr symshdr_mem; + GElf_Shdr *symshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), + &symshdr_mem); + if (symshdr == NULL) + /* The error has already been reported. */ + return; + + if (symshdr->sh_type != SHT_DYNSYM) + { + ERROR (gettext ("\ +section [%2d] '%s' refers in sh_link to section [%2d] '%s' which is no dynamic symbol table\n"), + idx, section_name (ebl, idx), + shdr->sh_link, section_name (ebl, shdr->sh_link)); + return; + } + + if (shdr->sh_size / shdr->sh_entsize + != symshdr->sh_size / symshdr->sh_entsize) + ERROR (gettext ("\ +section [%2d] '%s' has different number of entries than symbol table [%2d] '%s'\n"), + idx, section_name (ebl, idx), + shdr->sh_link, section_name (ebl, shdr->sh_link)); + + // XXX TODO A lot more tests + // check value of the fields. local symbols must have zero entries. + // nonlocal symbols refer to valid version. Check that version index + // in bound. +} + + +static void +check_sections (Ebl *ebl, GElf_Ehdr *ehdr) +{ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + size_t cnt; + bool dot_interp_section = false; + + if (ehdr->e_shoff == 0) + /* No section header. */ + return; + + /* Allocate array to count references in section groups. */ + scnref = (int *) xcalloc (shnum, sizeof (int)); + + /* Check the zeroth section first. It must not have any contents + and the section header must contain nonzero value at most in the + sh_size and sh_link fields. */ + shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); + if (shdr == NULL) + ERROR (gettext ("cannot get section header of zeroth section\n")); + else + { + if (shdr->sh_name != 0) + ERROR (gettext ("zeroth section has nonzero name\n")); + if (shdr->sh_type != 0) + ERROR (gettext ("zeroth section has nonzero type\n")); + if (shdr->sh_flags != 0) + ERROR (gettext ("zeroth section has nonzero flags\n")); + if (shdr->sh_addr != 0) + ERROR (gettext ("zeroth section has nonzero address\n")); + if (shdr->sh_offset != 0) + ERROR (gettext ("zeroth section has nonzero offset\n")); + if (shdr->sh_info != 0) + ERROR (gettext ("zeroth section has nonzero info field\n")); + if (shdr->sh_addralign != 0) + ERROR (gettext ("zeroth section has nonzero align value\n")); + if (shdr->sh_entsize != 0) + ERROR (gettext ("zeroth section has nonzero entry size value\n")); + + if (shdr->sh_size != 0 && ehdr->e_shnum != 0) + ERROR (gettext ("\ +zeroth section has nonzero size value while ELF header has nonzero shnum value\n")); + + if (shdr->sh_link != 0 && ehdr->e_shstrndx != SHN_XINDEX) + ERROR (gettext ("\ +zeroth section has nonzero link value while ELF header does not signal overflow in shstrndx\n")); + } + + for (cnt = 1; cnt < shnum; ++cnt) + { + Elf_Scn *scn; + + scn = elf_getscn (ebl->elf, cnt); + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + { + ERROR (gettext ("\ +cannot get section header for section [%2zu] '%s': %s\n"), + cnt, section_name (ebl, cnt), elf_errmsg (-1)); + continue; + } + + const char *scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name); + + if (scnname == NULL) + ERROR (gettext ("section [%2zu]: invalid name\n"), cnt); + else + { + /* Check whether it is one of the special sections defined in + the gABI. */ + size_t s; + for (s = 0; s < nspecial_sections; ++s) + if (strncmp (scnname, special_sections[s].name, + special_sections[s].namelen) == 0) + { + char stbuf1[100]; + char stbuf2[100]; + char stbuf3[100]; + + if (shdr->sh_type != special_sections[s].type + && !(is_debuginfo && shdr->sh_type == SHT_NOBITS)) + ERROR (gettext ("\ +section [%2d] '%s' has wrong type: expected %s, is %s\n"), + (int) cnt, scnname, + ebl_section_type_name (ebl, special_sections[s].type, + stbuf1, sizeof (stbuf1)), + ebl_section_type_name (ebl, shdr->sh_type, + stbuf2, sizeof (stbuf2))); + + if (special_sections[s].attrflag == exact) + { + /* Except for the link order and group bit all the + other bits should match exactly. */ + if ((shdr->sh_flags & ~(SHF_LINK_ORDER | SHF_GROUP)) + != special_sections[s].attr) + ERROR (gettext ("\ +section [%2zu] '%s' has wrong flags: expected %s, is %s\n"), + cnt, scnname, + section_flags_string (special_sections[s].attr, + stbuf1, sizeof (stbuf1)), + section_flags_string (shdr->sh_flags + & ~SHF_LINK_ORDER, + stbuf2, sizeof (stbuf2))); + } + else if (special_sections[s].attrflag == atleast) + { + if ((shdr->sh_flags & special_sections[s].attr) + != special_sections[s].attr + || ((shdr->sh_flags & ~(SHF_LINK_ORDER | SHF_GROUP + | special_sections[s].attr + | special_sections[s].attr2)) + != 0)) + ERROR (gettext ("\ +section [%2zu] '%s' has wrong flags: expected %s and possibly %s, is %s\n"), + cnt, scnname, + section_flags_string (special_sections[s].attr, + stbuf1, sizeof (stbuf1)), + section_flags_string (special_sections[s].attr2, + stbuf2, sizeof (stbuf2)), + section_flags_string (shdr->sh_flags + & ~(SHF_LINK_ORDER + | SHF_GROUP), + stbuf3, sizeof (stbuf3))); + } + + if (strcmp (scnname, ".interp") == 0) + { + dot_interp_section = true; + + if (ehdr->e_type == ET_REL) + ERROR (gettext ("\ +section [%2zu] '%s' present in object file\n"), + cnt, scnname); + + if ((shdr->sh_flags & SHF_ALLOC) != 0 + && !has_loadable_segment) + ERROR (gettext ("\ +section [%2zu] '%s' has SHF_ALLOC flag set but there is no loadable segment\n"), + cnt, scnname); + else if ((shdr->sh_flags & SHF_ALLOC) == 0 + && has_loadable_segment) + ERROR (gettext ("\ +section [%2zu] '%s' has SHF_ALLOC flag not set but there are loadable segments\n"), + cnt, scnname); + } + else + { + if (strcmp (scnname, ".symtab_shndx") == 0 + && ehdr->e_type != ET_REL) + ERROR (gettext ("\ +section [%2zu] '%s' is extension section index table in non-object file\n"), + cnt, scnname); + + /* These sections must have the SHF_ALLOC flag set iff + a loadable segment is available. + + .relxxx + .strtab + .symtab + .symtab_shndx + + Check that if there is a reference from the + loaded section these sections also have the + ALLOC flag set. */ +#if 0 + // XXX TODO + if ((shdr->sh_flags & SHF_ALLOC) != 0 + && !has_loadable_segment) + ERROR (gettext ("\ +section [%2zu] '%s' has SHF_ALLOC flag set but there is no loadable segment\n"), + cnt, scnname); + else if ((shdr->sh_flags & SHF_ALLOC) == 0 + && has_loadable_segment) + ERROR (gettext ("\ +section [%2zu] '%s' has SHF_ALLOC flag not set but there are loadable segments\n"), + cnt, scnname); +#endif + } + + break; + } + } + + if (shdr->sh_entsize != 0 && shdr->sh_size % shdr->sh_entsize) + ERROR (gettext ("\ +section [%2zu] '%s': size not multiple of entry size\n"), + cnt, section_name (ebl, cnt)); + + if (elf_strptr (ebl->elf, shstrndx, shdr->sh_name) == NULL) + ERROR (gettext ("cannot get section header\n")); + + if (shdr->sh_type >= SHT_NUM + && shdr->sh_type != SHT_GNU_LIBLIST + && shdr->sh_type != SHT_CHECKSUM + && shdr->sh_type != SHT_GNU_verdef + && shdr->sh_type != SHT_GNU_verneed + && shdr->sh_type != SHT_GNU_versym) + ERROR (gettext ("unsupported section type %d\n"), (int) shdr->sh_type); + +#define ALL_SH_FLAGS (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE \ + | SHF_STRINGS | SHF_INFO_LINK | SHF_LINK_ORDER \ + | SHF_OS_NONCONFORMING | SHF_GROUP | SHF_TLS) + if (shdr->sh_flags & ~ALL_SH_FLAGS) + ERROR (gettext ("section [%2zu] '%s' contain unknown flag(s) %d\n"), + cnt, section_name (ebl, cnt), + (int) shdr->sh_flags & ~ALL_SH_FLAGS); + else if (shdr->sh_flags & SHF_TLS) + { + // XXX Correct? + if (shdr->sh_addr != 0 && !gnuld) + ERROR (gettext ("\ +section [%2zu] '%s': thread-local data sections address not zero\n"), + cnt, section_name (ebl, cnt)); + + // XXX TODO more tests!? + } + + if (shdr->sh_link >= shnum) + ERROR (gettext ("\ +section [%2zu] '%s': invalid section reference in link value\n"), + cnt, section_name (ebl, cnt)); + + if (SH_INFO_LINK_P (shdr) && shdr->sh_info >= shnum) + ERROR (gettext ("\ +section [%2zu] '%s': invalid section reference in info value\n"), + cnt, section_name (ebl, cnt)); + + if ((shdr->sh_flags & SHF_MERGE) == 0 + && (shdr->sh_flags & SHF_STRINGS) != 0 + && be_strict) + ERROR (gettext ("\ +section [%2zu] '%s': strings flag set without merge flag\n"), + cnt, section_name (ebl, cnt)); + + if ((shdr->sh_flags & SHF_MERGE) != 0 && shdr->sh_entsize == 0) + ERROR (gettext ("\ +section [%2zu] '%s': merge flag set but entry size is zero\n"), + cnt, section_name (ebl, cnt)); + + if (shdr->sh_flags & SHF_GROUP) + check_scn_group (ebl, cnt); + + if (ehdr->e_type != ET_REL && (shdr->sh_flags & SHF_ALLOC) != 0) + { + /* Make sure the section is contained in a loaded segment + and that the initialization part matches NOBITS sections. */ + int pcnt; + GElf_Phdr phdr_mem; + GElf_Phdr *phdr; + + for (pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt) + if ((phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem)) != NULL + && ((phdr->p_type == PT_LOAD + && (shdr->sh_flags & SHF_TLS) == 0) + || (phdr->p_type == PT_TLS + && (shdr->sh_flags & SHF_TLS) != 0)) + && phdr->p_offset <= shdr->sh_offset + && phdr->p_offset + phdr->p_memsz > shdr->sh_offset) + { + /* Found the segment. */ + if (phdr->p_offset + phdr->p_memsz + < shdr->sh_offset + shdr->sh_size) + ERROR (gettext ("\ +section [%2zu] '%s' not fully contained in segment of program header entry %d\n"), + cnt, section_name (ebl, cnt), pcnt); + + if (shdr->sh_type == SHT_NOBITS) + { + if (shdr->sh_offset < phdr->p_offset + phdr->p_filesz + && !is_debuginfo) + ERROR (gettext ("\ +section [%2zu] '%s' has type NOBITS but is read from the file in segment of program header entry %d\n"), + cnt, section_name (ebl, cnt), pcnt); + } + else + { + if (shdr->sh_offset >= phdr->p_offset + phdr->p_filesz) + ERROR (gettext ("\ +section [%2zu] '%s' has not type NOBITS but is not read from the file in segment of program header entry %d\n"), + cnt, section_name (ebl, cnt), pcnt); + } + + break; + } + + if (pcnt == ehdr->e_phnum) + ERROR (gettext ("\ +section [%2zu] '%s': alloc flag set but section not in any loaded segment\n"), + cnt, section_name (ebl, cnt)); + } + + if (cnt == shstrndx && shdr->sh_type != SHT_STRTAB) + ERROR (gettext ("\ +section [%2zu] '%s': ELF header says this is the section header string table but type is not SHT_TYPE\n"), + cnt, section_name (ebl, cnt)); + + switch (shdr->sh_type) + { + case SHT_SYMTAB: + case SHT_DYNSYM: + check_symtab (ebl, ehdr, cnt); + break; + + case SHT_RELA: + check_rela (ebl, ehdr, cnt); + break; + + case SHT_REL: + check_rel (ebl, ehdr, cnt); + break; + + case SHT_DYNAMIC: + check_dynamic (ebl, cnt); + break; + + case SHT_SYMTAB_SHNDX: + check_symtab_shndx (ebl, cnt); + break; + + case SHT_HASH: + check_hash (ebl, cnt); + break; + + case SHT_NULL: + check_null (ebl, shdr, cnt); + break; + + case SHT_GROUP: + check_group (ebl, ehdr, shdr, cnt); + break; + + case SHT_GNU_versym: + check_versym (ebl, shdr, cnt); + break; + + default: + /* Nothing. */ + break; + } + } + + if (has_interp_segment && !dot_interp_section) + ERROR (gettext ("INTERP program header entry but no .interp section\n")); + + free (scnref); +} + + +static void +check_note (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Phdr *phdr, int cnt) +{ + if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL + && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) + ERROR (gettext ("\ +phdr[%d]: no note entries defined for the type of file\n"), + cnt); + + if (is_debuginfo) + /* The p_offset values in a separate debug file are bogus. */ + return; + + char *notemem = gelf_rawchunk (ebl->elf, phdr->p_offset, phdr->p_filesz); + + /* ELF64 files often use note section entries in the 32-bit format. + The p_align field is set to 8 in case the 64-bit format is used. + In case the p_align value is 0 or 4 the 32-bit format is + used. */ + GElf_Xword align = phdr->p_align == 0 || phdr->p_align == 4 ? 4 : 8; +#define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1)) + + GElf_Xword idx = 0; + while (idx < phdr->p_filesz) + { + uint64_t namesz; + uint64_t descsz; + uint64_t type; + uint32_t namesz32; + uint32_t descsz32; + + if (align == 4) + { + uint32_t *ptr = (uint32_t *) (notemem + idx); + + if ((__BYTE_ORDER == __LITTLE_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + || (__BYTE_ORDER == __BIG_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) + { + namesz32 = namesz = bswap_32 (*ptr); + ++ptr; + descsz32 = descsz = bswap_32 (*ptr); + ++ptr; + type = bswap_32 (*ptr); + } + else + { + namesz32 = namesz = *ptr++; + descsz32 = descsz = *ptr++; + type = *ptr; + } + } + else + { + uint64_t *ptr = (uint64_t *) (notemem + idx); + uint32_t *ptr32 = (uint32_t *) (notemem + idx); + + if ((__BYTE_ORDER == __LITTLE_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + || (__BYTE_ORDER == __BIG_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) + { + namesz = bswap_64 (*ptr); + ++ptr; + descsz = bswap_64 (*ptr); + ++ptr; + type = bswap_64 (*ptr); + + namesz32 = bswap_32 (*ptr32); + ++ptr32; + descsz32 = bswap_32 (*ptr32); + } + else + { + namesz = *ptr++; + descsz = *ptr++; + type = *ptr; + + namesz32 = *ptr32++; + descsz32 = *ptr32; + } + } + + if (idx + 3 * align > phdr->p_filesz + || (idx + 3 * align + ALIGNED_LEN (namesz) + ALIGNED_LEN (descsz) + > phdr->p_filesz)) + { + if (ehdr->e_ident[EI_CLASS] == ELFCLASS64 + && idx + 3 * 4 <= phdr->p_filesz + && (idx + 3 * 4 + ALIGNED_LEN (namesz32) + ALIGNED_LEN (descsz32) + <= phdr->p_filesz)) + ERROR (gettext ("\ +phdr[%d]: note entries probably in form of a 32-bit ELF file\n"), cnt); + else + ERROR (gettext ("phdr[%d]: extra %zu bytes after last note\n"), + cnt, (size_t) (phdr->p_filesz - idx)); + break; + } + + /* Make sure it is one of the note types we know about. */ + if (ehdr->e_type == ET_CORE) + { + switch (type) + { + case NT_PRSTATUS: + case NT_FPREGSET: + case NT_PRPSINFO: + case NT_TASKSTRUCT: /* NT_PRXREG on Solaris. */ + case NT_PLATFORM: + case NT_AUXV: + case NT_GWINDOWS: + case NT_ASRS: + case NT_PSTATUS: + case NT_PSINFO: + case NT_PRCRED: + case NT_UTSNAME: + case NT_LWPSTATUS: + case NT_LWPSINFO: + case NT_PRFPXREG: + /* Known type. */ + break; + + default: + ERROR (gettext ("\ +phdr[%d]: unknown core file note type %" PRIu64 " at offset %" PRIu64 "\n"), + cnt, type, idx); + } + } + else + { + if (type != NT_VERSION) + ERROR (gettext ("\ +phdr[%d]: unknown object file note type %" PRIu64 " at offset %" PRIu64 "\n"), + cnt, type, idx); + } + + /* Move to the next entry. */ + idx += 3 * align + ALIGNED_LEN (namesz) + ALIGNED_LEN (descsz); + + } + + gelf_freechunk (ebl->elf, notemem); +} + + +static void +check_program_header (Ebl *ebl, GElf_Ehdr *ehdr) +{ + if (ehdr->e_phoff == 0) + return; + + if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN + && ehdr->e_type != ET_CORE) + ERROR (gettext ("\ +only executables, shared objects, and core files can have program headers\n")); + + int num_pt_interp = 0; + int num_pt_tls = 0; + int num_pt_relro = 0; + + for (int cnt = 0; cnt < ehdr->e_phnum; ++cnt) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr; + + phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem); + if (phdr == NULL) + { + ERROR (gettext ("cannot get program header entry %d: %s\n"), + cnt, elf_errmsg (-1)); + continue; + } + + if (phdr->p_type >= PT_NUM && phdr->p_type != PT_GNU_EH_FRAME + && phdr->p_type != PT_GNU_STACK && phdr->p_type != PT_GNU_RELRO) + ERROR (gettext ("\ +program header entry %d: unknown program header entry type\n"), + cnt); + + if (phdr->p_type == PT_LOAD) + has_loadable_segment = true; + else if (phdr->p_type == PT_INTERP) + { + if (++num_pt_interp != 1) + { + if (num_pt_interp == 2) + ERROR (gettext ("\ +more than one INTERP entry in program header\n")); + } + has_interp_segment = true; + } + else if (phdr->p_type == PT_TLS) + { + if (++num_pt_tls == 2) + ERROR (gettext ("more than one TLS entry in program header\n")); + } + else if (phdr->p_type == PT_NOTE) + check_note (ebl, ehdr, phdr, cnt); + else if (phdr->p_type == PT_DYNAMIC + && ehdr->e_type == ET_EXEC && ! has_interp_segment) + ERROR (gettext ("static executable cannot have dynamic sections\n")); + else if (phdr->p_type == PT_GNU_RELRO) + { + if (++num_pt_relro == 2) + ERROR (gettext ("\ +more than one GNU_RELRO entry in program header\n")); + else + { + /* Check that the region is in a writable segment. */ + int inner; + for (inner = 0; inner < ehdr->e_phnum; ++inner) + { + GElf_Phdr phdr2_mem; + GElf_Phdr *phdr2; + + phdr2 = gelf_getphdr (ebl->elf, inner, &phdr2_mem); + if (phdr2 == NULL) + continue; + + if (phdr2->p_type == PT_LOAD + && phdr->p_vaddr >= phdr2->p_vaddr + && (phdr->p_vaddr + phdr->p_memsz + <= phdr2->p_vaddr + phdr2->p_memsz)) + { + if ((phdr2->p_flags & PF_W) == 0) + ERROR (gettext ("\ +loadable segment GNU_RELRO applies to is not writable\n")); + if ((phdr2->p_flags & PF_X) != 0) + ERROR (gettext ("\ +loadable segment GNU_RELRO applies to is executable\n")); + break; + } + } + + if (inner >= ehdr->e_phnum) + ERROR (gettext ("\ +GNU_RELRO segment not contained in a loaded segment\n")); + } + } + + if (phdr->p_filesz > phdr->p_memsz) + ERROR (gettext ("\ +program header entry %d: file size greater than memory size\n"), + cnt); + + if (phdr->p_align > 1) + { + if (!powerof2 (phdr->p_align)) + ERROR (gettext ("\ +program header entry %d: alignment not a power of 2\n"), cnt); + else if ((phdr->p_vaddr - phdr->p_offset) % phdr->p_align != 0) + ERROR (gettext ("\ +program header entry %d: file offset and virtual address not module of alignment\n"), cnt); + } + } +} + + +/* Process one file. */ +static void +process_elf_file (Elf *elf, const char *prefix, const char *suffix, + const char *fname, size_t size, bool only_one) +{ + /* Reset variables. */ + ndynamic = 0; + + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + Ebl *ebl; + + /* Print the file name. */ + if (!only_one) + { + if (prefix != NULL) + printf ("\n%s(%s)%s:\n", prefix, fname, suffix); + else + printf ("\n%s:\n", fname); + } + + if (ehdr == NULL) + { + ERROR (gettext ("cannot read ELF header: %s\n"), elf_errmsg (-1)); + return; + } + + ebl = ebl_openbackend (elf); + /* If there is no appropriate backend library we cannot test + architecture and OS specific features. Any encountered extension + is an error. */ + + /* Go straight by the gABI, check all the parts in turn. */ + check_elf_header (ebl, ehdr, size); + + /* Check the program header. */ + check_program_header (ebl, ehdr); + + /* Next the section headers. It is OK if there are no section + headers at all. */ + check_sections (ebl, ehdr); + + /* Free the resources. */ + ebl_closebackend (ebl); +} diff --git a/src/findtextrel.c b/src/findtextrel.c new file mode 100644 index 00000000..662fe95c --- /dev/null +++ b/src/findtextrel.c @@ -0,0 +1,596 @@ +/* Locate source files or functions which caused text relocations. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct segments +{ + GElf_Addr from; + GElf_Addr to; +}; + + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Bug report address. */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + +/* Values for the parameters which have no short form. */ +#define OPT_DEBUGINFO 0x100 + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { NULL, 0, NULL, 0, N_("Input Selection:"), 0 }, + { "root", 'r', "PATH", 0, N_("Prepend PATH to all file names"), 0 }, + { "debuginfo", OPT_DEBUGINFO, "PATH", 0, + N_("Use PATH as root of debuginfo hierarchy"), 0 }, + + { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Short description of program. */ +static const char doc[] = N_("\ +Locate source of text relocations in FILEs (a.out by default)."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("[FILE...]"); + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, NULL, NULL +}; + + +/* Print symbols in file named FNAME. */ +static int process_file (const char *fname, bool more_than_one); + +/* Check for text relocations in the given file. The segment + information is known. */ +static void check_rel (size_t nsegments, struct segments segments[nsegments], + GElf_Addr addr, Elf *elf, Elf_Scn *symscn, Dwarf *dw, + const char *fname, bool more_than_one, + void **knownsrcs); + + + +/* User-provided root directory. */ +static const char *rootdir = "/"; + +/* Root of debuginfo directory hierarchy. */ +static const char *debuginfo_root; + + +int +main (int argc, char *argv[]) +{ + int remaining; + int result = 0; + + /* Set locale. */ + (void) setlocale (LC_ALL, ""); + + /* Make sure the message catalog can be found. */ + (void) bindtextdomain (PACKAGE, LOCALEDIR); + + /* Initialize the message catalog. */ + (void) textdomain (PACKAGE); + + /* Parse and process arguments. */ + (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + /* Tell the library which version we are expecting. */ + elf_version (EV_CURRENT); + + /* If the user has not specified the root directory for the + debuginfo hierarchy, we have to determine it ourselves. */ + if (debuginfo_root == NULL) + { + // XXX The runtime should provide this information. +#if defined __ia64__ || defined __alpha__ + debuginfo_root = "/usr/lib/debug"; +#else + debuginfo_root = (sizeof (long int) == 4 + ? "/usr/lib/debug" : "/usr/lib64/debug"); +#endif + } + + if (remaining == argc) + result = process_file ("a.out", false); + else + { + /* Process all the remaining files. */ + const bool more_than_one = remaining + 1 < argc; + + do + result |= process_file (argv[remaining], more_than_one); + while (++remaining < argc); + } + + return result; +} + + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) +{ + fprintf (stream, "findtextrel (%s) %s\n", PACKAGE_NAME, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Red Hat, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2005"); + fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case 'r': + rootdir = arg; + break; + + case OPT_DEBUGINFO: + debuginfo_root = arg; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +static void +noop (void *arg __attribute__ ((unused))) +{ +} + + +static int +process_file (const char *fname, bool more_than_one) +{ + int result = 0; + void *knownsrcs = NULL; + + size_t fname_len = strlen (fname); + size_t rootdir_len = strlen (rootdir); + const char *real_fname = fname; + if (fname[0] == '/' && (rootdir[0] != '/' || rootdir[1] != '\0')) + { + /* Prepend the user-provided root directory. */ + char *new_fname = alloca (rootdir_len + fname_len + 2); + *((char *) mempcpy (stpcpy (mempcpy (new_fname, rootdir, rootdir_len), + "/"), + fname, fname_len)) = '\0'; + real_fname = new_fname; + } + + int fd = open64 (real_fname, O_RDONLY); + if (fd == -1) + { + error (0, errno, gettext ("cannot open '%s'"), fname); + return 1; + } + + Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) + { + error (0, 0, gettext ("cannot create ELF descriptor for '%s': %s"), + fname, elf_errmsg (-1)); + goto err_close; + } + + /* Make sure the file is a DSO. */ + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + error (0, 0, gettext ("cannot get ELF header '%s': %s"), + fname, elf_errmsg (-1)); + err_elf_close: + elf_end (elf); + err_close: + close (fd); + return 1; + } + + if (ehdr->e_type != ET_DYN) + { + error (0, 0, gettext ("'%s' is not a DSO or PIE"), fname); + goto err_elf_close; + } + + /* Determine whether the DSO has text relocations at all and locate + the symbol table. */ + Elf_Scn *symscn = NULL; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + /* Handle the section if it is a symbol table. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr == NULL) + { + error (0, 0, + gettext ("getting get section header of section %zu: %s"), + elf_ndxscn (scn), elf_errmsg (-1)); + goto err_elf_close; + } + + if (shdr->sh_type == SHT_DYNAMIC) + { + Elf_Data *data = elf_getdata (scn, NULL); + + for (size_t cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; + ++cnt) + { + GElf_Dyn dynmem; + GElf_Dyn *dyn; + + dyn = gelf_getdyn (data, cnt, &dynmem); + if (dyn == NULL) + { + error (0, 0, gettext ("cannot read dynamic section: %s"), + elf_errmsg (-1)); + goto err_elf_close; + } + + if (dyn->d_tag == DT_TEXTREL + || (dyn->d_tag == DT_FLAGS + && (dyn->d_un.d_val & DF_TEXTREL) != 0)) + goto have_textrel; + } + } + else if (shdr->sh_type == SHT_SYMTAB) + symscn = scn; + } + + error (0, 0, gettext ("no text relocations reported in '%s'"), fname); + return 1; + + have_textrel:; + int fd2 = -1; + Elf *elf2 = NULL; + /* Get the address ranges for the loaded segments. */ + size_t nsegments_max = 10; + size_t nsegments = 0; + struct segments *segments + = (struct segments *) malloc (nsegments_max * sizeof (segments[0])); + if (segments == NULL) + error (1, errno, gettext ("while reading ELF file")); + + for (int i = 0; i < ehdr->e_phnum; ++i) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); + if (phdr == NULL) + { + error (0, 0, + gettext ("cannot get program header index at offset %d: %s"), + i, elf_errmsg (-1)); + result = 1; + goto next; + } + + if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_W) == 0) + { + if (nsegments == nsegments_max) + { + nsegments_max *= 2; + segments + = (struct segments *) realloc (segments, + nsegments_max + * sizeof (segments[0])); + if (segments == NULL) + { + error (0, 0, gettext ("\ +cannot get program header index at offset %d: %s"), + i, elf_errmsg (-1)); + result = 1; + goto next; + } + } + + segments[nsegments].from = phdr->p_vaddr; + segments[nsegments].to = phdr->p_vaddr + phdr->p_memsz; + ++nsegments; + } + } + + if (nsegments > 0) + { + + Dwarf *dw = dwarf_begin_elf (elf, DWARF_C_READ, NULL); + /* Look for debuginfo files if the information is not the in + opened file itself. This makes only sense if the input file + is specified with an absolute path. */ + if (dw == NULL && fname[0] == '/') + { + size_t debuginfo_rootlen = strlen (debuginfo_root); + char *difname = (char *) alloca (rootdir_len + debuginfo_rootlen + + fname_len + 8); + strcpy (mempcpy (stpcpy (mempcpy (mempcpy (difname, rootdir, + rootdir_len), + debuginfo_root, + debuginfo_rootlen), + "/"), + fname, fname_len), + ".debug"); + + fd2 = open64 (difname, O_RDONLY); + if (fd2 != -1 + && (elf2 = elf_begin (fd2, ELF_C_READ_MMAP, NULL)) != NULL) + dw = dwarf_begin_elf (elf2, DWARF_C_READ, NULL); + } + + /* Look at all relocations and determine which modify + write-protected segments. */ + scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + /* Handle the section if it is a symbol table. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr == NULL) + { + error (0, 0, + gettext ("cannot get section header of section %Zu: %s"), + elf_ndxscn (scn), elf_errmsg (-1)); + result = 1; + goto next; + } + + if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) + && symscn == NULL) + { + symscn = elf_getscn (elf, shdr->sh_link); + if (symscn == NULL) + { + error (0, 0, gettext ("\ +cannot get symbol table section %zu in '%s': %s"), + (size_t) shdr->sh_link, fname, elf_errmsg (-1)); + result = 1; + goto next; + } + } + + if (shdr->sh_type == SHT_REL) + { + Elf_Data *data = elf_getdata (scn, NULL); + + for (int cnt = 0; + (size_t) cnt < shdr->sh_size / shdr->sh_entsize; + ++cnt) + { + GElf_Rel rel_mem; + GElf_Rel *rel = gelf_getrel (data, cnt, &rel_mem); + if (rel == NULL) + { + error (0, 0, gettext ("\ +cannot get relocation at index %d in section %zu in '%s': %s"), + cnt, elf_ndxscn (scn), fname, elf_errmsg (-1)); + result = 1; + goto next; + } + + check_rel (nsegments, segments, rel->r_offset, elf, + symscn, dw, fname, more_than_one, &knownsrcs); + } + } + else if (shdr->sh_type == SHT_RELA) + { + Elf_Data *data = elf_getdata (scn, NULL); + + for (int cnt = 0; + (size_t) cnt < shdr->sh_size / shdr->sh_entsize; + ++cnt) + { + GElf_Rela rela_mem; + GElf_Rela *rela = gelf_getrela (data, cnt, &rela_mem); + if (rela == NULL) + { + error (0, 0, gettext ("\ +cannot get relocation at index %d in section %zu in '%s': %s"), + cnt, elf_ndxscn (scn), fname, elf_errmsg (-1)); + result = 1; + goto next; + } + + check_rel (nsegments, segments, rela->r_offset, elf, + symscn, dw, fname, more_than_one, &knownsrcs); + } + } + } + + dwarf_end (dw); + } + + next: + elf_end (elf); + elf_end (elf2); + close (fd); + if (fd2 != -1) + close (fd2); + + tdestroy (knownsrcs, noop); + + return result; +} + + +static int +ptrcompare (const void *p1, const void *p2) +{ + if ((uintptr_t) p1 < (uintptr_t) p2) + return -1; + if ((uintptr_t) p1 > (uintptr_t) p2) + return 1; + return 0; +} + + +static void +check_rel (size_t nsegments, struct segments segments[nsegments], + GElf_Addr addr, Elf *elf, Elf_Scn *symscn, Dwarf *dw, + const char *fname, bool more_than_one, void **knownsrcs) +{ + for (size_t cnt = 0; cnt < nsegments; ++cnt) + if (segments[cnt].from <= addr && segments[cnt].to > addr) + { + Dwarf_Die die_mem; + Dwarf_Die *die; + Dwarf_Line *line; + const char *src; + + if (more_than_one) + printf ("%s: ", fname); + + if ((die = dwarf_addrdie (dw, addr, &die_mem)) != NULL + && (line = dwarf_getsrc_die (die, addr)) != NULL + && (src = dwarf_linesrc (line, NULL, NULL)) != NULL) + { + /* There can be more than one relocation against one file. + Try to avoid multiple messages. And yes, the code uses + pointer comparison. */ + if (tfind (src, knownsrcs, ptrcompare) == NULL) + { + printf (gettext ("%s not compiled with -fpic/-fPIC\n"), src); + tsearch (src, knownsrcs, ptrcompare); + } + return; + } + else + { + /* At least look at the symbol table to see which function + the modified address is in. */ + Elf_Data *symdata = elf_getdata (symscn, NULL); + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem); + if (shdr != NULL) + { + GElf_Addr lowaddr = 0; + int lowidx = -1; + GElf_Addr highaddr = ~0ul; + int highidx = -1; + GElf_Sym sym_mem; + GElf_Sym *sym; + + for (int i = 0; (size_t) i < shdr->sh_size / shdr->sh_entsize; + ++i) + { + sym = gelf_getsym (symdata, i, &sym_mem); + if (sym == NULL) + continue; + + if (sym->st_value < addr && sym->st_value > lowaddr) + { + lowaddr = sym->st_value; + lowidx = i; + } + if (sym->st_value > addr && sym->st_value < highaddr) + { + highaddr = sym->st_value; + highidx = i; + } + } + + if (lowidx != -1) + { + sym = gelf_getsym (symdata, lowidx, &sym_mem); + assert (sym != NULL); + + const char *lowstr = elf_strptr (elf, shdr->sh_link, + sym->st_name); + + if (sym->st_value + sym->st_size > addr) + { + /* It is this function. */ + if (tfind (lowstr, knownsrcs, ptrcompare) == NULL) + { + printf (gettext ("\ +the file containing the function '%s' is not compiled with -fpic/-fPIC\n"), + lowstr); + tsearch (lowstr, knownsrcs, ptrcompare); + } + } + else if (highidx == -1) + printf (gettext ("\ +the file containing the function '%s' might not be compiled with -fpic/-fPIC\n"), + lowstr); + else + { + sym = gelf_getsym (symdata, highidx, &sym_mem); + assert (sym != NULL); + + printf (gettext ("\ +either the file containing the function '%s' or the file containing the function '%s' is not compiled with -fpic/-fPIC\n"), + lowstr, elf_strptr (elf, shdr->sh_link, + sym->st_name)); + } + return; + } + else if (highidx != -1) + { + sym = gelf_getsym (symdata, highidx, &sym_mem); + assert (sym != NULL); + + printf (gettext ("\ +the file containing the function '%s' might not be compiled with -fpic/-fPIC\n"), + elf_strptr (elf, shdr->sh_link, sym->st_name)); + return; + } + } + } + + printf (gettext ("\ +a relocation modifies memory at offset %llu in a write-protected segment\n"), + (unsigned long long int) addr); + break; + } +} diff --git a/src/i386_ld.c b/src/i386_ld.c new file mode 100644 index 00000000..ee1cb966 --- /dev/null +++ b/src/i386_ld.c @@ -0,0 +1,894 @@ +/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +// XXX For debugging +#include + +#include +#include "ld.h" +#include "list.h" +/* x86 is little endian. */ +#define UNALIGNED_ACCESS_CLASS LITTLE_ENDIAN +#include "unaligned.h" +#include "xelf.h" + + +/* The old callbacks. */ +static int (*old_open_outfile) (struct ld_state *, int, int, int); + + +static int +elf_i386_open_outfile (struct ld_state *statep, + int machine __attribute__ ((unused)), + int klass __attribute__ ((unused)), + int data __attribute__ ((unused))) +{ + /* This backend only handles 32-bit object files. */ + /* XXX For now just use the generic backend. */ + return old_open_outfile (statep, EM_386, ELFCLASS32, ELFDATA2LSB); +} + + +/* Process relocations for the output in a relocatable file. This + only means adjusting offset and symbol indices. */ +static void +elf_i386_relocate_section (struct ld_state *statep __attribute__ ((unused)), + Elf_Scn *outscn, struct scninfo *firstp, + const Elf32_Word *dblindirect) +{ + struct scninfo *runp; + Elf_Data *data; + + /* Iterate over all the input sections. Appropriate data buffers in the + output sections were already created. I get them iteratively, too. */ + runp = firstp; + data = NULL; + do + { + Elf_Data *reltgtdata; + Elf_Data *insymdata; + Elf_Data *inxndxdata = NULL; + size_t maxcnt; + size_t cnt; + const Elf32_Word *symindirect; + struct symbol **symref; + struct usedfiles *file = runp->fileinfo; + XElf_Shdr *shdr = &SCNINFO_SHDR (runp->shdr); + + /* Get the output section data buffer for this input section. */ + data = elf_getdata (outscn, data); + assert (data != NULL); + + /* Get the data for section in the input file this relocation + section is relocating. Since these buffers are reused in the + output modifying these buffers has the correct result. */ + reltgtdata = elf_getdata (file->scninfo[shdr->sh_info].scn, NULL); + + /* Get the data for the input section symbol table for this + relocation section. */ + insymdata = elf_getdata (file->scninfo[shdr->sh_link].scn, NULL); + assert (insymdata != NULL); + + /* And the extended section index table. */ + inxndxdata = runp->fileinfo->xndxdata; + + /* Number of relocations. */ + maxcnt = shdr->sh_size / shdr->sh_entsize; + + /* Array directing local symbol table offsets to output symbol + table offsets. */ + symindirect = file->symindirect; + + /* References to the symbol records. */ + symref = file->symref; + + /* Iterate over all the relocations in the section. */ + for (cnt = 0; cnt < maxcnt; ++cnt) + { + XElf_Rel_vardef (rel); + Elf32_Word si; + XElf_Sym_vardef (sym); + Elf32_Word xndx; + + /* Get the relocation data itself. x86 uses Rel + relocations. In case we have to handle Rela as well the + whole loop probably should be duplicated. */ + xelf_getrel (data, cnt, rel); + assert (rel != NULL); + + /* Compute the symbol index in the output file. */ + si = symindirect[XELF_R_SYM (rel->r_info)]; + if (si == 0) + { + /* This happens if the symbol is locally undefined or + superceded by some other definition. */ + assert (symref[XELF_R_SYM (rel->r_info)] != NULL); + si = symref[XELF_R_SYM (rel->r_info)]->outsymidx; + } + /* Take reordering performed to sort the symbol table into + account. */ + si = dblindirect[si]; + + /* Get the symbol table entry. */ + xelf_getsymshndx (insymdata, inxndxdata, XELF_R_SYM (rel->r_info), + sym, xndx); + if (sym->st_shndx != SHN_XINDEX) + xndx = sym->st_shndx; + assert (xndx < SHN_LORESERVE || xndx > SHN_HIRESERVE); + + /* We fortunately don't have to do much. The relocations + mostly get only updates of the offset. Only is a + relocation referred to a section do we have to do + something. In this case the reference to the sections + has no direct equivalent since the part the input section + contributes need not start at the same offset as in the + input file. Therefore we have to adjust the addend which + in the case of Rel relocations is in the target section + itself. */ + if (XELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + Elf32_Word toadd; + + /* We expect here on R_386_32 relocations. */ + assert (XELF_R_TYPE (rel->r_info) == R_386_32); + + /* Avoid writing to the section memory if this is + effectively a no-op since it might save a + copy-on-write operation. */ + toadd = file->scninfo[xndx].offset; + if (toadd != 0) + add_4ubyte_unaligned (reltgtdata->d_buf + rel->r_offset, + toadd); + } + + /* Adjust the offset for the position of the input section + content in the output section. */ + rel->r_offset += file->scninfo[shdr->sh_info].offset; + + /* And finally adjust the index of the symbol in the output + symbol table. */ + rel->r_info = XELF_R_INFO (si, XELF_R_TYPE (rel->r_info)); + + /* Store the result. */ + (void) xelf_update_rel (data, cnt, rel); + } + + runp = runp->next; + } + while (runp != firstp); +} + + +/* Each PLT entry has 16 bytes. We need one entry as overhead for + the code to set up the call into the runtime relocation. */ +#define PLT_ENTRY_SIZE 16 + +static void +elf_i386_initialize_plt (struct ld_state *statep, Elf_Scn *scn) +{ + Elf_Data *data; + XElf_Shdr_vardef (shdr); + + /* Change the entry size in the section header. */ + xelf_getshdr (scn, shdr); + assert (shdr != NULL); + shdr->sh_entsize = PLT_ENTRY_SIZE; + (void) xelf_update_shdr (scn, shdr); + + data = elf_newdata (scn); + if (data == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot allocate PLT section: %s"), + elf_errmsg (-1)); + + /* We need one special PLT entry (performing the jump to the runtime + relocation routines) and one for each function we call in a DSO. */ + data->d_size = (1 + statep->nplt) * PLT_ENTRY_SIZE; + data->d_buf = xcalloc (1, data->d_size); + data->d_align = 8; + data->d_off = 0; + + statep->nplt_used = 1; +} + + +static void +elf_i386_initialize_pltrel (struct ld_state *statep, Elf_Scn *scn) +{ + Elf_Data *data; + + data = elf_newdata (scn); + if (data == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot allocate PLTREL section: %s"), + elf_errmsg (-1)); + + /* One relocation per PLT entry. */ + data->d_size = statep->nplt * sizeof (Elf32_Rel); + data->d_buf = xcalloc (1, data->d_size); + data->d_type = ELF_T_REL; + data->d_align = 4; + data->d_off = 0; +} + + +static void +elf_i386_initialize_got (struct ld_state *statep, Elf_Scn *scn) +{ + Elf_Data *data; + + /* If we have no .plt we don't need the special entries we normally + create for it. The other contents is created later. */ + if (statep->ngot + statep->nplt == 0) + return; + + data = elf_newdata (scn); + if (data == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot allocate GOT section: %s"), + elf_errmsg (-1)); + + /* We construct the .got section in pieces. Here we only add the data + structures which are used by the PLT. This includes three reserved + entries at the beginning (the first will contain a pointer to the + .dynamic section), and one word for each PLT entry. */ + data->d_size = (3 + statep->ngot + statep->nplt) * sizeof (Elf32_Addr); + data->d_buf = xcalloc (1, data->d_size); + data->d_align = sizeof (Elf32_Addr); + data->d_off = 0; +} + + +/* The first entry in an absolute procedure linkage table looks like + this. See the SVR4 ABI i386 supplement to see how this works. */ +static const unsigned char elf_i386_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x35, /* pushl contents of address */ + 0, 0, 0, 0, /* replaced with address of .got + 4. */ + 0xff, 0x25, /* jmp indirect */ + 0, 0, 0, 0, /* replaced with address of .got + 8. */ + 0, 0, 0, 0 /* pad out to 16 bytes. */ +}; + +/* Type describing the first PLT entry in non-PIC. */ +struct plt0_entry +{ + /* First a 'push' of the second GOT entry. */ + unsigned char push_instr[2]; + uint32_t gotp4_addr; + /* Second, a 'jmp indirect' to the third GOT entry. */ + unsigned char jmp_instr[2]; + uint32_t gotp8_addr; + /* Padding. */ + unsigned char padding[4]; +} __attribute__ ((packed)); + +/* The first entry in a PIC procedure linkage table look like this. */ +static const unsigned char elf_i386_pic_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ + 0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */ + 0, 0, 0, 0 /* pad out to 16 bytes. */ +}; + +/* Contents of all but the first PLT entry in executable. */ +static const unsigned char elf_i386_plt_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x25, /* jmp indirect */ + 0, 0, 0, 0, /* replaced with address of this symbol in .got. */ + 0x68, /* pushl immediate */ + 0, 0, 0, 0, /* replaced with offset into relocation table. */ + 0xe9, /* jmp relative */ + 0, 0, 0, 0 /* replaced with offset to start of .plt. */ +}; + +/* Contents of all but the first PLT entry in DSOs. */ +static const unsigned char elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0xa3, /* jmp *offset(%ebx) */ + 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ + 0x68, /* pushl immediate */ + 0, 0, 0, 0, /* replaced with offset into relocation table. */ + 0xe9, /* jmp relative */ + 0, 0, 0, 0 /* replaced with offset to start of .plt. */ +}; + +/* Type describing a PLT entry. */ +struct plt_entry +{ + /* The first instruction is 'jmp indirect' or 'jmp *offset(%ebs)'. */ + unsigned char jmp_instr[2]; + uint32_t offset_got; + /* The second instruction is 'push immediate'. */ + unsigned char push_instr; + uint32_t push_imm; + /* Finally a 'jmp relative'. */ + unsigned char jmp_instr2; + uint32_t plt0_offset; +} __attribute__ ((packed)); + + +static void +elf_i386_finalize_plt (struct ld_state *statep, size_t nsym, + size_t nsym_dyn __attribute__ ((unused))) +{ + Elf_Scn *scn; + XElf_Shdr_vardef (shdr); + Elf_Data *data; + Elf_Data *symdata = NULL; + Elf_Data *dynsymdata; + size_t cnt; + const bool build_dso = statep->file_type == dso_file_type; + + if (unlikely (statep->nplt + statep->ngot == 0)) + /* Nothing to be done. */ + return; + + /* Get the address of the got section. */ + scn = elf_getscn (statep->outelf, statep->gotscnidx); + xelf_getshdr (scn, shdr); + data = elf_getdata (scn, NULL); + assert (shdr != NULL && data != NULL); + Elf32_Addr gotaddr = shdr->sh_addr; + + /* Now create the initial values for the .got section. The first + word contains the address of the .dynamic section. */ + xelf_getshdr (elf_getscn (statep->outelf, statep->dynamicscnidx), shdr); + assert (shdr != NULL); + ((Elf32_Word *) data->d_buf)[0] = shdr->sh_addr; + + /* The second and third entry are left empty for use by the dynamic + linker. The following entries are pointers to the instructions + following the initial jmp instruction in the corresponding PLT + entry. Since the first PLT entry is special the first used one + has the index 1. */ + scn = elf_getscn (statep->outelf, statep->pltscnidx); + xelf_getshdr (scn, shdr); + assert (shdr != NULL); + + dynsymdata = elf_getdata (elf_getscn (statep->outelf, statep->dynsymscnidx), + NULL); + assert (dynsymdata != NULL); + + if (statep->symscnidx != 0) + { + symdata = elf_getdata (elf_getscn (statep->outelf, statep->symscnidx), + NULL); + assert (symdata != NULL); + } + + for (cnt = 0; cnt < statep->nplt; ++cnt) + { + assert ((4 + cnt) * sizeof (Elf32_Word) <= data->d_size); + + /* Address in the PLT. */ + Elf32_Addr pltentryaddr = shdr->sh_addr + (1 + cnt) * PLT_ENTRY_SIZE; + + /* Point the GOT entry at the PLT entry, after the initial jmp. */ + ((Elf32_Word *) data->d_buf)[3 + cnt] = pltentryaddr + 6; + + /* The value of the symbol is the address of the corresponding PLT + entry. Store the address, also for the normal symbol table if + this is necessary. */ + ((Elf32_Sym *) dynsymdata->d_buf)[1 + cnt].st_value = pltentryaddr; + + if (symdata != NULL) + ((Elf32_Sym *) symdata->d_buf)[nsym - statep->nplt + cnt].st_value + = pltentryaddr; + } + + /* Create the .plt section. */ + scn = elf_getscn (statep->outelf, statep->pltscnidx); + data = elf_getdata (scn, NULL); + assert (data != NULL); + + /* Create the first entry. */ + assert (data->d_size >= PLT_ENTRY_SIZE); + if (build_dso) + /* Copy the entry. It's complete, no relocation needed. */ + memcpy (data->d_buf, elf_i386_pic_plt0_entry, PLT_ENTRY_SIZE); + else + { + /* Copy the skeleton. */ + memcpy (data->d_buf, elf_i386_plt0_entry, PLT_ENTRY_SIZE); + + /* And fill in the addresses. */ + struct plt0_entry *addr = (struct plt0_entry *) data->d_buf; + addr->gotp4_addr = target_bswap_32 (gotaddr + 4); + addr->gotp8_addr = target_bswap_32 (gotaddr + 8); + } + + /* For DSOs we need GOT offsets, otherwise the GOT address. */ + Elf32_Addr gotaddr_off = build_dso ? 0 : gotaddr; + + /* Create the remaining entries. */ + const unsigned char *plt_template + = build_dso ? elf_i386_pic_plt_entry : elf_i386_plt_entry; + + for (cnt = 0; cnt < statep->nplt; ++cnt) + { + struct plt_entry *addr; + + /* Copy the template. */ + assert (data->d_size >= (2 + cnt) * PLT_ENTRY_SIZE); + addr = (struct plt_entry *) ((char *) data->d_buf + + (1 + cnt) * PLT_ENTRY_SIZE); + memcpy (addr, plt_template, PLT_ENTRY_SIZE); + + /* And once more, fill in the addresses. First the address of + this symbol in .got. */ + addr->offset_got = target_bswap_32 (gotaddr_off + + (3 + cnt) * sizeof (Elf32_Addr)); + /* Offset into relocation table. */ + addr->push_imm = target_bswap_32 (cnt * sizeof (Elf32_Rel)); + /* Offset to start of .plt. */ + addr->plt0_offset = target_bswap_32 (-(2 + cnt) * PLT_ENTRY_SIZE); + } + + /* Create the .rel.plt section data. It simply means relocations + addressing the corresponding entry in the .got section. The + section name is misleading. */ + scn = elf_getscn (statep->outelf, statep->pltrelscnidx); + xelf_getshdr (scn, shdr); + data = elf_getdata (scn, NULL); + assert (shdr != NULL && data != NULL); + + /* Update the sh_link to point to the section being modified. We + point it here (correctly) to the .got section. Some linkers + (e.g., the GNU binutils linker) point to the .plt section. This + is wrong since the .plt section isn't modified even though the + name .rel.plt suggests that this is correct. */ + shdr->sh_link = statep->dynsymscnidx; + shdr->sh_info = statep->gotscnidx; + (void) xelf_update_shdr (scn, shdr); + + for (cnt = 0; cnt < statep->nplt; ++cnt) + { + XElf_Rel_vardef (rel); + + assert ((1 + cnt) * sizeof (Elf32_Rel) <= data->d_size); + xelf_getrel_ptr (data, cnt, rel); + rel->r_offset = gotaddr + (3 + cnt) * sizeof (Elf32_Addr); + /* The symbol table entries for the functions from DSOs are at + the end of the symbol table. */ + rel->r_info = XELF_R_INFO (1 + cnt, R_386_JMP_SLOT); + (void) xelf_update_rel (data, cnt, rel); + } +} + + +static int +elf_i386_rel_type (struct ld_state *statep __attribute__ ((__unused__))) +{ + /* ELF/i386 uses REL. */ + return DT_REL; +} + + +static void +elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo) +{ + /* We go through the list of input sections and count those relocations + which are not handled by the linker. At the same time we have to + see how many GOT entries we need and how much .bss space is needed + for copy relocations. */ + Elf_Data *data = elf_getdata (scninfo->scn, NULL); + XElf_Shdr *shdr = &SCNINFO_SHDR (scninfo->shdr); + size_t maxcnt = shdr->sh_size / shdr->sh_entsize; + size_t relsize = 0; + size_t cnt; + struct symbol *sym; + + assert (shdr->sh_type == SHT_REL); + + for (cnt = 0; cnt < maxcnt; ++cnt) + { + XElf_Rel_vardef (rel); + + xelf_getrel (data, cnt, rel); + /* XXX Should we complain about failing accesses? */ + if (rel != NULL) + { + Elf32_Word r_sym = XELF_R_SYM (rel->r_info); + + switch (XELF_R_TYPE (rel->r_info)) + { + case R_386_GOT32: + if (! scninfo->fileinfo->symref[r_sym]->defined) + relsize += sizeof (Elf32_Rel); + + /* This relocation is not emitted in the output file but + requires a GOT entry. */ + ++statep->ngot; + ++statep->nrel_got; + + /* FALLTHROUGH */ + + case R_386_GOTOFF: + case R_386_GOTPC: + statep->need_got = true; + break; + + case R_386_32: + case R_386_PC32: + /* These relocations cause text relocations in DSOs. */ + if (linked_from_dso_p (scninfo, r_sym)) + { + if (statep->file_type == dso_file_type) + { + relsize += sizeof (Elf32_Rel); + statep->dt_flags |= DF_TEXTREL; + } + else + { + /* Non-function objects from a DSO need to get a + copy relocation. */ + sym = scninfo->fileinfo->symref[r_sym]; + + /* Only do this if we have not requested a copy + relocation already. */ + if (unlikely (sym->type != STT_FUNC) && ! sym->need_copy) + { + sym->need_copy = 1; + ++statep->ncopy; + relsize += sizeof (Elf32_Rel); + } + } + } + else if (statep->file_type == dso_file_type + && r_sym >= SCNINFO_SHDR (scninfo->fileinfo->scninfo[shdr->sh_link].shdr).sh_info + && scninfo->fileinfo->symref[r_sym]->outdynsymidx != 0 + && XELF_R_TYPE (rel->r_info) == R_386_32) + relsize += sizeof (Elf32_Rel); + break; + + case R_386_PLT32: + /* We might need a PLT entry. But we cannot say for sure + here since one of the symbols might turn up being + defined in the executable (if we create such a thing). + If a DSO is created we still might use a local + definition. + + If the symbol is not defined and we are not creating + a statically linked binary, then we need in any case + a PLT entry. */ + if (! scninfo->fileinfo->symref[r_sym]->defined) + { + assert (!statep->statically); + + sym = scninfo->fileinfo->symref[r_sym]; + sym->type = STT_FUNC; + sym->in_dso = 1; + sym->defined = 1; + + /* Remove from the list of unresolved symbols. */ + --statep->nunresolved; + if (! sym->weak) + --statep->nunresolved_nonweak; + CDBL_LIST_DEL (statep->unresolved, sym); + + /* Add to the list of symbols we expect from a DSO. */ + ++statep->nplt; + ++statep->nfrom_dso; + CDBL_LIST_ADD_REAR (statep->from_dso, sym); + } + break; + + case R_386_TLS_GD: + case R_386_TLS_LDM: + case R_386_TLS_GD_32: + case R_386_TLS_GD_PUSH: + case R_386_TLS_GD_CALL: + case R_386_TLS_GD_POP: + case R_386_TLS_LDM_32: + case R_386_TLS_LDM_PUSH: + case R_386_TLS_LDM_CALL: + case R_386_TLS_LDM_POP: + case R_386_TLS_LDO_32: + case R_386_TLS_IE_32: + case R_386_TLS_LE_32: + /* XXX */ + abort (); + break; + + case R_386_NONE: + /* Nothing to be done. */ + break; + + /* These relocation should never be generated by an + assembler. */ + case R_386_COPY: + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + case R_386_RELATIVE: + case R_386_TLS_DTPMOD32: + case R_386_TLS_DTPOFF32: + case R_386_TLS_TPOFF32: + /* Unknown relocation. */ + default: + abort (); + } + } + } + + scninfo->relsize = relsize; +} + + +static void +elf_i386_create_relocations (struct ld_state *statep, + const Elf32_Word *dblindirect __attribute__ ((unused))) +{ + /* Get the address of the got section. */ + Elf_Scn *pltscn = elf_getscn (statep->outelf, statep->pltscnidx); + Elf32_Shdr *shdr = elf32_getshdr (pltscn); + assert (shdr != NULL); + Elf32_Addr pltaddr = shdr->sh_addr; + + Elf_Scn *gotscn = elf_getscn (statep->outelf, statep->gotscnidx); + shdr = elf32_getshdr (gotscn); + assert (shdr != NULL); + Elf32_Addr gotaddr = shdr->sh_addr; + + Elf_Scn *reldynscn = elf_getscn (statep->outelf, statep->reldynscnidx); + Elf_Data *reldyndata = elf_getdata (reldynscn, NULL); + + size_t nreldyn = 0; +#define ngot_used (3 + statep->nplt + nreldyn) + + struct scninfo *first = statep->rellist->next; + struct scninfo *runp = first; + do + { + XElf_Shdr *rshdr = &SCNINFO_SHDR (runp->shdr); + Elf_Data *reldata = elf_getdata (runp->scn, NULL); + int nrels = rshdr->sh_size / rshdr->sh_entsize; + + /* We will need the following vlaues a couple of times. Help + the compiler and improve readability. */ + struct symbol **symref = runp->fileinfo->symref; + struct scninfo *scninfo = runp->fileinfo->scninfo; + + /* This is the offset of the input section we are looking at in + the output file. */ + XElf_Addr inscnoffset = scninfo[rshdr->sh_info].offset; + + /* The target section. We use the data from the input file. */ + Elf_Data *data = elf_getdata (scninfo[rshdr->sh_info].scn, NULL); + + /* We cannot handle relocations against merge-able sections. */ + assert ((SCNINFO_SHDR (scninfo[rshdr->sh_link].shdr).sh_flags + & SHF_MERGE) == 0); + + /* Cache the access to the symbol table data. */ + Elf_Data *symdata = elf_getdata (scninfo[rshdr->sh_link].scn, NULL); + + int cnt; + for (cnt = 0; cnt < nrels; ++cnt) + { + XElf_Rel_vardef (rel); + XElf_Rel *rel2; + xelf_getrel (reldata, cnt, rel); + assert (rel != NULL); + XElf_Addr reladdr = inscnoffset + rel->r_offset; + XElf_Addr value; + + size_t idx = XELF_R_SYM (rel->r_info); + if (idx < runp->fileinfo->nlocalsymbols) + { + XElf_Sym_vardef (sym); + xelf_getsym (symdata, idx, sym); + + /* The value just depends on the position of the referenced + section in the output file and the addend. */ + value = scninfo[sym->st_shndx].offset + sym->st_value; + } + else if (symref[idx]->in_dso) + { + /* MERGE.VALUE contains the PLT index. We have to add 1 since + there is this one special PLT entry at the beginning. */ + assert (symref[idx]->merge.value != 0 + || symref[idx]->type != STT_FUNC); + value = pltaddr + symref[idx]->merge.value * PLT_ENTRY_SIZE; + } + else + value = symref[idx]->merge.value; + + /* Address of the relocated memory in the data buffer. */ + void *relloc = (char *) data->d_buf + rel->r_offset; + + switch (XELF_R_TYPE (rel->r_info)) + { + /* These three cases can be handled together since the + symbol associated with the R_386_GOTPC relocation is + _GLOBAL_OFFSET_TABLE_ which has a value corresponding + to the address of the GOT and the address of the PLT + entry required for R_386_PLT32 is computed above. */ + case R_386_PC32: + case R_386_GOTPC: + case R_386_PLT32: + value -= reladdr; + /* FALLTHROUGH */ + + case R_386_32: + if (linked_from_dso_p (scninfo, idx) + && statep->file_type != dso_file_type + && symref[idx]->type != STT_FUNC) + { + value = (ld_state.copy_section->offset + + symref[idx]->merge.value); + + if (unlikely (symref[idx]->need_copy)) + { + /* Add a relocation to initialize the GOT entry. */ + assert (symref[idx]->outdynsymidx != 0); +#if NATIVE_ELF != 0 + xelf_getrel_ptr (reldyndata, nreldyn, rel2); +#else + rel2 = &rel_mem; +#endif + rel2->r_offset = value; + rel2->r_info + = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_COPY); + (void) xelf_update_rel (reldyndata, nreldyn, rel2); + ++nreldyn; + + /* Update the symbol table record for the new + address. */ + Elf32_Word symidx = symref[idx]->outdynsymidx; + Elf_Scn *symscn = elf_getscn (statep->outelf, + statep->dynsymscnidx); + Elf_Data *outsymdata = elf_getdata (symscn, NULL); + assert (outsymdata != NULL); + XElf_Sym_vardef (sym); + xelf_getsym (outsymdata, symidx, sym); + sym->st_value = value; + sym->st_shndx = statep->copy_section->outscnndx; + (void) xelf_update_sym (outsymdata, symidx, sym); + + symidx = symref[idx]->outsymidx; + if (symidx != 0) + { + symidx = statep->dblindirect[symidx]; + symscn = elf_getscn (statep->outelf, + statep->symscnidx); + outsymdata = elf_getdata (symscn, NULL); + assert (outsymdata != NULL); + xelf_getsym (outsymdata, symidx, sym); + sym->st_value = value; + sym->st_shndx = statep->copy_section->outscnndx; + (void) xelf_update_sym (outsymdata, symidx, sym); + } + + /* Remember that we set up the copy relocation. */ + symref[idx]->need_copy = 0; + } + } + else if (statep->file_type == dso_file_type + && idx >= SCNINFO_SHDR (scninfo[rshdr->sh_link].shdr).sh_info + && symref[idx]->outdynsymidx != 0) + { +#if NATIVE_ELF != 0 + xelf_getrel_ptr (reldyndata, nreldyn, rel2); +#else + rel2 = &rel_mem; +#endif + rel2->r_offset = value; + rel2->r_info + = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_32); + (void) xelf_update_rel (reldyndata, nreldyn, rel2); + ++nreldyn; + + value = 0; + } + add_4ubyte_unaligned (relloc, value); + break; + + case R_386_GOT32: + store_4ubyte_unaligned (relloc, ngot_used * sizeof (Elf32_Addr)); + + /* Add a relocation to initialize the GOT entry. */ +#if NATIVE_ELF != 0 + xelf_getrel_ptr (reldyndata, nreldyn, rel2); +#else + rel2 = &rel_mem; +#endif + rel2->r_offset = gotaddr + ngot_used * sizeof (Elf32_Addr); + rel2->r_info + = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_GLOB_DAT); + (void) xelf_update_rel (reldyndata, nreldyn, rel2); + ++nreldyn; + break; + + case R_386_GOTOFF: + add_4ubyte_unaligned (relloc, value - gotaddr); + break; + + case R_386_32PLT: + case R_386_TLS_TPOFF: + case R_386_TLS_IE: + case R_386_TLS_GOTIE: + case R_386_TLS_LE: + case R_386_TLS_GD: + case R_386_TLS_LDM: + case R_386_16: + case R_386_PC16: + case R_386_8: + case R_386_PC8: + case R_386_TLS_GD_32: + case R_386_TLS_GD_PUSH: + case R_386_TLS_GD_CALL: + case R_386_TLS_GD_POP: + case R_386_TLS_LDM_32: + case R_386_TLS_LDM_PUSH: + case R_386_TLS_LDM_CALL: + case R_386_TLS_LDM_POP: + case R_386_TLS_LDO_32: + case R_386_TLS_IE_32: + case R_386_TLS_LE_32: + // XXX For now fall through + printf("ignored relocation %d\n", (int) XELF_R_TYPE (rel->r_info)); + break; + + case R_386_NONE: + /* Nothing to do. */ + break; + + case R_386_COPY: + case R_386_JMP_SLOT: + case R_386_RELATIVE: + case R_386_GLOB_DAT: + case R_386_TLS_DTPMOD32: + case R_386_TLS_DTPOFF32: + case R_386_TLS_TPOFF32: + default: + /* Should not happen. */ + abort (); + } + } + } + while ((runp = runp->next) != first); +} + + +int +elf_i386_ld_init (struct ld_state *statep) +{ + /* We have a few callbacks available. */ + old_open_outfile = statep->callbacks.open_outfile; + statep->callbacks.open_outfile = elf_i386_open_outfile; + + statep->callbacks.relocate_section = elf_i386_relocate_section; + + statep->callbacks.initialize_plt = elf_i386_initialize_plt; + statep->callbacks.initialize_pltrel = elf_i386_initialize_pltrel; + + statep->callbacks.initialize_got = elf_i386_initialize_got; + + statep->callbacks.finalize_plt = elf_i386_finalize_plt; + + statep->callbacks.rel_type = elf_i386_rel_type; + + statep->callbacks.count_relocations = elf_i386_count_relocations; + + statep->callbacks.create_relocations = elf_i386_create_relocations; + + return 0; +} diff --git a/src/ld.c b/src/ld.c new file mode 100644 index 00000000..2aece00e --- /dev/null +++ b/src/ld.c @@ -0,0 +1,1506 @@ +/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ld.h" +#include "list.h" + + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Bug report address. */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + + +/* Values for the various options. */ +enum + { + ARGP_whole_archive = 300, + ARGP_no_whole_archive, + ARGP_static, + ARGP_dynamic, + ARGP_pagesize, + ARGP_rpath, + ARGP_rpath_link, + ARGP_runpath, + ARGP_runpath_link, + ARGP_version_script, + ARGP_gc_sections, + ARGP_no_gc_sections, + ARGP_no_undefined, + ARGP_conserve, +#if YYDEBUG + ARGP_yydebug, +#endif + }; + + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + /* XXX This list will be reordered and section names will be added. + Just not right now. */ + { "whole-archive", ARGP_whole_archive, NULL, 0, + N_("Include whole archives in the output from now on."), 0 }, + { "no-whole-archive", ARGP_no_whole_archive, NULL, 0, + N_("Stop including the whole arhives in the output."), 0 }, + + { "output", 'o', N_("FILE"), 0, N_("Place output in FILE."), 0 }, + + { NULL, 'O', N_("LEVEL"), OPTION_ARG_OPTIONAL, + N_("Set optimization level to LEVEL."), 0 }, + + { "verbose", 'v', NULL, 0, N_("Verbose messages."), 0 }, + { "trace", 't', NULL, 0, N_("Trace file opens."), 0 }, + { "conserve-memory", ARGP_conserve, NULL, 0, + N_("Trade speed for less memory usage"), 0 }, + + { NULL, 'z', "KEYWORD", OPTION_HIDDEN, NULL, 0 }, + { "-z nodefaultlib", '\0', NULL, OPTION_DOC, + N_("Object is marked to not use default search path at runtime."), 0 }, + { "-z allextract", '\0', NULL, OPTION_DOC, + N_("Same as --whole-archive."), 0 }, + { "-z defaultextract", '\0', NULL, OPTION_DOC, N_("\ +Default rules of extracting from archive; weak references are not enough."), + 0 }, + { "-z weakextract", '\0', NULL, OPTION_DOC, + N_("Weak references cause extraction from archive."), 0 }, + { "-z muldefs", '\0', NULL, OPTION_DOC, + N_("Allow multiple definitions; first is used."), 0 }, + { "-z defs | nodefs", '\0', NULL, OPTION_DOC, + N_("Disallow/allow undefined symbols in DSOs."), 0 }, + { "no-undefined", ARGP_no_undefined, NULL, OPTION_HIDDEN, NULL, 0 }, + { "-z origin", '\0', NULL, OPTION_DOC, + N_("Object requires immediate handling of $ORIGIN."), 0 }, + { "-z now", '\0', NULL, OPTION_DOC, + N_("Relocation will not be processed lazily."), 0 }, + { "-z nodelete", '\0', NULL, OPTION_DOC, + N_("Object cannot be unloaded at runtime."), 0 }, + { "-z initfirst", '\0', NULL, OPTION_DOC, + N_("Mark object to be initialized first."), 0 }, + { "-z lazyload | nolazyload", '\0', NULL, OPTION_DOC, + N_("Enable/disable lazy-loading flag for following dependencies."), 0 }, + { "-z nodlopen", '\0', NULL, OPTION_DOC, + N_("Mark object as not loadable with 'dlopen'."), 0 }, + { "-z ignore | record", '\0', NULL, OPTION_DOC, + N_("Ignore/record dependencies on unused DSOs."), 0 }, + { "-z systemlibrary", '\0', NULL, OPTION_DOC, + N_("Generated DSO will be a system library."), 0 }, + + { NULL, 'l', N_("FILE"), OPTION_HIDDEN, NULL, 0 }, + + { NULL, '(', NULL, 0, N_("Start a group."), 0 }, + { NULL, ')', NULL, 0, N_("End a group."), 0 }, + + { NULL, 'L', N_("PATH"), 0, + N_("Add PATH to list of directories files are searched in."), 0 }, + + { NULL, 'c', N_("FILE"), 0, N_("Use linker script in FILE."), 0 }, + + { "entry", 'e', N_("ADDRESS"), 0, N_("Set entry point address."), 0 }, + + { "static", ARGP_static, NULL, OPTION_HIDDEN, NULL, 0 }, + { "-B static", ARGP_static, NULL, OPTION_DOC, + N_("Do not link against shared libraries."), 0 }, + { "dynamic", ARGP_dynamic, NULL, OPTION_HIDDEN, NULL, 0 }, + { "-B dynamic", ARGP_dynamic, NULL, OPTION_DOC, + N_("Prefer linking against shared libraries."), 0 }, + + { "export-dynamic", 'E', NULL, 0, N_("Export all dynamic symbols."), 0 }, + + { "strip-all", 's', NULL, 0, N_("Strip all symbols."), 0 }, + { "strip-debug", 'S', NULL, 0, N_("Strip debugging symbols."), 0 }, + + { "pagesize", ARGP_pagesize, "SIZE", 0, + N_("Assume pagesize for the target system to be SIZE."), 0 }, + + { "rpath", ARGP_rpath, "PATH", OPTION_HIDDEN, NULL, 0 }, + { "rpath-link", ARGP_rpath_link, "PATH", OPTION_HIDDEN, NULL, 0 }, + + { "runpath", ARGP_runpath, "PATH", 0, N_("Set runtime DSO search path."), + 0 }, + { "runpath-link", ARGP_runpath_link, "PATH", 0, + N_("Set link time DSO search path."), 0 }, + + { NULL, 'i', NULL, 0, N_("Ignore LD_LIBRARY_PATH environment variable."), + 0 }, + + { "version-script", ARGP_version_script, "FILE", 0, + N_("Read version information from FILE."), 0 }, + + { "emulation", 'm', "NAME", 0, N_("Set emulation to NAME."), 0 }, + + { "shared", 'G', NULL, 0, N_("Generate dynamic shared object."), 0 }, + { NULL, 'r', NULL, 0L, N_("Generate relocatable object."), 0 }, + + { NULL, 'B', "KEYWORD", OPTION_HIDDEN, "", 0 }, + { "-B local", 'B', NULL, OPTION_DOC, + N_("Causes symbol not assigned to a version be reduced to local."), 0 }, + + { "gc-sections", ARGP_gc_sections, NULL, 0, N_("Remove unused sections."), + 0 }, + { "no-gc-sections", ARGP_no_gc_sections, NULL, 0, + N_("Don't remove unused sections."), 0 }, + + { "soname", 'h', "NAME", 0, N_("Set soname of shared object."), 0 }, + { "dynamic-linker", 'I', "NAME", 0, N_("Set the dynamic linker name."), 0 }, + + { NULL, 'Q', "YN", OPTION_HIDDEN, NULL, 0 }, + { "-Q y | n", 'Q', NULL, OPTION_DOC, + N_("Add/suppress addition indentifying link-editor to .comment section"), + 0 }, + +#if YYDEBUG + { "yydebug", ARGP_yydebug, NULL, 0, + N_("Select to get parser debug information"), 0 }, +#endif + + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Short description of program. */ +static const char doc[] = N_("Combine object and archive files."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("[FILE]..."); + +/* Prototype for option handler. */ +static error_t parse_opt_1st (int key, char *arg, struct argp_state *state); +static error_t parse_opt_2nd (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp_1st = +{ + options, parse_opt_1st, args_doc, doc, NULL, NULL, NULL +}; +static struct argp argp_2nd = +{ + options, parse_opt_2nd, args_doc, doc, NULL, NULL, NULL +}; + + +/* Linker state. This contains all global information. */ +struct ld_state ld_state; + +/* List of the input files. */ +static struct file_list +{ + const char *name; + struct file_list *next; +} *input_file_list; + +/* If nonzero be verbose. */ +int verbose; + +/* If nonzero, trade speed for less memory/address space usage. */ +int conserve_memory; + +/* The emulation name to use. */ +static const char *emulation; + +/* Keep track of the nesting level. Even though we don't handle nested + groups we still keep track to improve the error messages. */ +static int group_level; + +/* The last file we processed. */ +static struct usedfiles *last_file; + +/* The default linker script. */ +/* XXX We'll do this a bit different in the real solution. */ +static const char *linker_script = SRCDIR "/elf32-i386.script"; + +/* Nonzero if an error occurred while loading the input files. */ +static int error_loading; + + +/* Intermediate storage for the LD_LIBRARY_PATH information from the + environment. */ +static char *ld_library_path1; + +/* Flag used to communicate with the scanner. */ +int ld_scan_version_script; + +/* Name of the input file. */ +const char *ldin_fname; + +/* Define by parser if required. */ +extern int lddebug; + + +/* Prototypes for local functions. */ +static void parse_z_option (const char *arg); +static void parse_z_option_2 (const char *arg); +static void parse_B_option (const char *arg); +static void parse_B_option_2 (const char *arg); +static void determine_output_format (void); +static void load_needed (void); +static void collect_sections (void); +static void add_rxxpath (struct pathelement **pathp, const char *str); +static void gen_rxxpath_data (void); +static void read_version_script (const char *fname); +static void create_lscript_symbols (void); +static void create_special_section_symbol (struct symbol **symp, + const char *name); + + +int +main (int argc, char *argv[]) +{ + int remaining; + int err; + +#ifndef NDEBUG + /* Enable memory debugging. */ + mtrace (); +#endif + + /* Sanity check. We always want to use the LFS functionality. */ + if (sizeof (off_t) != sizeof (off64_t)) + abort (); + + /* We use no threads here which can interfere with handling a stream. */ + __fsetlocking (stdin, FSETLOCKING_BYCALLER); + __fsetlocking (stdout, FSETLOCKING_BYCALLER); + __fsetlocking (stderr, FSETLOCKING_BYCALLER); + + /* Set locale. */ + setlocale (LC_ALL, ""); + + /* Make sure the message catalog can be found. */ + bindtextdomain (PACKAGE, LOCALEDIR); + + /* Initialize the message catalog. */ + textdomain (PACKAGE); + + /* Before we start tell the ELF library which version we are using. */ + elf_version (EV_CURRENT); + + /* The user can use the LD_LIBRARY_PATH environment variable to add + additional lookup directories. */ + ld_library_path1 = getenv ("LD_LIBRARY_PATH"); + + /* Initialize the memory handling. */ +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + obstack_init (&ld_state.smem); + + /* One quick pass over the parameters which allows us to scan for options + with global effect which influence the rest of the processing. */ + argp_parse (&argp_1st, argc, argv, ARGP_IN_ORDER, &remaining, NULL); + + /* We need at least one input file. */ + if (input_file_list == NULL) + { + error (0, 0, gettext ("At least one input file needed")); + argp_help (&argp_1st, stderr, ARGP_HELP_SEE, "ld"); + exit (EXIT_FAILURE); + } + + /* Determine which ELF backend to use. */ + determine_output_format (); + + /* Prepare state. */ + err = ld_prepare_state (emulation); + if (err != 0) + error (EXIT_FAILURE, 0, gettext ("error while preparing linking")); + + /* XXX Read the linker script now. Since we later will have the linker + script built in we don't go into trouble to make sure we handle GROUP + statements in the script. This simply must not happen. */ + ldin = fopen (linker_script, "r"); + if (ldin == NULL) + error (EXIT_FAILURE, errno, gettext ("cannot open linker script \"%s\""), + linker_script); + /* No need for locking. */ + __fsetlocking (ldin, FSETLOCKING_BYCALLER); + + ld_state.srcfiles = NULL; + ldlineno = 1; + ld_scan_version_script = 0; + ldin_fname = linker_script; + if (ldparse () != 0) + /* Something went wrong during parsing. */ + exit (EXIT_FAILURE); + fclose (ldin); + + /* We now might have a list of directories to look for libraries in + named by the linker script. Put them in a different list so that + they are searched after all paths given by the user on the + command line. */ + ld_state.default_paths = ld_state.paths; + ld_state.paths = ld_state.tailpaths = NULL; + + /* Get runpath/rpath information in usable form. */ + gen_rxxpath_data (); + + /* Parse and process arguments for real. */ + argp_parse (&argp_2nd, argc, argv, ARGP_IN_ORDER, &remaining, NULL); + /* All options should have been processed by the argp parser. */ + assert (remaining == argc); + + /* Process the last file. */ + while (last_file != NULL) + /* Try to open the file. */ + error_loading |= FILE_PROCESS (-1, last_file, &ld_state, &last_file); + + /* Stop if there has been a problem while reading the input files. */ + if (error_loading) + exit (error_loading); + + /* See whether all opened -( were closed. */ + if (group_level > 0) + { + error (0, 0, gettext ("-( without matching -)")); + argp_help (&argp_1st, stderr, ARGP_HELP_SEE, "ld"); + exit (EXIT_FAILURE); + } + + /* When we create a relocatable file we don't have to look for the + DT_NEEDED DSOs and we also don't test for undefined symbols. */ + if (ld_state.file_type != relocatable_file_type) + { + /* At this point we have loaded all the direct dependencies. What + remains to be done is find the indirect dependencies. These are + DSOs which are referenced by the DT_NEEDED entries in the DSOs + which are direct dependencies. We have to transitively find and + load all these dependencies. */ + load_needed (); + + /* At this point all object files and DSOs are read. If there + are still undefined symbols left they might have to be + synthesized from the linker script. */ + create_lscript_symbols (); + + /* Now that we have loaded all the object files we can determine + whether we have any non-weak unresolved references left. If + there are any we stop. If the user used the '-z nodefs' option + and we are creating a DSO don't perform the tests. */ + if (FLAG_UNRESOLVED (&ld_state) != 0) + exit (1); + } + + /* Collect information about the relocations which will be carried + forward into the output. We have to do this here and now since + we need to know which sections have to be created. */ + if (ld_state.file_type != relocatable_file_type) + { + void *p ; + struct scnhead *h; + + p = NULL; + while ((h = ld_section_tab_iterate (&ld_state.section_tab, &p)) != NULL) + if (h->type == SHT_REL || h->type == SHT_RELA) + { + struct scninfo *runp = h->last; + do + { + /* If we are processing the relocations determine how + many will be in the output file. Also determine + how many GOT entries are needed. */ + COUNT_RELOCATIONS (&ld_state, runp); + + ld_state.relsize_total += runp->relsize; + } + while ((runp = runp->next) != h->last); + } + } + + /* Not part of the gABI, but part of every psABI: the symbols for the + GOT section. Add the symbol if necessary. */ + if (ld_state.need_got) + create_special_section_symbol (&ld_state.got_symbol, + "_GLOBAL_OFFSET_TABLE_"); + /* Similarly for the _DYNAMIC symbol which points to the dynamic + section. */ + if (dynamically_linked_p ()) + create_special_section_symbol (&ld_state.dyn_symbol, "_DYNAMIC"); + + /* We are ready to start working on the output file. Not all + information has been gather or created yet. This will be done as + we go. Open the file now. */ + if (OPEN_OUTFILE (&ld_state, EM_NONE, ELFCLASSNONE, ELFDATANONE) != 0) + exit (1); + + /* Create the sections which are generated by the linker and are not + present in the input file. The output file must already have + been opened since we need the ELF descriptor to deduce type + sizes. */ + GENERATE_SECTIONS (&ld_state); + + /* At this point we have read all the files and know all the + sections which have to be linked into the application. We do now + create an array listing all the sections. We will than pass this + array to a system specific function which can reorder it at will. + The functions can also merge sections if this is what is + wanted. */ + collect_sections (); + + /* Create the output sections now. This may requires sorting them + first. */ + CREATE_SECTIONS (&ld_state); + + /* Create the output file data. Appropriate code for the selected + output file type is called. */ + if (CREATE_OUTFILE (&ld_state) != 0) + exit (1); + + /* Finalize the output file, write the data out. */ + err |= FINALIZE (&ld_state); + + /* Return with an non-zero exit status also if any error message has + been printed. */ + return err | (error_message_count != 0); +} + + +/* Quick scan of the parameter list for options with global effect. */ +static error_t +parse_opt_1st (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case 'B': + parse_B_option (arg); + break; + + case 'c': + linker_script = arg; + break; + + case 'E': + ld_state.export_all_dynamic = true; + break; + + case 'G': + if (ld_state.file_type != no_file_type) + error (EXIT_FAILURE, 0, + gettext ("only one option of -G and -r is allowed")); + ld_state.file_type = dso_file_type; + + /* If we generate a DSO we have to export all symbols. */ + ld_state.export_all_dynamic = true; + break; + + case 'h': + ld_state.soname = arg; + break; + + case 'i': + /* Discard the LD_LIBRARY_PATH value we found. */ + ld_library_path1 = NULL; + break; + + case 'I': + ld_state.interp = arg; + break; + + case 'm': + if (emulation != NULL) + error (EXIT_FAILURE, 0, gettext ("more than one '-m' parameter")); + emulation = arg; + break; + + case 'Q': + if (arg[1] == '\0' && (arg[0] == 'y' || arg[0] == 'Y')) + ld_state.add_ld_comment = true; + else if (arg[1] == '\0' && (arg[0] == 'n' || arg[0] == 'N')) + ld_state.add_ld_comment = true; + else + error (EXIT_FAILURE, 0, gettext ("unknown option `-%c %s'"), 'Q', arg); + break; + + case 'r': + if (ld_state.file_type != no_file_type) + error (EXIT_FAILURE, 0, + gettext ("only one option of -G and -r is allowed")); + ld_state.file_type = relocatable_file_type; + break; + + case 'S': + ld_state.strip = strip_debug; + break; + + case 't': + ld_state.trace_files = true; + break; + + case 'v': + verbose = 1; + break; + + case 'z': + /* The SysV linker used 'z' to pass various flags to the linker. + We follow this. See 'parse_z_option' for the options we + recognize. */ + parse_z_option (arg); + break; + + case ARGP_pagesize: + { + char *endp; + ld_state.pagesize = strtoul (arg, &endp, 0); + if (*endp != '\0') + { + if (endp[1] == '\0' && tolower (*endp) == 'k') + ld_state.pagesize *= 1024; + else if (endp[1] == '\0' && tolower (*endp) == 'm') + ld_state.pagesize *= 1024 * 1024; + else + { + error (0, 0, + gettext ("invalid page size value \"%s\": ignored"), + arg); + ld_state.pagesize = 0; + } + } + } + break; + + case ARGP_rpath: + add_rxxpath (&ld_state.rpath, arg); + break; + + case ARGP_rpath_link: + add_rxxpath (&ld_state.rpath_link, arg); + break; + + case ARGP_runpath: + add_rxxpath (&ld_state.runpath, arg); + break; + + case ARGP_runpath_link: + add_rxxpath (&ld_state.runpath_link, arg); + break; + + case ARGP_gc_sections: + case ARGP_no_gc_sections: + ld_state.gc_sections = key == ARGP_gc_sections; + break; + + case 's': + if (arg == NULL) + { + if (ld_state.strip == strip_all) + ld_state.strip = strip_everything; + else + ld_state.strip = strip_all; + break; + } + /* FALLTHROUGH */ + + case 'e': + case 'o': + case 'O': + case ARGP_whole_archive: + case ARGP_no_whole_archive: + case 'L': + case '(': + case ')': + case 'l': + case ARGP_static: + case ARGP_dynamic: + case ARGP_version_script: + /* We'll handle these in the second pass. */ + break; + + case ARGP_KEY_ARG: + { + struct file_list *newp; + + newp = (struct file_list *) xmalloc (sizeof (struct file_list)); + newp->name = arg; +#ifndef NDEBUG + newp->next = NULL; +#endif + CSNGL_LIST_ADD_REAR (input_file_list, newp); + } + break; + +#if YYDEBUG + case ARGP_yydebug: + lddebug = 1; + break; +#endif + + case ARGP_no_undefined: + ld_state.nodefs = false; + break; + + case ARGP_conserve: + conserve_memory = 1; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +/* Handle program arguments for real. */ +static error_t +parse_opt_2nd (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + static bool group_start_requested; + static bool group_end_requested; + + switch (key) + { + case 'B': + parse_B_option_2 (arg); + break; + + case 'e': + ld_state.entry = arg; + break; + + case 'o': + if (ld_state.outfname != NULL) + { + error (0, 0, gettext ("More than one output file name given.")); + see_help: + argp_help (&argp_2nd, stderr, ARGP_HELP_SEE, "ld"); + exit (EXIT_FAILURE); + } + ld_state.outfname = arg; + break; + + case 'O': + if (arg == NULL) + ld_state.optlevel = 1; + else + { + char *endp; + unsigned long int level = strtoul (arg, &endp, 10); + if (*endp != '\0') + { + error (0, 0, gettext ("Invalid optimization level `%s'"), arg); + goto see_help; + } + ld_state.optlevel = level; + } + break; + + case ARGP_whole_archive: + ld_state.extract_rule = allextract; + break; + case ARGP_no_whole_archive: + ld_state.extract_rule = defaultextract; + break; + + case ARGP_static: + case ARGP_dynamic: + /* Enable/disable use for DSOs. */ + ld_state.statically = key == ARGP_static; + break; + + case 'z': + /* The SysV linker used 'z' to pass various flags to the linker. + We follow this. See 'parse_z_option' for the options we + recognize. */ + parse_z_option_2 (arg); + break; + + case ARGP_version_script: + read_version_script (arg); + break; + + case 'L': + /* Add a new search directory. */ + ld_new_searchdir (arg); + break; + + case '(': + /* Start a link group. We have to be able to determine the object + file which is named next. Do this by remembering a pointer to + the pointer which will point to the next object. */ + if (verbose && (group_start_requested || !group_end_requested)) + error (0, 0, gettext ("nested -( -) groups are not allowed")); + + /* Increment the nesting level. */ + ++group_level; + + /* Record group start. */ + group_start_requested = true; + group_end_requested = false; + break; + + case ')': + /* End a link group. If there is no group open this is clearly + a bug. If there is a group open insert a back reference + pointer in the record for the last object of the group. If + there is no new object or just one don't do anything. */ + if (!group_end_requested) + { + if (group_level == 0) + { + error (0, 0, gettext ("-) without matching -(")); + goto see_help; + } + } + else + last_file->group_end = true; + + if (group_level > 0) + --group_level; + break; + + case 'l': + case ARGP_KEY_ARG: + { + while (last_file != NULL) + /* Try to open the file. */ + error_loading |= FILE_PROCESS (-1, last_file, &ld_state, &last_file); + + last_file = ld_new_inputfile (arg, + key == 'l' + ? archive_file_type + : relocatable_file_type); + if (group_start_requested) + { + last_file->group_start = true; + + group_start_requested = false; + group_end_requested = true; + } + } + break; + + default: + /* We can catch all other options here. They either have + already been handled or, if the parameter was not correct, + the error has been reported. */ + break; + } + return 0; +} + + +/* Load all the DSOs named as dependencies in other DSOs we already + loaded. */ +static void +load_needed (void) +{ + struct usedfiles *first; + struct usedfiles *runp; + + /* XXX There is one problem here: do we allow references from + regular object files to be satisfied by these implicit + dependencies? The old linker allows this and several libraries + depend on this. Solaris' linker does not allow this; it provides + the user with a comprehensive error message explaining the + situation. + + XXX IMO the old ld behavior is correct since this is also how the + dynamic linker will work. It will look for unresolved references + in all loaded DSOs. + + XXX Should we add an option to get Solaris compatibility? */ + if (ld_state.needed == NULL) + return; + + runp = first = ld_state.needed->next; + do + { + struct usedfiles *ignore; + struct usedfiles *next = runp->next; + int err; + + err = FILE_PROCESS (-1, runp, &ld_state, &ignore); + if (err != 0) + /* Something went wrong. */ + exit (err); + + runp = next; + } + while (runp != first); +} + + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) +{ + fprintf (stream, "ld (%s) %s\n", PACKAGE_NAME, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Red Hat, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2005"); + fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); +} + + +/* There are a lot of -z options, parse them here. Some of them have + to be parsed in the first pass, others must be handled in the + second pass. */ +static void +parse_z_option (const char *arg) +{ + if (strcmp (arg, "nodefaultlib") == 0 + /* This is only meaningful if we create a DSO. */ + && ld_state.file_type == dso_file_type) + ld_state.dt_flags_1 |= DF_1_NODEFLIB; + else if (strcmp (arg, "muldefs") == 0) + ld_state.muldefs = true; + else if (strcmp (arg, "nodefs") == 0) + ld_state.nodefs = true; + else if (strcmp (arg, "defs") == 0) + ld_state.nodefs = false; + else if (strcmp (arg, "now") == 0) + /* We could also set the DF_1_NOW flag in DT_FLAGS_1 but this isn't + necessary. */ + ld_state.dt_flags |= DF_BIND_NOW; + else if (strcmp (arg, "origin") == 0) + /* We could also set the DF_1_ORIGIN flag in DT_FLAGS_1 but this isn't + necessary. */ + ld_state.dt_flags |= DF_ORIGIN; + else if (strcmp (arg, "nodelete") == 0 + /* This is only meaningful if we create a DSO. */ + && ld_state.file_type == dso_file_type) + ld_state.dt_flags_1 |= DF_1_NODELETE; + else if (strcmp (arg, "initfirst") == 0) + ld_state.dt_flags_1 |= DF_1_INITFIRST; + else if (strcmp (arg, "nodlopen") == 0 + /* This is only meaningful if we create a DSO. */ + && ld_state.file_type == dso_file_type) + ld_state.dt_flags_1 |= DF_1_NOOPEN; + else if (strcmp (arg, "ignore") == 0) + ld_state.ignore_unused_dsos = true; + else if (strcmp (arg, "record") == 0) + ld_state.ignore_unused_dsos = false; + else if (strcmp (arg, "systemlibrary") == 0) + ld_state.is_system_library = true; + else if (strcmp (arg, "allextract") != 0 + && strcmp (arg, "defaultextract") != 0 + && strcmp (arg, "weakextract") != 0 + && strcmp (arg, "lazyload") != 0 + && strcmp (arg, "nolazyload") != 0) + error (0, 0, gettext ("unknown option `-%c %s'"), 'z', arg); +} + + +static void +parse_z_option_2 (const char *arg) +{ + if (strcmp (arg, "allextract") == 0) + ld_state.extract_rule = allextract; + else if (strcmp (arg, "defaultextract") == 0) + ld_state.extract_rule = defaultextract; + else if (strcmp (arg, "weakextract") == 0) + ld_state.extract_rule = weakextract; + else if (strcmp (arg, "lazyload") == 0) + ld_state.lazyload = true; + else if (strcmp (arg, "nolazyload") == 0) + ld_state.lazyload = false; +} + + +/* There are a lot of -B options, parse them here. */ +static void +parse_B_option (const char *arg) +{ + if (strcmp (arg, "local") == 0) + ld_state.default_bind_local = true; + else if (strcmp (arg, "symbolic") != 0 + && strcmp (arg, "static") != 0 + && strcmp (arg, "dynamic") != 0) + error (0, 0, gettext ("unknown option '-%c %s'"), 'B', arg); +} + + +/* The same functionality, but called in the second pass over the + parameters. */ +static void +parse_B_option_2 (const char *arg) +{ + if (strcmp (arg, "static") == 0) + ld_state.statically = true; + else if (strcmp (arg, "dynamic") == 0) + ld_state.statically = false; + else if (strcmp (arg, "symbolic") == 0 + /* This is only meaningful if we create a DSO. */ + && ld_state.file_type == dso_file_type) + ld_state.dt_flags |= DF_SYMBOLIC; +} + + +static void +determine_output_format (void) +{ + /* First change the 'input_file_list' variable in a simple + single-linked list. */ + struct file_list *last = input_file_list; + input_file_list = input_file_list->next; + last->next = NULL; + + /* Determine the target configuration which we are supposed to use. + The user can use the '-m' option to select one. If this is + missing we are trying to load one file and determine the + architecture from that. */ + if (emulation != NULL) + { + ld_state.ebl = ebl_openbackend_emulation (emulation); + + assert (ld_state.ebl != NULL); + } + else + { + /* Find an ELF input file and let it determine the ELf backend. */ + struct file_list *runp = input_file_list; + + while (runp != NULL) + { + int fd = open (runp->name, O_RDONLY); + if (fd != -1) + { + int try (Elf *elf) + { + int result = 0; + + if (elf == NULL) + return 0; + + if (elf_kind (elf) == ELF_K_ELF) + { + /* We have an ELF file. We now can find out + what the output format should be. */ + XElf_Ehdr_vardef(ehdr); + + /* Get the ELF header of the object. */ + xelf_getehdr (elf, ehdr); + if (ehdr != NULL) + ld_state.ebl = + ebl_openbackend_machine (ehdr->e_machine); + + result = 1; + } + else if (elf_kind (elf) == ELF_K_AR) + { + /* Try the archive members. This could + potentially lead to wrong results if the + archive contains files for more than one + architecture. But this is the user's + problem. */ + Elf *subelf; + Elf_Cmd cmd = ELF_C_READ_MMAP; + + while ((subelf = elf_begin (fd, cmd, elf)) != NULL) + { + cmd = elf_next (subelf); + + if (try (subelf) != 0) + break; + } + } + + elf_end (elf); + + return result; + } + + if (try (elf_begin (fd, ELF_C_READ_MMAP, NULL)) != 0) + /* Found a file. */ + break; + } + + runp = runp->next; + } + + if (ld_state.ebl == NULL) + { + error (0, 0, gettext ("\ +could not find input file to determine output file format")); + error (EXIT_FAILURE, 0, gettext ("\ +try again with an appropriate '-m' parameter")); + } + } + + /* We don't need the list of input files anymore. The second run over + the parameters will handle them. */ + while (input_file_list != NULL) + { + struct file_list *oldp = input_file_list; + input_file_list = input_file_list->next; + free (oldp); + } + + /* We also know now what kind of file we are supposed to create. If + the user hasn't selected anythign we create and executable. */ + if (ld_state.file_type == no_file_type) + ld_state.file_type = executable_file_type; +} + +/* Add DIR to the list of directories searched for object files and + libraries. */ +void +ld_new_searchdir (const char *dir) +{ + struct pathelement *newpath; + + newpath = (struct pathelement *) + obstack_calloc (&ld_state.smem, sizeof (struct pathelement)); + + newpath->pname = dir; + + /* Enqueue the file. */ + if (ld_state.tailpaths == NULL) + ld_state.paths = ld_state.tailpaths = newpath; + else + { + ld_state.tailpaths->next = newpath; + ld_state.tailpaths = newpath; + } +} + + +struct usedfiles * +ld_new_inputfile (const char *fname, enum file_type type) +{ + struct usedfiles *newfile = (struct usedfiles *) + obstack_calloc (&ld_state.smem, sizeof (struct usedfiles)); + + newfile->soname = newfile->fname = newfile->rfname = fname; + newfile->file_type = type; + newfile->extract_rule = ld_state.extract_rule; + newfile->lazyload = ld_state.lazyload; + newfile->status = not_opened; + + return newfile; +} + + +/* Create an array listing all the sections. We will than pass this + array to a system specific function which can reorder it at will. + The functions can also merge sections if this is what is + wanted. */ +static void +collect_sections (void) +{ + void *p ; + struct scnhead *h; + size_t cnt; + + /* We have that many sections. At least for now. */ + ld_state.nallsections = ld_state.section_tab.filled; + + /* Allocate the array. We allocate one more entry than computed so + far since we might need a new section for the copy relocations. */ + ld_state.allsections = + (struct scnhead **) obstack_alloc (&ld_state.smem, + (ld_state.nallsections + 1) + * sizeof (struct scnhead *)); + + /* Fill the array. We rely here on the hash table iterator to + return the entries in the order they were added. */ + cnt = 0; + p = NULL; + while ((h = ld_section_tab_iterate (&ld_state.section_tab, &p)) != NULL) + { + struct scninfo *runp; + bool used = false; + + if (h->kind == scn_normal) + { + runp = h->last; + do + { + if (h->type == SHT_REL || h->type == SHT_RELA) + { + if (runp->used) + /* This is a relocation section. If the section + it is relocating is used in the result so must + the relocation section. */ + runp->used + = runp->fileinfo->scninfo[SCNINFO_SHDR (runp->shdr).sh_info].used; + } + + /* Accumulate the result. */ + used |= runp->used; + + /* Next input section. */ + runp = runp->next; + } + while (runp != h->last); + + h->used = used; + } + + ld_state.allsections[cnt++] = h; + } + ld_state.nusedsections = cnt; + + assert (cnt == ld_state.nallsections); +} + + +/* Add given path to the end of list. */ +static void +add_rxxpath (struct pathelement **pathp, const char *str) +{ + struct pathelement *newp; + + /* The path elements can in theory be freed after we read all the + files. But the amount of memory we are talking about is small + and the cost of free() calls is not neglectable. */ + newp = (struct pathelement *) obstack_alloc (&ld_state.smem, sizeof (*newp)); + newp->pname = str; + newp->exist = 0; +#ifndef NDEBUG + newp->next = NULL; +#endif + + CSNGL_LIST_ADD_REAR (*pathp, newp); +} + + +/* Convert lists of possibly colon-separated directory lists into lists + where each entry is for a single directory. */ +static void +normalize_dirlist (struct pathelement **pathp) +{ + struct pathelement *firstp = *pathp; + + do + { + const char *pname = (*pathp)->pname; + const char *colonp = strchrnul (pname, ':'); + + if (colonp != NULL) + { + struct pathelement *lastp = *pathp; + struct pathelement *newp; + + while (1) + { + if (colonp == pname) + lastp->pname = "."; + else + lastp->pname = obstack_strndup (&ld_state.smem, pname, + colonp - pname); + + if (*colonp == '\0') + break; + pname = colonp + 1; + + newp = (struct pathelement *) obstack_alloc (&ld_state.smem, + sizeof (*newp)); + newp->next = lastp->next; + newp->exist = 0; + lastp = lastp->next = newp; + + colonp = strchrnul (pname, ':'); + } + + pathp = &lastp->next; + } + else + pathp = &(*pathp)->next; + } + while (*pathp != firstp); +} + + +/* Called after all parameters are parsed to bring the runpath/rpath + information into a usable form. */ +static void +gen_rxxpath_data (void) +{ + char *ld_library_path2; + + /* Convert the information in true single-linked lists for easy use. + At this point we also discard the rpath information if runpath + information is provided. rpath is deprecated and should not be + used (or ever be invented for that matter). */ + if (ld_state.rpath != NULL) + { + struct pathelement *endp = ld_state.rpath; + ld_state.rpath = ld_state.rpath->next; + endp->next = NULL; + } + if (ld_state.rpath_link != NULL) + { + struct pathelement *endp = ld_state.rpath_link; + ld_state.rpath_link = ld_state.rpath_link->next; + endp->next = NULL; + } + + if (ld_state.runpath != NULL) + { + struct pathelement *endp = ld_state.runpath; + ld_state.runpath = ld_state.runpath->next; + endp->next = NULL; + + /* If rpath information is also available discard it. + XXX Should there be a possibility to avoid this? */ + while (ld_state.rpath != NULL) + { + struct pathelement *old = ld_state.rpath; + ld_state.rpath = ld_state.rpath->next; + free (old); + } + } + if (ld_state.runpath_link != NULL) + { + struct pathelement *endp = ld_state.runpath_link; + ld_state.runpath_link = ld_state.runpath_link->next; + endp->next = NULL; + + /* If rpath information is also available discard it. + XXX Should there be a possibility to avoid this? */ + while (ld_state.rpath_link != NULL) + { + struct pathelement *old = ld_state.rpath_link; + ld_state.rpath_link = ld_state.rpath_link->next; + free (old); + } + + /* The information in the strings in the list can actually be + directory lists themselves, with entries separated by colons. + Convert the list now to a list with one list entry for each + directory. */ + normalize_dirlist (&ld_state.runpath_link); + } + else if (ld_state.rpath_link != NULL) + /* Same as for the runpath_link above. */ + normalize_dirlist (&ld_state.rpath_link); + + + /* As a related task, handle the LD_LIBRARY_PATH value here. First + we have to possibly split the value found (if it contains a + semicolon). Then we have to split the value in list of + directories, i.e., split at the colons. */ + if (ld_library_path1 != NULL) + { + ld_library_path2 = strchr (ld_library_path1, ';'); + if (ld_library_path2 == NULL) + { + /* If no semicolon is present the directories are looked at + after the -L parameters (-> ld_library_path2). */ + ld_library_path2 = ld_library_path1; + ld_library_path1 = NULL; + } + else + { + /* NUL terminate the first part. */ + *ld_library_path2++ = '\0'; + + /* Convert the string value in a list. */ + add_rxxpath (&ld_state.ld_library_path1, ld_library_path1); + normalize_dirlist (&ld_state.ld_library_path1); + } + + add_rxxpath (&ld_state.ld_library_path2, ld_library_path2); + normalize_dirlist (&ld_state.ld_library_path2); + } +} + + +static void +read_version_script (const char *fname) +{ + /* Open the file. The name is supposed to be the complete (relative + or absolute) path. No search along a path will be performed. */ + ldin = fopen (fname, "r"); + if (ldin == NULL) + error (EXIT_FAILURE, errno, gettext ("cannot read version script \"%s\""), + fname); + /* No need for locking. */ + __fsetlocking (ldin, FSETLOCKING_BYCALLER); + + /* Tell the parser that this is a version script. */ + ld_scan_version_script = 1; + + ldlineno = 1; + ldin_fname = fname; + if (ldparse () != 0) + /* Something went wrong during parsing. */ + exit (EXIT_FAILURE); + + fclose (ldin); +} + + +static void +create_lscript_symbols (void) +{ + /* Walk through the data from the linker script and generate all the + symbols which are required to be present and and those marked + with PROVIDE if there is a undefined reference. */ + if (ld_state.output_segments == NULL) + return; + + struct output_segment *segment = ld_state.output_segments->next; + do + { + struct output_rule *orule; + + for (orule = segment->output_rules; orule != NULL; orule = orule->next) + if (orule->tag == output_assignment + /* The assignments to "." (i.e., the PC) have to be + ignored here. */ + && strcmp (orule->val.assignment->variable, ".") != 0) + { + struct symbol *s = ld_state.unresolved; + + /* Check whether the symbol is needed. */ + if (likely (s != NULL)) + { + struct symbol *first = s; + const char *providename = orule->val.assignment->variable; + + /* Determine whether the provided symbol is still + undefined. */ + // XXX TODO Loop inside a loop. Gag! Must rewrite. */ + do + if (strcmp (s->name, providename) == 0) + { + /* Not defined but referenced. */ + if (unlikely (!s->defined)) + { + /* Put on the list of symbols. First remove it from + whatever list it currently is on. */ + CDBL_LIST_DEL (ld_state.unresolved, s); + --ld_state.nunresolved; + goto use_it; + } + + if (unlikely (!orule->val.assignment->provide_flag)) + { + /* The symbol is already defined and now again + in the linker script. This is an error. */ + error (0, 0, gettext ("\ +duplicate definition of '%s' in linker script"), + providename); + goto next_rule; + } + } + while ((s = s->next) != first); + } + + /* If the symbol only has to be provided if it is needed, + ignore it here since it is not undefined. */ + if (orule->val.assignment->provide_flag) + continue; + + /* Allocate memory for this new symbol. */ + s = (struct symbol *) + obstack_calloc (&ld_state.smem, sizeof (struct symbol)); + + /* Initialize it. */ + s->name = orule->val.assignment->variable; + + /* Insert it into the symbol hash table. */ + unsigned long int hval = elf_hash (s->name); + if (unlikely (ld_symbol_tab_insert (&ld_state.symbol_tab, + hval, s) != 0)) + { + /* This means the symbol is defined somewhere else. + Maybe it comes from a DSO or so. Get the + definition. */ + free (s); + struct symbol *old = ld_symbol_tab_find (&ld_state.symbol_tab, + hval, s); + assert (old != NULL); + free (s); + + /* If this is a definition from the application itself + this means a duplicate definition. */ + if (! old->in_dso) + { + error (0, 0, gettext ("\ +duplicate definition of '%s' in linker script"), + s->name); + goto next_rule; + } + + /* We use the definition from the linker script. */ + s = old; + } + + use_it: + /* The symbol is (now) defined. */ + s->defined = 1; + s->type = STT_NOTYPE; + + /* Add a reference to the symbol record. We will come + across it when creating the output file. */ + orule->val.assignment->sym = s; + + SNGL_LIST_PUSH (ld_state.lscript_syms, s); + ++ld_state.nlscript_syms; + + next_rule: + ; + } + + segment = segment->next; + } + while (segment != ld_state.output_segments->next); +} + + +/* Create creation of spection section symbols representing sections in the + output file. This is done for symbols like _GLOBAL_OFFSET_TABLE_ and + _DYNAMIC. */ +static void +create_special_section_symbol (struct symbol **symp, const char *name) +{ + if (*symp == NULL) + { + /* No symbol defined found yet. Create one. */ + struct symbol *newsym = (struct symbol *) + obstack_calloc (&ld_state.smem, sizeof (*newsym)); + + newsym->name = name; + // XXX Should we mark the symbol hidden? They are hardly useful + // used outside the current object. + + /* Add to the symbol table. */ + if (unlikely (ld_symbol_tab_insert (&ld_state.symbol_tab, + elf_hash (name), newsym) != 0)) + abort (); + + *symp = newsym; + } + else if ((*symp)->defined) + /* Cannot happen. We do use this symbol from any input file. */ + abort (); + + (*symp)->defined = 1; + (*symp)->type = STT_OBJECT; + + ++ld_state.nsymtab; +} diff --git a/src/ld.h b/src/ld.h new file mode 100644 index 00000000..a463a188 --- /dev/null +++ b/src/ld.h @@ -0,0 +1,1074 @@ +/* Copyright (C) 2001, 2002, 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef LD_H +#define LD_H 1 + +#include +#include +#include +#include +#include "xelf.h" + + +/* Recommended size of the buffer passed to ld_strerror. */ +#define ERRBUFSIZE (512) + +/* Character used to introduce version name after symbol. */ +#define VER_CHR '@' + + +/* Methods for handling archives. */ +enum extract_rule + { + defaultextract, /* Weak references don't cause archive member to + be used. */ + weakextract, /* Weak references cause archive member to be + extracted. */ + allextract /* Extract all archive members regardless of + references (aka whole-archive). */ + }; + + +/* Type of output file. */ +enum file_type + { + no_file_type = 0, /* None selected so far. */ + executable_file_type, /* Executable. */ + dso_file_type, /* DSO. */ + dso_needed_file_type, /* DSO introduced by DT_NEEDED. */ + relocatable_file_type, /* Relocatable object file. */ + archive_file_type /* Archive (input only). */ + }; + + +struct usedfiles +{ + /* The next file given at the command line. */ + struct usedfiles *next; + /* Nonzero if this file is the beginning of a group. */ + bool group_start; + /* Nonzero if this file is the end of a group. */ + bool group_end; + /* Pointer to the beginning of the group. It is necessary to + explain why we cannot simply use the 'next' pointer and have a + circular single-linked list like in many cases. The problem is + that the last archive of the group, if it is the last file of the + group, contains the only existing pointer to the next file we + have to look at. All files are initially connected via the + 'next' pointer in a single-linked list. Therefore we cannot + overwrite this value. It instead will be used once the group is + handled and we go on processing the rest of the files. */ + struct usedfiles *group_backref; + + /* Name/path of the file. */ + const char *fname; + /* Resolved file name. */ + const char *rfname; + /* Name used as reference in DT_NEEDED entries. This is normally + the SONAME. If it is missing it's normally the fname above. */ + const char *soname; + /* Handle for the SONAME in the string table. */ + struct Ebl_Strent *sonameent; + + /* Help to identify duplicates. */ + dev_t dev; + ino_t ino; + + enum + { + not_opened, + opened, + in_archive, + closed + } status; + + /* How to extract elements from archives. */ + enum extract_rule extract_rule; + + /* Lazy-loading rule. */ + bool lazyload; + + /* If this is a DSO the flag indicates whether the file is directly + used in a reference. */ + bool used; + + /* If nonzero this is the archive sequence number which can be used to + determine whether back refernces from -( -) or GROUP statements + have to be followed. */ + int archive_seq; + + /* Pointer to the record for the archive containing this file. */ + struct usedfiles *archive_file; + + /* Type of file. We have to distinguish these types since they + are searched for differently. */ + enum file_type file_type; + /* This is the ELF library handle for this file. */ + Elf *elf; + + /* The ELF header. */ +#if NATIVE_ELF != 0 + XElf_Ehdr *ehdr; +# define FILEINFO_EHDR(fi) (*(fi)) +#else + XElf_Ehdr ehdr; +# define FILEINFO_EHDR(fi) (fi) +#endif + + /* Index of the section header string table section. We use a + separate field and not the e_shstrndx field in the ELF header + since in case of a file with more than 64000 sections the index + might be stored in the section header of section zero. The + elf_getshstrndx() function can find the value but it is too + costly to repeat this call over and over. */ + size_t shstrndx; + + /* Info about the sections of the file. */ + struct scninfo + { + /* Handle for the section. Note that we can store a section + handle here because the file is not changing. This together + with the knowledge about the libelf library is enough for us to + assume the section reference remains valid at all times. */ + Elf_Scn *scn; + /* Section header. */ +#if NATIVE_ELF != 0 + XElf_Shdr *shdr; +# define SCNINFO_SHDR(si) (*(si)) +#else + XElf_Shdr shdr; +# define SCNINFO_SHDR(si) (si) +#endif + /* Offset of this files section in the combined section. */ + XElf_Off offset; + /* Index of the section in the output file. */ + Elf32_Word outscnndx; + /* Index of the output section in the 'allsection' array. */ + Elf32_Word allsectionsidx; + /* True if the section is used. */ + bool used; + /* Section group number. This is the index of the SHT_GROUP section. */ + Elf32_Word grpid; + /* Pointer back to the containing file information structure. */ + struct usedfiles *fileinfo; + /* List of symbols in this section (set only for merge-able sections). */ + struct symbol *symbols; + /* Size of relocations in this section. Only used for relocation + sections. */ + size_t relsize; + /* Pointer to next section which is put in the given output + section. */ + struct scninfo *next; + } *scninfo; + + /* List of section group sections. */ + struct scninfo *groups; + + /* The symbol table section. + + XXX Maybe support for more than one symbol table is needed. */ + Elf_Data *symtabdata; + /* Extra section index table section. */ + Elf_Data *xndxdata; + /* Dynamic symbol table section. */ + Elf_Data *dynsymtabdata; + /* The version number section. */ + Elf_Data *versymdata; + /* The defined versions. */ + Elf_Data *verdefdata; + /* Number of versions defined. */ + size_t nverdef; + /* True if the version with the given index number is used in the + output. */ + XElf_Versym *verdefused; + /* How many versions are used. */ + size_t nverdefused; + /* Handle for name of the version. */ + struct Ebl_Strent **verdefent; + /* The needed versions. */ + Elf_Data *verneeddata; + /* String table section associated with the symbol table. */ + Elf32_Word symstridx; + /* String table section associated with the dynamic symbol table. */ + Elf32_Word dynsymstridx; + /* Number of entries in the symbol table. */ + size_t nsymtab; + size_t nlocalsymbols; + size_t ndynsymtab; + /* Dynamic section. */ + Elf_Scn *dynscn; + + /* Indirection table for the symbols defined here. */ + Elf32_Word *symindirect; + Elf32_Word *dynsymindirect; + /* For undefined or common symbols we need a reference to the symbol + record. */ + struct symbol **symref; + struct symbol **dynsymref; + + /* This is the file descriptor. The value is -1 if the descriptor + was already closed. This can happen if we needed file descriptors + to open new files. */ + int fd; + /* This flag is true if the descriptor was passed to the generic + functions from somewhere else. This is an implementation detail; + no machine-specific code must use this flag. */ + bool fd_passed; + + /* True if any of the sections is merge-able. */ + bool has_merge_sections; +}; + + +/* Functions to test for the various types of files we handle. */ +static inline int +ld_file_rel_p (struct usedfiles *file) +{ + return (elf_kind (file->elf) == ELF_K_ELF + && FILEINFO_EHDR (file->ehdr).e_type == ET_REL); +} + +static inline int +ld_file_dso_p (struct usedfiles *file) +{ + return (elf_kind (file->elf) == ELF_K_ELF + && FILEINFO_EHDR (file->ehdr).e_type == ET_DYN); +} + +static inline int +ld_file_ar_p (struct usedfiles *file) +{ + return elf_kind (file->elf) == ELF_K_AR; +} + + +struct pathelement +{ + /* The next path to search. */ + struct pathelement *next; + /* The path name. */ + const char *pname; + /* Larger than zero if the directory exists, smaller than zero if not, + zero if it is not yet known. */ + int exist; +}; + + +/* Forward declaration. */ +struct ld_state; + + +/* Callback functions. */ +struct callbacks +{ + /* Library names passed to the linker as -lXXX represent files named + libXXX.YY. The YY part can have different forms, depending on the + architecture. The generic set is .so and .a (in this order). */ + const char **(*lib_extensions) (struct ld_state *) + __attribute__ ((__const__)); +#define LIB_EXTENSION(state) \ + DL_CALL_FCT ((state)->callbacks.lib_extensions, (state)) + + /* Process the given file. If the file is not yet open, open it. + The first parameter is a file descriptor for the file which can + be -1 to indicate the file has not yet been found. The second + parameter describes the file to be opened, the last one is the + state of the linker which among other information contain the + paths we look at.*/ + int (*file_process) (int fd, struct usedfiles *, struct ld_state *, + struct usedfiles **); +#define FILE_PROCESS(fd, file, state, nextp) \ + DL_CALL_FCT ((state)->callbacks.file_process, (fd, file, state, nextp)) + + /* Close the given file. */ + int (*file_close) (struct usedfiles *, struct ld_state *); +#define FILE_CLOSE(file, state) \ + DL_CALL_FCT ((state)->callbacks.file_close, (file, state)) + + /* Create the output sections now. This requires knowledge about + all the sections we will need. It may be necessary to sort the + sections in the order they are supposed to appear in the + executable. The sorting use many different kinds of information + to optimize the resulting binary. Important is to respect + segment boundaries and the needed alignment. The mode of the + segments will be determined afterwards automatically by the + output routines. */ + void (*create_sections) (struct ld_state *); +#define CREATE_SECTIONS(state) \ + DL_CALL_FCT ((state)->callbacks.create_sections, (state)) + + /* Determine whether we have any non-weak unresolved references left. */ + int (*flag_unresolved) (struct ld_state *); +#define FLAG_UNRESOLVED(state) \ + DL_CALL_FCT ((state)->callbacks.flag_unresolved, (state)) + + /* Create the sections which are generated by the linker and are not + present in the input file. */ + void (*generate_sections) (struct ld_state *); +#define GENERATE_SECTIONS(state) \ + DL_CALL_FCT ((state)->callbacks.generate_sections, (state)) + + /* Open the output file. The file name is given or "a.out". We + create as much of the ELF structure as possible. */ + int (*open_outfile) (struct ld_state *, int, int, int); +#define OPEN_OUTFILE(state, machine, class, data) \ + DL_CALL_FCT ((state)->callbacks.open_outfile, (state, machine, class, data)) + + /* Create the data for the output file. */ + int (*create_outfile) (struct ld_state *); +#define CREATE_OUTFILE(state) \ + DL_CALL_FCT ((state)->callbacks.create_outfile, (state)) + + /* Process a relocation section. */ + void (*relocate_section) (struct ld_state *, Elf_Scn *, struct scninfo *, + const Elf32_Word *); +#define RELOCATE_SECTION(state, outscn, first, dblindirect) \ + DL_CALL_FCT ((state)->callbacks.relocate_section, (state, outscn, first, \ + dblindirect)) + + /* Allocate a data buffer for the relocations of the given output + section. */ + void (*count_relocations) (struct ld_state *, struct scninfo *); +#define COUNT_RELOCATIONS(state, scninfo) \ + DL_CALL_FCT ((state)->callbacks.count_relocations, (state, scninfo)) + + /* Create relocations for executable or DSO. */ + void (*create_relocations) (struct ld_state *, const Elf32_Word *); +#define CREATE_RELOCATIONS(state, dlbindirect) \ + DL_CALL_FCT ((state)->callbacks.create_relocations, (state, dblindirect)) + + /* Finalize the output file. */ + int (*finalize) (struct ld_state *); +#define FINALIZE(state) \ + DL_CALL_FCT ((state)->callbacks.finalize, (state)) + + /* Check whether special section number is known. */ + bool (*special_section_number_p) (struct ld_state *, size_t); +#define SPECIAL_SECTION_NUMBER_P(state, number) \ + DL_CALL_FCT ((state)->callbacks.special_section_number_p, (state, number)) + + /* Check whether section type is known. */ + bool (*section_type_p) (struct ld_state *, XElf_Word); +#define SECTION_TYPE_P(state, type) \ + DL_CALL_FCT ((state)->callbacks.section_type_p, (state, type)) + + /* Return section flags for .dynamic section. */ + XElf_Xword (*dynamic_section_flags) (struct ld_state *); +#define DYNAMIC_SECTION_FLAGS(state) \ + DL_CALL_FCT ((state)->callbacks.dynamic_section_flags, (state)) + + /* Create the data structures for the .plt section and initialize it. */ + void (*initialize_plt) (struct ld_state *, Elf_Scn *scn); +#define INITIALIZE_PLT(state, scn) \ + DL_CALL_FCT ((state)->callbacks.initialize_plt, (state, scn)) + + /* Create the data structures for the .rel.plt section and initialize it. */ + void (*initialize_pltrel) (struct ld_state *, Elf_Scn *scn); +#define INITIALIZE_PLTREL(state, scn) \ + DL_CALL_FCT ((state)->callbacks.initialize_pltrel, (state, scn)) + + /* Finalize the .plt section the what belongs to them. */ + void (*finalize_plt) (struct ld_state *, size_t, size_t); +#define FINALIZE_PLT(state, nsym, nsym_dyn) \ + DL_CALL_FCT ((state)->callbacks.finalize_plt, (state, nsym, nsym_dyn)) + + /* Create the data structures for the .got section and initialize it. */ + void (*initialize_got) (struct ld_state *, Elf_Scn *scn); +#define INITIALIZE_GOT(state, scn) \ + DL_CALL_FCT ((state)->callbacks.initialize_got, (state, scn)) + + /* Return the tag corresponding to the native relocation type for + the platform. */ + int (*rel_type) (struct ld_state *); +#define REL_TYPE(state) \ + DL_CALL_FCT ((state)->callbacks.rel_type, (state)) +}; + + +/* Structure for symbol representation. This data structure is used a + lot, so size is important. */ +struct symbol +{ + /* Symbol name. */ + const char *name; + /* Size of the object. */ + XElf_Xword size; + /* Index of the symbol in the symbol table of the object. */ + size_t symidx; + /* Index of the symbol in the symbol table of the output file. */ + size_t outsymidx; + + /* Description where the symbol is found/needed. */ + size_t scndx; + struct usedfiles *file; + /* Index of the symbol table. */ + Elf32_Word symscndx; + + /* Index of the symbol in the dynamic symbol table of the output + file. Note that the value only needs to be 16 bit wide since + there cannot be more sections in an executable or DSO. */ + unsigned int outdynsymidx:16; + + /* Type of the symbol. */ + unsigned int type:4; + /* Various flags. */ + unsigned int defined:1; + unsigned int common:1; + unsigned int weak:1; + unsigned int added:1; + unsigned int merged:1; + /* Nonzero if the symbol is on the from_dso list. */ + unsigned int on_dsolist:1; + /* Nonzero if symbol needs copy relocation, reset when the + relocation has been created. */ + unsigned int need_copy:1; + unsigned int in_dso:1; + + union + { + /* Pointer to the handle created by the functions which create + merged section contents. We use 'void *' because there are + different implementations used. */ + void *handle; + XElf_Addr value; + } merge; + + /* Pointer to next/previous symbol on whatever list the symbol is. */ + struct symbol *next; + struct symbol *previous; + /* Pointer to next symbol of the same section (only set for merge-able + sections). */ + struct symbol *next_in_scn; +}; + + +/* Get the definition for the symbol table. */ +#include + +/* Simple single linked list of file names. */ +struct filename_list +{ + const char *name; + struct usedfiles *real; + struct filename_list *next; + bool group_start; + bool group_end; + bool as_needed; +}; + + +/* Data structure to describe expression in linker script. */ +struct expression +{ + enum expression_tag + { + exp_num, + exp_sizeof_headers, + exp_pagesize, + exp_id, + exp_mult, + exp_div, + exp_mod, + exp_plus, + exp_minus, + exp_and, + exp_or, + exp_align + } tag; + + union + { + uintmax_t num; + struct expression *child; + struct + { + struct expression *left; + struct expression *right; + } binary; + const char *str; + } val; +}; + + +/* Data structure for section name with flags. */ +struct input_section_name +{ + const char *name; + bool sort_flag; +}; + +/* File name mask with section name. */ +struct filemask_section_name +{ + const char *filemask; + const char *excludemask; + struct input_section_name *section_name; + bool keep_flag; +}; + +/* Data structure for assignments. */ +struct assignment +{ + const char *variable; + struct expression *expression; + struct symbol *sym; + bool provide_flag; +}; + + +/* Data structure describing input for an output section. */ +struct input_rule +{ + enum + { + input_section, + input_assignment + } tag; + + union + { + struct assignment *assignment; + struct filemask_section_name *section; + } val; + + struct input_rule *next; +}; + + +/* Data structure to describe output section. */ +struct output_section +{ + const char *name; + struct input_rule *input; + XElf_Addr max_alignment; + bool ignored; +}; + + +/* Data structure to describe output file format. */ +struct output_rule +{ + enum + { + output_section, + output_assignment + } tag; + + union + { + struct assignment *assignment; + struct output_section section; + } val; + + struct output_rule *next; +}; + + +/* List of all the segments the linker script describes. */ +struct output_segment +{ + int mode; + struct output_rule *output_rules; + struct output_segment *next; + + XElf_Off offset; + XElf_Addr addr; + XElf_Xword align; +}; + + +/* List of identifiers. */ +struct id_list +{ + union + { + enum id_type + { + id_str, /* Normal string. */ + id_all, /* "*", matches all. */ + id_wild /* Globbing wildcard string. */ + } id_type; + struct + { + bool local; + const char *versionname; + } s; + } u; + const char *id; + struct id_list *next; +}; + + +/* Version information. */ +struct version +{ + struct version *next; + struct id_list *local_names; + struct id_list *global_names; + const char *versionname; + const char *parentname; +}; + + +/* Head for list of sections. */ +struct scnhead +{ + /* Name of the sections. */ + const char *name; + + /* Accumulated flags for the sections. */ + XElf_Xword flags; + + /* Type of the sections. */ + XElf_Word type; + + /* Entry size. If there are differencs between the sections with + the same name this field contains 1. */ + XElf_Word entsize; + + /* If non-NULL pointer to group signature. */ + const char *grp_signature; + + /* Maximum alignment for all sections. */ + XElf_Word align; + + /* Distinguish between normal sections coming from the input file + and sections generated by the linker. */ + enum scn_kind + { + scn_normal, /* Section from the input file(s). */ + scn_dot_interp, /* Generated .interp section. */ + scn_dot_got, /* Generated .got section. */ + scn_dot_dynrel, /* Generated .rel.dyn section. */ + scn_dot_dynamic, /* Generated .dynamic section. */ + scn_dot_dynsym, /* Generated .dynsym section. */ + scn_dot_dynstr, /* Generated .dynstr section. */ + scn_dot_hash, /* Generated .hash section. */ + scn_dot_plt, /* Generated .plt section. */ + scn_dot_pltrel, /* Generated .rel.plt section. */ + scn_dot_version, /* Generated .gnu.version section. */ + scn_dot_version_r /* Generated .gnu.version_r section. */ + } kind; + + /* True is the section is used in the output. */ + bool used; + + /* Total size (only determined this way for relocation sections). */ + size_t relsize; + + /* Filled in by the section sorting to indicate which segment the + section goes in. */ + int segment_nr; + + /* Index of the output section. We cannot store the section handle + directly here since the handle is a pointer in a dynamically + allocated table which might move if it becomes too small for all + the sections. Using the index the correct value can be found at + all times. */ + XElf_Word scnidx; + + /* Index of the STT_SECTION entry for this section in the symbol + table. */ + XElf_Word scnsymidx; + + /* Address of the section in the output file. */ + XElf_Addr addr; + + /* Handle for the section name in the output file's section header + string table. */ + struct Ebl_Strent *nameent; + + /* Tail of list of symbols for this section. Only set if the + section is merge-able. */ + struct symbol *symbols; + + /* Pointer to last section. */ + struct scninfo *last; +}; + + +/* Define hash table for sections. */ +#include + +/* Define hash table for version symbols. */ +#include + + +/* State of the linker. */ +struct ld_state +{ + /* ELF backend library handle. */ + Ebl *ebl; + + /* List of all archives participating, in this order. */ + struct usedfiles *archives; + /* End of the list. */ + struct usedfiles *tailarchives; + /* If nonzero we are looking for the beginning of a group. */ + bool group_start_requested; + /* Pointer to the archive starting the group. */ + struct usedfiles *group_start_archive; + + /* List of the DSOs we found. */ + struct usedfiles *dsofiles; + /* Number of DSO files. */ + size_t ndsofiles; + /* Ultimate list of object files which are linked in. */ + struct usedfiles *relfiles; + + /* List the DT_NEEDED DSOs. */ + struct usedfiles *needed; + + /* Temporary storage for the parser. */ + struct filename_list *srcfiles; + + /* List of all the paths to look at. */ + struct pathelement *paths; + /* Tail of the list. */ + struct pathelement *tailpaths; + + /* User provided paths for lookup of DSOs. */ + struct pathelement *rpath; + struct pathelement *rpath_link; + struct pathelement *runpath; + struct pathelement *runpath_link; + struct Ebl_Strent *rxxpath_strent; + int rxxpath_tag; + + /* From the environment variable LD_LIBRARY_PATH. */ + struct pathelement *ld_library_path1; + struct pathelement *ld_library_path2; + + /* Name of the output file. */ + const char *outfname; + /* Name of the temporary file we initially create. */ + const char *tempfname; + /* File descriptor opened for the output file. */ + int outfd; + /* The ELF descriptor for the output file. */ + Elf *outelf; + + /* Type of output file. */ + enum file_type file_type; + + /* Is this a system library or not. */ + bool is_system_library; + + /* Page size to be assumed for the binary. */ + size_t pagesize; + + /* Name of the interpreter for dynamically linked objects. */ + const char *interp; + /* Index of the .interp section. */ + Elf32_Word interpscnidx; + + /* Optimization level. */ + unsigned long int optlevel; + + /* If true static linking is requested. */ + bool statically; + + /* How to extract elements from archives. */ + enum extract_rule extract_rule; + + /* Sequence number of the last archive we used. */ + int last_archive_used; + + /* If true print to stdout information about the files we are + trying to open. */ + bool trace_files; + + /* If true multiple definitions are not considered an error; the + first is used. */ + bool muldefs; + + /* If true undefined symbols when building DSOs are not fatal. */ + bool nodefs; + + /* If true add line indentifying link-editor to .comment section. */ + bool add_ld_comment; + + /* Stripping while linking. */ + enum + { + strip_none, + strip_debug, + strip_all, + strip_everything + } strip; + + /* The callback function vector. */ + struct callbacks callbacks; + + /* Name of the entry symbol. Can also be a numeric value. */ + const char *entry; + + /* The description of the segments in the output file. */ + struct output_segment *output_segments; + + /* List of the symbols we created from linker script definitions. */ + struct symbol *lscript_syms; + size_t nlscript_syms; + + /* Table with known symbols. */ + ld_symbol_tab symbol_tab; + + /* Table with used sections. */ + ld_section_tab section_tab; + + /* The list of sections once we collected them. */ + struct scnhead **allsections; + size_t nallsections; + size_t nusedsections; + size_t nnotesections; + + /* Beginning of the list of symbols which are still unresolved. */ + struct symbol *unresolved; + /* Number of truely unresolved entries in the list. */ + size_t nunresolved; + /* Number of truely unresolved, non-weak entries in the list. */ + size_t nunresolved_nonweak; + + /* List of common symbols. */ + struct symbol *common_syms; + /* Section for the common symbols. */ + struct scninfo *common_section; + + /* List of symbols defined in DSOs and used in a relocatable file. + DSO symbols not referenced in the relocatable files are not on + the list. If a symbol is on the list the on_dsolist field in the + 'struct symbol' is nonzero. */ + struct symbol *from_dso; + /* Number of entries in from_dso. */ + size_t nfrom_dso; + /* Number of entries in the dynamic symbol table. */ + size_t ndynsym; + /* Number of PLT entries from DSO references. */ + size_t nplt; + /* Number of PLT entries from DSO references. */ + size_t ngot; + /* Number of copy relocations. */ + size_t ncopy; + /* Section for copy relocations. */ + struct scninfo *copy_section; + + /* Keeping track of the number of symbols in the output file. */ + size_t nsymtab; + size_t nlocalsymbols; + + /* Special symbols. */ + struct symbol *init_symbol; + struct symbol *fini_symbol; + + /* The description of the segments in the output file as described + in the default linker script. This information will be used in + addition to the user-provided information. */ + struct output_segment *default_output_segments; + /* Search paths added by the default linker script. */ + struct pathelement *default_paths; + +#ifndef BASE_ELF_NAME + /* The handle of the ld backend library. */ + void *ldlib; +#endif + + /* String table for the section headers. */ + struct Ebl_Strtab *shstrtab; + + /* True if output file should contain symbol table. */ + bool need_symtab; + /* Symbol table section. */ + Elf32_Word symscnidx; + /* Extended section table section. */ + Elf32_Word xndxscnidx; + /* Symbol string table section. */ + Elf32_Word strscnidx; + + /* True if output file should contain dynamic symbol table. */ + bool need_dynsym; + /* Dynamic symbol table section. */ + Elf32_Word dynsymscnidx; + /* Dynamic symbol string table section. */ + Elf32_Word dynstrscnidx; + /* Dynamic symbol hash table. */ + size_t hashscnidx; + + /* Procedure linkage table section. */ + Elf32_Word pltscnidx; + /* Number of entries already in the PLT section. */ + size_t nplt_used; + /* Relocation for procedure linkage table section. */ + Elf32_Word pltrelscnidx; + + /* Global offset table section. */ + Elf32_Word gotscnidx; + + /* This section will hole all non-PLT relocations. */ + Elf32_Word reldynscnidx; + + /* Index of the sections to handle versioning. */ + Elf32_Word versymscnidx; + Elf32_Word verneedscnidx; + /* XXX Should the following names be verneed...? */ + /* Number of version definitions in input DSOs used. */ + int nverdefused; + /* Number of input DSOs using versioning. */ + int nverdeffile; + /* Index of next version. */ + int nextveridx; + + /* Hash table for version symbol strings. Only strings without + special characters are hashed here. */ + ld_version_str_tab version_str_tab; + /* At most one of the following two variables is set to true if either + global or local symbol binding is selected as the default. */ + bool default_bind_local; + bool default_bind_global; + + /* True if only used sections are used. */ + bool gc_sections; + + /* Array to determine final index of symbol. */ + Elf32_Word *dblindirect; + + /* Section group handling. */ + struct scngroup + { + Elf32_Word outscnidx; + int nscns; + struct member + { + struct scnhead *scn; + struct member *next; + } *member; + struct Ebl_Strent *nameent; + struct symbol *symbol; + struct scngroup *next; + } *groups; + + /* True if the output file needs a .got section. */ + bool need_got; + /* Number of relocations for GOT section caused. */ + size_t nrel_got; + + /* Number of entries needed in the .dynamic section. */ + int ndynamic; + /* To keep track of added entries. */ + int ndynamic_filled; + /* Index for the dynamic section. */ + Elf32_Word dynamicscnidx; + + /* Flags set in the DT_FLAGS word. */ + Elf32_Word dt_flags; + /* Flags set in the DT_FLAGS_1 word. */ + Elf32_Word dt_flags_1; + /* Flags set in the DT_FEATURE_1 word. */ + Elf32_Word dt_feature_1; + + /* Lazy-loading state for dependencies. */ + bool lazyload; + + /* True is DSOs which are not used in the linking process are not + recorded. */ + bool ignore_unused_dsos; + + + /* True if in executables all global symbols should be exported in + the dynamic symbol table. */ + bool export_all_dynamic; + + /* If DSO is generated, this is the SONAME. */ + const char *soname; + + /* List of all relocation sections. */ + struct scninfo *rellist; + /* Total size of non-PLT relocations. */ + size_t relsize_total; + + /* Record for the GOT symbol, if known. */ + struct symbol *got_symbol; + /* Record for the dynamic section symbol, if known. */ + struct symbol *dyn_symbol; + + /* Obstack used for small objects which will not be deleted. */ + struct obstack smem; +}; + + +/* The interface to the scanner. */ + +/* Parser entry point. */ +extern int ldparse (void); + +/* The input file. */ +extern FILE *ldin; + +/* Name of the input file. */ +extern const char *ldin_fname; + +/* Current line number. Must be reset for a new file. */ +extern int ldlineno; + +/* If nonzero we are currently parsing a version script. */ +extern int ld_scan_version_script; + +/* Flags defined in ld.c. */ +extern int verbose; +extern int conserve_memory; + + +/* Linker state. This contains all global information. */ +extern struct ld_state ld_state; + + +/* Generic ld helper functions. */ + +/* Append a new directory to search libraries in. */ +extern void ld_new_searchdir (const char *dir); + +/* Append a new file to the list of input files. */ +extern struct usedfiles *ld_new_inputfile (const char *fname, + enum file_type type); + + +/* These are the generic implementations for the callbacks used by ld. */ + +/* Initialize state object. This callback function is called after the + parameters are parsed but before any file is searched for. */ +extern int ld_prepare_state (const char *emulation); + + +/* Function to determine whether an object will be dynamically linked. */ +extern bool dynamically_linked_p (void); + +/* Helper functions for the architecture specific code. */ + +/* Checked whether the symbol is undefined and referenced from a DSO. */ +extern bool linked_from_dso_p (struct scninfo *scninfo, size_t symidx); +extern inline bool +linked_from_dso_p (struct scninfo *scninfo, size_t symidx) +{ + struct usedfiles *file = scninfo->fileinfo; + + /* If this symbol is not undefined in this file it cannot come from + a DSO. */ + if (symidx < file->nlocalsymbols) + return false; + + struct symbol *sym = file->symref[symidx]; + + return sym->defined && sym->in_dso; +} + +#endif /* ld.h */ diff --git a/src/ldgeneric.c b/src/ldgeneric.c new file mode 100644 index 00000000..1b6c7207 --- /dev/null +++ b/src/ldgeneric.c @@ -0,0 +1,6376 @@ +/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ld.h" +#include "list.h" + + +/* Prototypes for local functions. */ +static const char **ld_generic_lib_extensions (struct ld_state *) + __attribute__ ((__const__)); +static int ld_generic_file_close (struct usedfiles *fileinfo, + struct ld_state *statep); +static int ld_generic_file_process (int fd, struct usedfiles *fileinfo, + struct ld_state *statep, + struct usedfiles **nextp); +static void ld_generic_generate_sections (struct ld_state *statep); +static void ld_generic_create_sections (struct ld_state *statep); +static int ld_generic_flag_unresolved (struct ld_state *statep); +static int ld_generic_open_outfile (struct ld_state *statep, int machine, + int class, int data); +static int ld_generic_create_outfile (struct ld_state *statep); +static void ld_generic_relocate_section (struct ld_state *statep, + Elf_Scn *outscn, + struct scninfo *firstp, + const Elf32_Word *dblindirect); +static int ld_generic_finalize (struct ld_state *statep); +static bool ld_generic_special_section_number_p (struct ld_state *statep, + size_t number); +static bool ld_generic_section_type_p (struct ld_state *statep, + XElf_Word type); +static XElf_Xword ld_generic_dynamic_section_flags (struct ld_state *statep); +static void ld_generic_initialize_plt (struct ld_state *statep, Elf_Scn *scn); +static void ld_generic_initialize_pltrel (struct ld_state *statep, + Elf_Scn *scn); +static void ld_generic_initialize_got (struct ld_state *statep, Elf_Scn *scn); +static void ld_generic_finalize_plt (struct ld_state *statep, size_t nsym, + size_t nsym_dyn); +static int ld_generic_rel_type (struct ld_state *statep); +static void ld_generic_count_relocations (struct ld_state *statep, + struct scninfo *scninfo); +static void ld_generic_create_relocations (struct ld_state *statep, + const Elf32_Word *dblindirect); + +static int file_process2 (struct usedfiles *fileinfo); +static void mark_section_used (struct scninfo *scninfo, Elf32_Word shndx, + struct scninfo **grpscnp); + + +/* Map symbol index to struct symbol record. */ +static struct symbol **ndxtosym; + +/* String table reference to all symbols in the symbol table. */ +static struct Ebl_Strent **symstrent; + + +/* Check whether file associated with FD is a DSO. */ +static bool +is_dso_p (int fd) +{ + /* We have to read the 'e_type' field. It has the same size (16 + bits) in 32- and 64-bit ELF. */ + XElf_Half e_type; + + return (pread (fd, &e_type, sizeof (e_type), offsetof (XElf_Ehdr, e_type)) + == sizeof (e_type) + && e_type == ET_DYN); +} + + +/* Print the complete name of a file, including the archive it is + contained in. */ +static int +print_file_name (FILE *s, struct usedfiles *fileinfo, int first_level, + int newline) +{ + int npar = 0; + + if (fileinfo->archive_file != NULL) + { + npar = print_file_name (s, fileinfo->archive_file, 0, 0) + 1; + fputc_unlocked ('(', s); + fputs_unlocked (fileinfo->rfname, s); + + if (first_level) + while (npar-- > 0) + fputc_unlocked (')', s); + } + else + fputs_unlocked (fileinfo->rfname, s); + + if (first_level && newline) + fputc_unlocked ('\n', s); + + return npar; +} + + +/* Function to determine whether an object will be dynamically linked. */ +bool +dynamically_linked_p (void) +{ + return (ld_state.file_type == dso_file_type || ld_state.nplt > 0 + || ld_state.ngot > 0); +} + + +bool +linked_from_dso_p (struct scninfo *scninfo, size_t symidx) +{ + struct usedfiles *file = scninfo->fileinfo; + + /* If this symbol is not undefined in this file it cannot come from + a DSO. */ + if (symidx < file->nlocalsymbols) + return false; + + struct symbol *sym = file->symref[symidx]; + + return sym->defined && sym->in_dso; +} + + +/* Initialize state object. This callback function is called after the + parameters are parsed but before any file is searched for. */ +int +ld_prepare_state (const char *emulation) +{ + /* When generating DSO we normally allow undefined symbols. */ + ld_state.nodefs = true; + + /* To be able to detect problems we add a .comment section entry by + default. */ + ld_state.add_ld_comment = true; + + /* XXX We probably should find a better place for this. The index + of the first user-defined version is 2. */ + ld_state.nextveridx = 2; + + /* Pick an not too small number for the initial size of the tables. */ + ld_symbol_tab_init (&ld_state.symbol_tab, 1027); + ld_section_tab_init (&ld_state.section_tab, 67); + ld_version_str_tab_init (&ld_state.version_str_tab, 67); + + /* Initialize the section header string table. */ + ld_state.shstrtab = ebl_strtabinit (true); + if (ld_state.shstrtab == NULL) + error (EXIT_FAILURE, errno, gettext ("cannot create string table")); + + /* Initialize the callbacks. These are the defaults, the appropriate + backend can later install its own callbacks. */ + ld_state.callbacks.lib_extensions = ld_generic_lib_extensions; + ld_state.callbacks.file_process = ld_generic_file_process; + ld_state.callbacks.file_close = ld_generic_file_close; + ld_state.callbacks.generate_sections = ld_generic_generate_sections; + ld_state.callbacks.create_sections = ld_generic_create_sections; + ld_state.callbacks.flag_unresolved = ld_generic_flag_unresolved; + ld_state.callbacks.open_outfile = ld_generic_open_outfile; + ld_state.callbacks.create_outfile = ld_generic_create_outfile; + ld_state.callbacks.relocate_section = ld_generic_relocate_section; + ld_state.callbacks.finalize = ld_generic_finalize; + ld_state.callbacks.special_section_number_p = + ld_generic_special_section_number_p; + ld_state.callbacks.section_type_p = ld_generic_section_type_p; + ld_state.callbacks.dynamic_section_flags = ld_generic_dynamic_section_flags; + ld_state.callbacks.initialize_plt = ld_generic_initialize_plt; + ld_state.callbacks.initialize_pltrel = ld_generic_initialize_pltrel; + ld_state.callbacks.initialize_got = ld_generic_initialize_got; + ld_state.callbacks.finalize_plt = ld_generic_finalize_plt; + ld_state.callbacks.rel_type = ld_generic_rel_type; + ld_state.callbacks.count_relocations = ld_generic_count_relocations; + ld_state.callbacks.create_relocations = ld_generic_create_relocations; + +#ifndef BASE_ELF_NAME + /* Find the ld backend library. Use EBL to determine the name if + the user hasn't provided one on the command line. */ + if (emulation == NULL) + { + emulation = ebl_backend_name (ld_state.ebl); + assert (emulation != NULL); + } + size_t emulation_len = strlen (emulation); + + /* Construct the file name. */ + char *fname = (char *) alloca (sizeof "libld_" - 1 + emulation_len + + sizeof ".so"); + strcpy (mempcpy (stpcpy (fname, "libld_"), emulation, emulation_len), ".so"); + + /* Try loading. */ + void *h = dlopen (fname, RTLD_LAZY); + if (h == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot load ld backend library '%s': %s"), + fname, dlerror ()); + + /* Find the initializer. It must be present. */ + char *initname = (char *) alloca (emulation_len + sizeof "_ld_init"); + strcpy (mempcpy (initname, emulation, emulation_len), "_ld_init"); + int (*initfct) (struct ld_state *) + = (int (*) (struct ld_state *)) dlsym (h, initname); + + if (initfct == NULL) + error (EXIT_FAILURE, 0, gettext ("\ +cannot find init function in ld backend library '%s': %s"), + fname, dlerror ()); + + /* Store the handle. */ + ld_state.ldlib = h; + + /* Call the init function. */ + return initfct (&ld_state); +#else +# define INIT_FCT_NAME(base) _INIT_FCT_NAME(base) +# define _INIT_FCT_NAME(base) base##_ld_init + /* Declare and call the initialization function. */ + extern int INIT_FCT_NAME(BASE_ELF_NAME) (struct ld_state *); + return INIT_FCT_NAME(BASE_ELF_NAME) (&ld_state); +#endif +} + + +static int +check_for_duplicate2 (struct usedfiles *newp, struct usedfiles *list) +{ + struct usedfiles *first; + struct usedfiles *prevp; + + if (list == NULL) + return 0; + + prevp = list; + list = first = list->next; + do + { + /* When searching the needed list we might come across entries + for files which are not yet opened. Stop then, there is + nothing more to test. */ + if (likely (list->status == not_opened)) + break; + + if (unlikely (list->ino == newp->ino) + && unlikely (list->dev == newp->dev)) + { + close (newp->fd); + newp->fd = -1; + newp->status = closed; + if (newp->file_type == relocatable_file_type) + error (0, 0, gettext ("%s listed more than once as input"), + newp->rfname); + + return 1; + } + list = list->next; + } + while (likely (list != first)); + + return 0; +} + + +static int +check_for_duplicate (struct usedfiles *newp) +{ + struct stat st; + + if (unlikely (fstat (newp->fd, &st) < 0)) + { + close (newp->fd); + return errno; + } + + newp->dev = st.st_dev; + newp->ino = st.st_ino; + + return (check_for_duplicate2 (newp, ld_state.relfiles) + || check_for_duplicate2 (newp, ld_state.dsofiles) + || check_for_duplicate2 (newp, ld_state.needed)); +} + + +/* Find a file along the path described in the state. */ +static int +open_along_path2 (struct usedfiles *fileinfo, struct pathelement *path) +{ + const char *fname = fileinfo->fname; + size_t fnamelen = strlen (fname); + int err = ENOENT; + struct pathelement *firstp = path; + + if (path == NULL) + /* Cannot find anything since we have no path. */ + return ENOENT; + + do + { + if (likely (path->exist >= 0)) + { + /* Create the file name. */ + char *rfname = NULL; + size_t dirlen = strlen (path->pname); + int fd = -1; + + if (fileinfo->file_type == archive_file_type) + { + const char **exts = (ld_state.statically + ? (const char *[2]) { ".a", NULL } + : LIB_EXTENSION (&ld_state)); + + /* We have to create the actual file name. We prepend "lib" + and add one of the extensions the platform has. */ + while (*exts != NULL) + { + size_t extlen = strlen (*exts); + rfname = (char *) alloca (dirlen + 5 + fnamelen + extlen); + memcpy (mempcpy (stpcpy (mempcpy (rfname, path->pname, + dirlen), + "/lib"), + fname, fnamelen), + *exts, extlen + 1); + + fd = open (rfname, O_RDONLY); + if (likely (fd != -1) || errno != ENOENT) + { + err = fd == -1 ? errno : 0; + break; + } + + /* Next extension. */ + ++exts; + } + } + else + { + assert (fileinfo->file_type == dso_file_type + || fileinfo->file_type == dso_needed_file_type); + + rfname = (char *) alloca (dirlen + 1 + fnamelen + 1); + memcpy (stpcpy (mempcpy (rfname, path->pname, dirlen), "/"), + fname, fnamelen + 1); + + fd = open (rfname, O_RDONLY); + if (unlikely (fd == -1)) + err = errno; + } + + if (likely (fd != -1)) + { + /* We found the file. This also means the directory + exists. */ + fileinfo->fd = fd; + path->exist = 1; + + /* Check whether we have this file already loaded. */ + if (unlikely (check_for_duplicate (fileinfo) != 0)) + return EAGAIN; + + /* Make a copy of the name. */ + fileinfo->rfname = obstack_strdup (&ld_state.smem, rfname); + + if (unlikely (ld_state.trace_files)) + printf (fileinfo->file_type == archive_file_type + ? gettext ("%s (for -l%s)\n") + : gettext ("%s (for DT_NEEDED %s)\n"), + rfname, fname); + + return 0; + } + + /* The file does not exist. Maybe the whole directory doesn't. + Check it unless we know it exists. */ + if (unlikely (path->exist == 0)) + { + struct stat st; + + /* Keep only the directory name. Note that the path + might be relative. This doesn't matter here. We do + the test in any case even if there is the chance that + somebody wants to change the programs working + directory at some point which would make the result + of this test void. Since changing the working + directory is completely wrong we are not taking this + case into account. */ + rfname[dirlen] = '\0'; + if (unlikely (stat (rfname, &st) < 0) || ! S_ISDIR (st.st_mode)) + /* The directory does not exist or the named file is no + directory. */ + path->exist = -1; + else + path->exist = 1; + } + } + + /* Next path element. */ + path = path->next; + } + while (likely (err == ENOENT && path != firstp)); + + return err; +} + + +static int +open_along_path (struct usedfiles *fileinfo) +{ + const char *fname = fileinfo->fname; + int err = ENOENT; + + if (fileinfo->file_type == relocatable_file_type) + { + /* Only libraries are searched along the path. */ + fileinfo->fd = open (fname, O_RDONLY); + + if (likely (fileinfo->fd != -1)) + { + /* We found the file. */ + if (unlikely (ld_state.trace_files)) + print_file_name (stdout, fileinfo, 1, 1); + + return check_for_duplicate (fileinfo); + } + + /* If the name is an absolute path we are done. */ + err = errno; + } + else + { + /* If the user specified two parts to the LD_LIBRARY_PATH variable + try the first part now. */ + err = open_along_path2 (fileinfo, ld_state.ld_library_path1); + + /* Try the user-specified path next. */ + if (err == ENOENT) + err = open_along_path2 (fileinfo, + fileinfo->file_type == archive_file_type + ? ld_state.paths : ld_state.rpath_link); + + /* Then the second part of the LD_LIBRARY_PATH value. */ + if (unlikely (err == ENOENT)) + { + err = open_along_path2 (fileinfo, ld_state.ld_library_path2); + + /* In case we look for a DSO handle now the RUNPATH. */ + if (err == ENOENT) + { + if (fileinfo->file_type == dso_file_type) + err = open_along_path2 (fileinfo, ld_state.runpath_link); + + /* Finally the path from the default linker script. */ + if (err == ENOENT) + err = open_along_path2 (fileinfo, ld_state.default_paths); + } + } + } + + if (unlikely (err != 0) + && (err != EAGAIN || fileinfo->file_type == relocatable_file_type)) + error (0, err, gettext ("cannot open %s"), fileinfo->fname); + + return err; +} + + +static void +check_type_and_size (const XElf_Sym *sym, struct usedfiles *fileinfo, + struct symbol *oldp) +{ + /* We check the type and size of the symbols. In both cases the + information can be missing (size is zero, type is STT_NOTYPE) in + which case we issue no warnings. Otherwise everything must + match. If the type does not match there is no point in checking + the size. */ + + if (XELF_ST_TYPE (sym->st_info) != STT_NOTYPE && oldp->type != STT_NOTYPE + && unlikely (oldp->type != XELF_ST_TYPE (sym->st_info))) + { + char buf1[64]; + char buf2[64]; + + error (0, 0, gettext ("\ +Warning: type of `%s' changed from %s in %s to %s in %s"), + oldp->name, + ebl_symbol_type_name (ld_state.ebl, oldp->type, + buf1, sizeof (buf1)), + oldp->file->rfname, + ebl_symbol_type_name (ld_state.ebl, XELF_ST_TYPE (sym->st_info), + buf2, sizeof (buf2)), + fileinfo->rfname); + } + else if (XELF_ST_TYPE (sym->st_info) == STT_OBJECT + && oldp->size != 0 + && unlikely (oldp->size != sym->st_size)) + error (0, 0, gettext ("\ +Warning: size of `%s' changed from %" PRIu64 " in %s to %" PRIu64 " in %s"), + oldp->name, (uint64_t) oldp->size, oldp->file->rfname, + (uint64_t) sym->st_size, fileinfo->rfname); +} + + +static int +check_definition (const XElf_Sym *sym, size_t symidx, + struct usedfiles *fileinfo, struct symbol *oldp) +{ + int result = 0; + bool old_in_dso = FILEINFO_EHDR (oldp->file->ehdr).e_type == ET_DYN; + bool new_in_dso = FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_DYN; + bool use_new_def = false; + + if (sym->st_shndx != SHN_UNDEF + && (! oldp->defined + || (sym->st_shndx != SHN_COMMON && oldp->common && ! new_in_dso) + || (old_in_dso && ! new_in_dso))) + { + /* We found a definition for a previously undefined symbol or a + real definition for a previous common-only definition or a + redefinition of a symbol definition in an object file + previously defined in a DSO. First perform some tests which + will show whether the common is really matching the + definition. */ + check_type_and_size (sym, fileinfo, oldp); + + /* We leave the next element intact to not interrupt the list + with the unresolved symbols. Whoever walks the list will + have to check the `defined' flag. But we remember that this + list element is not unresolved anymore. */ + if (! oldp->defined) + { + /* Remove from the list. */ + --ld_state.nunresolved; + if (! oldp->weak) + --ld_state.nunresolved_nonweak; + CDBL_LIST_DEL (ld_state.unresolved, oldp); + } + else if (oldp->common) + /* Remove from the list. */ + CDBL_LIST_DEL (ld_state.common_syms, oldp); + + /* Use the values of the definition from now on. */ + use_new_def = true; + } + else if (sym->st_shndx != SHN_UNDEF + && unlikely (! oldp->common) + && oldp->defined + && sym->st_shndx != SHN_COMMON + /* Multiple definitions are no fatal errors if the -z muldefs flag + is used. We don't warn about the multiple definition unless we + are told to be verbose. */ + && (!ld_state.muldefs || verbose) + && ! old_in_dso && fileinfo->file_type == relocatable_file_type) + { + /* We have a double definition. This is a problem. */ + char buf[64]; + XElf_Sym_vardef (oldsym); + struct usedfiles *oldfile; + const char *scnname; + Elf32_Word xndx; + size_t shndx; + size_t shnum; + + if (elf_getshnum (fileinfo->elf, &shnum) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot determine number of sections: %s"), + elf_errmsg (-1)); + + /* XXX Use only ebl_section_name. */ + if (sym->st_shndx < SHN_LORESERVE // || sym->st_shndx > SHN_HIRESERVE + && sym->st_shndx < shnum) + scnname = elf_strptr (fileinfo->elf, + fileinfo->shstrndx, + SCNINFO_SHDR (fileinfo->scninfo[sym->st_shndx].shdr).sh_name); + else + // XXX extended section + scnname = ebl_section_name (ld_state.ebl, sym->st_shndx, 0, + buf, sizeof (buf), NULL, shnum); + + /* XXX Print source file and line number. */ + print_file_name (stderr, fileinfo, 1, 0); + fprintf (stderr, + gettext ("(%s+%#" PRIx64 "): multiple definition of %s `%s'\n"), + scnname, + (uint64_t) sym->st_value, + ebl_symbol_type_name (ld_state.ebl, XELF_ST_TYPE (sym->st_info), + buf, sizeof (buf)), + oldp->name); + + oldfile = oldp->file; + xelf_getsymshndx (oldfile->symtabdata, oldfile->xndxdata, oldp->symidx, + oldsym, xndx); + if (oldsym == NULL) + /* This should never happen since the same call + succeeded before. */ + abort (); + + shndx = oldsym->st_shndx; + if (unlikely (oldsym->st_shndx == SHN_XINDEX)) + shndx = xndx; + + /* XXX Use only ebl_section_name. */ + if (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE) + scnname = elf_strptr (oldfile->elf, + oldfile->shstrndx, + SCNINFO_SHDR (oldfile->scninfo[shndx].shdr).sh_name); + else + scnname = ebl_section_name (ld_state.ebl, oldsym->st_shndx, shndx, buf, + sizeof (buf), NULL, shnum); + + /* XXX Print source file and line number. */ + print_file_name (stderr, oldfile, 1, 0); + fprintf (stderr, gettext ("(%s+%#" PRIx64 "): first defined here\n"), + scnname, (uint64_t) oldsym->st_value); + + if (likely (!ld_state.muldefs)) + result = 1; + } + else if (old_in_dso && fileinfo->file_type == relocatable_file_type + && sym->st_shndx != SHN_UNDEF) + /* We use the definition from a normal relocatable file over the + definition in a DSO. This is what the dynamic linker would + do, too. */ + use_new_def = true; + else if (old_in_dso && !new_in_dso && oldp->defined && !oldp->on_dsolist) + { + CDBL_LIST_ADD_REAR (ld_state.from_dso, oldp); + ++ld_state.nfrom_dso; + + /* If the object is a function we allocate a PLT entry, + otherwise only a GOT entry. */ + if (oldp->type == STT_FUNC) + ++ld_state.nplt; + else + ++ld_state.ngot; + + oldp->on_dsolist = 1; + } + else if (oldp->common && sym->st_shndx == SHN_COMMON) + { + /* The symbol size is the largest of all common definitions. */ + oldp->size = MAX (oldp->size, sym->st_size); + /* Similarly for the alignment. */ + oldp->merge.value = MAX (oldp->merge.value, sym->st_value); + } + + if (unlikely (use_new_def)) + { + /* Adjust the symbol record appropriately and remove + the symbol from the list of symbols which are taken from DSOs. */ + if (old_in_dso && fileinfo->file_type == relocatable_file_type) + { + CDBL_LIST_DEL (ld_state.from_dso, oldp); + --ld_state.nfrom_dso; + + if (likely (oldp->type == STT_FUNC)) + --ld_state.nplt; + else + --ld_state.ngot; + + oldp->on_dsolist = 0; + } + + /* Use the values of the definition from now on. */ + oldp->size = sym->st_size; + oldp->type = XELF_ST_TYPE (sym->st_info); + oldp->symidx = symidx; + oldp->scndx = sym->st_shndx; + //oldp->symscndx = THESYMSCNDX must be passed; + oldp->file = fileinfo; + oldp->defined = 1; + oldp->in_dso = new_in_dso; + oldp->common = sym->st_shndx == SHN_COMMON; + if (likely (fileinfo->file_type == relocatable_file_type)) + { + /* If the definition comes from a DSO we pertain the weak flag + and it's indicating whether the reference is weak or not. */ + oldp->weak = XELF_ST_BIND (sym->st_info) == STB_WEAK; + + if (sym->st_shndx != SHN_COMMON) + { + struct scninfo *ignore; + mark_section_used (&fileinfo->scninfo[sym->st_shndx], + sym->st_shndx, &ignore); + } + } + + /* Add to the list of symbols used from DSOs if necessary. */ + if (new_in_dso && !old_in_dso) + { + CDBL_LIST_ADD_REAR (ld_state.from_dso, oldp); + ++ld_state.nfrom_dso; + + /* If the object is a function we allocate a PLT entry, + otherwise only a GOT entry. */ + if (oldp->type == STT_FUNC) + ++ld_state.nplt; + else + ++ld_state.ngot; + + oldp->on_dsolist = 1; + } + else if (sym->st_shndx == SHN_COMMON) + { + /* Store the alignment. */ + oldp->merge.value = sym->st_value; + + CDBL_LIST_ADD_REAR (ld_state.common_syms, oldp); + } + } + + return result; +} + + +static struct scninfo * +find_section_group (struct usedfiles *fileinfo, Elf32_Word shndx, + Elf_Data **datap) +{ + struct scninfo *runp; + + for (runp = fileinfo->groups; runp != NULL; runp = runp->next) + if (!runp->used) + { + Elf32_Word *grpref; + size_t cnt; + Elf_Data *data; + + data = elf_getdata (runp->scn, NULL); + if (data == NULL) + error (EXIT_FAILURE, 0, + gettext ("%s: cannot get section group data: %s"), + fileinfo->fname, elf_errmsg (-1)); + + /* There cannot be another data block. */ + assert (elf_getdata (runp->scn, data) == NULL); + + grpref = (Elf32_Word *) data->d_buf; + cnt = data->d_size / sizeof (Elf32_Word); + /* Note that we stop after looking at index 1 since index 0 + contains the flags for the section group. */ + while (cnt > 1) + if (grpref[--cnt] == shndx) + { + *datap = data; + return runp; + } + } + + /* If we come here no section group contained the given section + despite the SHF_GROUP flag. This is an error in the input + file. */ + error (EXIT_FAILURE, 0, gettext ("\ +%s: section '%s' with group flag set does not belong to any group"), + fileinfo->fname, + elf_strptr (fileinfo->elf, fileinfo->shstrndx, + SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_name)); + return NULL; +} + + +/* Mark all sections which belong to the same group as section SHNDX + as used. */ +static void +mark_section_group (struct usedfiles *fileinfo, Elf32_Word shndx, + struct scninfo **grpscnp) +{ + /* First locate the section group. There can be several (many) of + them. */ + size_t cnt; + Elf32_Word *grpref; + Elf_Data *data; + struct scninfo *grpscn = find_section_group (fileinfo, shndx, &data); + *grpscnp = grpscn; + + /* Mark all the sections as used. + + XXX Two possible problems here: + + - the gABI says "The section must be referenced by a section of type + SHT_GROUP". I hope everybody reads this as "exactly one section". + + - section groups are also useful to mark the debugging section which + belongs to a text section. Unconditionally adding debugging sections + is therefore probably not what is wanted if stripping is required. */ + + /* Mark the section group as handled. */ + grpscn->used = true; + + grpref = (Elf32_Word *) data->d_buf; + cnt = data->d_size / sizeof (Elf32_Word); + while (cnt > 1) + { + Elf32_Word idx = grpref[--cnt]; + XElf_Shdr *shdr = &SCNINFO_SHDR (fileinfo->scninfo[idx].shdr); + + if (fileinfo->scninfo[idx].grpid != 0) + error (EXIT_FAILURE, 0, gettext ("\ +%s: section [%2d] '%s' is in more than one section group"), + fileinfo->fname, (int) idx, + elf_strptr (fileinfo->elf, fileinfo->shstrndx, shdr->sh_name)); + + fileinfo->scninfo[idx].grpid = grpscn->grpid; + + if (ld_state.strip == strip_none + /* If we are stripping, remove debug sections. */ + || (!ebl_debugscn_p (ld_state.ebl, + elf_strptr (fileinfo->elf, fileinfo->shstrndx, + shdr->sh_name)) + /* And the relocation sections for the debug sections. */ + && ((shdr->sh_type != SHT_RELA && shdr->sh_type != SHT_REL) + || !ebl_debugscn_p (ld_state.ebl, + elf_strptr (fileinfo->elf, + fileinfo->shstrndx, + SCNINFO_SHDR (fileinfo->scninfo[shdr->sh_info].shdr).sh_name))))) + { + struct scninfo *ignore; + + mark_section_used (&fileinfo->scninfo[idx], idx, &ignore); + } + } +} + + +static void +mark_section_used (struct scninfo *scninfo, Elf32_Word shndx, + struct scninfo **grpscnp) +{ + if (likely (scninfo->used)) + /* Nothing to be done. */ + return; + + /* We need this section. */ + scninfo->used = true; + + /* Make sure the section header has been read from the file. */ + XElf_Shdr *shdr = &SCNINFO_SHDR (scninfo->shdr); +#if NATIVE_ELF + if (unlikely (scninfo->shdr == NULL)) +#else + if (unlikely (scninfo->shdr.sh_type == SHT_NULL)) +#endif + { +#if NATIVE_ELF != 0 + shdr = xelf_getshdr (scninfo->scn, scninfo->shdr); +#else + xelf_getshdr_copy (scninfo->scn, shdr, scninfo->shdr); +#endif + if (unlikely (shdr == NULL)) + /* Something is very wrong. The calling code will notice it + soon and print a message. */ + return; + } + + /* Handle section linked by 'sh_link'. */ + if (unlikely (shdr->sh_link != 0)) + { + struct scninfo *ignore; + mark_section_used (&scninfo->fileinfo->scninfo[shdr->sh_link], + shdr->sh_link, &ignore); + } + + /* Handle section linked by 'sh_info'. */ + if (unlikely (shdr->sh_info != 0) && (shdr->sh_flags & SHF_INFO_LINK)) + { + struct scninfo *ignore; + mark_section_used (&scninfo->fileinfo->scninfo[shdr->sh_info], + shdr->sh_info, &ignore); + } + + if (unlikely (shdr->sh_flags & SHF_GROUP) && ld_state.gc_sections) + /* Find the section group which contains this section. */ + mark_section_group (scninfo->fileinfo, shndx, grpscnp); +} + + +/* We collect all sections in a hashing table. All sections with the + same name are collected in a list. Note that we do not determine + which sections are finally collected in the same output section + here. This would be terribly inefficient. It will be done later. */ +static void +add_section (struct usedfiles *fileinfo, struct scninfo *scninfo) +{ + struct scnhead *queued; + struct scnhead search; + unsigned long int hval; + XElf_Shdr *shdr = &SCNINFO_SHDR (scninfo->shdr); + struct scninfo *grpscn = NULL; + Elf_Data *grpscndata = NULL; + + /* See whether we can determine right away whether we need this + section in the output. + + XXX I assume here that --gc-sections only affects extraction + from an archive. If it also affects objects files given on + the command line then somebody must explain to me how the + dependency analysis should work. Should the entry point be + the root? What if it is a numeric value? */ + if (!scninfo->used + && (ld_state.strip == strip_none + || (shdr->sh_flags & SHF_ALLOC) != 0 + || shdr->sh_type == SHT_NOTE + || (shdr->sh_type == SHT_PROGBITS + && strcmp (elf_strptr (fileinfo->elf, + fileinfo->shstrndx, + shdr->sh_name), ".comment") == 0)) + && (fileinfo->status != in_archive || !ld_state.gc_sections)) + /* Mark as used and handle reference recursively if necessary. */ + mark_section_used (scninfo, elf_ndxscn (scninfo->scn), &grpscn); + + if ((shdr->sh_flags & SHF_GROUP) && grpscn == NULL) + /* Determine the symbol which name constitutes the signature + for the section group. */ + grpscn = find_section_group (fileinfo, elf_ndxscn (scninfo->scn), + &grpscndata); + assert (grpscn == NULL || grpscn->symbols->name != NULL); + + /* Determine the section name. */ + search.name = elf_strptr (fileinfo->elf, fileinfo->shstrndx, shdr->sh_name); + search.type = shdr->sh_type; + search.flags = shdr->sh_flags; + search.entsize = shdr->sh_entsize; + search.grp_signature = grpscn != NULL ? grpscn->symbols->name : NULL; + search.kind = scn_normal; + hval = elf_hash (search.name); + + /* Find already queued sections. */ + queued = ld_section_tab_find (&ld_state.section_tab, hval, &search); + if (queued != NULL) + { + bool is_comdat = false; + + /* If this section is part of a COMDAT section group we simply + ignore it since we already have a copy. */ + if (unlikely (shdr->sh_flags & SHF_GROUP)) + { + /* Get the data of the section group section. */ + if (grpscndata == NULL) + { + grpscndata = elf_getdata (grpscn->scn, NULL); + assert (grpscndata != NULL); + } + + /* XXX Possibly unaligned memory access. */ + is_comdat = ((Elf32_Word *) grpscndata->d_buf)[0] & GRP_COMDAT; + } + + if (!is_comdat) + { + /* No COMDAT section, we use the data. */ + scninfo->next = queued->last->next; + queued->last = queued->last->next = scninfo; + + queued->flags = SH_FLAGS_COMBINE (queued->flags, shdr->sh_flags); + queued->align = MAX (queued->align, shdr->sh_addralign); + } + } + else + { + /* We do not use obstacks here since the memory might be + deallocated. */ + queued = (struct scnhead *) xcalloc (sizeof (struct scnhead), 1); + queued->kind = scn_normal; + queued->name = search.name; + queued->type = shdr->sh_type; + queued->flags = shdr->sh_flags; + queued->align = shdr->sh_addralign; + queued->entsize = shdr->sh_entsize; + queued->grp_signature = grpscn != NULL ? grpscn->symbols->name : NULL; + queued->segment_nr = ~0; + queued->last = scninfo->next = scninfo; + + /* Add to the hash table and possibly overwrite existing value. */ + ld_section_tab_insert (&ld_state.section_tab, hval, queued); + } +} + + +static int +add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype) +{ + size_t scncnt; + size_t cnt; + Elf_Data *symtabdata = NULL; + Elf_Data *xndxdata = NULL; + Elf_Data *versymdata = NULL; + Elf_Data *verdefdata = NULL; + Elf_Data *verneeddata = NULL; + size_t symstridx = 0; + size_t nsymbols = 0; + size_t nlocalsymbols = 0; + bool has_merge_sections = false; + + /* Prerequisites. */ + assert (fileinfo->elf != NULL); + + /* Allocate memory for the sections. */ + if (unlikely (elf_getshnum (fileinfo->elf, &scncnt) < 0)) + error (EXIT_FAILURE, 0, + gettext ("cannot determine number of sections: %s"), + elf_errmsg (-1)); + + fileinfo->scninfo = (struct scninfo *) + obstack_calloc (&ld_state.smem, scncnt * sizeof (struct scninfo)); + + /* Read all the section headers and find the symbol table. Note + that we don't skip the section with index zero. Even though the + section itself is always empty the section header contains + informaton for the case when the section index for the section + header string table is too large to fit in the ELF header. */ + for (cnt = 0; cnt < scncnt; ++cnt) + { + /* Store the handle for the section. */ + fileinfo->scninfo[cnt].scn = elf_getscn (fileinfo->elf, cnt); + + /* Get the ELF section header and data. */ + XElf_Shdr *shdr; +#if NATIVE_ELF != 0 + if (fileinfo->scninfo[cnt].shdr == NULL) +#else + if (fileinfo->scninfo[cnt].shdr.sh_type == SHT_NULL) +#endif + { +#if NATIVE_ELF != 0 + shdr = xelf_getshdr (fileinfo->scninfo[cnt].scn, + fileinfo->scninfo[cnt].shdr); +#else + xelf_getshdr_copy (fileinfo->scninfo[cnt].scn, shdr, + fileinfo->scninfo[cnt].shdr); +#endif + if (shdr == NULL) + { + /* This should never happen. */ + fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), + fileinfo->rfname, __FILE__, __LINE__); + return 1; + } + } + else + shdr = &SCNINFO_SHDR (fileinfo->scninfo[cnt].shdr); + + Elf_Data *data = elf_getdata (fileinfo->scninfo[cnt].scn, NULL); + + /* Check whether this section is marked as merge-able. */ + has_merge_sections |= (shdr->sh_flags & SHF_MERGE) != 0; + + /* Get the ELF section header and data. */ + /* Make the file structure available. */ + fileinfo->scninfo[cnt].fileinfo = fileinfo; + + if (unlikely (shdr->sh_type == SHT_SYMTAB) + || unlikely (shdr->sh_type == SHT_DYNSYM)) + { + if (shdr->sh_type == SHT_SYMTAB) + { + assert (fileinfo->symtabdata == NULL); + fileinfo->symtabdata = data; + fileinfo->nsymtab = shdr->sh_size / shdr->sh_entsize; + fileinfo->nlocalsymbols = shdr->sh_info; + fileinfo->symstridx = shdr->sh_link; + } + else + { + assert (fileinfo->dynsymtabdata == NULL); + fileinfo->dynsymtabdata = data; + fileinfo->ndynsymtab = shdr->sh_size / shdr->sh_entsize; + fileinfo->dynsymstridx = shdr->sh_link; + } + + /* If we are looking for the normal symbol table we just + found it. */ + if (secttype == shdr->sh_type) + { + assert (symtabdata == NULL); + symtabdata = data; + symstridx = shdr->sh_link; + nsymbols = shdr->sh_size / shdr->sh_entsize; + nlocalsymbols = shdr->sh_info; + } + } + else if (unlikely (shdr->sh_type == SHT_SYMTAB_SHNDX)) + { + assert (xndxdata == NULL); + fileinfo->xndxdata = xndxdata = data; + } + else if (unlikely (shdr->sh_type == SHT_GNU_versym)) + { + assert (versymdata == 0); + fileinfo->versymdata = versymdata = data; + } + else if (unlikely (shdr->sh_type == SHT_GNU_verdef)) + { + size_t nversions; + + assert (verdefdata == 0); + fileinfo->verdefdata = verdefdata = data; + + /* Allocate the arrays flagging the use of the version and + to track of allocated names. */ + fileinfo->nverdef = nversions = shdr->sh_info; + /* We have NVERSIONS + 1 because the indeces used to access the + sectino start with one; zero represents local binding. */ + fileinfo->verdefused = (XElf_Versym *) + obstack_calloc (&ld_state.smem, + sizeof (XElf_Versym) * (nversions + 1)); + fileinfo->verdefent = (struct Ebl_Strent **) + obstack_alloc (&ld_state.smem, + sizeof (struct Ebl_Strent *) * (nversions + 1)); + } + else if (unlikely (shdr->sh_type == SHT_GNU_verneed)) + { + assert (verneeddata == 0); + fileinfo->verneeddata = verneeddata = data; + } + else if (unlikely (shdr->sh_type == SHT_DYNAMIC)) + { + assert (fileinfo->dynscn == NULL); + fileinfo->dynscn = fileinfo->scninfo[cnt].scn; + } + else if (unlikely (shdr->sh_type == SHT_GROUP)) + { + Elf_Scn *symscn; + XElf_Shdr_vardef (symshdr); + Elf_Data *symdata; + + if (FILEINFO_EHDR (fileinfo->ehdr).e_type != ET_REL) + error (EXIT_FAILURE, 0, gettext ("\ +%s: only files of type ET_REL might contain section groups"), + fileinfo->fname); + + fileinfo->scninfo[cnt].next = fileinfo->groups; + fileinfo->scninfo[cnt].grpid = cnt; + fileinfo->groups = &fileinfo->scninfo[cnt]; + + /* Determine the signature. We create a symbol record for + it. Only the name element is important. */ + fileinfo->scninfo[cnt].symbols = (struct symbol *) + obstack_calloc (&ld_state.smem, sizeof (struct symbol)); + + symscn = elf_getscn (fileinfo->elf, shdr->sh_link); + xelf_getshdr (symscn, symshdr); + symdata = elf_getdata (symscn, NULL); + if (symshdr != NULL) + { + XElf_Sym_vardef (sym); + + /* We don't need the section index and therefore we don't + have to use 'xelf_getsymshndx'. */ + xelf_getsym (symdata, shdr->sh_info, sym); + if (sym != NULL) + { + struct symbol *symbol = fileinfo->scninfo[cnt].symbols; + + symbol->name = elf_strptr (fileinfo->elf, symshdr->sh_link, + sym->st_name); + symbol->symidx = shdr->sh_info; + symbol->file = fileinfo; + } + } + if (fileinfo->scninfo[cnt].symbols->name == NULL) + error (EXIT_FAILURE, 0, gettext ("\ +%s: cannot determine signature of section group [%2zd] '%s': %s"), + fileinfo->fname, + elf_ndxscn (fileinfo->scninfo[cnt].scn), + elf_strptr (fileinfo->elf, fileinfo->shstrndx, + shdr->sh_name), + elf_errmsg (-1)); + + /* The 'used' flag is used to indicate when the information + in the section group is used to mark all other sections + as used. So it must not be true yet. */ + assert (fileinfo->scninfo[cnt].used == false); + } + else if (! SECTION_TYPE_P (&ld_state, shdr->sh_type) + && unlikely ((shdr->sh_flags & SHF_OS_NONCONFORMING) != 0)) + /* According to the gABI it is a fatal error if the file contains + a section with unknown type and the SHF_OS_NONCONFORMING flag + set. */ + error (EXIT_FAILURE, 0, + gettext ("%s: section '%s' has unknown type: %d"), + fileinfo->fname, + elf_strptr (fileinfo->elf, fileinfo->shstrndx, + shdr->sh_name), + (int) shdr->sh_type); + /* We don't have to add a few section types here. These will be + generated from scratch for the new output file. We also + don't add the sections of DSOs here since these sections are + not used in the resulting object file. */ + else if (likely (fileinfo->file_type == relocatable_file_type) + && likely (cnt > 0) + && likely (shdr->sh_type == SHT_PROGBITS + || shdr->sh_type == SHT_RELA + || shdr->sh_type == SHT_REL + || shdr->sh_type == SHT_NOTE + || shdr->sh_type == SHT_NOBITS + || shdr->sh_type == SHT_INIT_ARRAY + || shdr->sh_type == SHT_FINI_ARRAY + || shdr->sh_type == SHT_PREINIT_ARRAY)) + add_section (fileinfo, &fileinfo->scninfo[cnt]); + } + + /* Handle the symbols. Record defined and undefined symbols in the + hash table. In theory there can be a file without any symbol + table. */ + if (likely (symtabdata != NULL)) + { + /* In case this file contains merge-able sections we have to + locate the symbols which are in these sections. */ + fileinfo->has_merge_sections = has_merge_sections; + if (likely (has_merge_sections)) + { + fileinfo->symref = (struct symbol **) + obstack_calloc (&ld_state.smem, + nsymbols * sizeof (struct symbol *)); + + /* Only handle the local symbols here. */ + for (cnt = 0; cnt < nlocalsymbols; ++cnt) + { + Elf32_Word shndx; + XElf_Sym_vardef (sym); + + xelf_getsymshndx (symtabdata, xndxdata, cnt, sym, shndx); + if (sym == NULL) + { + /* This should never happen. */ + fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), + fileinfo->rfname, __FILE__, __LINE__); + return 1; + } + + if (likely (shndx != SHN_XINDEX)) + shndx = sym->st_shndx; + else if (unlikely (shndx == 0)) + { + fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), + fileinfo->rfname, __FILE__, __LINE__); + return 1; + } + + if (XELF_ST_TYPE (sym->st_info) != STT_SECTION + && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE) + && (SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags + & SHF_MERGE)) + { + /* Create a symbol record for this symbol and add it + to the list for this section. */ + struct symbol *newp; + + newp = (struct symbol *) + obstack_calloc (&ld_state.smem, sizeof (struct symbol)); + + newp->symidx = cnt; + newp->scndx = shndx; + newp->file = fileinfo; + fileinfo->symref[cnt] = newp; + + if (fileinfo->scninfo[shndx].symbols == NULL) + fileinfo->scninfo[shndx].symbols = newp->next_in_scn + = newp; + else + { + newp->next_in_scn + = fileinfo->scninfo[shndx].symbols->next_in_scn; + fileinfo->scninfo[shndx].symbols + = fileinfo->scninfo[shndx].symbols->next_in_scn = newp; + } + } + } + } + else + /* Create array with pointers to the symbol definitions. Note + that we only allocate memory for the non-local symbols + since we have no merge-able sections. But we store the + pointer as if it was for the whole symbol table. This + saves some memory. */ + fileinfo->symref = (struct symbol **) + obstack_calloc (&ld_state.smem, ((nsymbols - nlocalsymbols) + * sizeof (struct symbol *))) + - nlocalsymbols; + + /* Don't handle local symbols here. It's either not necessary + at all or has already happened. */ + for (cnt = nlocalsymbols; cnt < nsymbols; ++cnt) + { + XElf_Sym_vardef (sym); + Elf32_Word shndx; + xelf_getsymshndx (symtabdata, xndxdata, cnt, sym, shndx); + + if (sym == NULL) + { + /* This should never happen. */ + fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), + fileinfo->rfname, __FILE__, __LINE__); + return 1; + } + + if (likely (shndx != SHN_XINDEX)) + shndx = sym->st_shndx; + else if (unlikely (shndx == 0)) + { + fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), + fileinfo->rfname, __FILE__, __LINE__); + return 1; + } + + /* We ignore ABS symbols from DSOs. */ + // XXX Is this correct? + if (unlikely (shndx == SHN_ABS) && secttype == SHT_DYNSYM) + continue; + + /* If the DSO uses symbols determine whether this is the default + version. Otherwise we'll ignore the symbol. */ + if (versymdata != NULL) + { + XElf_Versym versym; + + if (xelf_getversym_copy (versymdata, cnt, versym) == NULL) + /* XXX Should we handle faulty input files more graceful? */ + assert (! "xelf_getversym failed"); + + if ((versym & 0x8000) != 0) + /* Ignore the symbol, it's not the default version. */ + continue; + } + + /* See whether we know anything about this symbol. */ + struct symbol search; + search.name = elf_strptr (fileinfo->elf, symstridx, sym->st_name); + unsigned long int hval = elf_hash (search.name); + + /* We ignore the symbols the linker generates. This are + _GLOBAL_OFFSET_TABLE_, _DYNAMIC. */ + // XXX This loop is hot and the following tests hardly ever match. + // XXX Maybe move the tests somewhere they are executed less often. + if (((unlikely (hval == 165832675) + && strcmp (search.name, "_DYNAMIC") == 0) + || (unlikely (hval == 102264335) + && strcmp (search.name, "_GLOBAL_OFFSET_TABLE_") == 0)) + && sym->st_shndx != SHN_UNDEF + /* If somebody defines such a variable in a relocatable we + don't ignore it. Let the user get what s/he deserves. */ + && fileinfo->file_type != relocatable_file_type) + continue; + + struct symbol *oldp = ld_symbol_tab_find (&ld_state.symbol_tab, + hval, &search); + struct symbol *newp; + if (likely (oldp == NULL)) + { + /* No symbol of this name know. Add it. */ + newp = (struct symbol *) obstack_alloc (&ld_state.smem, + sizeof (*newp)); + newp->name = search.name; + newp->size = sym->st_size; + newp->type = XELF_ST_TYPE (sym->st_info); + newp->symidx = cnt; + newp->outsymidx = 0; + newp->outdynsymidx = 0; + newp->scndx = shndx; + newp->file = fileinfo; + newp->defined = newp->scndx != SHN_UNDEF; + newp->common = newp->scndx == SHN_COMMON; + newp->weak = XELF_ST_BIND (sym->st_info) == STB_WEAK; + newp->added = 0; + newp->merged = 0; + newp->need_copy = 0; + newp->on_dsolist = 0; + newp->in_dso = secttype == SHT_DYNSYM; + newp->next_in_scn = NULL; +#ifndef NDEBUG + newp->next = NULL; + newp->previous = NULL; +#endif + + if (newp->scndx == SHN_UNDEF) + { + CDBL_LIST_ADD_REAR (ld_state.unresolved, newp); + ++ld_state.nunresolved; + if (! newp->weak) + ++ld_state.nunresolved_nonweak; + } + else if (newp->scndx == SHN_COMMON) + { + /* Store the alignment requirement. */ + newp->merge.value = sym->st_value; + + CDBL_LIST_ADD_REAR (ld_state.common_syms, newp); + } + + /* Insert the new symbol. */ + if (unlikely (ld_symbol_tab_insert (&ld_state.symbol_tab, + hval, newp) != 0)) + /* This cannot happen. */ + abort (); + + fileinfo->symref[cnt] = newp; + + /* We have a few special symbols to recognize. The symbols + _init and _fini are the initialization and finalization + functions respectively. They have to be made known in + the dynamic section and therefore we have to find out + now whether these functions exist or not. */ + if (hval == 6685956 && strcmp (newp->name, "_init") == 0) + ld_state.init_symbol = newp; + else if (hval == 6672457 && strcmp (newp->name, "_fini") == 0) + ld_state.fini_symbol = newp; + } + else if (unlikely (check_definition (sym, cnt, fileinfo, oldp) != 0)) + /* A fatal error (multiple definition of a symbol) + occurred, no need to continue. */ + return 1; + else + /* Use the previously allocated symbol record. It has + been updated in check_definition(), if necessary. */ + newp = fileinfo->symref[cnt] = oldp; + + /* Mark the section the symbol we need comes from as used. */ + if (shndx != SHN_UNDEF + && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE)) + { + struct scninfo *ignore; + +#ifndef NDEBUG + size_t shnum; + assert (elf_getshnum (fileinfo->elf, &shnum) == 0); + assert (shndx < shnum); +#endif + + /* Mark section (and all dependencies) as used. */ + mark_section_used (&fileinfo->scninfo[shndx], shndx, &ignore); + + /* Check whether the section is merge-able. In this case we + have to record the symbol. */ + if (SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags + & SHF_MERGE) + { + if (fileinfo->scninfo[shndx].symbols == NULL) + fileinfo->scninfo[shndx].symbols = newp->next_in_scn + = newp; + else + { + newp->next_in_scn + = fileinfo->scninfo[shndx].symbols->next_in_scn; + fileinfo->scninfo[shndx].symbols + = fileinfo->scninfo[shndx].symbols->next_in_scn = newp; + } + } + } + } + + /* This file is used. */ + if (likely (fileinfo->file_type == relocatable_file_type)) + { + if (unlikely (ld_state.relfiles == NULL)) + ld_state.relfiles = fileinfo->next = fileinfo; + else + { + fileinfo->next = ld_state.relfiles->next; + ld_state.relfiles = ld_state.relfiles->next = fileinfo; + } + + /* Update some summary information in the state structure. */ + ld_state.nsymtab += fileinfo->nsymtab; + ld_state.nlocalsymbols += fileinfo->nlocalsymbols; + } + else if (likely (fileinfo->file_type == dso_file_type)) + { + CSNGL_LIST_ADD_REAR (ld_state.dsofiles, fileinfo); + ++ld_state.ndsofiles; + + if (fileinfo->lazyload) + /* We have to create another dynamic section entry for the + DT_POSFLAG_1 entry. + + XXX Once more functionality than the lazyloading flag + are suppported the test must be extended. */ + ++ld_state.ndsofiles; + } + } + + return 0; +} + + +int +ld_handle_filename_list (struct filename_list *fnames) +{ + struct filename_list *runp; + int res = 0; + + for (runp = fnames; runp != NULL; runp = runp->next) + { + struct usedfiles *curp; + + /* Create a record for the new file. */ + curp = runp->real = ld_new_inputfile (runp->name, relocatable_file_type); + + /* Set flags for group handling. */ + runp->real->group_start = runp->group_start; + runp->real->group_end = runp->group_end; + + /* Read the file and everything else which comes up, including + handling groups. */ + do + res |= FILE_PROCESS (-1, curp, &ld_state, &curp); + while (curp != NULL); + } + + /* Free the list. */ + while (fnames != NULL) + { + runp = fnames; + fnames = fnames->next; + free (runp); + } + + return res; +} + + +/* Handle opening of the given file with ELF descriptor. */ +static int +open_elf (struct usedfiles *fileinfo, Elf *elf) +{ + int res = 0; + + if (elf == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get descriptor for ELF file (%s:%d): %s\n"), + __FILE__, __LINE__, elf_errmsg (-1)); + + if (unlikely (elf_kind (elf) == ELF_K_NONE)) + { + struct filename_list *fnames; + + /* We don't have to look at this file again. */ + fileinfo->status = closed; + + /* Let's see whether this is a linker script. */ + if (fileinfo->fd != -1) + /* Create a stream from the file handle we know. */ + ldin = fdopen (fileinfo->fd, "r"); + else + { + /* Get the memory for the archive member. */ + char *content; + size_t contentsize; + + /* Get the content of the file. */ + content = elf_rawfile (elf, &contentsize); + if (content == NULL) + { + fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), + fileinfo->rfname, __FILE__, __LINE__); + return 1; + } + + /* The content of the file is available in memory. Read the + memory region as a stream. */ + ldin = fmemopen (content, contentsize, "r"); + } + + /* No need for locking. */ + __fsetlocking (ldin, FSETLOCKING_BYCALLER); + + if (ldin == NULL) + error (EXIT_FAILURE, errno, gettext ("cannot open \"%s\""), + fileinfo->rfname); + + /* Parse the file. If it is a linker script no problems will be + reported. */ + ld_state.srcfiles = NULL; + ldlineno = 1; + ld_scan_version_script = 0; + ldin_fname = fileinfo->rfname; + res = ldparse (); + + fclose (ldin); + if (fileinfo->fd != -1 && !fileinfo->fd_passed) + { + /* We won't need the file descriptor again. */ + close (fileinfo->fd); + fileinfo->fd = -1; + } + + elf_end (elf); + + if (unlikely (res != 0)) + /* Something went wrong during parsing. */ + return 1; + + /* This is no ELF file. */ + fileinfo->elf = NULL; + + /* Now we have to handle eventual INPUT and GROUP statements in + the script. Read the files mentioned. */ + fnames = ld_state.srcfiles; + if (fnames != NULL) + { + struct filename_list *oldp; + + /* Convert the list into a normal single-linked list. */ + oldp = fnames; + fnames = fnames->next; + oldp->next = NULL; + + /* Remove the list from the state structure. */ + ld_state.srcfiles = NULL; + + if (unlikely (ld_handle_filename_list (fnames) != 0)) + return 1; + } + + return 0; + } + + /* Store the file info. */ + fileinfo->elf = elf; + + /* The file is ready for action. */ + fileinfo->status = opened; + + return 0; +} + + +static int +add_whole_archive (struct usedfiles *fileinfo) +{ + Elf *arelf; + Elf_Cmd cmd = ELF_C_READ_MMAP_PRIVATE; + int res = 0; + + while ((arelf = elf_begin (fileinfo->fd, cmd, fileinfo->elf)) != NULL) + { + Elf_Arhdr *arhdr = elf_getarhdr (arelf); + struct usedfiles *newp; + + if (arhdr == NULL) + abort (); + + /* Just to be sure; since these are no files in the archive + these names should never be returned. */ + assert (strcmp (arhdr->ar_name, "/") != 0); + assert (strcmp (arhdr->ar_name, "//") != 0); + + newp = ld_new_inputfile (arhdr->ar_name, relocatable_file_type); + newp->archive_file = fileinfo; + + if (unlikely (ld_state.trace_files)) + print_file_name (stdout, newp, 1, 1); + + /* This shows that this file is contained in an archive. */ + newp->fd = -1; + /* Store the ELF descriptor. */ + newp->elf = arelf; + /* Show that we are open for business. */ + newp->status = opened; + + /* Proces the file, add all the symbols etc. */ + res = file_process2 (newp); + if (unlikely (res != 0)) + break; + + /* Advance to the next archive element. */ + cmd = elf_next (arelf); + } + + return res; +} + + +static int +extract_from_archive (struct usedfiles *fileinfo) +{ + static int archive_seq; + int res = 0; + + /* This is an archive we are not using completely. Give it a + unique number. */ + fileinfo->archive_seq = ++archive_seq; + + /* If there are no unresolved symbols don't do anything. */ + if ((likely (ld_state.extract_rule == defaultextract) + && ld_state.nunresolved_nonweak == 0) + || (unlikely (ld_state.extract_rule == weakextract) + && ld_state.nunresolved == 0)) + return 0; + + Elf_Arsym *syms; + size_t nsyms; + + /* Get all the symbols. */ + syms = elf_getarsym (fileinfo->elf, &nsyms); + if (syms == NULL) + { + cannot_read_archive: + error (0, 0, gettext ("cannot read archive `%s': %s"), + fileinfo->rfname, elf_errmsg (-1)); + + /* We cannot use this archive anymore. */ + fileinfo->status = closed; + + return 1; + } + + /* Now add all the symbols to the hash table. Note that there + can potentially be duplicate definitions. We'll always use + the first definition. */ + // XXX Is this a compatible behavior? + bool any_used; + int nround = 0; + do + { + any_used = false; + + size_t cnt; + for (cnt = 0; cnt < nsyms; ++cnt) + { + struct symbol search = { .name = syms[cnt].as_name }; + struct symbol *sym = ld_symbol_tab_find (&ld_state.symbol_tab, + syms[cnt].as_hash, &search); + if (sym != NULL && ! sym->defined) + { + /* The symbol is referenced and not defined. */ + Elf *arelf; + Elf_Arhdr *arhdr; + struct usedfiles *newp; + + /* Find the archive member for this symbol. */ + if (unlikely (elf_rand (fileinfo->elf, syms[cnt].as_off) + != syms[cnt].as_off)) + goto cannot_read_archive; + + /* Note: no test of a failing 'elf_begin' call. That's fine + since 'elf'getarhdr' will report the problem. */ + arelf = elf_begin (fileinfo->fd, ELF_C_READ_MMAP_PRIVATE, + fileinfo->elf); + arhdr = elf_getarhdr (arelf); + if (arhdr == NULL) + goto cannot_read_archive; + + /* We have all the information and an ELF handle for the + archive member. Create the normal data structure for + a file now. */ + newp = ld_new_inputfile (obstack_strdup (&ld_state.smem, + arhdr->ar_name), + relocatable_file_type); + newp->archive_file = fileinfo; + + if (unlikely (ld_state.trace_files)) + print_file_name (stdout, newp, 1, 1); + + /* This shows that this file is contained in an archive. */ + newp->fd = -1; + /* Store the ELF descriptor. */ + newp->elf = arelf; + /* Show that we are open for business. */ + newp->status = in_archive; + + /* Now read the file and add all the symbols. */ + res = file_process2 (newp); + if (unlikely (res != 0)) + return res; + + any_used = true; + } + } + + if (++nround == 1) + { + /* This is an archive therefore it must have a number. */ + assert (fileinfo->archive_seq != 0); + ld_state.last_archive_used = fileinfo->archive_seq; + } + } + while (any_used); + + return res; +} + + +static int +file_process2 (struct usedfiles *fileinfo) +{ + int res; + + if (likely (elf_kind (fileinfo->elf) == ELF_K_ELF)) + { + /* The first time we get here we read the ELF header. */ +#if NATIVE_ELF != 0 + if (likely (fileinfo->ehdr == NULL)) +#else + if (likely (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_NONE)) +#endif + { + XElf_Ehdr *ehdr; +#if NATIVE_ELF != 0 + ehdr = xelf_getehdr (fileinfo->elf, fileinfo->ehdr); +#else + xelf_getehdr_copy (fileinfo->elf, ehdr, fileinfo->ehdr); +#endif + if (ehdr == NULL) + { + fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), + fileinfo->rfname, __FILE__, __LINE__); + fileinfo->status = closed; + return 1; + } + + if (FILEINFO_EHDR (fileinfo->ehdr).e_type != ET_REL + && unlikely (FILEINFO_EHDR (fileinfo->ehdr).e_type != ET_DYN)) + /* XXX Add ebl* function to query types which are allowed + to link in. */ + { + char buf[64]; + + print_file_name (stderr, fileinfo, 1, 0); + fprintf (stderr, + gettext ("file of type %s cannot be linked in\n"), + ebl_object_type_name (ld_state.ebl, + FILEINFO_EHDR (fileinfo->ehdr).e_type, + buf, sizeof (buf))); + fileinfo->status = closed; + return 1; + } + + /* Determine the section header string table section index. */ + if (unlikely (elf_getshstrndx (fileinfo->elf, &fileinfo->shstrndx) + < 0)) + { + fprintf (stderr, gettext ("\ +%s: cannot get section header string table index: %s\n"), + fileinfo->rfname, elf_errmsg (-1)); + fileinfo->status = closed; + return 1; + } + } + + /* Now handle the different types of files. */ + if (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_REL) + { + /* Add all the symbol. Relocatable files have symbol + tables. */ + res = add_relocatable_file (fileinfo, SHT_SYMTAB); + } + else + { + bool has_l_name = fileinfo->file_type == archive_file_type; + + assert (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_DYN); + + /* If the file is a DT_NEEDED dependency then the type is + already correctly specified. */ + if (fileinfo->file_type != dso_needed_file_type) + fileinfo->file_type = dso_file_type; + + /* We cannot use DSOs when generating relocatable objects. */ + if (ld_state.file_type == relocatable_file_type) + { + error (0, 0, gettext ("\ +cannot use DSO '%s' when generating relocatable object file"), + fileinfo->fname); + return 1; + } + + /* Add all the symbols. For DSOs we are looking at the + dynamic symbol table. */ + res = add_relocatable_file (fileinfo, SHT_DYNSYM); + + /* We always have to have a dynamic section. */ + assert (fileinfo->dynscn != NULL); + + /* We have to remember the dependencies for this object. It + is necessary to look them up. */ + XElf_Shdr_vardef (dynshdr); + xelf_getshdr (fileinfo->dynscn, dynshdr); + + Elf_Data *dyndata = elf_getdata (fileinfo->dynscn, NULL); + /* XXX Should we flag the failure to get the dynamic section? */ + if (dynshdr != NULL) + { + int cnt = dynshdr->sh_size / dynshdr->sh_entsize; + XElf_Dyn_vardef (dyn); + + while (--cnt >= 0) + { + xelf_getdyn (dyndata, cnt, dyn); + if (dyn != NULL) + { + if(dyn->d_tag == DT_NEEDED) + { + struct usedfiles *newp; + + newp = ld_new_inputfile (elf_strptr (fileinfo->elf, + dynshdr->sh_link, + dyn->d_un.d_val), + dso_needed_file_type); + + /* Enqueue the newly found dependencies. */ + // XXX Check that there not already a file with the + // same name. + CSNGL_LIST_ADD_REAR (ld_state.needed, newp); + } + else if (dyn->d_tag == DT_SONAME) + { + /* We use the DT_SONAME (this is what's there + for). */ + fileinfo->soname = elf_strptr (fileinfo->elf, + dynshdr->sh_link, + dyn->d_un.d_val); + has_l_name = false; + } + } + } + } + + /* Construct the file name if the DSO has no SONAME and the + file name comes from a -lXX parameter on the comment + line. */ + if (unlikely (has_l_name)) + { + /* The FNAME is the parameter the user specified on the + command line. We prepend "lib" and append ".so". */ + size_t len = strlen (fileinfo->fname) + 7; + char *newp; + + newp = (char *) obstack_alloc (&ld_state.smem, len); + strcpy (stpcpy (stpcpy (newp, "lib"), fileinfo->fname), ".so"); + + fileinfo->soname = newp; + } + } + } + else if (likely (elf_kind (fileinfo->elf) == ELF_K_AR)) + { + if (unlikely (ld_state.extract_rule == allextract)) + /* Which this option enabled we have to add all the object + files in the archive. */ + res = add_whole_archive (fileinfo); + else if (ld_state.file_type == relocatable_file_type) + { + /* When generating a relocatable object we don't find files + in archives. */ + if (verbose) + error (0, 0, gettext ("input file '%s' ignored"), fileinfo->fname); + + res = 0; + } + else + /* Extract only the members from the archive which are + currently referenced by unresolved symbols. */ + res = extract_from_archive (fileinfo); + } + else + /* This should never happen, we know about no other types. */ + abort (); + + return res; +} + + +/* Process a given file. The first parameter is a file descriptor for + the file which can be -1 to indicate the file has not yet been + found. The second parameter describes the file to be opened, the + last one is the state of the linker which among other information + contain the paths we look at. */ +static int +ld_generic_file_process (int fd, struct usedfiles *fileinfo, + struct ld_state *statep, struct usedfiles **nextp) +{ + int res = 0; + + /* By default we go to the next file in the list. */ + *nextp = fileinfo->next; + + /* Set the flag to signal we are looking for a group start. */ + if (unlikely (fileinfo->group_start)) + { + ld_state.group_start_requested = true; + fileinfo->group_start = false; + } + + /* If the file isn't open yet, open it now. */ + if (likely (fileinfo->status == not_opened)) + { + bool fd_passed = true; + + if (likely (fd == -1)) + { + /* Find the file ourselves. */ + int err = open_along_path (fileinfo); + if (unlikely (err != 0)) + /* We allow libraries and DSOs to be named more than once. + Don't report an error to the caller. */ + return err == EAGAIN ? 0 : err; + + fd_passed = false; + } + else + fileinfo->fd = fd; + + /* Remember where we got the descriptor from. */ + fileinfo->fd_passed = fd_passed; + + /* We found the file. Now test whether it is a file type we can + handle. + + XXX Do we have to have the ability to start from a given + position in the search path again to look for another file if + the one found has not the right type? */ + res = open_elf (fileinfo, elf_begin (fileinfo->fd, + is_dso_p (fileinfo->fd) + ? ELF_C_READ_MMAP + : ELF_C_READ_MMAP_PRIVATE, NULL)); + if (unlikely (res != 0)) + return res; + } + + /* Now that we have opened the file start processing it. */ + if (likely (fileinfo->status != closed)) + res = file_process2 (fileinfo); + + /* Determine which file to look at next. */ + if (unlikely (fileinfo->group_backref != NULL)) + { + /* We only go back if an archive other than the one we would go + back to has been used in the last round. */ + if (ld_state.last_archive_used > fileinfo->group_backref->archive_seq) + { + *nextp = fileinfo->group_backref; + ld_state.last_archive_used = 0; + } + else + { + /* If we come here this means that the archives we read so + far are not needed anymore. We can free some of the data + now. */ + struct usedfiles *runp = ld_state.archives; + + do + { + /* We don't need the ELF descriptor anymore. Unless there + are no files from the archive used this will not free + the whole file but only some data structures. */ + elf_end (runp->elf); + runp->elf = NULL; + + runp = runp->next; + } + while (runp != fileinfo->next); + } + } + else if (unlikely (fileinfo->group_end)) + { + /* This is the end of a group. We possibly of to go back. + Determine which file we would go back to and see whether it + makes sense. If there has not been an archive we don't have + to do anything. */ + if (!ld_state.group_start_requested) + { + if (ld_state.group_start_archive != ld_state.tailarchives) + /* The loop would include more than one archive, add the + pointer. */ + { + *nextp = ld_state.tailarchives->group_backref = + ld_state.group_start_archive; + ld_state.last_archive_used = 0; + } + else + /* We might still have to go back to the beginning of the + group if since the last archive other files have been + added. But we go back exactly once. */ + if (ld_state.tailarchives != fileinfo) + { + *nextp = ld_state.group_start_archive; + ld_state.last_archive_used = 0; + } + } + + /* Clear the flags. */ + ld_state.group_start_requested = false; + fileinfo->group_end = false; + } + + return res; +} + + +/* Library names passed to the linker as -lXX represent files named + libXX.YY. The YY part can have different forms, depending on the + platform. The generic set is .so and .a (in this order). */ +static const char ** +ld_generic_lib_extensions (struct ld_state *statep __attribute__ ((__unused__))) +{ + static const char *exts[] = + { + ".so", ".a", NULL + }; + + return exts; +} + + +/* Flag unresolved symbols. */ +static int +ld_generic_flag_unresolved (struct ld_state *statep) +{ + int retval = 0; + + if (ld_state.nunresolved_nonweak > 0) + { + /* Go through the list and determine the unresolved symbols. */ + struct symbol *first; + struct symbol *s; + + s = first = ld_state.unresolved->next; + do + { + if (! s->defined && ! s->weak) + { + /* Two special symbol we recognize: the symbol for the + GOT and the dynamic section. */ + if (strcmp (s->name, "_GLOBAL_OFFSET_TABLE_") == 0 + || strcmp (s->name, "_DYNAMIC") == 0) + { + /* We will have to fill in more information later. */ + ld_state.need_got = true; + + /* Remember that we found it. */ + if (s->name[1] == 'G') + ld_state.got_symbol = s; + else + ld_state.dyn_symbol = s; + } + else if (ld_state.file_type != dso_file_type || !ld_state.nodefs) + { + /* XXX The error message should get better. It should use + the debugging information if present to tell where in the + sources the undefined reference is. */ + error (0, 0, gettext ("undefined symbol `%s' in %s"), + s->name, s->file->fname); + + retval = 1; + } + } + + /* We cannot decide here what to do with undefined + references which will come from DSO since we do not know + what kind of symbol we expect. Only when looking at the + relocations we can see whether we need a PLT entry or + only a GOT entry. */ + + s = s->next; + } + while (s != first); + } + + return retval; +} + + +/* Close the given file. */ +static int +ld_generic_file_close (struct usedfiles *fileinfo, struct ld_state *statep) +{ + /* Close the ELF descriptor. */ + elf_end (fileinfo->elf); + + /* If we have opened the file descriptor close it. But we might + have done this already in which case FD is -1. */ + if (!fileinfo->fd_passed && fileinfo->fd != -1) + close (fileinfo->fd); + + /* We allocated the resolved file name. */ + if (fileinfo->fname != fileinfo->rfname) + free ((char *) fileinfo->rfname); + + return 0; +} + + +static void +new_generated_scn (enum scn_kind kind, const char *name, int type, int flags, + int entsize, int align) +{ + struct scnhead *newp; + + newp = (struct scnhead *) obstack_calloc (&ld_state.smem, + sizeof (struct scnhead)); + newp->kind = kind; + newp->name = name; + newp->nameent = ebl_strtabadd (ld_state.shstrtab, name, 0); + newp->type = type; + newp->flags = flags; + newp->entsize = entsize; + newp->align = align; + newp->grp_signature = NULL; + newp->used = true; + + /* All is well. Create now the data for the section and insert it + into the section table. */ + ld_section_tab_insert (&ld_state.section_tab, elf_hash (name), newp); +} + + +/* Create the sections which are generated by the linker and are not + present in the input file. */ +static void +ld_generic_generate_sections (struct ld_state *statep) +{ + /* The relocation section type. */ + int rel_type = REL_TYPE (&ld_state) == DT_REL ? SHT_REL : SHT_RELA; + + /* When building dynamically linked object we have to include a + section containing a string describing the interpreter. This + should be at the very beginning of the file together with the + other information the ELF loader (kernel or wherever) has to look + at. We put it as the first section in the file. + + We also have to create the dynamic segment which is a special + section the dynamic linker locates through an entry in the + program header. */ + if (dynamically_linked_p ()) + { + int ndt_needed; + /* Use any versioning (defined or required)? */ + bool use_versioning = false; + /* Use version requirements? */ + bool need_version = false; + + /* First the .interp section. */ + new_generated_scn (scn_dot_interp, ".interp", SHT_PROGBITS, SHF_ALLOC, + 0, 1); + + /* Now the .dynamic section. */ + new_generated_scn (scn_dot_dynamic, ".dynamic", SHT_DYNAMIC, + DYNAMIC_SECTION_FLAGS (&ld_state), + xelf_fsize (ld_state.outelf, ELF_T_DYN, 1), + xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); + + /* We will need in any case the dynamic symbol table (even in + the unlikely case that no symbol is exported or referenced + from a DSO). */ + ld_state.need_dynsym = true; + new_generated_scn (scn_dot_dynsym, ".dynsym", SHT_DYNSYM, SHF_ALLOC, + xelf_fsize (ld_state.outelf, ELF_T_SYM, 1), + xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); + /* It comes with a string table. */ + new_generated_scn (scn_dot_dynstr, ".dynstr", SHT_STRTAB, SHF_ALLOC, + 0, 1); + /* And a hashing table. */ + // XXX For Linux/Alpha we need other sizes unless they change... + new_generated_scn (scn_dot_hash, ".hash", SHT_HASH, SHF_ALLOC, + sizeof (Elf32_Word), sizeof (Elf32_Word)); + + /* By default we add all DSOs provided on the command line. If + the user added '-z ignore' to the command line we only add + those which are actually used. */ + ndt_needed = ld_state.ignore_unused_dsos ? 0 : ld_state.ndsofiles; + + /* Create the section associated with the PLT if necessary. */ + if (ld_state.nplt > 0) + { + /* Create the .plt section. */ + /* XXX We might need a function which returns the section flags. */ + new_generated_scn (scn_dot_plt, ".plt", SHT_PROGBITS, + SHF_ALLOC | SHF_EXECINSTR, + /* XXX Is the size correct? */ + xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1), + xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); + + /* Create the relocation section for the .plt. This is always + separate even if the other relocation sections are combined. */ + new_generated_scn (scn_dot_pltrel, ".rel.plt", rel_type, SHF_ALLOC, + rel_type == SHT_REL + ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1) + : xelf_fsize (ld_state.outelf, ELF_T_RELA, 1), + xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); + + /* This means we will also need the .got section. */ + ld_state.need_got = true; + + /* Mark all used DSOs as used. Determine whether any referenced + object uses symbol versioning. */ + if (ld_state.from_dso != NULL) + { + struct symbol *srunp = ld_state.from_dso; + + do + { + srunp->file->used = true; + + if (srunp->file->verdefdata != NULL) + { + XElf_Versym versym; + + /* The input DSO uses versioning. */ + use_versioning = true; + /* We reference versions. */ + need_version = true; + + if (xelf_getversym_copy (srunp->file->versymdata, + srunp->symidx, versym) == NULL) + assert (! "xelf_getversym failed"); + + /* We cannot link explicitly with an older + version of a symbol. */ + assert ((versym & 0x8000) == 0); + /* We cannot reference local (index 0) or plain + global (index 1) versions. */ + assert (versym > 1); + + /* Check whether we have already seen the + version and if not add it to the referenced + versions in the output file. */ + if (! srunp->file->verdefused[versym]) + { + srunp->file->verdefused[versym] = 1; + + if (++srunp->file->nverdefused == 1) + /* Count the file if it is using versioning. */ + ++ld_state.nverdeffile; + ++ld_state.nverdefused; + } + } + } + while ((srunp = srunp->next) != ld_state.from_dso); + } + + /* Create the sections used to record version dependencies. */ + if (need_version) + new_generated_scn (scn_dot_version_r, ".gnu.version_r", + SHT_GNU_verneed, SHF_ALLOC, 0, + xelf_fsize (ld_state.outelf, ELF_T_WORD, 1)); + + /* Now count the used DSOs since this is what the user + wants. */ + ndt_needed = 0; + if (ld_state.ndsofiles > 0) + { + struct usedfiles *frunp = ld_state.dsofiles; + + do + if (! ld_state.ignore_unused_dsos || frunp->used) + { + ++ndt_needed; + if (frunp->lazyload) + /* We have to create another dynamic section + entry for the DT_POSFLAG_1 entry. + + XXX Once more functionality than the + lazyloading flag are suppported the test + must be extended. */ + ++ndt_needed; + } + while ((frunp = frunp->next) != ld_state.dsofiles); + } + } + + if (use_versioning) + new_generated_scn (scn_dot_version, ".gnu.version", SHT_GNU_versym, + SHF_ALLOC, + xelf_fsize (ld_state.outelf, ELF_T_HALF, 1), + xelf_fsize (ld_state.outelf, ELF_T_HALF, 1)); + + /* We need some entries all the time. */ + ld_state.ndynamic = (7 + (ld_state.runpath != NULL + || ld_state.rpath != NULL) + + ndt_needed + + (ld_state.init_symbol != NULL ? 1 : 0) + + (ld_state.fini_symbol != NULL ? 1 : 0) + + (use_versioning ? 1 : 0) + + (need_version ? 2 : 0) + + (ld_state.nplt > 0 ? 4 : 0) + + (ld_state.relsize_total > 0 ? 3 : 0)); + } + + /* When creating a relocatable file or when we are not stripping the + output file we create a symbol table. */ + ld_state.need_symtab = (ld_state.file_type == relocatable_file_type + || ld_state.strip == strip_none); + + /* Add the .got section if needed. */ + if (ld_state.need_got) + /* XXX We might need a function which returns the section flags. */ + new_generated_scn (scn_dot_got, ".got", SHT_PROGBITS, + SHF_ALLOC | SHF_WRITE, + xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1), + xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); + + /* Add the .rel.dyn section. */ + if (ld_state.relsize_total > 0) + new_generated_scn (scn_dot_dynrel, ".rel.dyn", rel_type, SHF_ALLOC, + rel_type == SHT_REL + ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1) + : xelf_fsize (ld_state.outelf, ELF_T_RELA, 1), + xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); +} + + +/* Callback function registered with on_exit to make sure the temporary + files gets removed if something goes wrong. */ +static void +remove_tempfile (int status, void *arg) +{ + if (status != 0 && ld_state.tempfname != NULL) + unlink (ld_state.tempfname); +} + + +/* Create the output file. The file name is given or "a.out". We + create as much of the ELF structure as possible. */ +static int +ld_generic_open_outfile (struct ld_state *statep, int machine, int klass, + int data) +{ + /* We do not create the new file right away with the final name. + This would destroy an existing file with this name before a + replacement is finalized. We create instead a temporary file in + the same directory. */ + if (ld_state.outfname == NULL) + ld_state.outfname = "a.out"; + + size_t outfname_len = strlen (ld_state.outfname); + char *tempfname = (char *) obstack_alloc (&ld_state.smem, + outfname_len + sizeof (".XXXXXX")); + ld_state.tempfname = tempfname; + + int fd; + int try = 0; + while (1) + { + strcpy (mempcpy (tempfname, ld_state.outfname, outfname_len), ".XXXXXX"); + + /* The useof mktemp() here is fine. We do not want to use + mkstemp() since then the umask isn't used. And the output + file will have these permissions anyhow. Any intruder could + change the file later if it would be possible now. */ + if (mktemp (tempfname) != NULL + && (fd = open (tempfname, O_RDWR | O_EXCL | O_CREAT | O_NOFOLLOW, + ld_state.file_type == relocatable_file_type + ? DEFFILEMODE : ACCESSPERMS)) != -1) + break; + + /* Failed this round. We keep trying a number of times. */ + if (++try >= 10) + error (EXIT_FAILURE, errno, gettext ("cannot create output file")); + } + ld_state.outfd = fd; + + /* Make sure we remove the temporary file in case something goes + wrong. */ + on_exit (remove_tempfile, NULL); + + /* Create the ELF file data for the output file. */ + Elf *elf = ld_state.outelf = elf_begin (fd, + conserve_memory + ? ELF_C_WRITE : ELF_C_WRITE_MMAP, + NULL); + if (elf == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create ELF descriptor for output file: %s"), + elf_errmsg (-1)); + + /* Create the basic data structures. */ + if (! xelf_newehdr (elf, klass)) + /* Couldn't create the ELF header. Very bad. */ + error (EXIT_FAILURE, 0, + gettext ("could not create ELF header for output file: %s"), + elf_errmsg (-1)); + + /* And get the current header so that we can modify it. */ + XElf_Ehdr_vardef (ehdr); + xelf_getehdr (elf, ehdr); + assert (ehdr != NULL); + + /* Set the machine type. */ + ehdr->e_machine = machine; + + /* Modify it according to the info we have here and now. */ + if (ld_state.file_type == executable_file_type) + ehdr->e_type = ET_EXEC; + else if (ld_state.file_type == dso_file_type) + ehdr->e_type = ET_DYN; + else + { + assert (ld_state.file_type == relocatable_file_type); + ehdr->e_type = ET_REL; + } + + /* Set the ELF version. */ + ehdr->e_version = EV_CURRENT; + + /* Set the endianness. */ + ehdr->e_ident[EI_DATA] = data; + + /* Write the ELF header information back. */ + (void) xelf_update_ehdr (elf, ehdr); + + return 0; +} + + +/* We compute the offsets of the various copied objects and the total + size of the memory needed. */ +// XXX The method used here is simple: go from front to back and pack +// the objects in this order. A more space efficient way would +// actually trying to pack the objects as dense as possible. But this +// is more expensive. +static void +compute_copy_reloc_offset (XElf_Shdr *shdr) +{ + struct symbol *runp = ld_state.from_dso; + assert (runp != NULL); + + XElf_Off maxalign = 1; + XElf_Off offset = 0; + + do + if (runp->need_copy) + { + /* Determine alignment for the symbol. */ + // XXX The question is how? The symbol record itself does not + // have the information. So we have to be conservative and + // assume the alignment of the section the symbol is in. + + // XXX We can be more precise. Use the offset from the beginning + // of the section and determine the largest power of two with + // module zero. + XElf_Off symalign = MAX (SCNINFO_SHDR (runp->file->scninfo[runp->scndx].shdr).sh_addralign, 1); + /* Keep track of the maximum alignment requirement. */ + maxalign = MAX (maxalign, symalign); + + /* Align current position. */ + offset = (offset + symalign - 1) & ~(symalign - 1); + + runp->merge.value = offset; + + offset += runp->size; + } + while ((runp = runp->next) != ld_state.from_dso); + + shdr->sh_type = SHT_NOBITS; + shdr->sh_size = offset; + shdr->sh_addralign = maxalign; +} + + +static void +compute_common_symbol_offset (XElf_Shdr *shdr) +{ + struct symbol *runp = ld_state.common_syms; + assert (runp != NULL); + + XElf_Off maxalign = 1; + XElf_Off offset = 0; + + do + { + /* Determine alignment for the symbol. */ + XElf_Off symalign = runp->merge.value; + + /* Keep track of the maximum alignment requirement. */ + maxalign = MAX (maxalign, symalign); + + /* Align current position. */ + offset = (offset + symalign - 1) & ~(symalign - 1); + + runp->merge.value = offset; + + offset += runp->size; + } + while ((runp = runp->next) != ld_state.common_syms); + + shdr->sh_type = SHT_NOBITS; + shdr->sh_size = offset; + shdr->sh_addralign = maxalign; +} + + +static void +sort_sections_generic (void) +{ + /* XXX TBI */ + abort (); +} + + +static int +match_section (const char *osectname, struct filemask_section_name *sectmask, + struct scnhead **scnhead, bool new_section, size_t segment_nr) +{ + struct scninfo *prevp; + struct scninfo *runp; + struct scninfo *notused; + + if (fnmatch (sectmask->section_name->name, (*scnhead)->name, 0) != 0) + /* The section name does not match. */ + return new_section; + + /* If this is a section generated by the linker it doesn't contain + the regular information (i.e., input section data etc) and must + be handle special. */ + if ((*scnhead)->kind != scn_normal) + { + (*scnhead)->name = osectname; + (*scnhead)->segment_nr = segment_nr; + + /* We have to count note section since they get their own + program header entry. */ + if ((*scnhead)->type == SHT_NOTE) + ++ld_state.nnotesections; + + ld_state.allsections[ld_state.nallsections++] = (*scnhead); + return true; + } + + /* Now we have to match the file names of the input files. Some of + the sections here might not match. */ + runp = (*scnhead)->last->next; + prevp = (*scnhead)->last; + notused = NULL; + + do + { + /* Base of the file name the section comes from. */ + const char *brfname = basename (runp->fileinfo->rfname); + + /* If the section isn't used, the name doesn't match the positive + inclusion list or the name does match the negative inclusion + list, ignore the section. */ + if (!runp->used + || (sectmask->filemask != NULL + && fnmatch (sectmask->filemask, brfname, 0) != 0) + || (sectmask->excludemask != NULL + && fnmatch (sectmask->excludemask, brfname, 0) == 0)) + { + /* This file does not match the file name masks. */ + if (notused == NULL) + notused = runp; + + prevp = runp; + runp = runp->next; + if (runp == notused) + runp = NULL; + } + /* The section fulfills all requirements, add it to the output + file with the correct section name etc. */ + else + { + struct scninfo *found = runp; + + /* Remove this input section data buffer from the list. */ + if (prevp != runp) + runp = prevp->next = runp->next; + else + { + free (*scnhead); + *scnhead = NULL; + runp = NULL; + } + + /* Create a new section for the output file if the 'new_section' + flag says so. Otherwise append the buffer to the last + section which we created in one of the last calls. */ + if (new_section) + { + struct scnhead *newp; + + newp = (struct scnhead *) obstack_calloc (&ld_state.smem, + sizeof (*newp)); + newp->kind = scn_normal; + newp->name = osectname; + newp->type = SCNINFO_SHDR (found->shdr).sh_type; + newp->flags = SCNINFO_SHDR (found->shdr).sh_flags; + newp->segment_nr = segment_nr; + newp->last = found->next = found; + newp->used = true; + newp->relsize = found->relsize; + newp->entsize = SCNINFO_SHDR (found->shdr).sh_entsize; + + /* We have to count note section since they get their own + program header entry. */ + if (newp->type == SHT_NOTE) + ++ld_state.nnotesections; + + ld_state.allsections[ld_state.nallsections++] = newp; + new_section = false; + } + else + { + struct scnhead *queued; + + queued = ld_state.allsections[ld_state.nallsections - 1]; + + found->next = queued->last->next; + queued->last = queued->last->next = found; + + /* If the linker script forces us to add incompatible + sections together do so. But reflect this in the + type and flags of the resulting file. */ + if (queued->type != SCNINFO_SHDR (found->shdr).sh_type) + /* XXX Any better choice? */ + queued->type = SHT_PROGBITS; + if (queued->flags != SCNINFO_SHDR (found->shdr).sh_flags) + queued->flags = ebl_sh_flags_combine (ld_state.ebl, + queued->flags, + SCNINFO_SHDR (found->shdr).sh_flags); + + /* Accumulate the relocation section size. */ + queued->relsize += found->relsize; + } + } + } + while (runp != NULL); + + return new_section; +} + + +static void +sort_sections_lscript (void) +{ + struct scnhead *temp[ld_state.nallsections]; + + /* Make a copy of the section head pointer array. */ + memcpy (temp, ld_state.allsections, + ld_state.nallsections * sizeof (temp[0])); + size_t nallsections = ld_state.nallsections; + + /* Convert the output segment list in a single-linked list. */ + struct output_segment *segment = ld_state.output_segments->next; + ld_state.output_segments->next = NULL; + ld_state.output_segments = segment; + + /* Put the sections in the correct order in the array in the state + structure. This might involve merging of sections and also + renaming the containing section in the output file. */ + ld_state.nallsections = 0; + size_t segment_nr; + size_t last_writable = ~0ul; + for (segment_nr = 0; segment != NULL; segment = segment->next, ++segment_nr) + { + struct output_rule *orule; + + for (orule = segment->output_rules; orule != NULL; orule = orule->next) + if (orule->tag == output_section) + { + struct input_rule *irule; + bool new_section = true; + + for (irule = orule->val.section.input; irule != NULL; + irule = irule->next) + if (irule->tag == input_section) + { + size_t cnt; + + for (cnt = 0; cnt < nallsections; ++cnt) + if (temp[cnt] != NULL) + new_section = + match_section (orule->val.section.name, + irule->val.section, &temp[cnt], + new_section, segment_nr); + } + } + + if ((segment->mode & PF_W) != 0) + last_writable = ld_state.nallsections - 1; + } + + /* In case we have to create copy relocations or we have common + symbols, find the last writable segment and add one more data + block. It will be a NOBITS block and take up no disk space. + This is why it is important to get the last block. */ + if (ld_state.ncopy > 0 || ld_state.common_syms != NULL) + { + if (last_writable == ~0ul) + error (EXIT_FAILURE, 0, "no writable segment"); + + if (ld_state.allsections[last_writable]->type != SHT_NOBITS) + { + /* Make room in the ALLSECTIONS array for a new section. + There is guaranteed room in the array. We add the new + entry after the last writable section. */ + ++last_writable; + memmove (&ld_state.allsections[last_writable + 1], + &ld_state.allsections[last_writable], + (ld_state.nallsections - last_writable) + * sizeof (ld_state.allsections[0])); + + ld_state.allsections[last_writable] = (struct scnhead *) + obstack_calloc (&ld_state.smem, sizeof (struct scnhead)); + + /* Name for the new section. */ + ld_state.allsections[last_writable]->name = ".bss"; + /* Type: NOBITS. */ + ld_state.allsections[last_writable]->type = SHT_NOBITS; + /* Same segment as the last writable section. */ + ld_state.allsections[last_writable]->segment_nr + = ld_state.allsections[last_writable - 1]->segment_nr; + } + } + + /* Create common symbol data block. */ + if (ld_state.ncopy > 0) + { +#if NATIVE_ELF + struct scninfo *si = (struct scninfo *) + obstack_calloc (&ld_state.smem, sizeof (*si) + sizeof (XElf_Shdr)); + si->shdr = (XElf_Shdr *) (si + 1); +#else + struct scninfo *si = (struct scninfo *) obstack_calloc (&ld_state.smem, + sizeof (*si)); +#endif + + /* Get the information regarding the symbols with copy relocations. */ + compute_copy_reloc_offset (&SCNINFO_SHDR (si->shdr)); + + /* This section is needed. */ + si->used = true; + /* Remember for later the section data structure. */ + ld_state.copy_section = si; + + if (likely (ld_state.allsections[last_writable]->last != NULL)) + { + si->next = ld_state.allsections[last_writable]->last->next; + ld_state.allsections[last_writable]->last->next = si; + ld_state.allsections[last_writable]->last = si; + } + else + ld_state.allsections[last_writable]->last = si->next = si; + } + + /* Create common symbol data block. */ + if (ld_state.common_syms != NULL) + { +#if NATIVE_ELF + struct scninfo *si = (struct scninfo *) + obstack_calloc (&ld_state.smem, sizeof (*si) + sizeof (XElf_Shdr)); + si->shdr = (XElf_Shdr *) (si + 1); +#else + struct scninfo *si = (struct scninfo *) obstack_calloc (&ld_state.smem, + sizeof (*si)); +#endif + + /* Get the information regarding the symbols with copy relocations. */ + compute_common_symbol_offset (&SCNINFO_SHDR (si->shdr)); + + /* This section is needed. */ + si->used = true; + /* Remember for later the section data structure. */ + ld_state.common_section = si; + + if (likely (ld_state.allsections[last_writable]->last != NULL)) + { + si->next = ld_state.allsections[last_writable]->last->next; + ld_state.allsections[last_writable]->last->next = si; + ld_state.allsections[last_writable]->last = si; + } + else + ld_state.allsections[last_writable]->last = si->next = si; + } +} + + +/* Create the output sections now. This requires knowledge about all + the sections we will need. It may be necessary to sort sections in + the order they are supposed to appear in the executable. The + sorting use many different kinds of information to optimize the + resulting binary. Important is to respect segment boundaries and + the needed alignment. The mode of the segments will be determined + afterwards automatically by the output routines. + + The generic sorting routines work in one of two possible ways: + + - if a linker script specifies the sections to be used in the + output and assigns them to a segment this information is used; + + - otherwise the linker will order the sections based on permissions + and some special knowledge about section names.*/ +static void +ld_generic_create_sections (struct ld_state *statep) +{ + struct scngroup *groups; + size_t cnt; + + /* For relocatable object we don't have to bother sorting the + sections and we do want to preserve the relocation sections as + they appear in the input files. */ + if (ld_state.file_type != relocatable_file_type) + { + /* Collect all the relocation sections. They are handled + separately. */ + struct scninfo *list = NULL; + for (cnt = 0; cnt < ld_state.nallsections; ++cnt) + if ((ld_state.allsections[cnt]->type == SHT_REL + || ld_state.allsections[cnt]->type == SHT_RELA) + /* The generated relocation sections are not of any + interest here. */ + && ld_state.allsections[cnt]->last != NULL) + { + if (list == NULL) + list = ld_state.allsections[cnt]->last; + else + { + /* Merge the sections list. */ + struct scninfo *first = list->next; + list->next = ld_state.allsections[cnt]->last->next; + ld_state.allsections[cnt]->last->next = first; + list = ld_state.allsections[cnt]->last; + } + + /* Remove the entry from the section list. */ + ld_state.allsections[cnt] = NULL; + } + ld_state.rellist = list; + + if (ld_state.output_segments == NULL) + /* Sort using builtin rules. */ + sort_sections_generic (); + else + sort_sections_lscript (); + } + + /* Now iterate over the input sections and create the sections in the + order they are required in the output file. */ + for (cnt = 0; cnt < ld_state.nallsections; ++cnt) + { + struct scnhead *head = ld_state.allsections[cnt]; + Elf_Scn *scn; + XElf_Shdr_vardef (shdr); + + /* Don't handle unused sections. */ + if (!head->used) + continue; + + /* We first have to create the section group if necessary. + Section group sections must come (in section index order) + before any of the section contained. This all is necessary + only for relocatable object as other object types are not + allowed to contain section groups. */ + if (ld_state.file_type == relocatable_file_type + && unlikely (head->flags & SHF_GROUP)) + { + /* There is at least one section which is contained in a + section group in the input file. This means we must + create a section group here as well. The only problem is + that not all input files have to have to same kind of + partitioning of the sections. I.e., sections A and B in + one input file and sections B and C in another input file + can be in one group. That will result in a group + containing the sections A, B, and C in the output + file. */ + struct scninfo *runp; + Elf32_Word here_groupidx = 0; + struct scngroup *here_group; + struct member *newp; + + /* First check whether any section is already in a group. + In this case we have to add this output section, too. */ + runp = head->last; + do + { + assert (runp->grpid != 0); + + here_groupidx = runp->fileinfo->scninfo[runp->grpid].outscnndx; + if (here_groupidx != 0) + break; + } + while ((runp = runp->next) != head->last); + + if (here_groupidx == 0) + { + /* We need a new section group section. */ + scn = elf_newscn (ld_state.outelf); + xelf_getshdr (scn, shdr); + if (shdr == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + here_group = (struct scngroup *) xmalloc (sizeof (*here_group)); + here_group->outscnidx = here_groupidx = elf_ndxscn (scn); + here_group->nscns = 0; + here_group->member = NULL; + here_group->next = ld_state.groups; + /* Pick a name for the section. To keep it meaningful + we use a name used in the input files. If the + section group in the output file should contain + section which were in section groups of different + names in the input files this is the users + problem. */ + here_group->nameent + = ebl_strtabadd (ld_state.shstrtab, + elf_strptr (runp->fileinfo->elf, + runp->fileinfo->shstrndx, + SCNINFO_SHDR (runp->shdr).sh_name), + 0); + /* Signature symbol. */ + here_group->symbol + = runp->fileinfo->scninfo[runp->grpid].symbols; + + ld_state.groups = here_group; + } + else + { + /* Search for the group with this index. */ + here_group = ld_state.groups; + while (here_group->outscnidx != here_groupidx) + here_group = here_group->next; + } + + /* Add the new output section. */ + newp = (struct member *) alloca (sizeof (*newp)); + newp->scn = head; +#ifndef NDT_NEEDED + newp->next = NULL; +#endif + CSNGL_LIST_ADD_REAR (here_group->member, newp); + ++here_group->nscns; + + /* Store the section group index in all input files. */ + runp = head->last; + do + { + assert (runp->grpid != 0); + + if (runp->fileinfo->scninfo[runp->grpid].outscnndx == 0) + runp->fileinfo->scninfo[runp->grpid].outscnndx = here_groupidx; + else + assert (runp->fileinfo->scninfo[runp->grpid].outscnndx + == here_groupidx); + } + while ((runp = runp->next) != head->last); + } + + /* We'll use this section so get it's name in the section header + string table. */ + if (head->kind == scn_normal) + head->nameent = ebl_strtabadd (ld_state.shstrtab, head->name, 0); + + /* Create a new section in the output file and add all data + from all the sections we read. */ + scn = elf_newscn (ld_state.outelf); + head->scnidx = elf_ndxscn (scn); + xelf_getshdr (scn, shdr); + if (shdr == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + assert (head->type != SHT_NULL); + assert (head->type != SHT_SYMTAB); + assert (head->type != SHT_DYNSYM || head->kind != scn_normal); + assert (head->type != SHT_STRTAB || head->kind != scn_normal); + assert (head->type != SHT_GROUP); + shdr->sh_type = head->type; + shdr->sh_flags = head->flags; + shdr->sh_addralign = head->align; + shdr->sh_entsize = head->entsize; + assert (shdr->sh_entsize != 0 || (shdr->sh_flags & SHF_MERGE) == 0); + (void) xelf_update_shdr (scn, shdr); + + /* We have to know the section index of the dynamic symbol table + right away. */ + if (head->kind == scn_dot_dynsym) + ld_state.dynsymscnidx = elf_ndxscn (scn); + } + + /* Actually create the section group sections. */ + groups = ld_state.groups; + while (groups != NULL) + { + Elf_Scn *scn; + Elf_Data *data; + Elf32_Word *grpdata; + struct member *runp; + + scn = elf_getscn (ld_state.outelf, groups->outscnidx); + assert (scn != NULL); + + data = elf_newdata (scn); + if (data == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + data->d_size = (groups->nscns + 1) * sizeof (Elf32_Word); + data->d_buf = grpdata = (Elf32_Word *) xmalloc (data->d_size); + data->d_type = ELF_T_WORD; + data->d_version = EV_CURRENT; + data->d_off = 0; + /* XXX What better to use? */ + data->d_align = sizeof (Elf32_Word); + + /* The first word in the section is the flag word. */ + /* XXX Set COMDATA flag is necessary. */ + grpdata[0] = 0; + + runp = groups->member->next; + cnt = 1; + do + /* Fill in the index of the section. */ + grpdata[cnt++] = runp->scn->scnidx; + while ((runp = runp->next) != groups->member->next); + + groups = groups->next; + } +} + + +static bool +reduce_symbol_p (XElf_Sym *sym, struct Ebl_Strent *strent) +{ + const char *str; + const char *version; + struct id_list search; + struct id_list *verp; + bool result = ld_state.default_bind_local; + + if (XELF_ST_BIND (sym->st_info) == STB_LOCAL || sym->st_shndx == SHN_UNDEF) + /* We don't have to do anything to local symbols here. */ + /* XXX Any section value in [SHN_LORESERVER,SHN_XINDEX) need + special treatment? */ + return false; + + /* XXX Handle other symbol bindings. */ + assert (XELF_ST_BIND (sym->st_info) == STB_GLOBAL + || XELF_ST_BIND (sym->st_info) == STB_WEAK); + + str = ebl_string (strent); + version = strchr (str, VER_CHR); + if (version != NULL) + { + search.id = strndupa (str, version - str); + if (*++version == VER_CHR) + /* Skip the second '@' signalling a default definition. */ + ++version; + } + else + { + search.id = str; + version = ""; + } + + verp = ld_version_str_tab_find (&ld_state.version_str_tab, + elf_hash (search.id), &search); + while (verp != NULL) + { + /* We have this symbol in the version hash table. Now match the + version name. */ + if (strcmp (verp->u.s.versionname, version) == 0) + /* Match! */ + return verp->u.s.local; + + verp = verp->next; + } + + /* XXX Add test for wildcard version symbols. */ + + return result; +} + + +static XElf_Addr +eval_expression (struct expression *expr, XElf_Addr addr) +{ + XElf_Addr val = ~((XElf_Addr) 0); + + switch (expr->tag) + { + case exp_num: + val = expr->val.num; + break; + + case exp_sizeof_headers: + { + /* The 'elf_update' call determine the offset of the first + section. The the size of the header. */ + XElf_Shdr_vardef (shdr); + + xelf_getshdr (elf_getscn (ld_state.outelf, 1), shdr); + assert (shdr != NULL); + + val = shdr->sh_offset; + } + break; + + case exp_pagesize: + val = ld_state.pagesize; + break; + + case exp_id: + /* We are here computing only address expressions. It seems not + to be necessary to handle any variable but ".". Let's avoid + the complication. If it turns up to be needed we can add + it. */ + if (strcmp (expr->val.str, ".") != 0) + error (EXIT_FAILURE, 0, gettext ("\ +address computation expression contains variable '%s'"), + expr->val.str); + + val = addr; + break; + + case exp_mult: + val = (eval_expression (expr->val.binary.left, addr) + * eval_expression (expr->val.binary.right, addr)); + break; + + case exp_div: + val = (eval_expression (expr->val.binary.left, addr) + / eval_expression (expr->val.binary.right, addr)); + break; + + case exp_mod: + val = (eval_expression (expr->val.binary.left, addr) + % eval_expression (expr->val.binary.right, addr)); + break; + + case exp_plus: + val = (eval_expression (expr->val.binary.left, addr) + + eval_expression (expr->val.binary.right, addr)); + break; + + case exp_minus: + val = (eval_expression (expr->val.binary.left, addr) + - eval_expression (expr->val.binary.right, addr)); + break; + + case exp_and: + val = (eval_expression (expr->val.binary.left, addr) + & eval_expression (expr->val.binary.right, addr)); + break; + + case exp_or: + val = (eval_expression (expr->val.binary.left, addr) + | eval_expression (expr->val.binary.right, addr)); + break; + + case exp_align: + val = eval_expression (expr->val.child, addr); + if ((val & (val - 1)) != 0) + error (EXIT_FAILURE, 0, gettext ("argument '%" PRIuMAX "' of ALIGN in address computation expression is no power of two"), + (uintmax_t) val); + val = (addr + val - 1) & ~(val - 1); + break; + } + + return val; +} + + +/* Find a good as possible size for the hash table so that all the + non-zero entries in HASHCODES don't collide too much and the table + isn't too large. There is no exact formular for this so we use a + heuristic. Depending on the optimization level the search is + longer or shorter. */ +static size_t +optimal_bucket_size (Elf32_Word *hashcodes, size_t maxcnt, int optlevel) +{ + size_t minsize; + size_t maxsize; + size_t bestsize; + uint64_t bestcost; + size_t size; + uint32_t *counts; + uint32_t *lengths; + + if (maxcnt == 0) + return 0; + + /* When we are not optimizing we run only very few tests. */ + if (optlevel <= 0) + { + minsize = maxcnt; + maxsize = maxcnt + 10000 / maxcnt; + } + else + { + /* Does not make much sense to start with a smaller table than + one which has at least four collisions. */ + minsize = MAX (1, maxcnt / 4); + /* We look for a best fit in the range of up to eigth times the + number of elements. */ + maxsize = 2 * maxcnt + (6 * MIN (optlevel, 100) * maxcnt) / 100; + } + bestsize = maxcnt; + bestcost = UINT_MAX; + + /* Array for counting the collisions and chain lengths. */ + counts = (uint32_t *) xmalloc ((maxcnt + 1 + maxsize) * sizeof (uint32_t)); + lengths = &counts[maxcnt + 1]; + + for (size = minsize; size <= maxsize; ++size) + { + size_t inner; + uint64_t cost; + uint32_t maxlength; + uint64_t success; + uint32_t acc; + double factor; + + memset (lengths, '\0', size * sizeof (uint32_t)); + memset (counts, '\0', (maxcnt + 1) * sizeof (uint32_t)); + + /* Determine how often each hash bucket is used. */ + for (inner = 0; inner < maxcnt; ++inner) + ++lengths[hashcodes[inner] % size]; + + /* Determine the lengths. */ + maxlength = 0; + for (inner = 0; inner < size; ++inner) + { + ++counts[lengths[inner]]; + + if (lengths[inner] > maxlength) + maxlength = lengths[inner]; + } + + /* Determine successful lookup length. */ + acc = 0; + success = 0; + for (inner = 0; inner <= maxlength; ++inner) + { + acc += inner; + success += counts[inner] * acc; + } + + /* We can compute two factors now: the average length of a + positive search and the average length of a negative search. + We count the number of comparisons which have to look at the + names themselves. Recognizing that the chain ended is not + accounted for since it's almost for free. + + Which lookup is more important depends on the kind of DSO. + If it is a system DSO like libc it is expected that most + lookups succeed. Otherwise most lookups fail. */ + if (ld_state.is_system_library) + factor = (1.0 * (double) success / (double) maxcnt + + 0.3 * (double) maxcnt / (double) size); + else + factor = (0.3 * (double) success / (double) maxcnt + + 1.0 * (double) maxcnt / (double) size); + + /* Combine the lookup cost factor. The 1/16th addend adds + penalties for too large table sizes. */ + cost = (2 + maxcnt + size) * (factor + 1.0 / 16.0); + +#if 0 + printf ("maxcnt = %d, size = %d, cost = %Ld, success = %g, fail = %g, factor = %g\n", + maxcnt, size, cost, (double) success / (double) maxcnt, (double) maxcnt / (double) size, factor); +#endif + + /* Compare with current best results. */ + if (cost < bestcost) + { + bestcost = cost; + bestsize = size; + } + } + + free (counts); + + return bestsize; +} + + +static XElf_Addr +find_entry_point (void) +{ + XElf_Addr result; + + if (ld_state.entry != NULL) + { + struct symbol search = { .name = ld_state.entry }; + struct symbol *syment; + + syment = ld_symbol_tab_find (&ld_state.symbol_tab, + elf_hash (ld_state.entry), &search); + if (syment != NULL && syment->defined) + { + /* We found the symbol. */ + Elf_Data *data = elf_getdata (elf_getscn (ld_state.outelf, + ld_state.symscnidx), NULL); + + XElf_Sym_vardef (sym); + + sym = NULL; + if (data != NULL) + xelf_getsym (data, ld_state.dblindirect[syment->outsymidx], sym); + + if (sym == NULL && ld_state.need_dynsym && syment->outdynsymidx != 0) + { + /* Use the dynamic symbol table if available. */ + data = elf_getdata (elf_getscn (ld_state.outelf, + ld_state.dynsymscnidx), NULL); + + sym = NULL; + if (data != NULL) + xelf_getsym (data, syment->outdynsymidx, sym); + } + + if (sym != NULL) + return sym->st_value; + + /* XXX What to do if the output has no non-dynamic symbol + table and the dynamic symbol table does not contain the + symbol? */ + assert (ld_state.need_symtab); + assert (ld_state.symscnidx != 0); + } + } + + /* We couldn't find the symbol or none was given. Use the first + address of the ".text" section then. */ + + + result = 0; + + /* In DSOs this is no fatal error. They usually have no entry + points. In this case we set the entry point to zero, which makes + sure it will always fail. */ + if (ld_state.file_type == executable_file_type) + { + if (ld_state.entry != NULL) + error (0, 0, gettext ("\ +cannot find entry symbol \"%s\": defaulting to %#0*" PRIx64), + ld_state.entry, + xelf_getclass (ld_state.outelf) == ELFCLASS32 ? 10 : 18, + (uint64_t) result); + else + error (0, 0, gettext ("\ +no entry symbol specified: defaulting to %#0*" PRIx64), + xelf_getclass (ld_state.outelf) == ELFCLASS32 ? 10 : 18, + (uint64_t) result); + } + + return result; +} + + +static void +fillin_special_symbol (struct symbol *symst, size_t scnidx, size_t nsym, + Elf_Data *symdata, struct Ebl_Strtab *strtab) +{ + assert (ld_state.file_type != relocatable_file_type); + + XElf_Sym_vardef (sym); + xelf_getsym_ptr (symdata, nsym, sym); + + /* The name offset will be filled in later. */ + sym->st_name = 0; + /* Traditionally: globally visible. */ + sym->st_info = XELF_ST_INFO (STB_GLOBAL, symst->type); + /* No special visibility or so. */ + sym->st_other = 0; + /* Reference to the GOT or dynamic section. Since the GOT and + dynamic section are only created for executables and DSOs it + cannot be that the section index is too large. */ + assert (scnidx != 0); + assert (scnidx < SHN_LORESERVE || scnidx == SHN_ABS); + sym->st_shndx = scnidx; + /* We want the beginning of the section. */ + sym->st_value = 0; + + /* Determine the size of the section. */ + if (scnidx != SHN_ABS) + { + Elf_Data *data = elf_getdata (elf_getscn (ld_state.outelf, scnidx), + NULL); + assert (data != NULL); + sym->st_size = data->d_size; + /* Make sure there is no second data block. */ + assert (elf_getdata (elf_getscn (ld_state.outelf, scnidx), data) + == NULL); + } + + /* Insert symbol into the symbol table. Note that we do not have to + use xelf_update_symshdx. */ + (void) xelf_update_sym (symdata, nsym, sym); + + /* Cross-references. */ + ndxtosym[nsym] = symst; + symst->outsymidx = nsym; + + /* Add the name to the string table. */ + symstrent[nsym] = ebl_strtabadd (strtab, symst->name, 0); +} + + +static void +new_dynamic_entry (Elf_Data *data, int idx, XElf_Sxword tag, XElf_Addr val) +{ + XElf_Dyn_vardef (dyn); + xelf_getdyn_ptr (data, idx, dyn); + dyn->d_tag = tag; + dyn->d_un.d_ptr = val; + (void) xelf_update_dyn (data, idx, dyn); +} + + +static void +allocate_version_names (struct usedfiles *runp, struct Ebl_Strtab *dynstrtab) +{ + /* If this DSO has no versions skip it. */ + if (runp->status != opened || runp->verdefdata == NULL) + return; + + /* Add the object name. */ + int offset = 0; + while (1) + { + XElf_Verdef_vardef (def); + XElf_Verdaux_vardef (aux); + + /* Get data at the next offset. */ + xelf_getverdef (runp->verdefdata, offset, def); + assert (def != NULL); + xelf_getverdaux (runp->verdefdata, offset + def->vd_aux, aux); + assert (aux != NULL); + + assert (def->vd_ndx <= runp->nverdef); + if (def->vd_ndx == 1 || runp->verdefused[def->vd_ndx] != 0) + { + runp->verdefent[def->vd_ndx] + = ebl_strtabadd (dynstrtab, elf_strptr (runp->elf, + runp->dynsymstridx, + aux->vda_name), 0); + + if (def->vd_ndx > 1) + runp->verdefused[def->vd_ndx] = ld_state.nextveridx++; + } + + if (def->vd_next == 0) + /* That were all versions. */ + break; + + offset += def->vd_next; + } +} + + +XElf_Off +create_verneed_data (XElf_Off offset, Elf_Data *verneeddata, + struct usedfiles *runp, int *ntotal) +{ + size_t verneed_size = xelf_fsize (ld_state.outelf, ELF_T_VNEED, 1); + size_t vernaux_size = xelf_fsize (ld_state.outelf, ELF_T_VNAUX, 1); + int need_offset; + bool filled = false; + GElf_Verneed verneed; + GElf_Vernaux vernaux; + int ndef = 0; +size_t cnt; + + /* If this DSO has no versions skip it. */ + if (runp->nverdefused == 0) + return offset; + + /* We fill in the Verneed record last. Remember the + offset. */ + need_offset = offset; + offset += verneed_size; + + for (cnt = 2; cnt <= runp->nverdef; ++cnt) + if (runp->verdefused[cnt] != 0) + { + assert (runp->verdefent[cnt] != NULL); + + if (filled) + { + vernaux.vna_next = vernaux_size; + (void) gelf_update_vernaux (verneeddata, offset, + &vernaux); + offset += vernaux_size; + } + + vernaux.vna_hash + = elf_hash (ebl_string (runp->verdefent[cnt])); + vernaux.vna_flags = 0; + vernaux.vna_other = runp->verdefused[cnt]; + vernaux.vna_name = ebl_strtaboffset (runp->verdefent[cnt]); + filled = true; + ++ndef; + } + + assert (filled); + vernaux.vna_next = 0; + (void) gelf_update_vernaux (verneeddata, offset, &vernaux); + offset += vernaux_size; + + verneed.vn_version = VER_NEED_CURRENT; + verneed.vn_cnt = ndef; + verneed.vn_file = ebl_strtaboffset (runp->verdefent[1]); + /* The first auxiliary entry is always found directly + after the verneed entry. */ + verneed.vn_aux = verneed_size; + verneed.vn_next = --*ntotal > 0 ? offset - need_offset : 0; + (void) gelf_update_verneed (verneeddata, need_offset, + &verneed); + + return offset; +} + + +/* Create the output file. + + For relocatable files what basically has to happen is that all + sections from all input files are written into the output file. + Sections with the same name are combined (offsets adjusted + accordingly). The symbol tables are combined in one single table. + When stripping certain symbol table entries are omitted. + + For executables (shared or not) we have to create the program header, + additional sections like the .interp, eventually (in addition) create + a dynamic symbol table and a dynamic section. Also the relocations +have to be processed differently. */ +static int +ld_generic_create_outfile (struct ld_state *statep) +{ + struct scnlist + { + size_t scnidx; + struct scninfo *scninfo; + struct scnlist *next; + }; + struct scnlist *rellist = NULL; + size_t cnt; + Elf_Scn *symscn = NULL; + Elf_Scn *xndxscn = NULL; + Elf_Scn *strscn = NULL; + struct Ebl_Strtab *strtab = NULL; + struct Ebl_Strtab *dynstrtab = NULL; + XElf_Shdr_vardef (shdr); + Elf_Data *data; + Elf_Data *symdata = NULL; + Elf_Data *xndxdata = NULL; + struct usedfiles *file; + size_t nsym; + size_t nsym_local; + size_t nsym_allocated; + size_t nsym_dyn = 0; + Elf32_Word *dblindirect = NULL; +#ifndef NDEBUG + bool need_xndx; +#endif + Elf_Scn *shstrtab_scn; + size_t shstrtab_ndx; + XElf_Ehdr_vardef (ehdr); + struct Ebl_Strent *symtab_ent = NULL; + struct Ebl_Strent *xndx_ent = NULL; + struct Ebl_Strent *strtab_ent = NULL; + struct Ebl_Strent *shstrtab_ent; + struct scngroup *groups; + Elf_Scn *dynsymscn = NULL; + Elf_Data *dynsymdata = NULL; + Elf_Data *dynstrdata = NULL; + Elf32_Word *hashcodes = NULL; + size_t nsym_dyn_allocated = 0; + Elf_Scn *versymscn = NULL; + Elf_Data *versymdata = NULL; + + if (ld_state.need_symtab) + { + /* First create the symbol table. We need the symbol section itself + and the string table for it. */ + symscn = elf_newscn (ld_state.outelf); + ld_state.symscnidx = elf_ndxscn (symscn); + symdata = elf_newdata (symscn); + if (symdata == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create symbol table for output file: %s"), + elf_errmsg (-1)); + + symdata->d_type = ELF_T_SYM; + /* This is an estimated size, but it will definitely cap the real value. + We might have to adjust the number later. */ + nsym_allocated = (1 + ld_state.nsymtab + ld_state.nplt + ld_state.ngot + + ld_state.nusedsections + ld_state.nlscript_syms); + symdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, + nsym_allocated); + + /* Optionally the extended section table. */ + /* XXX Is SHN_LORESERVE correct? Do we need some other sections? */ + if (unlikely (ld_state.nusedsections >= SHN_LORESERVE)) + { + xndxscn = elf_newscn (ld_state.outelf); + ld_state.xndxscnidx = elf_ndxscn (xndxscn); + + xndxdata = elf_newdata (xndxscn); + if (xndxdata == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create symbol table for output file: %s"), + elf_errmsg (-1)); + + /* The following relies on the fact that Elf32_Word and Elf64_Word + have the same size. */ + xndxdata->d_type = ELF_T_WORD; + /* This is an estimated size, but it will definitely cap the + real value. we might have to adjust the number later. */ + xndxdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_WORD, + nsym_allocated); + /* The first entry is left empty, clear it here and now. */ + xndxdata->d_buf = memset (xmalloc (xndxdata->d_size), '\0', + xelf_fsize (ld_state.outelf, ELF_T_WORD, + 1)); + xndxdata->d_off = 0; + /* XXX Should use an ebl function. */ + xndxdata->d_align = sizeof (Elf32_Word); + } + } + else + { + assert (ld_state.need_dynsym); + + /* First create the symbol table. We need the symbol section itself + and the string table for it. */ + symscn = elf_getscn (ld_state.outelf, ld_state.dynsymscnidx); + symdata = elf_newdata (symscn); + if (symdata == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create symbol table for output file: %s"), + elf_errmsg (-1)); + + symdata->d_version = EV_CURRENT; + symdata->d_type = ELF_T_SYM; + /* This is an estimated size, but it will definitely cap the real value. + We might have to adjust the number later. */ + nsym_allocated = (1 + ld_state.nsymtab + ld_state.nplt + ld_state.ngot + - ld_state.nlocalsymbols + ld_state.nlscript_syms); + symdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, + nsym_allocated); + } + + /* The first entry is left empty, clear it here and now. */ + symdata->d_buf = memset (xmalloc (symdata->d_size), '\0', + xelf_fsize (ld_state.outelf, ELF_T_SYM, 1)); + symdata->d_off = 0; + /* XXX This is ugly but how else can it be done. */ + symdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); + + /* Allocate another array to keep track of the handles for the symbol + names. */ + symstrent = (struct Ebl_Strent **) xcalloc (nsym_allocated, + sizeof (struct Ebl_Strent *)); + + /* By starting at 1 we effectively add a null entry. */ + nsym = 1; + + /* Iteration over all sections. */ + for (cnt = 0; cnt < ld_state.nallsections; ++cnt) + { + struct scnhead *head = ld_state.allsections[cnt]; + Elf_Scn *scn; + struct scninfo *runp; + XElf_Off offset; + Elf32_Word xndx; + + /* Don't handle unused sections at all. */ + if (!head->used) + continue; + + /* Get the section handle. */ + scn = elf_getscn (ld_state.outelf, head->scnidx); + + if (unlikely (head->kind == scn_dot_interp)) + { + Elf_Data *outdata = elf_newdata (scn); + if (outdata == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + /* This is the string we'll put in the section. */ + const char *interp = ld_state.interp ?: "/lib/ld.so.1"; + + /* Create the section data. */ + outdata->d_buf = (void *) interp; + outdata->d_size = strlen (interp) + 1; + outdata->d_type = ELF_T_BYTE; + outdata->d_off = 0; + outdata->d_align = 1; + outdata->d_version = EV_CURRENT; + + /* Remember the index of this section. */ + ld_state.interpscnidx = head->scnidx; + + continue; + } + + if (unlikely (head->kind == scn_dot_got)) + { + /* Remember the index of this section. */ + ld_state.gotscnidx = elf_ndxscn (scn); + + /* Give the backend the change to initialize the section. */ + INITIALIZE_GOT (&ld_state, scn); + + continue; + } + + if (unlikely (head->kind == scn_dot_dynrel)) + { + Elf_Data *outdata; + + outdata = elf_newdata (scn); + if (outdata == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + outdata->d_size = ld_state.relsize_total; + outdata->d_buf = xmalloc (outdata->d_size); + outdata->d_type = (REL_TYPE (&ld_state) == DT_REL + ? ELF_T_REL : ELF_T_RELA); + outdata->d_off = 0; + outdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); + + /* Remember the index of this section. */ + ld_state.reldynscnidx = elf_ndxscn (scn); + + continue; + } + + if (unlikely (head->kind == scn_dot_dynamic)) + { + /* Only create the data for now. */ + Elf_Data *outdata; + + /* Account for a few more entries we have to add. */ + if (ld_state.dt_flags != 0) + ++ld_state.ndynamic; + if (ld_state.dt_flags_1 != 0) + ++ld_state.ndynamic; + if (ld_state.dt_feature_1 != 0) + ++ld_state.ndynamic; + + outdata = elf_newdata (scn); + if (outdata == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + /* Create the section data. */ + outdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_DYN, + ld_state.ndynamic); + outdata->d_buf = xcalloc (1, outdata->d_size); + outdata->d_type = ELF_T_DYN; + outdata->d_off = 0; + outdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); + + /* Remember the index of this section. */ + ld_state.dynamicscnidx = elf_ndxscn (scn); + + continue; + } + + if (unlikely (head->kind == scn_dot_dynsym)) + { + /* We already know the section index. */ + assert (ld_state.dynsymscnidx == elf_ndxscn (scn)); + + continue; + } + + if (unlikely (head->kind == scn_dot_dynstr)) + { + /* Remember the index of this section. */ + ld_state.dynstrscnidx = elf_ndxscn (scn); + + /* Create the string table. */ + dynstrtab = ebl_strtabinit (true); + + /* XXX TBI + We have to add all the strings which are needed in the + dynamic section here. This means DT_FILTER, + DT_AUXILIARY, ... entries. */ + if (ld_state.ndsofiles > 0) + { + struct usedfiles *frunp = ld_state.dsofiles; + + do + if (! ld_state.ignore_unused_dsos || frunp->used) + frunp->sonameent = ebl_strtabadd (dynstrtab, frunp->soname, + 0); + while ((frunp = frunp->next) != ld_state.dsofiles); + } + + + /* Add the runtime path information. The strings are stored + in the .dynstr section. If both rpath and runpath are defined + the runpath information is used. */ + if (ld_state.runpath != NULL || ld_state.rpath != NULL) + { + struct pathelement *startp; + struct pathelement *prunp; + int tag; + size_t len; + char *str; + char *cp; + + if (ld_state.runpath != NULL) + { + startp = ld_state.runpath; + tag = DT_RUNPATH; + } + else + { + startp = ld_state.rpath; + tag = DT_RPATH; + } + + /* Determine how long the string will be. */ + for (len = 0, prunp = startp; prunp != NULL; prunp = prunp->next) + len += strlen (prunp->pname) + 1; + + cp = str = (char *) obstack_alloc (&ld_state.smem, len); + /* Copy the string. */ + for (prunp = startp; prunp != NULL; prunp = prunp->next) + { + cp = stpcpy (cp, prunp->pname); + *cp++ = ':'; + } + /* Remove the last colon. */ + cp[-1] = '\0'; + + /* Remember the values until we can generate the dynamic + section. */ + ld_state.rxxpath_strent = ebl_strtabadd (dynstrtab, str, len); + ld_state.rxxpath_tag = tag; + } + + continue; + } + + if (unlikely (head->kind == scn_dot_hash)) + { + /* Remember the index of this section. */ + ld_state.hashscnidx = elf_ndxscn (scn); + + continue; + } + + if (unlikely (head->kind == scn_dot_plt)) + { + /* Remember the index of this section. */ + ld_state.pltscnidx = elf_ndxscn (scn); + + /* Give the backend the change to initialize the section. */ + INITIALIZE_PLT (&ld_state, scn); + + continue; + } + + if (unlikely (head->kind == scn_dot_pltrel)) + { + /* Remember the index of this section. */ + ld_state.pltrelscnidx = elf_ndxscn (scn); + + /* Give the backend the change to initialize the section. */ + INITIALIZE_PLTREL (&ld_state, scn); + + continue; + } + + if (unlikely (head->kind == scn_dot_version)) + { + /* Remember the index of this section. */ + ld_state.versymscnidx = elf_ndxscn (scn); + + continue; + } + + if (unlikely (head->kind == scn_dot_version_r)) + { + /* Remember the index of this section. */ + ld_state.verneedscnidx = elf_ndxscn (scn); + + continue; + } + + /* If we come here we must be handling a normal section. */ + assert (head->kind == scn_normal); + + /* Create an STT_SECTION entry in the symbol table. But not for + the symbolic symbol table. */ + if (ld_state.need_symtab) + { + /* XXX Can we be cleverer and do this only if needed? */ + XElf_Sym_vardef (sym); + + /* Optimization ahead: in the native linker we get a pointer + to the final location so that the following code writes + directly in the correct place. Otherwise we write into + the local variable first. */ + xelf_getsym_ptr (symdata, nsym, sym); + + /* Usual section symbol: local, no specific information, + except the section index. The offset here is zero, the + start address will later be added. */ + sym->st_name = 0; + sym->st_info = XELF_ST_INFO (STB_LOCAL, STT_SECTION); + sym->st_other = 0; + sym->st_value = 0; + sym->st_size = 0; + /* In relocatable files the section index can be too big for + the ElfXX_Sym struct. we have to deal with the extended + symbol table. */ + if (likely (head->scnidx < SHN_LORESERVE)) + { + sym->st_shndx = head->scnidx; + xndx = 0; + } + else + { + sym->st_shndx = SHN_XINDEX; + xndx = head->scnidx; + } + /* Commit the change. See the optimization above, this does + not change the symbol table entry. But the extended + section index table entry is always written, if there is + such a table. */ + assert (nsym < nsym_allocated); + xelf_update_symshndx (symdata, xndxdata, nsym, sym, xndx, 0); + + /* Remember the symbol's index in the symbol table. */ + head->scnsymidx = nsym++; + } + + if (head->type == SHT_REL || head->type == SHT_RELA) + { + /* Remember that we have to fill in the symbol table section + index. */ + if (ld_state.file_type == relocatable_file_type) + { + struct scnlist *newp; + + newp = (struct scnlist *) alloca (sizeof (*newp)); + newp->scnidx = head->scnidx; + newp->scninfo = head->last->next; +#ifndef NDEBUG + newp->next = NULL; +#endif + SNGL_LIST_PUSH (rellist, newp); + } + else + { + /* When we create an executable or a DSO we don't simply + copy the existing relocations. Instead many will be + resolved, others will be converted. Create a data buffer + large enough to contain the contents which we will fill + in later. */ + int type = head->type == SHT_REL ? ELF_T_REL : ELF_T_RELA; + + data = elf_newdata (scn); + if (data == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + data->d_size = xelf_fsize (ld_state.outelf, type, head->relsize); + data->d_buf = xcalloc (data->d_size, 1); + data->d_type = type; + data->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); + data->d_off = 0; + + continue; + } + } + + /* Recognize string and merge flag and handle them. */ + if (head->flags & SHF_MERGE) + { + /* We merge the contents of the sections. For this we do + not look at the contents of section directly. Instead we + look at the symbols of the section. */ + Elf_Data *outdata; + + /* Concatenate the lists of symbols for all sections. + + XXX In case any input section has no symbols associated + (this happens for debug sections) we cannot use this + method. Implement parsing the other debug sections and + find the string pointers. For now we don't merge. */ + runp = head->last->next; + if (runp->symbols == NULL) + { + head->flags &= ~SHF_MERGE; + goto no_merge; + } + head->symbols = runp->symbols; + + while ((runp = runp->next) != head->last->next) + { + if (runp->symbols == NULL) + { + head->flags &= ~SHF_MERGE; + head->symbols = NULL; + goto no_merge; + } + + struct symbol *oldhead = head->symbols->next_in_scn; + + head->symbols->next_in_scn = runp->symbols->next_in_scn; + runp->symbols->next_in_scn = oldhead; + head->symbols = runp->symbols; + } + + /* Create the output section. */ + outdata = elf_newdata (scn); + if (outdata == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + /* We use different merging algorithms for performance + reasons. We can easily handle single-byte and + wchar_t-wide character strings. All other cases (which + really should happen in real life) are handled by the + generic code. */ + if (SCNINFO_SHDR (head->last->shdr).sh_entsize == 1 + && (head->flags & SHF_STRINGS)) + { + /* Simple, single-byte string matching. */ + struct Ebl_Strtab *mergestrtab; + struct symbol *symrunp; + Elf_Data *locsymdata = NULL; + Elf_Data *locdata = NULL; + + mergestrtab = ebl_strtabinit (false); + + symrunp = head->symbols->next_in_scn; + file = NULL; + do + { + /* Accelarate the loop. We cache the file + information since it might very well be the case + that the previous entry was from the same + file. */ + if (symrunp->file != file) + { + /* Remember the file. */ + file = symrunp->file; + /* Symbol table data from that file. */ + locsymdata = file->symtabdata; + /* String section data. */ + locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn, + NULL); + assert (locdata != NULL); + /* While we are at it, remember the output + section. If we don't access the string data + section the section won't be in the output + file. So it is sufficient to do the work + here. */ + file->scninfo[symrunp->scndx].outscnndx = head->scnidx; + } + + /* Get the symbol information. This provides us the + offset into the string data section. */ + XElf_Sym_vardef (sym); + xelf_getsym (locsymdata, symrunp->symidx, sym); + assert (sym != NULL); + + /* Get the data from the file. Note that we access + the raw section data; no endian-ness issues with + single-byte strings. */ + symrunp->merge.handle + = ebl_strtabadd (mergestrtab, + (char *) locdata->d_buf + sym->st_value, + 0); + } + while ((symrunp = symrunp->next_in_scn) + != head->symbols->next_in_scn); + + /* All strings have been added. Create the final table. */ + ebl_strtabfinalize (mergestrtab, outdata); + + /* Compute the final offsets in the section. */ + symrunp = runp->symbols; + do + { + symrunp->merge.value + = ebl_strtaboffset (symrunp->merge.handle); + symrunp->merged = 1; + } + while ((symrunp = symrunp->next_in_scn) != runp->symbols); + + /* We don't need the string table anymore. */ + ebl_strtabfree (mergestrtab); + } + else if (likely (SCNINFO_SHDR (head->last->shdr).sh_entsize + == sizeof (wchar_t)) + && likely (head->flags & SHF_STRINGS)) + { + /* Simple, wchar_t string merging. */ + struct Ebl_WStrtab *mergestrtab; + struct symbol *symrunp; + Elf_Data *locsymdata = NULL; + Elf_Data *locdata = NULL; + + mergestrtab = ebl_wstrtabinit (false); + + symrunp = runp->symbols; + file = NULL; + do + { + /* Accelarate the loop. We cache the file + information since it might very well be the case + that the previous entry was from the same + file. */ + if (symrunp->file != file) + { + /* Remember the file. */ + file = symrunp->file; + /* Symbol table data from that file. */ + locsymdata = file->symtabdata; + /* String section data. */ + locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn, + NULL); + assert (locdata != NULL); + + /* While we are at it, remember the output + section. If we don't access the string data + section the section won't be in the output + file. So it is sufficient to do the work + here. */ + file->scninfo[symrunp->scndx].outscnndx = head->scnidx; + } + + /* Get the symbol information. This provides us the + offset into the string data section. */ + XElf_Sym_vardef (sym); + xelf_getsym (locsymdata, symrunp->symidx, sym); + assert (sym != NULL); + + /* Get the data from the file. Using the raw + section data here is possible since we don't + interpret the string themselves except for + looking for the wide NUL character. The NUL + character has fortunately the same representation + regardless of the byte order. */ + symrunp->merge.handle + = ebl_wstrtabadd (mergestrtab, + (wchar_t *) ((char *) locdata->d_buf + + sym->st_value), 0); + } + while ((symrunp = symrunp->next_in_scn) != runp->symbols); + + /* All strings have been added. Create the final table. */ + ebl_wstrtabfinalize (mergestrtab, outdata); + + /* Compute the final offsets in the section. */ + symrunp = runp->symbols; + do + { + symrunp->merge.value + = ebl_wstrtaboffset (symrunp->merge.handle); + symrunp->merged = 1; + } + while ((symrunp = symrunp->next_in_scn) != runp->symbols); + + /* We don't need the string table anymore. */ + ebl_wstrtabfree (mergestrtab); + } + else + { + /* Non-standard merging. */ + struct Ebl_GStrtab *mergestrtab; + struct symbol *symrunp; + Elf_Data *locsymdata = NULL; + Elf_Data *locdata = NULL; + /* If this is no string section the length of each "string" + is always one. */ + unsigned int len = (head->flags & SHF_STRINGS) ? 0 : 1; + + /* This is the generic string table functionality. Much + slower than the specialized code. */ + mergestrtab + = ebl_gstrtabinit (SCNINFO_SHDR (head->last->shdr).sh_entsize, + false); + + symrunp = runp->symbols; + file = NULL; + do + { + /* Accelarate the loop. We cache the file + information since it might very well be the case + that the previous entry was from the same + file. */ + if (symrunp->file != file) + { + /* Remember the file. */ + file = symrunp->file; + /* Symbol table data from that file. */ + locsymdata = file->symtabdata; + /* String section data. */ + locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn, + NULL); + assert (locdata != NULL); + + /* While we are at it, remember the output + section. If we don't access the string data + section the section won't be in the output + file. So it is sufficient to do the work + here. */ + file->scninfo[symrunp->scndx].outscnndx = head->scnidx; + } + + /* Get the symbol information. This provides us the + offset into the string data section. */ + XElf_Sym_vardef (sym); + xelf_getsym (locsymdata, symrunp->symidx, sym); + assert (sym != NULL); + + /* Get the data from the file. Using the raw + section data here is possible since we don't + interpret the string themselves except for + looking for the wide NUL character. The NUL + character has fortunately the same representation + regardless of the byte order. */ + symrunp->merge.handle + = ebl_gstrtabadd (mergestrtab, + (char *) locdata->d_buf + sym->st_value, + len); + } + while ((symrunp = symrunp->next_in_scn) != runp->symbols); + + /* Create the final table. */ + ebl_gstrtabfinalize (mergestrtab, outdata); + + /* Compute the final offsets in the section. */ + symrunp = runp->symbols; + do + { + symrunp->merge.value + = ebl_gstrtaboffset (symrunp->merge.handle); + symrunp->merged = 1; + } + while ((symrunp = symrunp->next_in_scn) != runp->symbols); + + /* We don't need the string table anymore. */ + ebl_gstrtabfree (mergestrtab); + } + } + else + { + no_merge: + assert (head->scnidx == elf_ndxscn (scn)); + + /* It is important to start with the first list entry (and + not just any one) to add the sections in the correct + order. */ + runp = head->last->next; + offset = 0; + do + { + Elf_Data *outdata = elf_newdata (scn); + if (outdata == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + /* Exceptional case: if we synthesize a data block SCN + is NULL and the sectio header info must be for a + SHT_NOBITS block and the size and alignment are + filled in. */ + if (likely (runp->scn != NULL)) + { + data = elf_getdata (runp->scn, NULL); + assert (data != NULL); + + /* We reuse the data buffer in the input file. */ + *outdata = *data; + + /* Given that we read the input file from disk we know there + cannot be another data part. */ + assert (elf_getdata (runp->scn, data) == NULL); + } + else + { + /* Must be a NOBITS section. */ + assert (SCNINFO_SHDR (runp->shdr).sh_type == SHT_NOBITS); + + outdata->d_buf = NULL; /* Not needed. */ + outdata->d_type = ELF_T_BYTE; + outdata->d_version = EV_CURRENT; + outdata->d_size = SCNINFO_SHDR (runp->shdr).sh_size; + outdata->d_align = SCNINFO_SHDR (runp->shdr).sh_addralign; + } + + XElf_Off align = MAX (1, outdata->d_align); + assert (powerof2 (align)); + offset = ((offset + align - 1) & ~(align - 1)); + + runp->offset = offset; + runp->outscnndx = head->scnidx; + runp->allsectionsidx = cnt; + + outdata->d_off = offset; + + offset += outdata->d_size; + } + while ((runp = runp->next) != head->last->next); + + /* If necessary add the additional line to the .comment section. */ + if (ld_state.add_ld_comment + && head->flags == 0 + && head->type == SHT_PROGBITS + && strcmp (head->name, ".comment") == 0 + && head->entsize == 0) + { + Elf_Data *outdata = elf_newdata (scn); + + if (outdata == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + outdata->d_buf = (void *) "\0ld (Red Hat " PACKAGE ") " VERSION; + outdata->d_size = strlen ((char *) outdata->d_buf + 1) + 2; + outdata->d_off = offset; + outdata->d_type = ELF_T_BYTE; + outdata->d_align = 1; + } + /* XXX We should create a .comment section if none exists. + This requires that we early on detect that no such + section exists. This should probably be implemented + together with some merging of the section contents. + Currently identical entries are not merged. */ + } + } + + /* The table we collect the strings in. */ + strtab = ebl_strtabinit (true); + if (strtab == NULL) + error (EXIT_FAILURE, errno, gettext ("cannot create string table")); + + +#ifndef NDEBUG + /* Keep track of the use of the XINDEX. */ + need_xndx = false; +#endif + + /* We we generate a normal symbol table for an executable and the + --export-dynamic option is not given, we need an extra table + which keeps track of the symbol entry belonging to the symbol + table entry. Note that EXPORT_ALL_DYNAMIC is always set if we + generate a DSO so we do not have to test this separately. */ + ndxtosym = (struct symbol **) xcalloc (nsym_allocated, + sizeof (struct symbol)); + + /* Create the special symbol for the GOT section. */ + if (ld_state.got_symbol != NULL) + { + assert (nsym < nsym_allocated); + fillin_special_symbol (ld_state.got_symbol, ld_state.gotscnidx, + nsym++, symdata, strtab); + } + + /* Similarly for the dynamic section symbol. */ + if (ld_state.dyn_symbol != NULL) + { + assert (nsym < nsym_allocated); + fillin_special_symbol (ld_state.dyn_symbol, ld_state.dynamicscnidx, + nsym++, symdata, strtab); + } + + /* Create symbol table entries for the symbols defined in the linker + script. */ + if (ld_state.lscript_syms != NULL) + { + struct symbol *rsym = ld_state.lscript_syms; + do + { + assert (nsym < nsym_allocated); + fillin_special_symbol (rsym, SHN_ABS, nsym++, symdata, strtab); + } + while ((rsym = rsym->next) != NULL); + } + + /* Iterate over all input files to collect the symbols. */ + file = ld_state.relfiles->next; + symdata = elf_getdata (elf_getscn (ld_state.outelf, ld_state.symscnidx), + NULL); + do + { + size_t maxcnt; + Elf_Data *insymdata; + Elf_Data *inxndxdata; + + /* There must be no dynamic symbol table when creating + relocatable files. */ + assert (ld_state.file_type != relocatable_file_type + || file->dynsymtabdata == NULL); + + insymdata = file->symtabdata; + assert (insymdata != NULL); + inxndxdata = file->xndxdata; + + maxcnt = file->nsymtab; + + file->symindirect = (Elf32_Word *) xcalloc (maxcnt, sizeof (Elf32_Word)); + + /* The dynamic symbol table does not contain local symbols. So + we skip those entries. */ + for (cnt = ld_state.need_symtab ? 1 : file->nlocalsymbols; cnt < maxcnt; + ++cnt) + { + XElf_Sym_vardef (sym); + Elf32_Word xndx; + struct symbol *defp = NULL; + + xelf_getsymshndx (insymdata, inxndxdata, cnt, sym, xndx); + assert (sym != NULL); + + if (unlikely (XELF_ST_TYPE (sym->st_info) == STT_SECTION)) + { + /* Section symbols should always be local but who knows... */ + if (ld_state.need_symtab) + { + /* Determine the real section index in the source file. + Use the XINDEX section content if necessary. We don't + add this information to the dynamic symbol table. */ + if (sym->st_shndx != SHN_XINDEX) + xndx = sym->st_shndx; + + assert (file->scninfo[xndx].allsectionsidx + < ld_state.nallsections); + file->symindirect[cnt] = ld_state.allsections[file->scninfo[xndx].allsectionsidx]->scnsymidx; + /* Note that the resulting index can be zero here. There is + no guarantee that the output file will contain all the + sections the input file did. */ + } + continue; + } + + if ((ld_state.strip >= strip_all || !ld_state.need_symtab) + /* XXX Do we need these entries? */ + && XELF_ST_TYPE (sym->st_info) == STT_FILE) + continue; + +#if NATIVE_ELF != 0 + /* Copy old data. */ + XElf_Sym *sym2 = sym; + assert (nsym < nsym_allocated); + xelf_getsym (symdata, nsym, sym); + *sym = *sym2; +#endif + + if (sym->st_shndx != SHN_UNDEF + && (sym->st_shndx < SHN_LORESERVE + || sym->st_shndx == SHN_XINDEX)) + { + /* If we are creating an executable with no normal + symbol table and we do not export all symbols and + this symbol is not defined in a DSO as well, ignore + it. */ + if (!ld_state.export_all_dynamic && !ld_state.need_symtab) + { + assert (cnt >= file->nlocalsymbols); + defp = file->symref[cnt]; + assert (defp != NULL); + + if (!defp->in_dso) + /* Ignore it. */ + continue; + } + + /* Determine the real section index in the source file. Use + the XINDEX section content if necessary. */ + if (sym->st_shndx != SHN_XINDEX) + xndx = sym->st_shndx; + + sym->st_value += file->scninfo[xndx].offset; + + assert (file->scninfo[xndx].outscnndx < SHN_LORESERVE + || file->scninfo[xndx].outscnndx > SHN_HIRESERVE); + if (unlikely (file->scninfo[xndx].outscnndx > SHN_LORESERVE)) + { + /* It is not possible to have an extended section index + table for the dynamic symbol table. */ + if (!ld_state.need_symtab) + error (EXIT_FAILURE, 0, gettext ("\ +section index too large in dynamic symbol table")); + + assert (xndxdata != NULL); + sym->st_shndx = SHN_XINDEX; + xndx = file->scninfo[xndx].outscnndx; +#ifndef NDEBUG + need_xndx = true; +#endif + } + else + { + sym->st_shndx = file->scninfo[xndx].outscnndx; + xndx = 0; + } + } + else if (sym->st_shndx == SHN_COMMON || sym->st_shndx == SHN_UNDEF) + { + /* Check whether we have a (real) definition for this + symbol. If this is the case we skip this symbol + table entry. */ + assert (cnt >= file->nlocalsymbols); + defp = file->symref[cnt]; + assert (defp != NULL); + + assert (sym->st_shndx != SHN_COMMON || defp->defined); + + if ((sym->st_shndx == SHN_COMMON && !defp->common) + || (sym->st_shndx == SHN_UNDEF && defp->defined) + || defp->added) + /* Ignore this symbol table entry, there is a + "better" one or we already added it. */ + continue; + + /* Remember that we already added this symbol. */ + defp->added = 1; + + /* Adjust the section number for common symbols. */ + if (sym->st_shndx == SHN_COMMON) + { + sym->st_value = (ld_state.common_section->offset + + file->symref[cnt]->merge.value); + assert (ld_state.common_section->outscnndx < SHN_LORESERVE); + sym->st_shndx = ld_state.common_section->outscnndx; + xndx = 0; + } + } + else if (unlikely (sym->st_shndx != SHN_ABS)) + { + if (SPECIAL_SECTION_NUMBER_P (&ld_state, sym->st_shndx)) + /* XXX Add code to handle machine specific special + sections. */ + abort (); + } + + /* Add the symbol name to the string table. If the user + chooses the highest level of stripping avoid adding names + for local symbols in the string table. */ + if (sym->st_name != 0 + && (ld_state.strip < strip_everything + || XELF_ST_BIND (sym->st_info) != STB_LOCAL)) + symstrent[nsym] = ebl_strtabadd (strtab, + elf_strptr (file->elf, + file->symstridx, + sym->st_name), 0); + + /* Once we know the name this field will get the correct + offset. For now set it to zero which means no name + associated. */ + sym->st_name = 0; + + /* If we had to merge sections we have a completely new + offset for the symbol. */ + if (file->has_merge_sections && file->symref[cnt] != NULL + && file->symref[cnt]->merged) + sym->st_value = file->symref[cnt]->merge.value; + + /* Create the record in the output sections. */ + assert (nsym < nsym_allocated); + xelf_update_symshndx (symdata, xndxdata, nsym, sym, xndx, 0); + + /* Add the reference to the symbol record in case we need it. + Find the symbol if this has not happened yet. We do + not need the information for local symbols. */ + if (defp == NULL && cnt >= file->nlocalsymbols) + { + defp = file->symref[cnt]; + assert (defp != NULL); + } + + /* Store the reference to the symbol record. The + sorting code will have to keep this array in the + correct order, too. */ + ndxtosym[nsym] = defp; + + /* One more entry finished. */ + if (cnt >= file->nlocalsymbols) + { + assert (file->symref[cnt]->outsymidx == 0); + file->symref[cnt]->outsymidx = nsym; + } + file->symindirect[cnt] = nsym++; + } + } + while ((file = file->next) != ld_state.relfiles->next); + /* Make sure we didn't create the extended section index table for + nothing. */ + assert (xndxdata == NULL || need_xndx); + + + /* Create the version related sections. */ + if (ld_state.verneedscnidx != 0) + { + /* We know the number of input files and total number of + referenced versions. This allows us to allocate the memory + and then we iterate over the DSOs to get the version + information. */ + struct usedfiles *runp; + + runp = ld_state.dsofiles->next; + do + allocate_version_names (runp, dynstrtab); + while ((runp = runp->next) != ld_state.dsofiles->next); + + if (ld_state.needed != NULL) + { + runp = ld_state.needed->next; + do + allocate_version_names (runp, dynstrtab); + while ((runp = runp->next) != ld_state.needed->next); + } + } + + /* At this point we should hide symbols and so on. */ + if (ld_state.default_bind_local || ld_state.version_str_tab.filled > 0) + /* XXX Add one more test when handling of wildcard symbol names + is supported. */ + { + /* Check all non-local symbols whether they are on the export list. */ + bool any_reduced = false; + + for (cnt = 1; cnt < nsym; ++cnt) + { + XElf_Sym_vardef (sym); + + /* Note that we don't have to use 'xelf_getsymshndx' since we + only need the binding and the symbol name. */ + xelf_getsym (symdata, cnt, sym); + assert (sym != NULL); + + if (reduce_symbol_p (sym, symstrent[cnt])) + { + sym->st_info = XELF_ST_INFO (STB_LOCAL, + XELF_ST_TYPE (sym->st_info)); + (void) xelf_update_sym (symdata, cnt, sym); + + /* Show that we don't need this string anymore. */ + if (ld_state.strip == strip_everything) + { + symstrent[cnt] = NULL; + any_reduced = true; + } + } + } + + if (unlikely (any_reduced)) + { + /* Since we will not write names of local symbols in the + output file and we have reduced the binding of some + symbols the string table previously constructed contains + too many string. Correct it. */ + struct Ebl_Strtab *newp = ebl_strtabinit (true); + + for (cnt = 1; cnt < nsym; ++cnt) + if (symstrent[cnt] != NULL) + symstrent[cnt] = ebl_strtabadd (newp, + ebl_string (symstrent[cnt]), 0); + + ebl_strtabfree (strtab); + strtab = newp; + } + } + + /* Add the references to DSOs. We can add these entries this late + (after sorting out versioning) because references to DSOs are not + effected. */ + if (ld_state.from_dso != NULL) + { + struct symbol *runp; + size_t plt_base = nsym + ld_state.nfrom_dso - ld_state.nplt; + size_t plt_idx = 0; + size_t obj_idx = 0; + + assert (ld_state.nfrom_dso >= ld_state.nplt); + runp = ld_state.from_dso; + do + { + // XXX What about functions which are only referenced via + // pointers and not PLT entries? Can we distinguish such uses? + size_t idx; + if (runp->type == STT_FUNC) + { + /* Store the PLT entry number. */ + runp->merge.value = plt_idx + 1; + idx = plt_base + plt_idx++; + } + else + idx = nsym + obj_idx++; + + XElf_Sym_vardef (sym); + xelf_getsym_ptr (symdata, idx, sym); + + sym->st_value = 0; + sym->st_size = runp->size; + sym->st_info = XELF_ST_INFO (runp->weak ? STB_WEAK : STB_GLOBAL, + runp->type); + sym->st_other = STV_DEFAULT; + sym->st_shndx = SHN_UNDEF; + + /* Create the record in the output sections. */ + xelf_update_symshndx (symdata, xndxdata, idx, sym, 0, 0); + + const char *name = runp->name; + size_t namelen = 0; + + if (runp->file->verdefdata != NULL) + { + // XXX Is it useful to add the versym value to struct symbol? + XElf_Versym versym; + + (void) xelf_getversym_copy (runp->file->versymdata, runp->symidx, + versym); + + /* One can only link with the default version. */ + assert ((versym & 0x8000) == 0); + + const char *versname + = ebl_string (runp->file->verdefent[versym]); + + size_t versname_len = strlen (versname) + 1; + namelen = strlen (name) + versname_len + 2; + char *newp = (char *) obstack_alloc (&ld_state.smem, namelen); + memcpy (stpcpy (stpcpy (newp, name), "@@"), + versname, versname_len); + name = newp; + } + + symstrent[idx] = ebl_strtabadd (strtab, name, namelen); + + /* Record the initial index in the symbol table. */ + runp->outsymidx = idx; + + /* Remember the symbol record this ELF symbol came from. */ + ndxtosym[idx] = runp; + } + while ((runp = runp->next) != ld_state.from_dso); + + assert (nsym + obj_idx == plt_base); + assert (plt_idx == ld_state.nplt); + nsym = plt_base + plt_idx; + } + + /* Now we know how many symbols will be in the output file. Adjust + the count in the section data. */ + symdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym); + if (unlikely (xndxdata != NULL)) + xndxdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_WORD, nsym); + + /* Create the symbol string table section. */ + strscn = elf_newscn (ld_state.outelf); + ld_state.strscnidx = elf_ndxscn (strscn); + data = elf_newdata (strscn); + xelf_getshdr (strscn, shdr); + if (data == NULL || shdr == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + /* Create a compact string table, allocate the memory for it, and + fill in the section data information. */ + ebl_strtabfinalize (strtab, data); + + shdr->sh_type = SHT_STRTAB; + assert (shdr->sh_entsize == 0); + + if (unlikely (xelf_update_shdr (strscn, shdr) == 0)) + error (EXIT_FAILURE, 0, + gettext ("cannot create section for output file: %s"), + elf_errmsg (-1)); + + /* Fill in the offsets of the symbol names. */ + for (cnt = 1; cnt < nsym; ++cnt) + if (symstrent[cnt] != NULL) + { + XElf_Sym_vardef (sym); + + /* Note that we don't have to use 'xelf_getsymshndx' since we don't + modify the section index. */ + xelf_getsym (symdata, cnt, sym); + /* This better worked, we did it before. */ + assert (sym != NULL); + sym->st_name = ebl_strtaboffset (symstrent[cnt]); + (void) xelf_update_sym (symdata, cnt, sym); + } + + /* Since we are going to reorder the symbol table but still have to + be able to find the new position based on the old one (since the + latter is stored in 'symindirect' information of the input file + data structure) we have to create yet another indirection + table. */ + ld_state.dblindirect = dblindirect + = (Elf32_Word *) xmalloc (nsym * sizeof (Elf32_Word)); + + /* Sort the symbol table so that the local symbols come first. */ + /* XXX We don't use stable sorting here. It seems not necessary and + would be more expensive. If it turns out to be necessary this can + be fixed easily. */ + nsym_local = 1; + cnt = nsym - 1; + while (nsym_local < cnt) + { + XElf_Sym_vardef (locsym); + Elf32_Word locxndx; + XElf_Sym_vardef (globsym); + Elf32_Word globxndx; + + do + { + xelf_getsymshndx (symdata, xndxdata, nsym_local, locsym, locxndx); + /* This better works. */ + assert (locsym != NULL); + + if (XELF_ST_BIND (locsym->st_info) != STB_LOCAL + && (ld_state.need_symtab || ld_state.export_all_dynamic)) + { + do + { + xelf_getsymshndx (symdata, xndxdata, cnt, globsym, globxndx); + /* This better works. */ + assert (globsym != NULL); + + if (unlikely (XELF_ST_BIND (globsym->st_info) == STB_LOCAL)) + { + /* We swap the two entries. */ +#if NATIVE_ELF != 0 + /* Since we directly modify the data in the ELF + data structure we have to make a copy of one + of the entries. */ + XElf_Sym locsym_copy = *locsym; + locsym = &locsym_copy; +#endif + xelf_update_symshndx (symdata, xndxdata, nsym_local, + globsym, globxndx, 1); + xelf_update_symshndx (symdata, xndxdata, cnt, + locsym, locxndx, 1); + + /* Also swap the cross references. */ + dblindirect[nsym_local] = cnt; + dblindirect[cnt] = nsym_local; + + /* And the entries for the symbol names. */ + struct Ebl_Strent *strtmp = symstrent[nsym_local]; + symstrent[nsym_local] = symstrent[cnt]; + symstrent[cnt] = strtmp; + + /* And the mapping from symbol table entry to + struct symbol record. */ + struct symbol *symtmp = ndxtosym[nsym_local]; + ndxtosym[nsym_local] = ndxtosym[cnt]; + ndxtosym[cnt] = symtmp; + + /* Go to the next entry. */ + ++nsym_local; + --cnt; + + break; + } + + dblindirect[cnt] = cnt; + } + while (nsym_local < --cnt); + + break; + } + + dblindirect[nsym_local] = nsym_local; + } + while (++nsym_local < cnt); + } + + /* The symbol 'nsym_local' is currently pointing to might be local, + too. Check and increment the variable if this is the case. */ + if (likely (nsym_local < nsym)) + { + XElf_Sym_vardef (locsym); + + /* This entry isn't moved. */ + dblindirect[nsym_local] = nsym_local; + + /* Note that it is OK to not use 'xelf_getsymshndx' here. */ + xelf_getsym (symdata, nsym_local, locsym); + /* This better works. */ + assert (locsym != NULL); + + if (XELF_ST_BIND (locsym->st_info) == STB_LOCAL) + ++nsym_local; + } + + + /* We need the versym array right away to keep track of the version + symbols. */ + if (ld_state.versymscnidx != 0) + { + /* We allocate more memory than we need since the array is morroring + the dynamic symbol table and not the normal symbol table. I.e., + no local symbols are present. */ + versymscn = elf_getscn (ld_state.outelf, ld_state.versymscnidx); + versymdata = elf_newdata (versymscn); + if (versymdata == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create versioning section: %s"), + elf_errmsg (-1)); + + versymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_HALF, + nsym - nsym_local + 1); + versymdata->d_buf = xcalloc (1, versymdata->d_size); + versymdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_HALF, 1); + versymdata->d_off = 0; + versymdata->d_type = ELF_T_HALF; + } + + + /* If we have to construct the dynamic symbol table we must not include + the local symbols. If the normal symbol has to be emitted as well + we haven't done anything else yet and we can construct it from + scratch now. */ + if (unlikely (!ld_state.need_symtab)) + { + /* Note that the following code works even if there is no entry + to remove since the zeroth entry is always local. */ + size_t reduce = xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym_local - 1); + + XElf_Sym_vardef (nullsym); + xelf_getsym_ptr (symdata, nsym_local - 1, nullsym); + + /* Note that we don't have to use 'xelf_update_symshndx' since + this is the dynamic symbol table we write. */ + (void) xelf_update_sym (symdata, nsym_local - 1, + memset (nullsym, '\0', sizeof (*nullsym))); + + /* Update the buffer pointer and size in the output data. */ + symdata->d_buf = (char *) symdata->d_buf + reduce; + symdata->d_size -= reduce; + + /* Add the version symbol information. */ + if (versymdata != NULL) + { + nsym_dyn = 1; + for (cnt = nsym_local; cnt < nsym; ++cnt, ++nsym_dyn) + { + struct symbol *symp = ndxtosym[cnt]; + + if (symp->file->versymdata != NULL) + { + GElf_Versym versym; + + gelf_getversym (symp->file->versymdata, symp->symidx, + &versym); + + (void) gelf_update_versym (versymdata, nsym_dyn, + &symp->file->verdefused[versym]); + } + } + } + + /* Since we only created the dynamic symbol table the number of + dynamic symbols is the total number of symbols. */ + nsym_dyn = nsym - nsym_local + 1; + + /* XXX TBI. Create whatever data structure is missing. */ + abort (); + } + else if (ld_state.need_dynsym) + { + /* Create the dynamic symbol table section data along with the + string table. We look at all non-local symbols we found for + the normal symbol table and add those. */ + dynsymscn = elf_getscn (ld_state.outelf, ld_state.dynsymscnidx); + dynsymdata = elf_newdata (dynsymscn); + + dynstrdata = elf_newdata (elf_getscn (ld_state.outelf, + ld_state.dynstrscnidx)); + if (dynsymdata == NULL || dynstrdata == NULL) + error (EXIT_FAILURE, 0, gettext ("\ +cannot create dynamic symbol table for output file: %s"), + elf_errmsg (-1)); + + nsym_dyn_allocated = nsym - nsym_local + 1; + dynsymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, + nsym_dyn_allocated); + dynsymdata->d_buf = memset (xmalloc (dynsymdata->d_size), '\0', + xelf_fsize (ld_state.outelf, ELF_T_SYM, 1)); + dynsymdata->d_type = ELF_T_SYM; + dynsymdata->d_off = 0; + dynsymdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); + + /* We need one more array which contains the hash codes of the + symbol names. */ + hashcodes = (Elf32_Word *) xcalloc (nsym_dyn_allocated, + sizeof (Elf32_Word)); + + /* We have and empty entry at the beginning. */ + nsym_dyn = 1; + + /* We don't mix PLT symbols and others. */ + size_t plt_idx = 1; + size_t obj_idx = 1 + ld_state.nplt; + + /* Populate the table. */ + for (cnt = nsym_local; cnt < nsym; ++cnt) + { + XElf_Sym_vardef (sym); + + xelf_getsym (symdata, cnt, sym); + assert (sym != NULL); + + if (sym->st_shndx == SHN_XINDEX) + error (EXIT_FAILURE, 0, gettext ("\ +section index too large in dynamic symbol table")); + + /* We do not add the symbol to the dynamic symbol table if + + - the symbol is for a file + - it is not externally visible (internal, hidden) + - if export_all_dynamic is not set and is only defined in + the executable (i.e., it is defined, but not (also) in + in DSO) + + Set symstrent[cnt] to NULL in case an entry is ignored. */ + if (XELF_ST_TYPE (sym->st_info) == STT_FILE + || XELF_ST_VISIBILITY (sym->st_other) == STV_INTERNAL + || XELF_ST_VISIBILITY (sym->st_other) == STV_HIDDEN + || (!ndxtosym[cnt]->in_dso && ndxtosym[cnt]->defined)) + { + symstrent[cnt] = NULL; + continue; + } + + size_t idx; + if (ndxtosym[cnt]->in_dso && ndxtosym[cnt]->type == STT_FUNC) + { + idx = plt_idx++; + assert (idx < 1 + ld_state.nplt); + } + else + { + idx = obj_idx++; + assert (idx < nsym_dyn_allocated); + } + + /* Add the version information. */ + if (versymdata != NULL) + { + struct symbol *symp = ndxtosym[cnt]; + + if (symp->file->verdefdata != NULL) + { + GElf_Versym versym; + + gelf_getversym (symp->file->versymdata, symp->symidx, + &versym); + + (void) gelf_update_versym (versymdata, idx, + &symp->file->verdefused[versym]); + } + else + { + /* XXX Add support for version definitions. */ + GElf_Versym global = VER_NDX_GLOBAL; + (void) gelf_update_versym (versymdata, idx, &global); + } + } + + /* Store the index of the symbol in the dynamic symbol table. */ + ndxtosym[cnt]->outdynsymidx = idx; + + /* Create a new string table entry. */ + const char *str = ndxtosym[cnt]->name; + symstrent[cnt] = ebl_strtabadd (dynstrtab, str, 0); + hashcodes[idx] = elf_hash (str); + ++nsym_dyn; + } + assert (nsym_dyn == obj_idx); + assert (ld_state.nplt + 1 == plt_idx); + + /* Update the information about the symbol section. */ + if (versymdata != NULL) + { + /* Correct the size now that we know how many entries the + dynamic symbol table has. */ + versymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_HALF, + nsym_dyn); + + /* Add the reference to the symbol table. */ + xelf_getshdr (versymscn, shdr); + assert (shdr != NULL); + + shdr->sh_link = ld_state.dynsymscnidx; + + (void) xelf_update_shdr (versymscn, shdr); + } + } + + if (ld_state.file_type != relocatable_file_type) + { + size_t nbucket; + Elf32_Word *bucket; + Elf32_Word *chain; + size_t nchain; + Elf_Scn *hashscn; + Elf_Data *hashdata; + + /* Finalize the dynamic string table. */ + ebl_strtabfinalize (dynstrtab, dynstrdata); + + /* Determine the "optimal" bucket size. */ + nbucket = optimal_bucket_size (hashcodes, nsym_dyn, ld_state.optlevel); + + /* Create the .hash section data structures. */ + assert (ld_state.hashscnidx != 0); + hashscn = elf_getscn (ld_state.outelf, ld_state.hashscnidx); + xelf_getshdr (hashscn, shdr); + hashdata = elf_newdata (hashscn); + if (shdr == NULL || hashdata == NULL) + error (EXIT_FAILURE, 0, gettext ("\ +cannot create hash table section for output file: %s"), + elf_errmsg (-1)); + + shdr->sh_link = ld_state.dynsymscnidx; + (void) xelf_update_shdr (hashscn, shdr); + + hashdata->d_size = (2 + nsym_dyn + nbucket) * sizeof (Elf32_Word); + hashdata->d_buf = xcalloc (1, hashdata->d_size); + hashdata->d_align = sizeof (Elf32_Word); + hashdata->d_type = ELF_T_WORD; + hashdata->d_off = 0; + + ((Elf32_Word *) hashdata->d_buf)[0] = nbucket; + ((Elf32_Word *) hashdata->d_buf)[1] = nsym_dyn; + bucket = &((Elf32_Word *) hashdata->d_buf)[2]; + chain = &((Elf32_Word *) hashdata->d_buf)[2 + nbucket]; + + /* Haven't yet filled in any chain value. */ + nchain = 0; + + /* Now put the names in. */ + for (cnt = nsym_local; cnt < nsym; ++cnt) + if (symstrent[cnt] != NULL) + { + XElf_Sym_vardef (sym); + size_t hashidx; + size_t dynidx = ndxtosym[cnt]->outdynsymidx; + +#if NATIVE_ELF != 0 + XElf_Sym *osym; + memcpy (xelf_getsym (dynsymdata, dynidx, sym), + xelf_getsym (symdata, cnt, osym), + sizeof (XElf_Sym)); +#else + xelf_getsym (symdata, cnt, sym); + assert (sym != NULL); +#endif + + sym->st_name = ebl_strtaboffset (symstrent[cnt]); + + (void) xelf_update_sym (dynsymdata, dynidx, sym); + + /* Add to the hash table. */ + hashidx = hashcodes[dynidx] % nbucket; + if (bucket[hashidx] == 0) + bucket[hashidx] = dynidx; + else + { + hashidx = bucket[hashidx]; + while (chain[hashidx] != 0) + hashidx = chain[hashidx]; + + chain[hashidx] = dynidx; + } + } + + free (hashcodes); + + /* We don't need the map from the symbol table index to the symbol + structure anymore. */ + free (ndxtosym); + + /* Create the required version section. */ + if (ld_state.verneedscnidx != 0) + { + Elf_Scn *verneedscn; + Elf_Data *verneeddata; + struct usedfiles *runp; + size_t verneed_size = xelf_fsize (ld_state.outelf, ELF_T_VNEED, 1); + size_t vernaux_size = xelf_fsize (ld_state.outelf, ELF_T_VNAUX, 1); + size_t offset; + int ntotal; + + verneedscn = elf_getscn (ld_state.outelf, ld_state.verneedscnidx); + xelf_getshdr (verneedscn, shdr); + verneeddata = elf_newdata (verneedscn); + if (shdr == NULL || verneeddata == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create versioning data: %s"), + elf_errmsg (-1)); + + verneeddata->d_size = (ld_state.nverdeffile * verneed_size + + ld_state.nverdefused * vernaux_size); + verneeddata->d_buf = xmalloc (verneeddata->d_size); + verneeddata->d_type = ELF_T_VNEED; + verneeddata->d_align = xelf_fsize (ld_state.outelf, ELF_T_WORD, 1); + verneeddata->d_off = 0; + + offset = 0; + ntotal = ld_state.nverdeffile; + runp = ld_state.dsofiles->next; + do + { + offset = create_verneed_data (offset, verneeddata, runp, + &ntotal); + runp = runp->next; + } + while (ntotal > 0 && runp != ld_state.dsofiles->next); + + if (ntotal > 0) + { + runp = ld_state.needed->next; + do + { + offset = create_verneed_data (offset, verneeddata, runp, + &ntotal); + runp = runp->next; + } + while (ntotal > 0 && runp != ld_state.needed->next); + } + + assert (offset == verneeddata->d_size); + + /* Add the needed information to the section header. */ + shdr->sh_link = ld_state.dynstrscnidx; + shdr->sh_info = ld_state.nverdeffile; + (void) xelf_update_shdr (verneedscn, shdr); + } + + /* Adjust the section size. */ + dynsymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym_dyn); + if (versymdata != NULL) + versymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_HALF, + nsym_dyn); + + /* Add the remaining information to the section header. */ + xelf_getshdr (dynsymscn, shdr); + /* There is always exactly one local symbol. */ + shdr->sh_info = 1; + /* Reference the string table. */ + shdr->sh_link = ld_state.dynstrscnidx; + /* Write the updated info back. */ + (void) xelf_update_shdr (dynsymscn, shdr); + } + else + /* We don't need the map from the symbol table index to the symbol + structure anymore. */ + free (ndxtosym); + + /* We don't need the string table anymore. */ + free (symstrent); + + /* Remember the total number of symbols in the dynamic symbol table. */ + ld_state.ndynsym = nsym_dyn; + + /* Fill in the section header information. */ + symscn = elf_getscn (ld_state.outelf, ld_state.symscnidx); + xelf_getshdr (symscn, shdr); + if (shdr == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create symbol table for output file: %s"), + elf_errmsg (-1)); + + shdr->sh_type = SHT_SYMTAB; + shdr->sh_link = ld_state.strscnidx; + shdr->sh_info = nsym_local; + shdr->sh_entsize = xelf_fsize (ld_state.outelf, ELF_T_SYM, 1); + + (void) xelf_update_shdr (symscn, shdr); + + + /* Add names for the generated sections. */ + if (ld_state.symscnidx != 0) + symtab_ent = ebl_strtabadd (ld_state.shstrtab, ".symtab", 8); + if (ld_state.xndxscnidx != 0) + xndx_ent = ebl_strtabadd (ld_state.shstrtab, ".symtab_shndx", 14); + if (ld_state.strscnidx != 0) + strtab_ent = ebl_strtabadd (ld_state.shstrtab, ".strtab", 8); + /* At this point we would have to test for failures in the + allocation. But we skip this. First, the problem will be caught + latter when doing more allocations for the section header table. + Even if this would not be the case all that would happen is that + the section names are empty. The binary would still be usable if + it is an executable or a DSO. Not adding the test here saves + quite a bit of code. */ + + + /* Finally create the section for the section header string table. */ + shstrtab_scn = elf_newscn (ld_state.outelf); + shstrtab_ndx = elf_ndxscn (shstrtab_scn); + if (unlikely (shstrtab_ndx == SHN_UNDEF)) + error (EXIT_FAILURE, 0, + gettext ("cannot create section header string section: %s"), + elf_errmsg (-1)); + + /* Add the name of the section to the string table. */ + shstrtab_ent = ebl_strtabadd (ld_state.shstrtab, ".shstrtab", 10); + if (unlikely (shstrtab_ent == NULL)) + error (EXIT_FAILURE, errno, + gettext ("cannot create section header string section")); + + /* Finalize the section header string table. */ + data = elf_newdata (shstrtab_scn); + if (data == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section header string section: %s"), + elf_errmsg (-1)); + ebl_strtabfinalize (ld_state.shstrtab, data); + + /* Now we know the string offsets for all section names. */ + for (cnt = 0; cnt < ld_state.nallsections; ++cnt) + if (ld_state.allsections[cnt]->scnidx != 0) + { + Elf_Scn *scn; + + scn = elf_getscn (ld_state.outelf, ld_state.allsections[cnt]->scnidx); + + xelf_getshdr (scn, shdr); + assert (shdr != NULL); + + shdr->sh_name = ebl_strtaboffset (ld_state.allsections[cnt]->nameent); + + if (xelf_update_shdr (scn, shdr) == 0) + assert (0); + } + + /* Add the names for the generated sections to the respective + section headers. */ + if (symtab_ent != NULL) + { + Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.symscnidx); + + xelf_getshdr (scn, shdr); + /* This cannot fail, we already accessed the header before. */ + assert (shdr != NULL); + + shdr->sh_name = ebl_strtaboffset (symtab_ent); + + (void) xelf_update_shdr (scn, shdr); + } + if (xndx_ent != NULL) + { + Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.xndxscnidx); + + xelf_getshdr (scn, shdr); + /* This cannot fail, we already accessed the header before. */ + assert (shdr != NULL); + + shdr->sh_name = ebl_strtaboffset (xndx_ent); + + (void) xelf_update_shdr (scn, shdr); + } + if (strtab_ent != NULL) + { + Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.strscnidx); + + xelf_getshdr (scn, shdr); + /* This cannot fail, we already accessed the header before. */ + assert (shdr != NULL); + + shdr->sh_name = ebl_strtaboffset (strtab_ent); + + (void) xelf_update_shdr (scn, shdr); + } + + /* And the section header table section itself. */ + xelf_getshdr (shstrtab_scn, shdr); + if (shdr == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create section header string section: %s"), + elf_errmsg (-1)); + + shdr->sh_name = ebl_strtaboffset (shstrtab_ent); + shdr->sh_type = SHT_STRTAB; + + if (unlikely (xelf_update_shdr (shstrtab_scn, shdr) == 0)) + error (EXIT_FAILURE, 0, + gettext ("cannot create section header string section: %s"), + elf_errmsg (-1)); + + + /* Add the correct section header info to the section group sections. */ + groups = ld_state.groups; + while (groups != NULL) + { + Elf_Scn *scn; + struct scngroup *oldp; + Elf32_Word si; + + scn = elf_getscn (ld_state.outelf, groups->outscnidx); + xelf_getshdr (scn, shdr); + assert (shdr != NULL); + + shdr->sh_name = ebl_strtaboffset (groups->nameent); + shdr->sh_type = SHT_GROUP; + shdr->sh_flags = 0; + shdr->sh_link = ld_state.symscnidx; + shdr->sh_entsize = sizeof (Elf32_Word); + + /* Determine the index for the signature symbol. */ + si = groups->symbol->file->symindirect[groups->symbol->symidx]; + if (si == 0) + { + assert (groups->symbol->file->symref[groups->symbol->symidx] + != NULL); + si = groups->symbol->file->symref[groups->symbol->symidx]->outsymidx; + assert (si != 0); + } + shdr->sh_info = ld_state.dblindirect[si]; + + (void) xelf_update_shdr (scn, shdr); + + oldp = groups; + groups = groups->next; + free (oldp); + } + + + if (ld_state.file_type != relocatable_file_type) + { + size_t nphdr; + XElf_Addr addr; + struct output_segment *segment; + Elf_Scn *scn; + Elf32_Word nsec; + XElf_Phdr_vardef (phdr); + + /* Every executable needs a program header. The number of entries + varies. One exists for each segment. Each SHT_NOTE section gets + one, too. For dynamically linked executables we have to create + one for the program header, the interpreter, and the dynamic + section. First count the number of segments. + + XXX Determine whether the segment is non-empty. */ + nphdr = 0; + segment = ld_state.output_segments; + while (segment != NULL) + { + ++nphdr; + segment = segment->next; + } + + /* Add the number of SHT_NOTE sections. We counted them earlier. */ + nphdr += ld_state.nnotesections; + + /* If we create a DSO or the file is linked against DSOs we have three + more entries: INTERP, PHDR, DYNAMIC. */ + if (dynamically_linked_p ()) + nphdr += 3; + + /* Create the program header structure. */ + if (xelf_newphdr (ld_state.outelf, nphdr) == 0) + error (EXIT_FAILURE, 0, gettext ("cannot create program header: %s"), + elf_errmsg (-1)); + + + /* Determine the section sizes and offsets. We have to do this + to be able to determine the memory layout (which normally + differs from the file layout). */ + if (elf_update (ld_state.outelf, ELF_C_NULL) == -1) + error (EXIT_FAILURE, 0, gettext ("while determining file layout: %s"), + elf_errmsg (-1)); + + + /* Now determine the memory addresses of all the sections and + segments. */ + nsec = 0; + scn = elf_getscn (ld_state.outelf, ld_state.allsections[nsec]->scnidx); + xelf_getshdr (scn, shdr); + assert (shdr != NULL); + + /* The address we start with is the offset of the first (not + zeroth) section. */ + addr = shdr->sh_offset; + + /* The index of the first loadable segment. */ + nphdr = 1 + (dynamically_linked_p () == true) * 2; + + segment = ld_state.output_segments; + while (segment != NULL) + { + struct output_rule *orule; + bool first_section = true; + XElf_Off nobits_size = 0; + XElf_Off memsize = 0; + + /* the minimum alignment is a page size. */ + segment->align = ld_state.pagesize; + + for (orule = segment->output_rules; orule != NULL; + orule = orule->next) + if (orule->tag == output_section) + { + XElf_Off oldoff; + + /* See whether this output rule corresponds to the next + section. Yes, this is a pointer comparison. */ + if (ld_state.allsections[nsec]->name + != orule->val.section.name) + /* No, ignore this output rule. */ + continue; + + /* We assign addresses only in segments which are actually + loaded. */ + if (segment->mode != 0) + { + /* Adjust the offset of the input sections. */ + struct scninfo *isect; + struct scninfo *first; + + isect = first = ld_state.allsections[nsec]->last; + if (isect != NULL) + do + isect->offset += addr; + while ((isect = isect->next) != first); + + /* Set the address of current section. */ + shdr->sh_addr = addr; + + /* Write the result back. */ + (void) xelf_update_shdr (scn, shdr); + + /* Remember the address. */ + ld_state.allsections[nsec]->addr = addr; + } + + if (first_section) + { + /* The first segment starts at offset zero. */ + if (segment == ld_state.output_segments) + { + segment->offset = 0; + segment->addr = addr - shdr->sh_offset; + } + else + { + segment->offset = shdr->sh_offset; + segment->addr = addr; + } + + /* Determine the maximum alignment requirement. */ + segment->align = MAX (segment->align, shdr->sh_addralign); + + first_section = false; + } + + memsize = shdr->sh_offset - segment->offset + shdr->sh_size; + if (nobits_size != 0 && shdr->sh_type != SHT_NOTE) + error (EXIT_FAILURE, 0, gettext ("\ +internal error: nobits section follows nobits section")); + if (shdr->sh_type == SHT_NOBITS) + nobits_size += shdr->sh_size; + + /* Determine the new address which is computed using + the difference of the offsets on the sections. Note + that this assumes that the sections following each + other in the section header table are also + consecutive in the file. This is true here because + libelf constructs files this way. */ + oldoff = shdr->sh_offset; + + if (++nsec >= ld_state.nallsections) + break; + + scn = elf_getscn (ld_state.outelf, + ld_state.allsections[nsec]->scnidx); + xelf_getshdr (scn, shdr); + assert (shdr != NULL); + + /* This is the new address resulting from the offsets + in the file. */ + assert (oldoff <= shdr->sh_offset); + addr += shdr->sh_offset - oldoff; + } + else + { + assert (orule->tag == output_assignment); + + if (strcmp (orule->val.assignment->variable, ".") == 0) + /* This is a change of the address. */ + addr = eval_expression (orule->val.assignment->expression, + addr); + else if (orule->val.assignment->sym != NULL) + { + /* This symbol is used. Update the symbol table + entry. */ + XElf_Sym_vardef (sym); + size_t idx; + + /* Note that we do not have to use + xelf_getsymshndx since we only update the + symbol address, not the section + information. */ + idx = dblindirect[orule->val.assignment->sym->outsymidx]; + xelf_getsym (symdata, idx, sym); + sym->st_value = addr; + (void) xelf_update_sym (symdata, idx, sym); + + idx = orule->val.assignment->sym->outdynsymidx; + if (idx != 0) + { + assert (dynsymdata != NULL); + xelf_getsym (dynsymdata, idx, sym); + sym->st_value = addr; + (void) xelf_update_sym (dynsymdata, idx, sym); + } + } + } + + /* Store the segment parameter for loadable segments. */ + if (segment->mode != 0) + { + xelf_getphdr_ptr (ld_state.outelf, nphdr, phdr); + + phdr->p_type = PT_LOAD; + phdr->p_offset = segment->offset; + phdr->p_vaddr = segment->addr; + phdr->p_paddr = phdr->p_vaddr; + phdr->p_filesz = memsize - nobits_size; + phdr->p_memsz = memsize; + phdr->p_flags = segment->mode; + phdr->p_align = segment->align; + + (void) xelf_update_phdr (ld_state.outelf, nphdr, phdr); + ++nphdr; + } + + segment = segment->next; + } + + /* Create the other program header entries. */ + xelf_getehdr (ld_state.outelf, ehdr); + assert (ehdr != NULL); + + xelf_getphdr_ptr (ld_state.outelf, 1, phdr); + phdr->p_type = PT_PHDR; + phdr->p_offset = ehdr->e_phoff; + phdr->p_vaddr = ld_state.output_segments->addr + phdr->p_offset; + phdr->p_paddr = phdr->p_vaddr; + phdr->p_filesz = ehdr->e_phnum * ehdr->e_phentsize; + phdr->p_memsz = phdr->p_filesz; + phdr->p_flags = 0; /* No need to set PF_R or so. */ + phdr->p_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); + (void) xelf_update_phdr (ld_state.outelf, 0, phdr); + + + /* Adjust the addresses in the addresses of the symbol according + to the load addresses of the sections. */ + if (ld_state.need_symtab) + for (cnt = 1; cnt < nsym; ++cnt) + { + XElf_Sym_vardef (sym); + Elf32_Word shndx; + + xelf_getsymshndx (symdata, xndxdata, cnt, sym, shndx); + assert (sym != NULL); + + if (sym->st_shndx != SHN_XINDEX) + shndx = sym->st_shndx; + + if ((shndx > SHN_UNDEF && shndx < SHN_LORESERVE) + || shndx > SHN_HIRESERVE) + { + /* Note we subtract 1 from the section index since ALLSECTIONS + does not store the dummy section with offset zero. */ + sym->st_value += ld_state.allsections[shndx - 1]->addr; + + /* We don't have to use 'xelf_update_symshndx' since the + section number doesn't change. */ + (void) xelf_update_sym (symdata, cnt, sym); + } + } + + if (ld_state.need_dynsym) + for (cnt = 1; cnt < nsym_dyn; ++cnt) + { + XElf_Sym_vardef (sym); + + xelf_getsym (dynsymdata, cnt, sym); + assert (sym != NULL); + + if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) + { + /* Note we subtract 1 from the section index since ALLSECTIONS + does not store the dummy section with offset zero. */ + sym->st_value += ld_state.allsections[sym->st_shndx - 1]->addr; + + /* We don't have to use 'xelf_update_symshndx' since the + section number doesn't change. */ + (void) xelf_update_sym (dynsymdata, cnt, sym); + } + } + + + /* Now is a good time to determine the values of all the symbols + we encountered. */ + // XXX This loop is very inefficient. The hash tab iterator also + // returns all symbols in DSOs. + struct symbol *se; + void *p = NULL; + while ((se = ld_symbol_tab_iterate (&ld_state.symbol_tab, &p)) != NULL) + if (! se->in_dso) + { + XElf_Sym_vardef (sym); + + addr = 0; + + if (se->outdynsymidx != 0) + { + xelf_getsym (dynsymdata, se->outdynsymidx, sym); + assert (sym != NULL); + addr = sym->st_value; + } + else if (se->outsymidx != 0) + { + assert (dblindirect[se->outsymidx] != 0); + xelf_getsym (symdata, dblindirect[se->outsymidx], sym); + assert (sym != NULL); + addr = sym->st_value; + } + else + abort (); + + se->merge.value = addr; + } + + /* Complete the header of the .rel.dyn/.rela.dyn section. Point + to the symbol table. The sh_info field is left zero since + there is no specific section the contained relocations are + for. */ + if (ld_state.reldynscnidx != 0) + { + assert (ld_state.dynsymscnidx != 0); + scn = elf_getscn (ld_state.outelf, ld_state.reldynscnidx); + xelf_getshdr (scn, shdr); + assert (shdr != NULL); + + shdr->sh_link = ld_state.dynsymscnidx; + + (void) xelf_update_shdr (scn, shdr); + } + + /* Fill in the dynamic segment/section. */ + if (dynamically_linked_p ()) + { + Elf_Scn *outscn; + + assert (ld_state.interpscnidx != 0); + xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.interpscnidx), + shdr); + assert (shdr != NULL); + + /* The interpreter string. */ + // XXX Do we need to support files (DSOs) without interpreters? + xelf_getphdr_ptr (ld_state.outelf, 1, phdr); + phdr->p_type = PT_INTERP; + phdr->p_offset = shdr->sh_offset; + phdr->p_vaddr = shdr->sh_addr; + phdr->p_paddr = phdr->p_vaddr; + phdr->p_filesz = shdr->sh_size; + phdr->p_memsz = phdr->p_filesz; + phdr->p_flags = 0; /* No need to set PF_R or so. */ + phdr->p_align = 1; /* It's a string. */ + + (void) xelf_update_phdr (ld_state.outelf, 1, phdr); + + /* The pointer to the dynamic section. We this we need to + get the information for the dynamic section first. */ + assert (ld_state.dynamicscnidx); + outscn = elf_getscn (ld_state.outelf, ld_state.dynamicscnidx); + xelf_getshdr (outscn, shdr); + assert (shdr != NULL); + + xelf_getphdr_ptr (ld_state.outelf, 2, phdr); + phdr->p_type = PT_DYNAMIC; + phdr->p_offset = shdr->sh_offset; + phdr->p_vaddr = shdr->sh_addr; + phdr->p_paddr = phdr->p_vaddr; + phdr->p_filesz = shdr->sh_size; + phdr->p_memsz = phdr->p_filesz; + phdr->p_flags = 0; /* No need to set PF_R or so. */ + phdr->p_align = shdr->sh_addralign; + + (void) xelf_update_phdr (ld_state.outelf, 2, phdr); + + /* Fill in the reference to the .dynstr section. */ + assert (ld_state.dynstrscnidx != 0); + shdr->sh_link = ld_state.dynstrscnidx; + (void) xelf_update_shdr (outscn, shdr); + + /* And fill the remaining entries. */ + Elf_Data *dyndata = elf_getdata (outscn, NULL); + assert (dyndata != NULL); + + /* Add the DT_NEEDED entries. */ + if (ld_state.ndsofiles > 0) + { + struct usedfiles *runp = ld_state.dsofiles->next; + + do + if (! ld_state.ignore_unused_dsos || runp->used) + { + /* Add the position-dependent flag if necessary. */ + if (runp->lazyload) + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_POSFLAG_1, DF_P1_LAZYLOAD); + + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_NEEDED, + ebl_strtaboffset (runp->sonameent)); + } + while ((runp = runp->next) != ld_state.dsofiles->next); + } + + /* We can finish the DT_RUNPATH/DT_RPATH entries now. */ + if (ld_state.rxxpath_strent != NULL) + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + ld_state.rxxpath_tag, + ebl_strtaboffset (ld_state.rxxpath_strent)); + + /* Reference to initialization and finalization functions. */ + // XXX This code depends on symbol table being relocated. + if (ld_state.init_symbol != NULL) + { + XElf_Sym_vardef (sym); + + if (ld_state.need_symtab) + xelf_getsym (symdata, + dblindirect[ld_state.init_symbol->outsymidx], + sym); + else + xelf_getsym (dynsymdata, ld_state.init_symbol->outdynsymidx, + sym); + assert (sym != NULL); + + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_INIT, sym->st_value); + } + if (ld_state.fini_symbol != NULL) + { + XElf_Sym_vardef (sym); + + if (ld_state.need_symtab) + xelf_getsym (symdata, + dblindirect[ld_state.fini_symbol->outsymidx], + sym); + else + xelf_getsym (dynsymdata, ld_state.fini_symbol->outdynsymidx, + sym); + assert (sym != NULL); + + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_FINI, sym->st_value); + } + // XXX Support init,fini,preinit arrays + + /* The hash table which comes with dynamic symbol table. */ + xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.hashscnidx), + shdr); + assert (shdr != NULL); + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_HASH, + shdr->sh_addr); + + /* Reference to the symbol table section. */ + assert (ld_state.dynsymscnidx != 0); + xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.dynsymscnidx), + shdr); + assert (shdr != NULL); + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_SYMTAB, + shdr->sh_addr); + + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_SYMENT, + xelf_fsize (ld_state.outelf, ELF_T_SYM, 1)); + + /* And the string table which comes with it. */ + xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.dynstrscnidx), + shdr); + assert (shdr != NULL); + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_STRTAB, + shdr->sh_addr); + + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_STRSZ, + shdr->sh_size); + + /* Add the entries related to the .plt. */ + if (ld_state.nplt > 0) + { + xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.gotscnidx), + shdr); + assert (shdr != NULL); + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + // XXX This should probably be machine + // dependent. + DT_PLTGOT, shdr->sh_addr); + + xelf_getshdr (elf_getscn (ld_state.outelf, + ld_state.pltrelscnidx), shdr); + assert (shdr != NULL); + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_PLTRELSZ, shdr->sh_size); + + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_JMPREL, shdr->sh_addr); + + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_PLTREL, REL_TYPE (statep)); + } + + if (ld_state.relsize_total > 0) + { + int rel = REL_TYPE (statep); + xelf_getshdr (elf_getscn (ld_state.outelf, + ld_state.reldynscnidx), shdr); + assert (shdr != NULL); + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + rel, shdr->sh_addr); + + /* Trick ahead. Use arithmetic to get the right tag. + We check the validity of this assumption in the asserts. */ + assert (DT_RELASZ - DT_RELA == 1); + assert (DT_RELSZ - DT_REL == 1); + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + rel + 1, shdr->sh_size); + + /* Similar for the entry size tag. */ + assert (DT_RELAENT - DT_RELA == 2); + assert (DT_RELENT - DT_REL == 2); + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + rel + 2, + rel == DT_REL + ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1) + : xelf_fsize (ld_state.outelf, ELF_T_RELA, + 1)); + } + + if (ld_state.verneedscnidx != 0) + { + xelf_getshdr (elf_getscn (ld_state.outelf, + ld_state.verneedscnidx), shdr); + assert (shdr != NULL); + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_VERNEED, shdr->sh_addr); + + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_VERNEEDNUM, ld_state.nverdeffile); + } + + if (ld_state.versymscnidx != 0) + { + xelf_getshdr (elf_getscn (ld_state.outelf, + ld_state.versymscnidx), shdr); + assert (shdr != NULL); + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_VERSYM, shdr->sh_addr); + } + + /* We always create the DT_DEBUG entry. */ + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_DEBUG, 0); + assert (ld_state.ndynamic_filled < ld_state.ndynamic); + + /* Add the flag words if necessary. */ + if (ld_state.dt_flags != 0) + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_FLAGS, + ld_state.dt_flags); + + /* Create entry for the DT_FLAGS_1 flag. */ + if (ld_state.dt_flags_1 != 0) + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_FLAGS_1, ld_state.dt_flags_1); + + /* Create entry for the DT_FEATURE_1 flag. */ + if (ld_state.dt_feature_1 != 0) + new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, + DT_FEATURE_1, ld_state.dt_feature_1); + + assert (ld_state.ndynamic_filled <= ld_state.ndynamic); + } + } + + + // XXX The following code isn't nice. We use two different + // mechanisms to handle relocations, one for relocatable files, one + // for executables and DSOs. Maybe this is the best method but also + // maybe it can be somewhat unified. + + /* Now that we created the symbol table we can add the reference to + it in the sh_link field of the section headers of the relocation + sections. */ + while (rellist != NULL) + { + assert (ld_state.file_type == relocatable_file_type); + Elf_Scn *outscn; + + outscn = elf_getscn (ld_state.outelf, rellist->scnidx); + xelf_getshdr (outscn, shdr); + /* This must not fail since we did it before. */ + assert (shdr != NULL); + + /* Remember the symbol table which belongs to the relocation section. */ + shdr->sh_link = ld_state.symscnidx; + + /* And the reference to the section which is relocated by this + relocation section. We use the info from the first input + section but all records should have the same information. */ + shdr->sh_info = + rellist->scninfo->fileinfo->scninfo[SCNINFO_SHDR (rellist->scninfo->shdr).sh_info].outscnndx; + + + /* Perform the actual relocations. We only have to adjust + offsets and symbol indices. */ + RELOCATE_SECTION (statep, outscn, rellist->scninfo, dblindirect); + + /* Store the changes. */ + (void) xelf_update_shdr (outscn, shdr); + + /* Up to the next relocation section. */ + rellist = rellist->next; + } + + if (ld_state.rellist != NULL) + { + assert (ld_state.file_type != relocatable_file_type); + /* Create the relocations for the output file. */ + CREATE_RELOCATIONS (statep, dblindirect); + } + + + /* We need the ELF header once more. */ + xelf_getehdr (ld_state.outelf, ehdr); + assert (ehdr != NULL); + + /* Set the section header string table index. */ + if (likely (shstrtab_ndx < SHN_HIRESERVE) + && likely (shstrtab_ndx != SHN_XINDEX)) + ehdr->e_shstrndx = shstrtab_ndx; + else + { + /* We have to put the section index in the sh_link field of the + zeroth section header. */ + Elf_Scn *scn = elf_getscn (ld_state.outelf, 0); + + xelf_getshdr (scn, shdr); + if (unlikely (shdr == NULL)) + error (EXIT_FAILURE, 0, + gettext ("cannot get header of 0th section: %s"), + elf_errmsg (-1)); + + shdr->sh_link = shstrtab_ndx; + + (void) xelf_update_shdr (scn, shdr); + + ehdr->e_shstrndx = SHN_XINDEX; + } + + if (ld_state.file_type != relocatable_file_type) + /* DSOs and executables have to define the entry point symbol. */ + ehdr->e_entry = find_entry_point (); + + if (unlikely (xelf_update_ehdr (ld_state.outelf, ehdr) == 0)) + error (EXIT_FAILURE, 0, + gettext ("cannot update ELF header: %s"), + elf_errmsg (-1)); + + + /* Free the data which we don't need anymore. */ + free (ld_state.dblindirect); + + + /* Finalize the .plt section the what belongs to them. */ + FINALIZE_PLT (statep, nsym, nsym_dyn); + + return 0; +} + + +/* This is a function which must be specified in all backends. */ +static void +ld_generic_relocate_section (struct ld_state *statep, Elf_Scn *outscn, + struct scninfo *firstp, + const Elf32_Word *dblindirect) +{ + error (EXIT_FAILURE, 0, gettext ("\ +linker backend didn't specify function to relocate section")); + /* NOTREACHED */ +} + + +/* Finalize the output file. */ +static int +ld_generic_finalize (struct ld_state *statep) +{ + /* Write out the ELF file data. */ + if (elf_update (ld_state.outelf, ELF_C_WRITE) == -1) + error (EXIT_FAILURE, 0, gettext ("while writing output file: %s"), + elf_errmsg (-1)); + + /* Free the resources. */ + if (elf_end (ld_state.outelf) != 0) + error (EXIT_FAILURE, 0, gettext ("while finishing output file: %s"), + elf_errmsg (-1)); + + /* Get the file status of the temporary file. */ + struct stat temp_st; + if (fstat (ld_state.outfd, &temp_st) != 0) + error (EXIT_FAILURE, errno, gettext ("cannot stat output file")); + + /* Now it's time to rename the file. Remove an old existing file + first. */ + if (rename (ld_state.tempfname, ld_state.outfname) != 0) + /* Something went wrong. */ + error (EXIT_FAILURE, errno, gettext ("cannot rename output file")); + + /* Make sure the output file is really the one we created. */ + struct stat new_st; + if (stat (ld_state.outfname, &new_st) != 0 + || new_st.st_ino != temp_st.st_ino + || new_st.st_dev != temp_st.st_dev) + { + /* Wow, somebody overwrote the output file, probably some intruder. */ + unlink (ld_state.outfname); + error (EXIT_FAILURE, 0, gettext ("\ +WARNING: temporary output file overwritten before linking finished")); + } + + /* Close the file descriptor. */ + (void) close (ld_state.outfd); + + /* Signal the cleanup handler that the file is correctly created. */ + ld_state.tempfname = NULL; + + return 0; +} + + +static bool +ld_generic_special_section_number_p (struct ld_state *statep, size_t number) +{ + /* There are no special section numbers in the gABI. */ + return false; +} + + +static bool +ld_generic_section_type_p (struct ld_state *statep, GElf_Word type) +{ + if (type < SHT_NUM + /* XXX Enable the following two when implemented. */ + // || type == SHT_GNU_LIBLIST + // || type == SHT_CHECKSUM + /* XXX Eventually include SHT_SUNW_move, SHT_SUNW_COMDAT, and + SHT_SUNW_syminfo. */ + || (type >= SHT_GNU_verdef && type <= SHT_GNU_versym)) + return true; + + return false; +} + + +static XElf_Xword +ld_generic_dynamic_section_flags (struct ld_state *statep) +{ + /* By default the .dynamic section is writable (and is of course + loaded). Few architecture differ from this. */ + return SHF_ALLOC | SHF_WRITE; +} + + +static void +ld_generic_initialize_plt (struct ld_state *statep, Elf_Scn *scn) +{ + /* This cannot be implemented generally. There should have been a + machine dependent implementation and we should never have arrived + here. */ + error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), + "initialize_plt"); +} + + +static void +ld_generic_initialize_pltrel (struct ld_state *statep, Elf_Scn *scn) +{ + /* This cannot be implemented generally. There should have been a + machine dependent implementation and we should never have arrived + here. */ + error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), + "initialize_pltrel"); +} + + +static void +ld_generic_initialize_got (struct ld_state *statep, Elf_Scn *scn) +{ + /* This cannot be implemented generally. There should have been a + machine dependent implementation and we should never have arrived + here. */ + error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), + "initialize_got"); +} + + +static void +ld_generic_finalize_plt (struct ld_state *statep, size_t nsym, size_t nsym_dyn) +{ + /* By default we assume that nothing has to be done. */ +} + + +static int +ld_generic_rel_type (struct ld_state *statep) +{ + /* This cannot be implemented generally. There should have been a + machine dependent implementation and we should never have arrived + here. */ + error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), + "rel_type"); + /* Just to keep the compiler calm. */ + return 0; +} + + +static void +ld_generic_count_relocations (struct ld_state *statep, struct scninfo *scninfo) +{ + /* This cannot be implemented generally. There should have been a + machine dependent implementation and we should never have arrived + here. */ + error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), + "count_relocations"); +} + + +static void +ld_generic_create_relocations (struct ld_state *statep, + const Elf32_Word *dblindirect) +{ + /* This cannot be implemented generally. There should have been a + machine dependent implementation and we should never have arrived + here. */ + error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), + "create_relocations"); +} diff --git a/src/ldlex.l b/src/ldlex.l new file mode 100644 index 00000000..9e30a865 --- /dev/null +++ b/src/ldlex.l @@ -0,0 +1,349 @@ +%{ +/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "ldscript.h" + +/* We sure use no threads to read the stream, so use the _unlocked + variants of the functions. */ +#undef getc +#define getc(s) getc_unlocked (s) +#undef ferror +#define ferror(s) ferror_unlocked (s) +#undef fread +#define fread(b, m, n, s) fread_unlocked (b, m, n, s) +#undef fwrite +#define fwrite(b, m, n, s) fwrite_unlocked (b, m, n, s) + +/* ECHO must be redefined since the default implementation ignores + the return value of fwrite_unlocked. */ +#define ECHO do { size_t n__ __attribute__ ((unused)) \ + = fwrite (yytext, yyleng, 1, yyout); } while (0) + +/* Defined in ld.c. */ +extern int ld_scan_version_script; + +#define MAX_PREPDEPTH 20 +static enum prepstate +{ + prep_normal, + skip_if, + skip_to_endif +} prepstate[MAX_PREPDEPTH]; +static int prepdepth; + +static void eat_comment (void); +static void eat_to_eol (bool empty); +static int attrib_convert (int c); +static void push_state (enum prepstate); +static int pop_state (void); +static int handle_ifdef (void); +static void invalid_char (int ch); +%} + +ID [a-zA-Z0-9_.*?]+ +FILENAMECHAR1 [a-zA-Z0-9_/.\\~] +FILENAMECHAR [^][{}[:space:]():;]+ +HEX 0[xX][0-9a-fA-F]+[kKmM]? +OCT 0[0-7]*[kKmM]? +DEC [0-9]+[kKmM]? +WHITE [[:space:]]+ + +%option yylineno +%option never-interactive +%option noyywrap + +%x IGNORE + +%% + if (unlikely (ld_scan_version_script)) + { + ld_scan_version_script = -1; + return kVERSION_SCRIPT; + } + +^"#"ifdef/[[:space:]] { BEGIN (handle_ifdef ()); } +^"#"else/[[:space:]\n] { eat_to_eol (true); + push_state (skip_to_endif); + BEGIN (IGNORE); } +^"#"elifdef/[[:space:]] { eat_to_eol (false); + push_state (skip_to_endif); + BEGIN (IGNORE); } +^"#"endif/[[:space:]\n] { eat_to_eol (true) ; } + +^"#"ifdef/[[:space:]\n] { eat_to_eol (false); + push_state (skip_to_endif); } +^"#"else/[[:space:]\n] { eat_to_eol (true); + assert (prepdepth > 0); + if (prepstate[prepdepth - 1] == skip_if) + { + /* Back to normal processing. */ + assert (prepdepth == 1); + BEGIN (pop_state ()); + } + } +^"#"elifdef/[[:space:]] { assert (prepdepth > 0); + if (prepstate[prepdepth - 1] == skip_if) + { + /* Maybe this symbol is defined. */ + pop_state (); + BEGIN (handle_ifdef ()); + } + } +^"#"endif/[[:space:]\n] { eat_to_eol (true); + BEGIN (pop_state ()); } +.|\n { /* nothing */ } + + +"/*" { eat_comment (); } + +ALIGN { return kALIGN; } +AS_NEEDED { return kAS_NEEDED; } +ENTRY { return kENTRY; } +EXCLUDE_FILE { return kEXCLUDE_FILE; } +"global:" { return kGLOBAL; } +GROUP { return kGROUP; } +INPUT { return kINPUT; } +INTERP { return kINTERP; } +KEEP { return kKEEP; } +"local:" { return kLOCAL; } +OUTPUT_FORMAT { return kOUTPUT_FORMAT; } +PAGESIZE { return kPAGESIZE; } +PROVIDE { return kPROVIDE; } +SEARCH_DIR { return kSEARCH_DIR; } +SEGMENT { return kSEGMENT; } +SIZEOF_HEADERS { return kSIZEOF_HEADERS; } +SORT { return kSORT; } +VERSION { return kVERSION; } + +"["([RWX]){0,3}"]" { int cnt = 1 ; + ldlval.num = 0; + while (cnt < yyleng - 1) + ldlval.num |= attrib_convert (yytext[cnt++]); + return kMODE; } + +"{" { return '{'; } +"}" { return '}'; } +"(" { return '('; } +")" { return ')'; } +":" { return ':'; } +";" { return ';'; } +"=" { return '='; } +"+" { ldlval.op = exp_plus; return kADD_OP; } +"-" { ldlval.op = exp_minus; return kADD_OP; } +"*" { return '*'; } +"/" { ldlval.op = exp_div; return kMUL_OP; } +"%" { ldlval.op = exp_mod; return kMUL_OP; } +"&" { return '&'; } +"|" { return '|'; } + +"," { return ','; } + +{HEX}|{OCT}|{DEC} { char *endp; + ldlval.num = strtoumax (yytext, &endp, 0); + if (*endp != '\0') + { + if (tolower (*endp) == 'k') + ldlval.num *= 1024; + else + { + assert (tolower (*endp) == 'm'); + ldlval.num *= 1024 * 1024; + } + } + return kNUM; } + +{ID} { ldlval.str = obstack_strndup (&ld_state.smem, + yytext, yyleng); + return kID; } + +{FILENAMECHAR1}{FILENAMECHAR} { ldlval.str = obstack_strndup (&ld_state.smem, + yytext, yyleng); + return kFILENAME; } + +{WHITE} { /* IGNORE */ } + +. { invalid_char (*yytext); } + +%% + +static void +eat_comment (void) +{ + while (1) + { + int c = input (); + + while (c != '*' && c != EOF) + c = input (); + + if (c == '*') + { + c = input (); + while (c == '*') + c = input (); + if (c == '/') + break; + } + + if (c == EOF) + { + /* XXX Use the setjmp buffer and signal EOF in comment */ + error (0, 0, gettext ("EOF in comment")); + break; + } + } +} + + +static void +eat_to_eol (bool empty) +{ + bool warned = false; + + while (1) + { + int c = input (); + + if (c == EOF) + break; + if (c == '\n') + { + ++yylineno; + break; + } + + if (empty && ! isspace (c) && ! warned) + { + error (0, 0, gettext ("%d: garbage at end of line"), yylineno); + warned = true; + } + } +} + + +static int +attrib_convert (int c) +{ + if (c == 'X') + return PF_X; + if (c == 'W') + return PF_W; + assert (c == 'R'); + return PF_R; +} + + +static void +push_state (enum prepstate state) +{ + if (prepdepth >= MAX_PREPDEPTH) + error (EXIT_FAILURE, 0, gettext ("%d: conditionals nested too deep"), + yylineno); + + prepstate[prepdepth++] = state; +} + + +static int +pop_state (void) +{ + if (prepdepth == 0) + error (0, 0, gettext ("%d: unexpected #endif"), yylineno); + else + --prepdepth; + + return prepdepth == 0 ? INITIAL : IGNORE; +} + + +static int +handle_ifdef (void) +{ + char idbuf[50]; + char *id = idbuf; + size_t idlen = 0; + size_t idmax = sizeof (idbuf); + bool ignore_ws = true; + bool defined = false; + int result; + + while (1) + { + int c = input (); + + if (isspace (c) && ignore_ws) + continue; + + if (c != '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') + && (idlen == 0 || c < '0' || c > '9')) + { + unput (c); + break; + } + + if (idlen == idmax) + { + char *newp = (char *) alloca (idmax *= 2); + id = memcpy (newp, id, idlen); + } + + id[idlen++] = c; + ignore_ws = false; + } + + /* XXX Compare in a better way. */ + if (idlen == 6 && strncmp (id, "SHARED", 6) == 0) + defined = ld_state.file_type == dso_file_type; + + if (defined) + result = INITIAL; + else + { + push_state (skip_if); + result = IGNORE; + } + + return result; +} + + +static void +invalid_char (int ch) +{ + error (0, 0, (isascii (ch) + ? gettext ("invalid character '%c' at line %d; ignored") + : gettext ("invalid character '\\%o' at line %d; ignored")), + ch, yylineno); +} + + +// Local Variables: +// mode: C +// End: diff --git a/src/ldscript.y b/src/ldscript.y new file mode 100644 index 00000000..23741b7d --- /dev/null +++ b/src/ldscript.y @@ -0,0 +1,795 @@ +%{ +/* Parser for linker scripts. + Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* The error handler. */ +static void yyerror (const char *s); + +/* Some helper functions we need to construct the data structures + describing information from the file. */ +static struct expression *new_expr (int tag); +static struct input_section_name *new_input_section_name (const char *name, + bool sort_flag); +static struct input_rule *new_input_rule (int tag); +static struct output_rule *new_output_rule (int tag); +static struct assignment *new_assignment (const char *variable, + struct expression *expression, + bool provide_flag); +static void new_segment (int mode, struct output_rule *output_rule); +static struct filename_list *new_filename_listelem (const char *string); +static void add_inputfiles (struct filename_list *fnames); +static struct id_list *new_id_listelem (const char *str); + static struct filename_list *mark_as_needed (struct filename_list *listp); +static struct version *new_version (struct id_list *local, + struct id_list *global); +static struct version *merge_versions (struct version *one, + struct version *two); +static void add_versions (struct version *versions); + +extern int yylex (void); +%} + +%union { + uintmax_t num; + enum expression_tag op; + char *str; + struct expression *expr; + struct input_section_name *sectionname; + struct filemask_section_name *filemask_section_name; + struct input_rule *input_rule; + struct output_rule *output_rule; + struct assignment *assignment; + struct filename_list *filename_list; + struct version *version; + struct id_list *id_list; +} + +%token kADD_OP +%token kALIGN +%token kAS_NEEDED +%token kENTRY +%token kEXCLUDE_FILE +%token kFILENAME +%token kGLOBAL +%token kGROUP +%token kID +%token kINPUT +%token kINTERP +%token kKEEP +%token kLOCAL +%token kMODE +%token kMUL_OP +%token kNUM +%token kOUTPUT_FORMAT +%token kPAGESIZE +%token kPROVIDE +%token kSEARCH_DIR +%token kSEGMENT +%token kSIZEOF_HEADERS +%token kSORT +%token kVERSION +%token kVERSION_SCRIPT + +%left '|' +%left '&' +%left ADD_OP +%left MUL_OP '*' + +%type kADD_OP +%type kMUL_OP +%type filename_id +%type filename_id_star +%type exclude_opt +%type expr +%type sort_opt_name +%type sectionname +%type inputsection +%type inputsections +%type outputsection +%type outputsections +%type assignment +%type filename_id_list +%type versionlist +%type version +%type version_stmt_list +%type version_stmt +%type filename_id_star_list + +%expect 16 + +%% + +script_or_version: + file + | kVERSION_SCRIPT versionlist + { add_versions ($2); } + ; + +file: file content + | content + ; + +content: kENTRY '(' kID ')' ';' + { + if (likely (ld_state.entry == NULL)) + ld_state.entry = $3; + } + | kSEARCH_DIR '(' filename_id ')' ';' + { + ld_new_searchdir ($3); + } + | kPAGESIZE '(' kNUM ')' ';' + { + if (likely (ld_state.pagesize == 0)) + ld_state.pagesize = $3; + } + | kINTERP '(' filename_id ')' ';' + { + if (likely (ld_state.interp == NULL)) + ld_state.interp = $3; + } + | kSEGMENT kMODE '{' outputsections '}' + { + new_segment ($2, $4); + } + | kSEGMENT error '{' outputsections '}' + { + fputs_unlocked (gettext ("mode for segment invalid\n"), + stderr); + new_segment (0, $4); + } + | kGROUP '(' filename_id_list ')' + { + /* First little optimization. If there is only one + file in the group don't do anything. */ + if ($3 != $3->next) + { + $3->next->group_start = 1; + $3->group_end = 1; + } + add_inputfiles ($3); + } + | kINPUT '(' filename_id_list ')' + { add_inputfiles ($3); } + | kAS_NEEDED '(' filename_id_list ')' + { add_inputfiles (mark_as_needed ($3)); } + | kVERSION '{' versionlist '}' + { add_versions ($3); } + | kOUTPUT_FORMAT '(' filename_id ')' + { /* XXX TODO */ } + ; + +outputsections: outputsections outputsection + { + $2->next = $1->next; + $$ = $1->next = $2; + } + | outputsection + { $$ = $1; } + ; + +outputsection: assignment ';' + { + $$ = new_output_rule (output_assignment); + $$->val.assignment = $1; + } + | kID '{' inputsections '}' + { + $$ = new_output_rule (output_section); + $$->val.section.name = $1; + $$->val.section.input = $3->next; + if (ld_state.strip == strip_debug + && ebl_debugscn_p (ld_state.ebl, $1)) + $$->val.section.ignored = true; + else + $$->val.section.ignored = false; + $3->next = NULL; + } + | kID ';' + { + /* This is a short cut for "ID { *(ID) }". */ + $$ = new_output_rule (output_section); + $$->val.section.name = $1; + $$->val.section.input = new_input_rule (input_section); + $$->val.section.input->next = NULL; + $$->val.section.input->val.section = + (struct filemask_section_name *) + obstack_alloc (&ld_state.smem, + sizeof (struct filemask_section_name)); + $$->val.section.input->val.section->filemask = NULL; + $$->val.section.input->val.section->excludemask = NULL; + $$->val.section.input->val.section->section_name = + new_input_section_name ($1, false); + $$->val.section.input->val.section->keep_flag = false; + if (ld_state.strip == strip_debug + && ebl_debugscn_p (ld_state.ebl, $1)) + $$->val.section.ignored = true; + else + $$->val.section.ignored = false; + } + ; + +assignment: kID '=' expr + { $$ = new_assignment ($1, $3, false); } + | kPROVIDE '(' kID '=' expr ')' + { $$ = new_assignment ($3, $5, true); } + ; + +inputsections: inputsections inputsection + { + $2->next = $1->next; + $$ = $1->next = $2; + } + | inputsection + { $$ = $1; } + ; + +inputsection: sectionname + { + $$ = new_input_rule (input_section); + $$->val.section = $1; + } + | kKEEP '(' sectionname ')' + { + $3->keep_flag = true; + + $$ = new_input_rule (input_section); + $$->val.section = $3; + } + | assignment ';' + { + $$ = new_input_rule (input_assignment); + $$->val.assignment = $1; + } + ; + +sectionname: filename_id_star '(' exclude_opt sort_opt_name ')' + { + $$ = (struct filemask_section_name *) + obstack_alloc (&ld_state.smem, sizeof (*$$)); + $$->filemask = $1; + $$->excludemask = $3; + $$->section_name = $4; + $$->keep_flag = false; + } + ; + +sort_opt_name: kID + { $$ = new_input_section_name ($1, false); } + | kSORT '(' kID ')' + { $$ = new_input_section_name ($3, true); } + ; + +exclude_opt: kEXCLUDE_FILE '(' filename_id ')' + { $$ = $3; } + | + { $$ = NULL; } + ; + +expr: kALIGN '(' expr ')' + { + $$ = new_expr (exp_align); + $$->val.child = $3; + } + | '(' expr ')' + { $$ = $2; } + | expr '*' expr + { + $$ = new_expr (exp_mult); + $$->val.binary.left = $1; + $$->val.binary.right = $3; + } + | expr kMUL_OP expr + { + $$ = new_expr ($2); + $$->val.binary.left = $1; + $$->val.binary.right = $3; + } + | expr kADD_OP expr + { + $$ = new_expr ($2); + $$->val.binary.left = $1; + $$->val.binary.right = $3; + } + | expr '&' expr + { + $$ = new_expr (exp_and); + $$->val.binary.left = $1; + $$->val.binary.right = $3; + } + | expr '|' expr + { + $$ = new_expr (exp_or); + $$->val.binary.left = $1; + $$->val.binary.right = $3; + } + | kNUM + { + $$ = new_expr (exp_num); + $$->val.num = $1; + } + | kID + { + $$ = new_expr (exp_id); + $$->val.str = $1; + } + | kSIZEOF_HEADERS + { $$ = new_expr (exp_sizeof_headers); } + | kPAGESIZE + { $$ = new_expr (exp_pagesize); } + ; + +filename_id_list: kGROUP '(' filename_id_list ')' + { + /* First little optimization. If there is only one + file in the group don't do anything. */ + if ($3 != $3->next) + { + $3->next->group_start = 1; + $3->group_end = 1; + } + $$ = $3; + } + | kAS_NEEDED '(' filename_id_list ')' + { $$ = mark_as_needed ($3); } + | filename_id_list comma_opt filename_id + { + struct filename_list *newp = new_filename_listelem ($3); + newp->next = $1->next; + $$ = $1->next = newp; + } + | filename_id + { $$ = new_filename_listelem ($1); } + ; + +comma_opt: ',' + | + ; + +versionlist: versionlist version + { + $2->next = $1->next; + $$ = $1->next = $2; + } + | version + { $$ = $1; } + ; + +version: '{' version_stmt_list '}' ';' + { + $2->versionname = ""; + $2->parentname = NULL; + $$ = $2; + } + | filename_id '{' version_stmt_list '}' ';' + { + $3->versionname = $1; + $3->parentname = NULL; + $$ = $3; + } + | filename_id '{' version_stmt_list '}' filename_id ';' + { + $3->versionname = $1; + $3->parentname = $5; + $$ = $3; + } + ; + +version_stmt_list: + version_stmt_list version_stmt + { $$ = merge_versions ($1, $2); } + | version_stmt + { $$ = $1; } + ; + +version_stmt: kGLOBAL filename_id_star_list + { $$ = new_version (NULL, $2); } + | kLOCAL filename_id_star_list + { $$ = new_version ($2, NULL); } + ; + +filename_id_star_list: + filename_id_star_list filename_id_star ';' + { + struct id_list *newp = new_id_listelem ($2); + newp->next = $1->next; + $$ = $1->next = newp; + } + | filename_id_star ';' + { $$ = new_id_listelem ($1); } + ; + +filename_id: kFILENAME + { $$ = $1; } + | kID + { $$ = $1; } + ; + +filename_id_star: filename_id + { $$ = $1; } + | '*' + { $$ = NULL; } + ; + +%% + +static void +yyerror (const char *s) +{ + error (0, 0, (ld_scan_version_script + ? gettext ("while reading version script '%s': %s at line %d") + : gettext ("while reading linker script '%s': %s at line %d")), + ldin_fname, gettext (s), ldlineno); +} + + +static struct expression * +new_expr (int tag) +{ + struct expression *newp = (struct expression *) + obstack_alloc (&ld_state.smem, sizeof (*newp)); + + newp->tag = tag; + return newp; +} + + +static struct input_section_name * +new_input_section_name (const char *name, bool sort_flag) +{ + struct input_section_name *newp = (struct input_section_name *) + obstack_alloc (&ld_state.smem, sizeof (*newp)); + + newp->name = name; + newp->sort_flag = sort_flag; + return newp; +} + + +static struct input_rule * +new_input_rule (int tag) +{ + struct input_rule *newp = (struct input_rule *) + obstack_alloc (&ld_state.smem, sizeof (*newp)); + + newp->tag = tag; + newp->next = newp; + return newp; +} + + +static struct output_rule * +new_output_rule (int tag) +{ + struct output_rule *newp = (struct output_rule *) + memset (obstack_alloc (&ld_state.smem, sizeof (*newp)), + '\0', sizeof (*newp)); + + newp->tag = tag; + newp->next = newp; + return newp; +} + + +static struct assignment * +new_assignment (const char *variable, struct expression *expression, + bool provide_flag) +{ + struct assignment *newp = (struct assignment *) + obstack_alloc (&ld_state.smem, sizeof (*newp)); + + newp->variable = variable; + newp->expression = expression; + newp->sym = NULL; + newp->provide_flag = provide_flag; + + /* Insert the symbol into a hash table. We will later have to matc*/ + return newp; +} + + +static void +new_segment (int mode, struct output_rule *output_rule) +{ + struct output_segment *newp; + + newp + = (struct output_segment *) obstack_alloc (&ld_state.smem, sizeof (*newp)); + newp->mode = mode; + newp->next = newp; + + newp->output_rules = output_rule->next; + output_rule->next = NULL; + + /* Enqueue the output segment description. */ + if (ld_state.output_segments == NULL) + ld_state.output_segments = newp; + else + { + newp->next = ld_state.output_segments->next; + ld_state.output_segments = ld_state.output_segments->next = newp; + } + + /* If the output file should be stripped of all symbol set the flag + in the structures of all output sections. */ + if (mode == 0 && ld_state.strip == strip_all) + { + struct output_rule *runp; + + for (runp = newp->output_rules; runp != NULL; runp = runp->next) + if (runp->tag == output_section) + runp->val.section.ignored = true; + } +} + + +static struct filename_list * +new_filename_listelem (const char *string) +{ + struct filename_list *newp; + + /* We use calloc and not the obstack since this object can be freed soon. */ + newp = (struct filename_list *) xcalloc (1, sizeof (*newp)); + newp->name = string; + newp->next = newp; + return newp; +} + + +static struct filename_list * +mark_as_needed (struct filename_list *listp) +{ + struct filename_list *runp = listp; + while (runp != NULL) + { + runp->as_needed = true; + runp = runp->next; + } + + return listp; +} + + +static void +add_inputfiles (struct filename_list *fnames) +{ + assert (fnames != NULL); + + if (ld_state.srcfiles == NULL) + ld_state.srcfiles = fnames; + else + { + struct filename_list *first = ld_state.srcfiles->next; + + ld_state.srcfiles->next = fnames->next; + fnames->next = first; + ld_state.srcfiles->next = fnames; + } +} + + +static _Bool +special_char_p (const char *str) +{ + while (*str != '\0') + { + if (__builtin_expect (*str == '*', 0) + || __builtin_expect (*str == '?', 0) + || __builtin_expect (*str == '[', 0)) + return true; + + ++str; + } + + return false; +} + + +static struct id_list * +new_id_listelem (const char *str) +{ + struct id_list *newp; + + newp = (struct id_list *) obstack_alloc (&ld_state.smem, sizeof (*newp)); + if (str == NULL) + newp->u.id_type = id_all; + else if (__builtin_expect (special_char_p (str), false)) + newp->u.id_type = id_wild; + else + newp->u.id_type = id_str; + newp->id = str; + newp->next = newp; + + return newp; +} + + +static struct version * +new_version (struct id_list *local, struct id_list *global) +{ + struct version *newp; + + newp = (struct version *) obstack_alloc (&ld_state.smem, sizeof (*newp)); + newp->next = newp; + newp->local_names = local; + newp->global_names = global; + newp->versionname = NULL; + newp->parentname = NULL; + + return newp; +} + + +static struct version * +merge_versions (struct version *one, struct version *two) +{ + assert (two->local_names == NULL || two->global_names == NULL); + + if (two->local_names != NULL) + { + if (one->local_names == NULL) + one->local_names = two->local_names; + else + { + two->local_names->next = one->local_names->next; + one->local_names = one->local_names->next = two->local_names; + } + } + else + { + if (one->global_names == NULL) + one->global_names = two->global_names; + else + { + two->global_names->next = one->global_names->next; + one->global_names = one->global_names->next = two->global_names; + } + } + + return one; +} + + +static void +add_id_list (const char *versionname, struct id_list *runp, _Bool local) +{ + struct id_list *lastp = runp; + + if (runp == NULL) + /* Nothing to do. */ + return; + + /* Convert into a simple single-linked list. */ + runp = runp->next; + assert (runp != NULL); + lastp->next = NULL; + + do + if (runp->u.id_type == id_str) + { + struct id_list *curp; + struct id_list *defp; + unsigned long int hval = elf_hash (runp->id); + + curp = runp; + runp = runp->next; + + defp = ld_version_str_tab_find (&ld_state.version_str_tab, hval, curp); + if (defp != NULL) + { + /* There is already a version definition for this symbol. */ + while (strcmp (defp->u.s.versionname, versionname) != 0) + { + if (defp->next == NULL) + { + /* No version like this so far. */ + defp->next = curp; + curp->u.s.local = local; + curp->u.s.versionname = versionname; + curp->next = NULL; + defp = NULL; + break; + } + + defp = defp->next; + } + + if (defp != NULL && defp->u.s.local != local) + error (EXIT_FAILURE, 0, versionname[0] == '\0' + ? gettext ("\ +symbol '%s' in declared both local and global for unnamed version") + : gettext ("\ +symbol '%s' in declared both local and global for version '%s'"), + runp->id, versionname); + } + else + { + /* This is the first version definition for this symbol. */ + ld_version_str_tab_insert (&ld_state.version_str_tab, hval, curp); + + curp->u.s.local = local; + curp->u.s.versionname = versionname; + curp->next = NULL; + } + } + else if (runp->u.id_type == id_all) + { + if (local) + { + if (ld_state.default_bind_global) + error (EXIT_FAILURE, 0, + gettext ("default visibility set as local and global")); + ld_state.default_bind_local = true; + } + else + { + if (ld_state.default_bind_local) + error (EXIT_FAILURE, 0, + gettext ("default visibility set as local and global")); + ld_state.default_bind_global = true; + } + + runp = runp->next; + } + else + { + assert (runp->u.id_type == id_wild); + /* XXX TBI */ + abort (); + } + while (runp != NULL); +} + + +static void +add_versions (struct version *versions) +{ + struct version *lastp = versions; + + if (versions == NULL) + return; + + /* Convert into a simple single-linked list. */ + versions = versions->next; + assert (versions != NULL); + lastp->next = NULL; + + do + { + struct version *oldp; + + add_id_list (versions->versionname, versions->local_names, true); + add_id_list (versions->versionname, versions->global_names, false); + + oldp = versions; + versions = versions->next; + } + while (versions != NULL); +} diff --git a/src/libld_elf_i386.map b/src/libld_elf_i386.map new file mode 100644 index 00000000..703af6d8 --- /dev/null +++ b/src/libld_elf_i386.map @@ -0,0 +1,7 @@ +ELFUTILS_1.0 { + global: + elf_i386_ld_init; + + local: + *; +}; diff --git a/src/nm.c b/src/nm.c new file mode 100644 index 00000000..b1e71a33 --- /dev/null +++ b/src/nm.c @@ -0,0 +1,1282 @@ +/* Print symbol information from ELF file in human-readable form. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../libebl/libeblP.h" + + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Bug report address. */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + + +/* Values for the parameters which have no short form. */ +#define OPT_DEFINED 0x100 +#define OPT_MARK_WEAK 0x101 + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { NULL, 0, NULL, 0, N_("Output selection:"), 0 }, + { "debug-syms", 'a', NULL, 0, N_("Display debugger-only symbols"), 0 }, + { "defined-only", OPT_DEFINED, NULL, 0, N_("Display only defined symbols"), + 0 }, + { "dynamic", 'D', NULL, 0, + N_("Display dynamic symbols instead of normal symbols"), 0 }, + { "extern-only", 'g', NULL, 0, N_("Display only external symbols"), 0 }, + { "undefined-only", 'u', NULL, 0, N_("Display only undefined symbols"), 0 }, + { "print-armap", 's', NULL, 0, + N_("Include index for symbols from archive members"), 0 }, + + { NULL, 0, NULL, 0, N_("Output format:"), 0 }, + { "print-file-name", 'A', NULL, 0, + N_("Print name of the input file before every symbol"), 0 }, + { NULL, 'o', NULL, OPTION_HIDDEN, "Same as -A", 0 }, + { "format", 'f', "FORMAT", 0, + N_("Use the output format FORMAT. FORMAT can be `bsd', `sysv' or `posix'. The default is `sysv'"), + 0 }, + { NULL, 'B', NULL, 0, N_("Same as --format=bsd"), 0 }, + { "portability", 'P', NULL, 0, N_("Same as --format=posix"), 0 }, + { "radix", 't', "RADIX", 0, N_("Use RADIX for printing symbol values"), 0 }, + { "mark-weak", OPT_MARK_WEAK, NULL, 0, N_("Mark weak symbols"), 0 }, + { "print-size", 'S', NULL, 0, N_("Print size of defined symbols"), 0 }, + + { NULL, 0, NULL, 0, N_("Output options:"), 0 }, + { "numeric-sort", 'n', NULL, 0, N_("Sort symbols numerically by address"), + 0 }, + { "no-sort", 'p', NULL, 0, N_("Do not sort the symbols"), 0 }, + { "reverse-sort", 'r', NULL, 0, N_("Reverse the sense of the sort"), 0 }, + { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Short description of program. */ +static const char doc[] = N_("List symbols from FILEs (a.out by default)."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("[FILE...]"); + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, NULL, NULL +}; + + +/* Print symbols in file named FNAME. */ +static int process_file (const char *fname, bool more_than_one); + +/* Handle content of archive. */ +static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, + const char *suffix); + +/* Handle ELF file. */ +static int handle_elf (Elf *elf, const char *prefix, const char *fname, + const char *suffix); + + +#define INTERNAL_ERROR(fname) \ + error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"), \ + fname, __LINE__, VERSION, __DATE__, elf_errmsg (-1)) + + +/* Internal representation of symbols. */ +typedef struct GElf_SymX +{ + GElf_Sym sym; + Elf32_Word xndx; + char *where; +} GElf_SymX; + + +/* User-selectable options. */ + +/* The selected output format. */ +static enum +{ + format_sysv = 0, + format_bsd, + format_posix +} format; + +/* Print defined, undefined, or both? */ +static bool hide_undefined; +static bool hide_defined; + +/* Print local symbols also? */ +static bool hide_local; + +/* Nonzero if full filename should precede every symbol. */ +static bool print_file_name; + +/* If true print size of defined symbols in BSD format. */ +static bool print_size; + +/* If true print archive index. */ +static bool print_armap; + +/* If true reverse sorting. */ +static bool reverse_sort; + +/* Type of the section we are printing. */ +static GElf_Word symsec_type = SHT_SYMTAB; + +/* Sorting selection. */ +static enum +{ + sort_name = 0, + sort_numeric, + sort_nosort +} sort; + +/* Radix for printed numbers. */ +static enum +{ + radix_hex = 0, + radix_decimal, + radix_octal +} radix; + +/* If nonzero weak symbols are distinguished from global symbols by adding + a `*' after the identifying letter for the symbol class and type. */ +static bool mark_weak; + + +int +main (int argc, char *argv[]) +{ + int remaining; + int result = 0; + + /* Make memory leak detection possible. */ + mtrace (); + + /* We use no threads here which can interfere with handling a stream. */ + (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); + (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); + (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER); + + /* Set locale. */ + (void) setlocale (LC_ALL, ""); + + /* Make sure the message catalog can be found. */ + (void) bindtextdomain (PACKAGE, LOCALEDIR); + + /* Initialize the message catalog. */ + (void) textdomain (PACKAGE); + + /* Parse and process arguments. */ + (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + /* Tell the library which version we are expecting. */ + (void) elf_version (EV_CURRENT); + + if (remaining == argc) + /* The user didn't specify a name so we use a.out. */ + result = process_file ("a.out", false); + else + { + /* Process all the remaining files. */ + const bool more_than_one = remaining + 1 < argc; + + do + result |= process_file (argv[remaining], more_than_one); + while (++remaining < argc); + } + + return result; +} + + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) +{ + fprintf (stream, "nm (%s) %s\n", PACKAGE_NAME, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Red Hat, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2005"); + fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case 'a': + /* XXX */ + break; + + case 'f': + if (strcmp (arg, "bsd") == 0) + format = format_bsd; + else if (strcmp (arg, "posix") == 0) + format = format_posix; + else + /* Be bug compatible. The BFD implementation also defaulted to + using the SysV format if nothing else matches. */ + format = format_sysv; + break; + + case 'g': + hide_local = true; + break; + + case 'n': + sort = sort_numeric; + break; + + case 'p': + sort = sort_nosort; + break; + + case 't': + if (strcmp (arg, "10") == 0 || strcmp (arg, "d") == 0) + radix = radix_decimal; + else if (strcmp (arg, "8") == 0 || strcmp (arg, "o") == 0) + radix = radix_octal; + else + radix = radix_hex; + break; + + case 'u': + hide_undefined = false; + hide_defined = true; + break; + + case 'A': + case 'o': + print_file_name = true; + break; + + case 'B': + format = format_bsd; + break; + + case 'D': + symsec_type = SHT_DYNSYM; + break; + + case 'P': + format = format_posix; + break; + + case OPT_DEFINED: + hide_undefined = true; + hide_defined = false; + break; + + case OPT_MARK_WEAK: + mark_weak = true; + break; + + case 'S': + print_size = true; + break; + + case 's': + print_armap = true; + break; + + case 'r': + reverse_sort = true; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +/* Open the file and determine the type. */ +static int +process_file (const char *fname, bool more_than_one) +{ + /* Open the file. */ + int fd = open (fname, O_RDONLY); + if (fd == -1) + { + error (0, errno, gettext ("cannot open '%s'"), fname); + return 1; + } + + /* Now get the ELF descriptor. */ + Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + if (elf != NULL) + { + if (elf_kind (elf) == ELF_K_ELF) + { + int result = handle_elf (elf, more_than_one ? "" : NULL, + fname, NULL); + + if (elf_end (elf) != 0) + INTERNAL_ERROR (fname); + + if (close (fd) != 0) + error (EXIT_FAILURE, errno, gettext ("while close '%s'"), fname); + + return result; + } + else if (elf_kind (elf) == ELF_K_AR) + { + int result = handle_ar (fd, elf, NULL, fname, NULL); + + if (elf_end (elf) != 0) + INTERNAL_ERROR (fname); + + if (close (fd) != 0) + error (EXIT_FAILURE, errno, gettext ("while close '%s'"), fname); + + return result; + } + + /* We cannot handle this type. Close the descriptor anyway. */ + if (elf_end (elf) != 0) + INTERNAL_ERROR (fname); + } + + error (0, 0, gettext ("%s: File format not recognized"), fname); + + return 1; +} + + +static int +handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, + const char *suffix) +{ + size_t fname_len = strlen (fname) + 1; + size_t prefix_len = prefix != NULL ? strlen (prefix) : 0; + char new_prefix[prefix_len + fname_len + 2]; + size_t suffix_len = suffix != NULL ? strlen (suffix) : 0; + char new_suffix[suffix_len + 2]; + Elf *subelf; + Elf_Cmd cmd = ELF_C_READ_MMAP; + int result = 0; + + char *cp = new_prefix; + if (prefix != NULL) + cp = stpcpy (cp, prefix); + cp = stpcpy (cp, fname); + stpcpy (cp, "["); + + cp = new_suffix; + if (suffix != NULL) + cp = stpcpy (cp, suffix); + stpcpy (cp, "]"); + + /* First print the archive index if this is wanted. */ + if (print_armap) + { + Elf_Arsym *arsym = elf_getarsym (elf, NULL); + + if (arsym != NULL) + { + Elf_Arhdr *arhdr = NULL; + size_t arhdr_off = 0; /* Note: 0 is no valid offset. */ + + puts (gettext("\nArchive index:")); + + while (arsym->as_off != 0) + { + if (arhdr_off != arsym->as_off + && (elf_rand (elf, arsym->as_off) != arsym->as_off + || (subelf = elf_begin (fd, cmd, elf)) == NULL + || (arhdr = elf_getarhdr (subelf)) == NULL)) + { + error (0, 0, gettext ("invalid offset %zu for symbol %s"), + arsym->as_off, arsym->as_name); + continue; + } + + printf (gettext ("%s in %s\n"), arsym->as_name, arhdr->ar_name); + + ++arsym; + } + + if (elf_rand (elf, SARMAG) != SARMAG) + { + error (0, 0, + gettext ("cannot reset archive offset to beginning")); + return 1; + } + } + } + + /* Process all the files contained in the archive. */ + while ((subelf = elf_begin (fd, cmd, elf)) != NULL) + { + /* The the header for this element. */ + Elf_Arhdr *arhdr = elf_getarhdr (subelf); + + /* Skip over the index entries. */ + if (strcmp (arhdr->ar_name, "/") != 0 + && strcmp (arhdr->ar_name, "//") != 0) + { + if (elf_kind (subelf) == ELF_K_ELF) + result |= handle_elf (subelf, new_prefix, arhdr->ar_name, + new_suffix); + else if (elf_kind (subelf) == ELF_K_AR) + result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, + new_suffix); + else + { + error (0, 0, gettext ("%s%s%s: file format not recognized"), + new_prefix, arhdr->ar_name, new_suffix); + result = 1; + } + } + + /* Get next archive element. */ + cmd = elf_next (subelf); + if (elf_end (subelf) != 0) + INTERNAL_ERROR (fname); + } + + return result; +} + + +/* Mapping of radix and binary class to length. */ +static const int length_map[2][3] = +{ + [ELFCLASS32 - 1] = + { + [radix_hex] = 8, + [radix_decimal] = 10, + [radix_octal] = 11 + }, + [ELFCLASS64 - 1] = + { + [radix_hex] = 16, + [radix_decimal] = 20, + [radix_octal] = 22 + } +}; + + +struct global_name +{ + Dwarf_Global global; + const char *name; +}; + + +static int +global_compare (const void *p1, const void *p2) +{ + const Dwarf_Global *g1 = (const Dwarf_Global *) p1; + const Dwarf_Global *g2 = (const Dwarf_Global *) p2; + + return strcmp (g1->name, g2->name); +} + + +static void *global_root; + + +static int +get_global (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global, + void *arg __attribute__ ((unused))) +{ + tsearch (memcpy (xmalloc (sizeof (Dwarf_Global)), global, + sizeof (Dwarf_Global)), + &global_root, global_compare); + + return DWARF_CB_OK; +} + + +struct local_name +{ + const char *name; + const char *file; + Dwarf_Word lineno; + Dwarf_Addr lowpc; + Dwarf_Addr highpc; +}; + + +static int +local_compare (const void *p1, const void *p2) +{ + struct local_name *g1 = (struct local_name *) p1; + struct local_name *g2 = (struct local_name *) p2; + int result; + + result = strcmp (g1->name, g2->name); + if (result == 0) + { + if (g1->lowpc <= g2->lowpc && g1->highpc >= g2->highpc) + { + /* g2 is contained in g1. Update the data. */ + g2->lowpc = g1->lowpc; + g2->highpc = g1->highpc; + result = 0; + } + else if (g2->lowpc <= g1->lowpc && g2->highpc >= g1->highpc) + { + /* g1 is contained in g2. Update the data. */ + g1->lowpc = g2->lowpc; + g1->highpc = g2->highpc; + result = 0; + } + else + result = g1->lowpc < g2->lowpc ? -1 : 1; + } + + return result; +} + + +static int +get_var_range (Dwarf_Die *die, Dwarf_Word *lowpc, Dwarf_Word *highpc) +{ + Dwarf_Attribute locattr_mem; + Dwarf_Attribute *locattr = dwarf_attr (die, DW_AT_location, &locattr_mem); + if (locattr == NULL) + return 1; + + Dwarf_Loc *loc; + size_t nloc; + if (dwarf_getloclist (locattr, &loc, &nloc) != 0) + return 1; + + /* Interpret the location expressions. */ + // XXX For now just the simple one: + if (nloc == 1 && loc[0].atom == DW_OP_addr) + { + *lowpc = *highpc = loc[0].number; + return 0; + } + + return 1; +} + + + +static void *local_root; + + +static void +get_local_names (Dwarf *dbg) +{ + Dwarf_Off offset = 0; + Dwarf_Off old_offset; + size_t hsize; + + while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL, + NULL) == 0) + { + Dwarf_Die cudie_mem; + Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem); + + /* If we cannot get the CU DIE there is no need to go on with + this CU. */ + if (cudie == NULL) + continue; + /* This better be a CU DIE. */ + if (dwarf_tag (cudie) != DW_TAG_compile_unit) + continue; + + /* Get the line information. */ + Dwarf_Files *files; + size_t nfiles; + if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0) + continue; + + Dwarf_Die die_mem; + Dwarf_Die *die = &die_mem; + if (dwarf_child (cudie, die) == 0) + /* Iterate over all immediate children of the CU DIE. */ + do + { + int tag = dwarf_tag (die); + if (tag != DW_TAG_subprogram && tag != DW_TAG_variable) + continue; + + /* We are interested in five attributes: name, decl_file, + decl_line, low_pc, and high_pc. */ + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = dwarf_attr (die, DW_AT_name, &attr_mem); + const char *name = dwarf_formstring (attr); + if (name == NULL) + continue; + + Dwarf_Word fileidx; + attr = dwarf_attr (die, DW_AT_decl_file, &attr_mem); + if (dwarf_formudata (attr, &fileidx) != 0 || fileidx >= nfiles) + continue; + + Dwarf_Word lineno; + attr = dwarf_attr (die, DW_AT_decl_line, &attr_mem); + if (dwarf_formudata (attr, &lineno) != 0 || lineno == 0) + continue; + + Dwarf_Addr lowpc; + Dwarf_Addr highpc; + if (tag == DW_TAG_subprogram) + { + if (dwarf_lowpc (die, &lowpc) != 0 + || dwarf_highpc (die, &highpc) != 0) + continue; + } + else + { + if (get_var_range (die, &lowpc, &highpc) != 0) + continue; + } + + /* We have all the information. Create a record. */ + struct local_name *newp + = (struct local_name *) xmalloc (sizeof (*newp)); + newp->name = name; + newp->file = dwarf_filesrc (files, fileidx, NULL, NULL); + newp->lineno = lineno; + newp->lowpc = lowpc; + newp->highpc = highpc; + + /* Since we cannot deallocate individual memory we do not test + for duplicates in the tree. This should not happen anyway. */ + if (tsearch (newp, &local_root, local_compare) == NULL) + error (EXIT_FAILURE, errno, + gettext ("cannot create search tree")); + } + while (dwarf_siblingof (die, die) == 0); + } +} + + +/* Show symbols in SysV format. */ +static void +show_symbols_sysv (Ebl *ebl, GElf_Word strndx, + const char *prefix, const char *fname, const char *fullname, + GElf_SymX *syms, size_t nsyms, int longest_name, + int longest_where) +{ + size_t shnum; + if (elf_getshnum (ebl->elf, &shnum) < 0) + INTERNAL_ERROR (fullname); + + bool scnnames_malloced = shnum * sizeof (const char *) > 128 * 1024; + const char **scnnames; + if (scnnames_malloced) + scnnames = (const char **) xmalloc (sizeof (const char *) * shnum); + else + scnnames = (const char **) alloca (sizeof (const char *) * shnum); + /* Get the section header string table index. */ + size_t shstrndx; + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + /* Cache the section names. */ + Elf_Scn *scn = NULL; + size_t cnt = 1; + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + + assert (elf_ndxscn (scn) == cnt++); + + scnnames[elf_ndxscn (scn)] + = elf_strptr (ebl->elf, shstrndx, + gelf_getshdr (scn, &shdr_mem)->sh_name); + } + + int digits = length_map[gelf_getclass (ebl->elf) - 1][radix]; + + /* We always print this prolog. */ + if (prefix == NULL || 1) + printf (gettext ("\n\nSymbols from %s:\n\n"), fullname); + else + printf (gettext ("\n\nSymbols from %s[%s]:\n\n"), prefix, fname); + + /* The header line. */ + printf (gettext ("%*s%-*s %-*s Class Type %-*s %*s Section\n\n"), + print_file_name ? (int) strlen (fullname) + 1: 0, "", + longest_name, sgettext ("sysv|Name"), + /* TRANS: the "sysv|" parts makes the string unique. */ + digits, sgettext ("sysv|Value"), + /* TRANS: the "sysv|" parts makes the string unique. */ + digits, sgettext ("sysv|Size"), + /* TRANS: the "sysv|" parts makes the string unique. */ + longest_where, sgettext ("sysv|Line")); + + /* Which format string to use (different radix for numbers). */ + const char *fmtstr; + if (radix == radix_hex) + fmtstr = "%-*s|%0*" PRIx64 "|%-6s|%-8s|%*" PRIx64 "|%*s|%s\n"; + else if (radix == radix_decimal) + fmtstr = "%-*s|%*" PRId64 "|%-6s|%-8s|%*" PRId64 "|%*s|%s\n"; + else + fmtstr = "%-*s|%0*" PRIo64 "|%-6s|%-8s|%*" PRIo64 "|%*s|%s\n"; + + /* Iterate over all symbols. */ + for (cnt = 0; cnt < nsyms; ++cnt) + { + const char *symstr = elf_strptr (ebl->elf, strndx, + syms[cnt].sym.st_name); + char symbindbuf[50]; + char symtypebuf[50]; + char secnamebuf[1024]; + + /* If we have to precede the line with the file name. */ + if (print_file_name) + { + fputs_unlocked (fullname, stdout); + putchar_unlocked (':'); + } + + /* Print the actual string. */ + printf (fmtstr, + longest_name, symstr, + digits, syms[cnt].sym.st_value, + ebl_symbol_binding_name (ebl, + GELF_ST_BIND (syms[cnt].sym.st_info), + symbindbuf, sizeof (symbindbuf)), + ebl_symbol_type_name (ebl, GELF_ST_TYPE (syms[cnt].sym.st_info), + symtypebuf, sizeof (symtypebuf)), + digits, syms[cnt].sym.st_size, longest_where, syms[cnt].where, + ebl_section_name (ebl, syms[cnt].sym.st_shndx, syms[cnt].xndx, + secnamebuf, sizeof (secnamebuf), scnnames, + shnum)); + } + + if (scnnames_malloced) + free (scnnames); +} + + +static char +class_type_char (GElf_Sym *sym) +{ + int local_p = GELF_ST_BIND (sym->st_info) == STB_LOCAL; + + /* XXX Add support for architecture specific types and classes. */ + if (sym->st_shndx == SHN_ABS) + return local_p ? 'a' : 'A'; + + if (sym->st_shndx == SHN_UNDEF) + /* Undefined symbols must be global. */ + return 'U'; + + char result = "NDTSFB "[GELF_ST_TYPE (sym->st_info)]; + + return local_p ? tolower (result) : result; +} + + +static void +show_symbols_bsd (Elf *elf, GElf_Word strndx, + const char *prefix, const char *fname, const char *fullname, + GElf_SymX *syms, size_t nsyms) +{ + int digits = length_map[gelf_getclass (elf) - 1][radix]; + + if (prefix != NULL && ! print_file_name) + printf ("\n%s:\n", fname); + + static const char *const fmtstrs[] = + { + [radix_hex] = "%0*" PRIx64 " %c%s %s\n", + [radix_decimal] = "%*" PRId64 " %c%s %s\n", + [radix_octal] = "%0*" PRIo64 " %c%s %s\n" + }; + static const char *const sfmtstrs[] = + { + [radix_hex] = "%2$0*1$" PRIx64 " %7$0*6$" PRIx64 " %3$c%4$s %5$s\n", + [radix_decimal] = "%2$*1$" PRId64 " %7$*6$" PRId64 " %3$c%4$s %5$s\n", + [radix_octal] = "%2$0*1$" PRIo64 " %7$0*6$" PRIo64 " %3$c%4$s %5$s\n" + }; + + /* Iterate over all symbols. */ + for (size_t cnt = 0; cnt < nsyms; ++cnt) + { + const char *symstr = elf_strptr (elf, strndx, syms[cnt].sym.st_name); + + /* Printing entries with a zero-length name makes the output + not very well parseable. Since these entries don't carry + much information we leave them out. */ + if (symstr[0] == '\0') + continue; + + /* If we have to precede the line with the file name. */ + if (print_file_name) + { + fputs_unlocked (fullname, stdout); + putchar_unlocked (':'); + } + + if (syms[cnt].sym.st_shndx == SHN_UNDEF) + printf ("%*s U%s %s\n", + digits, "", + mark_weak + ? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK + ? "*" : " ") + : "", + elf_strptr (elf, strndx, syms[cnt].sym.st_name)); + else + printf (print_size ? sfmtstrs[radix] : fmtstrs[radix], + digits, syms[cnt].sym.st_value, + class_type_char (&syms[cnt].sym), + mark_weak + ? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK + ? "*" : " ") + : "", + elf_strptr (elf, strndx, syms[cnt].sym.st_name), + digits, (uint64_t) syms[cnt].sym.st_size); + } +} + + +static void +show_symbols_posix (Elf *elf, GElf_Word strndx, const char *prefix, + const char *fullname, GElf_SymX *syms, size_t nsyms) +{ + if (prefix != NULL && ! print_file_name) + printf ("%s:\n", fullname); + + const char *fmtstr; + if (radix == radix_hex) + fmtstr = "%s %c%s %0*" PRIx64 " %0*" PRIx64 "\n"; + else if (radix == radix_decimal) + fmtstr = "%s %c%s %*" PRId64 " %*" PRId64 "\n"; + else + fmtstr = "%s %c%s %0*" PRIo64 " %0*" PRIo64 "\n"; + + int digits = length_map[gelf_getclass (elf) - 1][radix]; + + /* Iterate over all symbols. */ + for (size_t cnt = 0; cnt < nsyms; ++cnt) + { + const char *symstr = elf_strptr (elf, strndx, syms[cnt].sym.st_name); + + /* Printing entries with a zero-length name makes the output + not very well parseable. Since these entries don't carry + much information we leave them out. */ + if (symstr[0] == '\0') + continue; + + /* If we have to precede the line with the file name. */ + if (print_file_name) + { + fputs_unlocked (fullname, stdout); + putchar_unlocked (':'); + putchar_unlocked (' '); + } + + printf (fmtstr, + symstr, + class_type_char (&syms[cnt].sym), + mark_weak + ? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK ? "*" : " ") + : "", + digits, syms[cnt].sym.st_value, + digits, syms[cnt].sym.st_size); + } +} + + +/* Maximum size of memory we allocate on the stack. */ +#define MAX_STACK_ALLOC 65536 + +static void +show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, + GElf_Shdr *shdr, const char *prefix, const char *fname, + const char *fullname) +{ + int sort_by_name (const void *p1, const void *p2) + { + GElf_SymX *s1 = (GElf_SymX *) p1; + GElf_SymX *s2 = (GElf_SymX *) p2; + int result; + + result = strcmp (elf_strptr (ebl->elf, shdr->sh_link, s1->sym.st_name), + elf_strptr (ebl->elf, shdr->sh_link, s2->sym.st_name)); + + return reverse_sort ? -result : result; + } + + int sort_by_address (const void *p1, const void *p2) + { + GElf_SymX *s1 = (GElf_SymX *) p1; + GElf_SymX *s2 = (GElf_SymX *) p2; + + int result = (s1->sym.st_value < s2->sym.st_value + ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1)); + + return reverse_sort ? -result : result; + } + + /* Get the section header string table index. */ + size_t shstrndx; + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + /* The section is that large. */ + size_t size = shdr->sh_size; + /* One entry is this large. */ + size_t entsize = shdr->sh_entsize; + + /* Consistency checks. */ + if (entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, ehdr->e_version)) + error (0, 0, + gettext ("%s: entry size in section `%s' is not what we expect"), + fullname, elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); + else if (size % entsize != 0) + error (0, 0, + gettext ("%s: size of section `%s' is not multiple of entry size"), + fullname, elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); + + /* Compute number of entries. Handle buggy entsize values. */ + size_t nentries = size / (entsize ?: 1); + + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + struct obstack whereob; + obstack_init (&whereob); + + /* Get a DWARF debugging descriptor. It's no problem if this isn't + possible. We just won't print any line number information. */ + Dwarf *dbg = NULL; + if (format == format_sysv) + { + dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL); + if (dbg != NULL) + { + (void) dwarf_getpubnames (dbg, get_global, NULL, 0); + + get_local_names (dbg); + } + } + + /* Allocate the memory. + + XXX We can use a dirty trick here. Since GElf_Sym == Elf64_Sym we + can use the data memory instead of copying again if what we read + is a 64 bit file. */ + GElf_SymX *sym_mem; + if (nentries * sizeof (GElf_SymX) < MAX_STACK_ALLOC) + sym_mem = (GElf_SymX *) alloca (nentries * sizeof (GElf_SymX)); + else + sym_mem = (GElf_SymX *) xmalloc (nentries * sizeof (GElf_SymX)); + + /* Get the data of the section. */ + Elf_Data *data = elf_getdata (scn, NULL); + Elf_Data *xndxdata = elf_getdata (xndxscn, NULL); + if (data == NULL || (xndxscn != NULL && xndxdata == NULL)) + INTERNAL_ERROR (fullname); + + /* Iterate over all symbols. */ + int longest_name = 4; + int longest_where = 4; + size_t nentries_used = 0; + for (size_t cnt = 0; cnt < nentries; ++cnt) + { + GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt, + &sym_mem[nentries_used].sym, + &sym_mem[nentries_used].xndx); + if (sym == NULL) + INTERNAL_ERROR (fullname); + + /* Filter out administrative symbols without a name and those + deselected by ther user with command line options. */ + if ((hide_undefined && sym->st_shndx == SHN_UNDEF) + || (hide_defined && sym->st_shndx != SHN_UNDEF) + || (hide_local && GELF_ST_BIND (sym->st_info) == STB_LOCAL)) + continue; + + sym_mem[nentries_used].where = ""; + if (format == format_sysv) + { + const char *symstr = elf_strptr (ebl->elf, shdr->sh_link, + sym->st_name); + + longest_name = MAX ((size_t) longest_name, strlen (symstr)); + + if (sym->st_shndx != SHN_UNDEF + && GELF_ST_BIND (sym->st_info) != STB_LOCAL + && global_root != NULL) + { + Dwarf_Global fake = { .name = symstr }; + Dwarf_Global **found = tfind (&fake, &global_root, + global_compare); + if (found != NULL) + { + Dwarf_Die die_mem; + Dwarf_Die *die = dwarf_offdie (dbg, (*found)->die_offset, + &die_mem); + + Dwarf_Die cudie_mem; + Dwarf_Die *cudie = NULL; + + Dwarf_Addr lowpc; + Dwarf_Addr highpc; + if (die != NULL + && dwarf_lowpc (die, &lowpc) == 0 + && lowpc <= sym->st_value + && dwarf_highpc (die, &highpc) == 0 + && highpc > sym->st_value) + cudie = dwarf_offdie (dbg, (*found)->cu_offset, + &cudie_mem); + if (cudie != NULL) + { + Dwarf_Line *line = dwarf_getsrc_die (cudie, + sym->st_value); + if (line != NULL) + { + /* We found the line. */ + int lineno; + (void) dwarf_lineno (line, &lineno); + int n; + n = obstack_printf (&whereob, "%s:%d%c", + basename (dwarf_linesrc (line, + NULL, + NULL)), + lineno, '\0'); + sym_mem[nentries_used].where + = obstack_finish (&whereob); + + /* The return value of obstack_print included the + NUL byte, so subtract one. */ + if (--n > (int) longest_where) + longest_where = (size_t) n; + } + } + } + } + + /* Try to find the symol among the local symbols. */ + if (sym_mem[nentries_used].where[0] == '\0') + { + struct local_name fake = + { + .name = symstr, + .lowpc = sym->st_value, + .highpc = sym->st_value, + }; + struct local_name **found = tfind (&fake, &local_root, + local_compare); + if (found != NULL) + { + /* We found the line. */ + int n = obstack_printf (&whereob, "%s:%" PRIu64 "%c", + basename ((*found)->file), + (*found)->lineno, + '\0'); + sym_mem[nentries_used].where = obstack_finish (&whereob); + + /* The return value of obstack_print included the + NUL byte, so subtract one. */ + if (--n > (int) longest_where) + longest_where = (size_t) n; + } + } + } + + /* We use this entry. */ + ++nentries_used; + } + /* Now we know the exact number. */ + nentries = nentries_used; + + /* Sort the entries according to the users wishes. */ + if (sort == sort_name) + qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name); + else if (sort == sort_numeric) + qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_address); + + /* Finally print according to the users selection. */ + switch (format) + { + case format_sysv: + show_symbols_sysv (ebl, shdr->sh_link, prefix, fname, + fullname, sym_mem, nentries, longest_name, + longest_where); + break; + + case format_bsd: + show_symbols_bsd (ebl->elf, shdr->sh_link, prefix, fname, fullname, + sym_mem, nentries); + break; + + case format_posix: + default: + assert (format == format_posix); + show_symbols_posix (ebl->elf, shdr->sh_link, prefix, fullname, sym_mem, + nentries); + break; + } + + /* Free all memory. */ + if (nentries * sizeof (GElf_Sym) >= MAX_STACK_ALLOC) + free (sym_mem); + + obstack_free (&whereob, NULL); + + if (dbg != NULL) + { + tdestroy (global_root, free); + global_root = NULL; + + tdestroy (local_root, free); + local_root = NULL; + + (void) dwarf_end (dbg); + } +} + + +static int +handle_elf (Elf *elf, const char *prefix, const char *fname, + const char *suffix) +{ + size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); + size_t suffix_len = suffix == NULL ? 0 : strlen (suffix); + size_t fname_len = strlen (fname) + 1; + char fullname[prefix_len + 1 + fname_len + suffix_len]; + char *cp = fullname; + Elf_Scn *scn = NULL; + int any = 0; + int result = 0; + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + Ebl *ebl; + + /* Get the backend for this object file type. */ + ebl = ebl_openbackend (elf); + + /* We need the ELF header in a few places. */ + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + INTERNAL_ERROR (fullname); + + /* If we are asked to print the dynamic symbol table and this is + executable or dynamic executable, fail. */ + if (symsec_type == SHT_DYNSYM + && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) + { + /* XXX Add machine specific object file types. */ + error (0, 0, gettext ("%s%s%s%s: Invalid operation"), + prefix ?: "", prefix ? "(" : "", fname, prefix ? ")" : ""); + result = 1; + goto out; + } + + /* Create the full name of the file. */ + if (prefix != NULL) + cp = mempcpy (cp, prefix, prefix_len); + cp = mempcpy (cp, fname, fname_len); + if (suffix != NULL) + memcpy (cp - 1, suffix, suffix_len + 1); + + /* Find the symbol table. + + XXX Can there be more than one? Do we print all? Currently we do. */ + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr == NULL) + INTERNAL_ERROR (fullname); + + if (shdr->sh_type == symsec_type) + { + Elf_Scn *xndxscn = NULL; + + /* We have a symbol table. First make sure we remember this. */ + any = 1; + + /* Look for an extended section index table for this section. */ + if (symsec_type == SHT_SYMTAB) + { + size_t scnndx = elf_ndxscn (scn); + + while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL) + { + GElf_Shdr xndxshdr_mem; + GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem); + + if (xndxshdr == NULL) + INTERNAL_ERROR (fullname); + + if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX + && xndxshdr->sh_link == scnndx) + break; + } + } + + show_symbols (ebl, ehdr, scn, xndxscn, shdr, prefix, fname, + fullname); + } + } + + if (! any) + { + error (0, 0, gettext ("%s%s%s: no symbols"), + prefix ?: "", prefix ? ":" : "", fname); + result = 1; + } + + out: + /* Close the ELF backend library descriptor. */ + ebl_closebackend (ebl); + + return result; +} diff --git a/src/none_ld.c b/src/none_ld.c new file mode 100644 index 00000000..fb0f0fb2 --- /dev/null +++ b/src/none_ld.c @@ -0,0 +1 @@ +/* Nothing here. This is just a testimony of automake inflexibility. */ diff --git a/src/readelf.c b/src/readelf.c new file mode 100644 index 00000000..95532fa3 --- /dev/null +++ b/src/readelf.c @@ -0,0 +1,4997 @@ +/* Print information from ELF file in human-readable form. + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../libebl/libeblP.h" +#include "../libdw/libdwP.h" +#include "../libdw/memory-access.h" + + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Bug report address. */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { NULL, 0, NULL, 0, N_("Output selection:"), 0 }, + { "all", 'a', NULL, 0, N_("Equivalent to: -h -l"), 0 }, + { "dynamic", 'd', NULL, 0, N_("Display the dynamic segment"), 0 }, + { "file-header", 'h', NULL, 0, N_("Display the ELF file header"), 0 }, + { "histogram", 'I', NULL, 0, + N_("Display histogram of bucket list lengths"), 0 }, + { "program-headers", 'l', NULL, 0, N_("Display the program headers"), 0 }, + { "relocs", 'r', NULL, 0, N_("Display relocations"), 0 }, + { "section-headers", 'S', NULL, 0, N_("Display the sections' header"), 0 }, + { "symbols", 's', NULL, 0, N_("Display the symbol table"), 0 }, + { "version-info", 'V', NULL, 0, N_("Display versioning information"), 0 }, + { "debug-dump", 'w', "SECTION", OPTION_ARG_OPTIONAL, + N_("Display DWARF section content. SECTION can be one of abbrev, " + "aranges, frame, info, loc, line, ranges, pubnames, str, or macinfo."), + 0 }, + { "notes", 'n', NULL, 0, N_("Display the core notes"), 0 }, + { "arch-specific", 'A', NULL, 0, + N_("Display architecture specific information (if any)"), 0 }, + + { NULL, 0, NULL, 0, N_("Output control:"), 0 }, + + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Short description of program. */ +static const char doc[] = N_("\ +Print information from ELF file in human-readable form."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("FILE..."); + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, NULL, NULL +}; + + +/* Flags set by the option controlling the output. */ + +/* True if dynamic segment should be printed. */ +static bool print_dynamic_table; + +/* True if the file header should be printed. */ +static bool print_file_header; + +/* True if the program headers should be printed. */ +static bool print_program_header; + +/* True if relocations should be printed. */ +static bool print_relocations; + +/* True if the section headers should be printed. */ +static bool print_section_header; + +/* True if the symbol table should be printed. */ +static bool print_symbol_table; + +/* True if the version information should be printed. */ +static bool print_version_info; + +/* True if section groups should be printed. */ +static bool print_section_groups; + +/* True if bucket list length histogram should be printed. */ +static bool print_histogram; + +/* True if the architecture specific data should be printed. */ +static bool print_arch; + +/* True if note section content should be printed. */ +static bool print_notes; + +/* Select printing of debugging sections. */ +static enum section_e +{ + section_abbrev = 1, /* .debug_abbrev */ + section_aranges = 2, /* .debug_aranges */ + section_frame = 4, /* .debug_frame or .eh_frame */ + section_info = 8, /* .debug_info */ + section_line = 16, /* .debug_line */ + section_loc = 32, /* .debug_loc */ + section_pubnames = 64,/* .debug_pubnames */ + section_str = 128, /* .debug_str */ + section_macinfo = 256,/* .debug_macinfo */ + section_ranges = 512, /* .debug_ranges */ + section_all = (section_abbrev | section_aranges | section_frame + | section_info | section_line | section_loc + | section_pubnames | section_str | section_macinfo + | section_ranges) +} print_debug_sections; + +/* Number of sections in the file. */ +static size_t shnum; + + +/* Declarations of local functions. */ +static void process_file (int fd, Elf *elf, const char *prefix, + const char *fname, bool only_one); +static void process_elf_file (Elf *elf, const char *prefix, const char *fname, + bool only_one); +static void print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr); +static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr); +static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr); +static void print_scngrp (Ebl *ebl); +static void print_dynamic (Ebl *ebl); +static void print_relocs (Ebl *ebl); +static void handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); +static void handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); +static void print_symtab (Ebl *ebl, int type); +static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); +static void print_verinfo (Ebl *ebl); +static void handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); +static void handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); +static void handle_versym (Ebl *ebl, Elf_Scn *scn, + GElf_Shdr *shdr); +static void print_debug (Ebl *ebl, GElf_Ehdr *ehdr); +static void handle_hash (Ebl *ebl); +static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr); +static void print_liblist (Ebl *ebl); + + +int +main (int argc, char *argv[]) +{ + /* Set locale. */ + setlocale (LC_ALL, ""); + + /* Initialize the message catalog. */ + textdomain (PACKAGE); + + /* Parse and process arguments. */ + int remaining; + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + /* Before we start tell the ELF library which version we are using. */ + elf_version (EV_CURRENT); + + /* Now process all the files given at the command line. */ + bool only_one = remaining + 1 == argc; + do + { + /* Open the file. */ + int fd = open (argv[remaining], O_RDONLY); + if (fd == -1) + { + error (0, errno, gettext ("cannot open input file")); + continue; + } + + /* Create an `Elf' descriptor. */ + Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) + error (0, 0, gettext ("cannot generate Elf descriptor: %s\n"), + elf_errmsg (-1)); + else + { + process_file (fd, elf, NULL, argv[remaining], only_one); + + /* Now we can close the descriptor. */ + if (elf_end (elf) != 0) + error (0, 0, gettext ("error while closing Elf descriptor: %s"), + elf_errmsg (-1)); + } + + close (fd); + } + while (++remaining < argc); + + return error_message_count != 0; +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + /* True if any of the control options is set. */ + static bool any_control_option; + + switch (key) + { + case 'a': + print_file_header = true; + print_program_header = true; + print_relocations = true; + print_section_header = true; + print_symbol_table = true; + print_version_info = true; + print_dynamic_table = true; + print_section_groups = true; + print_histogram = true; + print_arch = true; + print_notes = true; + any_control_option = true; + break; + case 'A': + print_arch = true; + any_control_option = true; + break; + case 'd': + print_dynamic_table = true; + any_control_option = true; + break; + case 'g': + print_section_groups = true; + any_control_option = true; + break; + case 'h': + print_file_header = true; + any_control_option = true; + break; + case 'I': + print_histogram = true; + any_control_option = true; + break; + case 'l': + print_program_header = true; + any_control_option = true; + break; + case 'n': + print_notes = true; + any_control_option = true; + break; + case 'r': + print_relocations = true; + any_control_option = true; + break; + case 'S': + print_section_header = true; + any_control_option = true; + break; + case 's': + print_symbol_table = true; + any_control_option = true; + break; + case 'V': + print_version_info = true; + any_control_option = true; + break; + case 'w': + if (arg == NULL) + print_debug_sections = section_all; + else if (strcmp (arg, "abbrev") == 0) + print_debug_sections |= section_abbrev; + else if (strcmp (arg, "aranges") == 0) + print_debug_sections |= section_aranges; + else if (strcmp (arg, "ranges") == 0) + print_debug_sections |= section_ranges; + else if (strcmp (arg, "frame") == 0) + print_debug_sections |= section_frame; + else if (strcmp (arg, "info") == 0) + print_debug_sections |= section_info; + else if (strcmp (arg, "loc") == 0) + print_debug_sections |= section_loc; + else if (strcmp (arg, "line") == 0) + print_debug_sections |= section_line; + else if (strcmp (arg, "pubnames") == 0) + print_debug_sections |= section_pubnames; + else if (strcmp (arg, "str") == 0) + print_debug_sections |= section_str; + else if (strcmp (arg, "macinfo") == 0) + print_debug_sections |= section_macinfo; + else + { + fprintf (stderr, gettext ("Unknown DWARF debug section `%s'.\n"), + arg); + argp_help (&argp, stderr, ARGP_HELP_SEE, + program_invocation_short_name); + exit (1); + } + any_control_option = true; + break; + case ARGP_KEY_NO_ARGS: + fputs (gettext ("Missing file name.\n"), stderr); + goto do_argp_help; + case ARGP_KEY_FINI: + if (! any_control_option) + { + fputs (gettext ("No operation specified.\n"), stderr); + do_argp_help: + argp_help (&argp, stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR, + program_invocation_short_name); + exit (1); + } + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) +{ + fprintf (stream, "readelf (%s) %s\n", PACKAGE_NAME, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Red Hat, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2005"); + fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); +} + + +/* Process one file. */ +static void +process_file (int fd, Elf *elf, const char *prefix, const char *fname, + bool only_one) +{ + /* We can handle two types of files: ELF files and archives. */ + Elf_Kind kind = elf_kind (elf); + struct stat64 st; + + switch (kind) + { + case ELF_K_ELF: + /* Yes! It's an ELF file. */ + process_elf_file (elf, prefix, fname, only_one); + break; + + case ELF_K_AR: + { + Elf *subelf; + Elf_Cmd cmd = ELF_C_READ_MMAP; + size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); + size_t fname_len = strlen (fname) + 1; + char new_prefix[prefix_len + 1 + fname_len]; + char *cp = new_prefix; + + /* Create the full name of the file. */ + if (prefix != NULL) + { + cp = mempcpy (cp, prefix, prefix_len); + *cp++ = ':'; + } + memcpy (cp, fname, fname_len); + + /* It's an archive. We process each file in it. */ + while ((subelf = elf_begin (fd, cmd, elf)) != NULL) + { + kind = elf_kind (subelf); + + /* Call this function recursively. */ + if (kind == ELF_K_ELF || kind == ELF_K_AR) + { + Elf_Arhdr *arhdr = elf_getarhdr (subelf); + assert (arhdr != NULL); + + process_file (fd, subelf, new_prefix, arhdr->ar_name, false); + } + + /* Get next archive element. */ + cmd = elf_next (subelf); + if (elf_end (subelf) != 0) + error (0, 0, + gettext (" error while freeing sub-ELF descriptor: %s\n"), + elf_errmsg (-1)); + } + } + break; + + default: + if (fstat64 (fd, &st) != 0) + error (0, errno, gettext ("cannot stat input file")); + else if (st.st_size == 0) + error (0, 0, gettext ("input file is empty")); + else + /* We cannot do anything. */ + error (0, 0, gettext ("\ +Not an ELF file - it has the wrong magic bytes at the start")); + break; + } +} + + +/* Process one file. */ +static void +process_elf_file (Elf *elf, const char *prefix, const char *fname, + bool only_one) +{ + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + Ebl *ebl; + + /* Print the file name. */ + if (!only_one) + { + if (prefix != NULL) + printf ("\n%s(%s):\n\n", prefix, fname); + else + printf ("\n%s:\n\n", fname); + } + + if (ehdr == NULL) + { + error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1)); + return; + } + + ebl = ebl_openbackend (elf); + if (ebl == NULL) + { + error (0, errno, gettext ("cannot create EBL handle")); + return; + } + + /* Determine the number of sections. */ + if (elf_getshnum (ebl->elf, &shnum) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot determine number of sections: %s"), + elf_errmsg (-1)); + + if (print_file_header) + print_ehdr (ebl, ehdr); + if (print_section_header) + print_shdr (ebl, ehdr); + if (print_program_header) + print_phdr (ebl, ehdr); + if (print_section_groups) + print_scngrp (ebl); + if (print_dynamic_table) + print_dynamic (ebl); + if (print_relocations) + print_relocs (ebl); + if (print_histogram) + handle_hash (ebl); + if (print_symbol_table) + print_symtab (ebl, SHT_DYNSYM); + if (print_version_info) + print_verinfo (ebl); + if (print_symbol_table) + print_symtab (ebl, SHT_SYMTAB); + if (print_arch) + print_liblist (ebl); + if (print_debug_sections != 0) + print_debug (ebl, ehdr); + if (print_notes) + handle_notes (ebl, ehdr); + + ebl_closebackend (ebl); +} + + +/* Print file type. */ +static void +print_file_type (unsigned short int e_type) +{ + if (e_type <= ET_CORE) + { + static const char *knowntypes[] = + { + N_("NONE (None)"), + N_("REL (Relocatable file)"), + N_("EXEC (Executable file)"), + N_("DYN (Shared object file)"), + N_("CORE (Core file)") + }; + puts (gettext (knowntypes[e_type])); + } + else if (e_type >= ET_LOOS && e_type <= ET_HIOS) + printf (gettext ("OS Specific: (%x)\n"), e_type); + else if (e_type >= ET_LOPROC /* && e_type <= ET_HIPROC always true */) + printf (gettext ("Processor Specific: (%x)\n"), e_type); + else + puts ("???"); +} + + +/* Print ELF header. */ +static void +print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr) +{ + char buf[512]; + size_t cnt; + + fputs_unlocked (gettext ("ELF Header:\n Magic: "), stdout); + for (cnt = 0; cnt < EI_NIDENT; ++cnt) + printf (" %02hhx", ehdr->e_ident[cnt]); + + printf (gettext ("\n Class: %s\n"), + ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? "ELF32" + : ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? "ELF64" + : "\?\?\?"); + + printf (gettext (" Data: %s\n"), + ehdr->e_ident[EI_DATA] == ELFDATA2LSB + ? "2's complement, little endian" + : ehdr->e_ident[EI_DATA] == ELFDATA2MSB + ? "2's complement, big endian" : "\?\?\?"); + + printf (gettext (" Version: %hhd %s\n"), + ehdr->e_ident[EI_VERSION], + ehdr->e_ident[EI_VERSION] == EV_CURRENT ? gettext ("(current)") + : "(\?\?\?)"); + + printf (gettext (" OS/ABI: %s\n"), + ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf))); + + printf (gettext (" ABI Version: %hhd\n"), + ehdr->e_ident[EI_ABIVERSION]); + + fputs_unlocked (gettext (" Type: "), stdout); + print_file_type (ehdr->e_type); + + printf (gettext (" Machine: %s\n"), ebl->name); + + printf (gettext (" Version: %d %s\n"), + ehdr->e_version, + ehdr->e_version == EV_CURRENT ? gettext ("(current)") : "(\?\?\?)"); + + printf (gettext (" Entry point address: %#" PRIx64 "\n"), + ehdr->e_entry); + + printf (gettext (" Start of program headers: %" PRId64 " %s\n"), + ehdr->e_phoff, gettext ("(bytes into file)")); + + printf (gettext (" Start of section headers: %" PRId64 " %s\n"), + ehdr->e_shoff, gettext ("(bytes into file)")); + + printf (gettext (" Flags: %s\n"), + ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf))); + + printf (gettext (" Size of this header: %" PRId16 " %s\n"), + ehdr->e_ehsize, gettext ("(bytes)")); + + printf (gettext (" Size of program header entries: %" PRId16 " %s\n"), + ehdr->e_phentsize, gettext ("(bytes)")); + + printf (gettext (" Number of program headers entries: %" PRId16 "\n"), + ehdr->e_phnum); + + printf (gettext (" Size of section header entries: %" PRId16 " %s\n"), + ehdr->e_shentsize, gettext ("(bytes)")); + + printf (gettext (" Number of section headers entries: %" PRId16), + ehdr->e_shnum); + if (ehdr->e_shnum == 0) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); + if (shdr != NULL) + printf (gettext (" (%" PRIu32 " in [0].sh_size)"), + (uint32_t) shdr->sh_size); + else + fputs_unlocked (gettext (" ([0] not available)"), stdout); + } + fputc_unlocked ('\n', stdout); + + if (ehdr->e_shstrndx == SHN_XINDEX) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); + if (shdr != NULL) + /* We managed to get the zeroth section. */ + snprintf (buf, sizeof (buf), gettext (" (%" PRIu32 " in [0].sh_link)"), + (uint32_t) shdr->sh_link); + else + { + strncpy (buf, gettext (" ([0] not available)"), sizeof (buf)); + buf[sizeof (buf) - 1] = '\0'; + } + + printf (gettext (" Section header string table index: XINDEX%s\n\n"), + buf); + } + else + printf (gettext (" Section header string table index: %" PRId16 "\n\n"), + ehdr->e_shstrndx); +} + + +static const char * +get_visibility_type (int value) +{ + switch (value) + { + case STV_DEFAULT: + return "DEFAULT"; + case STV_INTERNAL: + return "INTERNAL"; + case STV_HIDDEN: + return "HIDDEN"; + case STV_PROTECTED: + return "PROTECTED"; + default: + return "???"; + } +} + + +/* Print the section headers. */ +static void +print_shdr (Ebl *ebl, GElf_Ehdr *ehdr) +{ + size_t cnt; + size_t shstrndx; + + if (! print_file_header) + printf (gettext ("\ +There are %d section headers, starting at offset %#" PRIx64 ":\n\ +\n"), + ehdr->e_shnum, ehdr->e_shoff); + + /* Get the section header string table index. */ + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + puts (gettext ("Section Headers:")); + + if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) + puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al")); + else + puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al")); + + for (cnt = 0; cnt < shnum; ++cnt) + { + char buf[128]; + char flagbuf[20]; + char *cp; + Elf_Scn *scn = elf_getscn (ebl->elf, cnt); + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + if (scn == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"), + elf_errmsg (-1)); + + /* Get the section header. */ + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"), + elf_errmsg (-1)); + + cp = flagbuf; + if (shdr->sh_flags & SHF_WRITE) + *cp++ = 'W'; + if (shdr->sh_flags & SHF_ALLOC) + *cp++ = 'A'; + if (shdr->sh_flags & SHF_EXECINSTR) + *cp++ = 'X'; + if (shdr->sh_flags & SHF_MERGE) + *cp++ = 'M'; + if (shdr->sh_flags & SHF_STRINGS) + *cp++ = 'S'; + if (shdr->sh_flags & SHF_INFO_LINK) + *cp++ = 'I'; + if (shdr->sh_flags & SHF_LINK_ORDER) + *cp++ = 'L'; + if (shdr->sh_flags & SHF_OS_NONCONFORMING) + *cp++ = 'N'; + if (shdr->sh_flags & SHF_GROUP) + *cp++ = 'G'; + if (shdr->sh_flags & SHF_TLS) + *cp++ = 'T'; + if (shdr->sh_flags & SHF_ORDERED) + *cp++ = 'O'; + if (shdr->sh_flags & SHF_EXCLUDE) + *cp++ = 'E'; + *cp = '\0'; + + printf ("[%2zu] %-20s %-12s %0*" PRIx64 " %0*" PRIx64 " %0*" PRIx64 + " %2" PRId64 " %-5s %2" PRId32 " %3" PRId32 + " %2" PRId64 "\n", + cnt, + elf_strptr (ebl->elf, shstrndx, shdr->sh_name) + ?: "", + ebl_section_type_name (ebl, shdr->sh_type, buf, sizeof (buf)), + ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, shdr->sh_addr, + ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_offset, + ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_size, + shdr->sh_entsize, flagbuf, shdr->sh_link, shdr->sh_info, + shdr->sh_addralign); + } + + fputc_unlocked ('\n', stdout); +} + + +/* Print the program header. */ +static void +print_phdr (Ebl *ebl, GElf_Ehdr *ehdr) +{ + size_t cnt; + size_t shstrndx; + + if (ehdr->e_phnum == 0) + /* No program header, this is OK in relocatable objects. */ + return; + + puts (gettext ("Program Headers:")); + if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) + puts (gettext ("\ + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align")); + else + puts (gettext ("\ + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align")); + + /* Process all program headers. */ + bool has_relro = false; + GElf_Addr relro_from = 0; + GElf_Addr relro_to = 0; + for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) + { + char buf[128]; + GElf_Phdr mem; + GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem); + + /* If for some reason the header cannot be returned show this. */ + if (phdr == NULL) + { + puts (" ???"); + continue; + } + + printf (" %-14s 0x%06" PRIx64 " 0x%0*" PRIx64 " 0x%0*" PRIx64 + " 0x%06" PRIx64 " 0x%06" PRIx64 " %c%c%c 0x%" PRIx64 "\n", + ebl_segment_type_name (ebl, phdr->p_type, buf, sizeof (buf)), + phdr->p_offset, + ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_vaddr, + ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_paddr, + phdr->p_filesz, + phdr->p_memsz, + phdr->p_flags & PF_R ? 'R' : ' ', + phdr->p_flags & PF_W ? 'W' : ' ', + phdr->p_flags & PF_X ? 'E' : ' ', + phdr->p_align); + + if (phdr->p_type == PT_INTERP) + { + /* We can show the user the name of the interpreter. */ + size_t maxsize; + char *filedata = elf_rawfile (ebl->elf, &maxsize); + + if (filedata != NULL && phdr->p_offset < maxsize) + printf (gettext ("\t[Requesting program interpreter: %s]\n"), + filedata + phdr->p_offset); + } + else if (phdr->p_type == PT_GNU_RELRO) + { + has_relro = true; + relro_from = phdr->p_vaddr; + relro_to = relro_from + phdr->p_memsz; + } + } + + /* Get the section header string table index. */ + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + puts (gettext ("\n Section to Segment mapping:\n Segment Sections...")); + + for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem); + size_t inner; + + /* Print the segment number. */ + printf (" %2.2zu ", cnt); + + /* This must not happen. */ + if (phdr == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot get program header: %s"), + elf_errmsg (-1)); + + /* Iterate over the sections. */ + bool in_relro = false; + bool in_ro = false; + for (inner = 1; inner < shnum; ++inner) + { + Elf_Scn *scn = elf_getscn (ebl->elf, inner); + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + /* It should not happen. */ + if (scn == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"), + elf_errmsg (-1)); + + /* Get the section header. */ + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header: %s"), + elf_errmsg (-1)); + + if (shdr->sh_size > 0 + /* Compare allocated sections by VMA, unallocated + sections by file offset. */ + && (shdr->sh_flags & SHF_ALLOC + ? (shdr->sh_addr >= phdr->p_vaddr + && (shdr->sh_addr + shdr->sh_size + <= phdr->p_vaddr + phdr->p_memsz)) + : (shdr->sh_offset >= phdr->p_offset + && (shdr->sh_offset + shdr->sh_size + <= phdr->p_offset + phdr->p_filesz)))) + { + if (has_relro && !in_relro + && shdr->sh_addr >= relro_from + && shdr->sh_addr + shdr->sh_size <= relro_to) + { + fputs_unlocked (" [RELRO:", stdout); + in_relro = true; + } + else if (has_relro && in_relro && shdr->sh_addr >= relro_to) + { + fputs_unlocked ("]", stdout); + in_relro = false; + } + else if (has_relro && in_relro + && shdr->sh_addr + shdr->sh_size > relro_to) + fputs_unlocked ("] p_type == PT_LOAD && (phdr->p_flags & PF_W) == 0) + { + if (!in_ro) + { + fputs_unlocked (" [RO:", stdout); + in_ro = true; + } + } + else + { + /* Determine the segment this section is part of. */ + size_t cnt2; + GElf_Phdr *phdr2 = NULL; + for (cnt2 = 0; cnt2 < ehdr->e_phnum; ++cnt2) + { + GElf_Phdr phdr2_mem; + phdr2 = gelf_getphdr (ebl->elf, cnt2, &phdr2_mem); + + if (phdr2 != NULL && phdr2->p_type == PT_LOAD + && shdr->sh_addr >= phdr2->p_vaddr + && (shdr->sh_addr + shdr->sh_size + <= phdr2->p_vaddr + phdr2->p_memsz)) + break; + } + + if (cnt2 < ehdr->e_phnum) + { + if ((phdr2->p_flags & PF_W) == 0 && !in_ro) + { + fputs_unlocked (" [RO:", stdout); + in_ro = true; + } + else if ((phdr2->p_flags & PF_W) != 0 && in_ro) + { + fputs_unlocked ("]", stdout); + in_ro = false; + } + } + } + + printf (" %s", + elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); + + /* Signal that this sectin is only partially covered. */ + if (has_relro && in_relro + && shdr->sh_addr + shdr->sh_size > relro_to) + { + fputs_unlocked (">", stdout); + in_relro = false; + } + } + } + if (in_relro || in_ro) + fputs_unlocked ("]", stdout); + + /* Finish the line. */ + fputc_unlocked ('\n', stdout); + } +} + + +static void +handle_scngrp (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) +{ + Elf_Data *data; + Elf32_Word *grpref; + Elf_Scn *symscn; + GElf_Shdr symshdr_mem; + GElf_Shdr *symshdr; + Elf_Data *symdata; + GElf_Sym sym_mem; + size_t cnt; + size_t shstrndx; + + /* Get the data of the section. */ + data = elf_getdata (scn, NULL); + + symscn = elf_getscn (ebl->elf, shdr->sh_link); + symshdr = gelf_getshdr (symscn, &symshdr_mem); + symdata = elf_getdata (symscn, NULL); + + if (data == NULL || data->d_size < sizeof (Elf32_Word) || symshdr == NULL + || symdata == NULL) + return; + + /* Get the section header string table index. */ + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + grpref = (Elf32_Word *) data->d_buf; + + printf ((grpref[0] & GRP_COMDAT) + ? ngettext ("\ +\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entry:\n", + "\ +\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entries:\n", + data->d_size / sizeof (Elf32_Word) - 1) + : ngettext ("\ +\nSection group [%2zu] '%s' with signature '%s' contains %zu entry:\n", "\ +\nSection group [%2zu] '%s' with signature '%s' contains %zu entries:\n", + data->d_size / sizeof (Elf32_Word) - 1), + elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + elf_strptr (ebl->elf, symshdr->sh_link, + gelf_getsym (symdata, shdr->sh_info, &sym_mem)->st_name) + ?: gettext (""), + data->d_size / sizeof (Elf32_Word) - 1); + + for (cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt) + { + GElf_Shdr grpshdr_mem; + GElf_Shdr *grpshdr; + + grpshdr = gelf_getshdr (elf_getscn (ebl->elf, grpref[cnt]), + &grpshdr_mem); + + if (grpshdr == NULL) + printf (gettext (" [%2u] \n"), grpref[cnt]); + else + printf (" [%2u] %s\n", + grpref[cnt], + elf_strptr (ebl->elf, shstrndx, grpshdr->sh_name) + ?: gettext ("")); + } +} + + +static void +print_scngrp (Ebl *ebl) +{ + /* Find all relocation sections and handle them. */ + Elf_Scn *scn = NULL; + + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + /* Handle the section if it is a symbol table. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr != NULL && shdr->sh_type == SHT_GROUP) + handle_scngrp (ebl, scn, shdr); + } +} + + +static const struct flags +{ + int mask; + const char *str; +} dt_flags[] = + { + { DF_ORIGIN, "ORIGIN" }, + { DF_SYMBOLIC, "SYMBOLIC" }, + { DF_TEXTREL, "TEXTREL" }, + { DF_BIND_NOW, "BIND_NOW" }, + { DF_STATIC_TLS, "STATIC_TLS" } + }; +static const int ndt_flags = sizeof (dt_flags) / sizeof (dt_flags[0]); + +static const struct flags dt_flags_1[] = + { + { DF_1_NOW, "NOW" }, + { DF_1_GLOBAL, "GLOBAL" }, + { DF_1_GROUP, "GROUP" }, + { DF_1_NODELETE, "NODELETE" }, + { DF_1_LOADFLTR, "LOADFLTR" }, + { DF_1_INITFIRST, "INITFIRST" }, + { DF_1_NOOPEN, "NOOPEN" }, + { DF_1_ORIGIN, "ORIGIN" }, + { DF_1_DIRECT, "DIRECT" }, + { DF_1_TRANS, "TRANS" }, + { DF_1_INTERPOSE, "INTERPOSE" }, + { DF_1_NODEFLIB, "NODEFLIB" }, + { DF_1_NODUMP, "NODUMP" }, + { DF_1_CONFALT, "CONFALT" }, + { DF_1_ENDFILTEE, "ENDFILTEE" }, + { DF_1_DISPRELDNE, "DISPRELDNE" }, + { DF_1_DISPRELPND, "DISPRELPND" }, + }; +static const int ndt_flags_1 = sizeof (dt_flags_1) / sizeof (dt_flags_1[0]); + +static const struct flags dt_feature_1[] = + { + { DTF_1_PARINIT, "PARINIT" }, + { DTF_1_CONFEXP, "CONFEXP" } + }; +static const int ndt_feature_1 = (sizeof (dt_feature_1) + / sizeof (dt_feature_1[0])); + +static const struct flags dt_posflag_1[] = + { + { DF_P1_LAZYLOAD, "LAZYLOAD" }, + { DF_P1_GROUPPERM, "GROUPPERM" } + }; +static const int ndt_posflag_1 = (sizeof (dt_posflag_1) + / sizeof (dt_posflag_1[0])); + + +static void +print_flags (int class, GElf_Xword d_val, const struct flags *flags, + int nflags) +{ + bool first = true; + int cnt; + + for (cnt = 0; cnt < nflags; ++cnt) + if (d_val & flags[cnt].mask) + { + if (!first) + putchar_unlocked (' '); + fputs_unlocked (flags[cnt].str, stdout); + d_val &= ~flags[cnt].mask; + first = false; + } + + if (d_val != 0) + { + if (!first) + putchar_unlocked (' '); + printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, d_val); + } + + putchar_unlocked ('\n'); +} + + +static void +print_dt_flags (int class, GElf_Xword d_val) +{ + print_flags (class, d_val, dt_flags, ndt_flags); +} + + +static void +print_dt_flags_1 (int class, GElf_Xword d_val) +{ + print_flags (class, d_val, dt_flags_1, ndt_flags_1); +} + + +static void +print_dt_feature_1 (int class, GElf_Xword d_val) +{ + print_flags (class, d_val, dt_feature_1, ndt_feature_1); +} + + +static void +print_dt_posflag_1 (int class, GElf_Xword d_val) +{ + print_flags (class, d_val, dt_posflag_1, ndt_posflag_1); +} + + +static void +handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) +{ + int class = gelf_getclass (ebl->elf); + GElf_Shdr glink; + Elf_Data *data; + size_t cnt; + size_t shstrndx; + + /* Get the data of the section. */ + data = elf_getdata (scn, NULL); + if (data == NULL) + return; + + /* Get the section header string table index. */ + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + printf (ngettext ("\ +\nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + "\ +\nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + shdr->sh_size / shdr->sh_entsize), + (unsigned long int) (shdr->sh_size / shdr->sh_entsize), + class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, + shdr->sh_offset, + (int) shdr->sh_link, + elf_strptr (ebl->elf, shstrndx, + gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), + &glink)->sh_name)); + fputs_unlocked (gettext (" Type Value\n"), stdout); + + for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) + { + char buf[64]; + GElf_Dyn dynmem; + GElf_Dyn *dyn; + + dyn = gelf_getdyn (data, cnt, &dynmem); + if (dyn == NULL) + break; + + printf (" %-17s ", + ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, sizeof (buf))); + + switch (dyn->d_tag) + { + case DT_NULL: + case DT_DEBUG: + case DT_BIND_NOW: + case DT_TEXTREL: + /* No further output. */ + fputc ('\n', stdout); + break; + + case DT_NEEDED: + printf (gettext ("Shared library: [%s]\n"), + elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); + break; + + case DT_SONAME: + printf (gettext ("Library soname: [%s]\n"), + elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); + break; + + case DT_RPATH: + printf (gettext ("Library rpath: [%s]\n"), + elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); + break; + + case DT_RUNPATH: + printf (gettext ("Library runpath: [%s]\n"), + elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); + break; + + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_STRSZ: + case DT_RELSZ: + case DT_RELAENT: + case DT_SYMENT: + case DT_RELENT: + case DT_PLTPADSZ: + case DT_MOVEENT: + case DT_MOVESZ: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_SYMINSZ: + case DT_SYMINENT: + case DT_GNU_CONFLICTSZ: + case DT_GNU_LIBLISTSZ: + printf (gettext ("%" PRId64 " (bytes)\n"), dyn->d_un.d_val); + break; + + case DT_VERDEFNUM: + case DT_VERNEEDNUM: + case DT_RELACOUNT: + case DT_RELCOUNT: + printf ("%" PRId64 "\n", dyn->d_un.d_val); + break; + + case DT_PLTREL: + puts (ebl_dynamic_tag_name (ebl, dyn->d_un.d_val, NULL, 0)); + break; + + case DT_FLAGS: + print_dt_flags (class, dyn->d_un.d_val); + break; + + case DT_FLAGS_1: + print_dt_flags_1 (class, dyn->d_un.d_val); + break; + + case DT_FEATURE_1: + print_dt_feature_1 (class, dyn->d_un.d_val); + break; + + case DT_POSFLAG_1: + print_dt_posflag_1 (class, dyn->d_un.d_val); + break; + + default: + printf ("%#0*" PRIx64 "\n", + class == ELFCLASS32 ? 10 : 18, dyn->d_un.d_val); + break; + } + } +} + + +/* Print the dynamic segment. */ +static void +print_dynamic (Ebl *ebl) +{ + /* Find all relocation sections and handle them. */ + Elf_Scn *scn = NULL; + + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + /* Handle the section if it is a symbol table. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC) + { + handle_dynamic (ebl, scn, shdr); + break; + } + } +} + + +/* Print relocations. */ +static void +print_relocs (Ebl *ebl) +{ + /* Find all relocation sections and handle them. */ + Elf_Scn *scn = NULL; + + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + /* Handle the section if it is a symbol table. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr != NULL) + { + if (shdr->sh_type == SHT_REL) + handle_relocs_rel (ebl, scn, shdr); + else if (shdr->sh_type == SHT_RELA) + handle_relocs_rela (ebl, scn, shdr); + } + } +} + + +/* Handle a relocation section. */ +static void +handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) +{ + int class = gelf_getclass (ebl->elf); + int nentries = shdr->sh_size / shdr->sh_entsize; + int cnt; + Elf_Data *data; + Elf_Scn *symscn; + GElf_Shdr symshdr_mem; + GElf_Shdr *symshdr; + Elf_Data *symdata; + GElf_Shdr destshdr_mem; + GElf_Shdr *destshdr; + Elf_Scn *xndxscn; + Elf_Data *xndxdata = NULL; + size_t shstrndx; + + /* Get the data of the section. */ + data = elf_getdata (scn, NULL); + if (data == NULL) + return; + + /* Get the symbol table information. */ + symscn = elf_getscn (ebl->elf, shdr->sh_link); + symshdr = gelf_getshdr (symscn, &symshdr_mem); + symdata = elf_getdata (symscn, NULL); + + /* Get the section header of the section the relocations are for. */ + destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info), + &destshdr_mem); + + if (symshdr == NULL || symdata == NULL || destshdr == NULL) + { + printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"), + shdr->sh_offset); + return; + } + + /* Search for the optional extended section index table. */ + xndxscn = NULL; + while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL) + { + GElf_Shdr xndxshdr_mem; + GElf_Shdr *xndxshdr; + + xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem); + if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX + && xndxshdr->sh_link == elf_ndxscn (symscn)) + { + /* Found it. */ + xndxdata = elf_getdata (xndxscn, NULL); + break; + } + } + + /* Get the section header string table index. */ + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + if (shdr->sh_info != 0) + printf (ngettext ("\ +\nRelocation section [%2u] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n", + "\ +\nRelocation section [%2u] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", + nentries), + (unsigned int) elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + (unsigned int) shdr->sh_info, + elf_strptr (ebl->elf, shstrndx, destshdr->sh_name), + shdr->sh_offset, + nentries); + else + /* The .rel.dyn section does not refer to a specific section but + instead of section index zero. Do not try to print a section + name. */ + printf (ngettext ("\ +\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n", + "\ +\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", + nentries), + (unsigned int) elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + shdr->sh_offset, + nentries); + fputs_unlocked (class == ELFCLASS32 + ? gettext ("\ + Offset Type Value Name\n") + : gettext ("\ + Offset Type Value Name\n"), + stdout); + + for (cnt = 0; cnt < nentries; ++cnt) + { + GElf_Rel relmem; + GElf_Rel *rel; + + rel = gelf_getrel (data, cnt, &relmem); + if (rel != NULL) + { + char buf[128]; + GElf_Sym symmem; + GElf_Sym *sym; + Elf32_Word xndx; + + sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (rel->r_info), + &symmem, &xndx); + if (sym == NULL) + printf (" %#0*" PRIx64 " %-20s <%s %ld>\n", + class == ELFCLASS32 ? 10 : 18, rel->r_offset, + ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) + /* Avoid the leading R_ which isn't carrying any + information. */ + ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), + buf, sizeof (buf)) + 2 + : gettext (""), + gettext ("INVALID SYMBOL"), + (long int) GELF_R_SYM (rel->r_info)); + else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION) + printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", + class == ELFCLASS32 ? 10 : 18, rel->r_offset, + ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) + /* Avoid the leading R_ which isn't carrying any + information. */ + ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), + buf, sizeof (buf)) + 2 + : gettext (""), + class == ELFCLASS32 ? 10 : 18, sym->st_value, + elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); + else + { + destshdr = gelf_getshdr (elf_getscn (ebl->elf, + sym->st_shndx == SHN_XINDEX + ? xndx : sym->st_shndx), + &destshdr_mem); + + if (shdr == NULL) + printf (" %#0*" PRIx64 " %-20s <%s %ld>\n", + class == ELFCLASS32 ? 10 : 18, rel->r_offset, + ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) + /* Avoid the leading R_ which isn't carrying any + information. */ + ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), + buf, sizeof (buf)) + 2 + : gettext (""), + gettext ("INVALID SECTION"), + (long int) (sym->st_shndx == SHN_XINDEX + ? xndx : sym->st_shndx)); + else + printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", + class == ELFCLASS32 ? 10 : 18, rel->r_offset, + ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) + /* Avoid the leading R_ which isn't carrying any + information. */ + ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), + buf, sizeof (buf)) + 2 + : gettext (""), + class == ELFCLASS32 ? 10 : 18, sym->st_value, + elf_strptr (ebl->elf, shstrndx, destshdr->sh_name)); + } + } + } +} + + +/* Handle a relocation section. */ +static void +handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) +{ + int class = gelf_getclass (ebl->elf); + int nentries = shdr->sh_size / shdr->sh_entsize; + + /* Get the data of the section. */ + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL) + return; + + /* Get the symbol table information. */ + Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link); + GElf_Shdr symshdr_mem; + GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem); + Elf_Data *symdata = elf_getdata (symscn, NULL); + + /* Get the section header of the section the relocations are for. */ + GElf_Shdr destshdr_mem; + GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info), + &destshdr_mem); + + if (symshdr == NULL || symdata == NULL || destshdr == NULL) + { + printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"), + shdr->sh_offset); + return; + } + + /* Search for the optional extended section index table. */ + Elf_Data *xndxdata = NULL; + Elf_Scn *xndxscn = NULL; + while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL) + { + GElf_Shdr xndxshdr_mem; + GElf_Shdr *xndxshdr; + + xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem); + if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX + && xndxshdr->sh_link == elf_ndxscn (symscn)) + { + /* Found it. */ + xndxdata = elf_getdata (xndxscn, NULL); + break; + } + } + + /* Get the section header string table index. */ + size_t shstrndx; + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + printf (ngettext ("\ +\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n", + "\ +\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", + nentries), + elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + (unsigned int) shdr->sh_info, + elf_strptr (ebl->elf, shstrndx, destshdr->sh_name), + shdr->sh_offset, + nentries); + fputs_unlocked (class == ELFCLASS32 + ? gettext ("\ + Offset Type Value Addend Name\n") + : gettext ("\ + Offset Type Value Addend Name\n"), + stdout); + + for (int cnt = 0; cnt < nentries; ++cnt) + { + GElf_Rela relmem; + GElf_Rela *rel = gelf_getrela (data, cnt, &relmem); + if (rel != NULL) + { + char buf[64]; + GElf_Sym symmem; + GElf_Sym *sym; + Elf32_Word xndx; + + sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (rel->r_info), + &symmem, &xndx); + + if (sym == NULL) + printf (" %#0*" PRIx64 " %-15s <%s %ld>\n", + class == ELFCLASS32 ? 10 : 18, rel->r_offset, + ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) + /* Avoid the leading R_ which isn't carrying any + information. */ + ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), + buf, sizeof (buf)) + 2 + : gettext (""), + gettext ("INVALID SYMBOL"), + (long int) GELF_R_SYM (rel->r_info)); + else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION) + printf ("\ + %#0*" PRIx64 " %-15s %#0*" PRIx64 " +%5" PRId64 " %s\n", + class == ELFCLASS32 ? 10 : 18, rel->r_offset, + ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) + /* Avoid the leading R_ which isn't carrying any + information. */ + ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), + buf, sizeof (buf)) + 2 + : gettext (""), + class == ELFCLASS32 ? 10 : 18, sym->st_value, + rel->r_addend, + elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); + else + { + destshdr = gelf_getshdr (elf_getscn (ebl->elf, + sym->st_shndx == SHN_XINDEX + ? xndx : sym->st_shndx), + &destshdr_mem); + + if (shdr == NULL) + printf (" %#0*" PRIx64 " %-15s <%s %ld>\n", + class == ELFCLASS32 ? 10 : 18, rel->r_offset, + ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) + /* Avoid the leading R_ which isn't carrying any + information. */ + ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), + buf, sizeof (buf)) + 2 + : gettext (""), + gettext ("INVALID SECTION"), + (long int) (sym->st_shndx == SHN_XINDEX + ? xndx : sym->st_shndx)); + else + printf ("\ + %#0*" PRIx64 " %-15s %#0*" PRIx64 " +%5" PRId64 " %s\n", + class == ELFCLASS32 ? 10 : 18, rel->r_offset, + ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) + /* Avoid the leading R_ which isn't carrying any + information. */ + ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), + buf, sizeof (buf)) + 2 + : gettext (""), + class == ELFCLASS32 ? 10 : 18, sym->st_value, + rel->r_addend, + elf_strptr (ebl->elf, shstrndx, destshdr->sh_name)); + } + } + } +} + + +/* Print the program header. */ +static void +print_symtab (Ebl *ebl, int type) +{ + /* Find the symbol table(s). For this we have to search through the + section table. */ + Elf_Scn *scn = NULL; + + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + /* Handle the section if it is a symbol table. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr != NULL && shdr->sh_type == (GElf_Word) type) + handle_symtab (ebl, scn, shdr); + } +} + + +static void +handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) +{ + Elf_Data *versym_data = NULL; + Elf_Data *verneed_data = NULL; + Elf_Data *verdef_data = NULL; + Elf_Data *xndx_data = NULL; + Elf_Scn *runscn; + Elf_Data *data; + int class = gelf_getclass (ebl->elf); + unsigned int nsyms; + unsigned int cnt; + Elf32_Word verneed_stridx = 0; + Elf32_Word verdef_stridx = 0; + GElf_Shdr glink; + size_t shstrndx; + + /* Get the data of the section. */ + data = elf_getdata (scn, NULL); + if (data == NULL) + return; + + /* Find out whether we have other sections we might need. */ + runscn = NULL; + while ((runscn = elf_nextscn (ebl->elf, runscn)) != NULL) + { + GElf_Shdr runshdr_mem; + GElf_Shdr *runshdr = gelf_getshdr (runscn, &runshdr_mem); + + if (runshdr != NULL) + { + if (runshdr->sh_type == SHT_GNU_versym + && runshdr->sh_link == elf_ndxscn (scn)) + /* Bingo, found the version information. Now get the data. */ + versym_data = elf_getdata (runscn, NULL); + else if (runshdr->sh_type == SHT_GNU_verneed) + { + /* This is the information about the needed versions. */ + verneed_data = elf_getdata (runscn, NULL); + verneed_stridx = runshdr->sh_link; + } + else if (runshdr->sh_type == SHT_GNU_verdef) + { + /* This is the information about the defined versions. */ + verdef_data = elf_getdata (runscn, NULL); + verdef_stridx = runshdr->sh_link; + } + else if (runshdr->sh_type == SHT_SYMTAB_SHNDX + && runshdr->sh_link == elf_ndxscn (scn)) + /* Extended section index. */ + xndx_data = elf_getdata (runscn, NULL); + } + } + + /* Get the section header string table index. */ + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + /* Now we can compute the number of entries in the section. */ + nsyms = data->d_size / (class == ELFCLASS32 + ? sizeof (Elf32_Sym) : sizeof (Elf64_Sym)); + + printf (ngettext ("\nSymbol table [%2u] '%s' contains %u entry:\n", + "\nSymbol table [%2u] '%s' contains %u entries:\n", + nsyms), + (unsigned int) elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), nsyms); + printf (ngettext (" %lu local symbol String table: [%2u] '%s'\n", + " %lu local symbols String table: [%2u] '%s'\n", + shdr->sh_info), + (unsigned long int) shdr->sh_info, + (unsigned int) shdr->sh_link, + elf_strptr (ebl->elf, shstrndx, + gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), + &glink)->sh_name)); + + fputs_unlocked (class == ELFCLASS32 + ? gettext ("\ + Num: Value Size Type Bind Vis Ndx Name\n") + : gettext ("\ + Num: Value Size Type Bind Vis Ndx Name\n"), + stdout); + + for (cnt = 0; cnt < nsyms; ++cnt) + { + char typebuf[64]; + char bindbuf[64]; + char scnbuf[64]; + Elf32_Word xndx; + GElf_Sym sym_mem; + GElf_Sym *sym = gelf_getsymshndx (data, xndx_data, cnt, &sym_mem, &xndx); + + if (sym == NULL) + continue; + + /* Determine the real section index. */ + if (sym->st_shndx != SHN_XINDEX) + xndx = sym->st_shndx; + + printf (gettext ("\ +%5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"), + cnt, + class == ELFCLASS32 ? 8 : 16, + sym->st_value, + sym->st_size, + ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info), + typebuf, sizeof (typebuf)), + ebl_symbol_binding_name (ebl, GELF_ST_BIND (sym->st_info), + bindbuf, sizeof (bindbuf)), + get_visibility_type (GELF_ST_VISIBILITY (sym->st_other)), + ebl_section_name (ebl, sym->st_shndx, xndx, scnbuf, + sizeof (scnbuf), NULL, shnum), + elf_strptr (ebl->elf, shdr->sh_link, sym->st_name)); + + if (versym_data != NULL) + { + /* Get the version information. */ + GElf_Versym versym_mem; + GElf_Versym *versym; + + versym = gelf_getversym (versym_data, cnt, &versym_mem); + + if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1)) + { + bool is_nobits = false; + bool check_def = xndx != SHN_UNDEF; + + if (xndx < SHN_LORESERVE || sym->st_shndx == SHN_XINDEX) + { + GElf_Shdr symshdr_mem; + GElf_Shdr *symshdr = + gelf_getshdr (elf_getscn (ebl->elf, xndx), &symshdr_mem); + + is_nobits = (symshdr != NULL + && symshdr->sh_type == SHT_NOBITS); + } + + if (is_nobits || ! check_def) + { + /* We must test both. */ + GElf_Verneed verneed_mem; + GElf_Verneed *verneed; + GElf_Vernaux vernaux_mem; + GElf_Vernaux *vernaux = NULL; + size_t vn_offset = 0; + + verneed = gelf_getverneed (verneed_data, 0, &verneed_mem); + while (verneed != NULL) + { + size_t vna_offset = vn_offset; + + vernaux = gelf_getvernaux (verneed_data, + vna_offset += verneed->vn_aux, + &vernaux_mem); + while (vernaux != NULL + && vernaux->vna_other != *versym + && vernaux->vna_next != 0) + { + /* Update the offset. */ + vna_offset += vernaux->vna_next; + + vernaux = (vernaux->vna_next == 0 + ? NULL + : gelf_getvernaux (verneed_data, + vna_offset, + &vernaux_mem)); + } + + /* Check whether we found the version. */ + if (vernaux != NULL && vernaux->vna_other == *versym) + /* Found it. */ + break; + + vn_offset += verneed->vn_next; + verneed = (verneed->vn_next == 0 + ? NULL + : gelf_getverneed (verneed_data, vn_offset, + &verneed_mem)); + } + + if (vernaux != NULL && vernaux->vna_other == *versym) + { + printf ("@%s (%u)", + elf_strptr (ebl->elf, verneed_stridx, + vernaux->vna_name), + (unsigned int) vernaux->vna_other); + check_def = 0; + } + else if (! is_nobits) + error (0, 0, gettext ("bad dynamic symbol")); + else + check_def = 1; + } + + if (check_def && *versym != 0x8001) + { + /* We must test both. */ + GElf_Verdef verdef_mem; + GElf_Verdef *verdef; + size_t vd_offset = 0; + + verdef = gelf_getverdef (verdef_data, 0, &verdef_mem); + while (verdef != NULL) + { + if (verdef->vd_ndx == (*versym & 0x7fff)) + /* Found the definition. */ + break; + + vd_offset += verdef->vd_next; + verdef = (verdef->vd_next == 0 + ? NULL + : gelf_getverdef (verdef_data, vd_offset, + &verdef_mem)); + } + + if (verdef != NULL) + { + GElf_Verdaux verdaux_mem; + GElf_Verdaux *verdaux; + + verdaux = gelf_getverdaux (verdef_data, + vd_offset + verdef->vd_aux, + &verdaux_mem); + + if (verdaux != NULL) + printf ((*versym & 0x8000) ? "@%s" : "@@%s", + elf_strptr (ebl->elf, verdef_stridx, + verdaux->vda_name)); + } + } + } + } + + putchar ('\n'); + } +} + + +/* Print version information. */ +static void +print_verinfo (Ebl *ebl) +{ + /* Find the version information sections. For this we have to + search through the section table. */ + Elf_Scn *scn = NULL; + + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + /* Handle the section if it is part of the versioning handling. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr != NULL) + { + if (shdr->sh_type == SHT_GNU_verneed) + handle_verneed (ebl, scn, shdr); + else if (shdr->sh_type == SHT_GNU_verdef) + handle_verdef (ebl, scn, shdr); + else if (shdr->sh_type == SHT_GNU_versym) + handle_versym (ebl, scn, shdr); + } + } +} + + +static const char * +get_ver_flags (unsigned int flags) +{ + static char buf[32]; + char *endp; + + if (flags == 0) + return gettext ("none"); + + if (flags & VER_FLG_BASE) + endp = stpcpy (buf, "BASE "); + else + endp = buf; + + if (flags & VER_FLG_WEAK) + { + if (endp != buf) + endp = stpcpy (endp, "| "); + + endp = stpcpy (endp, "WEAK "); + } + + if (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)) + { + strncpy (endp, gettext ("| "), buf + sizeof (buf) - endp); + buf[sizeof (buf) - 1] = '\0'; + } + + return buf; +} + + +static void +handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) +{ + Elf_Data *data; + int class = gelf_getclass (ebl->elf); + GElf_Shdr glink; + int cnt; + unsigned int offset; + size_t shstrndx; + + /* Get the data of the section. */ + data = elf_getdata (scn, NULL); + if (data == NULL) + return; + + /* Get the section header string table index. */ + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + printf (ngettext ("\ +\nVersion needs section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + "\ +\nVersion needs section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + shdr->sh_info), + (unsigned int) elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), shdr->sh_info, + class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, + shdr->sh_offset, + (unsigned int) shdr->sh_link, + elf_strptr (ebl->elf, shstrndx, + gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), + &glink)->sh_name)); + + offset = 0; + for (cnt = shdr->sh_info; --cnt >= 0; ) + { + GElf_Verneed needmem; + GElf_Verneed *need; + unsigned int auxoffset; + int cnt2; + + /* Get the data at the next offset. */ + need = gelf_getverneed (data, offset, &needmem); + if (need == NULL) + break; + + printf (gettext (" %#06x: Version: %hu File: %s Cnt: %hu\n"), + offset, (unsigned short int) need->vn_version, + elf_strptr (ebl->elf, shdr->sh_link, need->vn_file), + (unsigned short int) need->vn_cnt); + + auxoffset = offset + need->vn_aux; + for (cnt2 = need->vn_cnt; --cnt2 >= 0; ) + { + GElf_Vernaux auxmem; + GElf_Vernaux *aux; + + aux = gelf_getvernaux (data, auxoffset, &auxmem); + if (aux == NULL) + break; + + printf (gettext (" %#06x: Name: %s Flags: %s Version: %hu\n"), + auxoffset, + elf_strptr (ebl->elf, shdr->sh_link, aux->vna_name), + get_ver_flags (aux->vna_flags), + (unsigned short int) aux->vna_other); + + auxoffset += aux->vna_next; + } + + /* Find the next offset. */ + offset += need->vn_next; + } +} + + +static void +handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) +{ + Elf_Data *data; + int class = gelf_getclass (ebl->elf); + GElf_Shdr glink; + int cnt; + unsigned int offset; + size_t shstrndx; + + /* Get the data of the section. */ + data = elf_getdata (scn, NULL); + if (data == NULL) + return; + + /* Get the section header string table index. */ + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + printf (ngettext ("\ +\nVersion definition section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + "\ +\nVersion definition section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + shdr->sh_info), + (unsigned int) elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + shdr->sh_info, + class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, + shdr->sh_offset, + (unsigned int) shdr->sh_link, + elf_strptr (ebl->elf, shstrndx, + gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), + &glink)->sh_name)); + + offset = 0; + for (cnt = shdr->sh_info; --cnt >= 0; ) + { + GElf_Verdef defmem; + GElf_Verdef *def; + GElf_Verdaux auxmem; + GElf_Verdaux *aux; + unsigned int auxoffset; + int cnt2; + + /* Get the data at the next offset. */ + def = gelf_getverdef (data, offset, &defmem); + if (def == NULL) + break; + + auxoffset = offset + def->vd_aux; + aux = gelf_getverdaux (data, auxoffset, &auxmem); + if (aux == NULL) + break; + + printf (gettext ("\ + %#06x: Version: %hd Flags: %s Index: %hd Cnt: %hd Name: %s\n"), + offset, def->vd_version, + get_ver_flags (def->vd_flags), + def->vd_ndx, + def->vd_cnt, + elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name)); + + auxoffset += aux->vda_next; + for (cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2) + { + aux = gelf_getverdaux (data, auxoffset, &auxmem); + if (aux == NULL) + break; + + printf (gettext (" %#06x: Parent %d: %s\n"), + auxoffset, cnt2, + elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name)); + + auxoffset += aux->vda_next; + } + + /* Find the next offset. */ + offset += def->vd_next; + } +} + + +static void +handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) +{ + Elf_Data *data; + int class = gelf_getclass (ebl->elf); + Elf_Scn *verscn; + GElf_Shdr glink; + Elf_Scn *defscn; + Elf_Scn *needscn; + const char **vername; + const char **filename; + size_t nvername; + unsigned int cnt; + size_t shstrndx; + + /* Get the data of the section. */ + data = elf_getdata (scn, NULL); + if (data == NULL) + return; + + /* Get the section header string table index. */ + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + /* We have to find the version definition section and extract the + version names. */ + defscn = NULL; + needscn = NULL; + + verscn = NULL; + while ((verscn = elf_nextscn (ebl->elf, verscn)) != NULL) + { + GElf_Shdr vershdr_mem; + GElf_Shdr *vershdr = gelf_getshdr (verscn, &vershdr_mem); + + if (vershdr != NULL) + { + if (vershdr->sh_type == SHT_GNU_verdef) + defscn = verscn; + else if (vershdr->sh_type == SHT_GNU_verneed) + needscn = verscn; + } + } + + if (defscn != NULL || needscn != NULL) + { + /* We have a version information (better should have). Now get + the version names. First find the maximum version number. */ + nvername = 0; + if (defscn != NULL) + { + /* Run through the version definitions and find the highest + index. */ + unsigned int offset = 0; + Elf_Data *defdata; + GElf_Shdr defshdrmem; + GElf_Shdr *defshdr; + + defdata = elf_getdata (defscn, NULL); + if (defdata == NULL) + return; + + defshdr = gelf_getshdr (defscn, &defshdrmem); + if (defshdr == NULL) + return; + + for (cnt = 0; cnt < defshdr->sh_info; ++cnt) + { + GElf_Verdef defmem; + GElf_Verdef *def; + + /* Get the data at the next offset. */ + def = gelf_getverdef (defdata, offset, &defmem); + if (def == NULL) + break; + + nvername = MAX (nvername, (size_t) (def->vd_ndx & 0x7fff)); + + offset += def->vd_next; + } + } + if (needscn != NULL) + { + unsigned int offset = 0; + Elf_Data *needdata; + GElf_Shdr needshdrmem; + GElf_Shdr *needshdr; + + needdata = elf_getdata (needscn, NULL); + if (needdata == NULL) + return; + + needshdr = gelf_getshdr (needscn, &needshdrmem); + if (needshdr == NULL) + return; + + for (cnt = 0; cnt < needshdr->sh_info; ++cnt) + { + GElf_Verneed needmem; + GElf_Verneed *need; + unsigned int auxoffset; + int cnt2; + + /* Get the data at the next offset. */ + need = gelf_getverneed (needdata, offset, &needmem); + if (need == NULL) + break; + + /* Run through the auxiliary entries. */ + auxoffset = offset + need->vn_aux; + for (cnt2 = need->vn_cnt; --cnt2 >= 0; ) + { + GElf_Vernaux auxmem; + GElf_Vernaux *aux; + + aux = gelf_getvernaux (needdata, auxoffset, &auxmem); + if (aux == NULL) + break; + + nvername = MAX (nvername, + (size_t) (aux->vna_other & 0x7fff)); + + auxoffset += aux->vna_next; + } + + offset += need->vn_next; + } + } + + /* This is the number of versions we know about. */ + ++nvername; + + /* Allocate the array. */ + vername = (const char **) alloca (nvername * sizeof (const char *)); + filename = (const char **) alloca (nvername * sizeof (const char *)); + + /* Run through the data structures again and collect the strings. */ + if (defscn != NULL) + { + /* Run through the version definitions and find the highest + index. */ + unsigned int offset = 0; + Elf_Data *defdata; + GElf_Shdr defshdrmem; + GElf_Shdr *defshdr; + + defdata = elf_getdata (defscn, NULL); + if (defdata == NULL) + return; + + defshdr = gelf_getshdr (defscn, &defshdrmem); + if (defshdr == NULL) + return; + + for (cnt = 0; cnt < defshdr->sh_info; ++cnt) + { + GElf_Verdef defmem; + GElf_Verdef *def; + GElf_Verdaux auxmem; + GElf_Verdaux *aux; + + /* Get the data at the next offset. */ + def = gelf_getverdef (defdata, offset, &defmem); + if (def == NULL) + break; + + aux = gelf_getverdaux (defdata, offset + def->vd_aux, &auxmem); + if (aux == NULL) + break; + + vername[def->vd_ndx & 0x7fff] + = elf_strptr (ebl->elf, defshdr->sh_link, aux->vda_name); + filename[def->vd_ndx & 0x7fff] = NULL; + + offset += def->vd_next; + } + } + if (needscn != NULL) + { + unsigned int offset = 0; + Elf_Data *needdata; + GElf_Shdr needshdrmem; + GElf_Shdr *needshdr; + + needdata = elf_getdata (needscn, NULL); + if (needdata == NULL) + return; + + needshdr = gelf_getshdr (needscn, &needshdrmem); + if (needshdr == NULL) + return; + + for (cnt = 0; cnt < needshdr->sh_info; ++cnt) + { + GElf_Verneed needmem; + GElf_Verneed *need; + unsigned int auxoffset; + int cnt2; + + /* Get the data at the next offset. */ + need = gelf_getverneed (needdata, offset, &needmem); + if (need == NULL) + break; + + /* Run through the auxiliary entries. */ + auxoffset = offset + need->vn_aux; + for (cnt2 = need->vn_cnt; --cnt2 >= 0; ) + { + GElf_Vernaux auxmem; + GElf_Vernaux *aux; + + aux = gelf_getvernaux (needdata, auxoffset, &auxmem); + if (aux == NULL) + break; + + vername[aux->vna_other & 0x7fff] + = elf_strptr (ebl->elf, needshdr->sh_link, aux->vna_name); + filename[aux->vna_other & 0x7fff] + = elf_strptr (ebl->elf, needshdr->sh_link, need->vn_file); + + auxoffset += aux->vna_next; + } + + offset += need->vn_next; + } + } + } + else + { + vername = NULL; + nvername = 1; + filename = NULL; + } + + /* Print the header. */ + printf (ngettext ("\ +\nVersion symbols section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'", + "\ +\nVersion symbols section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'", + shdr->sh_size / shdr->sh_entsize), + (unsigned int) elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + (int) (shdr->sh_size / shdr->sh_entsize), + class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, + shdr->sh_offset, + (unsigned int) shdr->sh_link, + elf_strptr (ebl->elf, shstrndx, + gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), + &glink)->sh_name)); + + /* Now we can finally look at the actual contents of this section. */ + for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) + { + GElf_Versym symmem; + GElf_Versym *sym; + ssize_t n; + + if (cnt % 2 == 0) + printf ("\n %4d:", cnt); + + sym = gelf_getversym (data, cnt, &symmem); + if (sym == NULL) + break; + + switch (*sym) + { + case 0: + fputs_unlocked (gettext (" 0 *local* "), + stdout); + break; + + case 1: + fputs_unlocked (gettext (" 1 *global* "), + stdout); + break; + + default: + n = printf ("%4d%c%s", + *sym & 0x7fff, *sym & 0x8000 ? 'h' : ' ', + (unsigned int) (*sym & 0x7fff) < nvername + ? vername[*sym & 0x7fff] : "???"); + if ((unsigned int) (*sym & 0x7fff) < nvername + && filename[*sym & 0x7fff] != NULL) + n += printf ("(%s)", filename[*sym & 0x7fff]); + printf ("%*s", MAX (0, 33 - (int) n), " "); + break; + } + } + putchar ('\n'); +} + + +static void +handle_hash (Ebl *ebl) +{ + /* Find the symbol table(s). For this we have to search through the + section table. */ + Elf_Scn *scn = NULL; + size_t shstrndx; + + /* Get the section header string table index. */ + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + /* Handle the section if it is a symbol table. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr != NULL && shdr->sh_type == SHT_HASH) + { + Elf_Data *data = elf_getdata (scn, NULL); + Elf32_Word nbucket; + Elf32_Word nchain; + Elf32_Word *bucket; + Elf32_Word *chain; + uint32_t *lengths; + uint32_t *counts; + Elf32_Word cnt; + Elf32_Word maxlength = 0; + Elf32_Word nsyms = 0; + uint64_t nzero_counts = 0; + GElf_Shdr glink; + + if (data == NULL) + { + error (0, 0, gettext ("cannot get data for section %d: %s"), + (int) elf_ndxscn (scn), elf_errmsg (-1)); + continue; + } + + nbucket = ((Elf32_Word *) data->d_buf)[0]; + nchain = ((Elf32_Word *) data->d_buf)[1]; + bucket = &((Elf32_Word *) data->d_buf)[2]; + chain = &((Elf32_Word *) data->d_buf)[2 + nbucket]; + + printf (ngettext ("\ +\nHistogram for bucket list length in section [%2u] '%s' (total of %d bucket):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + "\ +\nHistogram for bucket list length in section [%2u] '%s' (total of %d buckets):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + nbucket), + (unsigned int) elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + (int) nbucket, + gelf_getclass (ebl->elf) == ELFCLASS32 ? 10 : 18, + shdr->sh_addr, + shdr->sh_offset, + (unsigned int) shdr->sh_link, + elf_strptr (ebl->elf, shstrndx, + gelf_getshdr (elf_getscn (ebl->elf, + shdr->sh_link), + &glink)->sh_name)); + + lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t)); + + for (cnt = 0; cnt < nbucket; ++cnt) + if (bucket[cnt] != 0) + { + Elf32_Word inner; + + inner = bucket[cnt]; + while (inner > 0 && inner < nchain) + { + ++nsyms; + if (maxlength < ++lengths[cnt]) + ++maxlength; + + inner = chain[inner]; + } + } + + counts = (uint32_t *) xcalloc (maxlength + 1, sizeof (uint32_t)); + + for (cnt = 0; cnt < nbucket; ++cnt) + ++counts[lengths[cnt]]; + + if (nbucket > 0) + { + uint64_t success = 0; + Elf32_Word acc; + + puts (gettext (" Length Number % of total Coverage")); + printf (gettext (" 0 %6" PRIu32 " %5.1f%%\n"), + counts[0], (counts[0] * 100.0) / nbucket); + + for (cnt = 1; cnt <= maxlength; ++cnt) + { + nzero_counts += counts[cnt] * cnt; + printf (gettext ("\ +%7d %6" PRIu32 " %5.1f%% %5.1f%%\n"), + (int) cnt, + counts[cnt], (counts[cnt] * 100.0) / nbucket, + (nzero_counts * 100.0) / nsyms); + } + + acc = 0; + for (cnt = 1; cnt <= maxlength; ++cnt) + { + acc += cnt; + success += counts[cnt] * acc; + } + + printf (gettext ("\ + Average number of tests: successful lookup: %f\n\ + unsuccessful lookup: %f\n"), + (double) success / (double) nzero_counts, + (double) nzero_counts / (double) nbucket); + } + + free (counts); + free (lengths); + } + } +} + + +static void +print_liblist (Ebl *ebl) +{ + /* Find the library list sections. For this we have to search + through the section table. */ + Elf_Scn *scn = NULL; + + /* Get the section header string table index. */ + size_t shstrndx; + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr != NULL && shdr->sh_type == SHT_GNU_LIBLIST) + { + int nentries = shdr->sh_size / shdr->sh_entsize; + printf (ngettext ("\ +\nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entry:\n", + "\ +\nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entries:\n", + nentries), + elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + shdr->sh_offset, + nentries); + + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL) + return; + + puts (gettext ("\ + Library Time Stamp Checksum Version Flags")); + + for (int cnt = 0; cnt < nentries; ++cnt) + { + GElf_Lib lib_mem; + GElf_Lib *lib = gelf_getlib (data, cnt, &lib_mem); + if (lib == NULL) + continue; + + time_t t = (time_t) lib->l_time_stamp; + struct tm *tm = gmtime (&t); + if (tm == NULL) + continue; + + printf (" [%2d] %-29s %04u-%02u-%02uT%02u:%02u:%02u %08x %-7u %u\n", + cnt, elf_strptr (ebl->elf, shdr->sh_link, lib->l_name), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, + (unsigned int) lib->l_checksum, + (unsigned int) lib->l_version, + (unsigned int) lib->l_flags); + } + } + } +} + + +static const char * +dwarf_tag_string (unsigned int tag) +{ + static const char *known_tags[] = + { + [DW_TAG_array_type] = "array_type", + [DW_TAG_class_type] = "class_type", + [DW_TAG_entry_point] = "entry_point", + [DW_TAG_enumeration_type] = "enumeration_type", + [DW_TAG_formal_parameter] = "formal_parameter", + [DW_TAG_imported_declaration] = "imported_declaration", + [DW_TAG_label] = "label", + [DW_TAG_lexical_block] = "lexical_block", + [DW_TAG_member] = "member", + [DW_TAG_pointer_type] = "pointer_type", + [DW_TAG_reference_type] = "reference_type", + [DW_TAG_compile_unit] = "compile_unit", + [DW_TAG_string_type] = "string_type", + [DW_TAG_structure_type] = "structure_type", + [DW_TAG_subroutine_type] = "subroutine_type", + [DW_TAG_typedef] = "typedef", + [DW_TAG_union_type] = "union_type", + [DW_TAG_unspecified_parameters] = "unspecified_parameters", + [DW_TAG_variant] = "variant", + [DW_TAG_common_block] = "common_block", + [DW_TAG_common_inclusion] = "common_inclusion", + [DW_TAG_inheritance] = "inheritance", + [DW_TAG_inlined_subroutine] = "inlined_subroutine", + [DW_TAG_module] = "module", + [DW_TAG_ptr_to_member_type] = "ptr_to_member_type", + [DW_TAG_set_type] = "set_type", + [DW_TAG_subrange_type] = "subrange_type", + [DW_TAG_with_stmt] = "with_stmt", + [DW_TAG_access_declaration] = "access_declaration", + [DW_TAG_base_type] = "base_type", + [DW_TAG_catch_block] = "catch_block", + [DW_TAG_const_type] = "const_type", + [DW_TAG_constant] = "constant", + [DW_TAG_enumerator] = "enumerator", + [DW_TAG_file_type] = "file_type", + [DW_TAG_friend] = "friend", + [DW_TAG_namelist] = "namelist", + [DW_TAG_namelist_item] = "namelist_item", + [DW_TAG_packed_type] = "packed_type", + [DW_TAG_subprogram] = "subprogram", + [DW_TAG_template_type_param] = "template_type_param", + [DW_TAG_template_value_param] = "template_value_param", + [DW_TAG_thrown_type] = "thrown_type", + [DW_TAG_try_block] = "try_block", + [DW_TAG_variant_part] = "variant_part", + [DW_TAG_variable] = "variable", + [DW_TAG_volatile_type] = "volatile_type", + [DW_TAG_dwarf_procedure] = "dwarf_procedure", + [DW_TAG_restrict_type] = "restrict_type", + [DW_TAG_interface_type] = "interface_type", + [DW_TAG_namespace] = "namespace", + [DW_TAG_imported_module] = "imported_module", + [DW_TAG_unspecified_type] = "unspecified_type", + [DW_TAG_partial_unit] = "partial_unit", + [DW_TAG_imported_unit] = "imported_unit", + [DW_TAG_unspecified_type] = "unspecified_type", + [DW_TAG_partial_unit] = "partial_unit", + [DW_TAG_imported_unit] = "imported_unit", + [DW_TAG_mutable_type] = "mutable_type", + }; + const unsigned int nknown_tags = (sizeof (known_tags) + / sizeof (known_tags[0])); + static char buf[40]; + const char *result = NULL; + + if (tag < nknown_tags) + result = known_tags[tag]; + + if (result == NULL) + /* There are a few known extensions. */ + switch (tag) + { + case DW_TAG_MIPS_loop: + result = "MIPS_loop"; + break; + + case DW_TAG_format_label: + result = "format_label"; + break; + + case DW_TAG_function_template: + result = "function_template"; + break; + + case DW_TAG_class_template: + result = "class_template"; + break; + + default: + if (tag < DW_TAG_lo_user) + snprintf (buf, sizeof buf, gettext ("unknown tag %hx"), tag); + else + snprintf (buf, sizeof buf, gettext ("unknown user tag %hx"), tag); + result = buf; + break; + } + + return result; +} + + +static const char * +dwarf_attr_string (unsigned int attrnum) +{ + static const char *known_attrs[] = + { + [DW_AT_sibling] = "sibling", + [DW_AT_location] = "location", + [DW_AT_name] = "name", + [DW_AT_ordering] = "ordering", + [DW_AT_subscr_data] = "subscr_data", + [DW_AT_byte_size] = "byte_size", + [DW_AT_bit_offset] = "bit_offset", + [DW_AT_bit_size] = "bit_size", + [DW_AT_element_list] = "element_list", + [DW_AT_stmt_list] = "stmt_list", + [DW_AT_low_pc] = "low_pc", + [DW_AT_high_pc] = "high_pc", + [DW_AT_language] = "language", + [DW_AT_member] = "member", + [DW_AT_discr] = "discr", + [DW_AT_discr_value] = "discr_value", + [DW_AT_visibility] = "visibility", + [DW_AT_import] = "import", + [DW_AT_string_length] = "string_length", + [DW_AT_common_reference] = "common_reference", + [DW_AT_comp_dir] = "comp_dir", + [DW_AT_const_value] = "const_value", + [DW_AT_containing_type] = "containing_type", + [DW_AT_default_value] = "default_value", + [DW_AT_inline] = "inline", + [DW_AT_is_optional] = "is_optional", + [DW_AT_lower_bound] = "lower_bound", + [DW_AT_producer] = "producer", + [DW_AT_prototyped] = "prototyped", + [DW_AT_return_addr] = "return_addr", + [DW_AT_start_scope] = "start_scope", + [DW_AT_stride_size] = "stride_size", + [DW_AT_upper_bound] = "upper_bound", + [DW_AT_abstract_origin] = "abstract_origin", + [DW_AT_accessibility] = "accessibility", + [DW_AT_address_class] = "address_class", + [DW_AT_artificial] = "artificial", + [DW_AT_base_types] = "base_types", + [DW_AT_calling_convention] = "calling_convention", + [DW_AT_count] = "count", + [DW_AT_data_member_location] = "data_member_location", + [DW_AT_decl_column] = "decl_column", + [DW_AT_decl_file] = "decl_file", + [DW_AT_decl_line] = "decl_line", + [DW_AT_declaration] = "declaration", + [DW_AT_discr_list] = "discr_list", + [DW_AT_encoding] = "encoding", + [DW_AT_external] = "external", + [DW_AT_frame_base] = "frame_base", + [DW_AT_friend] = "friend", + [DW_AT_identifier_case] = "identifier_case", + [DW_AT_macro_info] = "macro_info", + [DW_AT_namelist_items] = "namelist_items", + [DW_AT_priority] = "priority", + [DW_AT_segment] = "segment", + [DW_AT_specification] = "specification", + [DW_AT_static_link] = "static_link", + [DW_AT_type] = "type", + [DW_AT_use_location] = "use_location", + [DW_AT_variable_parameter] = "variable_parameter", + [DW_AT_virtuality] = "virtuality", + [DW_AT_vtable_elem_location] = "vtable_elem_location", + [DW_AT_allocated] = "allocated", + [DW_AT_associated] = "associated", + [DW_AT_data_location] = "data_location", + [DW_AT_stride] = "stride", + [DW_AT_entry_pc] = "entry_pc", + [DW_AT_use_UTF8] = "use_UTF8", + [DW_AT_extension] = "extension", + [DW_AT_ranges] = "ranges", + [DW_AT_trampoline] = "trampoline", + [DW_AT_call_column] = "call_column", + [DW_AT_call_file] = "call_file", + [DW_AT_call_line] = "call_line", + [DW_AT_description] = "description" + }; + const unsigned int nknown_attrs = (sizeof (known_attrs) + / sizeof (known_attrs[0])); + static char buf[40]; + const char *result = NULL; + + if (attrnum < nknown_attrs) + result = known_attrs[attrnum]; + + if (result == NULL) + /* There are a few known extensions. */ + switch (attrnum) + { + case DW_AT_MIPS_fde: + result = "MIPS_fde"; + break; + + case DW_AT_MIPS_loop_begin: + result = "MIPS_loop_begin"; + break; + + case DW_AT_MIPS_tail_loop_begin: + result = "MIPS_tail_loop_begin"; + break; + + case DW_AT_MIPS_epilog_begin: + result = "MIPS_epilog_begin"; + break; + + case DW_AT_MIPS_loop_unroll_factor: + result = "MIPS_loop_unroll_factor"; + break; + + case DW_AT_MIPS_software_pipeline_depth: + result = "MIPS_software_pipeline_depth"; + break; + + case DW_AT_MIPS_linkage_name: + result = "MIPS_linkage_name"; + break; + + case DW_AT_MIPS_stride: + result = "MIPS_stride"; + break; + + case DW_AT_MIPS_abstract_name: + result = "MIPS_abstract_name"; + break; + + case DW_AT_MIPS_clone_origin: + result = "MIPS_clone_origin"; + break; + + case DW_AT_MIPS_has_inlines: + result = "MIPS_has_inlines"; + break; + + case DW_AT_MIPS_stride_byte: + result = "MIPS_stride_byte"; + break; + + case DW_AT_MIPS_stride_elem: + result = "MIPS_stride_elem"; + break; + + case DW_AT_MIPS_ptr_dopetype: + result = "MIPS_ptr_dopetype"; + break; + + case DW_AT_MIPS_allocatable_dopetype: + result = "MIPS_allocatable_dopetype"; + break; + + case DW_AT_MIPS_assumed_shape_dopetype: + result = "MIPS_assumed_shape_dopetype"; + break; + + case DW_AT_MIPS_assumed_size: + result = "MIPS_assumed_size"; + break; + + case DW_AT_sf_names: + result = "sf_names"; + break; + + case DW_AT_src_info: + result = "src_info"; + break; + + case DW_AT_mac_info: + result = "mac_info"; + break; + + case DW_AT_src_coords: + result = "src_coords"; + break; + + case DW_AT_body_begin: + result = "body_begin"; + break; + + case DW_AT_body_end: + result = "body_end"; + break; + + default: + if (attrnum < DW_AT_lo_user) + snprintf (buf, sizeof buf, gettext ("unknown attribute %hx"), + attrnum); + else + snprintf (buf, sizeof buf, gettext ("unknown user attribute %hx"), + attrnum); + result = buf; + break; + } + + return result; +} + + +static const char * +dwarf_form_string (unsigned int form) +{ + static const char *known_forms[] = + { + [DW_FORM_addr] = "addr", + [DW_FORM_block2] = "block2", + [DW_FORM_block4] = "block4", + [DW_FORM_data2] = "data2", + [DW_FORM_data4] = "data4", + [DW_FORM_data8] = "data8", + [DW_FORM_string] = "string", + [DW_FORM_block] = "block", + [DW_FORM_block1] = "block1", + [DW_FORM_data1] = "data1", + [DW_FORM_flag] = "flag", + [DW_FORM_sdata] = "sdata", + [DW_FORM_strp] = "strp", + [DW_FORM_udata] = "udata", + [DW_FORM_ref_addr] = "ref_addr", + [DW_FORM_ref1] = "ref1", + [DW_FORM_ref2] = "ref2", + [DW_FORM_ref4] = "ref4", + [DW_FORM_ref8] = "ref8", + [DW_FORM_ref_udata] = "ref_udata", + [DW_FORM_indirect] = "indirect" + }; + const unsigned int nknown_forms = (sizeof (known_forms) + / sizeof (known_forms[0])); + static char buf[40]; + const char *result = NULL; + + if (form < nknown_forms) + result = known_forms[form]; + + if (result == NULL) + snprintf (buf, sizeof buf, gettext ("unknown form %" PRIx64), + (uint64_t) form); + + return result; +} + + +static const char * +dwarf_lang_string (unsigned int lang) +{ + static const char *known[] = + { + [DW_LANG_C89] = "ISO C89", + [DW_LANG_C] = "C", + [DW_LANG_Ada83] = "Ada83", + [DW_LANG_C_plus_plus ] = "C++", + [DW_LANG_Cobol74] = "Cobol74", + [DW_LANG_Cobol85] = "Cobol85", + [DW_LANG_Fortran77] = "Fortran77", + [DW_LANG_Fortran90] = "Fortran90", + [DW_LANG_Pascal83] = "Pascal83", + [DW_LANG_Modula2] = "Modula2", + [DW_LANG_Java] = "Java", + [DW_LANG_C99] = "ISO C99", + [DW_LANG_Ada95] = "Ada95", + [DW_LANG_Fortran95] = "Fortran95", + [DW_LANG_PL1] = "PL1" + }; + + if (lang < sizeof (known) / sizeof (known[0])) + return known[lang]; + else if (lang == DW_LANG_Mips_Assembler) + /* This language tag is used for assembler in general. */ + return "Assembler"; + + if (lang >= DW_LANG_lo_user && lang <= DW_LANG_hi_user) + { + static char buf[30]; + snprintf (buf, sizeof (buf), "lo_user+%u", lang - DW_LANG_lo_user); + return buf; + } + + return "???"; +} + + +static const char * +dwarf_inline_string (unsigned int code) +{ + static const char *known[] = + { + [DW_INL_not_inlined] = "not_inlined", + [DW_INL_inlined] = "inlined", + [DW_INL_declared_not_inlined] = "declared_not_inlined", + [DW_INL_declared_inlined] = "declared_inlined" + }; + + if (code < sizeof (known) / sizeof (known[0])) + return known[code]; + + return "???"; +} + + +static const char * +dwarf_encoding_string (unsigned int code) +{ + static const char *known[] = + { + [DW_ATE_void] = "void", + [DW_ATE_address] = "address", + [DW_ATE_boolean] = "boolean", + [DW_ATE_complex_float] = "complex_float", + [DW_ATE_float] = "float", + [DW_ATE_signed] = "signed", + [DW_ATE_signed_char] = "signed_char", + [DW_ATE_unsigned] = "unsigned", + [DW_ATE_unsigned_char] = "unsigned_char", + [DW_ATE_imaginary_float] = "imaginary_float" + }; + + if (code < sizeof (known) / sizeof (known[0])) + return known[code]; + + if (code >= DW_ATE_lo_user && code <= DW_ATE_hi_user) + { + static char buf[30]; + snprintf (buf, sizeof (buf), "lo_user+%u", code - DW_ATE_lo_user); + return buf; + } + + return "???"; +} + + +static const char * +dwarf_access_string (unsigned int code) +{ + static const char *known[] = + { + [DW_ACCESS_public] = "public", + [DW_ACCESS_protected] = "protected", + [DW_ACCESS_private] = "private" + }; + + if (code < sizeof (known) / sizeof (known[0])) + return known[code]; + + return "???"; +} + + +static const char * +dwarf_visibility_string (unsigned int code) +{ + static const char *known[] = + { + [DW_VIS_local] = "local", + [DW_VIS_exported] = "exported", + [DW_VIS_qualified] = "qualified" + }; + + if (code < sizeof (known) / sizeof (known[0])) + return known[code]; + + return "???"; +} + + +static const char * +dwarf_virtuality_string (unsigned int code) +{ + static const char *known[] = + { + [DW_VIRTUALITY_none] = "none", + [DW_VIRTUALITY_virtual] = "virtual", + [DW_VIRTUALITY_pure_virtual] = "pure_virtual" + }; + + if (code < sizeof (known) / sizeof (known[0])) + return known[code]; + + return "???"; +} + + +static const char * +dwarf_identifier_case_string (unsigned int code) +{ + static const char *known[] = + { + [DW_ID_case_sensitive] = "sensitive", + [DW_ID_up_case] = "up_case", + [DW_ID_down_case] = "down_case", + [DW_ID_case_insensitive] = "insensitive" + }; + + if (code < sizeof (known) / sizeof (known[0])) + return known[code]; + + return "???"; +} + + +static const char * +dwarf_calling_convention_string (unsigned int code) +{ + static const char *known[] = + { + [DW_CC_normal] = "normal", + [DW_CC_program] = "program", + [DW_CC_nocall] = "nocall", + }; + + if (code < sizeof (known) / sizeof (known[0])) + return known[code]; + + if (code >= DW_CC_lo_user && code <= DW_CC_hi_user) + { + static char buf[30]; + snprintf (buf, sizeof (buf), "lo_user+%u", code - DW_CC_lo_user); + return buf; + } + + return "???"; +} + + +static const char * +dwarf_ordering_string (unsigned int code) +{ + static const char *known[] = + { + [DW_ORD_row_major] = "row_major", + [DW_ORD_col_major] = "col_major" + }; + + if (code < sizeof (known) / sizeof (known[0])) + return known[code]; + + return "???"; +} + + +static const char * +dwarf_discr_list_string (unsigned int code) +{ + static const char *known[] = + { + [DW_DSC_label] = "label", + [DW_DSC_range] = "range" + }; + + if (code < sizeof (known) / sizeof (known[0])) + return known[code]; + + return "???"; +} + + +static void +print_ops (Dwarf *dbg, int indent, int indentrest, + unsigned int addrsize, Dwarf_Word len, const unsigned char *data) +{ + static const char *known[] = + { + [DW_OP_addr] = "addr", + [DW_OP_deref] = "deref", + [DW_OP_const1u] = "const1u", + [DW_OP_const1s] = "const1s", + [DW_OP_const2u] = "const2u", + [DW_OP_const2s] = "const2s", + [DW_OP_const4u] = "const4u", + [DW_OP_const4s] = "const4s", + [DW_OP_const8u] = "const8u", + [DW_OP_const8s] = "const8s", + [DW_OP_constu] = "constu", + [DW_OP_consts] = "consts", + [DW_OP_dup] = "dup", + [DW_OP_drop] = "drop", + [DW_OP_over] = "over", + [DW_OP_pick] = "pick", + [DW_OP_swap] = "swap", + [DW_OP_rot] = "rot", + [DW_OP_xderef] = "xderef", + [DW_OP_abs] = "abs", + [DW_OP_and] = "and", + [DW_OP_div] = "div", + [DW_OP_minus] = "minus", + [DW_OP_mod] = "mod", + [DW_OP_mul] = "mul", + [DW_OP_neg] = "neg", + [DW_OP_not] = "not", + [DW_OP_or] = "or", + [DW_OP_plus] = "plus", + [DW_OP_plus_uconst] = "plus_uconst", + [DW_OP_shl] = "shl", + [DW_OP_shr] = "shr", + [DW_OP_shra] = "shra", + [DW_OP_xor] = "xor", + [DW_OP_bra] = "bra", + [DW_OP_eq] = "eq", + [DW_OP_ge] = "ge", + [DW_OP_gt] = "gt", + [DW_OP_le] = "le", + [DW_OP_lt] = "lt", + [DW_OP_ne] = "ne", + [DW_OP_skip] = "skip", + [DW_OP_lit0] = "lit0", + [DW_OP_lit1] = "lit1", + [DW_OP_lit2] = "lit2", + [DW_OP_lit3] = "lit3", + [DW_OP_lit4] = "lit4", + [DW_OP_lit5] = "lit5", + [DW_OP_lit6] = "lit6", + [DW_OP_lit7] = "lit7", + [DW_OP_lit8] = "lit8", + [DW_OP_lit9] = "lit9", + [DW_OP_lit10] = "lit10", + [DW_OP_lit11] = "lit11", + [DW_OP_lit12] = "lit12", + [DW_OP_lit13] = "lit13", + [DW_OP_lit14] = "lit14", + [DW_OP_lit15] = "lit15", + [DW_OP_lit16] = "lit16", + [DW_OP_lit17] = "lit17", + [DW_OP_lit18] = "lit18", + [DW_OP_lit19] = "lit19", + [DW_OP_lit20] = "lit20", + [DW_OP_lit21] = "lit21", + [DW_OP_lit22] = "lit22", + [DW_OP_lit23] = "lit23", + [DW_OP_lit24] = "lit24", + [DW_OP_lit25] = "lit25", + [DW_OP_lit26] = "lit26", + [DW_OP_lit27] = "lit27", + [DW_OP_lit28] = "lit28", + [DW_OP_lit29] = "lit29", + [DW_OP_lit30] = "lit30", + [DW_OP_lit31] = "lit31", + [DW_OP_reg0] = "reg0", + [DW_OP_reg1] = "reg1", + [DW_OP_reg2] = "reg2", + [DW_OP_reg3] = "reg3", + [DW_OP_reg4] = "reg4", + [DW_OP_reg5] = "reg5", + [DW_OP_reg6] = "reg6", + [DW_OP_reg7] = "reg7", + [DW_OP_reg8] = "reg8", + [DW_OP_reg9] = "reg9", + [DW_OP_reg10] = "reg10", + [DW_OP_reg11] = "reg11", + [DW_OP_reg12] = "reg12", + [DW_OP_reg13] = "reg13", + [DW_OP_reg14] = "reg14", + [DW_OP_reg15] = "reg15", + [DW_OP_reg16] = "reg16", + [DW_OP_reg17] = "reg17", + [DW_OP_reg18] = "reg18", + [DW_OP_reg19] = "reg19", + [DW_OP_reg20] = "reg20", + [DW_OP_reg21] = "reg21", + [DW_OP_reg22] = "reg22", + [DW_OP_reg23] = "reg23", + [DW_OP_reg24] = "reg24", + [DW_OP_reg25] = "reg25", + [DW_OP_reg26] = "reg26", + [DW_OP_reg27] = "reg27", + [DW_OP_reg28] = "reg28", + [DW_OP_reg29] = "reg29", + [DW_OP_reg30] = "reg30", + [DW_OP_reg31] = "reg31", + [DW_OP_breg0] = "breg0", + [DW_OP_breg1] = "breg1", + [DW_OP_breg2] = "breg2", + [DW_OP_breg3] = "breg3", + [DW_OP_breg4] = "breg4", + [DW_OP_breg5] = "breg5", + [DW_OP_breg6] = "breg6", + [DW_OP_breg7] = "breg7", + [DW_OP_breg8] = "breg8", + [DW_OP_breg9] = "breg9", + [DW_OP_breg10] = "breg10", + [DW_OP_breg11] = "breg11", + [DW_OP_breg12] = "breg12", + [DW_OP_breg13] = "breg13", + [DW_OP_breg14] = "breg14", + [DW_OP_breg15] = "breg15", + [DW_OP_breg16] = "breg16", + [DW_OP_breg17] = "breg17", + [DW_OP_breg18] = "breg18", + [DW_OP_breg19] = "breg19", + [DW_OP_breg20] = "breg20", + [DW_OP_breg21] = "breg21", + [DW_OP_breg22] = "breg22", + [DW_OP_breg23] = "breg23", + [DW_OP_breg24] = "breg24", + [DW_OP_breg25] = "breg25", + [DW_OP_breg26] = "breg26", + [DW_OP_breg27] = "breg27", + [DW_OP_breg28] = "breg28", + [DW_OP_breg29] = "breg29", + [DW_OP_breg30] = "breg30", + [DW_OP_breg31] = "breg31", + [DW_OP_regx] = "regx", + [DW_OP_fbreg] = "fbreg", + [DW_OP_bregx] = "bregx", + [DW_OP_piece] = "piece", + [DW_OP_deref_size] = "deref_size", + [DW_OP_xderef_size] = "xderef_size", + [DW_OP_nop] = "nop", + [DW_OP_push_object_address] = "push_object_address", + [DW_OP_call2] = "call2", + [DW_OP_call4] = "call4", + [DW_OP_call_ref] = "call_ref", + }; + + Dwarf_Word offset = 0; + while (len-- > 0) + { + size_t op = *data++; + + switch (op) + { + case DW_OP_call_ref: + case DW_OP_addr:; + /* Address operand. */ + Dwarf_Word addr; + if (addrsize == 4) + addr = read_4ubyte_unaligned (dbg, data); + else + { + assert (addrsize == 8); + addr = read_8ubyte_unaligned (dbg, data); + } + data += addrsize; + len -= addrsize; + + printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", (uintmax_t) addr); + offset += 1 + addrsize; + break; + + case DW_OP_deref_size: /* XXX Correct? */ + case DW_OP_xderef_size: /* XXX Correct? */ + case DW_OP_pick: + case DW_OP_const1u: + printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 "\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", *((uint8_t *) data)); + ++data; + --len; + offset += 2; + break; + + case DW_OP_const2u: + printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", read_2ubyte_unaligned (dbg, data)); + len -= 2; + data += 2; + offset += 3; + break; + + case DW_OP_const4u: + printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", read_4ubyte_unaligned (dbg, data)); + len -= 4; + data += 4; + offset += 5; + break; + + case DW_OP_const8u: + printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", read_8ubyte_unaligned (dbg, data)); + len -= 8; + data += 8; + offset += 9; + break; + + case DW_OP_const1s: + printf ("%*s[%4" PRIuMAX "] %s %" PRId8 "\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", *((int8_t *) data)); + ++data; + --len; + offset += 2; + break; + + case DW_OP_const2s: + printf ("%*s[%4" PRIuMAX "] %s %" PRId16 "\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", read_2sbyte_unaligned (dbg, data)); + len -= 2; + data += 2; + offset += 3; + break; + + case DW_OP_const4s: + printf ("%*s[%4" PRIuMAX "] %s %" PRId32 "\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", read_4sbyte_unaligned (dbg, data)); + len -= 4; + data += 4; + offset += 5; + break; + + case DW_OP_const8s: + printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", read_8sbyte_unaligned (dbg, data)); + len -= 8; + data += 8; + offset += 9; + break; + + case DW_OP_piece: /* XXX Correct? */ + case DW_OP_regx: + case DW_OP_plus_uconst: + case DW_OP_constu:; + const unsigned char *start = data; + unsigned int uleb; + get_uleb128 (uleb, data); + printf ("%*s[%4" PRIuMAX "] %s %u\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", uleb); + len -= data - start; + offset += 1 + (data - start); + break; + + case DW_OP_fbreg: + case DW_OP_breg0 ... DW_OP_breg31: + case DW_OP_consts: + start = data; + unsigned int sleb; + get_sleb128 (sleb, data); + printf ("%*s[%4" PRIuMAX "] %s %d\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", sleb); + len -= data - start; + offset += 1 + (data - start); + break; + + case DW_OP_bregx: + start = data; + get_uleb128 (uleb, data); + get_sleb128 (sleb, data); + printf ("%*s[%4" PRIuMAX "] %s %u %d\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", uleb, sleb); + len -= data - start; + offset += 1 + (data - start); + break; + + case DW_OP_call2: + case DW_OP_call4: + case DW_OP_skip: + case DW_OP_bra: + printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???", + (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data))); + len -= 2; + data += 2; + offset += 3; + break; + + default: + /* No Operand. */ + printf ("%*s[%4" PRIuMAX "] %s\n", + indent, "", (uintmax_t) offset, + known[op] ?: "???"); + ++offset; + break; + } + + indent = indentrest; + } +} + + +static void +print_debug_abbrev_section (Ebl *ebl __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + Elf_Scn *scn __attribute__ ((unused)), + GElf_Shdr *shdr, Dwarf *dbg) +{ + printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n" + " [ Code]\n"), + ".debug_abbrev", (uint64_t) shdr->sh_offset); + + Dwarf_Off offset = 0; + while (offset < shdr->sh_size) + { + printf (gettext ("\nAbbreviation section at offset %" PRIu64 ":\n"), + offset); + + while (1) + { + size_t length; + Dwarf_Abbrev abbrev; + + int res = dwarf_offabbrev (dbg, offset, &length, &abbrev); + if (res != 0) + { + if (res < 0) + { + printf (gettext ("\ + *** error while reading abbreviation: %s\n"), + dwarf_errmsg (-1)); + return; + } + + /* This is the NUL byte at the end of the section. */ + ++offset; + break; + } + + /* We know these calls can never fail. */ + unsigned int code = dwarf_getabbrevcode (&abbrev); + unsigned int tag = dwarf_getabbrevtag (&abbrev); + int has_children = dwarf_abbrevhaschildren (&abbrev); + + printf (gettext (" [%5u] offset: %" PRId64 + ", children: %s, tag: %s\n"), + code, (int64_t) offset, + has_children ? gettext ("yes") : gettext ("no"), + dwarf_tag_string (tag)); + + size_t cnt = 0; + unsigned int name; + unsigned int form; + Dwarf_Off enoffset; + while (dwarf_getabbrevattr (&abbrev, cnt, + &name, &form, &enoffset) == 0) + { + printf (" attr: %s, form: %s, offset: %#" PRIx64 "\n", + dwarf_attr_string (name), dwarf_form_string (form), + (uint64_t) enoffset); + + ++cnt; + } + + offset += length; + } + } +} + + +/* Print content of DWARF .debug_aranges section. We fortunately do + not have to know a bit about the structure of the section, libdwarf + takes care of it. */ +static void +print_debug_aranges_section (Ebl *ebl __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + Elf_Scn *scn __attribute__ ((unused)), + GElf_Shdr *shdr, Dwarf *dbg) +{ + Dwarf_Aranges *aranges; + size_t cnt; + if (dwarf_getaranges (dbg, &aranges, &cnt) != 0) + { + error (0, 0, gettext ("cannot get .debug_aranges content: %s"), + dwarf_errmsg (-1)); + return; + } + + printf (ngettext ("\ +\nDWARF section '%s' at offset %#" PRIx64 " contains %zu entry:\n", + "\ +\nDWARF section '%s' at offset %#" PRIx64 " contains %zu entries:\n", + cnt), + ".debug_aranges", (uint64_t) shdr->sh_offset, cnt); + + /* Compute floor(log16(cnt)). */ + size_t tmp = cnt; + int digits = 1; + while (tmp >= 16) + { + ++digits; + tmp >>= 4; + } + + for (size_t n = 0; n < cnt; ++n) + { + Dwarf_Arange *runp = dwarf_onearange (aranges, n); + if (runp == NULL) + { + printf ("cannot get arange %zu: %s\n", n, dwarf_errmsg (-1)); + return; + } + + Dwarf_Addr start; + Dwarf_Word length; + Dwarf_Off offset; + + if (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0) + printf (gettext (" [%*zu] ???\n"), digits, n); + else + printf (gettext (" [%*zu] start: %0#*" PRIx64 + ", length: %5" PRIu64 ", CU DIE offset: %6" + PRId64 "\n"), + digits, n, ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 10 : 18, + (uint64_t) start, (uint64_t) length, (int64_t) offset); + } +} + +/* Print content of DWARF .debug_ranges section. */ +static void +print_debug_ranges_section (Ebl *ebl __attribute__ ((unused)), + GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr, + Dwarf *dbg) +{ + Elf_Data *data = elf_rawdata (scn, NULL); + + if (data == NULL) + { + error (0, 0, gettext ("cannot get .debug_ranges content: %s"), + elf_errmsg (-1)); + return; + } + + printf (gettext ("\ +\nDWARF section '%s' at offset %#" PRIx64 ":\n"), + ".debug_ranges", (uint64_t) shdr->sh_offset); + + size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + + bool first = true; + unsigned char *readp = data->d_buf; + while (readp < (unsigned char *) data->d_buf + data->d_size) + { + ptrdiff_t offset = readp - (unsigned char *) data->d_buf; + + if (data->d_size - offset < address_size * 2) + { + printf (" [%6tx] \n", offset); + break; + } + + Dwarf_Addr begin; + Dwarf_Addr end; + if (address_size == 8) + { + begin = read_8ubyte_unaligned_inc (dbg, readp); + end = read_8ubyte_unaligned_inc (dbg, readp); + } + else + { + begin = read_4ubyte_unaligned_inc (dbg, readp); + end = read_4ubyte_unaligned_inc (dbg, readp); + if (begin == (Dwarf_Addr) (uint32_t) -1) + begin = (Dwarf_Addr) -1l; + } + + if (begin == (Dwarf_Addr) -1l) /* Base address entry. */ + printf (" [%6tx] base address %#0*" PRIxMAX "\n", offset, + 2 + (int) (address_size * 2), (uintmax_t) end); + else if (begin == 0 && end == 0) /* End of list entry. */ + first = true; + else + { + /* We have an address range entry. */ + if (first) /* First address range entry in a list. */ + printf (" [%6tx] %#0*" PRIxMAX "..%#0*" PRIxMAX "\n", offset, + 2 + (int) (address_size * 2), (uintmax_t) begin, + 2 + (int) (address_size * 2), (uintmax_t) end); + else + printf (" %#0*" PRIxMAX "..%#0*" PRIxMAX "\n", + 2 + (int) (address_size * 2), (uintmax_t) begin, + 2 + (int) (address_size * 2), (uintmax_t) end); + + first = false; + } + } +} + + +static void +print_debug_frame_section (Ebl *ebl __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + Elf_Scn *scn __attribute__ ((unused)), + GElf_Shdr *shdr __attribute__ ((unused)), + Dwarf *dbg __attribute__ ((unused))) +{ +} + + +struct attrcb_args +{ + Dwarf *dbg; + int level; + unsigned int addrsize; + Dwarf_Off cu_offset; +}; + + +static int +attr_callback (Dwarf_Attribute *attrp, void *arg) +{ + struct attrcb_args *cbargs = (struct attrcb_args *) arg; + const int level = cbargs->level; + + unsigned int attr = dwarf_whatattr (attrp); + if (unlikely (attr == 0)) + { + error (0, 0, gettext ("cannot get attribute code: %s"), + dwarf_errmsg (-1)); + return DWARF_CB_ABORT; + } + + unsigned int form = dwarf_whatform (attrp); + if (unlikely (form == 0)) + { + error (0, 0, gettext ("cannot get attribute form: %s"), + dwarf_errmsg (-1)); + return DWARF_CB_ABORT; + } + + switch (form) + { + case DW_FORM_addr:; + Dwarf_Addr addr; + if (unlikely (dwarf_formaddr (attrp, &addr) != 0)) + { + attrval_out: + error (0, 0, gettext ("cannot get attribute value: %s"), + dwarf_errmsg (-1)); + return DWARF_CB_ABORT; + } + printf (" %*s%-20s %#0*" PRIxMAX "\n", + (int) (level * 2), "", dwarf_attr_string (attr), + 2 + (int) (cbargs->addrsize * 2), (uintmax_t) addr); + break; + + case DW_FORM_indirect: + case DW_FORM_strp: + case DW_FORM_string:; + const char *str = dwarf_formstring (attrp); + if (unlikely (str == NULL)) + goto attrval_out; + printf (" %*s%-20s \"%s\"\n", + (int) (level * 2), "", dwarf_attr_string (attr), str); + break; + + case DW_FORM_ref_addr: + case DW_FORM_ref_udata: + case DW_FORM_ref8: + case DW_FORM_ref4: + case DW_FORM_ref2: + case DW_FORM_ref1:; + Dwarf_Off ref; + if (unlikely (dwarf_formref (attrp, &ref) != 0)) + goto attrval_out; + + printf (" %*s%-20s [%6" PRIxMAX "]\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (uintmax_t) (ref + cbargs->cu_offset)); + break; + + case DW_FORM_udata: + case DW_FORM_sdata: + case DW_FORM_data8: + case DW_FORM_data4: + case DW_FORM_data2: + case DW_FORM_data1:; + Dwarf_Word num; + if (unlikely (dwarf_formudata (attrp, &num) != 0)) + goto attrval_out; + + const char *valuestr = NULL; + switch (attr) + { + case DW_AT_location: + case DW_AT_data_member_location: + case DW_AT_vtable_elem_location: + case DW_AT_string_length: + case DW_AT_use_location: + case DW_AT_frame_base: + case DW_AT_return_addr: + case DW_AT_static_link: + printf (" %*s%-20s location list [%6" PRIxMAX "]\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (uintmax_t) num); + return DWARF_CB_OK; + + case DW_AT_ranges: + printf (" %*s%-20s range list [%6" PRIxMAX "]\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (uintmax_t) num); + return DWARF_CB_OK; + + case DW_AT_language: + valuestr = dwarf_lang_string (num); + break; + case DW_AT_encoding: + valuestr = dwarf_encoding_string (num); + break; + case DW_AT_accessibility: + valuestr = dwarf_access_string (num); + break; + case DW_AT_visibility: + valuestr = dwarf_visibility_string (num); + break; + case DW_AT_virtuality: + valuestr = dwarf_virtuality_string (num); + break; + case DW_AT_identifier_case: + valuestr = dwarf_identifier_case_string (num); + break; + case DW_AT_calling_convention: + valuestr = dwarf_calling_convention_string (num); + break; + case DW_AT_inline: + valuestr = dwarf_inline_string (num); + break; + case DW_AT_ordering: + valuestr = dwarf_ordering_string (num); + break; + case DW_AT_discr_list: + valuestr = dwarf_discr_list_string (num); + break; + default: + /* Nothing. */ + break; + } + + if (valuestr == NULL) + printf (" %*s%-20s %" PRIuMAX "\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (uintmax_t) num); + else + printf (" %*s%-20s %s (%" PRIuMAX ")\n", + (int) (level * 2), "", dwarf_attr_string (attr), + valuestr, (uintmax_t) num); + break; + + case DW_FORM_flag:; + bool flag; + if (unlikely (dwarf_formflag (attrp, &flag) != 0)) + goto attrval_out; + + printf (" %*s%-20s %s\n", + (int) (level * 2), "", dwarf_attr_string (attr), + nl_langinfo (flag ? YESSTR : NOSTR)); + break; + + case DW_FORM_block4: + case DW_FORM_block2: + case DW_FORM_block1: + case DW_FORM_block:; + Dwarf_Block block; + if (unlikely (dwarf_formblock (attrp, &block) != 0)) + goto attrval_out; + + printf (" %*s%-20s %" PRIxMAX " byte block\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (uintmax_t) block.length); + + switch (attr) + { + case DW_AT_location: + case DW_AT_data_member_location: + case DW_AT_vtable_elem_location: + case DW_AT_string_length: + case DW_AT_use_location: + case DW_AT_frame_base: + case DW_AT_return_addr: + case DW_AT_static_link: + print_ops (cbargs->dbg, 12 + level * 2, 12 + level * 2, + cbargs->addrsize, block.length, block.data); + break; + } + break; + + default: + printf (" %*s%-20s [form: %d] ???\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (int) form); + break; + } + + return DWARF_CB_OK; +} + + +static void +print_debug_info_section (Ebl *ebl __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + Elf_Scn *scn __attribute__ ((unused)), + GElf_Shdr *shdr, Dwarf *dbg) +{ + printf (gettext ("\ +\nDWARF section '%s' at offset %#" PRIx64 ":\n [Offset]\n"), + ".debug_info", (uint64_t) shdr->sh_offset); + + /* If the section is empty we don't have to do anything. */ + if (shdr->sh_size == 0) + return; + + int maxdies = 20; + Dwarf_Die *dies = (Dwarf_Die *) xmalloc (maxdies * sizeof (Dwarf_Die)); + + Dwarf_Off offset = 0; + + /* New compilation unit. */ + size_t cuhl; + //Dwarf_Half version; + Dwarf_Off abbroffset; + uint8_t addrsize; + uint8_t offsize; + Dwarf_Off nextcu; + next_cu: + if (dwarf_nextcu (dbg, offset, &nextcu, &cuhl, &abbroffset, &addrsize, + &offsize) != 0) + goto do_return; + + printf (gettext (" Compilation unit at offset %" PRIu64 ":\n" + " Version: %" PRIu16 ", Abbreviation section offset: %" + PRIu64 ", Address size: %" PRIu8 ", Offset size: %" PRIu8 "\n"), + (uint64_t) offset, /*version*/2, abbroffset, addrsize, offsize); + + + struct attrcb_args args; + args.dbg = dbg; + args.addrsize = addrsize; + args.cu_offset = offset; + + offset += cuhl; + + int level = 0; + + if (unlikely (dwarf_offdie (dbg, offset, &dies[level]) == NULL)) + { + error (0, 0, gettext ("cannot get DIE at offset %" PRIu64 + " in section '%s': %s"), + (uint64_t) offset, ".debug_info", dwarf_errmsg (-1)); + goto do_return; + } + + do + { + offset = dwarf_dieoffset (&dies[level]); + if (offset == ~0ul) + { + error (0, 0, gettext ("cannot get DIE offset: %s"), + dwarf_errmsg (-1)); + goto do_return; + } + + int tag = dwarf_tag (&dies[level]); + if (tag == DW_TAG_invalid) + { + error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64 + " in section '%s': %s"), + (uint64_t) offset, ".debug_info", dwarf_errmsg (-1)); + goto do_return; + } + +#if 1 + const char *tagstr = dwarf_tag_string (tag); +#else + static const char *const lowtags[] = + { + [DW_TAG_array_type] = "array_type", + [DW_TAG_class_type] = "class_type", + [DW_TAG_entry_point] = "entry_point", + [DW_TAG_enumeration_type] = "enumeration_type", + [DW_TAG_formal_parameter] = "formal_parameter", + [DW_TAG_imported_declaration] = "imported_declaration", + [DW_TAG_label] = "label", + [DW_TAG_lexical_block] = "lexical_block", + [DW_TAG_member] = "member", + [DW_TAG_pointer_type] = "pointer_type", + [DW_TAG_reference_type] = "reference_type", + [DW_TAG_compile_unit] = "compile_unit", + [DW_TAG_string_type] = "string_type", + [DW_TAG_structure_type] = "structure_type", + [DW_TAG_subroutine_type] = "subroutine_type", + [DW_TAG_typedef] = "typedef", + [DW_TAG_union_type] = "union_type", + [DW_TAG_unspecified_parameters] = "unspecified_parameters", + [DW_TAG_variant] = "variant", + [DW_TAG_common_block] = "common_block", + [DW_TAG_common_inclusion] = "common_inclusion", + [DW_TAG_inheritance] = "inheritance", + [DW_TAG_inlined_subroutine] = "inlined_subroutine", + [DW_TAG_module] = "module", + [DW_TAG_ptr_to_member_type] = "ptr_to_member_type", + [DW_TAG_set_type] = "set_type", + [DW_TAG_subrange_type] = "subrange_type", + [DW_TAG_with_stmt] = "with_stmt", + [DW_TAG_access_declaration] = "access_declaration", + [DW_TAG_base_type] = "base_type", + [DW_TAG_catch_block] = "catch_block", + [DW_TAG_const_type] = "const_type", + [DW_TAG_constant] = "constant", + [DW_TAG_enumerator] = "enumerator", + [DW_TAG_file_type] = "file_type", + [DW_TAG_friend] = "friend", + [DW_TAG_namelist] = "namelist", + [DW_TAG_namelist_item] = "namelist_item", + [DW_TAG_packed_type] = "packed_type", + [DW_TAG_subprogram] = "subprogram", + [DW_TAG_template_type_param] = "template_type_param", + [DW_TAG_template_value_param] = "template_value_param", + [DW_TAG_thrown_type] = "thrown_type", + [DW_TAG_try_block] = "try_block", + [DW_TAG_variant_part] = "variant_part", + [DW_TAG_variable] = "variable", + [DW_TAG_volatile_type] = "volatile_type" + }; + + const char *tagstr; + switch (tag) + { + case DW_TAG_lo_user: + tagstr = "lo_user"; + break; + + case DW_TAG_MIPS_loop: + tagstr = "MIPS_loop"; + break; + + case DW_TAG_format_label: + tagstr = "format_label"; + break; + + case DW_TAG_function_template: + tagstr = "function_template"; + break; + + case DW_TAG_class_template: + tagstr = "class_template"; + break; + case DW_TAG_hi_user: + tagstr = "hi_user"; + break; + + default: + if (tag < (int) (sizeof (lowtags) / sizeof (lowtags[0]))) + tagstr = lowtags[tag]; + else + tagstr = "???"; + break; + } +#endif + + printf (" [%6" PRIx64 "] %*s%s\n", + (uint64_t) offset, (int) (level * 2), "", tagstr); + + /* Print the attribute values. */ + args.level = level; + (void) dwarf_getattrs (&dies[level], attr_callback, &args, 0); + + /* Make room for the next level's DIE. */ + if (level + 1 == maxdies) + dies = (Dwarf_Die *) xrealloc (dies, + (maxdies += 10) + * sizeof (Dwarf_Die)); + + int res = dwarf_child (&dies[level], &dies[level + 1]); + if (res > 0) + { + while ((res = dwarf_siblingof (&dies[level], &dies[level])) == 1) + if (level-- == 0) + break; + + if (res == -1) + { + error (0, 0, gettext ("cannot get next DIE: %s\n"), + dwarf_errmsg (-1)); + goto do_return; + } + } + else if (unlikely (res < 0)) + { + error (0, 0, gettext ("cannot get next DIE: %s"), + dwarf_errmsg (-1)); + goto do_return; + } + else + ++level; + } + while (level >= 0); + + offset = nextcu; + if (offset != 0) + goto next_cu; + + do_return: + free (dies); +} + + +static void +print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr __attribute__ ((unused)), + Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) +{ + printf (gettext ("\ +\nDWARF section '%s' at offset %#" PRIx64 ":\n"), + ".debug_line", (uint64_t) shdr->sh_offset); + + if (shdr->sh_size == 0) + return; + + /* There is no functionality in libdw to read the information in the + way it is represented here. Hardcode the decoder. */ + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL || data->d_buf == NULL) + { + error (0, 0, gettext ("cannot get line data section data: %s"), + elf_errmsg (-1)); + return; + } + + const unsigned char *linep = (const unsigned char *) data->d_buf; + const unsigned char *lineendp; + + while (linep + < (lineendp = (const unsigned char *) data->d_buf + data->d_size)) + { + size_t start_offset = linep - (const unsigned char *) data->d_buf; + + printf (gettext ("\nTable at offset %Zu:\n"), start_offset); + + Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); + unsigned int length = 4; + if (unlikely (unit_length == 0xffffffff)) + { + if (unlikely (linep + 8 > lineendp)) + { + invalid_data: + error (0, 0, gettext ("invalid data in section [%zu] '%s'"), + elf_ndxscn (scn), ".debug_line"); + return; + } + unit_length = read_8ubyte_unaligned_inc (dbg, linep); + length = 8; + } + + /* Check whether we have enough room in the section. */ + if (unit_length < 2 + length + 5 * 1 + || unlikely (linep + unit_length > lineendp)) + goto invalid_data; + lineendp = linep + unit_length; + + /* The next element of the header is the version identifier. */ + uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep); + + /* Next comes the header length. */ + Dwarf_Word header_length; + if (length == 4) + header_length = read_4ubyte_unaligned_inc (dbg, linep); + else + header_length = read_8ubyte_unaligned_inc (dbg, linep); + //const unsigned char *header_start = linep; + + /* Next the minimum instruction length. */ + uint_fast8_t minimum_instr_len = *linep++; + + /* Then the flag determining the default value of the is_stmt + register. */ + uint_fast8_t default_is_stmt = *linep++; + + /* Now the line base. */ + int_fast8_t line_base = *((const int_fast8_t *) linep); + ++linep; + + /* And the line range. */ + uint_fast8_t line_range = *linep++; + + /* The opcode base. */ + uint_fast8_t opcode_base = *linep++; + + /* Print what we got so far. */ + printf (gettext ("\n" + " Length: %" PRIu64 "\n" + " DWARF version: %" PRIuFAST16 "\n" + " Prologue length: %" PRIu64 "\n" + " Minimum instruction length: %" PRIuFAST8 "\n" + " Initial value if '%s': %" PRIuFAST8 "\n" + " Line base: %" PRIdFAST8 "\n" + " Line range: %" PRIuFAST8 "\n" + " Opcode base: %" PRIuFAST8 "\n" + "\n" + "Opcodes:\n"), + (uint64_t) unit_length, version, (uint64_t) header_length, + minimum_instr_len, "is_stmt", default_is_stmt, line_base, + line_range, opcode_base); + + if (unlikely (linep + opcode_base - 1 >= lineendp)) + goto invalid_data; + int opcode_base_l10 = 1; + unsigned int tmp = opcode_base; + while (tmp > 10) + { + tmp /= 10; + ++opcode_base_l10; + } + const uint8_t *standard_opcode_lengths = linep - 1; + for (uint_fast8_t cnt = 1; cnt < opcode_base; ++cnt) + printf (ngettext (" [%*" PRIuFAST8 "] %hhu argument\n", + " [%*" PRIuFAST8 "] %hhu arguments\n", + (int) linep[cnt - 1]), + opcode_base_l10, cnt, linep[cnt - 1]); + linep += opcode_base - 1; + if (unlikely (linep >= lineendp)) + goto invalid_data; + + puts (gettext ("\nDirectory table:")); + while (*linep != 0) + { + unsigned char *endp = memchr (linep, '\0', lineendp - linep); + if (endp == NULL) + goto invalid_data; + + printf (" %s\n", (char *) linep); + + linep = endp + 1; + } + /* Skip the final NUL byte. */ + ++linep; + + if (unlikely (linep >= lineendp)) + goto invalid_data; + puts (gettext ("\nFile name table:\n" + " Entry Dir Time Size Name")); + for (unsigned int cnt = 1; *linep != 0; ++cnt) + { + /* First comes the file name. */ + char *fname = (char *) linep; + unsigned char *endp = memchr (fname, '\0', lineendp - linep); + if (endp == NULL) + goto invalid_data; + linep = endp + 1; + + /* Then the index. */ + unsigned int diridx; + get_uleb128 (diridx, linep); + + /* Next comes the modification time. */ + unsigned int mtime; + get_uleb128 (mtime, linep); + + /* Finally the length of the file. */ + unsigned int fsize; + get_uleb128 (fsize, linep); + + printf (" %-5u %-5u %-9u %-9u %s\n", + cnt, diridx, mtime, fsize, fname); + } + /* Skip the final NUL byte. */ + ++linep; + + puts (gettext ("\nLine number statements:")); + Dwarf_Word address = 0; + size_t line = 1; + uint_fast8_t is_stmt = default_is_stmt; + + /* Default address value, in case we do not find the CU. */ + size_t address_size + = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8; + + /* Determine the CU this block is for. */ + Dwarf_Off cuoffset; + Dwarf_Off ncuoffset = 0; + size_t hsize; + while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize, + NULL, NULL, NULL) == 0) + { + Dwarf_Die cudie; + if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL) + continue; + Dwarf_Attribute stmt_list; + if (dwarf_attr (&cudie, DW_AT_stmt_list, &stmt_list) == NULL) + continue; + Dwarf_Word lineoff; + if (dwarf_formudata (&stmt_list, &lineoff) != 0) + continue; + if (lineoff == start_offset) + { + /* Found the CU. */ + address_size = cudie.cu->address_size; + break; + } + } + + while (linep < lineendp) + { + unsigned int u128; + int s128; + + /* Read the opcode. */ + unsigned int opcode = *linep++; + + /* Is this a special opcode? */ + if (likely (opcode >= opcode_base)) + { + /* Yes. Handling this is quite easy since the opcode value + is computed with + + opcode = (desired line increment - line_base) + + (line_range * address advance) + opcode_base + */ + int line_increment = (line_base + + (opcode - opcode_base) % line_range); + unsigned int address_increment = (minimum_instr_len + * ((opcode - opcode_base) + / line_range)); + + /* Perform the increments. */ + line += line_increment; + address += address_increment; + + printf (gettext ("\ + special opcode %u: address+%u = %#" PRIx64 ", line%+d = %zu\n"), + opcode, address_increment, (uint64_t) address, + line_increment, line); + } + else if (opcode == 0) + { + /* This an extended opcode. */ + if (unlikely (linep + 2 > lineendp)) + goto invalid_data; + + /* The length. */ + unsigned int len = *linep++; + + if (unlikely (linep + len > lineendp)) + goto invalid_data; + + /* The sub-opcode. */ + opcode = *linep++; + + printf (gettext (" extended opcode %u: "), opcode); + + switch (opcode) + { + case DW_LNE_end_sequence: + puts (gettext ("end of sequence")); + + /* Reset the registers we care about. */ + address = 0; + line = 1; + is_stmt = default_is_stmt; + break; + + case DW_LNE_set_address: + if (address_size == 4) + address = read_4ubyte_unaligned_inc (dbg, linep); + else + address = read_8ubyte_unaligned_inc (dbg, linep); + printf (gettext ("set address to %#" PRIx64 "\n"), + (uint64_t) address); + break; + + case DW_LNE_define_file: + { + char *fname = (char *) linep; + unsigned char *endp = memchr (linep, '\0', + lineendp - linep); + if (endp == NULL) + goto invalid_data; + linep = endp + 1; + + unsigned int diridx; + get_uleb128 (diridx, linep); + Dwarf_Word mtime; + get_uleb128 (mtime, linep); + Dwarf_Word filelength; + get_uleb128 (filelength, linep); + + printf (gettext ("\ +define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"), + diridx, (uint64_t) mtime, (uint64_t) filelength, + fname); + } + break; + + default: + /* Unknown, ignore it. */ + puts (gettext ("unknown opcode")); + linep += len - 1; + break; + } + } + else if (opcode <= DW_LNS_set_epilog_begin) + { + /* This is a known standard opcode. */ + switch (opcode) + { + case DW_LNS_copy: + /* Takes no argument. */ + puts (gettext (" copy")); + break; + + case DW_LNS_advance_pc: + /* Takes one uleb128 parameter which is added to the + address. */ + get_uleb128 (u128, linep); + address += minimum_instr_len * u128; + printf (gettext ("\ + advance address by %u to %#" PRIx64 "\n"), + u128, (uint64_t) address); + break; + + case DW_LNS_advance_line: + /* Takes one sleb128 parameter which is added to the + line. */ + get_sleb128 (s128, linep); + line += s128; + printf (gettext ("\ + advance line by constant %d to %" PRId64 "\n"), + s128, (int64_t) line); + break; + + case DW_LNS_set_file: + /* Takes one uleb128 parameter which is stored in file. */ + get_uleb128 (u128, linep); + printf (gettext (" set file to %" PRIu64 "\n"), + (uint64_t) u128); + break; + + case DW_LNS_set_column: + /* Takes one uleb128 parameter which is stored in column. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + get_uleb128 (u128, linep); + printf (gettext (" set column to %" PRIu64 "\n"), + (uint64_t) u128); + break; + + case DW_LNS_negate_stmt: + /* Takes no argument. */ + is_stmt = 1 - is_stmt; + printf (gettext (" set '%s' to %" PRIuFAST8 "\n"), + "is_stmt", is_stmt); + break; + + case DW_LNS_set_basic_block: + /* Takes no argument. */ + puts (gettext (" set basic block flag")); + break; + + case DW_LNS_const_add_pc: + /* Takes no argument. */ + u128 = (minimum_instr_len + * ((255 - opcode_base) / line_range)); + address += u128; + printf (gettext ("\ + advance address by constant %u to %#" PRIx64 "\n"), + u128, (uint64_t) address); + break; + + case DW_LNS_fixed_advance_pc: + /* Takes one 16 bit parameter which is added to the + address. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + u128 = read_2ubyte_unaligned_inc (dbg, linep); + address += u128; + printf (gettext ("\ + advance address by fixed value %u to %#" PRIx64 "\n"), + u128, (uint64_t) address); + break; + + case DW_LNS_set_prologue_end: + /* Takes no argument. */ + puts (gettext (" set prologue end flag")); + break; + + case DW_LNS_set_epilog_begin: + /* Takes no argument. */ + puts (gettext (" set epilogue begin flag")); + break; + } + } + else + { + /* This is a new opcode the generator but not we know about. + Read the parameters associated with it but then discard + everything. Read all the parameters for this opcode. */ + printf (ngettext (" unknown opcode with %" PRIu8 " parameter:", + " unknown opcode with %" PRIu8 " parameters:", + standard_opcode_lengths[opcode]), + standard_opcode_lengths[opcode]); + for (int n = standard_opcode_lengths[opcode]; n > 0; --n) + { + get_uleb128 (u128, linep); + if (n != standard_opcode_lengths[opcode]) + putc_unlocked (',', stdout); + printf (" %u", u128); + } + + /* Next round, ignore this opcode. */ + continue; + } + } + } + + /* There must only be one data block. */ + assert (elf_getdata (scn, data) == NULL); +} + + +static void +print_debug_loc_section (Ebl *ebl __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + Elf_Scn *scn __attribute__ ((unused)), + GElf_Shdr *shdr, + Dwarf *dbg __attribute__ ((unused))) +{ + Elf_Data *data = elf_rawdata (scn, NULL); + + if (data == NULL) + { + error (0, 0, gettext ("cannot get .debug_loc content: %s"), + elf_errmsg (-1)); + return; + } + + printf (gettext ("\ +\nDWARF section '%s' at offset %#" PRIx64 ":\n"), + ".debug_loc", (uint64_t) shdr->sh_offset); + + size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + + bool first = true; + unsigned char *readp = data->d_buf; + while (readp < (unsigned char *) data->d_buf + data->d_size) + { + ptrdiff_t offset = readp - (unsigned char *) data->d_buf; + + if (data->d_size - offset < address_size * 2) + { + printf (" [%6tx] \n", offset); + break; + } + + Dwarf_Addr begin; + Dwarf_Addr end; + if (address_size == 8) + { + begin = read_8ubyte_unaligned_inc (dbg, readp); + end = read_8ubyte_unaligned_inc (dbg, readp); + } + else + { + begin = read_4ubyte_unaligned_inc (dbg, readp); + end = read_4ubyte_unaligned_inc (dbg, readp); + if (begin == (Dwarf_Addr) (uint32_t) -1) + begin = (Dwarf_Addr) -1l; + } + + if (begin == (Dwarf_Addr) -1l) /* Base address entry. */ + printf (" [%6tx] base address %#0*" PRIxMAX "\n", offset, + 2 + (int) (address_size * 2), (uintmax_t) end); + else if (begin == 0 && end == 0) /* End of list entry. */ + first = true; + else + { + /* We have a location expression entry. */ + uint_fast16_t len = read_2ubyte_unaligned_inc (dbg, readp); + + if (first) /* First entry in a list. */ + printf (" [%6tx] %#0*" PRIxMAX "..%#0*" PRIxMAX, + offset, + 2 + (int) (address_size * 2), (uintmax_t) begin, + 2 + (int) (address_size * 2), (uintmax_t) end); + else + printf (" %#0*" PRIxMAX "..%#0*" PRIxMAX, + 2 + (int) (address_size * 2), (uintmax_t) begin, + 2 + (int) (address_size * 2), (uintmax_t) end); + + print_ops (dbg, 1, 18 + (address_size * 4), + address_size, len, readp); + + first = false; + readp += len; + } + } +} + +struct mac_culist +{ + Dwarf_Die die; + Dwarf_Off offset; + Dwarf_Files *files; + struct mac_culist *next; +}; + + +static int +mac_compare (const void *p1, const void *p2) +{ + struct mac_culist *m1 = (struct mac_culist *) p1; + struct mac_culist *m2 = (struct mac_culist *) p2; + + if (m1->offset < m2->offset) + return -1; + if (m1->offset > m2->offset) + return 1; + return 0; +} + + +static void +print_debug_macinfo_section (Ebl *ebl __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) +{ + printf (gettext ("\ +\nDWARF section '%s' at offset %#" PRIx64 ":\n"), + ".debug_macinfo", (uint64_t) shdr->sh_offset); + putc_unlocked ('\n', stdout); + + /* There is no function in libdw to iterate over the raw content of + the section but it is easy enough to do. */ + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL || data->d_buf == NULL) + { + error (0, 0, gettext ("cannot get macro information section data: %s"), + elf_errmsg (-1)); + return; + } + + /* Get the source file information for all CUs. */ + Dwarf_Off offset; + Dwarf_Off ncu = 0; + size_t hsize; + struct mac_culist *culist = NULL; + size_t nculist = 0; + while (dwarf_nextcu (dbg, offset = ncu, &ncu, &hsize, NULL, NULL, NULL) == 0) + { + Dwarf_Die cudie; + if (dwarf_offdie (dbg, offset + hsize, &cudie) == NULL) + continue; + + Dwarf_Attribute attr; + if (dwarf_attr (&cudie, DW_AT_macro_info, &attr) == NULL) + continue; + + Dwarf_Word macoff; + if (dwarf_formudata (&attr, &macoff) != 0) + continue; + + struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp)); + newp->die = cudie; + newp->offset = macoff; + newp->files = NULL; + newp->next = culist; + culist = newp; + ++nculist; + } + + /* Convert the list into an array for easier consumption. */ + struct mac_culist *cus = (struct mac_culist *) alloca ((nculist + 1) + * sizeof (*cus)); + /* Add sentinel. */ + cus[nculist].offset = data->d_size; + if (nculist > 0) + { + for (size_t cnt = nculist - 1; culist != NULL; --cnt) + { + assert (cnt < nculist); + cus[cnt] = *culist; + culist = culist->next; + } + + /* Sort the array according to the offset in the .debug_macinfo + section. Note we keep the sentinel at the end. */ + qsort (cus, nculist, sizeof (*cus), mac_compare); + } + + const unsigned char *readp = (const unsigned char *) data->d_buf; + const unsigned char *readendp = readp + data->d_size; + int level = 1; + + while (readp < readendp) + { + unsigned int opcode = *readp++; + unsigned int u128; + unsigned int u128_2; + const unsigned char *endp; + + switch (opcode) + { + case DW_MACINFO_define: + case DW_MACINFO_undef: + case DW_MACINFO_vendor_ext: + /* For the first two opcodes the parameters are + line, string + For the latter + number, string. + We can treat these cases together. */ + get_uleb128 (u128, readp); + + endp = memchr (readp, '\0', readendp - readp); + if (endp == NULL) + { + printf (gettext ("\ +%*s*** non-terminated string at end of section"), + level, ""); + return; + } + + if (opcode == DW_MACINFO_define) + printf ("%*s#define %s, line %u\n", + level, "", (char *) readp, u128); + else if (opcode == DW_MACINFO_undef) + printf ("%*s#undef %s, line %u\n", + level, "", (char *) readp, u128); + else + printf (" #vendor-ext %s, number %u\n", (char *) readp, u128); + + readp = endp + 1; + break; + + case DW_MACINFO_start_file: + /* The two parameters are line and file index, in this order. */ + get_uleb128 (u128, readp); + get_uleb128 (u128_2, readp); + + /* Find the CU DIE for this file. */ + size_t macoff = readp - (const unsigned char *) data->d_buf; + const char *fname = "???"; + if (macoff >= cus[0].offset) + { + while (macoff >= cus[1].offset) + ++cus; + + if (cus[0].files == NULL + && dwarf_getsrcfiles (&cus[0].die, &cus[0].files, NULL) != 0) + cus[0].files = (Dwarf_Files *) -1l; + + if (cus[0].files != (Dwarf_Files *) -1l) + fname = (dwarf_filesrc (cus[0].files, u128_2, NULL, NULL) + ?: "???"); + } + + printf ("%*sstart_file %u, [%u] %s\n", + level, "", u128, u128_2, fname); + ++level; + break; + + case DW_MACINFO_end_file: + --level; + printf ("%*send_file\n", level, ""); + /* Nothing more to do. */ + break; + + default: + // XXX gcc seems to generate files with a trailing zero. + if (opcode != 0 || readp != readendp) + printf ("%*s*** invalid opcode %u\n", level, "", opcode); + break; + } + } +} + + +/* Callback for printing global names. */ +static int +print_pubnames (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global, + void *arg) +{ + int *np = (int *) arg; + + printf (gettext (" [%5d] DIE offset: %6" PRId64 + ", CU DIE offset: %6" PRId64 ", name: %s\n"), + (*np)++, global->die_offset, global->cu_offset, global->name); + + return 0; +} + + +/* Print the known exported symbols in the DWARF section '.debug_pubnames'. */ +static void +print_debug_pubnames_section (Ebl *ebl __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + Elf_Scn *scn __attribute__ ((unused)), + GElf_Shdr *shdr, Dwarf *dbg) +{ + printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n"), + ".debug_pubnames", (uint64_t) shdr->sh_offset); + + int n = 0; + (void) dwarf_getpubnames (dbg, print_pubnames, &n, 0); +} + +/* Print the content of the DWARF string section '.debug_str'. */ +static void +print_debug_str_section (Ebl *ebl __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + Elf_Scn *scn __attribute__ ((unused)), + GElf_Shdr *shdr, Dwarf *dbg) +{ + /* Compute floor(log16(shdr->sh_size)). */ + GElf_Addr tmp = shdr->sh_size; + int digits = 1; + while (tmp >= 16) + { + ++digits; + tmp >>= 4; + } + digits = MAX (4, digits); + + printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n" + " %*s String\n"), + ".debug_str", (uint64_t) shdr->sh_offset, + /* TRANS: the debugstr| prefix makes the string unique. */ + digits + 2, sgettext ("debugstr|Offset")); + + Dwarf_Off offset = 0; + while (offset < shdr->sh_size) + { + size_t len; + const char *str = dwarf_getstring (dbg, offset, &len); + if (str == NULL) + { + printf (gettext (" *** error while reading strings: %s\n"), + dwarf_errmsg (-1)); + break; + } + + printf (" [%*" PRIx64 "] \"%s\"\n", digits, (uint64_t) offset, str); + + offset += len + 1; + } +} + + +static void +print_debug (Ebl *ebl, GElf_Ehdr *ehdr) +{ + /* Find the version information sections. For this we have to + search through the section table. */ + Dwarf *dbg; + Elf_Scn *scn; + size_t shstrndx; + + /* Before we start the real work get a debug context descriptor. */ + dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL); + if (dbg == NULL) + { + error (0, 0, gettext ("cannot get debug context descriptor: %s"), + dwarf_errmsg (-1)); + return; + } + + /* Get the section header string table index. */ + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + scn = NULL; + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + /* Handle the section if it is part of the versioning handling. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr != NULL || shdr->sh_type != SHT_PROGBITS) + { + static const struct + { + const char *name; + enum section_e bitmask; + void (*fp) (Ebl *, GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *); + } debug_sections[] = + { +#define NEW_SECTION(name) \ + { ".debug_" #name, section_##name, print_debug_##name##_section } + NEW_SECTION (abbrev), + NEW_SECTION (aranges), + NEW_SECTION (frame), + NEW_SECTION (info), + NEW_SECTION (line), + NEW_SECTION (loc), + NEW_SECTION (pubnames), + NEW_SECTION (str), + NEW_SECTION (macinfo), + NEW_SECTION (ranges), + { ".eh_frame", section_frame, print_debug_frame_section } + }; + const int ndebug_sections = (sizeof (debug_sections) + / sizeof (debug_sections[0])); + const char *name = elf_strptr (ebl->elf, shstrndx, + shdr->sh_name); + int n; + + for (n = 0; n < ndebug_sections; ++n) + if (strcmp (name, debug_sections[n].name) == 0) + { + if (print_debug_sections & debug_sections[n].bitmask) + debug_sections[n].fp (ebl, ehdr, scn, shdr, dbg); + break; + } + } + } + + /* We are done with the DWARF handling. */ + dwarf_end (dbg); +} + + +static void +handle_notes (Ebl *ebl, GElf_Ehdr *ehdr) +{ + int class = gelf_getclass (ebl->elf); + size_t cnt; + + /* We have to look through the program header to find the note + sections. There can be more than one. */ + for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) + { + GElf_Phdr mem; + GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem); + + if (phdr == NULL || phdr->p_type != PT_NOTE) + /* Not what we are looking for. */ + continue; + + printf (gettext ("\ +\nNote segment of %" PRId64 " bytes at offset %#0" PRIx64 ":\n"), + phdr->p_filesz, phdr->p_offset); + + char *notemem = gelf_rawchunk (ebl->elf, phdr->p_offset, phdr->p_filesz); + if (notemem == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get content of note section: %s"), + elf_errmsg (-1)); + + fputs_unlocked (gettext (" Owner Data size Type\n"), stdout); + + + /* Handle the note section content. It consists of one or more + entries each of which consists of five parts: + + - a 32-bit name length + - a 32-bit descriptor length + - a 32-bit type field + - the NUL-terminated name, length as specified in the first field + - the descriptor, length as specified in the second field + + The variable sized fields are padded to 32- or 64-bits + depending on whether the file is a 32- or 64-bit ELF file. + */ + // XXX Which 64-bit archs need 8-byte alignment? x86-64 does not. + size_t align = class == ELFCLASS32 ? 4 : 4; // XXX 8; +#define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1)) + + size_t idx = 0; + while (idx < phdr->p_filesz) + { + /* XXX Handle 64-bit note section entries correctly. */ + struct + { + uint32_t namesz; + uint32_t descsz; + uint32_t type; + char name[0]; + } *noteentry = (__typeof (noteentry)) (notemem + idx); + + if (idx + 12 > phdr->p_filesz + || (idx + 12 + ALIGNED_LEN (noteentry->namesz) + + ALIGNED_LEN (noteentry->descsz) > phdr->p_filesz)) + /* This entry isn't completely contained in the note + section. Ignore it. */ + break; + + char buf[100]; + char buf2[100]; + printf (gettext (" %-13.*s %9" PRId32 " %s\n"), + (int) noteentry->namesz, noteentry->name, + noteentry->descsz, + ehdr->e_type == ET_CORE + ? ebl_core_note_type_name (ebl, noteentry->type, + buf, sizeof (buf)) + : ebl_object_note_type_name (ebl, noteentry->type, + buf2, sizeof (buf2))); + + /* Filter out invalid entries. */ + if (memchr (noteentry->name, '\0', noteentry->namesz) != NULL + /* XXX For now help broken Linux kernels. */ + || 1) + { + if (ehdr->e_type == ET_CORE) + ebl_core_note (ebl, noteentry->name, noteentry->type, + noteentry->descsz, + ¬eentry->name[ALIGNED_LEN (noteentry->namesz)]); + else + ebl_object_note (ebl, noteentry->name, noteentry->type, + noteentry->descsz, + ¬eentry->name[ALIGNED_LEN (noteentry->namesz)]); + } + + /* Move to the next entry. */ + idx += (12 + ALIGNED_LEN (noteentry->namesz) + + ALIGNED_LEN (noteentry->descsz)); + } + + gelf_freechunk (ebl->elf, notemem); + } +} diff --git a/src/sectionhash.c b/src/sectionhash.c new file mode 100644 index 00000000..4641c7cb --- /dev/null +++ b/src/sectionhash.c @@ -0,0 +1,69 @@ +/* Section hash table implementation. + Copyright (C) 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include +#include + + +/* Comparison function for sections. */ +static int +scnhead_compare (struct scnhead *one, struct scnhead *two) +{ + int result = strcmp (one->name, two->name); + + if (result == 0) + { + result = one->type - two->type; + + if (result == 0) + { + GElf_Sxword diff = (SH_FLAGS_IMPORTANT (one->flags) + - SH_FLAGS_IMPORTANT (two->flags)); + result = diff < 0 ? -1 : diff == 0 ? 0 : 1; + + if (result == 0) + { + result = one->entsize - two->entsize; + + if (result == 0) + { + result = (one->grp_signature == NULL + ? (two->grp_signature == NULL ? 0 : -1) + : (two->grp_signature == NULL + ? 1 : strcmp (one->grp_signature, + two->grp_signature))); + + if (result == 0) + result = one->kind - two->kind; + } + } + } + } + + return result; +} + +/* Definitions for the section hash table. */ +#define TYPE struct scnhead * +#define NAME ld_section_tab +#define ITERATE 1 +#define COMPARE(a, b) scnhead_compare (a, b) + +#include "../lib/dynamicsizehash.c" diff --git a/src/sectionhash.h b/src/sectionhash.h new file mode 100644 index 00000000..50bcb9c8 --- /dev/null +++ b/src/sectionhash.h @@ -0,0 +1,23 @@ +/* Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef SECTIONHASH_H +#define SECTIONHASH_H 1 + +/* Definitions for the section hash table. */ +#define TYPE struct scnhead * +#define NAME ld_section_tab +#define ITERATE 1 +#include + +#endif /* sectionhash.h */ diff --git a/src/size.c b/src/size.c new file mode 100644 index 00000000..4dc7baf3 --- /dev/null +++ b/src/size.c @@ -0,0 +1,682 @@ +/* Print size information from ELF file. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Bug report address. */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + + +/* Values for the parameters which have no short form. */ +#define OPT_FORMAT 0x100 +#define OPT_RADIX 0x101 + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { NULL, 0, NULL, 0, N_("Output format:"), 0 }, + { "format", OPT_FORMAT, "FORMAT", 0, + N_("Use the output format FORMAT. FORMAT can be `bsd' or `sysv'. " + "The default is `bsd'"), 0 }, + { NULL, 'A', NULL, 0, N_("Same as `--format=sysv'"), 0 }, + { NULL, 'B', NULL, 0, N_("Same as `--format=bsd'"), 0 }, + { "radix", OPT_RADIX, "RADIX", 0, N_("Use RADIX for printing symbol values"), + 0}, + { NULL, 'd', NULL, 0, N_("Same as `--radix=10'"), 0 }, + { NULL, 'o', NULL, 0, N_("Same as `--radix=8'"), 0 }, + { NULL, 'x', NULL, 0, N_("Same as `--radix=16'"), 0 }, + { NULL, 'f', NULL, 0, + N_("Similar to `--format=sysv' output but in one line"), 0 }, + + { NULL, 0, NULL, 0, N_("Output options:"), 0 }, + { NULL, 'F', NULL, 0, + N_("Print size and permission flags for loadable segments"), 0 }, + { "totals", 't', NULL, 0, N_("Display the total sizes (bsd only)"), 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Short description of program. */ +static const char doc[] = N_("\ +List section sizes of FILEs (a.out by default)."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("[FILE...]"); + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, NULL, NULL +}; + + +/* Print symbols in file named FNAME. */ +static int process_file (const char *fname); + +/* Handle content of archive. */ +static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname); + +/* Handle ELF file. */ +static void handle_elf (Elf *elf, const char *fullname, const char *fname); + +/* Show total size. */ +static void show_bsd_totals (void); + +#define INTERNAL_ERROR(fname) \ + error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"), \ + fname, __LINE__, VERSION, __DATE__, elf_errmsg (-1)) + + +/* User-selectable options. */ + +/* The selected output format. */ +static enum +{ + format_bsd = 0, + format_sysv, + format_sysv_one_line, + format_segments +} format; + +/* Radix for printed numbers. */ +static enum +{ + radix_decimal = 0, + radix_hex, + radix_octal +} radix; + + +/* Mapping of radix and binary class to length. */ +static const int length_map[2][3] = +{ + [ELFCLASS32 - 1] = + { + [radix_hex] = 8, + [radix_decimal] = 10, + [radix_octal] = 11 + }, + [ELFCLASS64 - 1] = + { + [radix_hex] = 16, + [radix_decimal] = 20, + [radix_octal] = 22 + } +}; + +/* True if total sizes should be printed. */ +static bool totals; +/* To print the total sizes in a reasonable format remember the higest + "class" of ELF binaries processed. */ +static int totals_class; + + +int +main (int argc, char *argv[]) +{ + int remaining; + int result = 0; + + /* Make memory leak detection possible. */ + mtrace (); + + /* We use no threads here which can interfere with handling a stream. */ + __fsetlocking (stdin, FSETLOCKING_BYCALLER); + __fsetlocking (stdout, FSETLOCKING_BYCALLER); + __fsetlocking (stderr, FSETLOCKING_BYCALLER); + + /* Set locale. */ + setlocale (LC_ALL, ""); + + /* Make sure the message catalog can be found. */ + bindtextdomain (PACKAGE, LOCALEDIR); + + /* Initialize the message catalog. */ + textdomain (PACKAGE); + + /* Parse and process arguments. */ + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + + /* Tell the library which version we are expecting. */ + elf_version (EV_CURRENT); + + if (remaining == argc) + /* The user didn't specify a name so we use a.out. */ + result = process_file ("a.out"); + else + /* Process all the remaining files. */ + do + result |= process_file (argv[remaining]); + while (++remaining < argc); + + /* Print the total sizes but only if the output format is BSD and at + least one file has been correctly read (i.e., we recognized the + class). */ + if (totals && format == format_bsd && totals_class != 0) + show_bsd_totals (); + + return result; +} + + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) +{ + fprintf (stream, "size (%s) %s\n", PACKAGE_NAME, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Red Hat, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2005"); + fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case 'd': + radix = radix_decimal; + break; + + case 'f': + format = format_sysv_one_line; + break; + + case 'o': + radix = radix_octal; + break; + + case 'x': + radix = radix_hex; + break; + + case 'A': + format = format_sysv; + break; + + case 'B': + format = format_bsd; + break; + + case 'F': + format = format_segments; + break; + + case OPT_FORMAT: + if (strcmp (arg, "bsd") == 0 || strcmp (arg, "berkeley") == 0) + format = format_bsd; + else if (strcmp (arg, "sysv") == 0) + format = format_sysv; + else + error (EXIT_FAILURE, 0, gettext ("Invalid format: %s"), arg); + break; + + case OPT_RADIX: + if (strcmp (arg, "x") == 0 || strcmp (arg, "16") == 0) + radix = radix_hex; + else if (strcmp (arg, "d") == 0 || strcmp (arg, "10") == 0) + radix = radix_decimal; + else if (strcmp (arg, "o") == 0 || strcmp (arg, "8") == 0) + radix = radix_octal; + else + error (EXIT_FAILURE, 0, gettext ("Invalid radix: %s"), arg); + break; + + case 't': + totals = true; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +static int +process_file (const char *fname) +{ + /* Open the file and determine the type. */ + int fd; + Elf *elf; + + /* Open the file. */ + fd = open (fname, O_RDONLY); + if (fd == -1) + { + error (0, errno, gettext ("cannot open '%s"), fname); + return 1; + } + + /* Now get the ELF descriptor. */ + elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + if (elf != NULL) + { + if (elf_kind (elf) == ELF_K_ELF) + { + handle_elf (elf, NULL, fname); + + if (elf_end (elf) != 0) + INTERNAL_ERROR (fname); + + if (close (fd) != 0) + error (EXIT_FAILURE, errno, gettext ("while close '%s'"), fname); + + return 0; + } + else + return handle_ar (fd, elf, NULL, fname); + + /* We cannot handle this type. Close the descriptor anyway. */ + if (elf_end (elf) != 0) + INTERNAL_ERROR (fname); + } + + error (0, 0, gettext ("%s: file format not recognized"), fname); + + return 1; +} + + +/* Print the BSD-style header. This is done exactly once. */ +static void +print_header (Elf *elf) +{ + static int done; + + if (! done) + { + int ddigits = length_map[gelf_getclass (elf) - 1][radix_decimal]; + int xdigits = length_map[gelf_getclass (elf) - 1][radix_hex]; + + printf ("%*s %*s %*s %*s %*s %s\n", + ddigits - 2, sgettext ("bsd|text"), + ddigits - 2, sgettext ("bsd|data"), + ddigits - 2, sgettext ("bsd|bss"), + ddigits - 2, sgettext ("bsd|dec"), + xdigits - 2, sgettext ("bsd|hex"), + sgettext ("bsd|filename")); + + done = 1; + } +} + + +static int +handle_ar (int fd, Elf *elf, const char *prefix, const char *fname) +{ + Elf *subelf; + Elf_Cmd cmd = ELF_C_READ_MMAP; + size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); + size_t fname_len = strlen (fname) + 1; + char new_prefix[prefix_len + 1 + fname_len]; + int result = 0; + char *cp = new_prefix; + + /* Create the full name of the file. */ + if (prefix != NULL) + { + cp = mempcpy (cp, prefix, prefix_len); + *cp++ = ':'; + } + memcpy (cp, fname, fname_len); + + /* Process all the files contained in the archive. */ + while ((subelf = elf_begin (fd, cmd, elf)) != NULL) + { + /* The the header for this element. */ + Elf_Arhdr *arhdr = elf_getarhdr (subelf); + + if (elf_kind (subelf) == ELF_K_ELF) + handle_elf (subelf, new_prefix, arhdr->ar_name); + else if (elf_kind (subelf) == ELF_K_AR) + result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name); + /* else signal error??? */ + + /* Get next archive element. */ + cmd = elf_next (subelf); + if (elf_end (subelf) != 0) + INTERNAL_ERROR (fname); + } + + if (elf_end (elf) != 0) + INTERNAL_ERROR (fname); + + if (close (fd) != 0) + error (EXIT_FAILURE, errno, gettext ("while closing `%s'"), fname); + + return result; +} + + +/* Show sizes in SysV format. */ +static void +show_sysv (Elf *elf, const char *prefix, const char *fname, + const char *fullname) +{ + size_t shstrndx; + Elf_Scn *scn = NULL; + GElf_Shdr shdr_mem; + int maxlen = 10; + int digits = length_map[gelf_getclass (elf) - 1][radix]; + const char *fmtstr; + GElf_Off total = 0; + + /* Get the section header string table index. */ + if (elf_getshstrndx (elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + /* First round over the sections: determine the longest section name. */ + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr == NULL) + INTERNAL_ERROR (fullname); + + /* Ignore all sections which are not used at runtime. */ + if ((shdr->sh_flags & SHF_ALLOC) != 0) + maxlen = MAX (maxlen, + (int) strlen (elf_strptr (elf, shstrndx, + shdr->sh_name))); + } + + fputs_unlocked (fname, stdout); + if (prefix != NULL) + printf (gettext (" (ex %s)"), prefix); + printf (":\n%-*s %*s %*s\n", + maxlen, sgettext ("sysv|section"), + digits - 2, sgettext ("sysv|size"), + digits, sgettext ("sysv|addr")); + + if (radix == radix_hex) + fmtstr = "%-*s %*" PRIx64 " %*" PRIx64 "\n"; + else if (radix == radix_decimal) + fmtstr = "%-*s %*" PRId64 " %*" PRId64 "\n"; + else + fmtstr = "%-*s %*" PRIo64 " %*" PRIo64 "\n"; + + /* Iterate over all sections. */ + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + /* Ignore all sections which are not used at runtime. */ + if ((shdr->sh_flags & SHF_ALLOC) != 0) + { + printf (fmtstr, + maxlen, elf_strptr (elf, shstrndx, shdr->sh_name), + digits - 2, shdr->sh_size, + digits, shdr->sh_addr); + + total += shdr->sh_size; + } + } + + if (radix == radix_hex) + printf ("%-*s %*" PRIx64 "\n\n\n", maxlen, sgettext ("sysv|Total"), + digits - 2, total); + else if (radix == radix_decimal) + printf ("%-*s %*" PRId64 "\n\n\n", maxlen, sgettext ("sysv|Total"), + digits - 2, total); + else + printf ("%-*s %*" PRIo64 "\n\n\n", maxlen, sgettext ("sysv|Total"), + digits - 2, total); +} + + +/* Show sizes in SysV format in one line. */ +static void +show_sysv_one_line (Elf *elf) +{ + size_t shstrndx; + Elf_Scn *scn = NULL; + GElf_Shdr shdr_mem; + const char *fmtstr; + GElf_Off total = 0; + int first = 1; + + /* Get the section header string table index. */ + if (elf_getshstrndx (elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + if (radix == radix_hex) + fmtstr = "%" PRIx64 "(%s)"; + else if (radix == radix_decimal) + fmtstr = "%" PRId64 "(%s)"; + else + fmtstr = "%" PRIo64 "(%s)"; + + /* Iterate over all sections. */ + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + /* Ignore all sections which are not used at runtime. */ + if ((shdr->sh_flags & SHF_ALLOC) == 0) + continue; + + if (! first) + fputs_unlocked (" + ", stdout); + first = 0; + + printf (fmtstr, shdr->sh_size, + elf_strptr (elf, shstrndx, shdr->sh_name)); + + total += shdr->sh_size; + } + + if (radix == radix_hex) + printf (" = %#" PRIx64 "\n", total); + else if (radix == radix_decimal) + printf (" = %" PRId64 "\n", total); + else + printf (" = %" PRIo64 "\n", total); +} + + +/* Variables to add up the sizes of all files. */ +static uintmax_t total_textsize; +static uintmax_t total_datasize; +static uintmax_t total_bsssize; + + +/* Show sizes in BSD format. */ +static void +show_bsd (Elf *elf, const char *prefix, const char *fname, + const char *fullname) +{ + Elf_Scn *scn = NULL; + GElf_Shdr shdr_mem; + GElf_Off textsize = 0; + GElf_Off datasize = 0; + GElf_Off bsssize = 0; + int ddigits = length_map[gelf_getclass (elf) - 1][radix_decimal]; + int xdigits = length_map[gelf_getclass (elf) - 1][radix_hex]; + + /* Iterate over all sections. */ + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr == NULL) + INTERNAL_ERROR (fullname); + + /* Ignore all sections which are not marked as loaded. */ + if ((shdr->sh_flags & SHF_ALLOC) == 0) + continue; + + if ((shdr->sh_flags & SHF_WRITE) == 0) + textsize += shdr->sh_size; + else if (shdr->sh_type == SHT_NOBITS) + bsssize += shdr->sh_size; + else + datasize += shdr->sh_size; + } + + printf ("%*" PRId64 " %*" PRId64 " %*" PRId64 " %*" PRId64 " %*" + PRIx64 " %s", + ddigits - 2, textsize, + ddigits - 2, datasize, + ddigits - 2, bsssize, + ddigits - 2, textsize + datasize + bsssize, + xdigits - 2, textsize + datasize + bsssize, + fname); + if (prefix != NULL) + printf (gettext (" (ex %s)"), prefix); + fputs_unlocked ("\n", stdout); + + total_textsize += textsize; + total_datasize += datasize; + total_bsssize += bsssize; + + totals_class = MAX (totals_class, gelf_getclass (elf)); +} + + +/* Show total size. */ +static void +show_bsd_totals (void) +{ + int ddigits = length_map[totals_class - 1][radix_decimal]; + int xdigits = length_map[totals_class - 1][radix_hex]; + + printf ("%*" PRIuMAX " %*" PRIuMAX " %*" PRIuMAX " %*" PRIuMAX " %*" + PRIxMAX " %s", + ddigits - 2, total_textsize, + ddigits - 2, total_datasize, + ddigits - 2, total_bsssize, + ddigits - 2, total_textsize + total_datasize + total_bsssize, + xdigits - 2, total_textsize + total_datasize + total_bsssize, + gettext ("(TOTALS)\n")); +} + + +/* Show size and permission of loadable segments. */ +static void +show_segments (Elf *elf, const char *fullname) +{ + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + size_t cnt; + GElf_Off total = 0; + int first = 1; + + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + INTERNAL_ERROR (fullname); + + for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr; + + phdr = gelf_getphdr (elf, cnt, &phdr_mem); + if (phdr == NULL) + INTERNAL_ERROR (fullname); + + if (phdr->p_type != PT_LOAD) + /* Only load segments. */ + continue; + + if (! first) + fputs_unlocked (" + ", stdout); + first = 0; + + printf (radix == radix_hex ? "%" PRIx64 "(%c%c%c)" + : (radix == radix_decimal ? "%" PRId64 "(%c%c%c)" + : "%" PRIo64 "(%c%c%c)"), + phdr->p_memsz, + (phdr->p_flags & PF_R) == 0 ? '-' : 'r', + (phdr->p_flags & PF_W) == 0 ? '-' : 'w', + (phdr->p_flags & PF_X) == 0 ? '-' : 'x'); + + total += phdr->p_memsz; + } + + if (radix == radix_hex) + printf (" = %#" PRIx64 "\n", total); + else if (radix == radix_decimal) + printf (" = %" PRId64 "\n", total); + else + printf (" = %" PRIo64 "\n", total); +} + + +static void +handle_elf (Elf *elf, const char *prefix, const char *fname) +{ + size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); + size_t fname_len = strlen (fname) + 1; + char fullname[prefix_len + 1 + fname_len]; + char *cp = fullname; + + /* Create the full name of the file. */ + if (prefix != NULL) + { + cp = mempcpy (cp, prefix, prefix_len); + *cp++ = ':'; + } + memcpy (cp, fname, fname_len); + + if (format == format_sysv) + show_sysv (elf, prefix, fname, fullname); + else if (format == format_sysv_one_line) + show_sysv_one_line (elf); + else if (format == format_segments) + show_segments (elf, fullname); + else + { + print_header (elf); + + show_bsd (elf, prefix, fname, fullname); + } +} diff --git a/src/strip.c b/src/strip.c new file mode 100644 index 00000000..214513c4 --- /dev/null +++ b/src/strip.c @@ -0,0 +1,1750 @@ +/* Discard section not used at runtime from object files. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Bug report address. */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + + +/* Values for the parameters which have no short form. */ +#define OPT_REMOVE_COMMENT 0x100 +#define OPT_PERMISSIVE 0x101 + + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { NULL, 0, NULL, 0, N_("Output selection:"), 0 }, + { NULL, 'o', "FILE", 0, N_("Place stripped output into FILE"), 0 }, + { NULL, 'f', "FILE", 0, N_("Extract the removed sections into FILE"), 0 }, + { NULL, 'F', "FILE", 0, N_("Embed name FILE instead of -f argument"), 0 }, + + { NULL, 0, NULL, 0, N_("Output options:"), 0 }, + { "strip-debug", 'g', NULL, 0, N_("Remove all debugging symbols"), 0 }, + { "preserve-dates", 'p', NULL, 0, + N_("Copy modified/access timestamps to the output"), 0 }, + { "remove-comment", OPT_REMOVE_COMMENT, NULL, 0, + N_("Remove .comment section"), 0 }, + { "permissive", OPT_PERMISSIVE, NULL, 0, + N_("Relax a few rules to handle slightly broken ELF files"), 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Short description of program. */ +static const char doc[] = N_("Discard symbols from object files."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("[FILE...]"); + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, NULL, NULL +}; + + +/* Print symbols in file named FNAME. */ +static int process_file (const char *fname); + +/* Handle one ELF file. */ +static int handle_elf (int fd, Elf *elf, const char *prefix, + const char *fname, mode_t mode, struct timeval tvp[2]); + +/* Handle all files contained in the archive. */ +static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, + struct timeval tvp[2]); + +#define INTERNAL_ERROR(fname) \ + error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"), \ + fname, __LINE__, VERSION, __DATE__, elf_errmsg (-1)) + + +/* Name of the output file. */ +static const char *output_fname; + +/* Name of the debug output file. */ +static const char *debug_fname; + +/* Name to pretend the debug output file has. */ +static const char *debug_fname_embed; + +/* If true output files shall have same date as the input file. */ +static bool preserve_dates; + +/* If true .comment sections will be removed. */ +static bool remove_comment; + +/* If true remove all debug sections. */ +static bool remove_debug; + +/* If true relax some ELF rules for input files. */ +static bool permissive; + + +int +main (int argc, char *argv[]) +{ + int remaining; + int result = 0; + + /* Make memory leak detection possible. */ + mtrace (); + + /* We use no threads here which can interfere with handling a stream. */ + __fsetlocking (stdin, FSETLOCKING_BYCALLER); + __fsetlocking (stdout, FSETLOCKING_BYCALLER); + __fsetlocking (stderr, FSETLOCKING_BYCALLER); + + /* Set locale. */ + setlocale (LC_ALL, ""); + + /* Make sure the message catalog can be found. */ + bindtextdomain (PACKAGE, LOCALEDIR); + + /* Initialize the message catalog. */ + textdomain (PACKAGE); + + /* Parse and process arguments. */ + if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0) + return EXIT_FAILURE; + + /* Tell the library which version we are expecting. */ + elf_version (EV_CURRENT); + + if (remaining == argc) + /* The user didn't specify a name so we use a.out. */ + result = process_file ("a.out"); + else + { + /* If we have seen the '-o' or '-f' option there must be exactly one + input file. */ + if ((output_fname != NULL || debug_fname != NULL) + && remaining + 1 < argc) + error (EXIT_FAILURE, 0, gettext ("\ +Only one input file allowed together with '-o' and '-f'")); + + /* Process all the remaining files. */ + do + result |= process_file (argv[remaining]); + while (++remaining < argc); + } + + return result; +} + + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) +{ + fprintf (stream, "strip (%s) %s\n", PACKAGE_NAME, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Red Hat, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2005"); + fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case 'f': + if (debug_fname != NULL) + { + error (0, 0, gettext ("-f option specified twice")); + return EINVAL; + } + debug_fname = arg; + break; + + case 'F': + if (debug_fname_embed != NULL) + { + error (0, 0, gettext ("-F option specified twice")); + return EINVAL; + } + debug_fname_embed = arg; + break; + + case 'o': + if (output_fname != NULL) + { + error (0, 0, gettext ("-o option specified twice")); + return EINVAL; + } + output_fname = arg; + break; + + case 'p': + preserve_dates = true; + break; + + case OPT_REMOVE_COMMENT: + remove_comment = true; + break; + + case 'g': + remove_debug = true; + break; + + case OPT_PERMISSIVE: + permissive = true; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +static int +process_file (const char *fname) +{ + /* If we have to preserve the modify and access timestamps get them + now. We cannot use fstat() after opening the file since the open + would change the access time. */ + struct stat64 pre_st; + struct timeval tv[2]; + again: + if (preserve_dates) + { + if (stat64 (fname, &pre_st) != 0) + { + error (0, errno, gettext ("cannot stat input file \"%s\""), fname); + return 1; + } + + /* If we have to preserve the timestamp, we need it in the + format utimes() understands. */ + TIMESPEC_TO_TIMEVAL (&tv[0], &pre_st.st_atim); + TIMESPEC_TO_TIMEVAL (&tv[1], &pre_st.st_mtim); + } + + /* Open the file. */ + int fd = open (fname, O_RDWR); + if (fd == -1) + { + error (0, errno, gettext ("while opening \"%s\""), fname); + return 1; + } + + /* We always use fstat() even if we called stat() before. This is + done to make sure the information returned by stat() is for the + same file. */ + struct stat64 st; + if (fstat64 (fd, &st) != 0) + { + error (0, errno, gettext ("cannot stat input file \"%s\""), fname); + return 1; + } + /* Paranoid mode on. */ + if (preserve_dates + && (st.st_ino != pre_st.st_ino || st.st_dev != pre_st.st_dev)) + { + /* We detected a race. Try again. */ + close (fd); + goto again; + } + + /* Now get the ELF descriptor. */ + Elf *elf = elf_begin (fd, ELF_C_RDWR, NULL); + int result; + switch (elf_kind (elf)) + { + case ELF_K_ELF: + result = handle_elf (fd, elf, NULL, fname, st.st_mode & ACCESSPERMS, + preserve_dates ? tv : NULL); + break; + + case ELF_K_AR: + /* It is not possible to strip the content of an archive direct + the output to a specific file. */ + if (unlikely (output_fname != NULL)) + { + error (0, 0, gettext ("%s: cannot use -o when stripping archive"), + fname); + result = 1; + } + else + result = handle_ar (fd, elf, NULL, fname, preserve_dates ? tv : NULL); + break; + + default: + error (0, 0, gettext ("%s: File format not recognized"), fname); + result = 1; + break; + } + + if (unlikely (elf_end (elf) != 0)) + INTERNAL_ERROR (fname); + + close (fd); + + return result; +} + + +/* Maximum size of array allocated on stack. */ +#define MAX_STACK_ALLOC (400 * 1024) + +static int +handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, + mode_t mode, struct timeval tvp[2]) +{ + size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); + size_t fname_len = strlen (fname) + 1; + char *fullname = alloca (prefix_len + 1 + fname_len); + char *cp = fullname; + Elf *newelf; + Elf *debugelf = NULL; + char *tmp_debug_fname = NULL; + int result = 0; + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + size_t shstrndx; + size_t shnum; + struct shdr_info + { + Elf_Scn *scn; + GElf_Shdr shdr; + Elf_Data *data; + const char *name; + Elf32_Word idx; /* Index in new file. */ + Elf32_Word old_sh_link; /* Original value of shdr.sh_link. */ + Elf32_Word symtab_idx; + Elf32_Word version_idx; + Elf32_Word group_idx; + Elf32_Word group_cnt; + Elf_Scn *newscn; + struct Ebl_Strent *se; + Elf32_Word *newsymidx; + } *shdr_info = NULL; + Elf_Scn *scn; + size_t cnt; + size_t idx; + bool changes; + GElf_Ehdr newehdr_mem; + GElf_Ehdr *newehdr; + GElf_Ehdr debugehdr_mem; + GElf_Ehdr *debugehdr; + struct Ebl_Strtab *shst = NULL; + Elf_Data debuglink_crc_data; + bool any_symtab_changes = false; + Elf_Data *shstrtab_data = NULL; + + /* Create the full name of the file. */ + if (prefix != NULL) + { + cp = mempcpy (cp, prefix, prefix_len); + *cp++ = ':'; + } + memcpy (cp, fname, fname_len); + + /* If we are not replacing the input file open a new file here. */ + if (output_fname != NULL) + { + fd = open (output_fname, O_RDWR | O_CREAT, mode); + if (unlikely (fd == -1)) + { + error (0, errno, gettext ("cannot open '%s'"), output_fname); + return 1; + } + } + + int debug_fd = -1; + + /* Get the EBL handling. The -g option is currently the only reason + we need EBL so dont open the backend unless necessary. */ + Ebl *ebl = NULL; + if (remove_debug) + { + ebl = ebl_openbackend (elf); + if (ebl == NULL) + { + error (0, errno, gettext ("cannot open EBL backend")); + result = 1; + goto fail; + } + } + + /* Open the additional file the debug information will be stored in. */ + if (debug_fname != NULL) + { + /* Create a temporary file name. We do not want to overwrite + the debug file if the file would not contain any + information. */ + size_t debug_fname_len = strlen (debug_fname); + tmp_debug_fname = (char *) alloca (debug_fname_len + sizeof (".XXXXXX")); + strcpy (mempcpy (tmp_debug_fname, debug_fname, debug_fname_len), + ".XXXXXX"); + + debug_fd = mkstemp (tmp_debug_fname); + if (unlikely (debug_fd == -1)) + { + error (0, errno, gettext ("cannot open '%s'"), debug_fname); + result = 1; + goto fail; + } + } + + /* Get the information from the old file. */ + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + INTERNAL_ERROR (fname); + + /* Get the section header string table index. */ + if (unlikely (elf_getshstrndx (elf, &shstrndx) < 0)) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + /* We now create a new ELF descriptor for the same file. We + construct it almost exactly in the same way with some information + dropped. */ + if (output_fname != NULL) + newelf = elf_begin (fd, ELF_C_WRITE_MMAP, NULL); + else + newelf = elf_clone (elf, ELF_C_EMPTY); + + if (unlikely (gelf_newehdr (newelf, gelf_getclass (elf)) == 0) + || (ehdr->e_type != ET_REL + && unlikely (gelf_newphdr (newelf, ehdr->e_phnum) == 0))) + { + error (0, 0, gettext ("cannot create new file '%s': %s"), + output_fname, elf_errmsg (-1)); + goto fail; + } + + /* Copy over the old program header if needed. */ + if (ehdr->e_type != ET_REL) + for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr; + + phdr = gelf_getphdr (elf, cnt, &phdr_mem); + if (phdr == NULL + || unlikely (gelf_update_phdr (newelf, cnt, phdr) == 0)) + INTERNAL_ERROR (fname); + } + + if (debug_fname != NULL) + { + /* Also create an ELF descriptor for the debug file */ + debugelf = elf_begin (debug_fd, ELF_C_WRITE_MMAP, NULL); + if (unlikely (gelf_newehdr (debugelf, gelf_getclass (elf)) == 0) + || (ehdr->e_type != ET_REL + && unlikely (gelf_newphdr (debugelf, ehdr->e_phnum) == 0))) + { + error (0, 0, gettext ("cannot create new file '%s': %s"), + debug_fname, elf_errmsg (-1)); + goto fail_close; + } + + /* Copy over the old program header if needed. */ + if (ehdr->e_type != ET_REL) + for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr; + + phdr = gelf_getphdr (elf, cnt, &phdr_mem); + if (phdr == NULL + || unlikely (gelf_update_phdr (debugelf, cnt, phdr) == 0)) + INTERNAL_ERROR (fname); + } + } + + /* Number of sections. */ + if (unlikely (elf_getshnum (elf, &shnum) < 0)) + { + error (0, 0, gettext ("cannot determine number of sections: %s"), + elf_errmsg (-1)); + goto fail_close; + } + + /* Storage for section information. We leave room for two more + entries since we unconditionally create a section header string + table. Maybe some weird tool created an ELF file without one. + The other one is used for the debug link section. */ + if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC) + shdr_info = (struct shdr_info *) xcalloc (shnum + 2, + sizeof (struct shdr_info)); + else + { + shdr_info = (struct shdr_info *) alloca ((shnum + 2) + * sizeof (struct shdr_info)); + memset (shdr_info, '\0', (shnum + 2) * sizeof (struct shdr_info)); + } + + /* Prepare section information data structure. */ + scn = NULL; + cnt = 1; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + /* This should always be true (i.e., there should not be any + holes in the numbering). */ + assert (elf_ndxscn (scn) == cnt); + + shdr_info[cnt].scn = scn; + + /* Get the header. */ + if (gelf_getshdr (scn, &shdr_info[cnt].shdr) == NULL) + INTERNAL_ERROR (fname); + + /* Get the name of the section. */ + shdr_info[cnt].name = elf_strptr (elf, shstrndx, + shdr_info[cnt].shdr.sh_name); + if (shdr_info[cnt].name == NULL) + { + error (0, 0, gettext ("illformed file '%s'"), fname); + goto fail_close; + } + + /* Mark them as present but not yet investigated. */ + shdr_info[cnt].idx = 1; + + /* Remember the shdr.sh_link value. */ + shdr_info[cnt].old_sh_link = shdr_info[cnt].shdr.sh_link; + + /* Sections in files other than relocatable object files which + are not loaded can be freely moved by us. In relocatable + object files everything can be moved. */ + if (ehdr->e_type == ET_REL + || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0) + shdr_info[cnt].shdr.sh_offset = 0; + + /* If this is an extended section index table store an + appropriate reference. */ + if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX)) + { + assert (shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx == 0); + shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx = cnt; + } + else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GROUP)) + { + Elf32_Word *grpref; + size_t inner; + + /* Cross-reference the sections contained in the section + group. */ + shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL); + if (shdr_info[cnt].data == NULL) + INTERNAL_ERROR (fname); + + /* XXX Fix for unaligned access. */ + grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; + for (inner = 1; + inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); + ++inner) + shdr_info[grpref[inner]].group_idx = cnt; + + if (inner == 1 || (inner == 2 && (grpref[0] & GRP_COMDAT) == 0)) + /* If the section group contains only one element and this + is n COMDAT section we can drop it right away. */ + shdr_info[cnt].idx = 0; + else + shdr_info[cnt].group_cnt = inner - 1; + } + else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym)) + { + assert (shdr_info[shdr_info[cnt].shdr.sh_link].version_idx == 0); + shdr_info[shdr_info[cnt].shdr.sh_link].version_idx = cnt; + } + + /* If this section is part of a group make sure it is not + discarded right away. */ + if ((shdr_info[cnt].shdr.sh_flags & SHF_GROUP) != 0) + { + assert (shdr_info[cnt].group_idx != 0); + + if (shdr_info[shdr_info[cnt].group_idx].idx == 0) + { + /* The section group section will be removed. */ + shdr_info[cnt].group_idx = 0; + shdr_info[cnt].shdr.sh_flags &= ~SHF_GROUP; + } + } + + /* Increment the counter. */ + ++cnt; + } + + /* Now determine which sections can go away. The general rule is that + all sections which are not used at runtime are stripped out. But + there are a few exceptions: + + - special sections named ".comment" and ".note" are kept + - OS or architecture specific sections are kept since we might not + know how to handle them + - if a section is referred to from a section which is not removed + in the sh_link or sh_info element it cannot be removed either + */ + for (cnt = 1; cnt < shnum; ++cnt) + /* Check whether the section can be removed. */ + if (ebl_section_strip_p (ebl, ehdr, &shdr_info[cnt].shdr, + shdr_info[cnt].name, remove_comment, + remove_debug)) + { + /* For now assume this section will be removed. */ + shdr_info[cnt].idx = 0; + + idx = shdr_info[cnt].group_idx; + while (idx != 0) + { + /* If the references section group is a normal section + group and has one element remaining, or if it is an + empty COMDAT section group it is removed. */ + bool is_comdat; + + /* The section group data is already loaded. */ + assert (shdr_info[idx].data != NULL); + + is_comdat = (((Elf32_Word *) shdr_info[idx].data->d_buf)[0] + & GRP_COMDAT) != 0; + + --shdr_info[idx].group_cnt; + if ((!is_comdat && shdr_info[idx].group_cnt == 1) + || (is_comdat && shdr_info[idx].group_cnt == 0)) + { + shdr_info[idx].idx = 0; + /* Continue recursively. */ + idx = shdr_info[idx].group_idx; + } + else + break; + } + } + + /* Mark the SHT_NULL section as handled. */ + shdr_info[0].idx = 2; + + + /* Handle exceptions: section groups and cross-references. We might + have to repeat this a few times since the resetting of the flag + might propagate. */ + do + { + changes = false; + + for (cnt = 1; cnt < shnum; ++cnt) + { + if (shdr_info[cnt].idx == 0) + { + /* If a relocation section is marked as being removed make + sure the section it is relocating is removed, too. */ + if ((shdr_info[cnt].shdr.sh_type == SHT_REL + || shdr_info[cnt].shdr.sh_type == SHT_RELA) + && shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0) + shdr_info[cnt].idx = 1; + } + + if (shdr_info[cnt].idx == 1) + { + /* The content of symbol tables we don't remove must not + reference any section which we do remove. Otherwise + we cannot remove the section. */ + if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM + || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) + { + Elf_Data *symdata; + Elf_Data *xndxdata; + size_t elsize; + + /* Make sure the data is loaded. */ + if (shdr_info[cnt].data == NULL) + { + shdr_info[cnt].data + = elf_getdata (shdr_info[cnt].scn, NULL); + if (shdr_info[cnt].data == NULL) + INTERNAL_ERROR (fname); + } + symdata = shdr_info[cnt].data; + + /* If there is an extended section index table load it + as well. */ + if (shdr_info[cnt].symtab_idx != 0 + && shdr_info[shdr_info[cnt].symtab_idx].data == NULL) + { + assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB); + + shdr_info[shdr_info[cnt].symtab_idx].data + = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn, + NULL); + if (shdr_info[shdr_info[cnt].symtab_idx].data == NULL) + INTERNAL_ERROR (fname); + } + xndxdata = shdr_info[shdr_info[cnt].symtab_idx].data; + + /* Go through all symbols and make sure the section they + reference is not removed. */ + elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); + + for (size_t inner = 0; + inner < shdr_info[cnt].data->d_size / elsize; + ++inner) + { + GElf_Sym sym_mem; + Elf32_Word xndx; + GElf_Sym *sym; + size_t scnidx; + + sym = gelf_getsymshndx (symdata, xndxdata, inner, + &sym_mem, &xndx); + if (sym == NULL) + INTERNAL_ERROR (fname); + + scnidx = sym->st_shndx; + if (scnidx == SHN_UNDEF || scnidx >= shnum + || (scnidx >= SHN_LORESERVE + && scnidx <= SHN_HIRESERVE + && scnidx != SHN_XINDEX) + /* Don't count in the section symbols. */ + || GELF_ST_TYPE (sym->st_info) == STT_SECTION) + /* This is no section index, leave it alone. */ + continue; + else if (scnidx == SHN_XINDEX) + scnidx = xndx; + + if (shdr_info[scnidx].idx == 0) + { + /* Mark this section as used. */ + shdr_info[scnidx].idx = 1; + changes |= scnidx < cnt; + } + } + } + + /* Cross referencing happens: + - for the cases the ELF specification says. That are + + SHT_DYNAMIC in sh_link to string table + + SHT_HASH in sh_link to symbol table + + SHT_REL and SHT_RELA in sh_link to symbol table + + SHT_SYMTAB and SHT_DYNSYM in sh_link to string table + + SHT_GROUP in sh_link to symbol table + + SHT_SYMTAB_SHNDX in sh_link to symbol table + Other (OS or architecture-specific) sections might as + well use this field so we process it unconditionally. + - references inside section groups + - specially marked references in sh_info if the SHF_INFO_LINK + flag is set + */ + + if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0) + { + shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1; + changes |= shdr_info[cnt].shdr.sh_link < cnt; + } + + /* Handle references through sh_info. */ + if (SH_INFO_LINK_P (&shdr_info[cnt].shdr) + && shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0) + { + shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1; + changes |= shdr_info[cnt].shdr.sh_info < cnt; + } + + /* Mark the section as investigated. */ + shdr_info[cnt].idx = 2; + } + } + } + while (changes); + + /* Copy the removed sections to the debug output file. + The ones that are not removed in the stripped file are SHT_NOBITS. */ + if (debug_fname != NULL) + { + for (cnt = 1; cnt < shnum; ++cnt) + { + Elf_Data *debugdata; + GElf_Shdr debugshdr; + bool discard_section; + + scn = elf_newscn (debugelf); + if (scn == NULL) + error (EXIT_FAILURE, 0, + gettext ("while generating output file: %s"), + elf_errmsg (-1)); + + discard_section = shdr_info[cnt].idx > 0 && cnt != ehdr->e_shstrndx; + + /* Set the section header in the new file. */ + debugshdr = shdr_info[cnt].shdr; + if (discard_section) + debugshdr.sh_type = SHT_NOBITS; + + if (unlikely (gelf_update_shdr (scn, &debugshdr)) == 0) + /* There cannot be any overflows. */ + INTERNAL_ERROR (fname); + + /* Get the data from the old file if necessary. */ + if (shdr_info[cnt].data == NULL) + { + shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL); + if (shdr_info[cnt].data == NULL) + INTERNAL_ERROR (fname); + } + + /* Set the data. This is done by copying from the old file. */ + debugdata = elf_newdata (scn); + if (debugdata == NULL) + INTERNAL_ERROR (fname); + + /* Copy the structure. This data may be modified in place + before we write out the file. */ + *debugdata = *shdr_info[cnt].data; + if (discard_section) + debugdata->d_buf = NULL; + } + + /* Finish the ELF header. Fill in the fields not handled by + libelf from the old file. */ + debugehdr = gelf_getehdr (debugelf, &debugehdr_mem); + if (debugehdr == NULL) + INTERNAL_ERROR (fname); + + memcpy (debugehdr->e_ident, ehdr->e_ident, EI_NIDENT); + debugehdr->e_type = ehdr->e_type; + debugehdr->e_machine = ehdr->e_machine; + debugehdr->e_version = ehdr->e_version; + debugehdr->e_entry = ehdr->e_entry; + debugehdr->e_flags = ehdr->e_flags; + debugehdr->e_shstrndx = ehdr->e_shstrndx; + + if (unlikely (gelf_update_ehdr (debugelf, debugehdr)) == 0) + { + error (0, 0, gettext ("%s: error while creating ELF header: %s"), + debug_fname, elf_errmsg (-1)); + result = 1; + goto fail_close; + } + } + + /* Mark the section header string table as unused, we will create + a new one. */ + shdr_info[shstrndx].idx = 0; + + /* We need a string table for the section headers. */ + shst = ebl_strtabinit (true); + if (shst == NULL) + error (EXIT_FAILURE, errno, gettext ("while preparing output for '%s'"), + output_fname ?: fname); + + /* Assign new section numbers. */ + shdr_info[0].idx = 0; + for (cnt = idx = 1; cnt < shnum; ++cnt) + if (shdr_info[cnt].idx > 0) + { + shdr_info[cnt].idx = idx++; + + /* Create a new section. */ + shdr_info[cnt].newscn = elf_newscn (newelf); + if (shdr_info[cnt].newscn == NULL) + error (EXIT_FAILURE, 0, gettext ("while generating output file: %s"), + elf_errmsg (-1)); + + assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx); + + /* Add this name to the section header string table. */ + shdr_info[cnt].se = ebl_strtabadd (shst, shdr_info[cnt].name, 0); + } + + /* Test whether we are doing anything at all. */ + if (cnt == idx) + /* Nope, all removable sections are already gone. */ + goto fail_close; + + /* Create the reference to the file with the debug info. */ + if (debug_fname != NULL) + { + char *debug_basename; + off_t crc_offset; + + /* Add the section header string table section name. */ + shdr_info[cnt].se = ebl_strtabadd (shst, ".gnu_debuglink", 15); + shdr_info[cnt].idx = idx++; + + /* Create the section header. */ + shdr_info[cnt].shdr.sh_type = SHT_PROGBITS; + shdr_info[cnt].shdr.sh_flags = 0; + shdr_info[cnt].shdr.sh_addr = 0; + shdr_info[cnt].shdr.sh_link = SHN_UNDEF; + shdr_info[cnt].shdr.sh_info = SHN_UNDEF; + shdr_info[cnt].shdr.sh_entsize = 0; + shdr_info[cnt].shdr.sh_addralign = 4; + /* We set the offset to zero here. Before we write the ELF file the + field must have the correct value. This is done in the final + loop over all section. Then we have all the information needed. */ + shdr_info[cnt].shdr.sh_offset = 0; + + /* Create the section. */ + shdr_info[cnt].newscn = elf_newscn (newelf); + if (shdr_info[cnt].newscn == NULL) + error (EXIT_FAILURE, 0, + gettext ("while create section header section: %s"), + elf_errmsg (-1)); + assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx); + + shdr_info[cnt].data = elf_newdata (shdr_info[cnt].newscn); + if (shdr_info[cnt].data == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot allocate section data: %s"), + elf_errmsg (-1)); + + debug_basename = basename (debug_fname_embed ?: debug_fname); + crc_offset = strlen (debug_basename) + 1; + /* Align to 4 byte boundary */ + crc_offset = ((crc_offset - 1) & ~3) + 4; + + shdr_info[cnt].data->d_align = 4; + shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size + = crc_offset + 4; + shdr_info[cnt].data->d_buf = xcalloc (1, shdr_info[cnt].data->d_size); + + strcpy (shdr_info[cnt].data->d_buf, debug_basename); + + /* Cache this Elf_Data describing the CRC32 word in the section. + We'll fill this in when we have written the debug file. */ + debuglink_crc_data = *shdr_info[cnt].data; + debuglink_crc_data.d_buf = ((char *) debuglink_crc_data.d_buf + + crc_offset); + debuglink_crc_data.d_size = 4; + + /* One more section done. */ + ++cnt; + } + + /* Index of the section header table in the shdr_info array. */ + size_t shdridx = cnt; + + /* Add the section header string table section name. */ + shdr_info[cnt].se = ebl_strtabadd (shst, ".shstrtab", 10); + shdr_info[cnt].idx = idx; + + /* Create the section header. */ + shdr_info[cnt].shdr.sh_type = SHT_STRTAB; + shdr_info[cnt].shdr.sh_flags = 0; + shdr_info[cnt].shdr.sh_addr = 0; + shdr_info[cnt].shdr.sh_link = SHN_UNDEF; + shdr_info[cnt].shdr.sh_info = SHN_UNDEF; + shdr_info[cnt].shdr.sh_entsize = 0; + /* We set the offset to zero here. Before we write the ELF file the + field must have the correct value. This is done in the final + loop over all section. Then we have all the information needed. */ + shdr_info[cnt].shdr.sh_offset = 0; + shdr_info[cnt].shdr.sh_addralign = 1; + + /* Create the section. */ + shdr_info[cnt].newscn = elf_newscn (newelf); + if (shdr_info[cnt].newscn == NULL) + error (EXIT_FAILURE, 0, + gettext ("while create section header section: %s"), + elf_errmsg (-1)); + assert (elf_ndxscn (shdr_info[cnt].newscn) == idx); + + /* Finalize the string table and fill in the correct indices in the + section headers. */ + shstrtab_data = elf_newdata (shdr_info[cnt].newscn); + if (shstrtab_data == NULL) + error (EXIT_FAILURE, 0, + gettext ("while create section header string table: %s"), + elf_errmsg (-1)); + ebl_strtabfinalize (shst, shstrtab_data); + + /* We have to set the section size. */ + shdr_info[cnt].shdr.sh_size = shstrtab_data->d_size; + + /* Update the section information. */ + GElf_Off lastoffset = 0; + for (cnt = 1; cnt <= shdridx; ++cnt) + if (shdr_info[cnt].idx > 0) + { + Elf_Data *newdata; + + scn = elf_getscn (newelf, shdr_info[cnt].idx); + assert (scn != NULL); + + /* Update the name. */ + shdr_info[cnt].shdr.sh_name = ebl_strtaboffset (shdr_info[cnt].se); + + /* Update the section header from the input file. Some fields + might be section indeces which now have to be adjusted. */ + if (shdr_info[cnt].shdr.sh_link != 0) + shdr_info[cnt].shdr.sh_link = + shdr_info[shdr_info[cnt].shdr.sh_link].idx; + + if (shdr_info[cnt].shdr.sh_type == SHT_GROUP) + { + assert (shdr_info[cnt].data != NULL); + + Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; + for (size_t inner = 0; + inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); + ++inner) + grpref[inner] = shdr_info[grpref[inner]].idx; + } + + /* Handle the SHT_REL, SHT_RELA, and SHF_INFO_LINK flag. */ + if (SH_INFO_LINK_P (&shdr_info[cnt].shdr)) + shdr_info[cnt].shdr.sh_info = + shdr_info[shdr_info[cnt].shdr.sh_info].idx; + + /* Get the data from the old file if necessary. We already + created the data for the section header string table. */ + if (cnt < shnum) + { + if (shdr_info[cnt].data == NULL) + { + shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL); + if (shdr_info[cnt].data == NULL) + INTERNAL_ERROR (fname); + } + + /* Set the data. This is done by copying from the old file. */ + newdata = elf_newdata (scn); + if (newdata == NULL) + INTERNAL_ERROR (fname); + + /* Copy the structure. */ + *newdata = *shdr_info[cnt].data; + + /* We know the size. */ + shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size; + + /* We have to adjust symtol tables. The st_shndx member might + have to be updated. */ + if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM + || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) + { + Elf_Data *versiondata = NULL; + Elf_Data *shndxdata = NULL; + + size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, + ehdr->e_version); + + if (shdr_info[cnt].symtab_idx != 0) + { + assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX); + /* This section has extended section information. + We have to modify that information, too. */ + shndxdata = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn, + NULL); + + assert ((versiondata->d_size / sizeof (Elf32_Word)) + >= shdr_info[cnt].data->d_size / elsize); + } + + if (shdr_info[cnt].version_idx != 0) + { + assert (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM); + /* This section has associated version + information. We have to modify that + information, too. */ + versiondata = elf_getdata (shdr_info[shdr_info[cnt].version_idx].scn, + NULL); + + assert ((versiondata->d_size / sizeof (GElf_Versym)) + >= shdr_info[cnt].data->d_size / elsize); + } + + shdr_info[cnt].newsymidx + = (Elf32_Word *) xcalloc (shdr_info[cnt].data->d_size + / elsize, sizeof (Elf32_Word)); + + bool last_was_local = true; + size_t destidx; + size_t inner; + for (destidx = inner = 1; + inner < shdr_info[cnt].data->d_size / elsize; + ++inner) + { + Elf32_Word sec; + GElf_Sym sym_mem; + Elf32_Word xshndx; + GElf_Sym *sym = gelf_getsymshndx (shdr_info[cnt].data, + shndxdata, inner, + &sym_mem, &xshndx); + if (sym == NULL) + INTERNAL_ERROR (fname); + + if (sym->st_shndx == SHN_UNDEF + || (sym->st_shndx >= shnum + && sym->st_shndx != SHN_XINDEX)) + { + /* This is no section index, leave it alone + unless it is moved. */ + if (destidx != inner + && gelf_update_symshndx (shdr_info[cnt].data, + shndxdata, + destidx, sym, + xshndx) == 0) + INTERNAL_ERROR (fname); + + shdr_info[cnt].newsymidx[inner] = destidx++; + + if (last_was_local + && GELF_ST_BIND (sym->st_info) != STB_LOCAL) + { + last_was_local = false; + shdr_info[cnt].shdr.sh_info = destidx - 1; + } + + continue; + } + + /* Get the full section index, if necessary from the + XINDEX table. */ + if (sym->st_shndx != SHN_XINDEX) + sec = shdr_info[sym->st_shndx].idx; + else + { + assert (shndxdata != NULL); + + sec = shdr_info[xshndx].idx; + } + + if (sec != 0) + { + GElf_Section nshndx; + Elf32_Word nxshndx; + + if (sec < SHN_LORESERVE) + { + nshndx = sec; + nxshndx = 0; + } + else + { + nshndx = SHN_XINDEX; + nxshndx = sec; + } + + assert (sec < SHN_LORESERVE || shndxdata != NULL); + + if ((inner != destidx || nshndx != sym->st_shndx + || (shndxdata != NULL && nxshndx != xshndx)) + && (sym->st_shndx = nshndx, + gelf_update_symshndx (shdr_info[cnt].data, + shndxdata, + destidx, sym, + nxshndx) == 0)) + INTERNAL_ERROR (fname); + + shdr_info[cnt].newsymidx[inner] = destidx++; + + if (last_was_local + && GELF_ST_BIND (sym->st_info) != STB_LOCAL) + { + last_was_local = false; + shdr_info[cnt].shdr.sh_info = destidx - 1; + } + } + else + /* This is a section symbol for a section which has + been removed. */ + assert (GELF_ST_TYPE (sym->st_info) == STT_SECTION); + } + + if (destidx != inner) + { + /* The size of the symbol table changed. */ + shdr_info[cnt].shdr.sh_size = newdata->d_size + = destidx * elsize; + any_symtab_changes = true; + } + else + { + /* The symbol table didn't really change. */ + free (shdr_info[cnt].newsymidx); + shdr_info[cnt].newsymidx = NULL; + } + } + } + + /* If we have to, compute the offset of the section. */ + if (shdr_info[cnt].shdr.sh_offset == 0) + shdr_info[cnt].shdr.sh_offset + = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1) + & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1))); + + /* Set the section header in the new file. */ + if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0)) + /* There cannot be any overflows. */ + INTERNAL_ERROR (fname); + + /* Remember the last section written so far. */ + GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS + ? shdr_info[cnt].shdr.sh_size : 0); + if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz) + lastoffset = shdr_info[cnt].shdr.sh_offset + filesz; + } + + /* Adjust symbol references if symbol tables changed. */ + if (any_symtab_changes) + { + /* Find all relocation sections which use this + symbol table. */ + for (cnt = 1; cnt <= shdridx; ++cnt) + { + if (shdr_info[cnt].idx == 0 && debug_fname == NULL) + /* Ignore sections which are discarded. When we are saving a + relocation section in a separate debug file, we must fix up + the symbol table references. */ + continue; + + if (shdr_info[cnt].shdr.sh_type == SHT_REL + || shdr_info[cnt].shdr.sh_type == SHT_RELA) + { + /* If the symbol table hasn't changed, do not do anything. */ + if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx == NULL) + continue; + + Elf32_Word *newsymidx + = shdr_info[shdr_info[cnt].old_sh_link].newsymidx; + Elf_Data *d = elf_getdata (shdr_info[cnt].idx == 0 + ? elf_getscn (debugelf, cnt) + : elf_getscn (newelf, + shdr_info[cnt].idx), + NULL); + assert (d != NULL); + size_t nrels = (shdr_info[cnt].shdr.sh_size + / shdr_info[cnt].shdr.sh_entsize); + + if (shdr_info[cnt].shdr.sh_type == SHT_REL) + for (size_t relidx = 0; relidx < nrels; ++relidx) + { + GElf_Rel rel_mem; + if (gelf_getrel (d, relidx, &rel_mem) == NULL) + INTERNAL_ERROR (fname); + + size_t symidx = GELF_R_SYM (rel_mem.r_info); + if (newsymidx[symidx] != symidx) + { + rel_mem.r_info + = GELF_R_INFO (newsymidx[symidx], + GELF_R_TYPE (rel_mem.r_info)); + + if (gelf_update_rel (d, relidx, &rel_mem) == 0) + INTERNAL_ERROR (fname); + } + } + else + for (size_t relidx = 0; relidx < nrels; ++relidx) + { + GElf_Rela rel_mem; + if (gelf_getrela (d, relidx, &rel_mem) == NULL) + INTERNAL_ERROR (fname); + + size_t symidx = GELF_R_SYM (rel_mem.r_info); + if (newsymidx[symidx] != symidx) + { + rel_mem.r_info + = GELF_R_INFO (newsymidx[symidx], + GELF_R_TYPE (rel_mem.r_info)); + + if (gelf_update_rela (d, relidx, &rel_mem) == 0) + INTERNAL_ERROR (fname); + } + } + } + else if (shdr_info[cnt].shdr.sh_type == SHT_HASH) + { + /* We have to recompute the hash table. */ + Elf32_Word symtabidx = shdr_info[cnt].old_sh_link; + + /* We do not have to do anything if the symbol table was + not changed. */ + if (shdr_info[symtabidx].newsymidx == NULL) + continue; + + assert (shdr_info[cnt].idx > 0); + + /* The hash section in the new file. */ + scn = elf_getscn (newelf, shdr_info[cnt].idx); + + /* The symbol table data. */ + Elf_Data *symd = elf_getdata (elf_getscn (newelf, + shdr_info[symtabidx].idx), + NULL); + assert (symd != NULL); + + /* The hash table data. */ + Elf_Data *hashd = elf_getdata (scn, NULL); + assert (hashd != NULL); + + if (shdr_info[cnt].shdr.sh_entsize == sizeof (Elf32_Word)) + { + /* Sane arches first. */ + Elf32_Word *bucket = (Elf32_Word *) hashd->d_buf; + + size_t strshndx = shdr_info[symtabidx].old_sh_link; + size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, + ehdr->e_version); + + /* Adjust the nchain value. The symbol table size + changed. We keep the same size for the bucket array. */ + bucket[1] = symd->d_size / elsize; + Elf32_Word nbucket = bucket[0]; + bucket += 2; + Elf32_Word *chain = bucket + nbucket; + + /* New size of the section. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + shdr->sh_size = hashd->d_size + = (2 + symd->d_size / elsize + nbucket) + * sizeof (Elf32_Word); + (void) gelf_update_shdr (scn, shdr); + + /* Clear the arrays. */ + memset (bucket, '\0', + (symd->d_size / elsize + nbucket) + * sizeof (Elf32_Word)); + + for (size_t inner = shdr_info[symtabidx].shdr.sh_info; + inner < symd->d_size / elsize; ++inner) + { + GElf_Sym sym_mem; + GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem); + assert (sym != NULL); + + const char *name = elf_strptr (elf, strshndx, + sym->st_name); + assert (name != NULL); + size_t hidx = elf_hash (name) % nbucket; + + if (bucket[hidx] == 0) + bucket[hidx] = inner; + else + { + hidx = bucket[hidx]; + + while (chain[hidx] != 0) + hidx = chain[hidx]; + + chain[hidx] = inner; + } + } + } + else + { + /* Alpha and S390 64-bit use 64-bit SHT_HASH entries. */ + assert (shdr_info[cnt].shdr.sh_entsize + == sizeof (Elf64_Xword)); + + Elf64_Xword *bucket = (Elf64_Xword *) hashd->d_buf; + + size_t strshndx = shdr_info[symtabidx].old_sh_link; + size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, + ehdr->e_version); + + /* Adjust the nchain value. The symbol table size + changed. We keep the same size for the bucket array. */ + bucket[1] = symd->d_size / elsize; + Elf64_Xword nbucket = bucket[0]; + bucket += 2; + Elf64_Xword *chain = bucket + nbucket; + + /* New size of the section. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + shdr->sh_size = hashd->d_size + = (2 + symd->d_size / elsize + nbucket) + * sizeof (Elf64_Xword); + (void) gelf_update_shdr (scn, shdr); + + /* Clear the arrays. */ + memset (bucket, '\0', + (symd->d_size / elsize + nbucket) + * sizeof (Elf64_Xword)); + + for (size_t inner = shdr_info[symtabidx].shdr.sh_info; + inner < symd->d_size / elsize; ++inner) + { + GElf_Sym sym_mem; + GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem); + assert (sym != NULL); + + const char *name = elf_strptr (elf, strshndx, + sym->st_name); + assert (name != NULL); + size_t hidx = elf_hash (name) % nbucket; + + if (bucket[hidx] == 0) + bucket[hidx] = inner; + else + { + hidx = bucket[hidx]; + + while (chain[hidx] != 0) + hidx = chain[hidx]; + + chain[hidx] = inner; + } + } + } + } + else if (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym) + { + /* If the symbol table changed we have to adjust the + entries. */ + Elf32_Word symtabidx = shdr_info[cnt].old_sh_link; + + /* We do not have to do anything if the symbol table was + not changed. */ + if (shdr_info[symtabidx].newsymidx == NULL) + continue; + + assert (shdr_info[cnt].idx > 0); + + /* The symbol version section in the new file. */ + scn = elf_getscn (newelf, shdr_info[cnt].idx); + + /* The symbol table data. */ + Elf_Data *symd = elf_getdata (elf_getscn (newelf, + shdr_info[symtabidx].idx), + NULL); + assert (symd != NULL); + + /* The version symbol data. */ + Elf_Data *verd = elf_getdata (scn, NULL); + assert (verd != NULL); + + /* The symbol version array. */ + GElf_Half *verstab = (GElf_Half *) verd->d_buf; + + /* New indices of the symbols. */ + Elf32_Word *newsymidx = shdr_info[symtabidx].newsymidx; + + /* Walk through the list and */ + size_t elsize = gelf_fsize (elf, verd->d_type, 1, + ehdr->e_version); + for (size_t inner = 1; inner < verd->d_size / elsize; ++inner) + if (newsymidx[inner] != 0) + /* Overwriting the same array works since the + reordering can only move entries to lower indices + in the array. */ + verstab[newsymidx[inner]] = verstab[inner]; + + /* New size of the section. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + shdr->sh_size = verd->d_size + = gelf_fsize (newelf, verd->d_type, + symd->d_size / gelf_fsize (elf, symd->d_type, 1, + ehdr->e_version), + ehdr->e_version); + (void) gelf_update_shdr (scn, shdr); + } + else if (shdr_info[cnt].shdr.sh_type == SHT_GROUP) + { + /* Check whether the associated symbol table changed. */ + if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx != NULL) + { + /* Yes the symbol table changed. Update the section + header of the section group. */ + scn = elf_getscn (newelf, shdr_info[cnt].idx); + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + assert (shdr != NULL); + + size_t stabidx = shdr_info[cnt].old_sh_link; + shdr->sh_info = shdr_info[stabidx].newsymidx[shdr->sh_info]; + + (void) gelf_update_shdr (scn, shdr); + } + } + } + } + + /* Now that we have done all adjustments to the data, + we can actually write out the debug file. */ + if (debug_fname != NULL) + { + uint32_t debug_crc; + Elf_Data debug_crc_data = + { + .d_type = ELF_T_WORD, + .d_buf = &debug_crc, + .d_size = sizeof (debug_crc), + .d_version = EV_CURRENT + }; + + /* Finally write the file. */ + if (unlikely (elf_update (debugelf, ELF_C_WRITE)) == -1) + { + error (0, 0, gettext ("while writing '%s': %s"), + debug_fname, elf_errmsg (-1)); + result = 1; + goto fail_close; + } + + /* Create the real output file. First rename, then change the + mode. */ + if (rename (tmp_debug_fname, debug_fname) != 0 + || fchmod (debug_fd, mode) != 0) + { + error (0, errno, gettext ("while creating '%s'"), debug_fname); + result = 1; + goto fail_close; + } + + /* The temporary file does not exist anymore. */ + tmp_debug_fname = NULL; + + /* Compute the checksum which we will add to the executable. */ + if (crc32_file (debug_fd, &debug_crc) != 0) + { + error (0, errno, + gettext ("while computing checksum for debug information")); + unlink (debug_fname); + result = 1; + goto fail_close; + } + + /* Store it in the debuglink section data. */ + if (unlikely (gelf_xlatetof (newelf, &debuglink_crc_data, + &debug_crc_data, ehdr->e_ident[EI_DATA]) + != &debuglink_crc_data)) + INTERNAL_ERROR (fname); + } + + /* Finally finish the ELF header. Fill in the fields not handled by + libelf from the old file. */ + newehdr = gelf_getehdr (newelf, &newehdr_mem); + if (newehdr == NULL) + INTERNAL_ERROR (fname); + + memcpy (newehdr->e_ident, ehdr->e_ident, EI_NIDENT); + newehdr->e_type = ehdr->e_type; + newehdr->e_machine = ehdr->e_machine; + newehdr->e_version = ehdr->e_version; + newehdr->e_entry = ehdr->e_entry; + newehdr->e_flags = ehdr->e_flags; + newehdr->e_phoff = ehdr->e_phoff; + /* We need to position the section header table. */ + const size_t offsize = gelf_fsize (elf, ELF_T_OFF, 1, EV_CURRENT); + newehdr->e_shoff = ((shdr_info[shdridx].shdr.sh_offset + + shdr_info[shdridx].shdr.sh_size + offsize - 1) + & ~((GElf_Off) (offsize - 1))); + newehdr->e_shentsize = gelf_fsize (elf, ELF_T_SHDR, 1, EV_CURRENT); + + /* The new section header string table index. */ + if (likely (idx < SHN_HIRESERVE) && likely (idx != SHN_XINDEX)) + newehdr->e_shstrndx = idx; + else + { + /* The index does not fit in the ELF header field. */ + shdr_info[0].scn = elf_getscn (elf, 0); + + if (gelf_getshdr (shdr_info[0].scn, &shdr_info[0].shdr) == NULL) + INTERNAL_ERROR (fname); + + shdr_info[0].shdr.sh_link = idx; + (void) gelf_update_shdr (shdr_info[0].scn, &shdr_info[0].shdr); + + newehdr->e_shstrndx = SHN_XINDEX; + } + + if (gelf_update_ehdr (newelf, newehdr) == 0) + { + error (0, 0, gettext ("%s: error while creating ELF header: %s"), + fname, elf_errmsg (-1)); + return 1; + } + + /* We have everything from the old file. */ + if (elf_cntl (elf, ELF_C_FDDONE) != 0) + { + error (0, 0, gettext ("%s: error while reading the file: %s"), + fname, elf_errmsg (-1)); + return 1; + } + + /* The ELF library better follows our layout when this is not a + relocatable object file. */ + elf_flagelf (newelf, ELF_C_SET, + (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0) + | (permissive ? ELF_F_PERMISSIVE : 0)); + + /* Finally write the file. */ + if (elf_update (newelf, ELF_C_WRITE) == -1) + { + error (0, 0, gettext ("while writing '%s': %s"), + fname, elf_errmsg (-1)); + result = 1; + } + + fail_close: + if (shdr_info != NULL) + { + /* For some sections we might have created an table to map symbol + table indices. */ + if (any_symtab_changes) + for (cnt = 1; cnt <= shdridx; ++cnt) + free (shdr_info[cnt].newsymidx); + + /* Free the memory. */ + if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC) + free (shdr_info); + } + + /* Free other resources. */ + if (shstrtab_data != NULL) + free (shstrtab_data->d_buf); + if (shst != NULL) + ebl_strtabfree (shst); + + /* That was it. Close the descriptors. */ + if (elf_end (newelf) != 0) + { + error (0, 0, gettext ("error while finishing '%s': %s"), fname, + elf_errmsg (-1)); + result = 1; + } + + if (debugelf != NULL && elf_end (debugelf) != 0) + { + error (0, 0, gettext ("error while finishing '%s': %s"), debug_fname, + elf_errmsg (-1)); + result = 1; + } + + fail: + /* Close the EBL backend. */ + if (ebl != NULL) + ebl_closebackend (ebl); + + /* Close debug file descriptor, if opened */ + if (debug_fd >= 0) + { + if (tmp_debug_fname != NULL) + unlink (tmp_debug_fname); + close (debug_fd); + } + + /* If requested, preserve the timestamp. */ + if (tvp != NULL) + { + if (futimes (fd, tvp) != 0) + { + error (0, errno, gettext ("\ +cannot set access and modification date of '%s'"), + output_fname ?: fname); + result = 1; + } + } + + /* Close the file descriptor if we created a new file. */ + if (output_fname != NULL) + close (fd); + + return result; +} + + +static int +handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, + struct timeval tvp[2]) +{ + size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); + size_t fname_len = strlen (fname) + 1; + char new_prefix[prefix_len + 1 + fname_len]; + char *cp = new_prefix; + + /* Create the full name of the file. */ + if (prefix != NULL) + { + cp = mempcpy (cp, prefix, prefix_len); + *cp++ = ':'; + } + memcpy (cp, fname, fname_len); + + + /* Process all the files contained in the archive. */ + Elf *subelf; + Elf_Cmd cmd = ELF_C_RDWR; + int result = 0; + while ((subelf = elf_begin (fd, cmd, elf)) != NULL) + { + /* The the header for this element. */ + Elf_Arhdr *arhdr = elf_getarhdr (subelf); + + if (elf_kind (subelf) == ELF_K_ELF) + result |= handle_elf (fd, subelf, new_prefix, arhdr->ar_name, 0, NULL); + else if (elf_kind (subelf) == ELF_K_AR) + result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, NULL); + + /* Get next archive element. */ + cmd = elf_next (subelf); + if (unlikely (elf_end (subelf) != 0)) + INTERNAL_ERROR (fname); + } + + if (tvp != NULL) + { + if (unlikely (futimes (fd, tvp) != 0)) + { + error (0, errno, gettext ("\ +cannot set access and modification date of '%s'"), fname); + result = 1; + } + } + + if (unlikely (close (fd) != 0)) + error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname); + + return result; +} diff --git a/src/symbolhash.c b/src/symbolhash.c new file mode 100644 index 00000000..da2ae6f6 --- /dev/null +++ b/src/symbolhash.c @@ -0,0 +1,29 @@ +/* Symbol hash table implementation. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + +/* Definitions for the symbol hash table. */ +#define TYPE struct symbol * +#define NAME ld_symbol_tab +#define ITERATE 1 +#define COMPARE(a, b) strcmp ((a)->name, (b)->name) + +#include "../lib/dynamicsizehash.c" diff --git a/src/symbolhash.h b/src/symbolhash.h new file mode 100644 index 00000000..a8798c2a --- /dev/null +++ b/src/symbolhash.h @@ -0,0 +1,24 @@ +/* Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef SYMBOLHASH_H +#define SYMBOLHASH_H 1 + +/* Definitions for the symbol hash table. */ +#define TYPE struct symbol * +#define NAME ld_symbol_tab +#define ITERATE 1 +#define COMPARE(a, b) strcmp ((a)->name, (b)->name) +#include + +#endif /* symbolhash.h */ diff --git a/src/unaligned.h b/src/unaligned.h new file mode 100644 index 00000000..524b35c8 --- /dev/null +++ b/src/unaligned.h @@ -0,0 +1,98 @@ +/* Unaligned memory access functionality. + Copyright (C) 2000, 2001, 2002, 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _UNALIGNED_H +#define _UNALIGNED_H 1 + +#include +#include + + +#ifndef UNALIGNED_ACCESS_CLASS +# error "UNALIGNED_ACCESS_CLASS must be defined" +#endif + + +/* Macros to convert from the host byte order to that of the object file. */ +#if UNALIGNED_ACCESS_CLASS == BYTE_ORDER +# define target_bswap_16(n) (n) +# define target_bswap_32(n) (n) +# define target_bswap_64(n) (n) +#else +# define target_bswap_16(n) bswap_16 (n) +# define target_bswap_32(n) bswap_32 (n) +# define target_bswap_64(n) bswap_64 (n) +#endif + + +union u_2ubyte_unaligned +{ + uint16_t u; + char c[2]; +} __attribute__((packed)); + +union u_4ubyte_unaligned +{ + uint32_t u; + char c[4]; +} __attribute__((packed)); + +union u_8ubyte_unaligned +{ + uint64_t u; + char c[8]; +} __attribute__((packed)); + + +/* Macros to store value at unaligned address. */ +#define store_2ubyte_unaligned(ptr, value) \ + (void) (((union u_2ubyte_unaligned *) (ptr))->u = target_bswap_16 (value)) +#define store_4ubyte_unaligned(ptr, value) \ + (void) (((union u_4ubyte_unaligned *) (ptr))->u = target_bswap_32 (value)) +#define store_8ubyte_unaligned(ptr, value) \ + (void) (((union u_8ubyte_unaligned *) (ptr))->u = target_bswap_64 (value)) + + +/* Macros to add value to unaligned address. This is a bit more + complicated since the value must be read from memory and eventually + converted twice. */ +#if UNALIGNED_ACCESS_CLASS == BYTE_ORDER +# define add_2ubyte_unaligned(ptr, value) \ + (void) (((union u_2ubyte_unaligned *) (ptr))->u += value) +# define add_4ubyte_unaligned(ptr, value) \ + (void) (((union u_4ubyte_unaligned *) (ptr))->u += value) +# define add_8ubyte_unaligned(ptr, value) \ + (void) (((union u_8ubyte_unaligned *) (ptr))->u += value) +#else +# define add_2ubyte_unaligned(ptr, value) \ + do { \ + union u_2ubyte_unaligned *_ptr = (ptr); \ + uint16_t _val = bswap_16 (_ptr->u) + (value); \ + _ptr->u = bswap_16 (_val); \ + } while (0) +# define add_4ubyte_unaligned(ptr, value) \ + do { \ + union u_4ubyte_unaligned *_ptr = (ptr); \ + uint32_t _val = bswap_32 (_ptr->u) + (value); \ + _ptr->u = bswap_32 (_val); \ + } while (0) +# define add_8ubyte_unaligned(ptr, value) \ + do { \ + union u_8ubyte_unaligned *_ptr = (ptr); \ + uint64_t _val = bswap_64 (_ptr->u) + (value); \ + _ptr->u = bswap_64 (_val); \ + } while (0) +#endif + +#endif /* unaligned.h */ diff --git a/src/versionhash.c b/src/versionhash.c new file mode 100644 index 00000000..79b2e105 --- /dev/null +++ b/src/versionhash.c @@ -0,0 +1,28 @@ +/* Version symbol hash table implementation. + Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + +/* Definitions for the symbol hash table. */ +#define TYPE struct id_list * +#define NAME ld_version_str_tab +#define COMPARE(a, b) strcmp ((a)->id, (b)->id) + +#include "../lib/dynamicsizehash.c" diff --git a/src/versionhash.h b/src/versionhash.h new file mode 100644 index 00000000..243aeeb5 --- /dev/null +++ b/src/versionhash.h @@ -0,0 +1,22 @@ +/* Copyright (C) 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef VERSIONHASH_H +#define VERSIONHASH_H 1 + +/* Definitions for the symbol hash table. */ +#define TYPE struct id_list * +#define NAME ld_version_str_tab +#include + +#endif /* versionhash.h */ diff --git a/src/xelf.h b/src/xelf.h new file mode 100644 index 00000000..ab36e002 --- /dev/null +++ b/src/xelf.h @@ -0,0 +1,387 @@ +/* Macros to enable writing native and generic ELF access code. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper , 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +/* By default the linker is handling all architectures. But it can + be configured to be a native-only linker. */ +#if NATIVE_ELF == 32 +/* 32-bit only. */ +# define XElf_Ehdr Elf32_Ehdr +# define XElf_Shdr Elf32_Shdr +# define XElf_Off Elf32_Off +# define XElf_Addr Elf32_Addr +# define XElf_Half Elf32_Half +# define XElf_Word Elf32_Word +# define XElf_Xword Elf32_Word +# define XElf_Sxword Elf32_Sword +# define XElf_Versym Elf32_Versym +# define XElf_Sym Elf32_Sym +# define XElf_Rel Elf32_Rel +# define XElf_Rela Elf32_Rela + +# define XElf_Ehdr_vardef(name) Elf32_Ehdr *name +# define xelf_getehdr(elf, name) name = elf32_getehdr (elf) +# define xelf_getehdr_copy(elf, name, copy) \ + (copy) = *(name = elf32_getehdr (elf)) +# define xelf_newehdr(elf, klass) elf32_newehdr (elf) +# define xelf_update_ehdr(elf, ehdr) \ + /* nothing */ ((void) (elf), (void) (ehdr), 1) + +# define xelf_getclass(elf) ELFCLASS32 + +# define XElf_Phdr_vardef(name) Elf32_Phdr *name +# define xelf_newphdr(elf, n) elf32_newphdr (elf, n) +# define xelf_getphdr(elf, idx, name) name = elf32_getphdr (elf) + idx +# define xelf_getphdr_ptr(elf, idx, name) name = elf32_getphdr (elf) + idx +# define xelf_update_phdr(elf, idx, phdr) \ + /* nothing */ ((void) (elf), (void) (idx), (void) (phdr), 1) + +# define XElf_Shdr_vardef(name) Elf32_Shdr *name +# define xelf_getshdr(scn, name) name = elf32_getshdr (scn) +# define xelf_getshdr_copy(scn, name, copy) \ + (copy) = *(name = elf32_getshdr (scn)) +# define xelf_update_shdr(scn, shdr) \ + /* nothing */ ((void) (scn), (void) (shdr), 1) + +# define XElf_Sym_vardef(name) Elf32_Sym *name +# define xelf_getsym(data, idx, name) \ + name = &((Elf32_Sym *) (data)->d_buf)[idx] +# define xelf_getsym_ptr(data, idx, name) \ + name = &((Elf32_Sym *) (data)->d_buf)[idx] +# define xelf_getsymshndx(data, ndxdata, idx, name1, name2) \ + (name1 = &((Elf32_Sym *) ((data)->d_buf))[idx]); \ + name2 = (unlikely ((ndxdata) != NULL) \ + ? ((Elf32_Word *) ((ndxdata)->d_buf))[idx] : 0) +# define xelf_update_sym(data, idx, sym) \ + /* nothing */ ((void) (data), (void) (idx), (void) (sym), 1) +# define xelf_update_symshndx(data, ndxdata, idx, name1, name2, datachanged) \ + if (datachanged) \ + ((Elf32_Sym *) ((data)->d_buf))[idx] = *name1; \ + if (unlikely (ndxdata != NULL)) \ + ((Elf32_Word *) ((ndxdata)->d_buf))[idx] = name2 + +# define XElf_Versym_vardef(name) Elf32_Versym name +# define xelf_getversym_copy(data, idx, name) \ + (name = ((Elf32_Versym *) ((data)->d_buf))[idx], &name) + +# define XElf_Dyn_vardef(name) Elf32_Dyn *name +# define xelf_getdyn(data, idx, name) \ + name = &((Elf32_Dyn *) ((data)->d_buf))[idx] +# define xelf_getdyn_ptr(data, idx, name) \ + name = &((Elf32_Dyn *) ((data)->d_buf))[idx] +# define xelf_update_dyn(data, idx, name) \ + /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) + +# define XElf_Rel_vardef(name) Elf32_Rel *name +# define xelf_getrel(data, idx, name) \ + name = &((Elf32_Rel *) ((data)->d_buf))[idx] +# define xelf_getrel_ptr(data, idx, name) \ + name = &((Elf32_Rel *) ((data)->d_buf))[idx] +# define xelf_update_rel(data, idx, name) \ + /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) + +# define XElf_Rela_vardef(name) Elf32_Rela *name +# define xelf_getrela(data, idx, name) \ + name = &((Elf32_Rela *) ((data)->d_buf))[idx] +# define xelf_getrela_ptr(data, idx, name) \ + name = &((Elf32_Rela *) ((data)->d_buf))[idx] +# define xelf_update_rela(data, idx, name) \ + /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) + +# define XElf_Verdef_vardef(name) Elf32_Verdef *name +# define xelf_getverdef(data, offset, name) \ + name = ((Elf32_Verdef *) ((char *) ((data)->d_buf) + (offset))) + +# define XElf_Verdaux_vardef(name) Elf32_Verdaux *name +# define xelf_getverdaux(data, offset, name) \ + name = ((Elf32_Verdaux *) ((char *) ((data)->d_buf) + (offset))) + +# define XELF_ST_TYPE(info) ELF32_ST_TYPE (info) +# define XELF_ST_BIND(info) ELF32_ST_BIND (info) +# define XELF_ST_INFO(bind, type) ELF32_ST_INFO (bind, type) +# define XELF_ST_VISIBILITY(info) ELF32_ST_VISIBILITY (info) + +# define XELF_R_SYM(info) ELF32_R_SYM (info) +# define XELF_R_TYPE(info) ELF32_R_TYPE (info) +# define XELF_R_INFO(sym, type) ELF32_R_INFO (sym, type) + +# define xelf_fsize(elf, type, cnt) \ + (__builtin_constant_p (type) \ + ? ({ size_t fsize; \ + switch (type) \ + { \ + case ELF_T_BYTE: fsize = 1; break; \ + case ELF_T_ADDR: fsize = sizeof (Elf32_Addr); break; \ + case ELF_T_DYN: fsize = sizeof (Elf32_Dyn); break; \ + case ELF_T_EHDR: fsize = sizeof (Elf32_Ehdr); break; \ + case ELF_T_HALF: fsize = sizeof (Elf32_Half); break; \ + case ELF_T_OFF: fsize = sizeof (Elf32_Off); break; \ + case ELF_T_PHDR: fsize = sizeof (Elf32_Phdr); break; \ + case ELF_T_RELA: fsize = sizeof (Elf32_Rela); break; \ + case ELF_T_REL: fsize = sizeof (Elf32_Rel); break; \ + case ELF_T_SHDR: fsize = sizeof (Elf32_Shdr); break; \ + case ELF_T_SWORD: fsize = sizeof (Elf32_Sword); break; \ + case ELF_T_SYM: fsize = sizeof (Elf32_Sym); break; \ + case ELF_T_WORD: fsize = sizeof (Elf32_Word); break; \ + case ELF_T_XWORD: fsize = sizeof (Elf32_Xword); break; \ + case ELF_T_SXWORD: fsize = sizeof (Elf32_Sxword); break; \ + case ELF_T_VDEF: fsize = sizeof (Elf32_Verdef); break; \ + case ELF_T_VDAUX: fsize = sizeof (Elf32_Verdaux); break; \ + case ELF_T_VNEED: fsize = sizeof (Elf32_Verneed); break; \ + case ELF_T_VNAUX: fsize = sizeof (Elf32_Vernaux); break; \ + case ELF_T_NHDR: fsize = sizeof (Elf32_Nhdr); break; \ + case ELF_T_SYMINFO: fsize = sizeof (Elf32_Syminfo); break; \ + case ELF_T_MOVE: fsize = sizeof (Elf32_Move); break; \ + default: fsize = 0; break; \ + } \ + fsize * (cnt); }) \ + : gelf_fsize (elf, type, cnt, EV_CURRENT)) +#elif NATIVE_ELF == 64 +/* 64-bit only. */ +# define XElf_Ehdr Elf64_Ehdr +# define XElf_Shdr Elf64_Shdr +# define XElf_Addr Elf64_Addr +# define XElf_Half Elf64_Half +# define XElf_Off Elf64_Off +# define XElf_Word Elf64_Word +# define XElf_Xword Elf64_Xword +# define XElf_Sxword Elf64_Sxword +# define XElf_Versym Elf64_Versym +# define XElf_Sym Elf64_Sym +# define XElf_Rel Elf64_Rel +# define XElf_Rela Elf64_Rela + +# define XElf_Ehdr_vardef(name) Elf64_Ehdr *name +# define xelf_getehdr(elf, name) name = elf64_getehdr (elf) +# define xelf_getehdr_copy(elf, name, copy) \ + (copy) = *(name = elf64_getehdr (elf)) +# define xelf_newehdr(elf, klass) elf64_newehdr (elf) +# define xelf_update_ehdr(elf, ehdr) \ + /* nothing */ ((void) (elf), (void) (ehdr), 1) + +# define xelf_getclass(elf) ELFCLASS32 + +# define XElf_Phdr_vardef(name) Elf64_Phdr *name +# define xelf_newphdr(elf, n) elf64_newphdr (elf, n) +# define xelf_getphdr(elf, idx, name) name = elf64_getphdr (elf) + idx +# define xelf_getphdr_ptr(elf, idx, name) name = elf64_getphdr (elf) + idx +# define xelf_update_phdr(elf, idx, phdr) \ + /* nothing */ ((void) (elf), (void) (idx), (void) (phdr), 1) + +# define XElf_Shdr_vardef(name) Elf64_Shdr *name +# define xelf_getshdr(scn, name) name = elf64_getshdr (scn) +# define xelf_getshdr_copy(scn, name, copy) \ + (copy) = *(name = elf64_getshdr (scn)) +# define xelf_update_shdr(scn, shdr) \ + /* nothing */ ((void) (scn), (void) (shdr), 1) + +# define XElf_Sym_vardef(name) Elf64_Sym *name +# define xelf_getsym(data, idx, name) \ + name = &((Elf64_Sym *) (data)->d_buf)[idx] +# define xelf_getsym_ptr(data, idx, name) \ + name = &((Elf64_Sym *) (data)->d_buf)[idx] +# define xelf_getsymshndx(data, ndxdata, idx, name1, name2) \ + (name1 = &((Elf64_Sym *) ((data)->d_buf))[idx]); \ + name2 = (unlikely ((ndxdata) != NULL) \ + ? ((Elf32_Word *) ((ndxdata)->d_buf))[idx] : 0) +# define xelf_update_sym(data, idx, sym) \ + /* nothing */ ((void) (data), (void) (idx), (void) (sym), 1) +# define xelf_update_symshndx(data, ndxdata, idx, name1, name2, datachanged) \ + if (datachanged) \ + ((Elf64_Sym *) ((data)->d_buf))[idx] = *name1; \ + if (ndxdata != NULL) \ + (((Elf32_Word *) ((ndxdata)->d_buf))[idx] = name2) + +# define XElf_Versym_vardef(name) Elf64_Versym name +# define xelf_getversym_copy(data, idx, name) \ + (name = ((Elf64_Versym *) ((data)->d_buf))[idx], (&name)) + +# define XElf_Dyn_vardef(name) Elf64_Dyn *name +# define xelf_getdyn(data, idx, name) \ + name = &((Elf64_Dyn *) ((data)->d_buf))[idx] +# define xelf_getdyn_ptr(data, idx, name) \ + name = &((Elf64_Dyn *) ((data)->d_buf))[idx] +# define xelf_update_dyn(data, idx, name) \ + /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) + +# define XElf_Rel_vardef(name) Elf64_Rel *name +# define xelf_getrel(data, idx, name) \ + name = &((Elf64_Rel *) ((data)->d_buf))[idx] +# define xelf_getrel_ptr(data, idx, name) \ + name = &((Elf64_Rel *) ((data)->d_buf))[idx] +# define xelf_update_rel(data, idx, name) \ + /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) + +# define XElf_Rela_vardef(name) Elf64_Rela *name +# define xelf_getrela(data, idx, name) \ + name = &((Elf64_Rela *) ((data)->d_buf))[idx] +# define xelf_getrela_ptr(data, idx, name) \ + name = &((Elf64_Rela *) ((data)->d_buf))[idx] +# define xelf_update_rela(data, idx, name) \ + /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) + +# define XElf_Verdef_vardef(name) Elf64_Verdef *name +# define xelf_getverdef(data, offset, name) \ + name = ((Elf64_Verdef *) ((char *) ((data)->d_buf) + (offset))) + +# define XElf_Verdaux_vardef(name) Elf64_Verdaux *name +# define xelf_getverdaux(data, offset, name) \ + name = ((Elf64_Verdaux *) ((char *) ((data)->d_buf) + (offset))) + +# define XELF_ST_TYPE(info) ELF64_ST_TYPE (info) +# define XELF_ST_BIND(info) ELF64_ST_BIND (info) +# define XELF_ST_INFO(bind, type) ELF64_ST_INFO (bind, type) +# define XELF_ST_VISIBILITY(info) ELF64_ST_VISIBILITY (info) + +# define XELF_R_SYM(info) ELF64_R_SYM (info) +# define XELF_R_TYPE(info) ELF64_R_TYPE (info) +# define XELF_R_INFO(sym, type) ELF64_R_INFO (sym, type) + +# define xelf_fsize(elf, type, cnt) \ + (__builtin_constant_p (type) \ + ? ({ size_t fsize; \ + switch (type) \ + { \ + case ELF_T_BYTE: fsize = 1; break; \ + case ELF_T_ADDR: fsize = sizeof (Elf64_Addr); break; \ + case ELF_T_DYN: fsize = sizeof (Elf64_Dyn); break; \ + case ELF_T_EHDR: fsize = sizeof (Elf64_Ehdr); break; \ + case ELF_T_HALF: fsize = sizeof (Elf64_Half); break; \ + case ELF_T_OFF: fsize = sizeof (Elf64_Off); break; \ + case ELF_T_PHDR: fsize = sizeof (Elf64_Phdr); break; \ + case ELF_T_RELA: fsize = sizeof (Elf64_Rela); break; \ + case ELF_T_REL: fsize = sizeof (Elf64_Rel); break; \ + case ELF_T_SHDR: fsize = sizeof (Elf64_Shdr); break; \ + case ELF_T_SWORD: fsize = sizeof (Elf64_Sword); break; \ + case ELF_T_SYM: fsize = sizeof (Elf64_Sym); break; \ + case ELF_T_WORD: fsize = sizeof (Elf64_Word); break; \ + case ELF_T_XWORD: fsize = sizeof (Elf64_Xword); break; \ + case ELF_T_SXWORD: fsize = sizeof (Elf64_Sxword); break; \ + case ELF_T_VDEF: fsize = sizeof (Elf64_Verdef); break; \ + case ELF_T_VDAUX: fsize = sizeof (Elf64_Verdaux); break; \ + case ELF_T_VNEED: fsize = sizeof (Elf64_Verneed); break; \ + case ELF_T_VNAUX: fsize = sizeof (Elf64_Vernaux); break; \ + case ELF_T_NHDR: fsize = sizeof (Elf64_Nhdr); break; \ + case ELF_T_SYMINFO: fsize = sizeof (Elf64_Syminfo); break; \ + case ELF_T_MOVE: fsize = sizeof (Elf64_Move); break; \ + default: fsize = 0; break; \ + } \ + fsize * (cnt); }) \ + : gelf_fsize (elf, type, cnt, EV_CURRENT)) +#else +# include + +/* Generic linker. */ +# define XElf_Ehdr GElf_Ehdr +# define XElf_Shdr GElf_Shdr +# define XElf_Addr GElf_Addr +# define XElf_Half GElf_Half +# define XElf_Off GElf_Off +# define XElf_Word GElf_Word +# define XElf_Xword GElf_Xword +# define XElf_Sxword GElf_Sxword +# define XElf_Versym GElf_Versym +# define XElf_Sym GElf_Sym +# define XElf_Rel GElf_Rel +# define XElf_Rela GElf_Rela + +# define XElf_Ehdr_vardef(name) GElf_Ehdr name##_mem; GElf_Ehdr *name +# define xelf_getehdr(elf, name) name = gelf_getehdr (elf, &name##_mem) +# define xelf_getehdr_copy(elf, name, copy) \ + name = gelf_getehdr (elf, &(copy)) +# define xelf_newehdr(elf, klass) gelf_newehdr (elf, klass) +# define xelf_update_ehdr(elf, ehdr) gelf_update_ehdr (elf, ehdr) + +# define xelf_getclass(elf) gelf_getclass (elf) + +# define XElf_Phdr_vardef(name) GElf_Phdr name##_mem; GElf_Phdr *name +# define xelf_newphdr(elf, n) gelf_newphdr (elf, n) +# define xelf_getphdr(elf, idx, name) \ + name = gelf_getphdr (elf, idx, &name##_mem) +# define xelf_getphdr_ptr(elf, idx, name) \ + name = &name##_mem +# define xelf_update_phdr(elf, idx, phdr) \ + gelf_update_phdr (elf, idx, phdr) + +# define XElf_Shdr_vardef(name) GElf_Shdr name##_mem; GElf_Shdr *name +# define xelf_getshdr(scn, name) name = gelf_getshdr (scn, &name##_mem) +# define xelf_getshdr_copy(scn, name, copy) \ + name = gelf_getshdr (scn, &(copy)) +# define xelf_update_shdr(scn, shdr) gelf_update_shdr (scn, shdr) + +# define XElf_Sym_vardef(name) GElf_Sym name##_mem; GElf_Sym *name +# define xelf_getsym(data, idx, name) \ + name = gelf_getsym (data, idx, &name##_mem) +# define xelf_getsym_ptr(data, idx, name) \ + name = &name##_mem +# define xelf_getsymshndx(data, ndxdata, idx, name1, name2) \ + name1 = gelf_getsymshndx (data, ndxdata, idx, &name1##_mem, &(name2)) +# define xelf_update_sym(data, idx, sym) gelf_update_sym (data, idx, sym) +# define xelf_update_symshndx(data, ndxdata, idx, name1, name2, datachanged) \ + gelf_update_symshndx (data, ndxdata, idx, name1, name2) + +# define XElf_Versym_vardef(name) GElf_Versym name +# define xelf_getversym_copy(data, idx, name) \ + gelf_getversym (data, idx, &name) + +# define XElf_Dyn_vardef(name) GElf_Dyn name##_mem; GElf_Dyn *name +# define xelf_getdyn(data, idx, name) \ + name = gelf_getdyn (data, idx, &name##_mem) +# define xelf_getdyn_ptr(data, idx, name) \ + name = &name##_mem +# define xelf_update_dyn(data, idx, name) \ + gelf_update_dyn (data, idx, name) + +# define XElf_Rel_vardef(name) GElf_Rel name##_mem; GElf_Rel *name +# define xelf_getrel(data, idx, name) \ + name = gelf_getrel (data, idx, &name##_mem) +# define xelf_getrel_ptr(data, idx, name) \ + name = &name##_mem +# define xelf_update_rel(data, idx, name) \ + gelf_update_rel (data, idx, name) + +# define XElf_Rela_vardef(name) GElf_Rela name##_mem; GElf_Rela *name +# define xelf_getrela(data, idx, name) \ + name = gelf_getrela (data, idx, &name##_mem) +# define xelf_getrela_ptr(data, idx, name) \ + name = &name##_mem +# define xelf_update_rela(data, idx, name) \ + gelf_update_rela (data, idx, name) + +# define XElf_Verdef_vardef(name) GElf_Verdef name##_mem; GElf_Verdef *name +# define xelf_getverdef(data, offset, name) \ + name = gelf_getverdef (data, offset, &name##_mem) + +# define XElf_Verdaux_vardef(name) GElf_Verdaux name##_mem; GElf_Verdaux *name +# define xelf_getverdaux(data, offset, name) \ + name = gelf_getverdaux (data, offset, &name##_mem) + +# define XELF_ST_TYPE(info) GELF_ST_TYPE (info) +# define XELF_ST_BIND(info) GELF_ST_BIND (info) +# define XELF_ST_INFO(bind, type) GELF_ST_INFO (bind, type) +# define XELF_ST_VISIBILITY(info) GELF_ST_VISIBILITY (info) + +# define XELF_R_SYM(info) GELF_R_SYM (info) +# define XELF_R_TYPE(info) GELF_R_TYPE (info) +# define XELF_R_INFO(sym, type) GELF_R_INFO (sym, type) + +# define xelf_fsize(elf, type, cnt) \ + gelf_fsize (elf, type, cnt, EV_CURRENT) +#endif diff --git a/src/ylwrap b/src/ylwrap new file mode 100644 index 00000000..e8abf827 --- /dev/null +++ b/src/ylwrap @@ -0,0 +1,154 @@ +#! /bin/sh +# ylwrap - wrapper for lex/yacc invocations. +# Copyright 1996, 1997, 1998, 1999, 2001 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# 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 2, 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Usage: +# ylwrap INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... +# * INPUT is the input file +# * OUTPUT is file PROG generates +# * DESIRED is file we actually want +# * PROGRAM is program to run +# * ARGS are passed to PROG +# Any number of OUTPUT,DESIRED pairs may be used. + +# The input. +input="$1" +shift +case "$input" in + [\\/]* | ?:[\\/]*) + # Absolute path; do nothing. + ;; + *) + # Relative path. Make it absolute. + input="`pwd`/$input" + ;; +esac + +pairlist= +while test "$#" -ne 0; do + if test "$1" = "--"; then + shift + break + fi + pairlist="$pairlist $1" + shift +done + +# The program to run. +prog="$1" +shift +# Make any relative path in $prog absolute. +case "$prog" in + [\\/]* | ?:[\\/]*) ;; + *[\\/]*) prog="`pwd`/$prog" ;; +esac + +# FIXME: add hostname here for parallel makes that run commands on +# other machines. But that might take us over the 14-char limit. +dirname=ylwrap$$ +trap "cd `pwd`; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15 +mkdir $dirname || exit 1 + +cd $dirname + +$prog ${1+"$@"} "$input" +status=$? + +if test $status -eq 0; then + set X $pairlist + shift + first=yes + # Since DOS filename conventions don't allow two dots, + # the DOS version of Bison writes out y_tab.c instead of y.tab.c + # and y_tab.h instead of y.tab.h. Test to see if this is the case. + y_tab_nodot="no" + if test -f y_tab.c || test -f y_tab.h; then + y_tab_nodot="yes" + fi + + # The directory holding the input. + input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'` + # Quote $INPUT_DIR so we can use it in a regexp. + # FIXME: really we should care about more than `.' and `\'. + input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'` + + while test "$#" -ne 0; do + from="$1" + # Handle y_tab.c and y_tab.h output by DOS + if test $y_tab_nodot = "yes"; then + if test $from = "y.tab.c"; then + from="y_tab.c" + else + if test $from = "y.tab.h"; then + from="y_tab.h" + fi + fi + fi + if test -f "$from"; then + # If $2 is an absolute path name, then just use that, + # otherwise prepend `../'. + case "$2" in + [\\/]* | ?:[\\/]*) target="$2";; + *) target="../$2";; + esac + + # Edit out `#line' or `#' directives. + # + # We don't want the resulting debug information to point at + # an absolute srcdir; it is better for it to just mention the + # .y file with no path. + # + # We want to use the real output file name, not yy.lex.c for + # instance. + # + # We want the include guards to be adjusted too. + FROM=`echo "$from" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` + TARGET=`echo "$2" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` + sed "/^#/{s,$input_rx,,;s,$from,$2,;s,$FORM,$TO,;}" "$from" >"$target" || + status=$? + else + # A missing file is only an error for the first file. This + # is a blatant hack to let us support using "yacc -d". If -d + # is not specified, we don't want an error when the header + # file is "missing". + if test $first = yes; then + status=1 + fi + fi + shift + shift + first=no + done +else + status=$? +fi + +# Remove the directory. +cd .. +rm -rf $dirname + +exit $status diff --git a/tests/.cvsignore b/tests/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/tests/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/tests/ChangeLog b/tests/ChangeLog new file mode 100644 index 00000000..024c7c8b --- /dev/null +++ b/tests/ChangeLog @@ -0,0 +1,126 @@ +2005-07-21 Ulrich Drepper + + * testfile18.bz2: New file. + * run-elflint-test.sh: New file. + * Makefile.am (TESTS): Add run-elflint-test.sh. + (EXTRA_DIST): Add run-elflint-test.sh and testfile18.bz2. + +2005-05-24 Ulrich Drepper + + * get-files.c (main): Use correct format specifier. + +2005-05-21 Ulrich Drepper + + * Makefile.am: Add -Wextra to CFLAGS. + * get-files.c: Remove warning this produced. + * get-pubnames.c: Likewise. + * newfile.c: Likewise. + * newscn.c: Likewise. + * scnnames.c: Likewise. + * showptable.c: Likewise. + * test-nlist.c: Likewise. + * update1.c: Likewise. + * update2.c: Likewise. + * update3.c: Likewise. + * update4.c: Likewise. + +2005-05-08 Ulrich Drepper + + * run-line2addr.sh: Remove testfile14 at the end. + + * run-strip-test.sh: Remove deubinfo test input file as well. + + * Makefile.am (EXTRA_DIST): Newly added files incorrectly used + .bz, not .bz2. + +2005-05-03 Roland McGrath + + * run-strip-test.sh: Use variables for test file names. + Optionally produce separate debug file and check it. + * run-strip-test2.sh: Use run-strip-test.sh via ., no duplication. + * run-strip-test3.sh: Likewise. + * run-strip-test4.sh: New file. + * run-strip-test5.sh: New file. + * run-strip-test6.sh: New file. + * testfile15.bz: New file. + * testfile15.debug.bz: New file. + * testfile16.bz: New file. + * testfile16.debug.bz: New file. + * testfile17.bz: New file. + * testfile17.debug.bz: New file. + * Makefile.am (TESTS, EXTRA_DIST): Add them. + +2005-04-25 Ulrich Drepper + + * run-line2addr.sh: Also use testfile14. Adjust for correct + return of multiple matches. + * testfile14.bz2: New file. + * Makefile.am (EXTRA_DIST): Add testfile14.bz2. + + * show-abbrev.c (main): Adjust for dwarf_getabbrev interface change. + +2005-04-04 Roland McGrath + + * line2addr.c (main): Initialize LINES and NLINES before calling + dwarf_getsrc_file, and free LINES afterwards. + + * allfcts.c (main): Use size_t for CUHL. + +2005-04-04 Ulrich Drepper + + * line2addr.c: New file. + * run-line2addr.sh: New file. + * Makefile.am: Add rules to build, run, and distribute new code. + +2005-04-02 Ulrich Drepper + + * allfcts.c: New file. + * run-allfcts.sh: New file. + * Makefile.am: Add rules to build, run, and distribute new code. + +2005-02-05 Ulrich Drepper + + * Makefile.am [MUDFLAP] (AM_CFLAGS): Add -fmudflap. Link all test + programs with -lmudflap. + +2004-09-25 Ulrich Drepper + + * asm-tst4.c (main): Add LD_LIBRARY_PATH to elflint invocation. + * asm-tst5.c (main): Likewise. + * asm-tst6.c (main): Likewise. + +2004-01-17 Ulrich Drepper + + * Makefile.am: Support building with mudflap. + +2004-01-12 Ulrich Drepper + + * get-aranges.c: Rewrite to use libdw. + * Makefile.am: Reenable get-aranges test. + +2004-01-11 Ulrich Drepper + + * get-lines.c: New file. + * get-files.c: Adjust for libdw. + * run-get-files.sh: Adjust expected result. + * run-get-lines.sh: Likewise. + * Makefile.am: Run get-lines test. Don't run get-aranges and + get-ciefde test for now. + + * show-abbrev.c: Adjust call to dwarf_getabbrevattr after interface + change. Print attribute offset information. + * run-show-abbrev.sh: Adjust expected output. + +2004-01-09 Ulrich Drepper + + * show-abbrev.c: Adjust call to dwarf_nextcu after interface change. + * show-die-info.c: Likewise. + * run-show-die-info.sh: Adjust expected output. + +2003-08-13 Ulrich Drepper + + * Makefile.in: Depend on libebl.a, not libebl.so. + +2003-08-11 Ulrich Drepper + + * Moved to CVS archive. diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 00000000..674ed570 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,113 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 1996-2002, 2003, 2004, 2005 Red Hat, Inc. +## +## This program is Open Source software; you can redistribute it and/or +## modify it under the terms of the Open Software License version 1.0 as +## published by the Open Source Initiative. +## +## You should have received a copy of the Open Software License along +## with this program; if not, you may obtain a copy of the Open Software +## License version 1.0 from http://www.opensource.org/licenses/osl.php or +## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +## 3001 King Ranch Road, Ukiah, CA 95482. +## +DEFS = -DHAVE_CONFIG_H -D_GNU_SOURCE +if MUDFLAP +AM_CFLAGS = -Wall -Werror -Wextra -std=gnu99 -fmudflap\ + $(if $($(*F)_no_Wformat),-Wno-format,-Wformat=2) +else +AM_CFLAGS = -Wall -Werror -Wextra -std=gnu99 \ + $(if $($(*F)_no_Wformat),-Wno-format,-Wformat=2) +AM_LDFLAGS = -Wl,-rpath,\$$ORIGIN/../libasm:\$$ORIGIN/../libdw:\$$ORIGIN/../libebl:\$$ORIGIN/../libelf +endif +INCLUDES = -I$(top_srcdir)/libasm -I$(top_srcdir)/libdw \ + -I$(top_srcdir)/libebl -I$(top_srcdir)/libelf \ + -I$(top_srcdir)/lib -I.. + +noinst_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ + showptable update1 update2 update3 update4 test-nlist \ + show-die-info get-files get-lines get-pubnames \ + get-aranges allfcts line2addr \ + show-abbrev hash asm-tst1 asm-tst2 asm-tst3 \ + asm-tst4 asm-tst5 asm-tst6 asm-tst7 asm-tst8 asm-tst9 \ + msg_tst newscn ecp +# get-ciefde + +TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \ + update1 update2 update3 update4 \ + run-show-die-info.sh run-get-files.sh run-get-lines.sh \ + run-get-pubnames.sh run-get-aranges.sh run-allfcts.sh \ + run-show-abbrev.sh run-line2addr.sh hash asm-tst1 asm-tst2 \ + asm-tst3 asm-tst4 asm-tst5 asm-tst6 asm-tst7 asm-tst8 asm-tst9 \ + msg_tst newscn run-strip-test.sh run-strip-test2.sh \ + run-strip-test3.sh run-strip-test4.sh run-strip-test5.sh \ + run-strip-test6.sh run-ecp-test.sh run-ecp-test2.sh \ + run-elflint-test.sh +# run-show-ciefde.sh + +EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ + run-show-die-info.sh run-get-files.sh run-get-lines.sh \ + run-get-pubnames.sh run-get-aranges.sh \ + run-show-ciefde.sh run-show-abbrev.sh run-strip-test.sh \ + run-strip-test2.sh run-ecp-test.sh run-ecp-test2.sh \ + testfile.bz2 testfile2.bz2 testfile3.bz2 testfile4.bz2 \ + testfile5.bz2 testfile6.bz2 testfile7.bz2 testfile8.bz2 \ + testfile9.bz2 testfile10.bz2 testfile11.bz2 testfile12.bz2 \ + testfile13.bz2 run-strip-test3.sh run-allfcts.sh \ + run-line2addr.sh run-elflint-test.sh testfile14.bz2 \ + run-strip-test4.sh run-strip-test5.sh run-strip-test6.sh \ + testfile15.bz2 testfile15.debug.bz2 \ + testfile16.bz2 testfile16.debug.bz2 \ + testfile17.bz2 testfile17.debug.bz2 \ + testfile18.bz2 + +if MUDFLAP +libdw = ../libdw/libdw.a +libelf = ../libelf/libelf.a +libasm = ../libasm/libasm.a +libmudflap = -lmudflap +else +libdw = ../libdw/libdw.so +libelf = ../libelf/libelf.so +libasm = ../libasm/libasm.so +endif +libebl = ../libebl/libebl.a + +arextract_LDADD = $(libelf) $(libmudflap) +arsymtest_LDADD = $(libelf) $(libmudflap) +newfile_LDADD = $(libelf) $(libmudflap) +saridx_LDADD = $(libelf) $(libmudflap) +scnnames_LDADD = $(libelf) $(libmudflap) +sectiondump_LDADD = $(libelf) $(libmudflap) +showptable_LDADD = $(libelf) $(libmudflap) +hash_LDADD = $(libelf) $(libmudflap) +test_nlist_LDADD = $(libelf) $(libmudflap) +msg_tst_LDADD = $(libelf) $(libmudflap) +newscn_LDADD = $(libelf) $(libmudflap) +ecp_LDADD = $(libelf) $(libmudflap) +update1_LDADD = $(libelf) $(libmudflap) +update2_LDADD = $(libelf) $(libmudflap) +update3_LDADD = $(libebl) $(libelf) $(libmudflap) +update4_LDADD = $(libebl) $(libelf) $(libmudflap) +show_die_info_LDADD = $(libdw) $(libelf) $(libmudflap) +get_pubnames_LDADD = $(libdw) $(libelf) $(libmudflap) +show_abbrev_LDADD = $(libdw) $(libelf) $(libmudflap) +get_lines_LDADD = $(libdw) $(libelf) $(libmudflap) +get_files_LDADD = $(libdw) $(libelf) $(libmudflap) +get_aranges_LDADD = $(libdw) $(libelf) $(libmudflap) +allfcts_LDADD = $(libdw) $(libelf) $(libmudflap) +line2addr_no_Wformat = yes +line2addr_LDADD = $(libdw) $(libelf) $(libmudflap) +#show_ciefde_LDADD = ../libdwarf/libdwarf.so $(libelf) $(libmudflap) +asm_tst1_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) +asm_tst2_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) +asm_tst3_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) +asm_tst4_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) +asm_tst5_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) +asm_tst6_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) +asm_tst7_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) +asm_tst8_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) +asm_tst9_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) + +CLEANFILES = xxx diff --git a/tests/allfcts.c b/tests/allfcts.c new file mode 100644 index 00000000..147ebc2c --- /dev/null +++ b/tests/allfcts.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include + + +static int +cb (Dwarf_Func *func, void *arg __attribute__ ((unused))) +{ + const char *file = dwarf_func_file (func); + int line = -1; + dwarf_func_line (func, &line); + const char *fct = dwarf_func_name (func); + + printf ("%s:%d:%s\n", file, line, fct); + + return DWARF_CB_OK; +} + + +int +main (int argc, char *argv[]) +{ + for (int i = 1; i < argc; ++i) + { + int fd = open (argv[i], O_RDONLY); + + Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg != NULL) + { + Dwarf_Off off = 0; + size_t cuhl; + Dwarf_Off noff; + + while (dwarf_nextcu (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0) + { + Dwarf_Die die_mem; + Dwarf_Die *die = dwarf_offdie (dbg, off + cuhl, &die_mem); + + (void) dwarf_getfuncs (die, cb, NULL, 0); + + off = noff; + } + + dwarf_end (dbg); + } + + close (fd); + } +} diff --git a/tests/arextract.c b/tests/arextract.c new file mode 100644 index 00000000..aa86fb4e --- /dev/null +++ b/tests/arextract.c @@ -0,0 +1,155 @@ +/* Copyright (C) 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + + +int +main (int argc, char *argv[]) +{ + int fd; + Elf *elf; + Elf *subelf; + Elf_Cmd cmd; + off_t offset; + size_t todo; + + if (argc < 4) + exit (1); + + /* Open the archive. */ + fd = open (argv[1], O_RDONLY); + if (fd == -1) + { + printf ("Cannot open input file: %m"); + exit (1); + } + + /* Set the ELF version. */ + elf_version (EV_CURRENT); + + /* Create an ELF descriptor. */ + cmd = ELF_C_READ; + elf = elf_begin (fd, cmd, NULL); + if (elf == NULL) + { + printf ("Cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* If it is no archive punt. */ + if (elf_kind (elf) != ELF_K_AR) + { + printf ("`%s' is no archive\n", argv[1]); + exit (1); + } + + /* Get the elements of the archive one after the other. */ + while ((subelf = elf_begin (fd, cmd, elf)) != NULL) + { + /* The the header for this element. */ + Elf_Arhdr *arhdr = elf_getarhdr (subelf); + + if (arhdr == NULL) + { + printf ("cannot get arhdr: %s\n", elf_errmsg (-1)); + exit (1); + } + + if (strcmp (arhdr->ar_name, argv[2]) == 0) + { + int outfd; + + /* Get the offset of the file in the archive. */ + offset = elf_getbase (subelf); + if (offset == -1) + { + printf ("\ +Failed to get base address for the archive element: %s\n", + elf_errmsg (-1)); + exit (1); + } + + /* Open the output file. */ + outfd = open (argv[3], O_CREAT | O_TRUNC | O_RDWR, 0666); + if (outfd == -1) + { + printf ("cannot open output file: %m"); + exit (1); + } + + /* Now write out the data. */ + todo = arhdr->ar_size; + while (todo > 0) + { + char buf[1024]; + ssize_t n = pread (fd, buf, MIN (sizeof buf, todo), offset); + if (n == 0) + break; + + if (write (outfd, buf, n) != n) + { + puts ("Writing output failed"); + exit (1); + } + + offset += n; + todo -= n; + } + + /* Check whether all the date was read and written out. */ + if (todo != 0) + { + puts ("Reading archive member failed."); + exit (1); + } + + /* Close the descriptors. */ + if (elf_end (subelf) != 0 || elf_end (elf) != 0) + { + printf ("Freeing ELF descriptors failed: %s", elf_errmsg (-1)); + exit (1); + } + + close (outfd); + close (fd); + + /* All went well. */ + exit (0); + } + + /* Get next archive element. */ + cmd = elf_next (subelf); + if (elf_end (subelf) != 0) + { + printf ("error while freeing sub-ELF descriptor: %s\n", + elf_errmsg (-1)); + exit (1); + } + } + + /* When we reach this point we haven't found the given file in the + archive. */ + printf ("File `%s' not found in archive\n", argv[2]); + exit (1); +} diff --git a/tests/arsymtest.c b/tests/arsymtest.c new file mode 100644 index 00000000..e4c2cf09 --- /dev/null +++ b/tests/arsymtest.c @@ -0,0 +1,132 @@ +/* Copyright (C) 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include + +#include +#include +#include +#include +#include + + +int +main (int argc, char *argv[]) +{ + int fd; + FILE *fp; + Elf *elf; + Elf_Arsym *arsym; + size_t narsym; + + if (argc < 3) + exit (1); + + /* Open the archive. */ + fd = open (argv[1], O_RDONLY); + if (fd == -1) + { + printf ("Cannot open input file: %m"); + exit (1); + } + + /* Open the output file. */ + fp = fopen (argv[2], "w"); + if (fp == NULL) + { + printf ("Cannot open output file: %m"); + exit (1); + } + + /* Set the ELF version. */ + elf_version (EV_CURRENT); + + /* Create an ELF descriptor. */ + elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) + { + printf ("Cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* If it is no archive punt. */ + if (elf_kind (elf) != ELF_K_AR) + { + printf ("`%s' is no archive\n", argv[1]); + exit (1); + } + + /* Now get the index of the archive. */ + arsym = elf_getarsym (elf, &narsym); + if (arsym == NULL) + { + printf ("Cannot get archive index: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* If there is no element in the index do nothing. There always is + an empty entry at the end which is included in the count and + which we want to skip. */ + if (narsym-- > 1) + while (narsym-- > 0) + { + Elf *subelf; + Elf_Arhdr *arhdr; + + if (elf_rand (elf, arsym[narsym].as_off) != arsym[narsym].as_off) + { + printf ("random access for symbol `%s' fails: %s\n", + arsym[narsym].as_name, elf_errmsg (-1)); + exit (1); + } + + subelf = elf_begin (fd, ELF_C_READ, elf); + if (subelf == NULL) + { + printf ("Cannot create ELF descriptor for archive member: %s\n", + elf_errmsg (-1)); + exit (1); + } + + arhdr = elf_getarhdr (subelf); + if (arhdr == NULL) + { + printf ("Cannot get archive header for element `%s': %s\n", + arsym[narsym].as_name, elf_errmsg (-1)); + exit (1); + } + + /* Now print what we actually want. */ + fprintf (fp, "%s in %s\n", arsym[narsym].as_name, arhdr->ar_name); + + /* Free the ELF descriptor. */ + if (elf_end (subelf) != 0) + { + printf ("Error while freeing subELF descriptor: %s\n", + elf_errmsg (-1)); + exit (1); + } + } + + /* Free the ELF descriptor. */ + if (elf_end (elf) != 0) + { + printf ("Error while freeing ELF descriptor: %s\n", elf_errmsg (-1)); + exit (1); + } + + close (fd); + fclose (fp); + + return 0; +} diff --git a/tests/asm-tst1.c b/tests/asm-tst1.c new file mode 100644 index 00000000..b76930d0 --- /dev/null +++ b/tests/asm-tst1.c @@ -0,0 +1,239 @@ +/* Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include + + +static const char fname[] = "asm-tst1-out.o"; + + +static const GElf_Ehdr expected_ehdr = + { + .e_ident = { [EI_MAG0] = ELFMAG0, + [EI_MAG1] = ELFMAG1, + [EI_MAG2] = ELFMAG2, + [EI_MAG3] = ELFMAG3, + [EI_CLASS] = ELFCLASS32, + [EI_DATA] = ELFDATA2LSB, + [EI_VERSION] = EV_CURRENT }, + .e_type = ET_REL, + .e_machine = EM_386, + .e_version = EV_CURRENT, + .e_shoff = 88, + .e_ehsize = sizeof (Elf32_Ehdr), + .e_shentsize = sizeof (Elf32_Shdr), + .e_shnum = 4, + .e_shstrndx = 3 + }; + + +static const char *scnnames[4] = + { + [0] = "", + [1] = ".text", + [2] = ".data", + [3] = ".shstrtab" + }; + + +int +main (void) +{ + AsmCtx_t *ctx; + AsmScn_t *scn1; + AsmScn_t *scn2; + int fd; + Elf *elf; + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + int result = 0; + size_t cnt; + + elf_version (EV_CURRENT); + + ctx = asm_begin (fname, false, EM_386, ELFCLASS32, ELFDATA2LSB); + if (ctx == NULL) + { + printf ("cannot create assembler context: %s\n", asm_errmsg (-1)); + return 1; + } + + /* Create two sections. */ + scn1 = asm_newscn (ctx, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); + scn2 = asm_newscn (ctx, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + if (scn1 == NULL || scn2 == NULL) + { + printf ("cannot create section in output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Special alignment for the .text section. */ + if (asm_align (scn1, 32) != 0) + { + printf ("cannot align .text section: %s\n", asm_errmsg (-1)); + result = 1; + } + + /* Create the output file. */ + if (asm_end (ctx) != 0) + { + printf ("cannot create output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Check the file. */ + fd = open (fname, O_RDONLY); + if (fd == -1) + { + printf ("cannot open generated file: %m\n"); + result = 1; + goto out; + } + + elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) + { + printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + result = 1; + goto out_close; + } + if (elf_kind (elf) != ELF_K_ELF) + { + puts ("not a valid ELF file"); + result = 1; + goto out_close2; + } + + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + printf ("cannot get ELF header: %s\n", elf_errmsg (-1)); + result = 1; + goto out_close2; + } + + if (memcmp (ehdr, &expected_ehdr, sizeof (GElf_Ehdr)) != 0) + { + puts ("ELF header does not match"); + result = 1; + goto out_close2; + } + + for (cnt = 1; cnt < 4; ++cnt) + { + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + scn = elf_getscn (elf, cnt); + if (scn == NULL) + { + printf ("cannot get section %Zd: %s\n", cnt, elf_errmsg (-1)); + result = 1; + continue; + } + + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + { + printf ("cannot get section header for section %Zd: %s\n", + cnt, elf_errmsg (-1)); + result = 1; + continue; + } + + if (strcmp (elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name), + scnnames[cnt]) != 0) + { + printf ("section %Zd's name differs: %s vs %s\n", cnt, + elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name), + scnnames[cnt]); + result = 1; + } + + if (shdr->sh_type != (cnt == 3 ? SHT_STRTAB : SHT_PROGBITS)) + { + printf ("section %Zd's type differs\n", cnt); + result = 1; + } + + if ((cnt == 1 && shdr->sh_flags != (SHF_ALLOC | SHF_EXECINSTR)) + || (cnt == 2 && shdr->sh_flags != (SHF_ALLOC | SHF_WRITE)) + || (cnt == 3 && shdr->sh_flags != 0)) + { + printf ("section %Zd's flags differs\n", cnt); + result = 1; + } + + if (shdr->sh_addr != 0) + { + printf ("section %Zd's address differs\n", cnt); + result = 1; + } + + if (shdr->sh_offset != ((sizeof (Elf32_Ehdr) + 31) & ~31)) + { + printf ("section %Zd's offset differs\n", cnt); + result = 1; + } + + if ((cnt != 3 && shdr->sh_size != 0) + || (cnt == 3 && shdr->sh_size != 23)) + { + printf ("section %Zd's size differs\n", cnt); + result = 1; + } + + if (shdr->sh_link != 0) + { + printf ("section %Zd's link differs\n", cnt); + result = 1; + } + + if (shdr->sh_info != 0) + { + printf ("section %Zd's info differs\n", cnt); + result = 1; + } + + if ((cnt == 1 && shdr->sh_addralign != 32) + || (cnt != 1 && shdr->sh_addralign != 1)) + { + printf ("section %Zd's addralign differs\n", cnt); + result = 1; + } + + if (shdr->sh_entsize != 0) + { + printf ("section %Zd's entsize differs\n", cnt); + result = 1; + } + } + + out_close2: + elf_end (elf); + out_close: + close (fd); + out: + /* We don't need the file anymore. */ + unlink (fname); + + return result; +} diff --git a/tests/asm-tst2.c b/tests/asm-tst2.c new file mode 100644 index 00000000..a309976d --- /dev/null +++ b/tests/asm-tst2.c @@ -0,0 +1,261 @@ +/* Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include + + +static const char fname[] = "asm-tst2-out.o"; + + +static const GElf_Ehdr expected_ehdr = + { + .e_ident = { [EI_MAG0] = ELFMAG0, + [EI_MAG1] = ELFMAG1, + [EI_MAG2] = ELFMAG2, + [EI_MAG3] = ELFMAG3, + [EI_CLASS] = ELFCLASS32, + [EI_DATA] = ELFDATA2LSB, + [EI_VERSION] = EV_CURRENT }, + .e_type = ET_REL, + .e_machine = EM_386, + .e_version = EV_CURRENT, + .e_shoff = 96, + .e_ehsize = sizeof (Elf32_Ehdr), + .e_shentsize = sizeof (Elf32_Shdr), + .e_shnum = 3, + .e_shstrndx = 2 + }; + + +static const char *scnnames[3] = + { + [0] = "", + [1] = ".data", + [2] = ".shstrtab" + }; + + +int +main (void) +{ + AsmCtx_t *ctx; + AsmScn_t *scn1; + AsmScn_t *scn2; + int result = 0; + int fd; + Elf *elf; + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + size_t cnt; + + elf_version (EV_CURRENT); + + ctx = asm_begin (fname, false, EM_386, ELFCLASS32, ELFDATA2LSB); + if (ctx == NULL) + { + printf ("cannot create assembler context: %s\n", asm_errmsg (-1)); + return 1; + } + + /* Create two sections. */ + scn1 = asm_newscn (ctx, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + scn2 = asm_newsubscn (scn1, 1); + if (scn1 == NULL || scn2 == NULL) + { + printf ("cannot create section in output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Special alignment for the .text section. */ + if (asm_align (scn1, 16) != 0) + { + printf ("cannot align .text section: %s\n", asm_errmsg (-1)); + result = 1; + } + + /* Add a few strings. */ + if (asm_addstrz (scn1, "one", 4) != 0) + { + printf ("cannot insert first string: %s\n", asm_errmsg (-1)); + result = 1; + } + if (asm_addstrz (scn2, "three", 0) != 0) + { + printf ("cannot insert second string: %s\n", asm_errmsg (-1)); + result = 1; + } + if (asm_addstrz (scn1, "two", 4) != 0) + { + printf ("cannot insert third string: %s\n", asm_errmsg (-1)); + result = 1; + } + + /* Create the output file. */ + if (asm_end (ctx) != 0) + { + printf ("cannot create output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Check the file. */ + fd = open (fname, O_RDONLY); + if (fd == -1) + { + printf ("cannot open generated file: %m\n"); + result = 1; + goto out; + } + + elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) + { + printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + result = 1; + goto out_close; + } + if (elf_kind (elf) != ELF_K_ELF) + { + puts ("not a valid ELF file"); + result = 1; + goto out_close2; + } + + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + printf ("cannot get ELF header: %s\n", elf_errmsg (-1)); + result = 1; + goto out_close2; + } + + if (memcmp (ehdr, &expected_ehdr, sizeof (GElf_Ehdr)) != 0) + { + puts ("ELF header does not match"); + result = 1; + goto out_close2; + } + + for (cnt = 1; cnt < 3; ++cnt) + { + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + scn = elf_getscn (elf, cnt); + if (scn == NULL) + { + printf ("cannot get section %Zd: %s\n", cnt, elf_errmsg (-1)); + result = 1; + continue; + } + + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + { + printf ("cannot get section header for section %Zd: %s\n", + cnt, elf_errmsg (-1)); + result = 1; + continue; + } + + if (strcmp (elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name), + scnnames[cnt]) != 0) + { + printf ("section %Zd's name differs: %s vs %s\n", cnt, + elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name), + scnnames[cnt]); + result = 1; + } + + if (shdr->sh_type != (cnt == 2 ? SHT_STRTAB : SHT_PROGBITS)) + { + printf ("section %Zd's type differs\n", cnt); + result = 1; + } + + if ((cnt == 1 && shdr->sh_flags != (SHF_ALLOC | SHF_WRITE)) + || (cnt == 2 && shdr->sh_flags != 0)) + { + printf ("section %Zd's flags differs\n", cnt); + result = 1; + } + + if (shdr->sh_addr != 0) + { + printf ("section %Zd's address differs\n", cnt); + result = 1; + } + + if ((cnt == 1 && shdr->sh_offset != ((sizeof (Elf32_Ehdr) + 15) & ~15)) + || (cnt == 2 + && shdr->sh_offset != (((sizeof (Elf32_Ehdr) + 15) & ~15) + + strlen ("one") + 1 + + strlen ("two") + 1 + + strlen ("three") + 1))) + { + printf ("section %Zd's offset differs\n", cnt); + result = 1; + } + + if ((cnt == 1 && shdr->sh_size != (strlen ("one") + 1 + + strlen ("two") + 1 + + strlen ("three") + 1)) + || (cnt == 2 && shdr->sh_size != 17)) + { + printf ("section %Zd's size differs\n", cnt); + result = 1; + } + + if (shdr->sh_link != 0) + { + printf ("section %Zd's link differs\n", cnt); + result = 1; + } + + if (shdr->sh_info != 0) + { + printf ("section %Zd's info differs\n", cnt); + result = 1; + } + + if ((cnt == 1 && shdr->sh_addralign != 16) + || (cnt != 1 && shdr->sh_addralign != 1)) + { + printf ("section %Zd's addralign differs\n", cnt); + result = 1; + } + + if (shdr->sh_entsize != 0) + { + printf ("section %Zd's entsize differs\n", cnt); + result = 1; + } + } + + out_close2: + elf_end (elf); + out_close: + close (fd); + out: + /* We don't need the file anymore. */ + unlink (fname); + + return result; +} diff --git a/tests/asm-tst3.c b/tests/asm-tst3.c new file mode 100644 index 00000000..fb79ea78 --- /dev/null +++ b/tests/asm-tst3.c @@ -0,0 +1,322 @@ +/* Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include + + +static const char fname[] = "asm-tst3-out.o"; + + +static const char *scnnames[5] = + { + [0] = "", + [1] = ".data", + [2] = ".strtab", + [3] = ".symtab", + [4] = ".shstrtab" + }; + + +static unsigned int scntypes[5] = + { + [0] = SHT_NULL, + [1] = SHT_PROGBITS, + [2] = SHT_STRTAB, + [3] = SHT_SYMTAB, + [4] = SHT_STRTAB + }; + + +int +main (void) +{ + AsmCtx_t *ctx; + AsmScn_t *scn1; + AsmScn_t *scn2; + int result = 0; + int fd; + Elf *elf; + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + size_t cnt; + + elf_version (EV_CURRENT); + + ctx = asm_begin (fname, false, EM_386, ELFCLASS32, ELFDATA2LSB); + if (ctx == NULL) + { + printf ("cannot create assembler context: %s\n", asm_errmsg (-1)); + return 1; + } + + /* Create two sections. */ + scn1 = asm_newscn (ctx, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + scn2 = asm_newsubscn (scn1, 1); + if (scn1 == NULL || scn2 == NULL) + { + printf ("cannot create section in output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Special alignment for the .text section. */ + if (asm_align (scn1, 16) != 0) + { + printf ("cannot align .text section: %s\n", asm_errmsg (-1)); + result = 1; + } + + /* Add a few strings with names. */ + if (asm_newsym (scn1, "one", 4, STT_OBJECT, STB_GLOBAL) == NULL) + { + printf ("cannot create first name: %s\n", asm_errmsg (-1)); + result = 1; + } + if (asm_addstrz (scn1, "one", 4) != 0) + { + printf ("cannot insert first string: %s\n", asm_errmsg (-1)); + result = 1; + } + if (asm_newsym (scn2, "three", 6, STT_OBJECT, STB_WEAK) == NULL) + { + printf ("cannot create second name: %s\n", asm_errmsg (-1)); + result = 1; + } + if (asm_addstrz (scn2, "three", 0) != 0) + { + printf ("cannot insert second string: %s\n", asm_errmsg (-1)); + result = 1; + } + if (asm_newsym (scn1, "two", 4, STT_OBJECT, STB_LOCAL) == NULL) + { + printf ("cannot create third name: %s\n", asm_errmsg (-1)); + result = 1; + } + if (asm_addstrz (scn1, "two", 4) != 0) + { + printf ("cannot insert third string: %s\n", asm_errmsg (-1)); + result = 1; + } + + /* Create the output file. */ + if (asm_end (ctx) != 0) + { + printf ("cannot create output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Check the file. */ + fd = open (fname, O_RDONLY); + if (fd == -1) + { + printf ("cannot open generated file: %m\n"); + result = 1; + goto out; + } + + elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) + { + printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + result = 1; + goto out_close; + } + if (elf_kind (elf) != ELF_K_ELF) + { + puts ("not a valid ELF file"); + result = 1; + goto out_close2; + } + + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + printf ("cannot get ELF header: %s\n", elf_errmsg (-1)); + result = 1; + goto out_close2; + } + + for (cnt = 1; cnt < 5; ++cnt) + { + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + scn = elf_getscn (elf, cnt); + if (scn == NULL) + { + printf ("cannot get section %Zd: %s\n", cnt, elf_errmsg (-1)); + result = 1; + continue; + } + + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + { + printf ("cannot get section header for section %Zd: %s\n", + cnt, elf_errmsg (-1)); + result = 1; + continue; + } + + if (strcmp (elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name), + scnnames[cnt]) != 0) + { + printf ("section %Zd's name differs: %s vs %s\n", cnt, + elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name), + scnnames[cnt]); + result = 1; + } + + if (shdr->sh_type != scntypes[cnt]) + { + printf ("section %Zd's type differs\n", cnt); + result = 1; + } + + if ((cnt == 1 && shdr->sh_flags != (SHF_ALLOC | SHF_WRITE)) + || (cnt != 1 && shdr->sh_flags != 0)) + { + printf ("section %Zd's flags differs\n", cnt); + result = 1; + } + + if (shdr->sh_addr != 0) + { + printf ("section %Zd's address differs\n", cnt); + result = 1; + } + + if (cnt == 3) + { + Elf_Data *data; + + if (shdr->sh_link != 2) + { + puts ("symbol table has incorrect link"); + result = 1; + } + + data = elf_getdata (scn, NULL); + if (data == NULL) + { + puts ("cannot get data of symbol table"); + result = 1; + } + else + { + size_t inner; + + for (inner = 1; + inner < (shdr->sh_size + / gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT)); + ++inner) + { + GElf_Sym sym_mem; + GElf_Sym *sym; + + sym = gelf_getsym (data, inner, &sym_mem); + if (sym == NULL) + { + printf ("cannot get symbol %zu: %s\n", + inner, elf_errmsg (-1)); + result = 1; + } + else + { + /* The order of the third and fourth entry depends + on how the hash table is organized. */ + static const char *names[4] = + { + [0] = "", + [1] = "two", + [2] = "one", + [3] = "three" + }; + static const int info[4] = + { + [0] = GELF_ST_INFO (STB_LOCAL, STT_NOTYPE), + [1] = GELF_ST_INFO (STB_LOCAL, STT_OBJECT), + [2] = GELF_ST_INFO (STB_GLOBAL, STT_OBJECT), + [3] = GELF_ST_INFO (STB_WEAK, STT_OBJECT) + }; + static const unsigned value[4] = + { + [0] = 0, + [1] = 4, + [2] = 0, + [3] = 8 + }; + + if (strcmp (names[inner], + elf_strptr (elf, shdr->sh_link, + sym->st_name)) != 0) + { + printf ("symbol %zu has different name\n", inner); + result = 1; + } + + if (sym->st_value != value[inner]) + { + printf ("symbol %zu has wrong value\n", inner); + result = 1; + } + + if (sym->st_other != 0) + { + printf ("symbol %zu has wrong other info\n", inner); + result = 1; + } + + if (sym->st_shndx != 1) + { + printf ("symbol %zu has wrong section reference\n", + inner); + result = 1; + } + + if (sym->st_info != info[inner]) + { + printf ("symbol %zu has wrong type or binding\n", + inner); + result = 1; + } + + if ((inner != 3 && sym->st_size != 4) + || (inner == 3 && sym->st_size != 6)) + { + printf ("symbol %zu has wrong size\n", inner); + result = 1; + } + } + } + } + } + } + + out_close2: + elf_end (elf); + out_close: + close (fd); + out: + /* We don't need the file anymore. */ + unlink (fname); + + return result; +} diff --git a/tests/asm-tst4.c b/tests/asm-tst4.c new file mode 100644 index 00000000..29d6485d --- /dev/null +++ b/tests/asm-tst4.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +static const char fname[] = "asm-tst4-out.o"; + + +int +main (void) +{ + AsmCtx_t *ctx; + int result = 0; + size_t cnt; + + elf_version (EV_CURRENT); + + ctx = asm_begin (fname, false, EM_386, ELFCLASS32, ELFDATA2LSB); + if (ctx == NULL) + { + printf ("cannot create assembler context: %s\n", asm_errmsg (-1)); + return 1; + } + + /* Create 66000 sections. */ + for (cnt = 0; cnt < 66000; ++cnt) + { + char buf[20]; + AsmScn_t *scn; + + /* Create a unique name. */ + snprintf (buf, sizeof (buf), ".data.%Zu", cnt); + + /* Create the section. */ + scn = asm_newscn (ctx, buf, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + if (scn == NULL) + { + printf ("cannot create section \"%s\" in output file: %s\n", + buf, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Add some content. */ + if (asm_adduint32 (scn, cnt) != 0) + { + printf ("cannot create content of section \"%s\": %s\n", + buf, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + } + + /* Create the output file. */ + if (asm_end (ctx) != 0) + { + printf ("cannot create output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + if (result == 0) + result = WEXITSTATUS (system ("\ +env LD_LIBRARY_PATH=../libelf ../src/elflint -q asm-tst4-out.o")); + + /* We don't need the file anymore. */ + unlink (fname); + + return result; +} diff --git a/tests/asm-tst5.c b/tests/asm-tst5.c new file mode 100644 index 00000000..4f761aed --- /dev/null +++ b/tests/asm-tst5.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "system.h" + + +static const char fname[] = "asm-tst5-out.o"; + + +int +main (void) +{ + AsmCtx_t *ctx; + int result = 0; + size_t cnt; + + elf_version (EV_CURRENT); + + ctx = asm_begin (fname, false, EM_386, ELFCLASS32, ELFDATA2LSB); + if (ctx == NULL) + { + printf ("cannot create assembler context: %s\n", asm_errmsg (-1)); + return 1; + } + + /* Create 66000 sections. */ + for (cnt = 0; cnt < 66000; ++cnt) + { + char buf[20]; + AsmScn_t *scn; + + /* Create a unique name. */ + snprintf (buf, sizeof (buf), ".data.%Zu", cnt); + + /* Create the section. */ + scn = asm_newscn (ctx, buf, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + if (scn == NULL) + { + printf ("cannot create section \"%s\" in output file: %s\n", + buf, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Add a name. */ + snprintf (buf, sizeof (buf), "%Zu", cnt); + if (asm_newsym (scn, buf, sizeof (uint32_t), STT_OBJECT, + STB_GLOBAL) == NULL) + { + printf ("cannot create symbol \"%s\": %s\n", buf, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Add some content. */ + if (asm_adduint32 (scn, cnt) != 0) + { + printf ("cannot create content of section \"%s\": %s\n", + buf, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + } + + /* Create the output file. */ + if (asm_end (ctx) != 0) + { + printf ("cannot create output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + if (result == 0) + result = WEXITSTATUS (system ("\ +env LD_LIBRARY_PATH=../libelf ../src/elflint -q asm-tst5-out.o")); + + /* We don't need the file anymore. */ + unlink (fname); + + return result; +} diff --git a/tests/asm-tst6.c b/tests/asm-tst6.c new file mode 100644 index 00000000..ece69bc2 --- /dev/null +++ b/tests/asm-tst6.c @@ -0,0 +1,134 @@ +/* Copyright (C) 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include + +#include + + +static const char fname[] = "asm-tst6-out.o"; + + +int +main (void) +{ + AsmCtx_t *ctx; + int result = 0; + size_t cnt; + + elf_version (EV_CURRENT); + + ctx = asm_begin (fname, false, EM_386, ELFCLASS32, ELFDATA2LSB); + if (ctx == NULL) + { + printf ("cannot create assembler context: %s\n", asm_errmsg (-1)); + return 1; + } + + for (cnt = 0; cnt < 22000; ++cnt) + { + char buf[512]; + AsmScnGrp_t *grp; + AsmScn_t *scn; + AsmSym_t *sym; + + snprintf (buf, sizeof (buf), ".grp%Zu", cnt); + grp = asm_newscngrp (ctx, buf, NULL, 0); + if (grp == NULL) + { + printf ("cannot section group %Zu: %s\n", cnt, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + scn = asm_newscn_ingrp (ctx, ".data", SHT_PROGBITS, + SHF_ALLOC | SHF_WRITE, grp); + if (scn == NULL) + { + printf ("cannot data section for group %Zu: %s\n", + cnt, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Add a name. */ + snprintf (buf, sizeof (buf), "%Zu", cnt); + sym = asm_newsym (scn, buf, sizeof (uint32_t), STT_OBJECT, + STB_GLOBAL); + if (sym == NULL) + { + printf ("cannot create symbol \"%s\": %s\n", buf, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Add some content. */ + if (asm_adduint32 (scn, cnt) != 0) + { + printf ("cannot create content of section \"%s\": %s\n", + buf, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Now we have a symbol, use it as the signature. */ + if (asm_scngrp_newsignature (grp, sym) != 0) + { + printf ("cannot set signature for section group %Zu: %s\n", + cnt, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Create a phony debug info section. */ + scn = asm_newscn_ingrp (ctx, ".stab", SHT_PROGBITS, 0, grp); + if (scn == NULL) + { + printf ("cannot stab section for group %Zu: %s\n", + cnt, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Add some content. */ + if (asm_adduint32 (scn, cnt) != 0) + { + printf ("cannot create content of section \"%s\": %s\n", + buf, asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + } + + /* Create the output file. */ + if (asm_end (ctx) != 0) + { + printf ("cannot create output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + if (result == 0) + result = WEXITSTATUS (system ("\ +env LD_LIBRARY_PATH=../libelf ../src/elflint -q asm-tst6-out.o")); + + /* We don't need the file anymore. */ + unlink (fname); + + return result; +} diff --git a/tests/asm-tst7.c b/tests/asm-tst7.c new file mode 100644 index 00000000..ebd45594 --- /dev/null +++ b/tests/asm-tst7.c @@ -0,0 +1,164 @@ +/* Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include + + +static const char fname[] = "asm-tst7-out.o"; + + +int +main (void) +{ + int result = 0; + size_t cnt; + AsmCtx_t *ctx; + Elf *elf; + int fd; + + elf_version (EV_CURRENT); + + ctx = asm_begin (fname, false, EM_386, ELFCLASS32, ELFDATA2LSB); + if (ctx == NULL) + { + printf ("cannot create assembler context: %s\n", asm_errmsg (-1)); + return 1; + } + + if (asm_newcomsym (ctx, "commsym", 4, 16) == NULL) + { + printf ("cannot create common symbol: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Create the output file. */ + if (asm_end (ctx) != 0) + { + printf ("cannot create output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Check the file. */ + fd = open (fname, O_RDONLY); + if (fd == -1) + { + printf ("cannot open generated file: %m\n"); + result = 1; + goto out; + } + + elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) + { + printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + result = 1; + goto out_close; + } + if (elf_kind (elf) != ELF_K_ELF) + { + puts ("not a valid ELF file"); + result = 1; + goto out_close2; + } + + for (cnt = 1; 1; ++cnt) + { + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + scn = elf_getscn (elf, cnt); + if (scn == NULL) + { + printf ("cannot get section %Zd: %s\n", cnt, elf_errmsg (-1)); + result = 1; + continue; + } + + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + { + printf ("cannot get section header for section %Zd: %s\n", + cnt, elf_errmsg (-1)); + result = 1; + continue; + } + /* We are looking for the symbol table. */ + if (shdr->sh_type != SHT_SYMTAB) + continue; + + for (cnt = 1; cnt< (shdr->sh_size + / gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT)); + ++cnt) + { + GElf_Sym sym_mem; + GElf_Sym *sym; + + if (cnt > 1) + { + puts ("too many symbol"); + result = 1; + break; + } + + sym = gelf_getsym (elf_getdata (scn, NULL), cnt, &sym_mem); + if (sym == NULL) + { + printf ("cannot get symbol %zu: %s\n", cnt, elf_errmsg (-1)); + result = 1; + } + else + { + if (sym->st_shndx != SHN_COMMON) + { + printf ("expected common symbol, got section %u\n", + (unsigned int) sym->st_shndx); + result = 1; + } + + if (sym->st_value != 16) + { + printf ("requested alignment 16, is %" PRIuMAX "\n", + (uintmax_t) sym->st_value); + result = 1; + } + + if (sym->st_size != 4) + { + printf ("requested size 4, is %" PRIuMAX "\n", + (uintmax_t) sym->st_value); + result = 1; + } + } + } + + break; + } + + out_close2: + elf_end (elf); + out_close: + close (fd); + out: + /* We don't need the file anymore. */ + unlink (fname); + + return result; +} diff --git a/tests/asm-tst8.c b/tests/asm-tst8.c new file mode 100644 index 00000000..6ce7c9c0 --- /dev/null +++ b/tests/asm-tst8.c @@ -0,0 +1,172 @@ +/* Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include + + +static const char fname[] = "asm-tst8-out.o"; + + +int +main (void) +{ + int result = 0; + size_t cnt; + AsmCtx_t *ctx; + Elf *elf; + int fd; + + elf_version (EV_CURRENT); + + ctx = asm_begin (fname, false, EM_386, ELFCLASS32, ELFDATA2LSB); + if (ctx == NULL) + { + printf ("cannot create assembler context: %s\n", asm_errmsg (-1)); + return 1; + } + + if (asm_newabssym (ctx, "tst8-out.s", 4, 0xfeedbeef, STT_FILE, STB_LOCAL) + == NULL) + { + printf ("cannot create absolute symbol: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Create the output file. */ + if (asm_end (ctx) != 0) + { + printf ("cannot create output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Check the file. */ + fd = open (fname, O_RDONLY); + if (fd == -1) + { + printf ("cannot open generated file: %m\n"); + result = 1; + goto out; + } + + elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) + { + printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + result = 1; + goto out_close; + } + if (elf_kind (elf) != ELF_K_ELF) + { + puts ("not a valid ELF file"); + result = 1; + goto out_close2; + } + + for (cnt = 1; 1; ++cnt) + { + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + scn = elf_getscn (elf, cnt); + if (scn == NULL) + { + printf ("cannot get section %Zd: %s\n", cnt, elf_errmsg (-1)); + result = 1; + continue; + } + + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + { + printf ("cannot get section header for section %Zd: %s\n", + cnt, elf_errmsg (-1)); + result = 1; + continue; + } + /* We are looking for the symbol table. */ + if (shdr->sh_type != SHT_SYMTAB) + continue; + + for (cnt = 1; cnt< (shdr->sh_size + / gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT)); + ++cnt) + { + GElf_Sym sym_mem; + GElf_Sym *sym; + + if (cnt > 1) + { + puts ("too many symbol"); + result = 1; + break; + } + + sym = gelf_getsym (elf_getdata (scn, NULL), cnt, &sym_mem); + if (sym == NULL) + { + printf ("cannot get symbol %zu: %s\n", cnt, elf_errmsg (-1)); + result = 1; + } + else + { + if (sym->st_shndx != SHN_ABS) + { + printf ("expected common symbol, got section %u\n", + (unsigned int) sym->st_shndx); + result = 1; + } + + if (sym->st_value != 0xfeedbeef) + { + printf ("requested value 0xfeedbeef, is %#" PRIxMAX "\n", + (uintmax_t) sym->st_value); + result = 1; + } + + if (sym->st_size != 4) + { + printf ("requested size 4, is %" PRIuMAX "\n", + (uintmax_t) sym->st_value); + result = 1; + } + + if (GELF_ST_TYPE (sym->st_info) != STT_FILE) + { + printf ("requested type FILE, is %u\n", + (unsigned int) GELF_ST_TYPE (sym->st_info)); + result = 1; + } + } + } + + break; + } + + out_close2: + elf_end (elf); + out_close: + close (fd); + out: + /* We don't need the file anymore. */ + unlink (fname); + + return result; +} diff --git a/tests/asm-tst9.c b/tests/asm-tst9.c new file mode 100644 index 00000000..28bb4787 --- /dev/null +++ b/tests/asm-tst9.c @@ -0,0 +1,318 @@ +/* Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include +#include + + +static const char fname[] = "asm-tst9-out.o"; + + +static int32_t input[] = + { + 0, 1, 129, 510, 2000, 33000, 0x7ffffff, 0x7fffffff + }; +#define ninput (sizeof (input) / sizeof (input[0])) + + +static const GElf_Ehdr expected_ehdr = + { + .e_ident = { [EI_MAG0] = ELFMAG0, + [EI_MAG1] = ELFMAG1, + [EI_MAG2] = ELFMAG2, + [EI_MAG3] = ELFMAG3, + [EI_CLASS] = ELFCLASS32, + [EI_DATA] = ELFDATA2LSB, + [EI_VERSION] = EV_CURRENT }, + .e_type = ET_REL, + .e_machine = EM_386, + .e_version = EV_CURRENT, + .e_shoff = 180, + .e_ehsize = sizeof (Elf32_Ehdr), + .e_shentsize = sizeof (Elf32_Shdr), + .e_shnum = 3, + .e_shstrndx = 2 + }; + + +static const char *scnnames[3] = + { + [0] = "", + [1] = ".data", + [2] = ".shstrtab" + }; + + +static const char expecteddata[] = + { + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7f, + 0x81, 0x01, 0x81, 0x01, 0xff, 0xfe, 0xff, 0xff, 0x0f, 0xff, 0x7e, 0xfe, + 0x03, 0xfe, 0x03, 0x82, 0xfc, 0xff, 0xff, 0x0f, 0x82, 0x7c, 0xd0, 0x0f, + 0xd0, 0x0f, 0xb0, 0xf0, 0xff, 0xff, 0x0f, 0xb0, 0x70, 0xe8, 0x81, 0x02, + 0xe8, 0x81, 0x02, 0x98, 0xfe, 0xfd, 0xff, 0x0f, 0x98, 0xfe, 0x7d, 0xff, + 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0x81, 0x80, 0x80, 0xc0, 0x0f, + 0x81, 0x80, 0x80, 0x40, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, + 0xff, 0x07, 0x81, 0x80, 0x80, 0x80, 0x08, 0x81, 0x80, 0x80, 0x80, 0x78 + }; + + +int +main (void) +{ + AsmCtx_t *ctx; + AsmScn_t *scn; + int result = 0; + int fd; + Elf *elf; + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + size_t cnt; + + elf_version (EV_CURRENT); + + ctx = asm_begin (fname, false, EM_386, ELFCLASS32, ELFDATA2LSB); + if (ctx == NULL) + { + printf ("cannot create assembler context: %s\n", asm_errmsg (-1)); + return 1; + } + + /* Create two sections. */ + scn = asm_newscn (ctx, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + if (scn == NULL) + { + printf ("cannot create section in output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Special alignment for the .text section. */ + if (asm_align (scn, 16) != 0) + { + printf ("cannot align .text section: %s\n", asm_errmsg (-1)); + result = 1; + } + + /* Add a few ULEB128 and SLEB128 numbers. */ + for (cnt = 0; cnt < ninput; ++cnt) + { + if (asm_adduleb128 (scn, input[cnt]) != 0) + { + printf ("cannot insert uleb %" PRIu32 ": %s\n", + (uint32_t) input[cnt], asm_errmsg (-1)); + result = 1; + } + + if (asm_addsleb128 (scn, input[cnt]) != 0) + { + printf ("cannot insert sleb %" PRId32 ": %s\n", + input[cnt], asm_errmsg (-1)); + result = 1; + } + + if (asm_adduleb128 (scn, -input[cnt]) != 0) + { + printf ("cannot insert uleb %" PRIu32 ": %s\n", + (uint32_t) -input[cnt], asm_errmsg (-1)); + result = 1; + } + + if (asm_addsleb128 (scn, -input[cnt]) != 0) + { + printf ("cannot insert sleb %" PRId32 ": %s\n", + -input[cnt], asm_errmsg (-1)); + result = 1; + } + } + + /* Create the output file. */ + if (asm_end (ctx) != 0) + { + printf ("cannot create output file: %s\n", asm_errmsg (-1)); + asm_abort (ctx); + return 1; + } + + /* Check the file. */ + fd = open (fname, O_RDONLY); + if (fd == -1) + { + printf ("cannot open generated file: %m\n"); + result = 1; + goto out; + } + + elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) + { + printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + result = 1; + goto out_close; + } + if (elf_kind (elf) != ELF_K_ELF) + { + puts ("not a valid ELF file"); + result = 1; + goto out_close2; + } + + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + printf ("cannot get ELF header: %s\n", elf_errmsg (-1)); + result = 1; + goto out_close2; + } + + if (memcmp (ehdr, &expected_ehdr, sizeof (GElf_Ehdr)) != 0) + { + puts ("ELF header does not match"); + result = 1; + goto out_close2; + } + + for (cnt = 1; cnt < 3; ++cnt) + { + Elf_Scn *scn; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + scn = elf_getscn (elf, cnt); + if (scn == NULL) + { + printf ("cannot get section %Zd: %s\n", cnt, elf_errmsg (-1)); + result = 1; + continue; + } + + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + { + printf ("cannot get section header for section %Zd: %s\n", + cnt, elf_errmsg (-1)); + result = 1; + continue; + } + + if (strcmp (elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name), + scnnames[cnt]) != 0) + { + printf ("section %Zd's name differs: %s vs %s\n", cnt, + elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name), + scnnames[cnt]); + result = 1; + } + + if (shdr->sh_type != (cnt == 2 ? SHT_STRTAB : SHT_PROGBITS)) + { + printf ("section %Zd's type differs\n", cnt); + result = 1; + } + + if ((cnt == 1 && shdr->sh_flags != (SHF_ALLOC | SHF_WRITE)) + || (cnt == 2 && shdr->sh_flags != 0)) + { + printf ("section %Zd's flags differs\n", cnt); + result = 1; + } + + if (shdr->sh_addr != 0) + { + printf ("section %Zd's address differs\n", cnt); + result = 1; + } + + if ((cnt == 1 && shdr->sh_offset != ((sizeof (Elf32_Ehdr) + 15) & ~15)) + || (cnt == 2 + && shdr->sh_offset != (((sizeof (Elf32_Ehdr) + 15) & ~15) + + sizeof (expecteddata)))) + { + printf ("section %Zd's offset differs\n", cnt); + result = 1; + } + + if ((cnt == 1 && shdr->sh_size != sizeof (expecteddata)) + || (cnt == 2 && shdr->sh_size != 17)) + { + printf ("section %Zd's size differs\n", cnt); + result = 1; + } + + if (shdr->sh_link != 0) + { + printf ("section %Zd's link differs\n", cnt); + result = 1; + } + + if (shdr->sh_info != 0) + { + printf ("section %Zd's info differs\n", cnt); + result = 1; + } + + if ((cnt == 1 && shdr->sh_addralign != 16) + || (cnt != 1 && shdr->sh_addralign != 1)) + { + printf ("section %Zd's addralign differs\n", cnt); + result = 1; + } + + if (shdr->sh_entsize != 0) + { + printf ("section %Zd's entsize differs\n", cnt); + result = 1; + } + + if (cnt == 1) + { + Elf_Data *data = elf_getdata (scn, NULL); + + if (data == NULL) + { + printf ("cannot get data of section %Zd\n", cnt); + result = 1; + } + else + { + if (data->d_size != sizeof (expecteddata)) + { + printf ("data block size of section %Zd wrong: got %Zd, " + "expected 96\n", cnt, data->d_size); + result = 1; + } + + if (memcmp (data->d_buf, expecteddata, sizeof (expecteddata)) + != 0) + { + printf ("data block content of section %Zd wrong\n", cnt); + result = 1; + } + } + } + } + + out_close2: + elf_end (elf); + out_close: + close (fd); + out: + /* We don't need the file anymore. */ + unlink (fname); + + return result; +} diff --git a/tests/ecp.c b/tests/ecp.c new file mode 100644 index 00000000..15bc71cc --- /dev/null +++ b/tests/ecp.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + if (argc < 3) + error (EXIT_FAILURE, 0, "usage: %s FROMNAME TONAME", argv[0]); + + elf_version (EV_CURRENT); + + int infd = open (argv[1], O_RDONLY); + if (infd == -1) + error (EXIT_FAILURE, errno, "cannot open input file '%s'", argv[1]); + + Elf *inelf = elf_begin (infd, ELF_C_READ, NULL); + if (inelf == NULL) + error (EXIT_FAILURE, 0, "problems opening '%s' as ELF file: %s", + argv[1], elf_errmsg (-1)); + + int outfd = creat (argv[2], 0666); + if (outfd == -1) + error (EXIT_FAILURE, errno, "cannot open output file '%s'", argv[2]); + + Elf *outelf = elf_begin (outfd, ELF_C_WRITE, NULL); + if (outelf == NULL) + error (EXIT_FAILURE, 0, "problems opening '%s' as ELF file: %s", + argv[2], elf_errmsg (-1)); + + gelf_newehdr (outelf, gelf_getclass (inelf)); + + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + gelf_update_ehdr (outelf, (ehdr = gelf_getehdr (inelf, &ehdr_mem))); + + if (ehdr->e_phnum > 0) + { + int cnt; + + if (gelf_newphdr (outelf, ehdr->e_phnum) == 0) + error (EXIT_FAILURE, 0, "cannot create program header: %s", + elf_errmsg (-1)); + + for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) + { + GElf_Phdr phdr_mem; + + gelf_update_phdr (outelf, cnt, gelf_getphdr (inelf, cnt, &phdr_mem)); + } + } + + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (inelf, scn)) != NULL) + { + Elf_Scn *newscn = elf_newscn (outelf); + + GElf_Shdr shdr_mem; + gelf_update_shdr (newscn, gelf_getshdr (scn, &shdr_mem)); + + *elf_newdata (newscn) = *elf_getdata (scn, NULL); + } + + elf_flagelf (outelf, ELF_C_SET, ELF_F_LAYOUT); + + if (elf_update (outelf, ELF_C_WRITE) == -1) + error (EXIT_FAILURE, 0, "elf_update failed: %s", elf_errmsg (-1)); + + close (outfd); + + return 0; +} diff --git a/tests/get-aranges.c b/tests/get-aranges.c new file mode 100644 index 00000000..1be76b2d --- /dev/null +++ b/tests/get-aranges.c @@ -0,0 +1,134 @@ +/* Copyright (C) 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include + + +static const Dwarf_Addr testaddr[] = +{ + 0x804842b, 0x804842c, 0x804843c, 0x8048459, 0x804845a, + 0x804845b, 0x804845c, 0x8048460, 0x8048465, 0x8048466, + 0x8048467, 0x8048468, 0x8048470, 0x8048471, 0x8048472 +}; +#define ntestaddr (sizeof (testaddr) / sizeof (testaddr[0])) + + +int +main (int argc, char *argv[]) +{ + int result = 0; + int cnt; + + for (cnt = 1; cnt < argc; ++cnt) + { + int fd = open (argv[cnt], O_RDONLY); + + Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg == NULL) + { + printf ("%s not usable\n", argv[cnt]); + result = 1; + close (fd); + continue; + } + + Dwarf_Aranges *aranges; + size_t naranges; + if (dwarf_getaranges (dbg, &aranges, &naranges) != 0) + printf ("%s: cannot get aranges\n", argv[cnt]); + else + { + for (size_t i = 0; i < ntestaddr; ++i) + { + Dwarf_Arange *found; + + found = dwarf_getarange_addr (aranges, testaddr[i]); + if (found != NULL) + { + Dwarf_Off cu_offset; + + if (dwarf_getarangeinfo (found, NULL, NULL, &cu_offset) != 0) + { + puts ("failed to get CU die offset"); + result = 1; + } + else + { + const char *cuname; + Dwarf_Die cu_die; + + if (dwarf_offdie (dbg, cu_offset, &cu_die) == NULL + || (cuname = dwarf_diename (&cu_die)) == NULL) + { + puts ("failed to get CU die"); + result = 1; + } + else + printf ("CU name: \"%s\"\n", cuname); + } + } + else + printf ("%#llx: not in range\n", + (unsigned long long int) testaddr[i]); + } + + for (size_t i = 0; i < naranges; ++i) + { + Dwarf_Arange *arange = dwarf_onearange (aranges, i); + if (arange == NULL) + { + printf ("cannot get arange %zu: %s\n", i, dwarf_errmsg (-1)); + break; + } + + Dwarf_Addr start; + Dwarf_Word length; + Dwarf_Off cu_offset; + + if (dwarf_getarangeinfo (arange, &start, &length, &cu_offset) + != 0) + { + printf ("cannot get info from aranges[%zu]\n", i); + result = 1; + } + else + { + printf (" [%2zu] start: %#llx, length: %llu, cu: %llu\n", + i, (unsigned long long int) start, + (unsigned long long int) length, + (unsigned long long int) cu_offset); + + const char *cuname; + Dwarf_Die cu_die; + if (dwarf_offdie (dbg, cu_offset, &cu_die) == NULL + || (cuname = dwarf_diename (&cu_die)) == NULL) + { + puts ("failed to get CU die"); + result = 1; + } + else + printf ("CU name: \"%s\"\n", cuname); + } + } + } + + dwarf_end (dbg); + close (fd); + } + + return result; +} diff --git a/tests/get-files.c b/tests/get-files.c new file mode 100644 index 00000000..1294342c --- /dev/null +++ b/tests/get-files.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include + + +int +main (int argc, char *argv[]) +{ + int result = 0; + int cnt; + + for (cnt = 1; cnt < argc; ++cnt) + { + int fd = open (argv[cnt], O_RDONLY); + + Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg == NULL) + { + printf ("%s not usable\n", argv[cnt]); + result = 1; + if (fd != -1) + close (fd); + continue; + } + + Dwarf_Off o = 0; + Dwarf_Off ncu; + Dwarf_Off ao; + size_t cuhl; + uint8_t asz; + uint8_t osz; + while (dwarf_nextcu (dbg, o, &ncu, &cuhl, &ao, &asz, &osz) == 0) + { + printf ("cuhl = %zu, o = %llu, asz = %hhu, osz = %hhu, ncu = %llu\n", + cuhl, (unsigned long long int) ao, + asz, osz, (unsigned long long int) ncu); + + Dwarf_Die die_mem; + Dwarf_Die *die = dwarf_offdie (dbg, o + cuhl, &die_mem); + if (die == NULL) + { + printf ("%s: cannot get CU die\n", argv[cnt]); + result = 1; + break; + } + + Dwarf_Files *files; + size_t nfiles; + if (dwarf_getsrcfiles (die, &files, &nfiles) != 0) + { + printf ("%s: cannot get files\n", argv[cnt]); + result = 1; + break; + } + + for (size_t i = 0; i < nfiles; ++i) + printf (" file[%zu] = \"%s\"\n", i, + dwarf_filesrc (files, i, NULL, NULL)); + + o = ncu; + } + + dwarf_end (dbg); + close (fd); + } + + return result; +} diff --git a/tests/get-lines.c b/tests/get-lines.c new file mode 100644 index 00000000..6a8c0764 --- /dev/null +++ b/tests/get-lines.c @@ -0,0 +1,129 @@ +/* Copyright (C) 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include + + +int +main (int argc, char *argv[]) +{ + int result = 0; + int cnt; + + for (cnt = 1; cnt < argc; ++cnt) + { + int fd = open (argv[cnt], O_RDONLY); + + Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg == NULL) + { + printf ("%s not usable: %s\n", argv[cnt], dwarf_errmsg (-1)); + close (fd); + continue; + } + + Dwarf_Off cuoff = 0; + Dwarf_Off old_cuoff = 0; + size_t hsize; + Dwarf_Off ao; + uint8_t asz; + uint8_t osz; + while (dwarf_nextcu (dbg, cuoff, &cuoff, &hsize, &ao, &asz, &osz) == 0) + { + printf ("cuhl = %zu, o = %llu, asz = %hhu, osz = %hhu, ncu = %llu\n", + hsize, (unsigned long long int) ao, + asz, osz, (unsigned long long int) cuoff); + + /* Get the DIE for the CU. */ + Dwarf_Die die; + if (dwarf_offdie (dbg, old_cuoff + hsize, &die) == NULL) + { + /* Something went wrong. */ + printf ("%s: cannot get CU die\n", argv[cnt]); + result = 1; + break; + } + old_cuoff = cuoff; + + Dwarf_Lines *lb; + size_t nlb; + if (dwarf_getsrclines (&die, &lb, &nlb) != 0) + { + printf ("%s: cannot get lines\n", argv[cnt]); + result = 1; + break; + } + + printf (" %zu lines\n", nlb); + + for (size_t i = 0; i < nlb; ++i) + { + Dwarf_Line *l = dwarf_onesrcline (lb, i); + if (l == NULL) + { + printf ("%s: cannot get individual line\n", argv[cnt]); + result = 1; + break; + } + + Dwarf_Addr addr; + if (dwarf_lineaddr (l, &addr) != 0) + addr = 0; + const char *file = dwarf_linesrc (l, NULL, NULL); + int line; + if (dwarf_lineno (l, &line) != 0) + line = 0; + + printf ("%" PRIx64 ": %s:%d:", (uint64_t) addr, + file ?: "???", line); + + int column; + if (dwarf_linecol (l, &column) != 0) + column = 0; + if (column >= 0) + printf ("%d:", column); + + bool is_stmt; + if (dwarf_linebeginstatement (l, &is_stmt) != 0) + is_stmt = false; + bool end_sequence; + if (dwarf_lineendsequence (l, &end_sequence) != 0) + end_sequence = false; + bool basic_block; + if (dwarf_lineblock (l, &basic_block) != 0) + basic_block = false; + bool prologue_end; + if (dwarf_lineprologueend (l, &prologue_end) != 0) + prologue_end = false; + bool epilogue_begin; + if (dwarf_lineepiloguebegin (l, &epilogue_begin) != 0) + epilogue_begin = false; + + printf (" is_stmt:%s, end_seq:%s, bb:%s, prologue:%s, epilogue:%s\n", + is_stmt ? "yes" : "no", end_sequence ? "yes" : "no", + basic_block ? "yes" : "no", prologue_end ? "yes" : "no", + epilogue_begin ? "yes" : "no"); + } + } + + dwarf_end (dbg); + close (fd); + } + + return result; +} diff --git a/tests/get-pubnames.c b/tests/get-pubnames.c new file mode 100644 index 00000000..e2791a29 --- /dev/null +++ b/tests/get-pubnames.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include + + +static int globcnt; + +static int +callback (Dwarf *dbg, Dwarf_Global *gl, void *arg __attribute__ ((unused))) +{ + int result = DWARF_CB_OK; + + printf (" [%2d] \"%s\", die: %llu, cu: %llu\n", + globcnt++, gl->name, (unsigned long long int) gl->die_offset, + (unsigned long long int) gl->cu_offset); + + Dwarf_Die cu_die; + const char *cuname; + if (dwarf_offdie (dbg, gl->cu_offset, &cu_die) == NULL + || (cuname = dwarf_diename (&cu_die)) == NULL) + { + puts ("failed to get CU die"); + result = DWARF_CB_ABORT; + } + else + printf ("CU name: \"%s\"\n", cuname); + + const char *diename; + Dwarf_Die die; + if (dwarf_offdie (dbg, gl->die_offset, &die) == NULL + || (diename = dwarf_diename (&die)) == NULL) + { + puts ("failed to get object die"); + result = DWARF_CB_ABORT; + } + else + printf ("object name: \"%s\"\n", diename); + + return result; +} + + +int +main (int argc, char *argv[]) +{ + int result = 0; + int cnt; + + for (cnt = 1; cnt < argc; ++cnt) + { + int fd = open (argv[cnt], O_RDONLY); + Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg == NULL) + { + printf ("%s not usable: %s\n", argv[cnt], dwarf_errmsg (-1)); + result = 1; + close (fd); + continue; + } + + globcnt = 0; + + if (dwarf_getpubnames (dbg, callback, NULL, 0) != 0) + { + printf ("dwarf_get_pubnames didn't return zero: %s\n", + dwarf_errmsg (-1)); + result = 1; + } + + dwarf_end (dbg); + close (fd); + } + + return result; +} diff --git a/tests/hash.c b/tests/hash.c new file mode 100644 index 00000000..afe853bb --- /dev/null +++ b/tests/hash.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +static int +check (const char *name, unsigned long int expected) +{ + unsigned long int actual = elf_hash (name); + + return actual != expected; +} + + +int +main (void) +{ + int status; + + /* Check some names. We know what the expected result is. */ + status = check ("_DYNAMIC", 165832675); + status |= check ("_GLOBAL_OFFSET_TABLE_", 102264335); + + return status; +} diff --git a/tests/line2addr.c b/tests/line2addr.c new file mode 100644 index 00000000..d2017fba --- /dev/null +++ b/tests/line2addr.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include + + +int +main (int argc, char *argv[]) +{ + for (int cnt = 1; cnt < argc; ++cnt) + { + char *fname; + char *file; + int line; + + switch (sscanf (argv[cnt], "%a[^:]:%a[^:]:%d", + &fname, &file, &line)) + { + default: + case 0: + case 1: + printf ("ignored %s\n", argv[cnt]); + continue; + case 2: + line = 0; + break; + case 3: + break; + } + + int fd = open (fname, O_RDONLY); + if (fd == -1) + continue; + + Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg != NULL) + { + Dwarf_Line **lines = NULL; + size_t nlines = 0; + + if (dwarf_getsrc_file (dbg, file, line, 0, &lines, &nlines) == 0) + { + for (size_t inner = 0; inner < nlines; ++inner) + { + Dwarf_Addr addr; + if (dwarf_lineaddr (lines[inner], &addr) == 0) + printf ("%s -> %#" PRIxMAX "\n", + argv[cnt], (uintmax_t) addr); + } + + free (lines); + } + + dwarf_end (dbg); + } + + close (fd); + free (fname); + free (file); + } + + return 0; +} diff --git a/tests/msg_tst.c b/tests/msg_tst.c new file mode 100644 index 00000000..67e63c0e --- /dev/null +++ b/tests/msg_tst.c @@ -0,0 +1,99 @@ +/* Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper , 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include + +#include +#include +#include + +#include + +static struct +{ + int id; + const char *expected; +} libelf_msgs[ELF_E_NUM] = + { + { ELF_E_NOERROR, "no error" }, + { ELF_E_UNKNOWN_ERROR, "unknown error" }, + { ELF_E_UNKNOWN_VERSION, "unknown version" }, + { ELF_E_UNKNOWN_TYPE, "unknown type" }, + { ELF_E_INVALID_HANDLE, "invalid `Elf' handle" }, + { ELF_E_SOURCE_SIZE, "invalid size of source operand" }, + { ELF_E_DEST_SIZE, "invalid size of destination operand" }, + { ELF_E_INVALID_ENCODING, "invalid encoding" }, + { ELF_E_NOMEM, "out of memory" }, + { ELF_E_INVALID_FILE, "invalid file descriptor" }, + { ELF_E_INVALID_OP, "invalid operation" }, + { ELF_E_NO_VERSION, "ELF version not set" }, + { ELF_E_INVALID_CMD, "invalid command" }, + { ELF_E_RANGE, "offset out of range" }, + { ELF_E_ARCHIVE_FMAG, "invalid fmag field in archive header" }, + { ELF_E_INVALID_ARCHIVE, "invalid archive file" }, + { ELF_E_NO_ARCHIVE, "descriptor is not for an archive" }, + { ELF_E_NO_INDEX, "no index available" }, + { ELF_E_READ_ERROR, "cannot read data from file" }, + { ELF_E_WRITE_ERROR, "cannot write data to file" }, + { ELF_E_INVALID_CLASS, "invalid binary class" }, + { ELF_E_INVALID_INDEX, "invalid section index" }, + { ELF_E_INVALID_OPERAND, "invalid operand" }, + { ELF_E_INVALID_SECTION, "invalid section" }, + { ELF_E_INVALID_COMMAND, "invalid command" }, + { ELF_E_WRONG_ORDER_EHDR, "executable header not created first" }, + { ELF_E_FD_DISABLED, "file descriptor disabled" }, + { ELF_E_FD_MISMATCH, "archive/member fildes mismatch" }, + { ELF_E_OFFSET_RANGE, "offset out of range" }, + { ELF_E_NOT_NUL_SECTION, "cannot manipulate null section" }, + { ELF_E_DATA_MISMATCH, "data/scn mismatch" }, + { ELF_E_INVALID_SECTION_HEADER, "invalid section header" }, + { ELF_E_INVALID_DATA, "invalid data" }, + { ELF_E_DATA_ENCODING, "unknown data encoding" }, + { ELF_E_SECTION_TOO_SMALL, "section `sh_size' too small for data" }, + { ELF_E_INVALID_ALIGN, "invalid section alignment" }, + { ELF_E_INVALID_SHENTSIZE, "invalid section entry size" }, + { ELF_E_UPDATE_RO, "update() for write on read-only file" }, + { ELF_E_NOFILE, "no such file" }, + { ELF_E_GROUP_NOT_REL, + "only relocatable files can contain section groups" }, + { ELF_E_INVALID_PHDR, + "program header only allowed in executables and shared objects" }, + { ELF_E_NO_PHDR, + "file has no program header" } + }; + + +int +main (void) +{ + size_t cnt; + int result = EXIT_SUCCESS; + + /* Clear the error state. */ + (void) elf_errno (); + + /* Check all the messages of libelf. */ + for (cnt = 1; cnt < ELF_E_NUM; ++cnt) + { + const char *str = elf_errmsg (libelf_msgs[cnt].id); + + if (strcmp (str, libelf_msgs[cnt].expected) != 0) + { + printf ("libelf msg %zu: expected \"%s\", got \"%s\"\n", + cnt, libelf_msgs[cnt].expected, str); + result = EXIT_FAILURE; + } + } + + return result; +} diff --git a/tests/newfile.c b/tests/newfile.c new file mode 100644 index 00000000..32c4091c --- /dev/null +++ b/tests/newfile.c @@ -0,0 +1,166 @@ +/* Copyright (C) 1999, 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1999. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include + +#include +#include +#include +#include + +static void +print_ehdr (Elf32_Ehdr *ehdr) +{ + int n; + + for (n = 0; n < EI_NIDENT; ++n) + printf (" %02x", ehdr->e_ident[n]); + + printf ("\ntype = %d\nmachine = %d\nversion = %d\nentry = %d\n" + "phoff = %d\nshoff = %d\nflags = %d\nehsize = %d\n" + "phentsize = %d\nphnum = %d\nshentsize = %d\nshnum = %d\n" + "shstrndx = %d\n", + ehdr->e_type, + ehdr->e_machine, + ehdr->e_version, + ehdr->e_entry, + ehdr->e_phoff, + ehdr->e_shoff, + ehdr->e_flags, + ehdr->e_ehsize, + ehdr->e_phentsize, + ehdr->e_phnum, + ehdr->e_shentsize, + ehdr->e_shnum, + ehdr->e_shstrndx); +} + +int +main (int argc, char *argv[] __attribute__ ((unused))) +{ + Elf *elf; + int result = 0; + int fd; + char fname[] = "newfile-XXXXXX"; + + fd = mkstemp (fname); + if (fd == -1) + { + printf ("cannot create temporary file: %m\n"); + exit (1); + } + /* Remove the file when we exit. */ + unlink (fname); + + elf_version (EV_CURRENT); + elf = elf_begin (fd, ELF_C_WRITE, NULL); + if (elf == NULL) + { + printf ("elf_begin: %s\n", elf_errmsg (-1)); + result = 1; + } + else + { + if (elf32_newehdr (elf) == NULL) + { + printf ("elf32_newehdr: %s\n", elf_errmsg (-1)); + result = 1; + } + else + { + Elf32_Ehdr *ehdr = elf32_getehdr (elf); + + if (ehdr == NULL) + { + printf ("elf32_getehdr: %s\n", elf_errmsg (-1)); + result = 1; + } + else + { + int i; + + if (argc > 1) + /* Use argc as a debugging flag. */ + print_ehdr (ehdr); + + /* Some tests. */ + for (i = 0; i < EI_NIDENT; ++i) + if (ehdr->e_ident[i] != 0) + { + printf ("ehdr->e_ident[%d] != 0\n", i); + result = 1; + break; + } + +#define VALUE_TEST(name, val) \ + if (ehdr->name != val) \ + { \ + printf ("ehdr->%s != %d\n", #name, val); \ + result = 1; \ + } +#define ZERO_TEST(name) VALUE_TEST (name, 0) + ZERO_TEST (e_type); + ZERO_TEST (e_machine); + ZERO_TEST (e_version); + ZERO_TEST (e_entry); + ZERO_TEST (e_phoff); + ZERO_TEST (e_shoff); + ZERO_TEST (e_flags); + ZERO_TEST (e_ehsize); + ZERO_TEST (e_phentsize); + ZERO_TEST (e_phnum); + ZERO_TEST (e_shentsize); + ZERO_TEST (e_shnum); + ZERO_TEST (e_shstrndx); + + if (elf32_newphdr (elf, 10) == NULL) + { + printf ("elf32_newphdr: %s\n", elf_errmsg (-1)); + result = 1; + } + else + { + if (argc > 1) + print_ehdr (ehdr); + + ehdr = elf32_getehdr (elf); + if (ehdr == NULL) + { + printf ("elf32_getehdr (#2): %s\n", elf_errmsg (-1)); + result = 1; + } + else + { + ZERO_TEST (e_type); + ZERO_TEST (e_machine); + ZERO_TEST (e_version); + ZERO_TEST (e_entry); + ZERO_TEST (e_phoff); + ZERO_TEST (e_shoff); + ZERO_TEST (e_flags); + ZERO_TEST (e_ehsize); + VALUE_TEST (e_phentsize, (int) sizeof (Elf32_Phdr)); + VALUE_TEST (e_phnum, 10); + ZERO_TEST (e_shentsize); + ZERO_TEST (e_shnum); + ZERO_TEST (e_shstrndx); + } + } + } + } + + (void) elf_end (elf); + } + + return result; +} diff --git a/tests/newscn.c b/tests/newscn.c new file mode 100644 index 00000000..8c8b335a --- /dev/null +++ b/tests/newscn.c @@ -0,0 +1,58 @@ +/* Copyright (C) 1999, 2000, 2001, 2002, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include +#include +#include + + +int +main (void) +{ + Elf *elf; + int fd; + Elf_Scn *section; + + if (elf_version (EV_CURRENT) == EV_NONE) + { + fprintf (stderr, "library fd of date\n"); + exit (1); + } + + char name[] = "test.XXXXXX"; + fd = mkstemp (name); + if (fd < 0) + { + fprintf (stderr, "Failed to open fdput file: %s\n", name); + exit (1); + } + unlink (name); + + elf = elf_begin (fd, ELF_C_WRITE, NULL); + if (elf == NULL) + { + fprintf (stderr, "Failed to elf_begin fdput file: %s\n", name); + exit (1); + } + + section = elf_newscn (elf); + section = elf_nextscn (elf, section); + assert (section == NULL); + + elf_end (elf); + close (fd); + + return 0; +} diff --git a/tests/run-allfcts.sh b/tests/run-allfcts.sh new file mode 100644 index 00000000..51fe75ce --- /dev/null +++ b/tests/run-allfcts.sh @@ -0,0 +1,46 @@ +#! /bin/sh +# Copyright (C) 2005 Red Hat, Inc. +# Written by Ulrich Drepper , 2005. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile.bz2 > testfile 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile2.bz2 > testfile2 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile8.bz2 > testfile8 2>/dev/null || exit 0 + +./allfcts testfile testfile2 testfile8 > allfcts.out + +diff -u allfcts.out - <<"EOF" +/home/drepper/gnu/new-bu/build/ttt/m.c:5:main +/home/drepper/gnu/new-bu/build/ttt/b.c:4:bar +/home/drepper/gnu/new-bu/build/ttt/f.c:3:foo +/shoggoth/drepper/b.c:4:bar +/shoggoth/drepper/f.c:3:foo +/shoggoth/drepper/m.c:5:main +/home/drepper/gnu/elfutils/build/src/../../src/strip.c:107:main +/home/drepper/gnu/elfutils/build/src/../../src/strip.c:159:print_version +/home/drepper/gnu/elfutils/build/src/../../src/strip.c:173:parse_opt +/home/drepper/gnu/elfutils/build/src/../../src/strip.c:201:more_help +/home/drepper/gnu/elfutils/build/src/../../src/strip.c:217:process_file +/usr/include/sys/stat.h:375:stat64 +/home/drepper/gnu/elfutils/build/src/../../src/strip.c:291:crc32_file +/home/drepper/gnu/elfutils/build/src/../../src/strip.c:313:handle_elf +EOF + +rm -f testfile testfile2 testfile8 allfcts.out + +exit 0 diff --git a/tests/run-arextract.sh b/tests/run-arextract.sh new file mode 100644 index 00000000..69ac0bca --- /dev/null +++ b/tests/run-arextract.sh @@ -0,0 +1,33 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002, 2005 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. + +archive=../libelf/libelf.a +if test -f $archive; then + # The file is really available (i.e., no shared-only built). + echo -n "Extracting symbols... $ac_c" + + # The files we are looking at. + for f in ../libelf/*.o; do + ./arextract $archive `basename $f` arextract.test || exit 1 + cmp $f arextract.test || { + echo "Extraction of $1 failed" + exit 1 + } + rm -f ${objpfx}arextract.test + done + + echo "done" +fi + +exit 0 diff --git a/tests/run-arsymtest.sh b/tests/run-arsymtest.sh new file mode 100644 index 00000000..793cdb8f --- /dev/null +++ b/tests/run-arsymtest.sh @@ -0,0 +1,41 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. + +lib=../libelf/libelf.a +okfile=arsymtest.ok +tmpfile=arsymtest.tmp +testfile=arsymtest.test + +result=0 +if test -f $lib; then + # Generate list using `nm' we check against. + nm -s $lib | + sed -e '1,/^Arch/d' -e '/^$/,$d' | + sort > $okfile + + # Now run our program using libelf. + ./arsymtest $lib $tmpfile || exit 1 + sort $tmpfile > $testfile + rm $tmpfile + + # Compare the outputs. + if cmp $okfile $testfile; then + result=0 + rm $testfile $okfile + else + result=1 + fi +fi + +exit $result diff --git a/tests/run-ecp-test.sh b/tests/run-ecp-test.sh new file mode 100644 index 00000000..e4304965 --- /dev/null +++ b/tests/run-ecp-test.sh @@ -0,0 +1,25 @@ +#! /bin/sh +# Copyright (C) 2002 Red Hat, Inc. +# Written by Jakub Jelinek , 2002. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile10.bz2 > testfile10 2>/dev/null || exit 0 + +./ecp testfile10 testfile10.tmp + +cmp testfile10 testfile10.tmp + +rm -f testfile10 testfile10.tmp + +exit 0 diff --git a/tests/run-ecp-test2.sh b/tests/run-ecp-test2.sh new file mode 100644 index 00000000..143c70a6 --- /dev/null +++ b/tests/run-ecp-test2.sh @@ -0,0 +1,23 @@ +#! /bin/sh +# Copyright (C) 2002 Red Hat, Inc. +# Written by Jakub Jelinek , 2002. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile2.bz2 > testfile2 2>/dev/null || exit 0 + +./ecp testfile2 testfile2.tmp + +rm -f testfile2 testfile2.tmp + +exit 0 diff --git a/tests/run-elflint-test.sh b/tests/run-elflint-test.sh new file mode 100644 index 00000000..f008ccdc --- /dev/null +++ b/tests/run-elflint-test.sh @@ -0,0 +1,28 @@ +#! /bin/sh +# Copyright (C) 2005 Red Hat, Inc. +# Written by Ulrich Drepper , 2005. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile18.bz2 > testfile18 2>/dev/null || exit 0 + +LD_LIBRARY_PATH=../libebl:../libelf${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH \ + ../src/elflint --gnu testfile18 >& elflint-test.out || : + +diff -u elflint-test.out - <<"EOF" +section [ 8] '.rela.dyn': relocation 1: copy relocation against symbol of type FUNC +EOF + +rm -f testfile18 elflint-test.out + +exit 0 diff --git a/tests/run-get-aranges.sh b/tests/run-get-aranges.sh new file mode 100644 index 00000000..26b29863 --- /dev/null +++ b/tests/run-get-aranges.sh @@ -0,0 +1,71 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile.bz2 > testfile 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile2.bz2 > testfile2 2>/dev/null || exit 0 + +./get-aranges testfile testfile2 > get-aranges.out + +cmp get-aranges.out - <<"EOF" +0x804842b: not in range +CU name: "m.c" +CU name: "m.c" +CU name: "m.c" +0x804845a: not in range +0x804845b: not in range +CU name: "b.c" +CU name: "b.c" +CU name: "b.c" +0x8048466: not in range +0x8048467: not in range +CU name: "f.c" +CU name: "f.c" +CU name: "f.c" +0x8048472: not in range + [ 0] start: 0x804842c, length: 46, cu: 11 +CU name: "m.c" + [ 1] start: 0x804845c, length: 10, cu: 202 +CU name: "b.c" + [ 2] start: 0x8048468, length: 10, cu: 5628 +CU name: "f.c" +0x804842b: not in range +0x804842c: not in range +0x804843c: not in range +0x8048459: not in range +0x804845a: not in range +0x804845b: not in range +0x804845c: not in range +0x8048460: not in range +0x8048465: not in range +0x8048466: not in range +0x8048467: not in range +0x8048468: not in range +0x8048470: not in range +0x8048471: not in range +0x8048472: not in range + [ 0] start: 0x10000470, length: 32, cu: 11 +CU name: "b.c" + [ 1] start: 0x10000490, length: 32, cu: 2429 +CU name: "f.c" + [ 2] start: 0x100004b0, length: 100, cu: 2532 +CU name: "m.c" +EOF + +rm -f testfile testfile2 get-aranges.out + +exit 0 diff --git a/tests/run-get-files.sh b/tests/run-get-files.sh new file mode 100644 index 00000000..7af5c139 --- /dev/null +++ b/tests/run-get-files.sh @@ -0,0 +1,64 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002, 2004 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile.bz2 > testfile 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile2.bz2 > testfile2 2>/dev/null || exit 0 + +./get-files testfile testfile2 > get-files.out + +diff -u get-files.out - <<"EOF" +cuhl = 11, o = 0, asz = 4, osz = 4, ncu = 191 + file[0] = "???" + file[1] = "/home/drepper/gnu/new-bu/build/ttt/m.c" +cuhl = 11, o = 114, asz = 4, osz = 4, ncu = 5617 + file[0] = "???" + file[1] = "/home/drepper/gnu/new-bu/build/ttt/b.c" + file[2] = "/usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h" + file[3] = "/usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h" + file[4] = "/usr/include/bits/types.h" + file[5] = "/usr/include/bits/sched.h" + file[6] = "/usr/include/bits/pthreadtypes.h" + file[7] = "/usr/include/stdio.h" + file[8] = "/usr/include/libio.h" + file[9] = "/usr/include/wchar.h" + file[10] = "/usr/include/_G_config.h" + file[11] = "/usr/include/gconv.h" +cuhl = 11, o = 412, asz = 4, osz = 4, ncu = 5752 + file[0] = "???" + file[1] = "/home/drepper/gnu/new-bu/build/ttt/f.c" +cuhl = 11, o = 0, asz = 4, osz = 4, ncu = 2418 + file[0] = "???" + file[1] = "/shoggoth/drepper/b.c" + file[2] = "/home/geoffk/objs/laurel-000912-branch/lib/gcc-lib/powerpc-unknown-linux-gnu/2.96-laurel-000912/include/stddef.h" + file[3] = "/home/geoffk/objs/laurel-000912-branch/lib/gcc-lib/powerpc-unknown-linux-gnu/2.96-laurel-000912/include/stdarg.h" + file[4] = "/shoggoth/drepper/" + file[5] = "/usr/include/bits/types.h" + file[6] = "/usr/include/stdio.h" + file[7] = "/usr/include/libio.h" + file[8] = "/usr/include/_G_config.h" +cuhl = 11, o = 213, asz = 4, osz = 4, ncu = 2521 + file[0] = "???" + file[1] = "/shoggoth/drepper/f.c" +cuhl = 11, o = 267, asz = 4, osz = 4, ncu = 2680 + file[0] = "???" + file[1] = "/shoggoth/drepper/m.c" +EOF + +rm -f testfile testfil2 get-files.out + +exit 0 diff --git a/tests/run-get-lines.sh b/tests/run-get-lines.sh new file mode 100644 index 00000000..70c9cd84 --- /dev/null +++ b/tests/run-get-lines.sh @@ -0,0 +1,67 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002, 2004 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile.bz2 > testfile 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile2.bz2 > testfile2 2>/dev/null || exit 0 + +./get-lines testfile testfile2 > get-lines.out + +diff -u get-lines.out - <<"EOF" +cuhl = 11, o = 0, asz = 4, osz = 4, ncu = 191 + 5 lines +804842c: /home/drepper/gnu/new-bu/build/ttt/m.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048432: /home/drepper/gnu/new-bu/build/ttt/m.c:6:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804844d: /home/drepper/gnu/new-bu/build/ttt/m.c:7:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048458: /home/drepper/gnu/new-bu/build/ttt/m.c:8:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804845a: /home/drepper/gnu/new-bu/build/ttt/m.c:8:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +cuhl = 11, o = 114, asz = 4, osz = 4, ncu = 5617 + 4 lines +804845c: /home/drepper/gnu/new-bu/build/ttt/b.c:4:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804845f: /home/drepper/gnu/new-bu/build/ttt/b.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048464: /home/drepper/gnu/new-bu/build/ttt/b.c:6:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048466: /home/drepper/gnu/new-bu/build/ttt/b.c:6:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +cuhl = 11, o = 412, asz = 4, osz = 4, ncu = 5752 + 4 lines +8048468: /home/drepper/gnu/new-bu/build/ttt/f.c:3:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804846b: /home/drepper/gnu/new-bu/build/ttt/f.c:4:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048470: /home/drepper/gnu/new-bu/build/ttt/f.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048472: /home/drepper/gnu/new-bu/build/ttt/f.c:5:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +cuhl = 11, o = 0, asz = 4, osz = 4, ncu = 2418 + 4 lines +10000470: /shoggoth/drepper/b.c:4:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +1000047c: /shoggoth/drepper/b.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +10000480: /shoggoth/drepper/b.c:6:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +10000490: /shoggoth/drepper/b.c:6:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +cuhl = 11, o = 213, asz = 4, osz = 4, ncu = 2521 + 4 lines +10000490: /shoggoth/drepper/f.c:3:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +1000049c: /shoggoth/drepper/f.c:4:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +100004a0: /shoggoth/drepper/f.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +100004b0: /shoggoth/drepper/f.c:5:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +cuhl = 11, o = 267, asz = 4, osz = 4, ncu = 2680 + 5 lines +100004b0: /shoggoth/drepper/m.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +100004cc: /shoggoth/drepper/m.c:6:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +100004e8: /shoggoth/drepper/m.c:7:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +100004f4: /shoggoth/drepper/m.c:8:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +10000514: /shoggoth/drepper/m.c:8:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +EOF + +rm -f testfile testfile2 get-lines.out + +exit 0 diff --git a/tests/run-get-pubnames.sh b/tests/run-get-pubnames.sh new file mode 100644 index 00000000..a232bfd2 --- /dev/null +++ b/tests/run-get-pubnames.sh @@ -0,0 +1,53 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002, 2003 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile.bz2 > testfile 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile2.bz2 > testfile2 2>/dev/null || exit 0 + +./get-pubnames testfile testfile2 > get-pubnames.out + +diff -u get-pubnames.out - <<"EOF" + [ 0] "main", die: 104, cu: 11 +CU name: "m.c" +object name: "main" + [ 1] "a", die: 174, cu: 11 +CU name: "m.c" +object name: "a" + [ 2] "bar", die: 295, cu: 202 +CU name: "b.c" +object name: "bar" + [ 3] "foo", die: 5721, cu: 5628 +CU name: "f.c" +object name: "foo" + [ 0] "bar", die: 72, cu: 11 +CU name: "b.c" +object name: "bar" + [ 1] "foo", die: 2490, cu: 2429 +CU name: "f.c" +object name: "foo" + [ 2] "main", die: 2593, cu: 2532 +CU name: "m.c" +object name: "main" + [ 3] "a", die: 2663, cu: 2532 +CU name: "m.c" +object name: "a" +EOF + +rm -f testfile testfile2 get-pubnames.out + +exit 0 diff --git a/tests/run-line2addr.sh b/tests/run-line2addr.sh new file mode 100644 index 00000000..c46c8fda --- /dev/null +++ b/tests/run-line2addr.sh @@ -0,0 +1,44 @@ +#! /bin/sh +# Copyright (C) 2005 Red Hat, Inc. +# Written by Ulrich Drepper , 2005. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile.bz2 > testfile 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile2.bz2 > testfile2 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile8.bz2 > testfile8 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile14.bz2 > testfile14 2>/dev/null || exit 0 + +./line2addr testfile:f.c:4 testfile:f.c:8 testfile2:m.c:6 testfile2:b.c:1 testfile8:strip.c:953 testfile8:strip.c:365 testfile14:v.c:6 > line2addr.out + +diff -u line2addr.out - <<"EOF" +testfile:f.c:4 -> 0x804846b +testfile2:m.c:6 -> 0x100004cc +testfile2:b.c:1 -> 0x10000470 +testfile8:strip.c:953 -> 0x169f +testfile8:strip.c:953 -> 0x16aa +testfile8:strip.c:365 -> 0x278b +testfile8:strip.c:365 -> 0x2797 +testfile14:v.c:6 -> 0x400468 +testfile14:v.c:6 -> 0x400487 +EOF + +rm -f testfile testfile2 testfile8 testfile14 line2addr.out + +exit 0 diff --git a/tests/run-show-abbrev.sh b/tests/run-show-abbrev.sh new file mode 100644 index 00000000..78812a5f --- /dev/null +++ b/tests/run-show-abbrev.sh @@ -0,0 +1,355 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002, 2003, 2004 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile.bz2 > testfile 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile2.bz2 > testfile2 2>/dev/null || exit 0 + +./show-abbrev testfile testfile2 > show-abbrev.out + +diff -u show-abbrev.out - <<"EOF" +abbrev[0]: code = 1, tag = 17, children = 1 +abbrev[0]: attr[0]: code = 16, form = 6, offset = 0 +abbrev[0]: attr[1]: code = 18, form = 1, offset = 2 +abbrev[0]: attr[2]: code = 17, form = 1, offset = 4 +abbrev[0]: attr[3]: code = 3, form = 8, offset = 6 +abbrev[0]: attr[4]: code = 27, form = 8, offset = 8 +abbrev[0]: attr[5]: code = 37, form = 8, offset = 10 +abbrev[0]: attr[6]: code = 19, form = 11, offset = 12 +abbrev[19]: code = 2, tag = 46, children = 1 +abbrev[19]: attr[0]: code = 1, form = 19, offset = 19 +abbrev[19]: attr[1]: code = 63, form = 12, offset = 21 +abbrev[19]: attr[2]: code = 3, form = 8, offset = 23 +abbrev[19]: attr[3]: code = 58, form = 11, offset = 25 +abbrev[19]: attr[4]: code = 59, form = 11, offset = 27 +abbrev[19]: attr[5]: code = 39, form = 12, offset = 29 +abbrev[19]: attr[6]: code = 73, form = 19, offset = 31 +abbrev[19]: attr[7]: code = 17, form = 1, offset = 33 +abbrev[19]: attr[8]: code = 18, form = 1, offset = 35 +abbrev[19]: attr[9]: code = 64, form = 10, offset = 37 +abbrev[44]: code = 3, tag = 46, children = 1 +abbrev[44]: attr[0]: code = 1, form = 19, offset = 44 +abbrev[44]: attr[1]: code = 63, form = 12, offset = 46 +abbrev[44]: attr[2]: code = 3, form = 8, offset = 48 +abbrev[44]: attr[3]: code = 58, form = 11, offset = 50 +abbrev[44]: attr[4]: code = 59, form = 11, offset = 52 +abbrev[44]: attr[5]: code = 73, form = 19, offset = 54 +abbrev[44]: attr[6]: code = 60, form = 12, offset = 56 +abbrev[63]: code = 4, tag = 24, children = 0 +abbrev[68]: code = 5, tag = 46, children = 1 +abbrev[68]: attr[0]: code = 63, form = 12, offset = 68 +abbrev[68]: attr[1]: code = 3, form = 8, offset = 70 +abbrev[68]: attr[2]: code = 58, form = 11, offset = 72 +abbrev[68]: attr[3]: code = 59, form = 11, offset = 74 +abbrev[68]: attr[4]: code = 73, form = 19, offset = 76 +abbrev[68]: attr[5]: code = 60, form = 12, offset = 78 +abbrev[85]: code = 6, tag = 36, children = 0 +abbrev[85]: attr[0]: code = 3, form = 8, offset = 85 +abbrev[85]: attr[1]: code = 11, form = 11, offset = 87 +abbrev[85]: attr[2]: code = 62, form = 11, offset = 89 +abbrev[96]: code = 7, tag = 52, children = 0 +abbrev[96]: attr[0]: code = 3, form = 8, offset = 96 +abbrev[96]: attr[1]: code = 58, form = 11, offset = 98 +abbrev[96]: attr[2]: code = 59, form = 11, offset = 100 +abbrev[96]: attr[3]: code = 73, form = 19, offset = 102 +abbrev[96]: attr[4]: code = 63, form = 12, offset = 104 +abbrev[96]: attr[5]: code = 2, form = 10, offset = 106 +abbrev[0]: code = 1, tag = 17, children = 1 +abbrev[0]: attr[0]: code = 16, form = 6, offset = 114 +abbrev[0]: attr[1]: code = 18, form = 1, offset = 116 +abbrev[0]: attr[2]: code = 17, form = 1, offset = 118 +abbrev[0]: attr[3]: code = 3, form = 8, offset = 120 +abbrev[0]: attr[4]: code = 27, form = 8, offset = 122 +abbrev[0]: attr[5]: code = 37, form = 8, offset = 124 +abbrev[0]: attr[6]: code = 19, form = 11, offset = 126 +abbrev[19]: code = 2, tag = 46, children = 0 +abbrev[19]: attr[0]: code = 63, form = 12, offset = 133 +abbrev[19]: attr[1]: code = 3, form = 8, offset = 135 +abbrev[19]: attr[2]: code = 58, form = 11, offset = 137 +abbrev[19]: attr[3]: code = 59, form = 11, offset = 139 +abbrev[19]: attr[4]: code = 39, form = 12, offset = 141 +abbrev[19]: attr[5]: code = 73, form = 19, offset = 143 +abbrev[19]: attr[6]: code = 17, form = 1, offset = 145 +abbrev[19]: attr[7]: code = 18, form = 1, offset = 147 +abbrev[19]: attr[8]: code = 64, form = 10, offset = 149 +abbrev[42]: code = 3, tag = 36, children = 0 +abbrev[42]: attr[0]: code = 3, form = 8, offset = 156 +abbrev[42]: attr[1]: code = 11, form = 11, offset = 158 +abbrev[42]: attr[2]: code = 62, form = 11, offset = 160 +abbrev[53]: code = 4, tag = 22, children = 0 +abbrev[53]: attr[0]: code = 3, form = 8, offset = 167 +abbrev[53]: attr[1]: code = 58, form = 11, offset = 169 +abbrev[53]: attr[2]: code = 59, form = 11, offset = 171 +abbrev[53]: attr[3]: code = 73, form = 19, offset = 173 +abbrev[66]: code = 5, tag = 15, children = 0 +abbrev[66]: attr[0]: code = 11, form = 11, offset = 180 +abbrev[73]: code = 6, tag = 15, children = 0 +abbrev[73]: attr[0]: code = 11, form = 11, offset = 187 +abbrev[73]: attr[1]: code = 73, form = 19, offset = 189 +abbrev[82]: code = 7, tag = 19, children = 1 +abbrev[82]: attr[0]: code = 1, form = 19, offset = 196 +abbrev[82]: attr[1]: code = 11, form = 11, offset = 198 +abbrev[82]: attr[2]: code = 58, form = 11, offset = 200 +abbrev[82]: attr[3]: code = 59, form = 11, offset = 202 +abbrev[95]: code = 8, tag = 13, children = 0 +abbrev[95]: attr[0]: code = 3, form = 8, offset = 209 +abbrev[95]: attr[1]: code = 58, form = 11, offset = 211 +abbrev[95]: attr[2]: code = 59, form = 11, offset = 213 +abbrev[95]: attr[3]: code = 73, form = 19, offset = 215 +abbrev[95]: attr[4]: code = 56, form = 10, offset = 217 +abbrev[110]: code = 9, tag = 1, children = 1 +abbrev[110]: attr[0]: code = 1, form = 19, offset = 224 +abbrev[110]: attr[1]: code = 73, form = 19, offset = 226 +abbrev[119]: code = 10, tag = 33, children = 0 +abbrev[119]: attr[0]: code = 73, form = 19, offset = 233 +abbrev[119]: attr[1]: code = 47, form = 11, offset = 235 +abbrev[128]: code = 11, tag = 19, children = 1 +abbrev[128]: attr[0]: code = 1, form = 19, offset = 242 +abbrev[128]: attr[1]: code = 3, form = 8, offset = 244 +abbrev[128]: attr[2]: code = 11, form = 11, offset = 246 +abbrev[128]: attr[3]: code = 58, form = 11, offset = 248 +abbrev[128]: attr[4]: code = 59, form = 11, offset = 250 +abbrev[143]: code = 12, tag = 19, children = 0 +abbrev[143]: attr[0]: code = 3, form = 8, offset = 257 +abbrev[143]: attr[1]: code = 60, form = 12, offset = 259 +abbrev[152]: code = 13, tag = 13, children = 0 +abbrev[152]: attr[0]: code = 3, form = 8, offset = 266 +abbrev[152]: attr[1]: code = 58, form = 11, offset = 268 +abbrev[152]: attr[2]: code = 59, form = 5, offset = 270 +abbrev[152]: attr[3]: code = 73, form = 19, offset = 272 +abbrev[152]: attr[4]: code = 56, form = 10, offset = 274 +abbrev[167]: code = 14, tag = 22, children = 0 +abbrev[167]: attr[0]: code = 3, form = 8, offset = 281 +abbrev[167]: attr[1]: code = 58, form = 11, offset = 283 +abbrev[167]: attr[2]: code = 59, form = 5, offset = 285 +abbrev[167]: attr[3]: code = 73, form = 19, offset = 287 +abbrev[180]: code = 15, tag = 23, children = 1 +abbrev[180]: attr[0]: code = 1, form = 19, offset = 294 +abbrev[180]: attr[1]: code = 11, form = 11, offset = 296 +abbrev[180]: attr[2]: code = 58, form = 11, offset = 298 +abbrev[180]: attr[3]: code = 59, form = 11, offset = 300 +abbrev[193]: code = 16, tag = 13, children = 0 +abbrev[193]: attr[0]: code = 3, form = 8, offset = 307 +abbrev[193]: attr[1]: code = 58, form = 11, offset = 309 +abbrev[193]: attr[2]: code = 59, form = 11, offset = 311 +abbrev[193]: attr[3]: code = 73, form = 19, offset = 313 +abbrev[206]: code = 17, tag = 4, children = 1 +abbrev[206]: attr[0]: code = 1, form = 19, offset = 320 +abbrev[206]: attr[1]: code = 11, form = 11, offset = 322 +abbrev[206]: attr[2]: code = 58, form = 11, offset = 324 +abbrev[206]: attr[3]: code = 59, form = 11, offset = 326 +abbrev[219]: code = 18, tag = 40, children = 0 +abbrev[219]: attr[0]: code = 3, form = 8, offset = 333 +abbrev[219]: attr[1]: code = 28, form = 11, offset = 335 +abbrev[228]: code = 19, tag = 38, children = 0 +abbrev[228]: attr[0]: code = 73, form = 19, offset = 342 +abbrev[235]: code = 20, tag = 21, children = 1 +abbrev[235]: attr[0]: code = 1, form = 19, offset = 349 +abbrev[235]: attr[1]: code = 39, form = 12, offset = 351 +abbrev[235]: attr[2]: code = 73, form = 19, offset = 353 +abbrev[246]: code = 21, tag = 5, children = 0 +abbrev[246]: attr[0]: code = 73, form = 19, offset = 360 +abbrev[253]: code = 22, tag = 21, children = 1 +abbrev[253]: attr[0]: code = 1, form = 19, offset = 367 +abbrev[253]: attr[1]: code = 39, form = 12, offset = 369 +abbrev[262]: code = 23, tag = 33, children = 0 +abbrev[262]: attr[0]: code = 73, form = 19, offset = 376 +abbrev[262]: attr[1]: code = 47, form = 6, offset = 378 +abbrev[271]: code = 24, tag = 22, children = 0 +abbrev[271]: attr[0]: code = 3, form = 8, offset = 385 +abbrev[271]: attr[1]: code = 58, form = 11, offset = 387 +abbrev[271]: attr[2]: code = 59, form = 11, offset = 389 +abbrev[282]: code = 25, tag = 4, children = 1 +abbrev[282]: attr[0]: code = 1, form = 19, offset = 396 +abbrev[282]: attr[1]: code = 3, form = 8, offset = 398 +abbrev[282]: attr[2]: code = 11, form = 11, offset = 400 +abbrev[282]: attr[3]: code = 58, form = 11, offset = 402 +abbrev[282]: attr[4]: code = 59, form = 11, offset = 404 +abbrev[0]: code = 1, tag = 17, children = 1 +abbrev[0]: attr[0]: code = 16, form = 6, offset = 412 +abbrev[0]: attr[1]: code = 18, form = 1, offset = 414 +abbrev[0]: attr[2]: code = 17, form = 1, offset = 416 +abbrev[0]: attr[3]: code = 3, form = 8, offset = 418 +abbrev[0]: attr[4]: code = 27, form = 8, offset = 420 +abbrev[0]: attr[5]: code = 37, form = 8, offset = 422 +abbrev[0]: attr[6]: code = 19, form = 11, offset = 424 +abbrev[19]: code = 2, tag = 46, children = 0 +abbrev[19]: attr[0]: code = 63, form = 12, offset = 431 +abbrev[19]: attr[1]: code = 3, form = 8, offset = 433 +abbrev[19]: attr[2]: code = 58, form = 11, offset = 435 +abbrev[19]: attr[3]: code = 59, form = 11, offset = 437 +abbrev[19]: attr[4]: code = 39, form = 12, offset = 439 +abbrev[19]: attr[5]: code = 73, form = 19, offset = 441 +abbrev[19]: attr[6]: code = 17, form = 1, offset = 443 +abbrev[19]: attr[7]: code = 18, form = 1, offset = 445 +abbrev[19]: attr[8]: code = 64, form = 10, offset = 447 +abbrev[42]: code = 3, tag = 36, children = 0 +abbrev[42]: attr[0]: code = 3, form = 8, offset = 454 +abbrev[42]: attr[1]: code = 11, form = 11, offset = 456 +abbrev[42]: attr[2]: code = 62, form = 11, offset = 458 +abbrev[0]: code = 1, tag = 17, children = 1 +abbrev[0]: attr[0]: code = 16, form = 6, offset = 0 +abbrev[0]: attr[1]: code = 18, form = 1, offset = 2 +abbrev[0]: attr[2]: code = 17, form = 1, offset = 4 +abbrev[0]: attr[3]: code = 3, form = 8, offset = 6 +abbrev[0]: attr[4]: code = 27, form = 8, offset = 8 +abbrev[0]: attr[5]: code = 37, form = 8, offset = 10 +abbrev[0]: attr[6]: code = 19, form = 11, offset = 12 +abbrev[19]: code = 2, tag = 46, children = 0 +abbrev[19]: attr[0]: code = 63, form = 12, offset = 19 +abbrev[19]: attr[1]: code = 3, form = 8, offset = 21 +abbrev[19]: attr[2]: code = 58, form = 11, offset = 23 +abbrev[19]: attr[3]: code = 59, form = 11, offset = 25 +abbrev[19]: attr[4]: code = 39, form = 12, offset = 27 +abbrev[19]: attr[5]: code = 73, form = 19, offset = 29 +abbrev[19]: attr[6]: code = 17, form = 1, offset = 31 +abbrev[19]: attr[7]: code = 18, form = 1, offset = 33 +abbrev[19]: attr[8]: code = 64, form = 10, offset = 35 +abbrev[42]: code = 3, tag = 36, children = 0 +abbrev[42]: attr[0]: code = 3, form = 8, offset = 42 +abbrev[42]: attr[1]: code = 11, form = 11, offset = 44 +abbrev[42]: attr[2]: code = 62, form = 11, offset = 46 +abbrev[53]: code = 4, tag = 22, children = 0 +abbrev[53]: attr[0]: code = 3, form = 8, offset = 53 +abbrev[53]: attr[1]: code = 58, form = 11, offset = 55 +abbrev[53]: attr[2]: code = 59, form = 11, offset = 57 +abbrev[53]: attr[3]: code = 73, form = 19, offset = 59 +abbrev[66]: code = 5, tag = 1, children = 1 +abbrev[66]: attr[0]: code = 1, form = 19, offset = 66 +abbrev[66]: attr[1]: code = 3, form = 8, offset = 68 +abbrev[66]: attr[2]: code = 73, form = 19, offset = 70 +abbrev[77]: code = 6, tag = 33, children = 0 +abbrev[77]: attr[0]: code = 73, form = 19, offset = 77 +abbrev[77]: attr[1]: code = 47, form = 11, offset = 79 +abbrev[86]: code = 7, tag = 19, children = 1 +abbrev[86]: attr[0]: code = 1, form = 19, offset = 86 +abbrev[86]: attr[1]: code = 3, form = 8, offset = 88 +abbrev[86]: attr[2]: code = 11, form = 11, offset = 90 +abbrev[86]: attr[3]: code = 58, form = 11, offset = 92 +abbrev[86]: attr[4]: code = 59, form = 11, offset = 94 +abbrev[101]: code = 8, tag = 13, children = 0 +abbrev[101]: attr[0]: code = 3, form = 8, offset = 101 +abbrev[101]: attr[1]: code = 58, form = 11, offset = 103 +abbrev[101]: attr[2]: code = 59, form = 11, offset = 105 +abbrev[101]: attr[3]: code = 73, form = 19, offset = 107 +abbrev[101]: attr[4]: code = 56, form = 10, offset = 109 +abbrev[116]: code = 9, tag = 15, children = 0 +abbrev[116]: attr[0]: code = 11, form = 11, offset = 116 +abbrev[123]: code = 10, tag = 15, children = 0 +abbrev[123]: attr[0]: code = 11, form = 11, offset = 123 +abbrev[123]: attr[1]: code = 73, form = 19, offset = 125 +abbrev[132]: code = 11, tag = 19, children = 1 +abbrev[132]: attr[0]: code = 1, form = 19, offset = 132 +abbrev[132]: attr[1]: code = 11, form = 11, offset = 134 +abbrev[132]: attr[2]: code = 58, form = 11, offset = 136 +abbrev[132]: attr[3]: code = 59, form = 11, offset = 138 +abbrev[145]: code = 12, tag = 1, children = 1 +abbrev[145]: attr[0]: code = 1, form = 19, offset = 145 +abbrev[145]: attr[1]: code = 73, form = 19, offset = 147 +abbrev[154]: code = 13, tag = 22, children = 0 +abbrev[154]: attr[0]: code = 3, form = 8, offset = 154 +abbrev[154]: attr[1]: code = 58, form = 11, offset = 156 +abbrev[154]: attr[2]: code = 59, form = 5, offset = 158 +abbrev[154]: attr[3]: code = 73, form = 19, offset = 160 +abbrev[167]: code = 14, tag = 19, children = 0 +abbrev[167]: attr[0]: code = 3, form = 8, offset = 167 +abbrev[167]: attr[1]: code = 60, form = 12, offset = 169 +abbrev[176]: code = 15, tag = 22, children = 0 +abbrev[176]: attr[0]: code = 3, form = 8, offset = 176 +abbrev[176]: attr[1]: code = 58, form = 11, offset = 178 +abbrev[176]: attr[2]: code = 59, form = 11, offset = 180 +abbrev[187]: code = 16, tag = 21, children = 1 +abbrev[187]: attr[0]: code = 1, form = 19, offset = 187 +abbrev[187]: attr[1]: code = 39, form = 12, offset = 189 +abbrev[187]: attr[2]: code = 73, form = 19, offset = 191 +abbrev[198]: code = 17, tag = 5, children = 0 +abbrev[198]: attr[0]: code = 73, form = 19, offset = 198 +abbrev[205]: code = 18, tag = 38, children = 0 +abbrev[205]: attr[0]: code = 73, form = 19, offset = 205 +abbrev[0]: code = 1, tag = 17, children = 1 +abbrev[0]: attr[0]: code = 16, form = 6, offset = 213 +abbrev[0]: attr[1]: code = 18, form = 1, offset = 215 +abbrev[0]: attr[2]: code = 17, form = 1, offset = 217 +abbrev[0]: attr[3]: code = 3, form = 8, offset = 219 +abbrev[0]: attr[4]: code = 27, form = 8, offset = 221 +abbrev[0]: attr[5]: code = 37, form = 8, offset = 223 +abbrev[0]: attr[6]: code = 19, form = 11, offset = 225 +abbrev[19]: code = 2, tag = 46, children = 0 +abbrev[19]: attr[0]: code = 63, form = 12, offset = 232 +abbrev[19]: attr[1]: code = 3, form = 8, offset = 234 +abbrev[19]: attr[2]: code = 58, form = 11, offset = 236 +abbrev[19]: attr[3]: code = 59, form = 11, offset = 238 +abbrev[19]: attr[4]: code = 39, form = 12, offset = 240 +abbrev[19]: attr[5]: code = 73, form = 19, offset = 242 +abbrev[19]: attr[6]: code = 17, form = 1, offset = 244 +abbrev[19]: attr[7]: code = 18, form = 1, offset = 246 +abbrev[19]: attr[8]: code = 64, form = 10, offset = 248 +abbrev[42]: code = 3, tag = 36, children = 0 +abbrev[42]: attr[0]: code = 3, form = 8, offset = 255 +abbrev[42]: attr[1]: code = 11, form = 11, offset = 257 +abbrev[42]: attr[2]: code = 62, form = 11, offset = 259 +abbrev[0]: code = 1, tag = 17, children = 1 +abbrev[0]: attr[0]: code = 16, form = 6, offset = 267 +abbrev[0]: attr[1]: code = 18, form = 1, offset = 269 +abbrev[0]: attr[2]: code = 17, form = 1, offset = 271 +abbrev[0]: attr[3]: code = 3, form = 8, offset = 273 +abbrev[0]: attr[4]: code = 27, form = 8, offset = 275 +abbrev[0]: attr[5]: code = 37, form = 8, offset = 277 +abbrev[0]: attr[6]: code = 19, form = 11, offset = 279 +abbrev[19]: code = 2, tag = 46, children = 1 +abbrev[19]: attr[0]: code = 1, form = 19, offset = 286 +abbrev[19]: attr[1]: code = 63, form = 12, offset = 288 +abbrev[19]: attr[2]: code = 3, form = 8, offset = 290 +abbrev[19]: attr[3]: code = 58, form = 11, offset = 292 +abbrev[19]: attr[4]: code = 59, form = 11, offset = 294 +abbrev[19]: attr[5]: code = 39, form = 12, offset = 296 +abbrev[19]: attr[6]: code = 73, form = 19, offset = 298 +abbrev[19]: attr[7]: code = 17, form = 1, offset = 300 +abbrev[19]: attr[8]: code = 18, form = 1, offset = 302 +abbrev[19]: attr[9]: code = 64, form = 10, offset = 304 +abbrev[44]: code = 3, tag = 46, children = 1 +abbrev[44]: attr[0]: code = 1, form = 19, offset = 311 +abbrev[44]: attr[1]: code = 63, form = 12, offset = 313 +abbrev[44]: attr[2]: code = 3, form = 8, offset = 315 +abbrev[44]: attr[3]: code = 58, form = 11, offset = 317 +abbrev[44]: attr[4]: code = 59, form = 11, offset = 319 +abbrev[44]: attr[5]: code = 73, form = 19, offset = 321 +abbrev[44]: attr[6]: code = 60, form = 12, offset = 323 +abbrev[63]: code = 4, tag = 24, children = 0 +abbrev[68]: code = 5, tag = 46, children = 1 +abbrev[68]: attr[0]: code = 63, form = 12, offset = 335 +abbrev[68]: attr[1]: code = 3, form = 8, offset = 337 +abbrev[68]: attr[2]: code = 58, form = 11, offset = 339 +abbrev[68]: attr[3]: code = 59, form = 11, offset = 341 +abbrev[68]: attr[4]: code = 73, form = 19, offset = 343 +abbrev[68]: attr[5]: code = 60, form = 12, offset = 345 +abbrev[85]: code = 6, tag = 36, children = 0 +abbrev[85]: attr[0]: code = 3, form = 8, offset = 352 +abbrev[85]: attr[1]: code = 11, form = 11, offset = 354 +abbrev[85]: attr[2]: code = 62, form = 11, offset = 356 +abbrev[96]: code = 7, tag = 52, children = 0 +abbrev[96]: attr[0]: code = 3, form = 8, offset = 363 +abbrev[96]: attr[1]: code = 58, form = 11, offset = 365 +abbrev[96]: attr[2]: code = 59, form = 11, offset = 367 +abbrev[96]: attr[3]: code = 73, form = 19, offset = 369 +abbrev[96]: attr[4]: code = 63, form = 12, offset = 371 +abbrev[96]: attr[5]: code = 2, form = 10, offset = 373 +EOF + +rm -f testfile testfile2 show-abbrev.out + +exit 0 diff --git a/tests/run-show-ciefde.sh b/tests/run-show-ciefde.sh new file mode 100644 index 00000000..b3355334 --- /dev/null +++ b/tests/run-show-ciefde.sh @@ -0,0 +1,319 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile3.bz2 > testfile3 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile4.bz2 > testfile4 2>/dev/null || exit 0 + +./show-ciefde testfile3 testfile4 > show-ciefde.out + +diff -u show-ciefde.out - <<"EOF" +testfile3 has 1 CIEs and 1 FDEs +CIE[0]: bytes_in_cie = 16, version = 1, augmenter = "" +CIE[0]: code_alignment_factor = 1 +CIE[0]: data_alignment_factor = fffffffffffffffc +CIE[0]: return_address_register = 8 +CIE[0]: bytes = 0c 04 04 88 01 00 00 +FDE[0]: low_pc = 0x804842c, length = 41 +FDE[0]: bytes = 18 00 00 00 18 00 00 00 2c 84 04 08 29 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[0]: cie_offset = 0, cie_index = 0, fde_offset = 24 +FDE[0]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +no FDE at 8048400 +FDE[@804842c]: cie_offset = 0, cie_index = 0, fde_offset = 24 +FDE[@8048454]: cie_offset = 0, cie_index = 0, fde_offset = 24 +no FDE at 8048455 +no FDE at 80493fc +testfile4 has 5 CIEs and 61 FDEs +CIE[0]: bytes_in_cie = 20, version = 1, augmenter = "eh" +CIE[0]: code_alignment_factor = 1 +CIE[0]: data_alignment_factor = fffffffffffffffc +CIE[0]: return_address_register = 8 +CIE[0]: bytes = 0c 04 04 88 01 +CIE[1]: bytes_in_cie = 16, version = 1, augmenter = "" +CIE[1]: code_alignment_factor = 1 +CIE[1]: data_alignment_factor = fffffffffffffffc +CIE[1]: return_address_register = 8 +CIE[1]: bytes = 0c 04 04 88 01 00 00 +CIE[2]: bytes_in_cie = 16, version = 1, augmenter = "" +CIE[2]: code_alignment_factor = 1 +CIE[2]: data_alignment_factor = fffffffffffffffc +CIE[2]: return_address_register = 8 +CIE[2]: bytes = 0c 04 04 88 01 00 00 +CIE[3]: bytes_in_cie = 20, version = 1, augmenter = "eh" +CIE[3]: code_alignment_factor = 1 +CIE[3]: data_alignment_factor = fffffffffffffffc +CIE[3]: return_address_register = 8 +CIE[3]: bytes = 0c 04 04 88 01 +CIE[4]: bytes_in_cie = 16, version = 1, augmenter = "" +CIE[4]: code_alignment_factor = 1 +CIE[4]: data_alignment_factor = fffffffffffffffc +CIE[4]: return_address_register = 8 +CIE[4]: bytes = 0c 04 04 88 01 00 00 +FDE[0]: low_pc = 0x80493fc, length = 154 +FDE[0]: bytes = 2c 00 00 00 1c 00 00 00 fc 93 04 08 9a 00 00 00 41 0e 08 85 02 42 0d 05 53 2e 08 50 2e 10 48 2e 00 58 2e 10 62 2e 00 63 2e 10 45 2e 00 00 00 00 +FDE[0]: cie_offset = 0, cie_index = 0, fde_offset = 28 +FDE[0]: instructions = 41 0e 08 85 02 42 0d 05 53 2e 08 50 2e 10 48 2e 00 58 2e 10 62 2e 00 63 2e 10 45 2e 00 00 00 00 +FDE[1]: low_pc = 0x8049498, length = 49 +FDE[1]: bytes = 18 00 00 00 4c 00 00 00 98 94 04 08 31 00 00 00 41 0e 08 85 02 42 0d 05 4c 2e 10 00 +FDE[1]: cie_offset = 0, cie_index = 0, fde_offset = 76 +FDE[1]: instructions = 41 0e 08 85 02 42 0d 05 4c 2e 10 00 +FDE[2]: low_pc = 0x80494d4, length = 23 +FDE[2]: bytes = 18 00 00 00 18 00 00 00 d4 94 04 08 17 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[2]: cie_offset = 100, cie_index = 1, fde_offset = 24 +FDE[2]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[3]: low_pc = 0x80494f0, length = 26 +FDE[3]: bytes = 18 00 00 00 34 00 00 00 f0 94 04 08 1a 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[3]: cie_offset = 100, cie_index = 1, fde_offset = 52 +FDE[3]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[4]: low_pc = 0x8049560, length = 85 +FDE[4]: bytes = 24 00 00 00 50 00 00 00 60 95 04 08 55 00 00 00 41 0e 08 85 02 42 0d 05 41 86 03 41 83 04 53 2e 10 4e 2e 00 55 2e 10 00 +FDE[4]: cie_offset = 100, cie_index = 1, fde_offset = 80 +FDE[4]: instructions = 41 0e 08 85 02 42 0d 05 41 86 03 41 83 04 53 2e 10 4e 2e 00 55 2e 10 00 +FDE[5]: low_pc = 0x80495c0, length = 66 +FDE[5]: bytes = 20 00 00 00 78 00 00 00 c0 95 04 08 42 00 00 00 41 0e 08 85 02 42 0d 05 41 86 03 41 83 04 5e 2e 10 00 00 00 +FDE[5]: cie_offset = 100, cie_index = 1, fde_offset = 120 +FDE[5]: instructions = 41 0e 08 85 02 42 0d 05 41 86 03 41 83 04 5e 2e 10 00 00 00 +FDE[6]: low_pc = 0x8049610, length = 28 +FDE[6]: bytes = 18 00 00 00 9c 00 00 00 10 96 04 08 1c 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[6]: cie_offset = 100, cie_index = 1, fde_offset = 156 +FDE[6]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[7]: low_pc = 0x8049630, length = 31 +FDE[7]: bytes = 18 00 00 00 b8 00 00 00 30 96 04 08 1f 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[7]: cie_offset = 100, cie_index = 1, fde_offset = 184 +FDE[7]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[8]: low_pc = 0x80496e0, length = 71 +FDE[8]: bytes = 1c 00 00 00 d4 00 00 00 e0 96 04 08 47 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 5c 2e 10 00 00 +FDE[8]: cie_offset = 100, cie_index = 1, fde_offset = 212 +FDE[8]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 5c 2e 10 00 00 +FDE[9]: low_pc = 0x8049730, length = 165 +FDE[9]: bytes = 20 00 00 00 f4 00 00 00 30 97 04 08 a5 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 69 2e 10 02 66 2e 00 00 00 +FDE[9]: cie_offset = 100, cie_index = 1, fde_offset = 244 +FDE[9]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 69 2e 10 02 66 2e 00 00 00 +FDE[10]: low_pc = 0x80497e0, length = 89 +FDE[10]: bytes = 1c 00 00 00 18 01 00 00 e0 97 04 08 59 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 74 2e 10 00 00 +FDE[10]: cie_offset = 100, cie_index = 1, fde_offset = 280 +FDE[10]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 74 2e 10 00 00 +FDE[11]: low_pc = 0x8049840, length = 89 +FDE[11]: bytes = 28 00 00 00 38 01 00 00 40 98 04 08 59 00 00 00 41 0e 08 85 02 42 0d 05 41 86 03 41 83 04 55 2e 10 4e 2e 00 52 2e 10 4c 2e 00 00 00 +FDE[11]: cie_offset = 100, cie_index = 1, fde_offset = 312 +FDE[11]: instructions = 41 0e 08 85 02 42 0d 05 41 86 03 41 83 04 55 2e 10 4e 2e 00 52 2e 10 4c 2e 00 00 00 +FDE[12]: low_pc = 0x80498a0, length = 176 +FDE[12]: bytes = 24 00 00 00 64 01 00 00 a0 98 04 08 b0 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 5e 2e 10 4c 2e 00 00 +FDE[12]: cie_offset = 100, cie_index = 1, fde_offset = 356 +FDE[12]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 5e 2e 10 4c 2e 00 00 +FDE[13]: low_pc = 0x8049950, length = 116 +FDE[13]: bytes = 24 00 00 00 8c 01 00 00 50 99 04 08 74 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 5e 2e 10 00 00 00 +FDE[13]: cie_offset = 100, cie_index = 1, fde_offset = 396 +FDE[13]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 5e 2e 10 00 00 00 +FDE[14]: low_pc = 0x80499d0, length = 31 +FDE[14]: bytes = 18 00 00 00 b4 01 00 00 d0 99 04 08 1f 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[14]: cie_offset = 100, cie_index = 1, fde_offset = 436 +FDE[14]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[15]: low_pc = 0x80499f0, length = 313 +FDE[15]: bytes = 24 00 00 00 d0 01 00 00 f0 99 04 08 39 01 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 d8 2e 10 62 2e 00 +FDE[15]: cie_offset = 100, cie_index = 1, fde_offset = 464 +FDE[15]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 d8 2e 10 62 2e 00 +FDE[16]: low_pc = 0x8049b30, length = 262 +FDE[16]: bytes = 24 00 00 00 f8 01 00 00 30 9b 04 08 06 01 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 c8 2e 10 62 2e 00 +FDE[16]: cie_offset = 100, cie_index = 1, fde_offset = 504 +FDE[16]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 c8 2e 10 62 2e 00 +FDE[17]: low_pc = 0x8049c40, length = 95 +FDE[17]: bytes = 1c 00 00 00 20 02 00 00 40 9c 04 08 5f 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 6e 2e 10 00 00 +FDE[17]: cie_offset = 100, cie_index = 1, fde_offset = 544 +FDE[17]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 6e 2e 10 00 00 +FDE[18]: low_pc = 0x8049d60, length = 230 +FDE[18]: bytes = 20 00 00 00 40 02 00 00 60 9d 04 08 e6 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 02 9a 2e 10 00 00 +FDE[18]: cie_offset = 100, cie_index = 1, fde_offset = 576 +FDE[18]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 02 9a 2e 10 00 00 +FDE[19]: low_pc = 0x8049e50, length = 85 +FDE[19]: bytes = 18 00 00 00 64 02 00 00 50 9e 04 08 55 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[19]: cie_offset = 100, cie_index = 1, fde_offset = 612 +FDE[19]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[20]: low_pc = 0x8049eb0, length = 144 +FDE[20]: bytes = 20 00 00 00 80 02 00 00 b0 9e 04 08 90 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 5b 2e 10 +FDE[20]: cie_offset = 100, cie_index = 1, fde_offset = 640 +FDE[20]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 5b 2e 10 +FDE[21]: low_pc = 0x8049f40, length = 115 +FDE[21]: bytes = 20 00 00 00 a4 02 00 00 40 9f 04 08 73 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 59 2e 10 +FDE[21]: cie_offset = 100, cie_index = 1, fde_offset = 676 +FDE[21]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 59 2e 10 +FDE[22]: low_pc = 0x8049fd0, length = 948 +FDE[22]: bytes = 30 00 00 00 c8 02 00 00 d0 9f 04 08 b4 03 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 f7 2e 20 02 64 2e 10 03 15 01 2e 00 02 9f 2e 10 00 00 +FDE[22]: cie_offset = 100, cie_index = 1, fde_offset = 712 +FDE[22]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 f7 2e 20 02 64 2e 10 03 15 01 2e 00 02 9f 2e 10 00 00 +FDE[23]: low_pc = 0x804a390, length = 201 +FDE[23]: bytes = 28 00 00 00 fc 02 00 00 90 a3 04 08 c9 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 58 2e 10 52 2e 00 75 2e 10 00 +FDE[23]: cie_offset = 100, cie_index = 1, fde_offset = 764 +FDE[23]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 58 2e 10 52 2e 00 75 2e 10 00 +FDE[24]: low_pc = 0x804a460, length = 206 +FDE[24]: bytes = 28 00 00 00 28 03 00 00 60 a4 04 08 ce 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 64 2e 10 52 2e 00 6e 2e 10 00 +FDE[24]: cie_offset = 100, cie_index = 1, fde_offset = 808 +FDE[24]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 64 2e 10 52 2e 00 6e 2e 10 00 +FDE[25]: low_pc = 0x804b970, length = 1274 +FDE[25]: bytes = 44 00 00 00 18 00 00 00 70 b9 04 08 fa 04 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 66 2e 10 7b 2e 20 03 7f 01 2e 10 53 2e 08 4c 2e 10 79 2e 20 02 54 2e 10 7e 2e 20 03 6c 01 2e 10 02 45 2e 20 00 00 00 +FDE[25]: cie_offset = 948, cie_index = 2, fde_offset = 24 +FDE[25]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 66 2e 10 7b 2e 20 03 7f 01 2e 10 53 2e 08 4c 2e 10 79 2e 20 02 54 2e 10 7e 2e 20 03 6c 01 2e 10 02 45 2e 20 00 00 00 +FDE[26]: low_pc = 0x804be70, length = 60 +FDE[26]: bytes = 1c 00 00 00 60 00 00 00 70 be 04 08 3c 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 5e 2e 10 00 00 +FDE[26]: cie_offset = 948, cie_index = 2, fde_offset = 96 +FDE[26]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 5e 2e 10 00 00 +FDE[27]: low_pc = 0x804c090, length = 85 +FDE[27]: bytes = 24 00 00 00 80 00 00 00 90 c0 04 08 55 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 66 2e 04 4d 2e 0c 4c 2e 04 46 2e 20 00 +FDE[27]: cie_offset = 948, cie_index = 2, fde_offset = 128 +FDE[27]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 66 2e 04 4d 2e 0c 4c 2e 04 46 2e 20 00 +FDE[28]: low_pc = 0x804c0f0, length = 75 +FDE[28]: bytes = 2c 00 00 00 a8 00 00 00 f0 c0 04 08 4b 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 5b 2e 04 4a 2e 0c 4d 2e 04 46 2e 20 00 00 00 +FDE[28]: cie_offset = 948, cie_index = 2, fde_offset = 168 +FDE[28]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 5b 2e 04 4a 2e 0c 4d 2e 04 46 2e 20 00 00 00 +FDE[29]: low_pc = 0x804d8e0, length = 71 +FDE[29]: bytes = 20 00 00 00 d8 00 00 00 e0 d8 04 08 47 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[29]: cie_offset = 948, cie_index = 2, fde_offset = 216 +FDE[29]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[30]: low_pc = 0x804d980, length = 71 +FDE[30]: bytes = 20 00 00 00 fc 00 00 00 80 d9 04 08 47 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[30]: cie_offset = 948, cie_index = 2, fde_offset = 252 +FDE[30]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[31]: low_pc = 0x804da20, length = 71 +FDE[31]: bytes = 20 00 00 00 20 01 00 00 20 da 04 08 47 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[31]: cie_offset = 948, cie_index = 2, fde_offset = 288 +FDE[31]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[32]: low_pc = 0x804dac0, length = 71 +FDE[32]: bytes = 20 00 00 00 44 01 00 00 c0 da 04 08 47 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[32]: cie_offset = 948, cie_index = 2, fde_offset = 324 +FDE[32]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[33]: low_pc = 0x804db60, length = 71 +FDE[33]: bytes = 20 00 00 00 68 01 00 00 60 db 04 08 47 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[33]: cie_offset = 948, cie_index = 2, fde_offset = 360 +FDE[33]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[34]: low_pc = 0x804dc00, length = 71 +FDE[34]: bytes = 20 00 00 00 8c 01 00 00 00 dc 04 08 47 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[34]: cie_offset = 948, cie_index = 2, fde_offset = 396 +FDE[34]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[35]: low_pc = 0x804dca0, length = 71 +FDE[35]: bytes = 20 00 00 00 b0 01 00 00 a0 dc 04 08 47 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[35]: cie_offset = 948, cie_index = 2, fde_offset = 432 +FDE[35]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 60 2e 10 +FDE[36]: low_pc = 0x804c5b4, length = 26 +FDE[36]: bytes = 18 00 00 00 1c 00 00 00 b4 c5 04 08 1a 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[36]: cie_offset = 1412, cie_index = 3, fde_offset = 28 +FDE[36]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[37]: low_pc = 0x804c5d0, length = 23 +FDE[37]: bytes = 18 00 00 00 38 00 00 00 d0 c5 04 08 17 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[37]: cie_offset = 1412, cie_index = 3, fde_offset = 56 +FDE[37]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[38]: low_pc = 0x804c640, length = 24 +FDE[38]: bytes = 18 00 00 00 54 00 00 00 40 c6 04 08 18 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[38]: cie_offset = 1412, cie_index = 3, fde_offset = 84 +FDE[38]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[39]: low_pc = 0x804c660, length = 32 +FDE[39]: bytes = 18 00 00 00 70 00 00 00 60 c6 04 08 20 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[39]: cie_offset = 1412, cie_index = 3, fde_offset = 112 +FDE[39]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[40]: low_pc = 0x804c680, length = 29 +FDE[40]: bytes = 18 00 00 00 8c 00 00 00 80 c6 04 08 1d 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[40]: cie_offset = 1412, cie_index = 3, fde_offset = 140 +FDE[40]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[41]: low_pc = 0x804c6a0, length = 36 +FDE[41]: bytes = 18 00 00 00 a8 00 00 00 a0 c6 04 08 24 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[41]: cie_offset = 1412, cie_index = 3, fde_offset = 168 +FDE[41]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[42]: low_pc = 0x804c6d0, length = 98 +FDE[42]: bytes = 24 00 00 00 c4 00 00 00 d0 c6 04 08 62 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 43 2e 10 00 00 00 +FDE[42]: cie_offset = 1412, cie_index = 3, fde_offset = 196 +FDE[42]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 43 2e 10 00 00 00 +FDE[43]: low_pc = 0x804c740, length = 107 +FDE[43]: bytes = 24 00 00 00 ec 00 00 00 40 c7 04 08 6b 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 53 2e 10 7b 2e 00 00 +FDE[43]: cie_offset = 1412, cie_index = 3, fde_offset = 236 +FDE[43]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 53 2e 10 7b 2e 00 00 +FDE[44]: low_pc = 0x804c7b0, length = 256 +FDE[44]: bytes = 24 00 00 00 14 01 00 00 b0 c7 04 08 00 01 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 bf 2e 10 00 00 00 +FDE[44]: cie_offset = 1412, cie_index = 3, fde_offset = 276 +FDE[44]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 02 bf 2e 10 00 00 00 +FDE[45]: low_pc = 0x804c8b0, length = 78 +FDE[45]: bytes = 1c 00 00 00 3c 01 00 00 b0 c8 04 08 4e 00 00 00 41 0e 08 85 02 42 0d 05 41 86 03 41 83 04 00 00 +FDE[45]: cie_offset = 1412, cie_index = 3, fde_offset = 316 +FDE[45]: instructions = 41 0e 08 85 02 42 0d 05 41 86 03 41 83 04 00 00 +FDE[46]: low_pc = 0x804c900, length = 480 +FDE[46]: bytes = 40 00 00 00 5c 01 00 00 00 c9 04 08 e0 01 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 7d 2e 10 4c 2e 00 02 48 2e 10 02 54 2e 00 78 2e 10 4c 2e 00 02 44 2e 10 79 2e 08 49 2e 10 48 2e 00 00 00 +FDE[46]: cie_offset = 1412, cie_index = 3, fde_offset = 348 +FDE[46]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 7d 2e 10 4c 2e 00 02 48 2e 10 02 54 2e 00 78 2e 10 4c 2e 00 02 44 2e 10 79 2e 08 49 2e 10 48 2e 00 00 00 +FDE[47]: low_pc = 0x804cae0, length = 37 +FDE[47]: bytes = 1c 00 00 00 a0 01 00 00 e0 ca 04 08 25 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 52 2e 10 00 00 +FDE[47]: cie_offset = 1412, cie_index = 3, fde_offset = 416 +FDE[47]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 52 2e 10 00 00 +FDE[48]: low_pc = 0x804cb10, length = 128 +FDE[48]: bytes = 2c 00 00 00 c0 01 00 00 10 cb 04 08 80 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 62 2e 10 56 2e 08 49 2e 10 48 2e 00 6c 2e 10 +FDE[48]: cie_offset = 1412, cie_index = 3, fde_offset = 448 +FDE[48]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 62 2e 10 56 2e 08 49 2e 10 48 2e 00 6c 2e 10 +FDE[49]: low_pc = 0x804cb90, length = 128 +FDE[49]: bytes = 2c 00 00 00 f0 01 00 00 90 cb 04 08 80 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 62 2e 10 56 2e 08 49 2e 10 48 2e 00 6c 2e 10 +FDE[49]: cie_offset = 1412, cie_index = 3, fde_offset = 496 +FDE[49]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 62 2e 10 56 2e 08 49 2e 10 48 2e 00 6c 2e 10 +FDE[50]: low_pc = 0x804cc10, length = 45 +FDE[50]: bytes = 18 00 00 00 20 02 00 00 10 cc 04 08 2d 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[50]: cie_offset = 1412, cie_index = 3, fde_offset = 544 +FDE[50]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[51]: low_pc = 0x804cc40, length = 43 +FDE[51]: bytes = 18 00 00 00 3c 02 00 00 40 cc 04 08 2b 00 00 00 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[51]: cie_offset = 1412, cie_index = 3, fde_offset = 572 +FDE[51]: instructions = 41 0e 08 85 02 42 0d 05 41 83 03 00 +FDE[52]: low_pc = 0x804cde0, length = 89 +FDE[52]: bytes = 20 00 00 00 18 00 00 00 e0 cd 04 08 59 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 6d 2e 20 00 00 00 +FDE[52]: cie_offset = 2008, cie_index = 4, fde_offset = 24 +FDE[52]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 6d 2e 20 00 00 00 +FDE[53]: low_pc = 0x804ce40, length = 217 +FDE[53]: bytes = 20 00 00 00 3c 00 00 00 40 ce 04 08 d9 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 02 40 2e 20 00 00 +FDE[53]: cie_offset = 2008, cie_index = 4, fde_offset = 60 +FDE[53]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 02 40 2e 20 00 00 +FDE[54]: low_pc = 0x804d010, length = 117 +FDE[54]: bytes = 24 00 00 00 60 00 00 00 10 d0 04 08 75 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 5c 2e 10 02 48 2e 20 +FDE[54]: cie_offset = 2008, cie_index = 4, fde_offset = 96 +FDE[54]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 5c 2e 10 02 48 2e 20 +FDE[55]: low_pc = 0x804d090, length = 190 +FDE[55]: bytes = 24 00 00 00 88 00 00 00 90 d0 04 08 be 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 64 2e 10 02 89 2e 20 +FDE[55]: cie_offset = 2008, cie_index = 4, fde_offset = 136 +FDE[55]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 64 2e 10 02 89 2e 20 +FDE[56]: low_pc = 0x804d150, length = 101 +FDE[56]: bytes = 24 00 00 00 b0 00 00 00 50 d1 04 08 65 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 61 2e 10 73 2e 20 00 +FDE[56]: cie_offset = 2008, cie_index = 4, fde_offset = 176 +FDE[56]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 61 2e 10 73 2e 20 00 +FDE[57]: low_pc = 0x804d1c0, length = 480 +FDE[57]: bytes = 28 00 00 00 d8 00 00 00 c0 d1 04 08 e0 01 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 56 2e 10 02 f5 2e 20 02 91 2e 10 +FDE[57]: cie_offset = 2008, cie_index = 4, fde_offset = 216 +FDE[57]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 56 2e 10 02 f5 2e 20 02 91 2e 10 +FDE[58]: low_pc = 0x804d3a0, length = 897 +FDE[58]: bytes = 28 00 00 00 04 01 00 00 a0 d3 04 08 81 03 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 61 2e 10 03 61 01 2e 20 00 00 00 +FDE[58]: cie_offset = 2008, cie_index = 4, fde_offset = 260 +FDE[58]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 61 2e 10 03 61 01 2e 20 00 00 00 +FDE[59]: low_pc = 0x804d730, length = 238 +FDE[59]: bytes = 24 00 00 00 30 01 00 00 30 d7 04 08 ee 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 61 2e 10 02 8f 2e 20 +FDE[59]: cie_offset = 2008, cie_index = 4, fde_offset = 304 +FDE[59]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 41 86 04 41 83 05 61 2e 10 02 8f 2e 20 +FDE[60]: low_pc = 0x804e220, length = 73 +FDE[60]: bytes = 20 00 00 00 58 01 00 00 20 e2 04 08 49 00 00 00 41 0e 08 85 02 42 0d 05 41 87 03 44 86 04 74 2e 20 00 00 00 +FDE[60]: cie_offset = 2008, cie_index = 4, fde_offset = 344 +FDE[60]: instructions = 41 0e 08 85 02 42 0d 05 41 87 03 44 86 04 74 2e 20 00 00 00 +no FDE at 8048400 +no FDE at 804842c +no FDE at 8048454 +no FDE at 8048455 +FDE[@80493fc]: cie_offset = 0, cie_index = 0, fde_offset = 28 +EOF + +rm -f testfile3 testfile4 show-ciefde.out + +exit 0 diff --git a/tests/run-show-die-info.sh b/tests/run-show-die-info.sh new file mode 100644 index 00000000..04263268 --- /dev/null +++ b/tests/run-show-die-info.sh @@ -0,0 +1,988 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002, 2003, 2004 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile5.bz2 > testfile5 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/testfile2.bz2 > testfile2 2>/dev/null || exit 0 + +./show-die-info testfile5 testfile2 > show-die-info.out + +diff -u show-die-info.out - <<"EOF" +file: testfile5 +New CU: off = 0, hsize = 11, ab = 0, as = 4, os = 4 + DW_TAG_compile_unit + Name : b.c + Offset : 11 + CU offset : 11 + Attrs : name stmt_list low_pc high_pc language comp_dir producer + low PC : 0x804842c + high PC : 0x8048436 + language : 1 + directory : /home/drepper/gnu/new-bu/build/ttt + producer : GNU C 2.96 20000731 (Red Hat Linux 7.0) + DW_TAG_subprogram + Name : bar + Offset : 104 + CU offset : 104 + Attrs : name low_pc high_pc prototyped decl_file decl_line external frame_base type + low PC : 0x804842c + high PC : 0x8048436 + DW_TAG_base_type + Name : int + Offset : 127 + CU offset : 127 + Attrs : name byte_size encoding + byte size : 4 +New CU: off = 135, hsize = 11, ab = 54, as = 4, os = 4 + DW_TAG_compile_unit + Name : f.c + Offset : 146 + CU offset : 11 + Attrs : name stmt_list low_pc high_pc language comp_dir producer + low PC : 0x8048438 + high PC : 0x8048442 + language : 1 + directory : /home/drepper/gnu/new-bu/build/ttt + producer : GNU C 2.96 20000731 (Red Hat Linux 7.0) + DW_TAG_subprogram + Name : foo + Offset : 239 + CU offset : 104 + Attrs : name low_pc high_pc prototyped decl_file decl_line external frame_base type + low PC : 0x8048438 + high PC : 0x8048442 + DW_TAG_base_type + Name : int + Offset : 262 + CU offset : 127 + Attrs : name byte_size encoding + byte size : 4 +New CU: off = 270, hsize = 11, ab = 108, as = 4, os = 4 + DW_TAG_compile_unit + Name : m.c + Offset : 281 + CU offset : 11 + Attrs : name stmt_list low_pc high_pc language comp_dir producer + low PC : 0x8048444 + high PC : 0x8048472 + language : 1 + directory : /home/drepper/gnu/new-bu/build/ttt + producer : GNU C 2.96 20000731 (Red Hat Linux 7.0) + DW_TAG_subprogram + Name : main + Offset : 374 + CU offset : 104 + Attrs : sibling name low_pc high_pc prototyped decl_file decl_line external frame_base type + low PC : 0x8048444 + high PC : 0x8048472 + DW_TAG_subprogram + Name : bar + Offset : 402 + CU offset : 132 + Attrs : sibling name decl_file decl_line declaration external type + DW_TAG_unspecified_parameters + Name : * NO NAME * + Offset : 419 + CU offset : 149 + Attrs : + DW_TAG_subprogram + Name : foo + Offset : 421 + CU offset : 151 + Attrs : name decl_file decl_line declaration external type + DW_TAG_unspecified_parameters + Name : * NO NAME * + Offset : 434 + CU offset : 164 + Attrs : + DW_TAG_base_type + Name : int + Offset : 437 + CU offset : 167 + Attrs : name byte_size encoding + byte size : 4 + DW_TAG_variable + Name : a + Offset : 444 + CU offset : 174 + Attrs : location name decl_file decl_line external type +file: testfile2 +New CU: off = 0, hsize = 11, ab = 0, as = 4, os = 4 + DW_TAG_compile_unit + Name : b.c + Offset : 11 + CU offset : 11 + Attrs : name stmt_list low_pc high_pc language comp_dir producer + low PC : 0x10000470 + high PC : 0x10000490 + language : 1 + directory : /shoggoth/drepper + producer : GNU C 2.96-laurel-000912 + DW_TAG_subprogram + Name : bar + Offset : 72 + CU offset : 72 + Attrs : name low_pc high_pc prototyped decl_file decl_line external frame_base type + low PC : 0x10000470 + high PC : 0x10000490 + DW_TAG_base_type + Name : int + Offset : 95 + CU offset : 95 + Attrs : name byte_size encoding + byte size : 4 + DW_TAG_typedef + Name : size_t + Offset : 102 + CU offset : 102 + Attrs : name decl_file decl_line type + DW_TAG_base_type + Name : unsigned int + Offset : 116 + CU offset : 116 + Attrs : name byte_size encoding + byte size : 4 + DW_TAG_typedef + Name : __gnuc_va_list + Offset : 132 + CU offset : 132 + Attrs : name decl_file decl_line type + DW_TAG_array_type + Name : __builtin_va_list + Offset : 154 + CU offset : 154 + Attrs : sibling name type + DW_TAG_subrange_type + Name : * NO NAME * + Offset : 181 + CU offset : 181 + Attrs : upper_bound type + DW_TAG_base_type + Name : unsigned int + Offset : 188 + CU offset : 188 + Attrs : name byte_size encoding + byte size : 4 + DW_TAG_structure_type + Name : __va_list_tag + Offset : 204 + CU offset : 204 + Attrs : sibling name byte_size decl_file decl_line + byte size : 12 + DW_TAG_member + Name : gpr + Offset : 226 + CU offset : 226 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : fpr + Offset : 240 + CU offset : 240 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : overflow_arg_area + Offset : 254 + CU offset : 254 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : reg_save_area + Offset : 282 + CU offset : 282 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_base_type + Name : unsigned char + Offset : 307 + CU offset : 307 + Attrs : name byte_size encoding + byte size : 1 + DW_TAG_pointer_type + Name : * NO NAME * + Offset : 324 + CU offset : 324 + Attrs : byte_size + byte size : 4 + DW_TAG_typedef + Name : __u_char + Offset : 326 + CU offset : 326 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __u_short + Offset : 342 + CU offset : 342 + Attrs : name decl_file decl_line type + DW_TAG_base_type + Name : short unsigned int + Offset : 359 + CU offset : 359 + Attrs : name byte_size encoding + byte size : 2 + DW_TAG_typedef + Name : __u_int + Offset : 381 + CU offset : 381 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __u_long + Offset : 396 + CU offset : 396 + Attrs : name decl_file decl_line type + DW_TAG_base_type + Name : long unsigned int + Offset : 412 + CU offset : 412 + Attrs : name byte_size encoding + byte size : 4 + DW_TAG_typedef + Name : __u_quad_t + Offset : 433 + CU offset : 433 + Attrs : name decl_file decl_line type + DW_TAG_base_type + Name : long long unsigned int + Offset : 451 + CU offset : 451 + Attrs : name byte_size encoding + byte size : 8 + DW_TAG_typedef + Name : __quad_t + Offset : 477 + CU offset : 477 + Attrs : name decl_file decl_line type + DW_TAG_base_type + Name : long long int + Offset : 493 + CU offset : 493 + Attrs : name byte_size encoding + byte size : 8 + DW_TAG_typedef + Name : __int8_t + Offset : 510 + CU offset : 510 + Attrs : name decl_file decl_line type + DW_TAG_base_type + Name : signed char + Offset : 526 + CU offset : 526 + Attrs : name byte_size encoding + byte size : 1 + DW_TAG_typedef + Name : __uint8_t + Offset : 541 + CU offset : 541 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __int16_t + Offset : 558 + CU offset : 558 + Attrs : name decl_file decl_line type + DW_TAG_base_type + Name : short int + Offset : 575 + CU offset : 575 + Attrs : name byte_size encoding + byte size : 2 + DW_TAG_typedef + Name : __uint16_t + Offset : 588 + CU offset : 588 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __int32_t + Offset : 606 + CU offset : 606 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __uint32_t + Offset : 623 + CU offset : 623 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __int64_t + Offset : 641 + CU offset : 641 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __uint64_t + Offset : 658 + CU offset : 658 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __qaddr_t + Offset : 676 + CU offset : 676 + Attrs : name decl_file decl_line type + DW_TAG_pointer_type + Name : * NO NAME * + Offset : 693 + CU offset : 693 + Attrs : byte_size type + byte size : 4 + DW_TAG_typedef + Name : __dev_t + Offset : 699 + CU offset : 699 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __uid_t + Offset : 714 + CU offset : 714 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __gid_t + Offset : 729 + CU offset : 729 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __ino_t + Offset : 744 + CU offset : 744 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __mode_t + Offset : 759 + CU offset : 759 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __nlink_t + Offset : 775 + CU offset : 775 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __off_t + Offset : 792 + CU offset : 792 + Attrs : name decl_file decl_line type + DW_TAG_base_type + Name : long int + Offset : 807 + CU offset : 807 + Attrs : name byte_size encoding + byte size : 4 + DW_TAG_typedef + Name : __loff_t + Offset : 819 + CU offset : 819 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __pid_t + Offset : 835 + CU offset : 835 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __ssize_t + Offset : 850 + CU offset : 850 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __rlim_t + Offset : 867 + CU offset : 867 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __rlim64_t + Offset : 883 + CU offset : 883 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __id_t + Offset : 901 + CU offset : 901 + Attrs : name decl_file decl_line type + DW_TAG_structure_type + Name : * NO NAME * + Offset : 915 + CU offset : 915 + Attrs : sibling byte_size decl_file decl_line + byte size : 8 + DW_TAG_member + Name : __val + Offset : 923 + CU offset : 923 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_array_type + Name : * NO NAME * + Offset : 940 + CU offset : 940 + Attrs : sibling type + DW_TAG_subrange_type + Name : * NO NAME * + Offset : 949 + CU offset : 949 + Attrs : upper_bound type + DW_TAG_typedef + Name : __fsid_t + Offset : 956 + CU offset : 956 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __daddr_t + Offset : 972 + CU offset : 972 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __caddr_t + Offset : 989 + CU offset : 989 + Attrs : name decl_file decl_line type + DW_TAG_pointer_type + Name : * NO NAME * + Offset : 1006 + CU offset : 1006 + Attrs : byte_size type + byte size : 4 + DW_TAG_base_type + Name : char + Offset : 1012 + CU offset : 1012 + Attrs : name byte_size encoding + byte size : 1 + DW_TAG_typedef + Name : __time_t + Offset : 1020 + CU offset : 1020 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __swblk_t + Offset : 1036 + CU offset : 1036 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __clock_t + Offset : 1053 + CU offset : 1053 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __fd_mask + Offset : 1070 + CU offset : 1070 + Attrs : name decl_file decl_line type + DW_TAG_structure_type + Name : * NO NAME * + Offset : 1087 + CU offset : 1087 + Attrs : sibling byte_size decl_file decl_line + byte size : 128 + DW_TAG_member + Name : __fds_bits + Offset : 1095 + CU offset : 1095 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_array_type + Name : * NO NAME * + Offset : 1117 + CU offset : 1117 + Attrs : sibling type + DW_TAG_subrange_type + Name : * NO NAME * + Offset : 1126 + CU offset : 1126 + Attrs : upper_bound type + DW_TAG_typedef + Name : __fd_set + Offset : 1133 + CU offset : 1133 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __key_t + Offset : 1149 + CU offset : 1149 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __ipc_pid_t + Offset : 1164 + CU offset : 1164 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __blkcnt_t + Offset : 1183 + CU offset : 1183 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __blkcnt64_t + Offset : 1201 + CU offset : 1201 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __fsblkcnt_t + Offset : 1221 + CU offset : 1221 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __fsblkcnt64_t + Offset : 1241 + CU offset : 1241 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __fsfilcnt_t + Offset : 1263 + CU offset : 1263 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __fsfilcnt64_t + Offset : 1283 + CU offset : 1283 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __ino64_t + Offset : 1305 + CU offset : 1305 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __off64_t + Offset : 1322 + CU offset : 1322 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __t_scalar_t + Offset : 1339 + CU offset : 1339 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __t_uscalar_t + Offset : 1359 + CU offset : 1359 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : __intptr_t + Offset : 1380 + CU offset : 1380 + Attrs : name decl_file decl_line type + DW_TAG_structure_type + Name : _IO_FILE + Offset : 1398 + CU offset : 1398 + Attrs : sibling name byte_size decl_file decl_line + byte size : 152 + DW_TAG_member + Name : _flags + Offset : 1415 + CU offset : 1415 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _IO_read_ptr + Offset : 1432 + CU offset : 1432 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _IO_read_end + Offset : 1455 + CU offset : 1455 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _IO_read_base + Offset : 1478 + CU offset : 1478 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _IO_write_base + Offset : 1502 + CU offset : 1502 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _IO_write_ptr + Offset : 1527 + CU offset : 1527 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _IO_write_end + Offset : 1551 + CU offset : 1551 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _IO_buf_base + Offset : 1575 + CU offset : 1575 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _IO_buf_end + Offset : 1598 + CU offset : 1598 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _IO_save_base + Offset : 1620 + CU offset : 1620 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _IO_backup_base + Offset : 1644 + CU offset : 1644 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _IO_save_end + Offset : 1670 + CU offset : 1670 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _markers + Offset : 1693 + CU offset : 1693 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _chain + Offset : 1712 + CU offset : 1712 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _fileno + Offset : 1729 + CU offset : 1729 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _blksize + Offset : 1747 + CU offset : 1747 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _old_offset + Offset : 1766 + CU offset : 1766 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _cur_column + Offset : 1788 + CU offset : 1788 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _vtable_offset + Offset : 1810 + CU offset : 1810 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _shortbuf + Offset : 1835 + CU offset : 1835 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _lock + Offset : 1855 + CU offset : 1855 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _offset + Offset : 1871 + CU offset : 1871 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _unused2 + Offset : 1889 + CU offset : 1889 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_structure_type + Name : _IO_marker + Offset : 1909 + CU offset : 1909 + Attrs : sibling name byte_size decl_file decl_line + byte size : 12 + DW_TAG_member + Name : _next + Offset : 1928 + CU offset : 1928 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _sbuf + Offset : 1944 + CU offset : 1944 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_member + Name : _pos + Offset : 1960 + CU offset : 1960 + Attrs : name data_member_location decl_file decl_line type + DW_TAG_pointer_type + Name : * NO NAME * + Offset : 1976 + CU offset : 1976 + Attrs : byte_size type + byte size : 4 + DW_TAG_pointer_type + Name : * NO NAME * + Offset : 1982 + CU offset : 1982 + Attrs : byte_size type + byte size : 4 + DW_TAG_array_type + Name : * NO NAME * + Offset : 1988 + CU offset : 1988 + Attrs : sibling type + DW_TAG_subrange_type + Name : * NO NAME * + Offset : 1997 + CU offset : 1997 + Attrs : upper_bound type + DW_TAG_pointer_type + Name : * NO NAME * + Offset : 2004 + CU offset : 2004 + Attrs : byte_size + byte size : 4 + DW_TAG_array_type + Name : * NO NAME * + Offset : 2006 + CU offset : 2006 + Attrs : sibling type + DW_TAG_subrange_type + Name : * NO NAME * + Offset : 2015 + CU offset : 2015 + Attrs : upper_bound type + DW_TAG_typedef + Name : FILE + Offset : 2022 + CU offset : 2022 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : wchar_t + Offset : 2034 + CU offset : 2034 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : wint_t + Offset : 2050 + CU offset : 2050 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : _G_int16_t + Offset : 2065 + CU offset : 2065 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : _G_int32_t + Offset : 2083 + CU offset : 2083 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : _G_uint16_t + Offset : 2101 + CU offset : 2101 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : _G_uint32_t + Offset : 2120 + CU offset : 2120 + Attrs : name decl_file decl_line type + DW_TAG_structure_type + Name : _IO_jump_t + Offset : 2139 + CU offset : 2139 + Attrs : name declaration + DW_TAG_typedef + Name : _IO_lock_t + Offset : 2152 + CU offset : 2152 + Attrs : name decl_file decl_line + DW_TAG_typedef + Name : _IO_FILE + Offset : 2166 + CU offset : 2166 + Attrs : name decl_file decl_line type + DW_TAG_structure_type + Name : _IO_FILE_plus + Offset : 2182 + CU offset : 2182 + Attrs : name declaration + DW_TAG_typedef + Name : __io_read_fn + Offset : 2198 + CU offset : 2198 + Attrs : name decl_file decl_line type + DW_TAG_subroutine_type + Name : * NO NAME * + Offset : 2219 + CU offset : 2219 + Attrs : sibling prototyped type + DW_TAG_formal_parameter + Name : * NO NAME * + Offset : 2229 + CU offset : 2229 + Attrs : type + DW_TAG_formal_parameter + Name : * NO NAME * + Offset : 2234 + CU offset : 2234 + Attrs : type + DW_TAG_formal_parameter + Name : * NO NAME * + Offset : 2239 + CU offset : 2239 + Attrs : type + DW_TAG_typedef + Name : __io_write_fn + Offset : 2245 + CU offset : 2245 + Attrs : name decl_file decl_line type + DW_TAG_subroutine_type + Name : * NO NAME * + Offset : 2267 + CU offset : 2267 + Attrs : sibling prototyped type + DW_TAG_formal_parameter + Name : * NO NAME * + Offset : 2277 + CU offset : 2277 + Attrs : type + DW_TAG_formal_parameter + Name : * NO NAME * + Offset : 2282 + CU offset : 2282 + Attrs : type + DW_TAG_formal_parameter + Name : * NO NAME * + Offset : 2287 + CU offset : 2287 + Attrs : type + DW_TAG_pointer_type + Name : * NO NAME * + Offset : 2293 + CU offset : 2293 + Attrs : byte_size type + byte size : 4 + DW_TAG_const_type + Name : * NO NAME * + Offset : 2299 + CU offset : 2299 + Attrs : type + DW_TAG_typedef + Name : __io_seek_fn + Offset : 2304 + CU offset : 2304 + Attrs : name decl_file decl_line type + DW_TAG_subroutine_type + Name : * NO NAME * + Offset : 2325 + CU offset : 2325 + Attrs : sibling prototyped type + DW_TAG_formal_parameter + Name : * NO NAME * + Offset : 2335 + CU offset : 2335 + Attrs : type + DW_TAG_formal_parameter + Name : * NO NAME * + Offset : 2340 + CU offset : 2340 + Attrs : type + DW_TAG_formal_parameter + Name : * NO NAME * + Offset : 2345 + CU offset : 2345 + Attrs : type + DW_TAG_typedef + Name : __io_close_fn + Offset : 2351 + CU offset : 2351 + Attrs : name decl_file decl_line type + DW_TAG_subroutine_type + Name : * NO NAME * + Offset : 2373 + CU offset : 2373 + Attrs : sibling prototyped type + DW_TAG_formal_parameter + Name : * NO NAME * + Offset : 2383 + CU offset : 2383 + Attrs : type + DW_TAG_typedef + Name : fpos_t + Offset : 2389 + CU offset : 2389 + Attrs : name decl_file decl_line type + DW_TAG_typedef + Name : off_t + Offset : 2403 + CU offset : 2403 + Attrs : name decl_file decl_line type +New CU: off = 2418, hsize = 11, ab = 213, as = 4, os = 4 + DW_TAG_compile_unit + Name : f.c + Offset : 2429 + CU offset : 11 + Attrs : name stmt_list low_pc high_pc language comp_dir producer + low PC : 0x10000490 + high PC : 0x100004b0 + language : 1 + directory : /shoggoth/drepper + producer : GNU C 2.96-laurel-000912 + DW_TAG_subprogram + Name : foo + Offset : 2490 + CU offset : 72 + Attrs : name low_pc high_pc prototyped decl_file decl_line external frame_base type + low PC : 0x10000490 + high PC : 0x100004b0 + DW_TAG_base_type + Name : int + Offset : 2513 + CU offset : 95 + Attrs : name byte_size encoding + byte size : 4 +New CU: off = 2521, hsize = 11, ab = 267, as = 4, os = 4 + DW_TAG_compile_unit + Name : m.c + Offset : 2532 + CU offset : 11 + Attrs : name stmt_list low_pc high_pc language comp_dir producer + low PC : 0x100004b0 + high PC : 0x10000514 + language : 1 + directory : /shoggoth/drepper + producer : GNU C 2.96-laurel-000912 + DW_TAG_subprogram + Name : main + Offset : 2593 + CU offset : 72 + Attrs : sibling name low_pc high_pc prototyped decl_file decl_line external frame_base type + low PC : 0x100004b0 + high PC : 0x10000514 + DW_TAG_subprogram + Name : bar + Offset : 2621 + CU offset : 100 + Attrs : sibling name decl_file decl_line declaration external type + DW_TAG_unspecified_parameters + Name : * NO NAME * + Offset : 2638 + CU offset : 117 + Attrs : + DW_TAG_subprogram + Name : foo + Offset : 2640 + CU offset : 119 + Attrs : name decl_file decl_line declaration external type + DW_TAG_unspecified_parameters + Name : * NO NAME * + Offset : 2653 + CU offset : 132 + Attrs : + DW_TAG_base_type + Name : int + Offset : 2656 + CU offset : 135 + Attrs : name byte_size encoding + byte size : 4 + DW_TAG_variable + Name : a + Offset : 2663 + CU offset : 142 + Attrs : location name decl_file decl_line external type +EOF + +rm -f testfile2 testfile5 show-die-info.out + +exit 0 diff --git a/tests/run-strip-test.sh b/tests/run-strip-test.sh new file mode 100644 index 00000000..526eb091 --- /dev/null +++ b/tests/run-strip-test.sh @@ -0,0 +1,51 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002, 2003, 2005 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. +set -e + +original=${original:-testfile11} +stripped=${stripped:-testfile7} +debugout=${debugfile:+-f testfile.debug.temp -F $debugfile} + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/$original.bz2 > $original 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +bunzip2 -c $srcdir/$stripped.bz2 > $stripped 2>/dev/null || exit 0 + +# Don't fail if we cannot decompress the file. +test -z "$debugfile" || +bunzip2 -c $srcdir/$debugfile.bz2 > $debugfile 2>/dev/null || exit 0 + +LD_LIBRARY_PATH=../libebl:../libelf${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH \ + ../src/strip -o testfile.temp $debugout $original + +cmp $stripped testfile.temp + +# Check elflint and the expected result. +LD_LIBRARY_PATH=../libebl:../libelf${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH \ + ../src/elflint -q testfile.temp + +test -z "$debugfile" || { +cmp $debugfile testfile.debug.temp + +# Check elflint and the expected result. +LD_LIBRARY_PATH=../libebl:../libelf${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH \ + ../src/elflint -q -d testfile.debug.temp + +rm -f "$debugfile" +} + +rm -f $original $stripped testfile.temp testfile.debug.temp + +exit 0 diff --git a/tests/run-strip-test2.sh b/tests/run-strip-test2.sh new file mode 100644 index 00000000..824361c6 --- /dev/null +++ b/tests/run-strip-test2.sh @@ -0,0 +1,17 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002, 2005 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. + +original=testfile8 +stripped=testfile9 +. $srcdir/run-strip-test.sh diff --git a/tests/run-strip-test3.sh b/tests/run-strip-test3.sh new file mode 100644 index 00000000..3e8ac875 --- /dev/null +++ b/tests/run-strip-test3.sh @@ -0,0 +1,17 @@ +#! /bin/sh +# Copyright (C) 1999, 2000, 2002, 2003, 2005 Red Hat, Inc. +# Written by Ulrich Drepper , 1999. +# +# This program is Open Source software; you can redistribute it and/or +# modify it under the terms of the Open Software License version 1.0 as +# published by the Open Source Initiative. +# +# You should have received a copy of the Open Software License along +# with this program; if not, you may obtain a copy of the Open Software +# License version 1.0 from http://www.opensource.org/licenses/osl.php or +# by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +# 3001 King Ranch Road, Ukiah, CA 95482. + +original=testfile12 +stripped=testfile13 +. $srcdir/run-strip-test.sh diff --git a/tests/run-strip-test4.sh b/tests/run-strip-test4.sh new file mode 100644 index 00000000..8e9be228 --- /dev/null +++ b/tests/run-strip-test4.sh @@ -0,0 +1,5 @@ +original=testfile11 +stripped=testfile15 +debugfile=testfile15.debug + +. $srcdir/run-strip-test.sh diff --git a/tests/run-strip-test5.sh b/tests/run-strip-test5.sh new file mode 100644 index 00000000..9fa9ebef --- /dev/null +++ b/tests/run-strip-test5.sh @@ -0,0 +1,5 @@ +original=testfile8 +stripped=testfile16 +debugfile=testfile16.debug + +. $srcdir/run-strip-test.sh diff --git a/tests/run-strip-test6.sh b/tests/run-strip-test6.sh new file mode 100644 index 00000000..8ee5f02c --- /dev/null +++ b/tests/run-strip-test6.sh @@ -0,0 +1,5 @@ +original=testfile12 +stripped=testfile17 +debugfile=testfile17.debug + +. $srcdir/run-strip-test.sh diff --git a/tests/saridx.c b/tests/saridx.c new file mode 100644 index 00000000..4abc892f --- /dev/null +++ b/tests/saridx.c @@ -0,0 +1,253 @@ +/* Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +static const char *machines[] = +{ +#define MACHINE(name) [name] = #name + MACHINE (EM_NONE), + MACHINE (EM_M32), + MACHINE (EM_SPARC), + MACHINE (EM_386), + MACHINE (EM_68K), + MACHINE (EM_88K), + MACHINE (EM_860), + MACHINE (EM_MIPS), + MACHINE (EM_MIPS_RS3_LE), + MACHINE (EM_PARISC), + MACHINE (EM_VPP500), + MACHINE (EM_SPARC32PLUS), + MACHINE (EM_960), + MACHINE (EM_PPC), + MACHINE (EM_PPC64), + MACHINE (EM_V800), + MACHINE (EM_FR20), + MACHINE (EM_RH32), + MACHINE (EM_RCE), + MACHINE (EM_ARM), + MACHINE (EM_FAKE_ALPHA), + MACHINE (EM_SH), + MACHINE (EM_SPARCV9), + MACHINE (EM_TRICORE), + MACHINE (EM_ARC), + MACHINE (EM_H8_300), + MACHINE (EM_H8_300H), + MACHINE (EM_H8S), + MACHINE (EM_H8_500), + MACHINE (EM_IA_64), + MACHINE (EM_MIPS_X), + MACHINE (EM_COLDFIRE), + MACHINE (EM_68HC12), + MACHINE (EM_MMA), + MACHINE (EM_PCP), + MACHINE (EM_NCPU), + MACHINE (EM_NDR1), + MACHINE (EM_STARCORE), + MACHINE (EM_ME16), + MACHINE (EM_ST100), + MACHINE (EM_TINYJ), + MACHINE (EM_FX66), + MACHINE (EM_ST9PLUS), + MACHINE (EM_ST7), + MACHINE (EM_68HC16), + MACHINE (EM_68HC11), + MACHINE (EM_68HC08), + MACHINE (EM_68HC05), + MACHINE (EM_SVX), + MACHINE (EM_ST19), + MACHINE (EM_VAX) +}; + + +int +main (int argc, char *argv[]) +{ + int fd; + Elf *elf; + Elf_Cmd cmd; + size_t n; + int arg = 1; + int verbose = 0; + + /* Recognize optional verbosity flag. */ + if (arg < argc && strcmp (argv[arg], "-v") == 0) + { + verbose = 1; + ++arg; + } + + /* Any more arguments available. */ + if (arg >= argc) + error (EXIT_FAILURE, 0, "No input file given"); + + /* Open the input file. */ + fd = open (argv[arg], O_RDONLY); + if (fd == -1) + { + perror ("cannot open input file"); + exit (1); + } + + /* Set the ELF version we are using here. */ + if (elf_version (EV_CURRENT) == EV_NONE) + { + puts ("ELF library too old"); + exit (1); + } + + /* Start reading the file. */ + cmd = ELF_C_READ; + elf = elf_begin (fd, cmd, NULL); + if (elf == NULL) + { + printf ("elf_begin: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* If it is no archive punt. */ + if (elf_kind (elf) != ELF_K_AR) + { + printf ("%s is not an archive\n", argv[1]); + exit (1); + } + + if (verbose) + { + /* The verbose variant. We print a lot of information. */ + Elf *subelf; + char buf[100]; + time_t t; + + /* Get the elements of the archive one after the other. */ + while ((subelf = elf_begin (fd, cmd, elf)) != NULL) + { + /* The the header for this element. */ + Elf_Arhdr *arhdr = elf_getarhdr (subelf); + + if (arhdr == NULL) + { + printf ("cannot get arhdr: %s\n", elf_errmsg (-1)); + break; + } + + switch (elf_kind (subelf)) + { + case ELF_K_ELF: + fputs ("ELF file:\n", stdout); + break; + + case ELF_K_AR: + fputs ("archive:\n", stdout); + break; + + default: + fputs ("unknown file:\n", stdout); + break; + } + + /* Print general information. */ + t = arhdr->ar_date; + strftime (buf, sizeof buf, "%Y-%m-%dT%H:%M:%S%z", gmtime (&t)); + printf (" name : \"%s\"\n" + " time : %s\n" + " uid : %ld\n" + " gid : %ld\n" + " mode : %o\n" + " size : %ld\n" + " rawname : \"%s\"\n", + arhdr->ar_name, + buf, + (long int) arhdr->ar_uid, + (long int) arhdr->ar_gid, + arhdr->ar_mode, + (long int) arhdr->ar_size, + arhdr->ar_rawname); + + /* For ELF files we can provide some more information. */ + if (elf_kind (subelf) == ELF_K_ELF) + { + GElf_Ehdr ehdr; + + /* Get the ELF header. */ + if (gelf_getehdr (subelf, &ehdr) == NULL) + printf (" *** cannot get ELF header: %s\n", elf_errmsg (-1)); + else + { + printf (" binary class : %s\n", + ehdr.e_ident[EI_CLASS] == ELFCLASS32 + ? "ELFCLASS32" : "ELFCLASS64"); + printf (" data encoding: %s\n", + ehdr.e_ident[EI_DATA] == ELFDATA2LSB + ? "ELFDATA2LSB" : "ELFDATA2MSB"); + printf (" binary type : %s\n", + ehdr.e_type == ET_REL + ? "relocatable" + : (ehdr.e_type == ET_EXEC + ? "executable" + : (ehdr.e_type == ET_DYN + ? "dynamic" + : "core file"))); + printf (" machine : %s\n", + (ehdr.e_machine >= (sizeof (machines) + / sizeof (machines[0])) + || machines[ehdr.e_machine] == NULL) + ? "???" + : machines[ehdr.e_machine]); + } + } + + /* Get next archive element. */ + cmd = elf_next (subelf); + if (elf_end (subelf) != 0) + printf ("error while freeing sub-ELF descriptor: %s\n", + elf_errmsg (-1)); + } + } + else + { + /* The simple version. Only print a bit of information. */ + Elf_Arsym *arsym = elf_getarsym (elf, &n); + + if (n == 0) + printf ("no symbol table in archive: %s\n", elf_errmsg (-1)); + else + { + --n; + + while (n-- > 0) + printf ("name = \"%s\", offset = %ld, hash = %lx\n", + arsym[n].as_name, (long int) arsym[n].as_off, + arsym[n].as_hash); + } + } + + /* Free the ELF handle. */ + if (elf_end (elf) != 0) + printf ("error while freeing ELF descriptor: %s\n", elf_errmsg (-1)); + + /* Close the underlying file. */ + close (fd); + + return 0; +} diff --git a/tests/scnnames.c b/tests/scnnames.c new file mode 100644 index 00000000..14f428d0 --- /dev/null +++ b/tests/scnnames.c @@ -0,0 +1,87 @@ +/* Copyright (C) 1998, 1999, 2000, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include + +#include +#include +#include +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + Elf *elf; + int fd; + GElf_Ehdr ehdr; + size_t strndx; + Elf_Scn *scn; + + if (argc < 2) + { + puts ("missing parameter"); + exit (1); + } + + fd = open (argv[1], O_RDONLY); + if (fd == -1) + { + printf ("cannot open \"%s\": %s\n", argv[1], strerror (errno)); + exit (1); + } + + elf_version (EV_CURRENT); + + elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) + { + printf ("cannot open ELF file: %s\n", elf_errmsg (-1)); + exit (1); + } + + if (elf_kind (elf) != ELF_K_ELF) + { + printf ("\"%s\" is not an ELF file\n", argv[1]); + exit (1); + } + + if (gelf_getehdr (elf, &ehdr) == NULL) + { + printf ("cannot get the ELF header: %s\n", elf_errmsg (-1)); + exit (1); + } + + strndx = ehdr.e_shstrndx; + + scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + char *name = NULL; + GElf_Shdr shdr; + + if (gelf_getshdr (scn, &shdr) != NULL) + name = elf_strptr (elf, strndx, (size_t) shdr.sh_name); + + printf ("section: `%s'\n", name); + } + + if (elf_end (elf) != 0) + { + printf ("error while freeing ELF descriptor: %s\n", elf_errmsg (-1)); + exit (1); + } + + return 0; +} diff --git a/tests/sectiondump.c b/tests/sectiondump.c new file mode 100644 index 00000000..f19a2151 --- /dev/null +++ b/tests/sectiondump.c @@ -0,0 +1,178 @@ +/* Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Prototypes for local functions. */ +static int handle_section (Elf *elf, Elf_Scn *scn); +static void print_bytes (Elf_Data *data); +static void print_symtab (Elf *elf, Elf_Data *data); + + +int +main (int argc, char *argv[]) +{ + Elf *elf; + int fd; + int cnt; + + if (argc <= 1) + exit (1); + + /* Open the test file. This is given as the first parameter to the + program. */ + fd = open (argv[1], O_RDONLY); + if (fd == -1) + error (EXIT_FAILURE, errno, "cannot open input file `%s'", argv[1]); + + /* Set the library versio we expect. */ + elf_version (EV_CURRENT); + + /* Create the ELF descriptor. */ + elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) + error (EXIT_FAILURE, 0, "cannot create ELF descriptor: %s", + elf_errmsg (0)); + + /* Now proces all the sections mentioned in the rest of the command line. */ + for (cnt = 2; cnt < argc; ++cnt) + if (handle_section (elf, elf_getscn (elf, atoi (argv[cnt]))) != 0) + /* When we encounter an error stop immediately. */ + error (EXIT_FAILURE, 0, "while processing section %d: %s", cnt, + elf_errmsg (0)); + + /* Close the descriptor. */ + if (elf_end (elf) != 0) + error (EXIT_FAILURE, 0, "failure while closing ELF descriptor: %s", + elf_errmsg (0)); + + return 0; +} + + +static int +handle_section (Elf *elf, Elf_Scn *scn) +{ + GElf_Ehdr *ehdr; + GElf_Ehdr ehdr_mem; + GElf_Shdr *shdr; + GElf_Shdr shdr_mem; + Elf_Data *data; + + /* First get the ELF and section header. */ + ehdr = gelf_getehdr (elf, &ehdr_mem); + shdr = gelf_getshdr (scn, &shdr_mem); + if (ehdr == NULL || shdr == NULL) + return 1; + + /* Print the information from the ELF section header. */ + printf ("name = %s\n" + "type = %" PRId32 "\n" + "flags = %" PRIx64 "\n" + "addr = %" PRIx64 "\n" + "offset = %" PRIx64 "\n" + "size = %" PRId64 "\n" + "link = %" PRId32 "\n" + "info = %" PRIx32 "\n" + "addralign = %" PRIx64 "\n" + "entsize = %" PRId64 "\n", + elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name), + shdr->sh_type, + shdr->sh_flags, + shdr->sh_addr, + shdr->sh_offset, + shdr->sh_size, + shdr->sh_link, + shdr->sh_info, + shdr->sh_addralign, + shdr->sh_entsize); + + /* Get the section data now. */ + data = elf_getdata (scn, NULL); + if (data == NULL) + return 1; + + /* Now proces the different section types accordingly. */ + switch (shdr->sh_type) + { + case SHT_SYMTAB: + print_symtab (elf, data); + break; + + case SHT_PROGBITS: + default: + print_bytes (data); + break; + } + + /* Separate form the next section. */ + puts (""); + + /* All done correctly. */ + return 0; +} + + +static void +print_bytes (Elf_Data *data) +{ + size_t size = data->d_size; + off_t offset = data->d_off; + unsigned char *buf = (unsigned char *) data->d_buf; + size_t cnt; + + for (cnt = 0; cnt < size; cnt += 16) + { + size_t inner; + + printf ("%*Zx: ", sizeof (size_t) == 4 ? 8 : 16, (size_t) offset + cnt); + + for (inner = 0; inner < 16 && cnt + inner < size; ++inner) + printf (" %02hhx", buf[cnt + inner]); + + puts (""); + } +} + + +static void +print_symtab (Elf *elf, Elf_Data *data) +{ + int class = gelf_getclass (elf); + size_t nsym = data->d_size / (class == ELFCLASS32 + ? sizeof (Elf32_Sym) : sizeof (Elf64_Sym)); + size_t cnt; + + for (cnt = 0; cnt < nsym; ++cnt) + { + GElf_Sym sym_mem; + GElf_Sym *sym = gelf_getsym (data, cnt, &sym_mem); + + printf ("%5Zu: %*" PRIx64 " %6" PRIx64 " %4d\n", + cnt, + class == ELFCLASS32 ? 8 : 16, + sym->st_value, + sym->st_size, + GELF_ST_TYPE (sym->st_info)); + } +} diff --git a/tests/show-abbrev.c b/tests/show-abbrev.c new file mode 100644 index 00000000..fba73759 --- /dev/null +++ b/tests/show-abbrev.c @@ -0,0 +1,127 @@ +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include + +#include +#include +#include +#include +#include + + +int +main (int argc, char *argv[]) +{ + int cnt; + + for (cnt = 1; cnt < argc; ++cnt) + { + int fd = open (argv[cnt], O_RDONLY); + Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg == NULL) + { + printf ("%s not usable: %s\n", argv[cnt], dwarf_errmsg (-1)); + close (fd); + continue; + } + + Dwarf_Off cuoff = 0; + Dwarf_Off old_cuoff = 0; + size_t hsize; + while (dwarf_nextcu (dbg, cuoff, &cuoff, &hsize, NULL, NULL, NULL) == 0) + { + /* Get the DIE for the CU. */ + Dwarf_Die die; + if (dwarf_offdie (dbg, old_cuoff + hsize, &die) == NULL) + /* Something went wrong. */ + break; + + Dwarf_Off offset = 0; + + while (1) + { + size_t length; + Dwarf_Abbrev *abbrev = dwarf_getabbrev (&die, offset, &length); + if (abbrev == NULL || abbrev == DWARF_END_ABBREV) + /* End of the list. */ + break; + + unsigned tag = dwarf_getabbrevtag (abbrev); + if (tag == 0) + { + printf ("dwarf_getabbrevtag at offset %llu returned error: %s\n", + (unsigned long long int) offset, + dwarf_errmsg (-1)); + break; + } + + unsigned code = dwarf_getabbrevcode (abbrev); + if (code == 0) + { + printf ("dwarf_getabbrevcode at offset %llu returned error: %s\n", + (unsigned long long int) offset, + dwarf_errmsg (-1)); + break; + } + + int children = dwarf_abbrevhaschildren (abbrev); + if (children < 0) + { + printf ("dwarf_abbrevhaschildren at offset %llu returned error: %s\n", + (unsigned long long int) offset, + dwarf_errmsg (-1)); + break; + } + + printf ("abbrev[%llu]: code = %u, tag = %u, children = %d\n", + (unsigned long long int) offset, code, tag, children); + + size_t attrcnt; + if (dwarf_getattrcnt (abbrev, &attrcnt) != 0) + { + printf ("dwarf_getattrcnt at offset %llu returned error: %s\n", + (unsigned long long int) offset, + dwarf_errmsg (-1)); + break; + } + + unsigned int attr_num; + unsigned int attr_form; + Dwarf_Off aboffset; + size_t j; + for (j = 0; j < attrcnt; ++j) + if (dwarf_getabbrevattr (abbrev, j, &attr_num, &attr_form, + &aboffset)) + printf ("dwarf_getabbrevattr for abbrev[%llu] and index %zu failed\n", + (unsigned long long int) offset, j); + else + printf ("abbrev[%llu]: attr[%zu]: code = %u, form = %u, offset = %" PRIu64 "\n", + (unsigned long long int) offset, j, attr_num, + attr_form, (uint64_t) aboffset); + + offset += length; + } + + old_cuoff = cuoff; + } + + if (dwarf_end (dbg) != 0) + printf ("dwarf_end failed for %s: %s\n", argv[cnt], + dwarf_errmsg (-1)); + + close (fd); + } + + return 0; +} diff --git a/tests/show-ciefde.c b/tests/show-ciefde.c new file mode 100644 index 00000000..58eae343 --- /dev/null +++ b/tests/show-ciefde.c @@ -0,0 +1,218 @@ +/* Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include + +#include +#include +#include +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + int cnt; + + for (cnt = 1; cnt < argc; ++cnt) + { + int fd = open (argv[cnt], O_RDONLY); + Dwarf_Debug dbg; + Dwarf_Signed cie_cnt; + Dwarf_Cie *cie_data; + Dwarf_Signed fde_cnt; + Dwarf_Fde *fde_data; + Dwarf_Error err; + + if (dwarf_init (fd, DW_DLC_READ, NULL, NULL, &dbg, &err) != DW_DLV_OK) + { + printf ("%s not usable: %s\n", argv[cnt], dwarf_errmsg (err)); + continue; + } + else if (dwarf_get_fde_list_eh (dbg, &cie_data, &cie_cnt, &fde_data, + &fde_cnt, &err) != DW_DLV_OK) + printf ("cannot get CIEs and FDEs from %s: %s\n", argv[cnt], + dwarf_errmsg (err)); + else + { + Dwarf_Addr low_pc; + Dwarf_Addr high_pc; + Dwarf_Unsigned func_length; + Dwarf_Ptr fde_bytes; + Dwarf_Unsigned fde_byte_length; + Dwarf_Off cie_offset; + Dwarf_Signed cie_index; + Dwarf_Off fde_offset; + Dwarf_Fde fde; + int i; + + printf ("%s has %lld CIEs and %lld FDEs\n", + basename (argv[cnt]), + (long long int) cie_cnt, (long long int) fde_cnt); + + for (i = 0; i < cie_cnt; ++i) + { + Dwarf_Unsigned bytes_in_cie; + Dwarf_Small version; + char *augmenter; + Dwarf_Unsigned code_alignment_factor; + Dwarf_Signed data_alignment_factor; + Dwarf_Half return_address_register; + Dwarf_Ptr initial_instructions; + Dwarf_Unsigned initial_instructions_length; + + if (dwarf_get_cie_info (cie_data[i], &bytes_in_cie, &version, + &augmenter, &code_alignment_factor, + &data_alignment_factor, + &return_address_register, + &initial_instructions, + &initial_instructions_length, &err) + != DW_DLV_OK) + printf ("cannot get info for CIE %d: %s\n", i, + dwarf_errmsg (err)); + else + { + size_t j; + + printf ("CIE[%d]: bytes_in_cie = %llu, version = %hhd, augmenter = \"%s\"\n", + i, (unsigned long long int) bytes_in_cie, version, + augmenter); + printf ("CIE[%d]: code_alignment_factor = %llx\n" + "CIE[%d]: data_alignment_factor = %llx\n" + "CIE[%d]: return_address_register = %hu\n" + "CIE[%d]: bytes =", + i, (unsigned long long int) code_alignment_factor, + i, (unsigned long long int) data_alignment_factor, + i, return_address_register, i); + + for (j = 0; j < initial_instructions_length; ++j) + printf (" %02hhx", + ((unsigned char *) initial_instructions)[j]); + + putchar ('\n'); + } + } + + for (i = 0; i < fde_cnt; ++i) + { + Dwarf_Cie cie; + + if (dwarf_get_fde_range (fde_data[i], &low_pc, &func_length, + &fde_bytes, &fde_byte_length, + &cie_offset, &cie_index, &fde_offset, + &err) != DW_DLV_OK) + printf ("cannot get range of FDE %d: %s\n", i, + dwarf_errmsg (err)); + else + { + size_t j; + Dwarf_Ptr instrs; + Dwarf_Unsigned len; + + printf ("FDE[%d]: low_pc = %#llx, length = %llu\n", i, + (unsigned long long int) low_pc, + (unsigned long long int) func_length); + printf ("FDE[%d]: bytes =", i); + + for (j = 0; j < fde_byte_length; ++j) + printf (" %02hhx", ((unsigned char *) fde_bytes)[j]); + + printf ("\nFDE[%d]: cie_offset = %lld, cie_index = %lld, fde_offset = %lld\n", + i, (long long int) cie_offset, + (long long int) cie_index, + (long long int) fde_offset); + + if (dwarf_get_fde_instr_bytes (fde_data[i], &instrs, &len, + &err) != DW_DLV_OK) + printf ("cannot get instructions of FDE %d: %s\n", i, + dwarf_errmsg (err)); + else + { + printf ("FDE[%d]: instructions =", i); + + for (j = 0; j < len; ++j) + printf (" %02hhx", ((unsigned char *) instrs)[j]); + + putchar ('\n'); + } + + /* Consistency check. */ + if (dwarf_get_cie_of_fde (fde_data[i], &cie, &err) + != DW_DLV_OK) + printf ("cannot get CIE of FDE %d: %s\n", i, + dwarf_errmsg (err)); + else if (cie_data[cie_index] != cie) + puts ("cie_index for FDE[%d] does not match dwarf_get_cie_of_fde result"); + } + + if (dwarf_get_fde_n (fde_data, i, &fde, &err) != DW_DLV_OK) + printf ("dwarf_get_fde_n for FDE[%d] failed\n", i); + else if (fde != fde_data[i]) + printf ("dwarf_get_fde_n for FDE[%d] didn't return the right value\n", i); + } + + if (dwarf_get_fde_n (fde_data, fde_cnt, &fde, &err) + != DW_DLV_NO_ENTRY) + puts ("dwarf_get_fde_n for invalid index doesn't return DW_DLV_NO_ENTRY"); + + { + const unsigned int addrs[] = + { + 0x8048400, 0x804842c, 0x8048454, 0x8048455, 0x80493fc + }; + const int naddrs = sizeof (addrs) / sizeof (addrs[0]); + + for (i = 0; i < naddrs; ++i) + if (dwarf_get_fde_at_pc (fde_data, addrs[i], &fde, &low_pc, + &high_pc, &err) != DW_DLV_OK) + printf ("no FDE at %x\n", addrs[i]); + else + { + Dwarf_Addr other_low_pc; + + if (dwarf_get_fde_range (fde, &other_low_pc, &func_length, + &fde_bytes, &fde_byte_length, + &cie_offset, &cie_index, + &fde_offset, &err) != DW_DLV_OK) + printf ("cannot get range of FDE returned by dwarf_get_fde_at_pc for %u: %s\n", + addrs[i], dwarf_errmsg (err)); + else + { + printf ("FDE[@%x]: cie_offset = %lld, cie_index = %lld, fde_offset = %lld\n", + addrs[i], + (long long int) cie_offset, + (long long int) cie_index, + (long long int) fde_offset); + + if (low_pc != other_low_pc) + printf ("low_pc returned by dwarf_get_fde_at_pc for %x and dwarf_get_fde_range differs", + addrs[i]); + + if (high_pc != low_pc + func_length - 1) + printf ("high_pc returned by dwarf_get_fde_at_pc for %x and dwarf_get_fde_range differs", + addrs[i]); + } + } + } + } + + if (dwarf_finish (dbg, &err) != DW_DLV_OK) + printf ("dwarf_finish failed for %s: %s\n", argv[cnt], + dwarf_errmsg (err)); + + close (fd); + } + + return 0; +} diff --git a/tests/show-die-info.c b/tests/show-die-info.c new file mode 100644 index 00000000..d4f992f3 --- /dev/null +++ b/tests/show-die-info.c @@ -0,0 +1,475 @@ +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +static const char *tagnames[] = +{ + [DW_TAG_array_type] = "DW_TAG_array_type", + [DW_TAG_class_type] = "DW_TAG_class_type", + [DW_TAG_entry_point] = "DW_TAG_entry_point", + [DW_TAG_enumeration_type] = "DW_TAG_enumeration_type", + [DW_TAG_formal_parameter] = "DW_TAG_formal_parameter", + [DW_TAG_imported_declaration] = "DW_TAG_imported_declaration", + [DW_TAG_label] = "DW_TAG_label", + [DW_TAG_lexical_block] = "DW_TAG_lexical_block", + [DW_TAG_member] = "DW_TAG_member", + [DW_TAG_pointer_type] = "DW_TAG_pointer_type", + [DW_TAG_reference_type] = "DW_TAG_reference_type", + [DW_TAG_compile_unit] = "DW_TAG_compile_unit", + [DW_TAG_string_type] = "DW_TAG_string_type", + [DW_TAG_structure_type] = "DW_TAG_structure_type", + [DW_TAG_subroutine_type] = "DW_TAG_subroutine_type", + [DW_TAG_typedef] = "DW_TAG_typedef", + [DW_TAG_union_type] = "DW_TAG_union_type", + [DW_TAG_unspecified_parameters] = "DW_TAG_unspecified_parameters", + [DW_TAG_variant] = "DW_TAG_variant", + [DW_TAG_common_block] = "DW_TAG_common_block", + [DW_TAG_common_inclusion] = "DW_TAG_common_inclusion", + [DW_TAG_inheritance] = "DW_TAG_inheritance", + [DW_TAG_inlined_subroutine] = "DW_TAG_inlined_subroutine", + [DW_TAG_module] = "DW_TAG_module", + [DW_TAG_ptr_to_member_type] = "DW_TAG_ptr_to_member_type", + [DW_TAG_set_type] = "DW_TAG_set_type", + [DW_TAG_subrange_type] = "DW_TAG_subrange_type", + [DW_TAG_with_stmt] = "DW_TAG_with_stmt", + [DW_TAG_access_declaration] = "DW_TAG_access_declaration", + [DW_TAG_base_type] = "DW_TAG_base_type", + [DW_TAG_catch_block] = "DW_TAG_catch_block", + [DW_TAG_const_type] = "DW_TAG_const_type", + [DW_TAG_constant] = "DW_TAG_constant", + [DW_TAG_enumerator] = "DW_TAG_enumerator", + [DW_TAG_file_type] = "DW_TAG_file_type", + [DW_TAG_friend] = "DW_TAG_friend", + [DW_TAG_namelist] = "DW_TAG_namelist", + [DW_TAG_namelist_item] = "DW_TAG_namelist_item", + [DW_TAG_packed_type] = "DW_TAG_packed_type", + [DW_TAG_subprogram] = "DW_TAG_subprogram", + [DW_TAG_template_type_param] = "DW_TAG_template_type_param", + [DW_TAG_template_value_param] = "DW_TAG_template_value_param", + [DW_TAG_thrown_type] = "DW_TAG_thrown_type", + [DW_TAG_try_block] = "DW_TAG_try_block", + [DW_TAG_variant_part] = "DW_TAG_variant_part", + [DW_TAG_variable] = "DW_TAG_variable", + [DW_TAG_volatile_type] = "DW_TAG_volatile_type" +}; +#define ntagnames (sizeof (tagnames) / sizeof (tagnames[0])) + + +const struct +{ + int code; + const char *name; +} attrs[] = +{ + { DW_AT_sibling, "sibling" }, + { DW_AT_location, "location" }, + { DW_AT_name, "name" }, + { DW_AT_ordering, "ordering" }, + { DW_AT_subscr_data, "subscr_data" }, + { DW_AT_byte_size, "byte_size" }, + { DW_AT_bit_offset, "bit_offset" }, + { DW_AT_bit_size, "bit_size" }, + { DW_AT_element_list, "element_list" }, + { DW_AT_stmt_list, "stmt_list" }, + { DW_AT_low_pc, "low_pc" }, + { DW_AT_high_pc, "high_pc" }, + { DW_AT_language, "language" }, + { DW_AT_member, "member" }, + { DW_AT_discr, "discr" }, + { DW_AT_discr_value, "discr_value" }, + { DW_AT_visibility, "visibility" }, + { DW_AT_import, "import" }, + { DW_AT_string_length, "string_length" }, + { DW_AT_common_reference, "common_reference" }, + { DW_AT_comp_dir, "comp_dir" }, + { DW_AT_const_value, "const_value" }, + { DW_AT_containing_type, "containing_type" }, + { DW_AT_default_value, "default_value" }, + { DW_AT_inline, "inline" }, + { DW_AT_is_optional, "is_optional" }, + { DW_AT_lower_bound, "lower_bound" }, + { DW_AT_producer, "producer" }, + { DW_AT_prototyped, "prototyped" }, + { DW_AT_return_addr, "return_addr" }, + { DW_AT_start_scope, "start_scope" }, + { DW_AT_stride_size, "stride_size" }, + { DW_AT_upper_bound, "upper_bound" }, + { DW_AT_abstract_origin, "abstract_origin" }, + { DW_AT_accessibility, "accessibility" }, + { DW_AT_address_class, "address_class" }, + { DW_AT_artificial, "artificial" }, + { DW_AT_base_types, "base_types" }, + { DW_AT_calling_convention, "calling_convention" }, + { DW_AT_count, "count" }, + { DW_AT_data_member_location, "data_member_location" }, + { DW_AT_decl_column, "decl_column" }, + { DW_AT_decl_file, "decl_file" }, + { DW_AT_decl_line, "decl_line" }, + { DW_AT_declaration, "declaration" }, + { DW_AT_discr_list, "discr_list" }, + { DW_AT_encoding, "encoding" }, + { DW_AT_external, "external" }, + { DW_AT_frame_base, "frame_base" }, + { DW_AT_friend, "friend" }, + { DW_AT_identifier_case, "identifier_case" }, + { DW_AT_macro_info, "macro_info" }, + { DW_AT_namelist_items, "namelist_items" }, + { DW_AT_priority, "priority" }, + { DW_AT_segment, "segment" }, + { DW_AT_specification, "specification" }, + { DW_AT_static_link, "static_link" }, + { DW_AT_type, "type" }, + { DW_AT_use_location, "use_location" }, + { DW_AT_variable_parameter, "variable_parameter" }, + { DW_AT_virtuality, "virtuality" }, + { DW_AT_vtable_elem_location, "vtable_elem_location" }, + { DW_AT_MIPS_fde, "MIPS_fde" }, + { DW_AT_MIPS_loop_begin, "MIPS_loop_begin" }, + { DW_AT_MIPS_tail_loop_begin, "MIPS_tail_loop_begin" }, + { DW_AT_MIPS_epilog_begin, "MIPS_epilog_begin" }, + { DW_AT_MIPS_loop_unroll_factor, "MIPS_loop_unroll_factor" }, + { DW_AT_MIPS_software_pipeline_depth, "MIPS_software_pipeline_depth" }, + { DW_AT_MIPS_linkage_name, "MIPS_linkage_name" }, + { DW_AT_MIPS_stride, "MIPS_stride" }, + { DW_AT_MIPS_abstract_name, "MIPS_abstract_name" }, + { DW_AT_MIPS_clone_origin, "MIPS_clone_origin" }, + { DW_AT_MIPS_has_inlines, "MIPS_has_inlines" }, + { DW_AT_MIPS_stride_byte, "MIPS_stride_byte" }, + { DW_AT_MIPS_stride_elem, "MIPS_stride_elem" }, + { DW_AT_MIPS_ptr_dopetype, "MIPS_ptr_dopetype" }, + { DW_AT_MIPS_allocatable_dopetype, "MIPS_allocatable_dopetype" }, + { DW_AT_MIPS_assumed_shape_dopetype, "MIPS_assumed_shape_dopetype" }, + { DW_AT_MIPS_assumed_size, "MIPS_assumed_size" }, + { DW_AT_sf_names, "sf_names" }, + { DW_AT_src_info, "src_info" }, + { DW_AT_mac_info, "mac_info" }, + { DW_AT_src_coords, "src_coords" }, + { DW_AT_body_begin, "body_begin" }, + { DW_AT_body_end, "body_end" } +}; +#define nattrs (sizeof (attrs) / sizeof (attrs[0])) + + +void +handle (Dwarf *dbg, Dwarf_Die *die, int n) +{ + Dwarf_Die child; + unsigned int tag; + const char *str; + char buf[30]; + const char *name; + Dwarf_Off off; + Dwarf_Off cuoff; + size_t cnt; + Dwarf_Addr addr; + int i; + + tag = dwarf_tag (die); + if (tag != DW_TAG_invalid) + { + if (tag < ntagnames) + str = tagnames[tag]; + else + { + snprintf (buf, sizeof buf, "%#x", tag); + str = buf; + } + } + else + str = "* NO TAG *"; + + name = dwarf_diename (die); + if (name == 0) + name = "* NO NAME *"; + + off = dwarf_dieoffset (die); + cuoff = dwarf_cuoffset (die); + + printf ("%*s%s\n", n * 5, "", str); + printf ("%*s Name : %s\n", n * 5, "", name); + printf ("%*s Offset : %lld\n", n * 5, "", (long long int) off); + printf ("%*s CU offset : %lld\n", n * 5, "", (long long int) cuoff); + + printf ("%*s Attrs :", n * 5, ""); + for (cnt = 0; cnt < nattrs; ++cnt) + if (dwarf_hasattr (die, attrs[cnt].code)) + printf (" %s", attrs[cnt].name); + puts (""); + + if (dwarf_hasattr (die, DW_AT_low_pc) && dwarf_lowpc (die, &addr) == 0) + { + Dwarf_Attribute attr; + Dwarf_Addr addr2; + printf ("%*s low PC : %#llx\n", + n * 5, "", (unsigned long long int) addr); + + if (dwarf_attr (die, DW_AT_low_pc, &attr) == NULL + || dwarf_formaddr (&attr, &addr2) != 0 + || addr != addr2) + puts ("************* DW_AT_low_pc verify failed ************"); + else if (! dwarf_hasform (&attr, DW_FORM_addr)) + puts ("************* DW_AT_low_pc form failed ************"); + else if (dwarf_whatform (&attr) != DW_FORM_addr) + puts ("************* DW_AT_low_pc form (2) failed ************"); + else if (dwarf_whatattr (&attr) != DW_AT_low_pc) + puts ("************* DW_AT_low_pc attr failed ************"); + } + if (dwarf_hasattr (die, DW_AT_high_pc) && dwarf_highpc (die, &addr) == 0) + { + Dwarf_Attribute attr; + Dwarf_Addr addr2; + printf ("%*s high PC : %#llx\n", + n * 5, "", (unsigned long long int) addr); + if (dwarf_attr (die, DW_AT_high_pc, &attr) == NULL + || dwarf_formaddr (&attr, &addr2) != 0 + || addr != addr2) + puts ("************* DW_AT_high_pc verify failed ************"); + else if (! dwarf_hasform (&attr, DW_FORM_addr)) + puts ("************* DW_AT_high_pc form failed ************"); + else if (dwarf_whatform (&attr) != DW_FORM_addr) + puts ("************* DW_AT_high_pc form (2) failed ************"); + else if (dwarf_whatattr (&attr) != DW_AT_high_pc) + puts ("************* DW_AT_high_pc attr failed ************"); + } + + if (dwarf_hasattr (die, DW_AT_byte_size) && (i = dwarf_bytesize (die)) != -1) + { + Dwarf_Attribute attr; + Dwarf_Word u2; + unsigned int u; + printf ("%*s byte size : %d\n", n * 5, "", i); + if (dwarf_attr (die, DW_AT_byte_size, &attr) == NULL + || dwarf_formudata (&attr, &u2) != 0 + || i != (int) u2) + puts ("************* DW_AT_byte_size verify failed ************"); + else if (! dwarf_hasform (&attr, DW_FORM_data1) + && ! dwarf_hasform (&attr, DW_FORM_data2) + && ! dwarf_hasform (&attr, DW_FORM_data4) + && ! dwarf_hasform (&attr, DW_FORM_data8) + && ! dwarf_hasform (&attr, DW_FORM_sdata) + && ! dwarf_hasform (&attr, DW_FORM_udata)) + puts ("************* DW_AT_byte_size form failed ************"); + else if ((u = dwarf_whatform (&attr)) == 0 + || (u != DW_FORM_data1 + && u != DW_FORM_data2 + && u != DW_FORM_data4 + && u != DW_FORM_data8 + && u != DW_FORM_sdata + && u != DW_FORM_udata)) + puts ("************* DW_AT_byte_size form (2) failed ************"); + else if (dwarf_whatattr (&attr) != DW_AT_byte_size) + puts ("************* DW_AT_byte_size attr failed ************"); + } + if (dwarf_hasattr (die, DW_AT_bit_size) && (i = dwarf_bitsize (die)) != -1) + { + Dwarf_Attribute attr; + Dwarf_Word u2; + unsigned int u; + printf ("%*s bit size : %d\n", n * 5, "", i); + if (dwarf_attr (die, DW_AT_bit_size, &attr) == NULL + || dwarf_formudata (&attr, &u2) != 0 + || i != (int) u2) + puts ("************* DW_AT_bit_size test failed ************"); + else if (! dwarf_hasform (&attr, DW_FORM_data1) + && ! dwarf_hasform (&attr, DW_FORM_data2) + && ! dwarf_hasform (&attr, DW_FORM_data4) + && ! dwarf_hasform (&attr, DW_FORM_data8) + && ! dwarf_hasform (&attr, DW_FORM_sdata) + && ! dwarf_hasform (&attr, DW_FORM_udata)) + puts ("************* DW_AT_bit_size form failed ************"); + else if ((u = dwarf_whatform (&attr)) == 0 + || (u != DW_FORM_data1 + && u != DW_FORM_data2 + && u != DW_FORM_data4 + && u != DW_FORM_data8 + && u != DW_FORM_sdata + && u != DW_FORM_udata)) + puts ("************* DW_AT_bit_size form (2) failed ************"); + else if (dwarf_whatattr (&attr) != DW_AT_bit_size) + puts ("************* DW_AT_bit_size attr failed ************"); + } + if (dwarf_hasattr (die, DW_AT_bit_offset) + && (i = dwarf_bitoffset (die)) != -1) + { + Dwarf_Attribute attr; + Dwarf_Word u2; + unsigned int u; + printf ("%*s bit offset: %d\n", n * 5, "", i); + if (dwarf_attr (die, DW_AT_bit_offset, &attr) == NULL + || dwarf_formudata (&attr, &u2) != 0 + || i != (int) u2) + puts ("************* DW_AT_bit_offset test failed ************"); + else if (! dwarf_hasform (&attr, DW_FORM_data1) + && ! dwarf_hasform (&attr, DW_FORM_data2) + && ! dwarf_hasform (&attr, DW_FORM_data4) + && ! dwarf_hasform (&attr, DW_FORM_data8) + && ! dwarf_hasform (&attr, DW_FORM_sdata) + && ! dwarf_hasform (&attr, DW_FORM_udata)) + puts ("************* DW_AT_bit_offset form failed ************"); + else if ((u = dwarf_whatform (&attr)) == 0 + || (u != DW_FORM_data1 + && u != DW_FORM_data2 + && u != DW_FORM_data4 + && u != DW_FORM_data8 + && u != DW_FORM_sdata + && u != DW_FORM_udata)) + puts ("************* DW_AT_bit_offset form (2) failed ************"); + else if (dwarf_whatattr (&attr) != DW_AT_bit_offset) + puts ("************* DW_AT_bit_offset attr failed ************"); + } + + if (dwarf_hasattr (die, DW_AT_language) && (i = dwarf_srclang (die)) != -1) + { + Dwarf_Attribute attr; + Dwarf_Word u2; + unsigned int u; + printf ("%*s language : %d\n", n * 5, "", i); + if (dwarf_attr (die, DW_AT_language, &attr) == NULL + || dwarf_formudata (&attr, &u2) != 0 + || i != (int) u2) + puts ("************* DW_AT_language test failed ************"); + else if (! dwarf_hasform (&attr, DW_FORM_data1) + && ! dwarf_hasform (&attr, DW_FORM_data2) + && ! dwarf_hasform (&attr, DW_FORM_data4) + && ! dwarf_hasform (&attr, DW_FORM_data8) + && ! dwarf_hasform (&attr, DW_FORM_sdata) + && ! dwarf_hasform (&attr, DW_FORM_udata)) + puts ("************* DW_AT_language form failed ************"); + else if ((u = dwarf_whatform (&attr)) == 0 + || (u != DW_FORM_data1 + && u != DW_FORM_data2 + && u != DW_FORM_data4 + && u != DW_FORM_data8 + && u != DW_FORM_sdata + && u != DW_FORM_udata)) + puts ("************* DW_AT_language form (2) failed ************"); + else if (dwarf_whatattr (&attr) != DW_AT_language) + puts ("************* DW_AT_language attr failed ************"); + } + + if (dwarf_hasattr (die, DW_AT_ordering) + && (i = dwarf_arrayorder (die)) != -1) + { + Dwarf_Attribute attr; + Dwarf_Word u2; + unsigned int u; + printf ("%*s ordering : %d\n", n * 5, "", i); + if (dwarf_attr (die, DW_AT_ordering, &attr) == NULL + || dwarf_formudata (&attr, &u2) != 0 + || i != (int) u2) + puts ("************* DW_AT_ordering test failed ************"); + else if (! dwarf_hasform (&attr, DW_FORM_data1) + && ! dwarf_hasform (&attr, DW_FORM_data2) + && ! dwarf_hasform (&attr, DW_FORM_data4) + && ! dwarf_hasform (&attr, DW_FORM_data8) + && ! dwarf_hasform (&attr, DW_FORM_sdata) + && ! dwarf_hasform (&attr, DW_FORM_udata)) + puts ("************* DW_AT_ordering failed ************"); + else if ((u = dwarf_whatform (&attr)) == 0 + || (u != DW_FORM_data1 + && u != DW_FORM_data2 + && u != DW_FORM_data4 + && u != DW_FORM_data8 + && u != DW_FORM_sdata + && u != DW_FORM_udata)) + puts ("************* DW_AT_ordering form (2) failed ************"); + else if (dwarf_whatattr (&attr) != DW_AT_ordering) + puts ("************* DW_AT_ordering attr failed ************"); + } + + if (dwarf_hasattr (die, DW_AT_comp_dir)) + { + Dwarf_Attribute attr; + if (dwarf_attr (die, DW_AT_comp_dir, &attr) == NULL + || (name = dwarf_formstring (&attr)) == NULL) + puts ("************* DW_AT_comp_dir attr failed ************"); + else + printf ("%*s directory : %s\n", n * 5, "", name); + } + + if (dwarf_hasattr (die, DW_AT_producer)) + { + Dwarf_Attribute attr; + if (dwarf_attr (die, DW_AT_producer, &attr) == NULL + || (name = dwarf_formstring (&attr)) == NULL) + puts ("************* DW_AT_comp_dir attr failed ************"); + else + printf ("%*s producer : %s\n", n * 5, "", name); + } + + if (dwarf_haschildren (die) != 0 && dwarf_child (die, &child) == 0) + handle (dbg, &child, n + 1); + if (dwarf_siblingof (die, die) == 0) + handle (dbg, die, n); +} + + +int +main (int argc, char *argv[]) +{ + int cnt; + + for (cnt = 1; cnt < argc; ++cnt) + { + int fd = open (argv[cnt], O_RDONLY); + Dwarf *dbg; + + printf ("file: %s\n", basename (argv[cnt])); + + dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg == NULL) + { + printf ("%s not usable\n", argv[cnt]); + close (fd); + continue; + } + + Dwarf_Off off = 0; + Dwarf_Off old_off = 0; + size_t hsize; + Dwarf_Off abbrev; + uint8_t addresssize; + uint8_t offsetsize; + while (dwarf_nextcu (dbg, off, &off, &hsize, &abbrev, &addresssize, + &offsetsize) == 0) + { + printf ("New CU: off = %llu, hsize = %zu, ab = %llu, as = %" PRIu8 + ", os = %" PRIu8 "\n", + (unsigned long long int) old_off, hsize, + (unsigned long long int) abbrev, addresssize, + offsetsize); + + Dwarf_Die die; + if (dwarf_offdie (dbg, old_off + hsize, &die) != NULL) + handle (dbg, &die, 1); + + old_off = off; + } + + dwarf_end (dbg); + close (fd); + } + + return 0; +} diff --git a/tests/showptable.c b/tests/showptable.c new file mode 100644 index 00000000..21247c8b --- /dev/null +++ b/tests/showptable.c @@ -0,0 +1,135 @@ +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 1998. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include + +#include +#include +#include +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + Elf *elf; + int fd; + GElf_Ehdr ehdr; + int cnt; + + if (argc < 2) + { + puts ("missing parameter"); + exit (1); + } + + fd = open (argv[1], O_RDONLY); + if (fd == -1) + { + printf ("cannot open \"%s\": %s\n", argv[1], strerror (errno)); + exit (1); + } + + elf_version (EV_CURRENT); + + elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) + { + printf ("cannot open ELF file: %s\n", elf_errmsg (-1)); + exit (1); + } + + if (elf_kind (elf) != ELF_K_ELF) + { + printf ("\"%s\" is not an ELF file\n", argv[1]); + exit (1); + } + + if (gelf_getehdr (elf, &ehdr) == NULL) + { + printf ("cannot get the ELF header: %s\n", elf_errmsg (-1)); + exit (1); + } + + printf ("idx type %*s %*s %*s %*s %*s align flags\n", + gelf_getclass (elf) == ELFCLASS32 ? 9 : 17, "offset", + gelf_getclass (elf) == ELFCLASS32 ? 10 : 18, "vaddr", + gelf_getclass (elf) == ELFCLASS32 ? 10 : 18, "paddr", + gelf_getclass (elf) == ELFCLASS32 ? 9 : 12, "filesz", + gelf_getclass (elf) == ELFCLASS32 ? 9 : 12, "memsz"); + + for (cnt = 0; cnt < ehdr.e_phnum; ++cnt) + { + static const char *typenames[] = + { + [PT_NULL] = "NULL", + [PT_LOAD] = "LOAD", + [PT_DYNAMIC] = "DYNAMIC", + [PT_INTERP] = "INTERP", + [PT_NOTE] = "NOTE", + [PT_SHLIB] = "SHLIB", + [PT_PHDR] = "PHDR" + }; + GElf_Phdr mem; + GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &mem); + char buf[19]; + const char *p_type = typenames[phdr->p_type]; + + /* If we don't know the name of the type we use the number value. */ + if (phdr->p_type >= PT_NUM) + { + snprintf (buf, sizeof (buf), "%x", phdr->p_type); + p_type = buf; + } + + printf ("%3d %-7s %#0*llx %#0*llx %#0*llx %#0*llx %#0*llx %#6llx ", + cnt, p_type, + gelf_getclass (elf) == ELFCLASS32 ? 9 : 17, + (unsigned long long int) phdr->p_offset, + gelf_getclass (elf) == ELFCLASS32 ? 10 : 18, + (unsigned long long int) phdr->p_vaddr, + gelf_getclass (elf) == ELFCLASS32 ? 10 : 18, + (unsigned long long int) phdr->p_paddr, + gelf_getclass (elf) == ELFCLASS32 ? 9 : 12, + (unsigned long long int) phdr->p_filesz, + gelf_getclass (elf) == ELFCLASS32 ? 9 : 12, + (unsigned long long int) phdr->p_memsz, + (unsigned long long int) phdr->p_align); + + putc_unlocked ((phdr->p_flags & PF_X) ? 'X' : ' ', stdout); + putc_unlocked ((phdr->p_flags & PF_W) ? 'W' : ' ', stdout); + putc_unlocked ((phdr->p_flags & PF_R) ? 'R' : ' ', stdout); + + putc_unlocked ('\n', stdout); + + if (phdr->p_type == PT_INTERP) + { + /* We can show the user the name of the interpreter. */ + size_t maxsize; + char *filedata = elf_rawfile (elf, &maxsize); + + if (filedata != NULL && phdr->p_offset < maxsize) + printf ("\t[Requesting program interpreter: %s]\n", + filedata + phdr->p_offset); + } + } + + if (elf_end (elf) != 0) + { + printf ("error while freeing ELF descriptor: %s\n", elf_errmsg (-1)); + exit (1); + } + + return 0; +} diff --git a/tests/test-nlist.c b/tests/test-nlist.c new file mode 100644 index 00000000..1a3f3ec2 --- /dev/null +++ b/tests/test-nlist.c @@ -0,0 +1,79 @@ +/* Copyright (C) 2000, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include + + +int var = 1; + +int bss; + + +int +foo (int a) +{ + return a; +} + +int +main (int argc, char *argv[] __attribute__ ((unused))) +{ + struct nlist nl[6] = + { + [0] = { .n_name = "var" }, + [1] = { .n_name = "bss" }, + [2] = { .n_name = "main" }, + [3] = { .n_name = "foo" }, + [4] = { .n_name = "not-there" }, + [5] = { .n_name = NULL }, + }; + int cnt; + int result = 0; + + if (nlist (".libs/test-nlist", nl) != 0 + && nlist ("./test-nlist", nl) != 0) + { + puts ("nlist failed"); + exit (1); + } + + for (cnt = 0; nl[cnt].n_name != NULL; ++cnt) + { + if (argc > 1) + /* For debugging. */ + printf ("nl[%d].n_name = \"%s\"\n" + "nl[%d].n_value = %ld\n" + "nl[%d].n_scnum = %d\n" + "nl[%d].n_type = %u\n" + "nl[%d].n_sclass = %d\n" + "nl[%d].n_numaux = %d\n\n", + cnt, nl[cnt].n_name, + cnt, nl[cnt].n_value, + cnt, nl[cnt].n_scnum, + cnt, nl[cnt].n_type, + cnt, nl[cnt].n_sclass, + cnt, nl[cnt].n_numaux); + + if ((cnt != 4 && nl[cnt].n_value == 0 && nl[cnt].n_scnum == 0 + && nl[cnt].n_type == 0 && nl[cnt].n_sclass == 0 + && nl[cnt].n_numaux == 0) + || (cnt == 4 && (nl[cnt].n_value != 0 || nl[cnt].n_scnum != 0 + || nl[cnt].n_type != 0 || nl[cnt].n_sclass != 0 + || nl[cnt].n_numaux != 0))) + result = 1; + } + + return foo (result); +} diff --git a/tests/testfile.bz2 b/tests/testfile.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..bde9b1269e513a46c695c1929d7fd74e1e358347 GIT binary patch literal 8115 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 literal 0 HcmV?d00001 diff --git a/tests/testfile11.bz2 b/tests/testfile11.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..d094b848e936cce0323e98ff9c411f2b3ed5bdb1 GIT binary patch literal 30561 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 WX{N{RINs0yi@744C`csG;}ig$VoGxW literal 0 HcmV?d00001 diff --git a/tests/testfile12.bz2 b/tests/testfile12.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..8bb5ad3399fadafffa982415dfb4b396dd0a41f2 GIT binary patch literal 9948 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 a7L#jWKb|z4k1r$ti@744C`bm;F8KhCRXv0N literal 0 HcmV?d00001 diff --git a/tests/testfile13.bz2 b/tests/testfile13.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..3b0bcb9398f8f8b24162f250adcc25e3a2d0f476 GIT binary patch literal 1593 zcmV-92FCe9T4*^jL0KkKS(Ch%hyVrs|NsC0|Nr{u|9}7Y{`vp^|8VbW#&X3%Q9(^G zP!vXdWns_-S&upwVQd8D*zDWGLPn$1n^Ed%rly{zhMAB|fYa0iO&T&i8VRSVrhpn4 zLuf-rG=R~d!Wv{?nldy4Q$i-msPw7&WKUDlo~M-YMvv7VrhoyU00000000000000o z8UQst2tu1pP-w}K>Hq`O00TgJfB*m*Gynhq0MGyc0MO6~8W}Xu#AMSzWM~ZxO$HMq z2xJCBOoK+541i){7$y@0$kR*!OauZ%h=Q553VxD#Pfe<6>OD<7)iQY+gVCZ5skH`y z=>Py?4XDr!9;VU&Z&dV}4FeDW(Z2|6PnOyB?r?E15>S+qn$x<8!#pS==&ypZG62k| zUkE^#y%i$QM~1sSRw@XwttTMps$nIFeFbQfv%G7FRL0!8W!ae#M=Tw(ph6M_IS3*; zGq4;^k;{eCOfDrdK6DRdTZP{Zp1!tZn2;m#gYo)%W!|R`h;b z+`L>`k`>D96LC!FKm`cJxu3_N1dHBG1#Z?LF`mjoGp^6)nqA{S90nn1YVSTfwin>C zzo=+BaLzq6HC1t1xZI+}zQ#iUp)em9fNuehP6MsAD~5oDp1=WOFcK(fEjA1y716P! z3|>PKfW>BF=-h#KY+Ocyy8>;x8Uzi9NNim^Kn=Eqr4TlpKsbQ_+h8^%*fyIaEa(v)K?nY%~IYy#{W2UCa=j zS>`@)ts4Tuu)*RY!tmA$TGtw}HA)u}>m+ec0)!UU{X$N)5|y`1Q*?{r#RV4ul6Kh*?jAfeQJd zxYf-P$4hBI3vHRi<#V~*-h8X19;*&p5R9x72Sz~VZki_1&8&LcSUHM?OL%gYLSeJ} za>$1XM2f9F5;{!ra2*Y}G!#!?ww$IQ+0k58C4&P3>6&Wx$$xEOqh4j0p{@6tWQ0hj z2CZFz>0Sg<7Fcz#b7-)&uDylI#et?VlFeoN1QXV;r@5UQD$$p|rzbMz-T`}@e%IUsP&h|^n?T19fEtlNTJOdAt> z6%;oHpo`Tf%tpNi3JMbwUG$OVuuX>vcRGKNZQOvil~g_@jGoG?PvQGX<*%<|C!h zDC3R7S-zt}k0S#>{kcRVm0P`<$O($AGim$r1cO!yGNK+@Nh#%P_8F3~5R9@|3_n`DR1BqBFi_YmJnU1&(`%vI?@~ibvl4Sy zJI4Uv=?E~S0-ZQ*U2~!Mupw~4B5;bQ0)xhAK!iO&H7Gbst^%|Wp#?hSbs5t=XX0aN z-Y~(^F*G;{u|$EXr%j;mN`nSZ@i5z1+qia2o8(%?qO1U>-Q10VGkbc*YDu-DT8gFt zMc%l~uY+KLB!cW$T^#igLl96;C05GLkuif?+P(%5guV8J97`#R-vcAm*D4l+`C9d6 zN5Qw(7e9e{Ac=svd1>=5Ql1K<=}Q6pTIv@0y-(LZT`t0o3--iC+Vg4@Uig2MJCwVUrFem2_ literal 0 HcmV?d00001 diff --git a/tests/testfile14.bz2 b/tests/testfile14.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..ac7c69e10c87ee9b2c30eddb1c9d228ef60a4f22 GIT binary patch literal 2903 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 BFed;2 literal 0 HcmV?d00001 diff --git a/tests/testfile15.bz2 b/tests/testfile15.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..e75f4575c386554ffcd40dd7a89ab24e9c2da415 GIT binary patch literal 3132 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 z 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 literal 0 HcmV?d00001 diff --git a/tests/testfile16.bz2 b/tests/testfile16.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..909e2253baec7e97c807d27bc97e1af21c91dc55 GIT binary patch literal 8424 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 GB$_}2`2ffO literal 0 HcmV?d00001 diff --git a/tests/testfile17.debug.bz2 b/tests/testfile17.debug.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..86a76ab7be7d9ac056053868a8ff15fed86cb556 GIT binary patch literal 9134 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 literal 0 HcmV?d00001 diff --git a/tests/testfile18.bz2 b/tests/testfile18.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..8b5326ccabb10c5514bbe92dbfebccc109882448 GIT binary patch literal 1721 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%0A(msoExmIFvb+xD|1N8NJiT> zg&o=Mw;w{#kEvjORt>( literal 0 HcmV?d00001 diff --git a/tests/testfile3.bz2 b/tests/testfile3.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..30a456c7f970cb76f65005ff9bb42b60f40049bc GIT binary patch literal 8051 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 Bybb^W literal 0 HcmV?d00001 diff --git a/tests/testfile4.bz2 b/tests/testfile4.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..25b25dfc1ebea7b6713aa269706965041f9b412b GIT binary patch literal 41405 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 literal 0 HcmV?d00001 diff --git a/tests/testfile5.bz2 b/tests/testfile5.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..247313e02ab1422854a1914330841df11dfc2b88 GIT binary patch literal 5646 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 literal 0 HcmV?d00001 diff --git a/tests/testfile6.bz2 b/tests/testfile6.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..fd376b274beb03cb53bb9bd75aea258ce38b6606 GIT binary patch literal 30577 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 literal 0 HcmV?d00001 diff --git a/tests/testfile7.bz2 b/tests/testfile7.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..73452bbb5b67502e35c2bea9a9e66132a2849d4a GIT binary patch literal 3107 zcmV+;4BYcVT4*^jL0KkKSu_tZp#TX#fB*mg|Nnpg|NsC0|9}7g-}e9S|L=W8+h6_u z{%3b?U*F&gms+Cv#YavqbGR zJfL~0JtwK5y-4yjdZ5`u(ixO(N2%(1k5D|L(LF=dG(8YB29Ho08Xu`Pki=*i2dU(M z$pipKnI-}a1kjp26HK0_hK!jQfb|+QXfy!O0MG%TGyrHc01VV<0iX>44Ff;`5C9DT z14e)V8Zv0nh-d%+41mzW4Ff>P0009QZ8T($N#rI>O{f|gdPYMv0MVci zNuxjjGz~HXO{CD%Mw$Q`XaE`j00003{tvC!wpo`TKXAK~mUZYACfq(F8nl;*rY<9m zI0}CGQ=s!K%VL>qM-&!a^bTg@)LRm}W>r-0+^gkNYjDhcxxIII(Q5a$%Jj7UJ|!$m zbK;@7R=VRtOUOV+z8Kf7XNJA=Id^BU`X&1LU8dF?I)W%w1x;e1MnL%(YFl73)Sq$1 z(K>`H+W-*i#;;$(*K}{|Up&)E&&jT)2e^WnJ7)78g6uRmM9EfIPNz3~vOv&;O{GZ- z@h@HP>Ni%=sqE*VzN?nC7|}&)mBw)(>_3c8xx9}0=9zvC{}z@UsDfo>94d*DsBLeq zV{%%G2OQ&&gviR>(nK>ykrl5g&b74^n9W{P$k?=c%JW6vzNd|aE+s`}1q^OO!EZRb zPqo!HM2Xgp2~WGwEZH3so+{WVsPg~F@zKqmY3eX1m^KiI6eIawlWP*%%*x=nCBMCD z(l|77t$}VmXIZoHt?=nEHyV5DJ2zm#g8wZjA*q&Zjk5$nuw(#3j0}tIX%nyocEzG- zH;zgXjCEd(mn<{Pm4J#y1y&MR#7`J3QVlk)no8lKW`WqkRh?#AHECX0!tECk1^}X& zwp}UXoEK^g6&aL0rGar|)z-}e3yKV67Sw7D!m`#%!lK%W#RO#R!;ryJlBG;YOIbr# z>h%PQq*pAAB?a;tD1@SjovE4%%{HZA6VCxX{L&J!P|-U{NW~*UDGQ4Dh7ls7OkgAt zRDu=~YLp`?pcJhj8%P^LO9gPyj8jQkF=G98Kwb*B=Kw)5zFjk zlLAeC9A)tPyv<(buX#lzO|Tt^T`)13b;lA2wQDTIQ!xo@#!&_O5x{WTmt#tA4T4PT zAy9QXq^yC~E*Ya3XeiKY)<~M>q=`cjm1zDoX4;?HCoTU<$)Q zGZHIU!)Xj-VoUO2cU89!@RE4?LrL@?Rt7-`z`+IsE!I4JZCT52QcyMxR#Z-3+rLT(Wc5Q=j4ZvnZ+3*3#Jgt{A^n2}v@iO)^xV)^# z_Y-uGHD(B2>r>qxk#--P+#X5Sq5jBFFWsdU|Fn;))rmTp3^35uq5{A9^$GHMMiv1%_Lcn zg=Jb=S!sx*S4qe&TDa@t7hVo2@dB9D2oMNM;1;!zBG5D_z8?}bsKk97FS@r-J0d>& zt%0$mD5eJkTx#E+6udx01kluBiYiPzqu??n5ck3^L5v>h0Y?fCL!Z*?_;p$G9v9z; z*a~&l-cfne)I|&@#%5)d8x3U;NM81vUv^-bG=|!22aRQO7C1!^5IKk`YHo5il{54U zD8iNtYUvsh8xSmIBy+>lgI6Sog)}{QLZDbn}B5PD`Mgm9E(rzFQ+JBA?^^O z9G+(_+l=5D1ksTUmJXdjFMS`9u_(h0rj%Zx?s;jcxN7B0!R6R%0=mK-c20s_p!mAm`W(Fq+ zSbQ3wLdu}H7fp>BZ#K(X-I^4mr9ctfD-cmYk|l;};PkM8P9nE_YNS*Xa{CYcxYQvKR8pg= z>sV24;ocdLhcN&M41Dg(9WLt2B~uVwmr*($W)5eZ6F%?8OTfl%R0x~244--;_tjwTbjd-IOd2xKB3EKq5N z81ABplD)tuc8Li`qKTs(hLH7kq6F2OngdZC7DUdHC@;QIhR|FLFSKNDC7FxO(zLZp z;`MVj@YfDBMpRWfDu%5&!oZmcd?Vg7%M(2q&$Br-tLJQ41uc~mv7FXs1v+Q9s5FKR zNion83T?Ct-SrZh!g_WNXXk+|&V}-Lv=U<+CV_V!Mcl^2a^2oCTB0KoF=?$~-8zw! zY)W2HL4-*$1l9tAIQ)ZpMbjy*gofL|OzTbnhX5`Sh%Dt;spdP8r99@y@ebGzjAv%V zyn@aGLY72g*(@rkXIKsdEfCbA2Zem=(WornBoVdHq7wapJX#i)EmCTQd(}2&8AnUW zi-L8PrSI!V&`6xXS5RUoDyAz-ful;HNG(io-Xr4Ow*>7qGJv0P3aAs^B|L$MwcIpm zXLDss73$KKAeS+1Ut>HiaiuaLfp`KNq|mci<-V+27JyO3!fHw|(o|MrqSD(k`W%zJ z6>G+n$RI|J4kw{LqO;KnKe&wfE5SEaM?S{LBCG4$;noF-sJ zWS0ivEh;oJd9#o3auM8UKi%gVR$rG^yM`?h;8rIc(t;9pzBD0`&L;mz4T4W3N(5kJ zBR3}H8+hC=ptY~a;m~Q6>TgQ6(N|fwWr=kZUT3vg-9`>RtAURel{#rkl`2%JQl&}z z_xfA__qm=;qFsS@o3)@3fw8qxhKU%5P{!+A=#*<@)owsTrUAL34> zoZ6tL9LviXrI<=sA!;_FG?Xkaop!X@$i5gfk8avdu4_?gvQ!MiKZ|*46$H`Vog<4J;Xh72z+cOdv3}_(9U50ee*bGDfMS|{53xLE2Y^?k{B|PCsqg1R> za_02&;$Axd!|L%_wwKEO^*S1!9s}+Ed|i%(Z(n=O-v7S6 z5R0d-l#pa}0)?S?nj-;=ks1MIvW|HWX-0s;PyT!~NhC%)mM0-8n9fBCQ&M8mrwpY* xaSmVo6e&WahyV(yP+Zz+qK6Zr>ONFr|OxgdP8Xjk5Kf1qs0vkHjocOGynhqJwc!V zXaE7GLP0bF1kr+I(@h4N07{?ff}WZ~OixoLCaL;NOsBOslr*OFCa1JAPa>KgYEMb+ zQ_$4YN2q>@8hK4Tr<4byO+fWDJd-D=dW{cI@`0dY8XllCQbZ6&CV?|jKPE(Kcr_=J zO)w*Ap-rUndILntpQofvJtn96nx3iT@}~4O(<2i}=)@HLDE&>QL}}z@PtuP^lAclR zPbk#(Nu>OWdY(;9l0B+=BWin8WDTk4fg(f#XeNLG4F;J6!7xllrZNB%K-BQ5`b^P? z(w>+BsMAyQnNL$>$*O+Tr|BoPJerM@O){tDPtZ~7Z%s8#XHA_`(dc05U9qE0=l=JHrjo-;Tkib2(E#BI%U`9!J+@%Xr^@)%Y2m zD{dponR|yB;{+)QzfiYvq4cL_$d8Fu>8E{GID|KRNf8kO1Vm7f zC|el@#tm$P^GcSlJIh0VP^|3!?mPcSyW?L3t*;IIAsF(8n8&W$HTiz(Q|j(-C+Rh# zw(a`;9^-2L@Nazx3x79@;XgricVQuNkwh6yu3kVGz}!ch=ZkS?!hZj=JmmLpFOYDA zD9akSsNf|XTiqM&%VK0!tU}FgbxPgF{O~4eVNl9X2pw`+b*&ROKO>7WbYFKC54!s1 zAM&S0x(t40uSu$~U8}g=4&Rge!eT#0LW;DEA!QP|Y+xKIVTJo?X2wFUHM}usBSgyO z5C*N0D1it-(%p?Y4JEnle0r-qN5}t^r&wNOIXm`GOW0;_%8E#-G>(r(ztXqW`8R%V zlZRu6w~w>O@UuUfL=CeO1O{h&2?Pib6itUQj04O&a05`a=~eg2{)Y+mH<)ZQ?t(JI zwsB)>5RsjkLE|Oksf-Cjc%lB$A?j4y3zr<=iGIQ3O~3H;rE#)x}Cbc%zO8@TpReq?1Z1bnZcP zUCeuP*r*wRO;O=j^B`|_kHU(U1te@{dB*pwr$efuh_l7yGudgyg*lyNa|Dfb-7?A_#TwUtVuqi@5i2a*woWrndbL)GM=ht@HnG=dEMV z{J)spo=y)*zMy*Vg{GVx*naYe>IHkA`wkcR%hPwx-u0Q+NzX=-Nq1k>mp`Uq))VYR z<}Y&lQc=y5OrbaHQAhM^tCnSK*T-wx_EXQQmGzIjY97j{*rJ^)&*C+Gd(ciYDyia#bZOxzJ--_um~PWuE%1po_0f9MxC8Nj23O z2+YJI4nY9PxrQXC!+Pu1`~+c$R;G&vv{6L06jYjQ&piqAQRp9iMI3rs7qWSWJyp`& zb4g2;)6AN5#6-Ec+qOqjQ87hTNgBQCSrzwz&P1vvCz*rVI4Y#HY=5Ptfrb%PBauiCosG}WJpL!;4_~&K%8=jfxt#~7#bhB9rO3Ox{Xo<**O9=bwhoz6I+s{W}>#iU3`~sl66#)P`@E5sF02Xk|iXu_v+|12GkHo3nL?giXqrddf?r<%4r*pa*Slz zODWMsGIH*)!eBGXxdAmnFn>6Xu6qAu6ud6Jx89Le1 zlIjt<*J`@wnr^MO-#R3bnyibJZC2ZMNyn8uy7SX58u@7=>*`~fDqgshO*<>Hs;bY& zjTF?rkJ9s#~i8Ydo|!lsGx1t*qy5*ZMW8Gtmn^PK5Q_?k&~BO zDW=OcOwW9(s;kmhU6xj_g^Mh-gwjT-@2OQ~iE4P(^;I;}Lmz=9jrs`94K)lSgk$ez zojqiro%(y|BTY0ua@8YCtg#6FIv;u&=bnVwqLkB2d-uLQ6DFA6X{onILgU+`!?x`j z6;Foe`b#8_$I3=nk@w_ISb0q{-IP%`o|ai=rMaJ;N03P*?P7|gNV&M~9Fh&NDOAoN zkvqz5;l$w)nN>s%N#LrfdiulBeq1f<&VqD9HktEFacd?KmJl?^jgWdT12?lo(%3@? zLR{K%E6IKd8JLQ5zP)&oWdv_gV1bq*Le#KXBB1v+&_;$;6HzovVww49n|qCR35@y zn0a{>VZ3Q3g;Z;{x=u(w4S;xA0&~zUjzH3J8<^&|fzBZjAvA_`M1u{XvPF_1o{>kj z1UJYc1FaA;h7qJJnN>s7XWcWt zcf`)()5WAaf()*fX^tu^{1SgY_VXGSTDyNchCH@4f{?J~${Uw1!i=|{xD2-R1zciE z>1bt>X262>U^8`DVzMc6e)F~ZN!5Y;~3K%q(|#ir|Cy6TB&W^4tRYHTgOTH-rEL3Fjt zaobto2E^mJMul0qu3S4-)cfvazAJbX$e=_~YV5kgw**|=A%^&IYXTrWbFj$%-xx(c znAx=5z5fk&j(j_KIcs+TXLA14joWdAr%E0%W{(^6WIAoQTLIfuxYo@^Eb01p+q{#w z?+X)wECdGhxU%IcCZ0M3P%Z~zCFU0CFo7F{0cUKF0Bw{Y8Xy&PAZv7qo=$yz$N&_q z^mtwp(GR%eyS8Q8?$o_Ta?2D@$doK4c6At6FiP0Oh@G1v=oD4ZfsniC#1CJb!;B7q z3r_24YkdZ8GU|6;fn-FvVd*MaC34NC+n?a;Fv57Tg%R z#c^d~6!cB2G(d4o+vD!T>^LjjLcxfv0Se%fr!BmG3>(3E4KN-Ackof1UBb2mCJsF3 zX~4+sqmaoOG{+1U{4CqJyI7lP9f1Kr+7MtYGHx)Uib0ID?&C!AOK1SffStJEqD_6p zo>rZf!L){!9Caq%Z?vo1jh|1?)xC^RfRomVq?Ip)>?2&NnJ0NcB_7?X_JxC4y71ol+l)sAR zY$1a%D93j!0I4J}Dvkgl0<&XG;aiT^TzAo6wvBT#Ngn`|WY;3X-b;Zy14ie>3psH? zlTkz zX*_G;XJ36fkd`=ik7%i;)Q4IA3JxZ;wV8PeqII~&iM zlHR_ZUVg6yxOFbc_h8KeQZ!(+;lhSA%*JSN-g5Q5N@=~Da|Wt$hDd4W z-(emzEb2Gz+Cc-5Irg%Hjigp=vdeL^q%^clbvF_$MuAqX}kUt5r%(i|8mauL2 zTYZwzvGhTv?DqJ&$G5?8-3RJEH{l!=lTWYGHm^!6l{u)qou4^LaqQhmW!LQXJPo*% zU3lmeuETwOytudz#?!F}KXB(m#HJ9UL0pTGH)*KY4NqMYfPm_C?9V=_Zp>jyr1A_U z46m0C=U}gS@N;<>cO%?5`^tp$K(IA&FJZ!3-K$7QVdWlBT?ta%le=n%1I>yn<_cyo z;h5a5plYDBBFX`KUV=QjdyFnQPtaCYF7H8S49u&z9CqoOkOV1V4oxb=1d{VO_gvr- zTy%+KH~@`(&}1~Ja)-4xN|s; zck;w^R)?(0GQiGzt~9^0LG0>YjgT|4k)X?%7SL`j9?%d+P1SWq`HiZ9ZC0Ik_vV?L zC*2li@KOxr@-CZZ8U+A=e|njh zi?@GFAl*IF+DZrGF+v2}JKvAx(HzS`2w*<0nXzArT&1=!D$ShK5p=bPS=?2dcD}~> z>uXNsX@@wC;SzT*@L##6(3(kA@2`uCx7TtPTL`DXzU1U4f&&_e;#c`*q4m>0(mRa( zLpTqxBBE7qG+-{AAW3u!Z!iEX74SOy*V!Z1k(n z>umRNqZplw@4JgvrFUj_Xu#_$rC6@ZkAZ>OyG5<}!usrokd^S5C6Ebf`>WQsr(XDKK_!yh& zCDnGl5Nlm5^WKXoyq+9Iaw@8^mc+>~EH2F--+N}~h~pPul{zKDWH|Mh;&U6{OL{(B zL>$w3dAtYU?)b$ej!vaGmtlLxr+BBBi;2M#+UG@W|(lQdxE zWZcMWIvsbA+1kCmiOW@+4Cyk?OdPjM<~!t5kA3m-6=xz%%-FIcS@GkH(g#Sv1H;g> z99g7?c6z*6-B=IeJ9<@cFPF(`4d25sqvEwVOLis)9@C)#)9M%qd03jF@7oUqkq*@sSLxiAZMJL z)gbH;5xF1(ILxgfBqZ+cA-8xrb9<{?iwLgEK}~OWvBN`4x4)Jb z)T$Y`2Ok{tx{#K3$1B9$%qdqG;5Mv-)^0#@UpH=<2K|A9OQkE= z+B{BV95$BA-!h#Ii6Zxb_ibUr6+2qt(FuId;G+cB1%-A%h#D^SS+XDO!U`P>U46Kl zJa~ZdDT5me7#*|CYJr{G#KR@AV-uzlX$iWT>>9R;6%C9Dv&ybV+?Z0);`QRU)UMZq zLdrs>dZrjSa2{1~QpJ+pnJbz*_Jd~Vv7Kn^Nf7wj5U(B$*c9>GAn!9`PSzY&FS^!# zqyc*jtgWdyGrAI3@I{QMWn73wY@xO)Z-DWiIhHbpk5_;Aq_1VHwu>~Qlo)F8f$7bH{+RGl#8e(7Z(OG@aUQ_@t;LOXz)2@reACK#c8 z(gz^5{f?z@(Y~%Bhc)5CEZSxF=xr8~1$u}w1b@Q{lO;A4w6!S3CDLY%SiU6Dfyt$7 zlPz#+^{kRoVCW$W#`N$aLCC=+tiVG0Edm4lEhK%$Bkr_>gd!R1Scf=EN^MWhKI=V(DT zB--#8Bh&X&QaeH*HeLfd0r?P?=SPTgx%eVd^6Dz}D}O~*R}m>UDM)2?g0Ny5X@eV0 zv4d$KX#gP%5P=N<3ALshSMju!XxeP{Z_9n=T)9GG1tz4>Sj^S{9!mi`NK$sX*~Rbc zwrJ66zbYrI<<&ZMc-Xyvwzi}oScW7b=9V|JbO&J4n?Vd$w2pm{k^)nNNrEM*mP#6- zi2X(>u#-y*NXjta{FN5=QGdjU0x7v=*>2y*pzayDmaYm)3v_-|BGD69DLNt1|VWRYelRnX|(?L9zqVqji%5X*R0Y?#(_43-fIIrq>Yx2BMfaM zAF9CLRS6p`1;l6)?ixZiMh5#V3brGj*QaP&`VIgrW(Fi1U6xrIUN6wVyuJ)k{6A{m zckjo06}$poi_&5P&}kGt8%IcBaF~}-f?cagA7!K?S%7%$BH#SwEjE<=jh}rfq=W?w zJI=fSl9NKy*z$FAwC-9@s{5Q+px6PdwbwMBeUVvrwEx?!jpFfarv2;VZE=X z`TN?={fBEjEHSp{E7j0_TTc>c375EBkb7Gy8C**P@c%P*khf5kP2)PQz&; z(Dk2Q-8Ty}ZJGI&DN5^nuYu+fG=QfjXV%_fzfF|kjVG}59AH6aOFZq$0WCI=^I%1v zf)X2D!w_mxyV(dm!&JOY2qeX>(k);L^>;I`a=dQRnl&DdS8y+V^xV&G6si@RGG4Yf zb8GlqtsHE!bF&wQa>mNv$Zj8C{TZ)SH2m8dygx6NaSL&}&W%mZ)@0=O~n=I7EYvu&H$&i|YpTxW?bDJh~Vz(`)z#7N_y^;pUW`|Y)%35$`_ik#k z>g@3BC7Vauoz)m%&HZ_duB|{#e{RF9hW70A7A&^I-!?RxXs7@Yx}97q zNfO!_#Q7jGSU5>RO7j|vF1rS{bkHeE8=j9W8_(3btGYM8tX&?Xf(!b2acf(a+!PW! z5wSMf5@49o(r70*0*mFbvwmhiEL)!INC6U891nby&Gm={&aj}i!G&7)a&=q+Ml`n0 zchZfDl%&wPz@fa0>c#Y0Iw48WO0cUEYz)~>IO-r2*3gKvf>5az?5)T$xW`Y9+PSc9 z%9@ic*|O?7^#JKf0DjmplzYgmw)L4o840q=1rKfG>wC#iB&_d6#`4~2<;z63qqy$W zwpbUG2-1t##kt*O*y%^Pe9##{l@|mpUai?}p0{ITfK=j5VK+XXW$IG5Z1@bNTRGo+q2^c>Hhk^FLR2e!CKV3oygayF?(qIXo<)T-l^Isy&@u!8F$@ z2n9@jeSI!leG#I=W%IfS>23`UGwRn-1w{cz#hJ5he0v{XR<-EEXOy*}Z>jU;iAGJt zLlhujhi|;m-!$D#f7+)_zCX3{bE~{P|B*_aKn&Rm?l?&fx8n!7)3F4+YR=a_$_b&F zm^!q^nvY@yC%@k#=kOS@K=^{-s4k9M9{3Z`-_|oxyKQZ-VOj+$M+{ zL4P@jfyf+&1lfb&;$u+duJK%=Q4vcLxRez{)Rugi~9|Juzfg7SH9kD zPXi7CN>_+JK4(5bx6I~#*YnSJ^5WhrykF&+sLpTw$CQDF1b{FwFfh5WpNL2SquQJ~ zk)k%1xdes7Bb#lQs?x>bIJf;pYX{g2LIrO1qEAm7Cb3*4wBS#W4=Pk37({?T&JY=zBr^(1$O{X)$!($_`I}Ds@ zy*s%tg0VPDKVP`QUuWKCPA>X0-YsT@{I#l71>B?xjoA2N{s;;_-)m>6)&J!O@as=t zXoG;|Kdb;~seI6%l=)-_qd!1_EL=IR%-;Gs;U_mY2{*%FDr&X7m@DiUxvL3t&INxX zkcm=`hsg4|dmbW#CPv^roZMyfEOWGqxkWNy04>k$bf8P|d+fAx+L{ytJIcV_W;qVa z*(^6OwIl?5Rr&?v0ZWy|XkhFVem_@x-#zK7kVJ~ECTdL5N}?5e)t@2b@pbo zno9Ca8%{06V7Y5L3_iM((^K(uw^Z;R&(<33JwN$bD3jQUEO3&! z66{CS4)|;IclkQ8R~u0;)GEO_#Y}5{JSe6|vT4a1t}JhQSn%j5xF3V}H zs2dH)2p8TN!G=*r7V=9?9Ki`je(?CT#3G7qw$!sz^wO$HE?YcJ=rQBZep1_a+^M{M zR_9EEIvVDf+S=o9F8WJ_oxOU{A|h{i&W@+dvvYP+U7L>QF>K!as61ayKZ^Nm@%w)C zn|$M6cP{`yh!e?y!59P{e-C@X!&7B>63#pF+2gn@=FR04YDrNBmaBH1`6R}}q+3i< z{5Fm+yL8j8X@yx#=YgE*xNLj+sQ|J+JC$4}d)4yW_-#9@31;&g5rGgf0jJ}g#YIBot7K~CqPyacpqoCHan z0CSPSjmIpZ8?5H3B(OzuZqU!B=HQ?hKtaHFVzKyY8m8WjYh{wAM$pdgqoYf$kY;mN ze?RBDh~~vR&3pJ5Sw@U)o2_@kMO45_jdhzXwzG2>iIRgMC?ujhJ9oJoqRl7hy588D zB1;Wh$%A33RA+d92t^`HkS1L}iQC#D8P-WSCBUm++9skCrD|xx+os&r2EL;-{&GY? z3o^x*1rnfwYE-+8AB|-T*rr^=$+_`ofSkQgufewzta&@k5>)yPaAkMhL6^>B^rmLV zWge)%`tJs0nG)adf8+U2dWL8PRJ55St6zMYO(%h&gUd)}4fV7xide0-92W|gf0V(q z)Ay%dlD|8_(Z`D`e7?7IqdqQxqEQ zb8Cw6^zAp_4bL}c+V||5XIJaI<6I{-k_tup#*{HZ&&ywLIF+vg5^OrAl9I4D_|5%Y zYt}m2v5P3Z?-g4iKRC`6oPFi5OtE`T>$d*Em8|gb^85P*m9mZSXQx|?*#+FP?UR~( zabqE$XbJc*%m-73pAN|=7zQsYjt>Z_Qb9Bx8KB_}_Exr))L*v=gA3C11_uqqo@<|I z2|>H4g#jEAwt&%|&+0X-T4S|3b`FznLlcS3wKg^g3pgg(6-EZ*0yz+4d@$z=+2vhb z5i~+yLjitcqP4ta;3;xfoIdl}h^yOZ@lLZCWgilWzI5-IAI!a_$Zxt<*mj-@t`$2# zf)&EyACmj5mLVSEcA}$^-6>v7N7sawPZiMWDeLGyZz3v&_>qH^;PG9s-}Xc%i_Fo> z-|Z=R)7zg=+m$bJK-Pe66vxjSbOzJBQB#tF2DW2>LsVJ-ViHJ#$HK4R>nGUU^8Uwj z+Tyg#Zs(+m9Nhl8f-jX@Vh}Tl77>U2h|qUAAvKU%h#h zU?0$Q&!Z}uW=fJJA%IZpcqiz3!2+M09^b>3Pi=b5{V@3&FSb%s6#C}vYikV#9AgV| zPTEJ$C#u88zWlwb@AU}~uu!{0={`h|P{&dbQhhV(Gj6?ww3-`Qzv#I}<8%R-O1xC*-lv(n5gm1);L~MRcBd)C%zXLG00W9bbio-^aYf#WanK!2oILRPA_VdSoQ>5? z(>{oSAY2o5e}=x#x7h!Ge>1laHb8k^F9|2EJUUp_AX09 zOEYnJr2J1p8hud!1VI31at1fbT;R?G2HIrcaiP^?Ia*5X#mi?)E1%`;v>8rRkFT{A zwC*W>p3-eyF`uV$TmHE2YTt8Qx7o&~uZ(40(Fj66tEm*Czocy5`vHpr5R4Dr?Yk_r zbYD67uCXumcv46$bsctmkCQYRMofLk&-`4SeGlaRxs)(pjp9iSf3@1=HKg+R80G%A z+hsWw2DS_9MR>(G7Mxzi;M; zrCjuK;v!HMYEQpnt&nkNY_NrQ7b&;(_Nps=&1I4;oet&;!)_ z6b2pX^Xc`H2C0iv0ocB3=b>%%doTKTF>TA>dQC`=0OdKj(MLZ^^Z$&#@p4a(c(BZO zww7pw;Z-&jkE1|!ftuQ1#_sAB-JF?tpzb1N=KS2W%bJ|{AybPj+U7&DdwlI$@(ZlNX12g&cF>~FDmf4Qr(*XFOw8%Ny#ESVq=%I&6((Ve3fZ=DLD zZ3Aq#-gQ04m)HJ(>+rc&p5K#e{LK9B^Z9gX{rgPua>OJ4)P!M%eSd#Wtmn?0okN6> zeXs9!vcCA#^L_-9xt8aLo+Iuw5YCx`V1Ni{m(22PyLjtw&8i{Oo9^pz@3nmR`ijmp zcVChoJb^@xu&PODb~%IhV|(~ZSK_C?F8{IYXaet#NQ!_$jAz1ItkPo|vKzghboIaK zEqK?f205(vf!!a9Y_nwoy!<0t5^hXp#Fap5eb^2%@_GyvN7)+^7V7 z<&!Ix;jy)gj6`f`e=9e@#{HF5LKvVu(GTts%=iLP`?jtfH^u8BF_1dDKIxmah-KA^JwX|0i>q`?OXJ~iF)#aF z%fD%BZ!`ZR+b2z3nok_Bouf!Pj<56!B$v0A! z1@nh2j`NHpULy;7OKVBz_g;6oo;}A~F6$2ABk^&;+!Oe5Q$+Sy`3&qX+SvhR zYo@YxR_OJ-={zg!`t0>DAwA~@^BHRYF+FeNN0MUb%aegi1loShb8H1q8$I@OvtBv) z3~gATtUQ?$)9MYPA(9)59M9*((?YBzYd@4WT|;HMU#6{)`hAOBbC!SrK6JAp!d!vtnppD zi*VIDopfJ|Y}gX2)KYLC*&B%K)`NKO-?|FA9K4kOtHI=10r|5#eP1Whfm19^EH`I3<2Tq*-PLwy?a4GhP^{YOh3uioaZq%6Np31VKPEu@!F}W z{b+~Xe9zYT|I13Gz9F*j@BKIsE`<;#!#YBt5FsWmx0WT~+e$e0q@qO%v*vu=vBArN~Z zl(fky*XK*ShZ804ASwSu1>BE$BrfNfnM~4b3=~1hO-+hf7Zd;lAs8k=CvG@F17=9T z-|vm1KjE|IayDMR%X!=1!C?7vzJ1o~@q8Rxb)81-48N#u7?_2aBq<@d7>1xE1DOP5 z5fP9KUt3iE3YUBp6aoLW_+-+stq&q}Zea#BN^Uas({Y{}CfhajoZ0dLt4`271o)t{ zxGe%XWa!9Q7z8G5vG=#L)2266!XupcHZyX(_PrnD=R)Xzxc@};vn z26nGu(ATWlb`mOJEP!7Srv)$d9>!oks$|6Wp; z;%N{s7wu6mhSBD%Qbx}JTn-}N=W zZuk9q|Mv4Ou()tzyPtwQQ>EU)bZLz6Y1Vp!PaJr`NuZ_+9E2u(~n%dUB6_mH6azjI6W;_RqjxSDR=HXL~&vUslg zY+k|a>rZUPbhwV3OA^k6{WJUlK*2yP2((pOxayW}Rfr-RvIYsvT~KYPo7LOG#|}bE z>WgYNrB@L&I6U>-U}TqFwWI29JbaHYRlV}pbt-;+4&8-Lq$Z~GWAWNnd?nkJ(Zdcb z#pBU_4wfHxe}mk2V9A3{WAf{%pQiLc8;ZJI?$4JG#-v9csvT4i4T^-MOXzc}YXow(Q23TQ__89PUBjWLcQ6 zO6!^YAlphersu$%Vc}*u@F^QGs71k~6WJyXEh~-=6LzU3csSFh0sN}^>2|1Tano&Y zn+=oovQy*k$mVl7JecW6Qeil*c1=!#&G6{WM$~+NKXAYHjUvoRJL~v8TvGMyJ4xF+ zV*ecnT?L*fvI8X?=g?mk(xZ%zFSyYIUZI3B8XJmrq(lKl91#PM62HDO)S#@@P4BF} zPGpPJrBiGVTaSn6{@%y#_k*oVW|~Uz*y8y6ULOyn1=(dw)rnllA4S)tJA7QNZV^DK zp_?%W@u$Q4So~_t<~mcSn&!G`KCIOU+e3jmBkINv$|;>dvZ7&lzypB_Ky7ob>wZa^ zp9xQ{(|E2v+Y~f42jfq))Y)6B@w!c&>)78Vrmv-*#NvHdiI~fdah|67#~}jYaeL1^ z3MO({?U>VT@&g4Ov}TZ?X9;@_V1r1*GLl-1q)^cbe@L@486uCwW_q|(L462aP*p^; z@yr%|V)PdOMN+ysqxJoOAE(d@%tX}Yh21lk5g`c=3M8|q4&l*`a!ARcG|+-Nb`NW# zu&(&$@_mVH74F-R<*vNoy8rph1q(vDa&4NOft*M$rFqOstY4!w7`{X{3(yxVN$j=J zWw7SmetFXGhT4AcQiWr|P}{wnVK%tFoF=*BYbG|6R)bA*#Qq^P2b#>8a>x(|V!;Sq zyGTdNXatF|0;r5&3<127`1xUla;rp74%urOX>3Xiu#KGsqLf&l`ky9-o}TKr^rpRE zKD)iPx?1&s=ET(C|BdI@C!p4FdAoaBkoGT};!0>JfZFJ`E;(g>)@9I;*sUf}@&3;Z zT)p3cMI71)Vb%7~gPzjrzqHDk?)EJS0N8$uU%}Gppn3C-YT4R4@rzt(v{A9V>fYui zIyvhHeS_!vuKy@5zG9`nz$)zx-*0mDTh5AKXY{qo=ofM^V#{JL7-r{qwc3_#%Y6^) zXl*MvfWRG+M&2IIi878O7>Gp>FcfQY78GpV0-jsWi45?akU()W4Uu z^UeJ9x*iAn7XR|{>3oTCx2;}3uVNc%zNT7}gcUBcPlBQUH@8Z+!DAlhoO_*4dQG9F zx7Q2)+aN-vrZE+n2I>%%9Z^9>RZG=2g25D00VgkhM3gKFW;+$G=UYv^8 z`OYds`XxFLO}SZawV%7^cjvhJ_i4Y9Cr)Hlhk@aW&3ayOuNqmum8)!lZio{Gc`Mjr za0s)=JM&)X`1Nks8g-T^e{O?2pvZMU z6?wg0^iyZran8A~(?N%N_FUlMx)N#Ku)^l)NvwML=)b>gggq681;mJSLg=RRQ>KD~ zAreB=MvpNABuVG(N+cmmJVn{)dUuk#z7$?#F=49R-|r9F--~8kgJJ)a3hXp~4I!KM zauG1HqE7fl2s3;-6`!3M!#m6?OL~93uIz&Y0}b9>E?l7p8Hh=88b~>AY)BhP4Wx(d zVG0@$+5~Y}f*1oB17cLZO}x)rnc!V#@paZ_b)J7zoY$W}vB~HKrlr7+bB+V9U_oPe zey{r|x5hLgst2os-nDh!pW`-=o5&XyfNb-ZUaEoC3v~V(7u=7NhfFF1hIA5eN4kPk zEk_30k-O1n0b~R%tR?zKR4$zC`)kIEWR}oNY&EP-siyE5Z`0-A_qvOV>`Se~O|OM= z*XA%9eb4U{(fEPW?mFCmti=rmw{eTnbE^O9Ih~&i*Eh~rsi^I9<-NSP$mlt*o`%s9 z^py8ZNLPCDVwvw~Gwt+^c?WonPLm~{;qblr zSf2G)5!dJ6ljQgRUi^Q5zuJ1z?@@?@l%C8~Dd_CW<2)Rr*d#8}9j${u7(;fj@cz4Z zZx@c6g>>rO^t+gTApU!W4A)EB=`uwO4 zuLAQ0MfLLIwlw_7U603AzW1=`OZ?SRcSH!a{XF`dm-YCbtlnK1Op2zN;YTGriQ<+c zoJ)i*3M7DhvCWvE2ViWtT7&ox#3mLr=h8FT33fb7%2n-?_3Zr?e>Y`!U9QddfTGw_ z_OLE}-|6O}q8`4!zP`S`zP`6PUzglSSJ&RQd%RoTVYBz$9{qbZ5}%Es_x6z`(y>I> z^ra=E6U^hxW6CaQLAS($Ob%(lmoSm8$>vxb%Bz}ASQ_<7Eg~~X8#Yu#KWh^sm|CW0 zi-#C!Z~=bCX4kn^J73t}t01c@D=RBCcbZzwE%NuUti)DUR!7!WR%9zHD=RX!m7E&S ze^2_Z!8cp2HzDd0PFyizhhHTL{mWy0sU}Npz4)lRY1c%^2~)&Ns%Ipl0q{6$Mi+b5 zHsmNUy)%swfpC~bAWe|$g8yxn%(nZpl(}13x87@)4gHq$(URgm@V9(SpHkWO+{EO2 zveA266n@_<-}ivv&WWg7=P~-O7muW{MTsp$e29gG1Y%Tkky998+}cD}fk99OMW&R$Q{(qQksP&e812x}z)TC%4R#jJX_?$ z91oCv(C|Fi?FQ-um8dU5vk%i&PN+4Ek6KYSk}<}cAsCF$dApltpQWEao6bqArX;MG zR=o{gp04j@tEsD=tGm_O>gww1?=76%u93eAF{n*6_HHtrPm)P;xNxvQjlSD^QmaF# zR6h0q{~LXdkGrG4y>2Ay2Rv3*OsowE{IO$3lIa!Qv+0K?l<@B5c8XLSWz3blP&zxj z?ME+9L1sP5CYIcGn&lbjZ4+6FTSx|Dh0Rl|e7D_m7+khjE0m?l;xbQqEa=K*-g@^2 z?{Y&<>aAasQG??_jg~6Lh-iBxJ(42@67I;!psC0UX$i>ANJZ2515Fom8kl#N0S*%H zh0LN{^6nWa$5nssu&zEG-eWO9(V**RXFYrtX#eQ5>`jU$Inn>}p1J>@oPbuNd zW#nP31OXu6$LzBXb}i~-T=LAR;ptbGKG3BV=cua^QzWrvaxJNTTba;J##9_-UUW_A zxiU3~xQ*e>P!@6oPR?f%C-8^DX?RJ0N=yH9=zBprIqee7iG`0>`t6E}P`C0FO@o87RTL_tkJxsGF3OLh`6;s=86Ug*v)JwxtA$RdSLXjx zHdq?~{e;Wr;55oC^6E`1;enkB)Rws9pFdokp1H3>n}g!szSi7F{Mq~F-+EoLKJL?Z z{YJ|>7vCQq*pwbkGrkwGwbrg4lAmUgzl;0$RB2}P39v+w#3Byrdt;%(t%=oP4^9d) zOhgHLa(N(-k}-wFC3ea-0U$w+!8X*{TGX`5`Oblm+K@WGp%M7X(^9JA@8sWXi$h^M z?w}>aU+o#Fc&zovq&XU-#KcJPX1dtlIH%qF}D=fq}(03-gOy zXu{j*Qpeyem|S-AHiW?O0FjI#AysPp z7>G2D3_uWA2LM9D<*_B1AV3f?8_WTL0APSo1~7FMP>nD4&VGg-`G9e3p%acR$Xq@$T~0;7`R+sYU8+e<96c&Fh@TiTcB#q*`q!qrI}h_4SjkfiP=L zwQ%LX+8N+G8&|q&KDLrH9fiYG^6a*M^RgI!9T<(lnqcM2;bK$6}=ofCC7$%EmsyOaQctr@{l8i~ zccE8(+g-*x59ZvZrkZPG5|6dAIicwm$o9YTl1eG?eh9+QQA0?3&g>nqjv4TIpCRl| zv2daRvBLb33_&nINvQ4Hl#j5>TGz)?7#LbiVWm{NChH>{oe*vP_j_yx>xF95-`X?t zP}jFAOsov|`QzQpaO~fQ`wXvWUMyMd)yMSBGHmyI>Y|xh;5lZ(`@U1Ehun&QtFWD&w z4l(|d%&!B;`BcSUT3CCJ&-8=g9s_lX(juZS_5kBJE{Ws8FW`dERcm@XwHDbk)k|ir z^CkjrrM(-1i<)t6S!UpMq~3R}o_tQG=-&aZ#z*b(`%Vphe!Hp8s@s2mM{2dSoi_)Y zWGtTk1N!8Cs!Hh>qak(1)_M3Is;qUjtTsLH<`SMb$TUUb<)UNa*e-N9uSA**X%x{l zW5tZP#ckXLb)^cTCW)GD!89Zq08nXfQp(Z}o#h&r&hCDV-?s{)qN1XrqN1X6@u8{v zVJ?qQZgsCH^waKWtcaG+3X5Y$i?hr*Uz@zCN&6uD@kypP2|%HYV`J3R!h{iEqpAHpXUn_EXIHxa6Lfb&Qi?E)Ih*#2n z4PBBAEA$D77dhD2{P8RBQ8GfZ4z`2)-I#15blqE3whj&s4!3g&v)|NWqd%JjY{b{= z{kW`gjr&s|I>1H1T!CQEX3Z!fE!SiL4oVlf{|JMSU!zeA$jX>KMd227g~txI!SV0i zr0zfFqj@39>Nrhc=6!!(hVp)Xam~ra^I2g#)8mDb#@L#NE47h+wU}|tEntWlFiGr{ zs<>E_vLu`7fM zAz0l*kiKxbA@%5OsY)CPXG>AFuNvGMLWYv~0Kgluf$m?W|HCtxG<&83sicrT6R{az zob5LlUOpFna+RaWQ^$RB61@5Q#W!Qa+3{VUf3iEccD1xvGS0TJA5L#J555o!2moi# z3*MEx=rwtV6zs_V7o_(8*Y`h`yz8kt>#n-%uDb81*GK{Yq*2oyEgh|{@prRexsWL(k7Xw1!n=#E}10xn>)7#OeE@I|2D zAdxhEIl@GKn!2}E*f=;iK2I0Z-2VPPPdBHZPu$q-aC;nA!H zzyi!rq98+IlcPydmajlU$b+L|Zy51y3=nJNWAG^4(Og$OBsmSbYq>yQQ*Nerr0IX| z+|{qw?KMS6nOxD4&Iop5Dtnr?e$!zsY{Mq)&KPEJ97|b2=!@%$+73vlx^}J9Pyh%A zEkp0Mf1ly|KXf;|@9=Q{qCSVzhs69%%x&_%Q}k7Q9G4rZ+J}y@MDH#){p>E6yFJjd z2k3zFLu9&9#Yci0wFiindh&nzQ}cJ8v!m_*(R%g8Ed6(qkBtM9yjX)b<|m@Ad{uxvc+ zc)wqc&zo9YVjJ46z zfe5U^GI(H|`Pnb91J|&92pbLi3fd&=a-s&*HA5g}4Jp|L!zdjMGI2vq#6USf4U;7a zxiC$qRMeQ{4HYp=oF$5g6%hkvEJ?8<9Sw{sV7Ib5*QbWzZzmfM;nt5$?C3c*yVi8N zd9G#enat)i|GgY7nZfa*z#d2-=p-Qko7V4^*Sh{2NdHjv%bQQmE&#BzYpsR%E2s5) z?4QhdunWDC!Xf&1PebYP{;hdWj(5ENrg&z%FA|{RdL&`R3UQ|rl02d2bUbUBKK6s6 zIst)k&=C?DOWJ?ZzKKX0q4>;Bc= zg*~a^d%FKX)K~?8gxz;t;xuaDUR^j{egx(6<;a7~*}A`Mwm)$w;hxDf!`Xfa>+3!? zA$f{&phrbNjz?Rl9*SlvGwdN4i1tz3yzh+quCFPF{QDX|#ozv9Z2O;u-$(p&vX-+y zkAaJoYZxr?F0o{kEPb4!T_~QCjm@2ws+G+ppU$?I3x&ZZD>wuFa-fa4nJNgUZnBv^ z9_d<<-*=hPD9T+=z3k*>3^3J_s_bya$ACr$nqn^uFc89fPco(G4QPRUPEJbTrg1p!4G~eP16Sot!=8W=DvecysWA*2--JY~Cl!r4k1gb| zyiQ{sbl&JFtdu-i;>N$VDIi{{f>tnSh{OoQK*UA>qTT^K5dzb~@gDFvC@wAL4c*2c zds{W%((N?gFSgH{=KZdR&i}U~gO`iB(1Q;BEs^pzeQTx%&?^B8oM0CsvnQya?nS~M znM{OH#DGU&srG)(ZF?{5h(=xtuclywJL13-@p?SbodLuqLx#wRaSj>N*16SMIweB){lL=&n>}zh^B@S2zYM7;p2mO#6fM51ii;^f@3C~kTr=4~Py5epS3ho9$pfkSlwbdv%Ba2!ONXTg!J+z919 z_8+WJXz(Y^D$;(w#8+bG>z9Q=~|XL}BQPWfsJ(kx#B9%uba+ z!=(7kBq8_=Sh*KTE3R#}(=J{N$YU0)&ID@!4%9+ftcIGLpsRyH5s;x?wjk485~aO1 zi_9m{uu28_RIB&Zs|jV0!F=pY&Dft>kHhpQ^hFkS{r@A8{%QGpx=V6!2gCsT-@7TG zM++(1fbRG@Sh^n5c)NDUzwU_~<&SU$5z zs|K|;RVoRRmja|!Tz1KkE99!4Dhzi5DFkn4g9E;pR?(OUmKK_-_#LM# zDU~1U2@77j#QJ-2YX^_T#d|}%2)n$K4d@F&X%BYK2Tw~)XORVvrK_N-*Rtuv6v>sb zRNWJjZbXpLg<>cuW|5|u91*DOO6jH*0l$Fu#bf{#v_zAzr4yPb0Hq2|HnvzpQe91r zJ$+uTX0d6^GoT^<3GZv~t2XyErJ`@5rwrfrkZnDF%Q&WH+R{AvNY6t&7ADM1^fZ1JOKJ<2P9gIbMl>_>NC_e zJJojbz__25?0840>C=uI=P=-QD2KHMriXdn#*5Q*n?Q~15F+h~6mLV0!*-z%A#^tL zXg4Ls0N_!;RqM_=EJcjnqfS#UT2eq)dW4O^tEK3(oOxL>;>&L#uE31^>#=E18v326 z1QCIZMS)`%F%D*;2jc_DrmVv6xQFm0vFYPv_t z6u@sh5)zz9*;WhMMWLF|gp{#GS{OeFDT+5nzUR%>DV^3>EB7FQA72HmmR!iq)uC>B z!ZJ-%)If+bt>f@~uLJDGMm&*L_U)fd)Z+9xLu!IQV%tk22R#hn>gn;`N)a*Y!P|hw z168IJ9cT`Vsnpb0N~#&ieV`pFo8?lQkPwP66#%4RTNmnJu>!TE!Y}Gdcu zkg~dOBmG`i^cuoPAId7T%8XWgej%TzxEhhomW?ZOTa0XLl~}B%R|+kP&P!lWHZTAS ztwnuz!1+}|aF``nfpyhG1zIw&B$jZ#ZJLA?&Ptgg2g&g$RkEc(rnfnilENxYatQ#T zep$r>->4u=IcYFKGgLTX^{<^Qo8QRyHF^9lN0+t2AkDs-uz6+})Zz}SR?PeRE_fh- zE(dbL-ibmiK>5!;FS7}`nV1Z?Zz8BCYdx>@=bYeP5wg+=+GN!&y}4;}K;d7!;s*?0 z!{?2E#QtZYz1r9P4e8jv<9%sSt*FeJ^y6d|aCzm}Nt;rh4fS-?lzC1%Fq=t(3hcze z`DLk#M<%#=3|+VGCVQ(ofMmMqfpEgW3UG729cG)u#GFSDd3a^Q3fv{5zw}Jg|+XED=ivkJ^sGF^AKeI zi+s%AnB|*oTJNU++-r60vxUO|cZdvpFBeLIs~WpsacsP*dDvm~GGwnmUv&N{cVc6z zT6&*0Fk-z&==z^YUWf|olDoQZ*#AB=tIf~NgAdB|5P2Yid8Z8IC8B=+?rLR1(%bT5 zLe?G;MB6-N?o_lKFFsQ15?}88uodiujJF*;E$ZCM+(p|+xcYdQ56r;34SH>pSxy|c zsN4P{uP{5D*m`djk;rpqW!X5B9$d^=yHE_$qp8c9IxO|RqnjY@I;49&U+zJI03JOr zR$l5jwk))vebKZCgf|OWTJCV6PP|}_o&cbra`(hQ!2k?}r|*LO?J$jO^vOn1vDmV6 zywSJWIbRmk2y?c}WEg!Va#y+8Sk?2s>?TWrP+EIK-B6Xc-Bt`Zy$FIWI(pOAuTfZ5hl5(Hr99W1AhCk3RB0nFDVI-43Nx`bXSj_$Y5)@j8DjN> zUkI_@`BrjX z@9$RiT~w?L#;~m+MOA}Tl_DS#Gt1=3p%^6nYl#FPsM@L>GmFEOfjFQ-l&XP?3J4Sm z@*qvNHpbZM!-}6xZg^zFeb^wdsL0{aEkH%m60cwY8I}fgJYiBc>Qa|Jbfv@4tcJuEz+b_V(c|N24(DwX7TNW!lD|nY}gwWg?wg)IeJ>Pz+`Fy9?_XV{{BmOFqkl0>((4G zutB1{mn~J@3PHgZj`R-t=qwt+n}n3A&G0M(gF=+mdL$H*ShQb6@bzC-F{nLO&MSj3 z1b1ZY3sixrN{X2^gcQ^asv=`)33wDYSZ( zCe4cx+#42lK{W}+LmmaKtuX)*p022!NPjHYo1mt{pf# z?%wQk^&XQ?X=bx{#?l*E`E0z)Y%F=W>-sDS;1|aCNMusGg z63)aMDHaNFPIT_&kNf$;F}4H|gdC8TXp0@@a!Ik~X-Ub($a z4iPQ!P?2Ct6_Mr!LBo%dFqkeT=Am$hgieD1Tw4(dj7_#E7!Dr_iW_WUcz~$oG;Xjw zYw28&(L9h$fR%OKBwqM!KVaZ*3of7|ip#QSpw42hfrd*Ul5J#py82amzXmF*u(3c- zG+GQV*&*gadQ2*aNTeEOSYc^~70%yFi8i-ZgH|%QDV2y43cnCbhtP@Dkta@rlW3x4 zt}%SS8&BVKY1`ED{U=jLxxcFUk9Vy>*mW~;BS9hv&o(kV!@!Oq($h>#*SLUz*DR6{ zKp-U`sx5JnCruNPD5a~Ssq{jLtH@x+n+H0FHdtcE8!>jb8;v2&oU|%69!UpYMSzh| zuw|=`iv%}kHGJFhVP~vtVlG*%~gP#mVlBkG2lykiSG zNwhqRm5k6VRTWU3Lx8ZZl6gmbrxPPGCvjavWtRw9P{l|T!l%3#T##N+)d3=*M1$j% zwH#5lfYk}tOEM908s# z#b!gWKt{MeVeg6{B@sPQ8p9PpKodnoqXbVaG9GntX)+GUk0eZxIfm(m%v!R?W43-^ ztSAT-W?anoK;@p>$xe6$V_@H5wVp8Es1lzP2w2%RYYH7O6T3)z12tu(OCiazfzzDA zj9H+iaIy@Ln{dK0i*8@28@zl%%zNjnDLE1%A-2dRCsv2*dV9Jqc>Wvhd>My8A8FL( z@${ZWk*`Uc2uqgGC^>f*Y)XLvpvxivRUxJL_3Rjq3li`-Jeg40WuMqHf#*PR8AC{e zYlIdHKvu*=99W5F1f(IcQv?aHh-gY-nJIuk5`+*1T4+#!gVCv_Jju~nOQfa|_|Hex z_cPB*PtEjcB*~WAamX1)aTtj1%amZ}p03tQMWgWhZXxsdzqegSgUF6P6qIpjB6%{) z>e9X6AJpddHEC+?mpwtHjtnweMOu^NDT#6^3a4@x4%F%n6%a0!@Ko<47Q`f~tFfl^ zCZ@X9DjeP7En!h&l*L5xdYx0dqR}9z;D3>xdXf1XXKSaQDh>PL_V8^qJXc6|Swzi7 zZ^!WQH|RfaJ5y(82ghng*PoOFQe_W29+xzsIRR3X)`Fh{%ss}Y(>Icprv;AjvT;=q zP=qpv8i9iSHFzl!@2je%`5ZcHRRGmAJob@WrXz=GHz8VtV2c>L+bSC~*VNYZ(K)?1 zk6i>C=n^0uAMAop)x-|OAF9BF1&w`Aiyon_&%PtE@Ei??6xis`RHHvfX|uW3{IhL? zc#Y~Qzk$#i&UQGR77j4X_=cl}-CI2j-z&h0JW>bXTFWH|C0t3$L71eH?9~CYiI5?$ zZqW&5XpvdPBp|lN%;p*;PgFo+7v{{*)i69YvNK6D6QRkr0iBCUtPv?#|1Ia4g?TYX z7OzU<42H&HBY5C%v(vg45p+#RCM=U6kU=6yB!US964K<-P0nllg9$`&&?DnhxTTF+-r@4x5( zj;|OyJk*4EEdvC-r(s;e1&vs(OF(oAw9W3Hi7_f$C5jH(PajMHt#-KWrc)-GyHhn*0&Ee z-XNSPcr%Ubm-+TJ$8-!dwQd&8x5%a*qzd_9VR+^YoS>y{a)cDnX49F1(34h~(vdb* z1Qf9qu$p9unw*G|&jSNSfl*};yV^#{F|^pA1crbn%7dtSbD;@i#bVMgubmq#WuzTS zvjJs{nQcMXfsIy!V;TCH1+)avfq>Agh@Rs-LI_M@HQ<6fCO1k}@^kSleui1Othg1Z z49YGL77D(mX1@osFKdCUx^!N*Wdx@#S|E#tzPLMMhyUa_)EgrE;P2-TE#C;yS*9?p z^?pC4{L3kaQl~=T>D;4n&SyeF1n1CAa9bI?G^#8_>DIE&&Z@3OO*Ysj!LhWOa&WG& zRkrv7;ZRaBx}cz_tR^f3>|=O>h$M!&gjQ%B&2@s4Ra5LUk}m35zZ7n3?P5g62u>za zII5H#X;T zn%Ij5$R$*&sXTDhEEGT)09f!i5Z$wc#fkA=G!sDpivgwZ@I_^L9s)yhQEd*8r!_!r z_YF4KJS9r{OV(pdSTQ9C-{>IDVHphTg@{?1xDFn9hQl-<_-iUMDm>$b+Ewgc)5)%k z+qWU$9Je?1o8F24&(oRF-Hq$5pTEqQU&bgK+R(?43Mbw~K2yOI2th0;iCKs(Mi9|z zvDFh;C0MzDZ`cJ^a0#KJYm1z`KB9d}lA_NcvfaQ=hcLa%xIeFQgA38DeBdeTN8PxFO zAY@HC$_!Z1<$Bt9A_FOYbangW_%Y{vJUbN(MTjqm1`ZLv>v?$Ps)mfHNoNi?lY2xH zk-<}yfjx>uSyg21%GzOqtN^TTp;b9ICor_;g)AFm2GGsqRIFTJp9aIGclTx$U|{*+ zGrmkM&CSA{So}%|kT`WSdx%K)^IWTHwB^-1P{kay8XYXND8f`sq_Lue)DtrkSwjrK z)JiI;Y23y_6GH@KWyF|82@xn#0^q>~sNVBmjQ%-0tkr|9TVBJG=zJukc@Y$VJxwP^ z2sMzD=C&~)u(y%2Z^N(Va`gW;!QSv#^^Vtq50Q5sHJVwARPM=z8EU}oiVO;QD0B!B z0x9U3gVZS*fkf-n&HjzKW}sn|q8Y>pr8Zz9E|yaXe$YWI22OOtz5JcI9-&&B-ne?S zS}VRXF&Fj|f)KkT+0{UC?t}saNe(1Dc9+d7Y94&Ushdkpirp0}riv|6ONuaS2FYCO z&!rOd*AVlMSaZHL9_P%0?Psh!!%B<{o+h+p83IcJD-iqIr9p%S2ATi^Uqnf9Y509} zYc{RSA_H1g#AG!>;HH`8xd!gM8Nve~b~ez5MVnsk<(7~N65Vw%7C>0#ea4)oH=}KG zMqCw@0|rddaeN>y(GQ@ysR5r;mu{IS>B;?bY$b%>$oiy1YVeMNC<*JK#*-V77uI7*&)cHDoS+1vMnLq0#Tt1i%7Po6_#ra3kN#H z2O!=`#Li~a6Cxl2=th_z(7?M6o51D5FkXxong*z6y*X zPUwrw+{50%>qzh&~`a=j>L+Guk?wk+5EcV6KQ!? z%8#@AlEFUp=2;NX+i&6rFLI75zpqtvxCvFdR-Uk+W}*n`GYy2RhEJ`5bso!$=W_nt8~VMVd6|d{d_DX-x*AHuYeF zE+SOYkxxPQgrOq@k-tRrbUGQ?`kj9|;ib>7OGQWvBJqoE-HSPag2*HrXMN`I;w4%% zNHRViLq4BNC>{l`UmJSgy@wA-zRS|KL7ktW$R{ek1j<+|X#xfg2O>y7U~v?Zq_6~Z zh8qicQ}5lZs;ZC^6j#hnJ6*Y_%D$_#Sl9*ZrQCHa&$l+GS5kQdL_`-P1H!P8tf_>+ z<*jop&E=eJV_xw)nQosaaC5tc;qdmx&eG7xG>=}+tG406td=T+7DZ<CYl#)-=&rIMpV4x05r@!0m|_#GOGtrW`CdImA9&96h} zH|TFqaNx|oER4>Gz~qtH95fPe%O4V7N5K2-FBUz9#bA-RUo19PR_9q?v!deGowS00 zgsY3H13$Roxyt{M(dz#A-M8Cd?Cr$VaO<1;jZbdOtm#UImsDBYfykW6_?)hXZd}%V zno|<;Ff+{myS};ZIdP$BzN{KrRdekQO0yp52R4O_TE3~cCfwG)q`-e;z4;ZY8QX@T zEm_`kjFigxK0{zn=}LelnL&m_%wgjU2@SWqXC z`T2RK6;UOT8Bqx;&QrGXr(A`zRFqK2lSpof2YUt%VY=D zC&Va{aS;N+MJ*P(VC9`46R=7P#CWnCw3&?0C)RuJCjR%-`nRsdaih9Xe`|vDKXl`* zfkgJ6w32j?-0yQu$v-&9uwLoV{U1ai(nJG70IahQyjV#jL|ua5usYueoCfzR(uix{ z2ZlqEuYz@cgsL75D7cdk`V=4pEJiCIRCHX=2U$OFjofBX2@gwYV8~}%4SE#ZbdZ@^D z@-(i%^gZ|UONU9LBKGhz%8-nVI2yG3ud82pRhO+*Laz#gz3F+03cbgz+SJ*ShvPq3 zn$*%%KIq%pBjNao<*iPwK?L~;0m;tg9e>-V8j}%f`v<4zp~9zO)?Heod)!g}VX@7c z`cm>G3YIaf$J=cc$osFnbq^DdGCVnOWGMb9fz#wlR!lvL@?$(*RO(!3nFn@waz<&)6;TugX?@RDp#Xd$fwdld-+uh8cO`BcT zLP1X_)cUF|HDAoH#($lTHK6=a`!ZevMyIOP{%-$ZyS{rzdv|5#$Nsc*vo?whU^DRC zaBC9YwIUw)Yg_&cEZ=@ro`0X~@b|p-CgxY4&sPS7e*vhP0f(hVL+!A4%IA#cSt$Gz z=SpEMz!s$@Qb}ImQeR+0nIs(&Jd2^wLCRfOf>yzYwv` zJX~6s<++M=1rU((%a{kH{oJnx}Gi!4!Lov#8l6I%aN_$b0sj(?hypqK2)UThudBEJ{RDY0u7w#S^l-YhnwPJ z*ATq~*aM+NIJuySMJ+FHe8YanAm10mG@uZdV&?TXjulsONyo=>BL zCGWw^lwPNo30&WPN^m@CXSjh<9sU(U+vP_j4&NyOqD1_HIX~{vo~Jhscn9H{EFKse z^zp0Wcb%OP&?{W#tWnNAPtT!eCu4_x9DWazsq84j*iRiEhaUi8-GOh6PzQCfE3i=* zAScd)fc~!$zY}0L{aue$1nW0>;<`ae5g&d0y7${{hr%qjkkvUn@8E97WQ`IAi5Jf- zk4^S|UL3N9P8-@sbN5zReaHg_;;-V}>mYvP$x94uGcW4gb5Zyx%(xP%d&HZSb6 z$MOG<;rsx%bY`r1sNDbH35bK!5d(k1L&HQZf09GOHo z1yxiLLcge_PyUs>H#}i<{qq0{j_$+{!ZfTQEGz>yV$vLk8E_>a0E{=&4z&|CrMyeG zetZcb$kiQzUCA5ol)FMiLxl{6HbYK$=L2nj*y^p%2c45{>&)X}aCOOG^r63ScYWK7 zdej6oucZ)C10V*$WFV52xNMl)8kh~Xia#qUWR{FXI6EH7YbOLquRgr~ol*?Pvhzq$ zMe=`|;I2=vI_!1fXIgah)+jMrIDCtK4XYCNKTW67`b{3ELvcR!Soz25WXv!%d(oMR zVq)|pdg z*Eh_}%+D8_xJU;j1MJ{iorSNm7Zc#?z30yllo7krTxt3~hu5Fdz0maVf;Vi&&Gn75w)!S9c_9ApfvbS zK2tWdl||vPl0`r0za3dU(lbA!=g?SPMlS+f#SVautz6$O8D#Yb z5FR${P;BoSnzP>{sNLpAV#Q{vAlw4Z=a%E;dFxx$tLKVz|5*$j-ow?PSI-VIr0u@T zf;_&jH*|8>3M6@Wl$pOMj8aBsJ%6|3iS@^k!uiW}ASh-t2jsTG9R^^n2tWAl0w zQS^B}P}c%J|7)-6`+dhB@Hlz;%HVF%VGcajy!n&{rZb+>wNoN{yos4c4;^y|~&vMS$ERc|ptS=MSVGn~D(TNRhoF~UXhU=`MCa8+Y zsDbZnQhf@cz=>Yqr@vMZFL>u&3y@Dyo0h{awMehDr&aK_@E#u?!qm*A{`0i7-9D9{ zjGMppF&Bf|GY5{O{{Ob>cj?dMZ5>;zmw?l#fb_@+3U)6-&MC+$vWD1$Oamb&Z0ktG zPu%j=THdTLgZRzhm-OCpxMw_OkHuWv;u_lD@8!p!=;(iMe>Kir`uD;O&acs(CXrQ}lcv%9 z1_Fw*&E6NyLZVApT;52qCi}GeHkXh{3?RERGm4cR$dxu%^ynt-ivC~NRQO*>@Oe}H zLh;!_$Ba>9&m9BJ<9+T8J^gwFaD8Ih=2R;3rGt?Dq$}$Mu0==X)W1a{3=oSS@LKK) zNxfg9;wTZ6=pOf&?IsBb{vAAMo8%C3VnOy0@eh7_EJlYQQn=*Wg$TX(v0)h!g^q#9 z`2V5eASIEf`+BnP0Rw12XOWM@Jeg10!7iUpj{29l51qCvNk(C|a1Kg^)Q@3M=nXS` zZ!a~qm?%VNb#;hei{dcyG1|;4lMEC>_q(zo|ATmkm|*r-%YvCKikKEBG}ld)Wg z&N{$w=1sORjSDL-DJU@ANgW=Z+;1yE@30=XhNsscve?d;Gpk^ZVv^p8?Xs|L2?fBc z$q{45L=br2oquALYaoWD;)hSPxQ70R-0|*~Y+r<%uk*hV{EKi~ggmQz%DX`{pS-ob zFzydvwSr6ZJieOz+dIs9}8g5#i#_)&A-DPwLgWoqzDetbKn8XSAd-v6;E~ zWVKIxXL}j^%L4(z`yO9x=wIM?&5L<=!)E>Wqdhe#V0a5nfWH3C)GMWXjNa-wD=(>wJftdeow{2IAdWWgpKqWSVEqXQ>z{*vr!FkfS9PTbC3+zW+q7Wxs+3veHEQHNX9(LsOy)bJR z0&g?e<*}q>=bvpGas4lKjhaoG$wLPBCRc{A6(#~{E9XWwhxeEB*yPFZuh$cy`1dk2 zaazg=g6+{=Dyt~(kuZJn;?^>EvW3vXEr=r}m`apxk6DI}2qmjv%7IIQ7i z-d#cp3iB>7Owg#+LjJe@W&-~gE*I}Lu@bD%Ua{BN(^<^~HVrC2P=%r+?>7ctMPE|vplt*--2eB)Qc*2jMX9%BU_!p zfIS~V+Mhy2nyHza>INZ$7TX$6WIRvoQQ7p1zyXWw3TftpQ4usaZUljlIA8-CLKsAP zJ!F%V$RigYxKdseDa3+Jpc-)8Ac1NBY?8I>qHt=Yg+&4s0#GFh1RzQiZ9w2o2GfE8 zD2CJkNFFg}WLOf+0m1t}rvUWiRDO;-Ujd`i+ij*4rqA`rB{*Q2Glkw`LPNG!=BSP(!-%ZEszAetp45R@QLK)WGGlL8@-;s+55AQ=#$ z!AMYwWYQ7_4PRh|FQ?-9^d>?eNTS#v9dHU05UZvdX;BJtaGQc|0m&^059G}7{4Ql6 zx}W3!(p(RZ>@cGA6d@oySMuw&g-rqy_p(vG8oLr)A>qWUTDIg(vzET@g` R3WxuTxgwk>NF>#X;{b|{O?vwn{XDqTQ_5IS_golf}Yr?*U|C=eRk^m+FOkax!%^hb0&_dinX0% zcW$C`o_mJ9da$kKZ*rDTdtQ1(p2ncj5D=L((+B{VnKEK&f*NX{fI@mtB|k<}(@dJ1 zM8J(UQ_~W934u=&38qaNX^D}hXo=~mwvp;IH8MX`@Ka(SQ0LMKpSkQ}m$IM%2&-fDHg>^%@3) z)Mx+z&}}AyX`>2n zB-2GaLFp4>PewGJg*H>ldOaqSX{q`s{UcM!G#U(y(duPAPg5~R>S?F}>Ul;8&|m-r zGepqZBPM7~4@r<^**(wyYjZm(%WMfi4cDt01E`8>{K3);>RoQEdd8<*;Oy`!s;8u- zNzHOl1w~K=GN(wpY;Cv~ukZUAx+iXa6IZBkPLb*!?byk>?)zJ`F|>tO|kVlzpIfI0pwZ9DntY%BKHho<|7!Ozgm1 zLmU1Fyzj=agpx?>b#NgRf(W3HTpy+h9hTnZyYPI20Q5=n4KIw5`x*{1-lldN{jSJU z?u7NXKL_5oBah&B9&fHq;||by_UxPv$E%g~vuV5M)N`%ZzvZWtmyPpj3Z&r_9a}VNd#&lDd8mw-eCkq^u4Ws@)f8M) zh(=^qr&6vg-&#{qb-c5##zfe4=KM!)>g)`u%2kVf*R8rLEu}Ncan46&=1VE{i9kYi zCV(e_jHZ{bO(ULkuU>Tynbocuo_dSWy%kd4k~>$gGTj!Rs+6fsdFQWDM0er`ZaHbL z7C$SSO}gCMQbM~`KK+)hqG3Kkwe=N-sM29XkxM6rN+_YUxk{#&po*FxRWDk%Jrch& zr=sp%Q&=Yii`+QcO(G&DLPR;CfUq5;)?PmZ*m5~}1&1OCva*%XS2cGF6(s}^y$6wS zctk{)@ZlkBV{n+L8d1<9JenZsQ8Pkm&4NitfH7sA13DlLt3lbci81%vNi9zI47m#F z#KTFvwvQmgeCd@OI{2~CaeMzwT*sHGoYf?4wi30Wc#?eNF$hrEgm_rz=KYorIc(-I zMK>vOhxXb^Ph1SsVS@P0JhqpU%Ukf&q&KFObQIsz{5m9UxM#MxipGi8hI@7_PEoO! zVb#g2v@x?jn!Qj=9;1?ITg~t!tSaK#`Z=Sp`B=CydLZ4Tw~qTY(k&LuY`%5Z%k{3C z$%)4ZxDvvO6dRs>ak#V4UZmEECoEq{v04qpM2V~fa1?Y_!G>tn7Htm=jWq#@`3_qtrOGB*M?Lh10>1ATNXJDtws)HWaC>*F){X3 zy%U1b(ArQchWg8#0z2!tRNxL33RLc=n255K45zTFMp9%r@wHu?W?0OY4%OI00rpuI z*Aqa%NU=IGi%Xtkb56cxq^Zv8l%|V!+BuBUDar+dhePXFaxmprq8B#>J4NiHwpfzF zYsBND+~qF6LB?j?;a)MdkxA6<7y>S+Wr)fw%ge=64x;jX)FzM3|y{s2qB<2O$j!wXd!{hBeF!oCp)W`O|jB;8MS0p3Q__tv26l2 zNDw~`10?8ou!2nIS`z+No{V7dU>i#n7h5Ga;jwwPix|8uZspK%TnyiE?uXZGsTLD-r(BmW2-it#kO~k$ZKiT;~SmkUwO>1?|Fm(&JAB0&H^k%1hJ z5&#_&_iKfqW-co8IWLC|VZQ20tdmLsNRvJK6ojZi z0g!4nwesGCccZ6w8+O~~`T5*0uPevwK=)nL#bRliWcU;Py=+wkg}1xJ<^D2-`O;)O z?B^SGTfHABh7#JJ@5PYw8_!a*3WHr#KLr5*L^%K$1Xv0L012H!2q4T-2N3T++7aAqaZ_7$ojNDlMz3DkK}us_r6SaUQe0g_#KQi43($rk?6zK z%1iFsM8<+afBQ$ZXgNoqZ%%vhXTGnOkuB?Jwo7wUJAQC}}RncBH4{jwJ zQ~MOV=#1*BC0t4f5|zmGgcdKHNA*7;OmqXYm~lA#r!u=m(WlQ&trk9B83bCGPW`T z0SJal&P1fN>m_NO+kRiB+t1zj*ZEkxn9iGmj6G{I-&3O-|E7?Nmonco5*kQ3uM_>{ zWs$}1{!Eg&m_t+{LSzy_Aix!#mpI6DD#TRUyb&WCzMNYnX_saMM1dr9Fpt30F9UHc1nj{OhN>_$|C&+Di!`Ap zSvwiG++T7mpoRx4ECf8IlD}VP9TR5Ns{WEhR8sM3Hk#*j?;R~69+TcZR3xXNu$sOe z=C&(1(3uzTLk}k>xXd9W0WX-ZW3k!n>!2>XSPfPODD{{)h#Z*pnt}s{xZ1m~8i|Oe zy=*tlwBy6Uw>C@%WwNh>%xrsmE|*)O0^2fWkPXl_I4a4N0<%J4Wg;bexV$}=x#Mmr zp0yIkCVGjG=q6EVf50$8Sc@O_R^*`?h+X;P{8!XA&3f));7Ct^2Y|C|`Lj3$=m=g5 za5A-989))x009FBR3a6WA>I&exa=LP&c!5;Os8L)5zn&F$l{-FXAz7s$Q{juELgFh z9h(p;Yyv3IX0lCVN>E8OiA*su5^|a_;6w;zwIev3;uD^?mHwIChi|0gKF*{4TTDc} zzKoWOzU08f+q??lj8xUZ-8nhJ=zgxMd`m|{c31Cr9 zo#C>H#%fLJWNEpn)!FMxii-~xUX(XmGyIM~G7e`1z_n3>r17Ki?S67)=qQ1OjRaFL) zjONlY;d}dCW?w${Lho5`g!Ldc-d5A)*wN9<0*)45sLqKCodkUIPAqjq#?OG|uwa~( zY66GQ@FWl|Ns$1dJN@}7B`hEp1PDl}ye#@D-!oNX1POu!Ulz_!6`q6Wef#dFMb=}n z(|>$YFNOF5!IjV?2MR{;wdsq@4znmvz!-Z--D^j5FLd#g zB`z8AX!T?vv?77gE+Ggwa-xMy`XMR+VME#KGs--+wQCLmGSGnm2#bvn4{V2)CRSnw zi%^XO+@C+u9IQOBvE@dvVX=$*e83QZz-AEW2$2j(Amp(js-T_${Le6Sw-l`p2OfS% zbo!(Q>oP)wIJwja2M|%P%oFCh1AlJ(-FbJP=ouRfWeNs;@ zmxm9U`+FPzO+kS6-Cu5MLo6G%-Nl2G=Xms#$i+3Z&xJ_Gl-f{5(2MNQCZzk;X^uH# zpu!&{2#F4KwKPcg44S>upbHBaLd{>zQLFg9nMPSNI4f)#lJ<@CwHh5Gry=@fhPG-1 zJQO0A1W9~vqkpXvY zAE{3dsa8r!yDl$Byr6~-wL|_cGwV!IvQi29!YUL59Hq>&%Kp1uH0{~~#c=jyhCy#4i+xMMxhH|FW zy`m0Q*&(84=zG4O1B!|O!%BxxCDD0^5^8CPZLguE*ll}{9e34md2Ys!e7t8tSK_)Z zp@sA;sj#C93lS{X0~jbk*p(KF*Fx}S(Kjc7X8hP2V=!|VNATTx3gLjpMjl_Zsfq~$k<*ZPKZcItv^2pBzhzp)p7PU+g`(Y)D1sAAI(cbPkoNa)MNo<|G5TJyG$bn0k+2z+Uf${O_WRu6 z_>jPlr6HAlhz5r$M^{ZHZKuv#5+Zpru2p#G;BZqksZdZJk#K_&P~a8dQAmSyaI4&r zlLj~0m0p<`lOBw7Jqs`;a=FSq6yOm?`Yvc$bHzv>k zN>G`h1rkE75bU`iON5LRQ6*10pb$2ijF9A_4V7s=pQq`#DI&fD)Y?-#fY~mYGLaFB za0@pcVd>nR4DE(1iK{U%9$rF^5-1SL+{lh#3a`IEY{1M+II`0+7hh$@s8vE%Of#`U zELngNdzH&DG!O(4(sSC*MsJ)KaEr03g~XMHWEu1d0@4zJIWUoQszX;WXevk}Oc;s? zC|Z;Ri5M9GXNO-TgjQ{h%a*ZlYc(xJygDRU)m$M2f=DEEziGfgA`rc!5=!J4mKjb+ zpi2-Y4>*FQphQWrF)9Hhgi;|J2~g2q6I`*;W(DpBmDx#7(1+HBzn8sFFO$;<)Z6as zn-Cc%R?Lx>mW$fSVgQg?X$90fo2uT0Y<{uuythkDHs-gJl2TGG-i6>OAYkL_WI?|d zjnod03kIq2IK{Y%#m@l_kig}T(<2Bh_4E!>l(_}R%94;na*G&wxMXeSQLQdIeHwl_75OiI=ZQnZAk5w#IfaBtSWT3=(aQq#iQ@0Uf8|@6wEUc#tty zLN?5}8>vV`=-m&?EFiu7Jl@7I09JGGzB9`(;JcMqlo{!(+BVR^gu-RqYt1TN z@3mlIQ#Jm3cmg+@fZb@MBb8_v$4RFs@=?}x{3Fp5EMS$Ai#46nzC}c;A_#%Qa2vWo zF%ZN!n2dAn?G^6o5I>6=9L|LZ5D~?yh&MX?2Hwk$u2q4Nqd4mrMHsY)TH*}=X+73i zWld8HoLwsTwdP37-1#ipNOzi^qr6}wZyOJhAnh_7fO!y+yufHg9jIhz4M>nwOl*{t zq^F!qi72$8Cj?u&3?WI?e8X6C5T?xLyDO5rFqcUWTy%eAZQF>RviSQoN z8ii%6Ava2*1Py8zDr4&i%S86jL7LmngonDC6j)D11m#>70s~&AtXZZSXN4G9xm6Pi zlTL`Jf^tbn$z3#VD`p4G*hz+VptzI^E}?;G*UDk=F5NiP2n)Fq320d|H1gyb)T-tt zFf4LOnFGnU(}AIjMpCGbL!r=?)xjksTW^6x$g8O&3C_;vL5hFB~j@D}{3K)Sn zASYBtGg8f;+K!D>fIl!e6k7({T24>qTVY%bixFN~osIx03@&_)yQPm&t-gBE*+NQl zfeLRskg9Vfo7qlHbgZTEtf1HJ^2GDl#g7z`RfVMY9OpKLC7SFsn|b(F+gOH;T^u{B ziyo&_EDLj_71OPTrjgJEj?AxbP8780PbIWDK!CuD0Bu&EL!&D6lV@z2padkr3XDvM zOkS)xh%4qeQ4TWm+stXI-6Tl#CG$D(v4F-|U&>J3md zK|E9Di*yChQXyG!W>mw~o&#njx7|4fpGi=i4t4(i^F*dnM>*xY{pnUpg`xRftdNDn z>-^?9no$U`h_%V2hS3@&jTjJfJ1w7QpdKbGuB;Y1FpL3$gx5&5_)dhDOZiKhCrunr zQ@8GTKdVuIZx_~%qpj|$ncOwero1=*PVG2EGfmhpLj>e{I-yKwcfEsV`a{@!19IHo zahn)yHr|H^FmpFa32+(%vtnBfzO10;1HeA&eP-96Dv%szXK>4p-5UC6#JC1C|M}xs9Un5OUNG0f71Bt=aF8X%pWeVR~wcYy|^lV|? z(bFtVWf8ztz|qyMj&d2H1QFD&j+9jctXXQ1t|!YsiyDXp_3ed6=os8bO97xY zi-=gZrvTrCFS7l8^%Gwi;zouK8i1}|dKwux5f+$zQh3jG4)C#c#(R;o)>AW8mN4k5 zCzrOdPCV?^L<$GSk9{RhL>$#Xd%hd6)(lfLn#>~YS+_7jP~ZS#;Dw}sElKm-_cM)i zhRt>Sn+vY~`b1U$wAV)CG zlVrjesXOB5ap)v;a+#NgBM^iImCKaHO9KyW5TsVGu$3|)=Vv_`q)7~81T^ZLhS=1A zZM19lYTP13ty31c(xXlJN{zlNzaSN!^niJ@^8ID#s z;bt?Ci5d$~&9>(-+8Vpsz!EjLk?xEuLxaAz7gwnmvBJ!~OrT;LDPl{rxw|Sz{cNu6IU@jyiVRzrZMMO5Z3sk_dIvsI(4?qjXhH!3 zkZqgG9(9>@F5s%FO(0Vm?V9kRVQ!MqsI-n#Dz(NzdnN+~cz}!|fdXKTMhsK4=aMbv zYp33R^+)YjjOq_o%4VANrYMwygV@<6n6qlEK+0#qp49;$@9k+C2d44)^L*1l8-i|o zt~!Mlch`5i&$(D2FLuu{>YgzZ=6Y!toBfAA$E(4q11`y6ml$5 zk~OGSTSO&&26-lNFpvaEK_tMX(GY~tt1NLA3bv$T(`JRJ^+|7|S2$@?lz@@MG#MP2 zlsPR2dNFFI1qtyo657Z@jHV^Nmu#ehk_{EVrXVKS{=5hhpfxuPFIdc!BpTY!%SwAB zT@w_y4w;BUm*sMZ1CAgNN?4i8&j>&veTp70&2ZJObL#!c&$p&YWd_t&Sfd#nig+8> z4FEqq0JLVup^T;-6!!*hl{--9^0g*xy_b(>N`4_4L=Y$#&f5AEDOKEa_fHcIm2;nF zC2r@C5he`tgapsa=Jw8EP}Kz0eh3dw$=lR8%-?S`eY$J|lRpw&5dI`4PW_+fMaPK{ zcCdhe1WFkI;YZ+^o0k?CJSyAeetsLq6g#DjsQOSg_qRs?oqyV`}UD z^!ym3h-DpEYRa?z-oXr`OqJppW0GHrNszfPcA3L*CACXo88ze7rIVlE*HtaEUD80N z-RihBfW?5dJ@|3hGJ$4mkAbea%G3o^GsqwW1eK26LpgR=JdK*N>LF7Ks+Z*+%ryTu zUP}F(>!Y!Z0Tps-;{V@+DLau^=KPt5tWw7NCV!U@m!7a^)(hc zG%;4__K*Zh6%bE8hy)5yAxVqmL`J8B(DeNASG&d+hf|6{eTSc}TNT$OrRD=%KIWTQD zjRf+EV_!S2uJyO81=0mZGqjjyJ9~%{RiIq`@-=|4ilHu@flCPF64@Ep&<-F F6u1ked`|!X literal 0 HcmV?d00001 diff --git a/tests/update1.c b/tests/update1.c new file mode 100644 index 00000000..cf2d625c --- /dev/null +++ b/tests/update1.c @@ -0,0 +1,120 @@ +/* Test program for elf_update function. + Copyright (C) 2000, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + + +int +main (int argc, char *argv[] __attribute__ ((unused))) +{ + const char *fname = "xxx"; + int fd; + Elf *elf; + Elf32_Ehdr *ehdr; + int i; + + fd = open (fname, O_RDWR | O_CREAT | O_TRUNC, 0666); + if (fd == -1) + { + printf ("cannot open `%s': %s\n", fname, strerror (errno)); + exit (1); + } + + elf_version (EV_CURRENT); + + elf = elf_begin (fd, ELF_C_WRITE, NULL); + if (elf == NULL) + { + printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* Create an ELF header. */ + ehdr = elf32_newehdr (elf); + if (ehdr == NULL) + { + printf ("cannot create ELF header: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* Print the ELF header values. */ + if (argc > 1) + { + for (i = 0; i < EI_NIDENT; ++i) + printf (" %02x", ehdr->e_ident[i]); + printf ("\ +\ntype = %hu\nmachine = %hu\nversion = %u\nentry = %u\nphoff = %u\n" + "shoff = %u\nflags = %u\nehsize = %hu\nphentsize = %hu\n" + "phnum = %hu\nshentsize = %hu\nshnum = %hu\nshstrndx = %hu\n", + ehdr->e_type, ehdr->e_machine, ehdr->e_version, ehdr->e_entry, + ehdr->e_phoff, ehdr->e_shoff, ehdr->e_flags, ehdr->e_ehsize, + ehdr->e_phentsize, ehdr->e_phnum, ehdr->e_shentsize, + ehdr->e_shnum, ehdr->e_shstrndx); + } + + ehdr->e_ident[0] = 42; + ehdr->e_ident[4] = 1; + ehdr->e_ident[5] = 1; + ehdr->e_ident[6] = 2; + ehdr->e_ident[9] = 2; + ehdr->e_version = 1; + ehdr->e_ehsize = 1; + + /* Write out the file. */ + if (elf_update (elf, ELF_C_WRITE) < 0) + { + printf ("failure in elf_update: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* Create an ELF header. */ + ehdr = elf32_newehdr (elf); + if (ehdr == NULL) + { + printf ("cannot create ELF header: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* Print the ELF header values. */ + if (argc > 1) + { + for (i = 0; i < EI_NIDENT; ++i) + printf (" %02x", ehdr->e_ident[i]); + printf ("\ +\ntype = %hu\nmachine = %hu\nversion = %u\nentry = %u\nphoff = %u\n" + "shoff = %u\nflags = %u\nehsize = %hu\nphentsize = %hu\n" + "phnum = %hu\nshentsize = %hu\nshnum = %hu\nshstrndx = %hu\n", + ehdr->e_type, ehdr->e_machine, ehdr->e_version, ehdr->e_entry, + ehdr->e_phoff, ehdr->e_shoff, ehdr->e_flags, ehdr->e_ehsize, + ehdr->e_phentsize, ehdr->e_phnum, ehdr->e_shentsize, + ehdr->e_shnum, ehdr->e_shstrndx); + } + + if (elf_end (elf) != 0) + { + printf ("failure in elf_end: %s\n", elf_errmsg (-1)); + exit (1); + } + + return 0; +} diff --git a/tests/update2.c b/tests/update2.c new file mode 100644 index 00000000..743bfd21 --- /dev/null +++ b/tests/update2.c @@ -0,0 +1,143 @@ +/* Test program for elf_update function. + Copyright (C) 2000, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + + +int +main (int argc, char *argv[] __attribute__ ((unused))) +{ + const char *fname = "xxx"; + int fd; + Elf *elf; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + int i; + + fd = open (fname, O_RDWR | O_CREAT | O_TRUNC, 0666); + if (fd == -1) + { + printf ("cannot open `%s': %s\n", fname, strerror (errno)); + exit (1); + } + + elf_version (EV_CURRENT); + + elf = elf_begin (fd, ELF_C_WRITE, NULL); + if (elf == NULL) + { + printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* Create an ELF header. */ + ehdr = elf32_newehdr (elf); + if (ehdr == NULL) + { + printf ("cannot create ELF header: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* Print the ELF header values. */ + if (argc > 1) + { + for (i = 0; i < EI_NIDENT; ++i) + printf (" %02x", ehdr->e_ident[i]); + printf ("\ +\ntype = %hu\nmachine = %hu\nversion = %u\nentry = %u\nphoff = %u\n" + "shoff = %u\nflags = %u\nehsize = %hu\nphentsize = %hu\n" + "phnum = %hu\nshentsize = %hu\nshnum = %hu\nshstrndx = %hu\n", + ehdr->e_type, ehdr->e_machine, ehdr->e_version, ehdr->e_entry, + ehdr->e_phoff, ehdr->e_shoff, ehdr->e_flags, ehdr->e_ehsize, + ehdr->e_phentsize, ehdr->e_phnum, ehdr->e_shentsize, + ehdr->e_shnum, ehdr->e_shstrndx); + } + + ehdr->e_ident[0] = 42; + ehdr->e_ident[4] = 1; + ehdr->e_ident[5] = 1; + ehdr->e_ident[6] = 2; + ehdr->e_type = ET_EXEC; + ehdr->e_version = 1; + ehdr->e_ehsize = 1; + elf_flagehdr (elf, ELF_C_SET, ELF_F_DIRTY); + + /* Create the program header. */ + phdr = elf32_newphdr (elf, 1); + if (phdr == NULL) + { + printf ("cannot create program header: %s\n", elf_errmsg (-1)); + exit (1); + } + + phdr[0].p_type = PT_PHDR; + elf_flagphdr (elf, ELF_C_SET, ELF_F_DIRTY); + + /* Let the library compute the internal structure information. */ + if (elf_update (elf, ELF_C_NULL) < 0) + { + printf ("failure in elf_update(NULL): %s\n", elf_errmsg (-1)); + exit (1); + } + + ehdr = elf32_getehdr (elf); + + phdr[0].p_offset = ehdr->e_phoff; + phdr[0].p_offset = ehdr->e_phoff; + phdr[0].p_vaddr = ehdr->e_phoff; + phdr[0].p_paddr = ehdr->e_phoff; + phdr[0].p_flags = PF_R | PF_X; + phdr[0].p_filesz = ehdr->e_phnum * elf32_fsize (ELF_T_PHDR, 1, EV_CURRENT); + phdr[0].p_memsz = ehdr->e_phnum * elf32_fsize (ELF_T_PHDR, 1, EV_CURRENT); + phdr[0].p_align = sizeof (Elf32_Word); + + /* Write out the file. */ + if (elf_update (elf, ELF_C_WRITE) < 0) + { + printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1)); + exit (1); + } + + /* Print the ELF header values. */ + if (argc > 1) + { + for (i = 0; i < EI_NIDENT; ++i) + printf (" %02x", ehdr->e_ident[i]); + printf ("\ +\ntype = %hu\nmachine = %hu\nversion = %u\nentry = %u\nphoff = %u\n" + "shoff = %u\nflags = %u\nehsize = %hu\nphentsize = %hu\n" + "phnum = %hu\nshentsize = %hu\nshnum = %hu\nshstrndx = %hu\n", + ehdr->e_type, ehdr->e_machine, ehdr->e_version, ehdr->e_entry, + ehdr->e_phoff, ehdr->e_shoff, ehdr->e_flags, ehdr->e_ehsize, + ehdr->e_phentsize, ehdr->e_phnum, ehdr->e_shentsize, + ehdr->e_shnum, ehdr->e_shstrndx); + } + + if (elf_end (elf) != 0) + { + printf ("failure in elf_end: %s\n", elf_errmsg (-1)); + exit (1); + } + + return 0; +} diff --git a/tests/update3.c b/tests/update3.c new file mode 100644 index 00000000..160adf1e --- /dev/null +++ b/tests/update3.c @@ -0,0 +1,198 @@ +/* Test program for elf_update function. + Copyright (C) 2000, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include + + +int +main (int argc, char *argv[] __attribute__ ((unused))) +{ + const char *fname = "xxx"; + int fd; + Elf *elf; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + Elf_Scn *scn; + Elf32_Shdr *shdr; + Elf_Data *data; + struct Ebl_Strtab *shst; + struct Ebl_Strent *shstrtabse; + int i; + + fd = open (fname, O_RDWR | O_CREAT | O_TRUNC, 0666); + if (fd == -1) + { + printf ("cannot open `%s': %s\n", fname, strerror (errno)); + exit (1); + } + + elf_version (EV_CURRENT); + + elf_fill (0x42); + + elf = elf_begin (fd, ELF_C_WRITE, NULL); + if (elf == NULL) + { + printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* Create an ELF header. */ + ehdr = elf32_newehdr (elf); + if (ehdr == NULL) + { + printf ("cannot create ELF header: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* Print the ELF header values. */ + if (argc > 1) + { + for (i = 0; i < EI_NIDENT; ++i) + printf (" %02x", ehdr->e_ident[i]); + printf ("\ +\ntype = %hu\nmachine = %hu\nversion = %u\nentry = %u\nphoff = %u\n" + "shoff = %u\nflags = %u\nehsize = %hu\nphentsize = %hu\n" + "phnum = %hu\nshentsize = %hu\nshnum = %hu\nshstrndx = %hu\n", + ehdr->e_type, ehdr->e_machine, ehdr->e_version, ehdr->e_entry, + ehdr->e_phoff, ehdr->e_shoff, ehdr->e_flags, ehdr->e_ehsize, + ehdr->e_phentsize, ehdr->e_phnum, ehdr->e_shentsize, + ehdr->e_shnum, ehdr->e_shstrndx); + } + + ehdr->e_ident[0] = 42; + ehdr->e_ident[4] = 1; + ehdr->e_ident[5] = 1; + ehdr->e_ident[6] = 2; + ehdr->e_type = ET_EXEC; + ehdr->e_version = 1; + ehdr->e_ehsize = 1; + elf_flagehdr (elf, ELF_C_SET, ELF_F_DIRTY); + + /* Create the program header. */ + phdr = elf32_newphdr (elf, 1); + if (phdr == NULL) + { + printf ("cannot create program header: %s\n", elf_errmsg (-1)); + exit (1); + } + + phdr[0].p_type = PT_PHDR; + elf_flagphdr (elf, ELF_C_SET, ELF_F_DIRTY); + + shst = ebl_strtabinit (true); + + scn = elf_newscn (elf); + if (scn == NULL) + { + printf ("cannot create SHSTRTAB section: %s\n", elf_errmsg (-1)); + exit (1); + } + shdr = elf32_getshdr (scn); + if (shdr == NULL) + { + printf ("cannot get header for SHSTRTAB section: %s\n", elf_errmsg (-1)); + exit (1); + } + + shstrtabse = ebl_strtabadd (shst, ".shstrtab", 0); + + shdr->sh_type = SHT_STRTAB; + shdr->sh_flags = 0; + shdr->sh_addr = 0; + shdr->sh_link = SHN_UNDEF; + shdr->sh_info = SHN_UNDEF; + shdr->sh_addralign = 1; + shdr->sh_entsize = 0; + + /* We have to store the section index in the ELF header. */ + ehdr->e_shstrndx = elf_ndxscn (scn); + + data = elf_newdata (scn); + if (data == NULL) + { + printf ("cannot create data SHSTRTAB section: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* No more sections, finalize the section header string table. */ + ebl_strtabfinalize (shst, data); + + shdr->sh_name = ebl_strtaboffset (shstrtabse); + + /* Let the library compute the internal structure information. */ + if (elf_update (elf, ELF_C_NULL) < 0) + { + printf ("failure in elf_update(NULL): %s\n", elf_errmsg (-1)); + exit (1); + } + + ehdr = elf32_getehdr (elf); + + phdr[0].p_offset = ehdr->e_phoff; + phdr[0].p_offset = ehdr->e_phoff; + phdr[0].p_vaddr = ehdr->e_phoff; + phdr[0].p_paddr = ehdr->e_phoff; + phdr[0].p_flags = PF_R | PF_X; + phdr[0].p_filesz = ehdr->e_phnum * elf32_fsize (ELF_T_PHDR, 1, EV_CURRENT); + phdr[0].p_memsz = ehdr->e_phnum * elf32_fsize (ELF_T_PHDR, 1, EV_CURRENT); + phdr[0].p_align = sizeof (Elf32_Word); + + /* Write out the file. */ + if (elf_update (elf, ELF_C_WRITE) < 0) + { + printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1)); + exit (1); + } + + /* We don't need the string table anymore. */ + ebl_strtabfree (shst); + + /* And the data allocated in the .shstrtab section. */ + free (data->d_buf); + + /* Print the ELF header values. */ + if (argc > 1) + { + for (i = 0; i < EI_NIDENT; ++i) + printf (" %02x", ehdr->e_ident[i]); + printf ("\ +\ntype = %hu\nmachine = %hu\nversion = %u\nentry = %u\nphoff = %u\n" + "shoff = %u\nflags = %u\nehsize = %hu\nphentsize = %hu\n" + "phnum = %hu\nshentsize = %hu\nshnum = %hu\nshstrndx = %hu\n", + ehdr->e_type, ehdr->e_machine, ehdr->e_version, ehdr->e_entry, + ehdr->e_phoff, ehdr->e_shoff, ehdr->e_flags, ehdr->e_ehsize, + ehdr->e_phentsize, ehdr->e_phnum, ehdr->e_shentsize, + ehdr->e_shnum, ehdr->e_shstrndx); + } + + if (elf_end (elf) != 0) + { + printf ("failure in elf_end: %s\n", elf_errmsg (-1)); + exit (1); + } + + return 0; +} diff --git a/tests/update4.c b/tests/update4.c new file mode 100644 index 00000000..30f3a07d --- /dev/null +++ b/tests/update4.c @@ -0,0 +1,353 @@ +/* Test program for elf_update function. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper , 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + + +int +main (int argc, char *argv[] __attribute__ ((unused))) +{ + const char fname[] = "xxx"; + int fd; + Elf *elf; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + Elf_Scn *scn; + Elf32_Shdr *shdr; + Elf_Data *data; + struct Ebl_Strtab *shst; + struct Ebl_Strent *firstse; + struct Ebl_Strent *secondse; + struct Ebl_Strent *thirdse; + struct Ebl_Strent *fourthse; + struct Ebl_Strent *shstrtabse; + int i; + + fd = open (fname, O_RDWR | O_CREAT | O_TRUNC, 0666); + if (fd == -1) + { + printf ("cannot open `%s': %s\n", fname, strerror (errno)); + exit (1); + } + + elf_version (EV_CURRENT); + + elf_fill (0x42); + + elf = elf_begin (fd, ELF_C_WRITE, NULL); + if (elf == NULL) + { + printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* Create an ELF header. */ + ehdr = elf32_newehdr (elf); + if (ehdr == NULL) + { + printf ("cannot create ELF header: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* Print the ELF header values. */ + if (argc > 1) + { + for (i = 0; i < EI_NIDENT; ++i) + printf (" %02x", ehdr->e_ident[i]); + printf ("\ +\ntype = %hu\nmachine = %hu\nversion = %u\nentry = %u\nphoff = %u\n" + "shoff = %u\nflags = %u\nehsize = %hu\nphentsize = %hu\n" + "phnum = %hu\nshentsize = %hu\nshnum = %hu\nshstrndx = %hu\n", + ehdr->e_type, ehdr->e_machine, ehdr->e_version, ehdr->e_entry, + ehdr->e_phoff, ehdr->e_shoff, ehdr->e_flags, ehdr->e_ehsize, + ehdr->e_phentsize, ehdr->e_phnum, ehdr->e_shentsize, + ehdr->e_shnum, ehdr->e_shstrndx); + } + + ehdr->e_ident[0] = 42; + ehdr->e_ident[4] = 1; + ehdr->e_ident[5] = 1; + ehdr->e_ident[6] = 2; + ehdr->e_type = ET_EXEC; + ehdr->e_version = 1; + ehdr->e_ehsize = 1; + elf_flagehdr (elf, ELF_C_SET, ELF_F_DIRTY); + + /* Create the program header. */ + phdr = elf32_newphdr (elf, 1); + if (phdr == NULL) + { + printf ("cannot create program header: %s\n", elf_errmsg (-1)); + exit (1); + } + + phdr[0].p_type = PT_PHDR; + elf_flagphdr (elf, ELF_C_SET, ELF_F_DIRTY); + + shst = ebl_strtabinit (true); + + scn = elf_newscn (elf); + if (scn == NULL) + { + printf ("cannot create first section: %s\n", elf_errmsg (-1)); + exit (1); + } + shdr = elf32_getshdr (scn); + if (shdr == NULL) + { + printf ("cannot get header for first section: %s\n", elf_errmsg (-1)); + exit (1); + } + + firstse = ebl_strtabadd (shst, ".first", 0); + + shdr->sh_type = SHT_PROGBITS; + shdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR; + shdr->sh_addr = 0; + shdr->sh_link = 0; + shdr->sh_info = 0; + shdr->sh_entsize = 1; + + data = elf_newdata (scn); + if (data == NULL) + { + printf ("cannot create data first section: %s\n", elf_errmsg (-1)); + exit (1); + } + + data->d_buf = "hello"; + data->d_type = ELF_T_BYTE; + data->d_version = EV_CURRENT; + data->d_size = 5; + data->d_align = 16; + + + scn = elf_newscn (elf); + if (scn == NULL) + { + printf ("cannot create second section: %s\n", elf_errmsg (-1)); + exit (1); + } + shdr = elf32_getshdr (scn); + if (shdr == NULL) + { + printf ("cannot get header for second section: %s\n", elf_errmsg (-1)); + exit (1); + } + + secondse = ebl_strtabadd (shst, ".second", 0); + + shdr->sh_type = SHT_PROGBITS; + shdr->sh_flags = SHF_ALLOC | SHF_WRITE; + shdr->sh_addr = 0; + shdr->sh_link = 0; + shdr->sh_info = 0; + shdr->sh_entsize = 1; + + data = elf_newdata (scn); + if (data == NULL) + { + printf ("cannot create data second section: %s\n", elf_errmsg (-1)); + exit (1); + } + + data->d_buf = "world"; + data->d_type = ELF_T_BYTE; + data->d_version = EV_CURRENT; + data->d_size = 5; + data->d_align = 16; + + + scn = elf_newscn (elf); + if (scn == NULL) + { + printf ("cannot create third section: %s\n", elf_errmsg (-1)); + exit (1); + } + shdr = elf32_getshdr (scn); + if (shdr == NULL) + { + printf ("cannot get header for third section: %s\n", elf_errmsg (-1)); + exit (1); + } + + thirdse = ebl_strtabadd (shst, ".third", 0); + + shdr->sh_type = SHT_PROGBITS; + shdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR; + shdr->sh_addr = 0; + shdr->sh_link = 0; + shdr->sh_info = 0; + shdr->sh_entsize = 1; + + data = elf_newdata (scn); + if (data == NULL) + { + printf ("cannot create data third section: %s\n", elf_errmsg (-1)); + exit (1); + } + + data->d_buf = "!!!!!"; + data->d_type = ELF_T_BYTE; + data->d_version = EV_CURRENT; + data->d_size = 5; + data->d_align = 16; + + + scn = elf_newscn (elf); + if (scn == NULL) + { + printf ("cannot create fourth section: %s\n", elf_errmsg (-1)); + exit (1); + } + shdr = elf32_getshdr (scn); + if (shdr == NULL) + { + printf ("cannot get header for fourth section: %s\n", elf_errmsg (-1)); + exit (1); + } + + fourthse = ebl_strtabadd (shst, ".fourth", 0); + + shdr->sh_type = SHT_NOBITS; + shdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR; + shdr->sh_addr = 0; + shdr->sh_link = 0; + shdr->sh_info = 0; + shdr->sh_entsize = 1; + shdr->sh_size = 100; + + data = elf_newdata (scn); + if (data == NULL) + { + printf ("cannot create data fourth section: %s\n", elf_errmsg (-1)); + exit (1); + } + + data->d_buf = NULL; + data->d_type = ELF_T_BYTE; + data->d_version = EV_CURRENT; + data->d_size = 100; + data->d_align = 16; + + + scn = elf_newscn (elf); + if (scn == NULL) + { + printf ("cannot create SHSTRTAB section: %s\n", elf_errmsg (-1)); + exit (1); + } + shdr = elf32_getshdr (scn); + if (shdr == NULL) + { + printf ("cannot get header for SHSTRTAB section: %s\n", elf_errmsg (-1)); + exit (1); + } + + shstrtabse = ebl_strtabadd (shst, ".shstrtab", 0); + + shdr->sh_type = SHT_STRTAB; + shdr->sh_flags = 0; + shdr->sh_addr = 0; + shdr->sh_link = SHN_UNDEF; + shdr->sh_info = SHN_UNDEF; + shdr->sh_entsize = 1; + + /* We have to store the section index in the ELF header. */ + ehdr->e_shstrndx = elf_ndxscn (scn); + + data = elf_newdata (scn); + if (data == NULL) + { + printf ("cannot create data SHSTRTAB section: %s\n", elf_errmsg (-1)); + exit (1); + } + + /* No more sections, finalize the section header string table. */ + ebl_strtabfinalize (shst, data); + + elf32_getshdr (elf_getscn (elf, 1))->sh_name = ebl_strtaboffset (firstse); + elf32_getshdr (elf_getscn (elf, 2))->sh_name = ebl_strtaboffset (secondse); + elf32_getshdr (elf_getscn (elf, 3))->sh_name = ebl_strtaboffset (thirdse); + elf32_getshdr (elf_getscn (elf, 4))->sh_name = ebl_strtaboffset (fourthse); + shdr->sh_name = ebl_strtaboffset (shstrtabse); + + /* Let the library compute the internal structure information. */ + if (elf_update (elf, ELF_C_NULL) < 0) + { + printf ("failure in elf_update(NULL): %s\n", elf_errmsg (-1)); + exit (1); + } + + ehdr = elf32_getehdr (elf); + + phdr[0].p_offset = ehdr->e_phoff; + phdr[0].p_offset = ehdr->e_phoff; + phdr[0].p_vaddr = ehdr->e_phoff; + phdr[0].p_paddr = ehdr->e_phoff; + phdr[0].p_flags = PF_R | PF_X; + phdr[0].p_filesz = ehdr->e_phnum * elf32_fsize (ELF_T_PHDR, 1, EV_CURRENT); + phdr[0].p_memsz = ehdr->e_phnum * elf32_fsize (ELF_T_PHDR, 1, EV_CURRENT); + phdr[0].p_align = sizeof (Elf32_Word); + + /* Write out the file. */ + if (elf_update (elf, ELF_C_WRITE) < 0) + { + printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1)); + exit (1); + } + + /* We don't need the string table anymore. */ + ebl_strtabfree (shst); + + /* And the data allocated in the .shstrtab section. */ + free (data->d_buf); + + /* Print the ELF header values. */ + if (argc > 1) + { + for (i = 0; i < EI_NIDENT; ++i) + printf (" %02x", ehdr->e_ident[i]); + printf ("\ +\ntype = %hu\nmachine = %hu\nversion = %u\nentry = %u\nphoff = %u\n" + "shoff = %u\nflags = %u\nehsize = %hu\nphentsize = %hu\n" + "phnum = %hu\nshentsize = %hu\nshnum = %hu\nshstrndx = %hu\n", + ehdr->e_type, ehdr->e_machine, ehdr->e_version, ehdr->e_entry, + ehdr->e_phoff, ehdr->e_shoff, ehdr->e_flags, ehdr->e_ehsize, + ehdr->e_phentsize, ehdr->e_phnum, ehdr->e_shentsize, + ehdr->e_shnum, ehdr->e_shstrndx); + } + + if (elf_end (elf) != 0) + { + printf ("failure in elf_end: %s\n", elf_errmsg (-1)); + exit (1); + } + + unlink (fname); + + return 0; +}