summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorRichard Lowe <richlowe@richlowe.net>2012-10-08 03:37:11 +0100
committerRichard Lowe <richlowe@richlowe.net>2012-11-03 12:47:09 -0400
commit965630c18f016ba05cbfcf212b6b6b1024894b0d (patch)
treee19c935becaee4f1bfdcb7aff98503cca36c32c7 /usr/src
parent31d7e8fa33fae995f558673adb22641b5aa8b6e1 (diff)
downloadillumos-joyent-965630c18f016ba05cbfcf212b6b6b1024894b0d.tar.gz
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>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/sgs/elfdump/common/_elfdump.h2
-rw-r--r--usr/src/cmd/sgs/elfdump/common/dwarf.c21
-rw-r--r--usr/src/cmd/sgs/elfdump/common/elfdump.c28
-rw-r--r--usr/src/cmd/sgs/include/dwarf.h5
-rw-r--r--usr/src/cmd/sgs/libld/common/unwind.c13
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README1
-rw-r--r--usr/src/cmd/sgs/tools/common/leb128.c32
7 files changed, 70 insertions, 32 deletions
diff --git a/usr/src/cmd/sgs/elfdump/common/_elfdump.h b/usr/src/cmd/sgs/elfdump/common/_elfdump.h
index b2ce8c8e3e..401b29c2d3 100644
--- a/usr/src/cmd/sgs/elfdump/common/_elfdump.h
+++ b/usr/src/cmd/sgs/elfdump/common/_elfdump.h
@@ -224,7 +224,7 @@ typedef enum {
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 *,
diff --git a/usr/src/cmd/sgs/elfdump/common/dwarf.c b/usr/src/cmd/sgs/elfdump/common/dwarf.c
index ae95e09630..d6072f51f5 100644
--- a/usr/src/cmd/sgs/elfdump/common/dwarf.c
+++ b/usr/src/cmd/sgs/elfdump/common/dwarf.c
@@ -49,6 +49,7 @@ typedef struct {
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 @@ dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
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 @@ dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
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 @@ dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
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 @@ dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
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 @@ dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
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 @@ dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
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));
diff --git a/usr/src/cmd/sgs/elfdump/common/elfdump.c b/usr/src/cmd/sgs/elfdump/common/elfdump.c
index 3eb27cf804..cfd19abc76 100644
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.c
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c
@@ -521,6 +521,7 @@ getphdr(Word phnum, Word *type_arr, Word type_cnt, const char *file, Elf *elf)
* 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 @@ getphdr(Word phnum, Word *type_arr, Word type_cnt, const char *file, Elf *elf)
* 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 @@ unwind_eh_frame(Cache *cache, Word shndx, Phdr *uphdr, Ehdr *ehdr,
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 @@ unwind_eh_frame(Cache *cache, Word shndx, Phdr *uphdr, Ehdr *ehdr,
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 @@ unwind_eh_frame(Cache *cache, Word shndx, Phdr *uphdr, Ehdr *ehdr,
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 @@ unwind_eh_frame(Cache *cache, Word shndx, Phdr *uphdr, Ehdr *ehdr,
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 @@ unwind_eh_frame(Cache *cache, Word shndx, Phdr *uphdr, Ehdr *ehdr,
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 @@ unwind_eh_frame(Cache *cache, Word shndx, Phdr *uphdr, Ehdr *ehdr,
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(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, uchar_t osabi,
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);
}
}
diff --git a/usr/src/cmd/sgs/include/dwarf.h b/usr/src/cmd/sgs/include/dwarf.h
index 31c295d17c..8bb8b75eec 100644
--- a/usr/src/cmd/sgs/include/dwarf.h
+++ b/usr/src/cmd/sgs/include/dwarf.h
@@ -232,6 +232,8 @@ extern "C" {
#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 @@ typedef enum _LANG {
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
}
diff --git a/usr/src/cmd/sgs/libld/common/unwind.c b/usr/src/cmd/sgs/libld/common/unwind.c
index 20d7051a4f..1e10b4664d 100644
--- a/usr/src/cmd/sgs/libld/common/unwind.c
+++ b/usr/src/cmd/sgs/libld/common/unwind.c
@@ -639,8 +639,8 @@ ld_unwind_populate_hdr(Ofl_desc *ofl)
(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 @@ ld_unwind_populate_hdr(Ofl_desc *ofl)
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.
diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README
index 4e453ca276..184212bfb8 100644
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README
@@ -1639,3 +1639,4 @@ Bugid Risk Synopsis
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
diff --git a/usr/src/cmd/sgs/tools/common/leb128.c b/usr/src/cmd/sgs/tools/common/leb128.c
index 1183e6f854..42ed001e15 100644
--- a/usr/src/cmd/sgs/tools/common/leb128.c
+++ b/usr/src/cmd/sgs/tools/common/leb128.c
@@ -190,12 +190,16 @@ sleb_extract(unsigned char *data, uint64_t *dotp)
* 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 @@ dwarf_ehe_extract(unsigned char *data, uint64_t *dotp, uint_t ehe_flags,
/*
* 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);
}