Mercurial > illumos > illumos-gate
changeset 13872:20563857eb2d
3265 link-editor builds bogus .eh_frame_hdr on ia32
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Reviewed by: Gordon Ross <gwr@nexenta.com>
Approved by: Garrett D'Amore <garrett@damore.org>
author | Richard Lowe <richlowe@richlowe.net> |
---|---|
date | Mon, 08 Oct 2012 03:37:11 +0100 |
parents | a9c12c2c1647 |
children | 89c188fb29f6 |
files | usr/src/cmd/sgs/elfdump/common/_elfdump.h usr/src/cmd/sgs/elfdump/common/dwarf.c usr/src/cmd/sgs/elfdump/common/elfdump.c usr/src/cmd/sgs/include/dwarf.h usr/src/cmd/sgs/libld/common/unwind.c usr/src/cmd/sgs/packages/common/SUNWonld-README usr/src/cmd/sgs/tools/common/leb128.c |
diffstat | 7 files changed, 71 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/cmd/sgs/elfdump/common/_elfdump.h Fri Sep 07 17:29:12 2012 -0700 +++ b/usr/src/cmd/sgs/elfdump/common/_elfdump.h Mon Oct 08 03:37:11 2012 +0100 @@ -224,7 +224,7 @@ extern corenote_ret_t corenote(Half, int, Word, const char *, Word); extern void dump_eh_frame(uchar_t *, size_t, uint64_t, Half e_machine, - uchar_t *e_ident); + uchar_t *e_ident, uint64_t gotaddr); extern void dump_hex_bytes(const void *, size_t, int, int, int); extern int fake_shdr_cache32(const char *, int, Elf *, Elf32_Ehdr *,
--- a/usr/src/cmd/sgs/elfdump/common/dwarf.c Fri Sep 07 17:29:12 2012 -0700 +++ b/usr/src/cmd/sgs/elfdump/common/dwarf.c Mon Oct 08 03:37:11 2012 +0100 @@ -49,6 +49,7 @@ uint64_t ciecalign; /* CIE code align factor */ int64_t ciedalign; /* CIE data align factor */ uint64_t fdeinitloc; /* FDE initial location */ + uint64_t gotaddr; /* Address of the GOT */ } dump_cfi_state_t; @@ -301,8 +302,8 @@ case 0x01: /* v2: DW_CFA_set_loc, address */ cur_pc = dwarf_ehe_extract(&data[off], ndx, - state->cieRflag, state->e_ident, - state->sh_addr, off + *ndx); + state->cieRflag, state->e_ident, B_FALSE, + state->sh_addr, off + *ndx, state->gotaddr); dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX, EC_XWORD(cur_pc)); break; @@ -465,7 +466,7 @@ void dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr, - Half e_machine, uchar_t *e_ident) + Half e_machine, uchar_t *e_ident, uint64_t gotaddr) { Conv_dwarf_ehe_buf_t dwarf_ehe_buf; dump_cfi_state_t cfi_state; @@ -479,6 +480,7 @@ cfi_state.e_ident = e_ident; cfi_state.sh_addr = sh_addr; cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA]; + cfi_state.gotaddr = gotaddr; off = 0; while (off < datasize) { @@ -568,8 +570,8 @@ ndx += 1; persVal = dwarf_ehe_extract(&data[off], - &ndx, ciePflag, e_ident, - sh_addr, off + ndx); + &ndx, ciePflag, e_ident, B_FALSE, + sh_addr, off + ndx, gotaddr); dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXPERS)); dbg_print(0, @@ -633,11 +635,11 @@ fdelength, fdecieptr); cfi_state.fdeinitloc = dwarf_ehe_extract(&data[off], - &ndx, cfi_state.cieRflag, e_ident, - sh_addr, off + ndx); + &ndx, cfi_state.cieRflag, e_ident, B_FALSE, + sh_addr, off + ndx, gotaddr); fdeaddrrange = dwarf_ehe_extract(&data[off], &ndx, (cfi_state.cieRflag & ~DW_EH_PE_pcrel), - e_ident, sh_addr, off + ndx); + e_ident, B_FALSE, sh_addr, off + ndx, gotaddr); dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC), EC_XWORD(cfi_state.fdeinitloc), @@ -660,7 +662,8 @@ lsda = dwarf_ehe_extract(&data[off], &lndx, cieLflag, e_ident, - sh_addr, off + lndx); + B_FALSE, sh_addr, off + lndx, + gotaddr); dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXLSDA), EC_XWORD(lsda));
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.c Fri Sep 07 17:29:12 2012 -0700 +++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c Mon Oct 08 03:37:11 2012 +0100 @@ -521,6 +521,7 @@ * entry: * cache - Cache of all section headers * shndx - Index of .eh_frame or .eh_frame_hdr section to be displayed + * shnum - Total number of sections which exist * uphdr - NULL, or unwind program header associated with * the .eh_frame_hdr section. * ehdr - ELF header for file @@ -532,7 +533,7 @@ * flags - Command line option flags */ static void -unwind_eh_frame(Cache *cache, Word shndx, Phdr *uphdr, Ehdr *ehdr, +unwind_eh_frame(Cache *cache, Word shndx, Word shnum, Phdr *uphdr, Ehdr *ehdr, gnu_eh_state_t *eh_state, uchar_t osabi, const char *file, uint_t flags) { #if defined(_ELF64) @@ -551,7 +552,16 @@ uint64_t ndx, frame_ptr, fde_cnt, tabndx; uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc; uint64_t initloc, initloc0; - + uint64_t gotaddr = 0; + int cnt; + + for (cnt = 1; cnt < shnum; cnt++) { + if (strncmp(cache[cnt].c_name, MSG_ORIG(MSG_ELF_GOT), + MSG_ELF_GOT_SIZE) == 0) { + gotaddr = cache[cnt].c_shdr->sh_addr; + break; + } + } /* * Is this a .eh_frame_hdr? @@ -578,7 +588,7 @@ dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers); frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc, - ehdr->e_ident, shdr->sh_addr, ndx); + ehdr->e_ident, B_TRUE, shdr->sh_addr, ndx, gotaddr); if (eh_state->hdr_cnt == 1) { eh_state->hdr_ndx = shndx; eh_state->frame_ptr = frame_ptr; @@ -589,7 +599,7 @@ EC_XWORD(frame_ptr)); fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc, - ehdr->e_ident, shdr->sh_addr, ndx); + ehdr->e_ident, B_TRUE, shdr->sh_addr, ndx, gotaddr); dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC), conv_dwarf_ehe(fde_cnt_enc, &dwarf_ehe_buf), @@ -601,7 +611,7 @@ for (tabndx = 0; tabndx < fde_cnt; tabndx++) { initloc = dwarf_ehe_extract(data, &ndx, table_enc, - ehdr->e_ident, shdr->sh_addr, ndx); + ehdr->e_ident, B_TRUE, shdr->sh_addr, ndx, gotaddr); /*LINTED:E_VAR_USED_BEFORE_SET*/ if ((tabndx != 0) && (initloc0 > initloc)) (void) fprintf(stderr, @@ -610,8 +620,8 @@ dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT), EC_XWORD(initloc), EC_XWORD(dwarf_ehe_extract(data, &ndx, - table_enc, ehdr->e_ident, shdr->sh_addr, - ndx))); + table_enc, ehdr->e_ident, B_TRUE, shdr->sh_addr, + ndx, gotaddr))); initloc0 = initloc; } } else { /* Display the .eh_frame section */ @@ -628,7 +638,7 @@ conv_ehdr_type(osabi, ehdr->e_type, 0, &inv_buf)); } dump_eh_frame(data, datasize, shdr->sh_addr, - ehdr->e_machine, ehdr->e_ident); + ehdr->e_machine, ehdr->e_ident, gotaddr); } /* @@ -875,8 +885,8 @@ unwind_exception_ranges(_cache, file, _elf_sys_encoding() != ehdr->e_ident[EI_DATA]); else - unwind_eh_frame(cache, cnt, uphdr, ehdr, &eh_state, - osabi, file, flags); + unwind_eh_frame(cache, cnt, shnum, uphdr, ehdr, + &eh_state, osabi, file, flags); } }
--- a/usr/src/cmd/sgs/include/dwarf.h Fri Sep 07 17:29:12 2012 -0700 +++ b/usr/src/cmd/sgs/include/dwarf.h Mon Oct 08 03:37:11 2012 +0100 @@ -232,6 +232,8 @@ #define DW_EH_PE_datarel 0x30 /* Value is reletive to the beginning */ /* of the eh_frame_hdr segment */ /* ( segment type PT_AMD64_UNWIND ) */ + /* when within that segment, or to */ + /* the GOT when without. */ #define DW_EH_PE_funcrel 0x40 #define DW_EH_PE_aligned 0x50 /* value is an aligned void* */ #define DW_EH_PE_indirect 0x80 /* bit to signal indirection after */ @@ -251,7 +253,8 @@ extern uint64_t uleb_extract(unsigned char *, uint64_t *); extern int64_t sleb_extract(unsigned char *, uint64_t *); extern uint64_t dwarf_ehe_extract(unsigned char *, uint64_t *, - uint_t, unsigned char *, uint64_t, uint64_t); + uint_t, unsigned char *, boolean_t, uint64_t, + uint64_t, uint64_t); #ifdef __cplusplus }
--- a/usr/src/cmd/sgs/libld/common/unwind.c Fri Sep 07 17:29:12 2012 -0700 +++ b/usr/src/cmd/sgs/libld/common/unwind.c Mon Oct 08 03:37:11 2012 +0100 @@ -639,8 +639,8 @@ (void) dwarf_ehe_extract( &data[off + ndx], &ndx, ciePflag, - ofl->ofl_dehdr->e_ident, - shdr->sh_addr, off + ndx); + ofl->ofl_dehdr->e_ident, B_FALSE, + shdr->sh_addr, off + ndx, 0); break; case 'R': /* code encoding */ @@ -658,10 +658,17 @@ uint_t bintabndx; uint64_t initloc; uint64_t fdeaddr; + uint64_t gotaddr = 0; + + if (ofl->ofl_osgot != NULL) + gotaddr = + ofl->ofl_osgot->os_shdr->sh_addr; initloc = dwarf_ehe_extract(&data[off], &ndx, cieRflag, ofl->ofl_dehdr->e_ident, - shdr->sh_addr, off + ndx); + B_FALSE, + shdr->sh_addr, off + ndx, + gotaddr); /* * Ignore FDEs with initloc set to 0.
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README Fri Sep 07 17:29:12 2012 -0700 +++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README Mon Oct 08 03:37:11 2012 +0100 @@ -1639,3 +1639,4 @@ 3230 ld.so.1 should check default paths for DT_DEPAUDIT 3260 linker is insufficiently careful with strtok 3261 linker should ignore unknown hardware capabilities +3265 link-editor builds bogus .eh_frame_hdr on ia32
--- a/usr/src/cmd/sgs/tools/common/leb128.c Fri Sep 07 17:29:12 2012 -0700 +++ b/usr/src/cmd/sgs/tools/common/leb128.c Mon Oct 08 03:37:11 2012 +0100 @@ -190,12 +190,16 @@ * at which the desired datum starts. * ehe_flags - DWARF encoding * eident - ELF header e_ident[] array for object being processed + * frame_hdr - Boolean, true if we're extracting from .eh_frame_hdr * sh_base - Base address of ELF section containing desired datum * sh_offset - Offset relative to sh_base of desired datum. + * dbase - The base address to which DW_EH_PE_datarel is relative + * (if frame_hdr is false) */ uint64_t dwarf_ehe_extract(unsigned char *data, uint64_t *dotp, uint_t ehe_flags, - unsigned char *eident, uint64_t sh_base, uint64_t sh_offset) + unsigned char *eident, boolean_t frame_hdr, uint64_t sh_base, + uint64_t sh_offset, uint64_t dbase) { uint64_t dot = *dotp; uint_t lsb; @@ -281,17 +285,27 @@ /* * If value is relative to a base address, adjust it */ - if (result) { - switch (ehe_flags & 0xf0) { - case DW_EH_PE_pcrel: - result += sh_base + sh_offset; - break; + switch (ehe_flags & 0xf0) { + case DW_EH_PE_pcrel: + result += sh_base + sh_offset; + break; - case DW_EH_PE_datarel: + /* + * datarel is relative to .eh_frame_hdr if within .eh_frame, + * but GOT if not. + */ + case DW_EH_PE_datarel: + if (frame_hdr) result += sh_base; - break; - } + else + result += dbase; + break; } + + /* Truncate the result to its specified size */ + result = (result << ((sizeof (uint64_t) - fsize) * 8)) >> + ((sizeof (uint64_t) - fsize) * 8); + *dotp = dot; return (result); }