Permalink
Browse files

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>
  • Loading branch information...
1 parent 31d7e8f commit 965630c18f016ba05cbfcf212b6b6b1024894b0d @richlowe richlowe committed Oct 8, 2012
@@ -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 *,
@@ -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));
@@ -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);
}
}
@@ -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
}
@@ -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.
@@ -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
@@ -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);
}

0 comments on commit 965630c

Please sign in to comment.