diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/mdb/common/modules/libproc/libproc.c | 40 | ||||
-rw-r--r-- | usr/src/lib/libproc/Makefile.com | 4 | ||||
-rw-r--r-- | usr/src/lib/libproc/amd64/Makefile | 10 | ||||
-rw-r--r-- | usr/src/lib/libproc/amd64/Pisadep.c | 11 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pcontrol.h | 27 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pcore.c | 8 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pgcore.c | 25 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Psymtab.c | 877 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Psymtab_machelf.h | 48 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Psymtab_machelf32.c | 637 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Psymtab_machelf64.c | 34 | ||||
-rw-r--r-- | usr/src/lib/libproc/i386/Pisadep.c | 9 | ||||
-rw-r--r-- | usr/src/lib/libproc/sparc/Pisadep.c | 9 | ||||
-rw-r--r-- | usr/src/lib/libproc/sparcv9/Makefile | 10 | ||||
-rw-r--r-- | usr/src/lib/libproc/sparcv9/Pisadep.c | 11 |
15 files changed, 918 insertions, 842 deletions
diff --git a/usr/src/cmd/mdb/common/modules/libproc/libproc.c b/usr/src/cmd/mdb/common/modules/libproc/libproc.c index f1a87503cd..c0a3314f49 100644 --- a/usr/src/cmd/mdb/common/modules/libproc/libproc.c +++ b/usr/src/cmd/mdb/common/modules/libproc/libproc.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -46,7 +46,9 @@ static int pr_symtab(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { sym_tbl_t symtab; - Elf_Data data; + Elf_Data data_pri; + Elf_Data data_aux; + Elf_Data *data; #ifdef _LP64 Elf64_Sym sym; int width = 16; @@ -85,9 +87,25 @@ pr_symtab(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) return (DCMD_ERR); } - if (mdb_vread(&data, sizeof (Elf_Data), - (uintptr_t)symtab.sym_data) == -1) { - mdb_warn("failed to read Elf_Data at %p", symtab.sym_data); + /* + * As described in the libproc header Pcontrol.h, a sym_tbl_t + * contains a primary and an optional auxiliary symbol table. + * We treat the combination as a single table, with the auxiliary + * values coming before the primary ones. + * + * Read the primary and auxiliary Elf_Data structs. + */ + if (mdb_vread(&data_pri, sizeof (Elf_Data), + (uintptr_t)symtab.sym_data_pri) == -1) { + mdb_warn("failed to read primary Elf_Data at %p", + symtab.sym_data_pri); + return (DCMD_ERR); + } + if ((symtab.sym_symn_aux > 0) && + (mdb_vread(&data_aux, sizeof (Elf_Data), + (uintptr_t)symtab.sym_data_aux) == -1)) { + mdb_warn("failed to read auxiliary Elf_Data at %p", + symtab.sym_data_aux); return (DCMD_ERR); } @@ -116,10 +134,18 @@ pr_symtab(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) else idx = i; - if (mdb_vread(&sym, sizeof (sym), (uintptr_t)data.d_buf + + /* If index is in range of primary symtab, look it up there */ + if (idx >= symtab.sym_symn_aux) { + data = &data_pri; + idx -= symtab.sym_symn_aux; + } else { /* Look it up in the auxiliary symtab */ + data = &data_aux; + } + + if (mdb_vread(&sym, sizeof (sym), (uintptr_t)data->d_buf + idx * sizeof (sym)) == -1) { mdb_warn("failed to read symbol at %p", - (uintptr_t)data.d_buf + idx * sizeof (sym)); + (uintptr_t)data->d_buf + idx * sizeof (sym)); if (symlist) mdb_free(symlist, symlistsz); return (DCMD_ERR); diff --git a/usr/src/lib/libproc/Makefile.com b/usr/src/lib/libproc/Makefile.com index 521381ab6d..e9bd629f9d 100644 --- a/usr/src/lib/libproc/Makefile.com +++ b/usr/src/lib/libproc/Makefile.com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -40,6 +40,8 @@ CMNOBJS = \ Plwpregs.o \ Pservice.o \ Psymtab.o \ + Psymtab_machelf32.o \ + $(CMNOBJS64) \ Pscantext.o \ Pstack.o \ Psyscall.o \ diff --git a/usr/src/lib/libproc/amd64/Makefile b/usr/src/lib/libproc/amd64/Makefile index b74d317152..1e20da114e 100644 --- a/usr/src/lib/libproc/amd64/Makefile +++ b/usr/src/lib/libproc/amd64/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,12 +19,15 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # +# This is a 64-bit build, and as such needs 64-bit ELF support +CMNOBJS64 = Psymtab_machelf64.o + include ../Makefile.com include ../../Makefile.lib.64 diff --git a/usr/src/lib/libproc/amd64/Pisadep.c b/usr/src/lib/libproc/amd64/Pisadep.c index 2583474d58..c2ab4dd3ab 100644 --- a/usr/src/lib/libproc/amd64/Pisadep.c +++ b/usr/src/lib/libproc/amd64/Pisadep.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -71,7 +70,7 @@ Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr) if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) && (i = ELF64_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) { - Elf_Data *data = fp->file_dynsym.sym_data; + Elf_Data *data = fp->file_dynsym.sym_data_pri; Elf64_Sym *symp = &(((Elf64_Sym *)data->d_buf)[i]); return (fp->file_dynsym.sym_strs + symp->st_name); @@ -83,7 +82,7 @@ Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr) if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) && (i = ELF32_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) { - Elf_Data *data = fp->file_dynsym.sym_data; + Elf_Data *data = fp->file_dynsym.sym_data_pri; Elf32_Sym *symp = &(((Elf32_Sym *)data->d_buf)[i]); return (fp->file_dynsym.sym_strs + symp->st_name); diff --git a/usr/src/lib/libproc/common/Pcontrol.h b/usr/src/lib/libproc/common/Pcontrol.h index 8ac88d33cb..5a4d606c9d 100644 --- a/usr/src/lib/libproc/common/Pcontrol.h +++ b/usr/src/lib/libproc/common/Pcontrol.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -53,12 +53,31 @@ extern "C" { * These may change without affecting clients of libproc. */ +/* + * sym_tbl_t contains a primary and an (optional) auxiliary symbol table, which + * we wish to treat as a single logical symbol table. In this logical table, + * the data from the auxiliary table preceeds that from the primary. Symbol + * indices start at [0], which is the first item in the auxiliary table + * if there is one. The sole purpose for this is so that we can treat the + * combination of .SUNW_ldynsym and .dynsym sections as a logically single + * entity without having to violate the public interface to libelf. + * + * Both tables must share the same string table section. + * + * The symtab_getsym() function serves as a gelf_getsym() replacement + * that is aware of the two tables and makes them look like a single table + * to the caller. + * + */ typedef struct sym_tbl { /* symbol table */ - Elf_Data *sym_data; /* start of table */ - size_t sym_symn; /* number of entries */ + Elf_Data *sym_data_pri; /* primary table */ + Elf_Data *sym_data_aux; /* auxiliary table */ + size_t sym_symn_aux; /* number of entries in auxiliary table */ + size_t sym_symn; /* total number of entries in both tables */ char *sym_strs; /* ptr to strings */ size_t sym_strsz; /* size of string table */ - GElf_Shdr sym_hdr; /* symbol table section header */ + GElf_Shdr sym_hdr_pri; /* primary symbol table section header */ + GElf_Shdr sym_hdr_aux; /* auxiliary symbol table section header */ GElf_Shdr sym_strhdr; /* string table section header */ Elf *sym_elf; /* faked-up ELF handle from core file */ void *sym_elfmem; /* data for faked-up ELF handle */ diff --git a/usr/src/lib/libproc/common/Pcore.c b/usr/src/lib/libproc/common/Pcore.c index 80b7e16311..b4cfea717a 100644 --- a/usr/src/lib/libproc/common/Pcore.c +++ b/usr/src/lib/libproc/common/Pcore.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -812,7 +812,7 @@ fake_up_symtab(struct ps_prochandle *P, const elf_file_header_t *ehdr, if (symtab->sh_addr == 0 || (mp = Paddr2mptr(P, symtab->sh_addr)) == NULL || (fp = mp->map_file) == NULL || - fp->file_symtab.sym_data != NULL) { + fp->file_symtab.sym_data_pri != NULL) { dprintf("fake_up_symtab: invalid section\n"); return; } @@ -950,7 +950,7 @@ fake_up_symtab(struct ps_prochandle *P, const elf_file_header_t *ehdr, } if ((scn = elf_getscn(fp->file_symtab.sym_elf, 1)) == NULL || - (fp->file_symtab.sym_data = elf_getdata(scn, NULL)) == NULL || + (fp->file_symtab.sym_data_pri = elf_getdata(scn, NULL)) == NULL || (scn = elf_getscn(fp->file_symtab.sym_elf, 2)) == NULL || (data = elf_getdata(scn, NULL)) == NULL) { dprintf("fake_up_symtab: failed to get section data at %p\n", @@ -961,7 +961,7 @@ fake_up_symtab(struct ps_prochandle *P, const elf_file_header_t *ehdr, fp->file_symtab.sym_strs = data->d_buf; fp->file_symtab.sym_strsz = data->d_size; fp->file_symtab.sym_symn = symtab->sh_size / symtab->sh_entsize; - fp->file_symtab.sym_hdr = *symtab; + fp->file_symtab.sym_hdr_pri = *symtab; fp->file_symtab.sym_strhdr = *strtab; optimize_symtab(&fp->file_symtab); diff --git a/usr/src/lib/libproc/common/Pgcore.c b/usr/src/lib/libproc/common/Pgcore.c index cf60653e1d..8bb6781bf3 100644 --- a/usr/src/lib/libproc/common/Pgcore.c +++ b/usr/src/lib/libproc/common/Pgcore.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -573,13 +572,13 @@ count_sections(pgcore_t *pgc) hit_symtab = 1; } - if (sym->sym_data != NULL && sym->sym_symn != 0 && + if (sym->sym_data_pri != NULL && sym->sym_symn != 0 && sym->sym_strs != NULL) nshdrs += 2; } if ((pgc->pgc_content & CC_CONTENT_SYMTAB) && !hit_symtab && - fptr->file_symtab.sym_data != NULL && + fptr->file_symtab.sym_data_pri != NULL && fptr->file_symtab.sym_symn != 0 && fptr->file_symtab.sym_strs != NULL) { nshdrs += 2; @@ -651,18 +650,18 @@ dump_symtab(pgcore_t *pgc, file_info_t *fptr, uint_t index, int dynsym) size_t size; uintptr_t addr = fptr->file_map->map_pmap.pr_vaddr; - if (sym->sym_data == NULL || sym->sym_symn == 0 || + if (sym->sym_data_pri == NULL || sym->sym_symn == 0 || sym->sym_strs == NULL) return (0); - size = sym->sym_hdr.sh_size; - if (pwrite64(pgc->pgc_fd, sym->sym_data->d_buf, size, + size = sym->sym_hdr_pri.sh_size; + if (pwrite64(pgc->pgc_fd, sym->sym_data_pri->d_buf, size, *pgc->pgc_doff) != size) return (-1); if (write_shdr(pgc, symname, symtype, 0, addr, *pgc->pgc_doff, size, - index + 1, sym->sym_hdr.sh_info, sym->sym_hdr.sh_addralign, - sym->sym_hdr.sh_entsize) != 0) + index + 1, sym->sym_hdr_pri.sh_info, sym->sym_hdr_pri.sh_addralign, + sym->sym_hdr_pri.sh_entsize) != 0) return (-1); *pgc->pgc_doff += roundup(size, 8); @@ -718,7 +717,7 @@ dump_sections(pgcore_t *pgc) hit_symtab = 1; } - if (sym->sym_data != NULL && sym->sym_symn != 0 && + if (sym->sym_data_pri != NULL && sym->sym_symn != 0 && sym->sym_strs != NULL) { symindex = index; if (dump_symtab(pgc, fptr, index, dynsym) != 0) @@ -745,7 +744,7 @@ dump_sections(pgcore_t *pgc) } if ((pgc->pgc_content & CC_CONTENT_SYMTAB) && !hit_symtab && - fptr->file_symtab.sym_data != NULL && + fptr->file_symtab.sym_data_pri != NULL && fptr->file_symtab.sym_symn != 0 && fptr->file_symtab.sym_strs != NULL) { if (dump_symtab(pgc, fptr, index, 0) != 0) diff --git a/usr/src/lib/libproc/common/Psymtab.c b/usr/src/lib/libproc/common/Psymtab.c index 035102fb57..35107c546b 100644 --- a/usr/src/lib/libproc/common/Psymtab.c +++ b/usr/src/lib/libproc/common/Psymtab.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -50,6 +50,7 @@ #include "libproc.h" #include "Pcontrol.h" #include "Putil.h" +#include "Psymtab_machelf.h" static file_info_t *build_map_symtab(struct ps_prochandle *, map_info_t *); static map_info_t *exec_map(struct ps_prochandle *); @@ -708,7 +709,7 @@ Pbuild_file_ctf(struct ps_prochandle *P, file_info_t *fptr) return (NULL); symp = fptr->file_ctf_dyn ? &fptr->file_dynsym : &fptr->file_symtab; - if (symp->sym_data == NULL) + if (symp->sym_data_pri == NULL) return (NULL); /* @@ -741,12 +742,12 @@ Pbuild_file_ctf(struct ps_prochandle *P, file_info_t *fptr) ctdata.cts_offset = 0; symtab.cts_name = fptr->file_ctf_dyn ? ".dynsym" : ".symtab"; - symtab.cts_type = symp->sym_hdr.sh_type; - symtab.cts_flags = symp->sym_hdr.sh_flags; - symtab.cts_data = symp->sym_data->d_buf; - symtab.cts_size = symp->sym_hdr.sh_size; - symtab.cts_entsize = symp->sym_hdr.sh_entsize; - symtab.cts_offset = symp->sym_hdr.sh_offset; + symtab.cts_type = symp->sym_hdr_pri.sh_type; + symtab.cts_flags = symp->sym_hdr_pri.sh_flags; + symtab.cts_data = symp->sym_data_pri->d_buf; + symtab.cts_size = symp->sym_hdr_pri.sh_size; + symtab.cts_entsize = symp->sym_hdr_pri.sh_entsize; + symtab.cts_offset = symp->sym_hdr_pri.sh_offset; strtab.cts_name = fptr->file_ctf_dyn ? ".dynstr" : ".strtab"; strtab.cts_type = symp->sym_strhdr.sh_type; @@ -1294,27 +1295,17 @@ found_cksum: return (0); } +/* + * Read data from the specified process and construct an in memory + * image of an ELF file that represents it well enough to let + * us probe it for information. + */ static Elf * fake_elf(struct ps_prochandle *P, file_info_t *fptr) { - enum { - DI_PLTGOT = 0, - DI_JMPREL, - DI_PLTRELSZ, - DI_PLTREL, - DI_SYMTAB, - DI_HASH, - DI_SYMENT, - DI_STRTAB, - DI_STRSZ, - DI_NENT - }; - uintptr_t addr; - size_t size = 0; - caddr_t elfdata = NULL; Elf *elf; - Elf32_Word nchain; - static char shstr[] = ".shstrtab\0.dynsym\0.dynstr\0.dynamic\0.plt"; + uintptr_t addr; + uint_t phnum; if (fptr->file_map == NULL) return (NULL); @@ -1325,754 +1316,28 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr) addr = fptr->file_map->map_pmap.pr_vaddr; - /* - * We're building a in memory elf file that will let us use libelf - * for most of the work we need to later (e.g. symbol table lookups). - * We need sections for the dynsym, dynstr, and plt, and we need - * the program headers from the text section. The former is used in - * Pbuild_file_symtab(); the latter is used in several functions in - * Pcore.c to reconstruct the origin of each mapping from the load - * object that spawned it. - * - * Here are some useful pieces of elf trivia that will help - * to elucidate this code. - * - * All the information we need about the dynstr can be found in these - * two entries in the dynamic section: - * - * DT_STRTAB base of dynstr - * DT_STRSZ size of dynstr - * - * So deciphering the dynstr is pretty straightforward. - * - * The dynsym is a little trickier. - * - * DT_SYMTAB base of dynsym - * DT_SYMENT size of a dynstr entry (Elf{32,64}_Sym) - * DT_HASH base of hash table for dynamic lookups - * - * The DT_SYMTAB entry gives us any easy way of getting to the base - * of the dynsym, but getting the size involves rooting around in the - * dynamic lookup hash table. Here's the layout of the hash table: - * - * +-------------------+ - * | nbucket | All values are of type - * +-------------------+ Elf32_Word - * | nchain | - * +-------------------+ - * | bucket[0] | - * | . . . | - * | bucket[nbucket-1] | - * +-------------------+ - * | chain[0] | - * | . . . | - * | chain[nchain-1] | - * +-------------------+ - * (figure 5-12 from the SYS V Generic ABI) - * - * Symbols names are hashed into a particular bucket which contains - * an index into the symbol table. Each entry in the symbol table - * has a corresponding entry in the chain table which tells the - * consumer where the next entry in the hash chain is. We can use - * the nchain field to find out the size of the dynsym. - * - * We can figure out the size of the .plt section, but it takes some - * doing. We need to use the following information: - * - * DT_PLTGOT base of the PLT - * DT_JMPREL base of the PLT's relocation section - * DT_PLTRELSZ size of the PLT's relocation section - * DT_PLTREL type of the PLT's relocation section - * - * We can use the relocation section to figure out the address of the - * last entry and subtract off the value of DT_PLTGOT to calculate - * the size of the PLT. - * - * For more information, check out the System V Generic ABI. - */ - if (P->status.pr_dmodel == PR_MODEL_ILP32) { - Elf32_Ehdr ehdr, *ep; + Elf32_Ehdr ehdr; Elf32_Phdr phdr; - Elf32_Shdr *sp; - Elf32_Dyn *dp; - Elf32_Dyn *d[DI_NENT] = { 0 }; - uint_t phnum, i, dcount = 0; - uint32_t off; - size_t pltsz = 0, pltentsz; if ((read_ehdr32(P, &ehdr, &phnum, addr) != 0) || read_dynamic_phdr32(P, &ehdr, phnum, &phdr, addr) != 0) return (NULL); - if (ehdr.e_type == ET_DYN) - phdr.p_vaddr += addr; - - if ((dp = malloc(phdr.p_filesz)) == NULL) - return (NULL); - - if (Pread(P, dp, phdr.p_filesz, phdr.p_vaddr) != - phdr.p_filesz) - goto bad32; - - /* - * Allow librtld_db the opportunity to "fix" the program - * headers, if it needs to, before we process them. - */ - if (P->rap != NULL && ehdr.e_type == ET_DYN) { - rd_fix_phdrs(P->rap, dp, phdr.p_filesz, addr); - } - - for (i = 0; i < phdr.p_filesz / sizeof (Elf32_Dyn); i++) { - switch (dp[i].d_tag) { - /* - * For the .plt section. - */ - case DT_PLTGOT: - d[DI_PLTGOT] = &dp[i]; - continue; - case DT_JMPREL: - d[DI_JMPREL] = &dp[i]; - continue; - case DT_PLTRELSZ: - d[DI_PLTRELSZ] = &dp[i]; - continue; - case DT_PLTREL: - d[DI_PLTREL] = &dp[i]; - continue; - default: - continue; - - /* - * For the .dynsym section. - */ - case DT_SYMTAB: - d[DI_SYMTAB] = &dp[i]; - break; - case DT_HASH: - d[DI_HASH] = &dp[i]; - break; - case DT_SYMENT: - d[DI_SYMENT] = &dp[i]; - break; - - /* - * For the .dynstr section. - */ - case DT_STRTAB: - d[DI_STRTAB] = &dp[i]; - break; - case DT_STRSZ: - d[DI_STRSZ] = &dp[i]; - break; - } - - dcount++; - } - - /* - * We need all of those dynamic entries in order to put - * together a complete set of elf sections, but we'll - * let the PLT section slide if need be. The dynsym- and - * dynstr-related dynamic entries are mandatory in both - * executables and shared objects so if one of those is - * missing, we're in some trouble and should abort. - */ - if (dcount + 4 != DI_NENT) { - dprintf("text section missing required dynamic " - "entries\n"); - goto bad32; - } - - if (ehdr.e_type == ET_DYN) { - if (d[DI_PLTGOT] != NULL) - d[DI_PLTGOT]->d_un.d_ptr += addr; - if (d[DI_JMPREL] != NULL) - d[DI_JMPREL]->d_un.d_ptr += addr; - d[DI_SYMTAB]->d_un.d_ptr += addr; - d[DI_HASH]->d_un.d_ptr += addr; - d[DI_STRTAB]->d_un.d_ptr += addr; - } - - /* elf header */ - size = sizeof (Elf32_Ehdr); - - /* program headers from in-core elf fragment */ - size += phnum * ehdr.e_phentsize; - - /* unused shdr, and .shstrtab section */ - size += sizeof (Elf32_Shdr); - size += sizeof (Elf32_Shdr); - size += roundup(sizeof (shstr), 4); - - /* .dynsym section */ - size += sizeof (Elf32_Shdr); - if (Pread(P, &nchain, sizeof (nchain), - d[DI_HASH]->d_un.d_ptr + 4) != sizeof (nchain)) { - dprintf("Pread of .dynsym at %lx failed\n", - (long)(d[DI_HASH]->d_un.d_val + 4)); - goto bad32; - } - size += sizeof (Elf32_Sym) * nchain; - - /* .dynstr section */ - size += sizeof (Elf32_Shdr); - size += roundup(d[DI_STRSZ]->d_un.d_val, 4); - - /* .dynamic section */ - size += sizeof (Elf32_Shdr); - size += roundup(phdr.p_filesz, 4); - - /* .plt section */ - if (d[DI_PLTGOT] != NULL && d[DI_JMPREL] != NULL && - d[DI_PLTRELSZ] != NULL && d[DI_PLTREL] != NULL) { - uintptr_t penult, ult; - uintptr_t jmprel = d[DI_JMPREL]->d_un.d_ptr; - size_t pltrelsz = d[DI_PLTRELSZ]->d_un.d_val; - - if (d[DI_PLTREL]->d_un.d_val == DT_RELA) { - uint_t ndx = pltrelsz / sizeof (Elf32_Rela) - 2; - Elf32_Rela r[2]; - - if (Pread(P, r, sizeof (r), jmprel + - sizeof (r[0]) * ndx) != sizeof (r)) { - dprintf("Pread of DT_RELA failed\n"); - goto bad32; - } - - penult = r[0].r_offset; - ult = r[1].r_offset; - - } else if (d[DI_PLTREL]->d_un.d_val == DT_REL) { - uint_t ndx = pltrelsz / sizeof (Elf32_Rel) - 2; - Elf32_Rel r[2]; - - if (Pread(P, r, sizeof (r), jmprel + - sizeof (r[0]) * ndx) != sizeof (r)) { - dprintf("Pread of DT_REL failed\n"); - goto bad32; - } - - penult = r[0].r_offset; - ult = r[1].r_offset; - } else { - dprintf(".plt: unknown jmprel value\n"); - goto bad32; - } - - pltentsz = ult - penult; - - if (ehdr.e_type == ET_DYN) - ult += addr; - - pltsz = ult - d[DI_PLTGOT]->d_un.d_ptr + pltentsz; - - size += sizeof (Elf32_Shdr); - size += roundup(pltsz, 4); - } - - if ((elfdata = calloc(1, size)) == NULL) - goto bad32; - - /* LINTED - alignment */ - ep = (Elf32_Ehdr *)elfdata; - (void) memcpy(ep, &ehdr, offsetof(Elf32_Ehdr, e_phoff)); - - ep->e_ehsize = sizeof (Elf32_Ehdr); - ep->e_phoff = sizeof (Elf32_Ehdr); - ep->e_phentsize = ehdr.e_phentsize; - ep->e_phnum = phnum; - ep->e_shoff = ep->e_phoff + phnum * ep->e_phentsize; - ep->e_shentsize = sizeof (Elf32_Shdr); - ep->e_shnum = (pltsz == 0) ? 5 : 6; - ep->e_shstrndx = 1; - - /* LINTED - alignment */ - sp = (Elf32_Shdr *)(elfdata + ep->e_shoff); - off = ep->e_shoff + ep->e_shentsize * ep->e_shnum; - - /* - * Copying the program headers directly from the process's - * address space is a little suspect, but since we only - * use them for their address and size values, this is fine. - */ - if (Pread(P, &elfdata[ep->e_phoff], phnum * ep->e_phentsize, - addr + ehdr.e_phoff) != phnum * ep->e_phentsize) { - free(elfdata); - dprintf("failed to read program headers\n"); - goto bad32; - } - - /* - * The first elf section is always skipped. - */ - sp++; - - /* - * Section Header[1] sh_name: .shstrtab - */ - sp->sh_name = 0; - sp->sh_type = SHT_STRTAB; - sp->sh_flags = SHF_STRINGS; - sp->sh_addr = 0; - sp->sh_offset = off; - sp->sh_size = sizeof (shstr); - sp->sh_link = 0; - sp->sh_info = 0; - sp->sh_addralign = 1; - sp->sh_entsize = 0; - - (void) memcpy(&elfdata[off], shstr, sizeof (shstr)); - off += roundup(sp->sh_size, 4); - sp++; - - /* - * Section Header[2] sh_name: .dynsym - */ - sp->sh_name = 10; - sp->sh_type = SHT_DYNSYM; - sp->sh_flags = SHF_ALLOC; - sp->sh_addr = d[DI_SYMTAB]->d_un.d_ptr; - if (ehdr.e_type == ET_DYN) - sp->sh_addr -= addr; - sp->sh_offset = off; - sp->sh_size = nchain * sizeof (Elf32_Sym); - sp->sh_link = 3; - sp->sh_info = 1; - sp->sh_addralign = 4; - sp->sh_entsize = sizeof (Elf32_Sym); - - if (Pread(P, &elfdata[off], sp->sh_size, - d[DI_SYMTAB]->d_un.d_ptr) != sp->sh_size) { - free(elfdata); - dprintf("failed to read .dynsym at %lx\n", - (long)d[DI_SYMTAB]->d_un.d_ptr); - goto bad32; - } - - off += roundup(sp->sh_size, 4); - sp++; - - /* - * Section Header[3] sh_name: .dynstr - */ - sp->sh_name = 18; - sp->sh_type = SHT_STRTAB; - sp->sh_flags = SHF_ALLOC | SHF_STRINGS; - sp->sh_addr = d[DI_STRTAB]->d_un.d_ptr; - if (ehdr.e_type == ET_DYN) - sp->sh_addr -= addr; - sp->sh_offset = off; - sp->sh_size = d[DI_STRSZ]->d_un.d_val; - sp->sh_link = 0; - sp->sh_info = 0; - sp->sh_addralign = 1; - sp->sh_entsize = 0; - - if (Pread(P, &elfdata[off], sp->sh_size, - d[DI_STRTAB]->d_un.d_ptr) != sp->sh_size) { - free(elfdata); - dprintf("failed to read .dynstr\n"); - goto bad32; - } - off += roundup(sp->sh_size, 4); - sp++; - - /* - * Section Header[4] sh_name: .dynamic - */ - sp->sh_name = 26; - sp->sh_type = SHT_DYNAMIC; - sp->sh_flags = SHF_WRITE | SHF_ALLOC; - sp->sh_addr = phdr.p_vaddr; - if (ehdr.e_type == ET_DYN) - sp->sh_addr -= addr; - sp->sh_offset = off; - sp->sh_size = phdr.p_filesz; - sp->sh_link = 3; - sp->sh_info = 0; - sp->sh_addralign = 4; - sp->sh_entsize = sizeof (Elf32_Dyn); - - (void) memcpy(&elfdata[off], dp, sp->sh_size); - off += roundup(sp->sh_size, 4); - sp++; - - /* - * Section Header[5] sh_name: .plt - */ - if (pltsz != 0) { - sp->sh_name = 35; - sp->sh_type = SHT_PROGBITS; - sp->sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR; - sp->sh_addr = d[DI_PLTGOT]->d_un.d_ptr; - if (ehdr.e_type == ET_DYN) - sp->sh_addr -= addr; - sp->sh_offset = off; - sp->sh_size = pltsz; - sp->sh_link = 0; - sp->sh_info = 0; - sp->sh_addralign = 4; - sp->sh_entsize = pltentsz; - - if (Pread(P, &elfdata[off], sp->sh_size, - d[DI_PLTGOT]->d_un.d_ptr) != sp->sh_size) { - free(elfdata); - dprintf("failed to read .plt\n"); - goto bad32; - } - off += roundup(sp->sh_size, 4); - sp++; - } - - free(dp); - goto good; - -bad32: - free(dp); - return (NULL); + elf = fake_elf32(P, fptr, addr, &ehdr, phnum, &phdr); #ifdef _LP64 - } else if (P->status.pr_dmodel == PR_MODEL_LP64) { - Elf64_Ehdr ehdr, *ep; + } else { + Elf64_Ehdr ehdr; Elf64_Phdr phdr; - Elf64_Shdr *sp; - Elf64_Dyn *dp; - Elf64_Dyn *d[DI_NENT] = { 0 }; - uint_t phnum, i, dcount = 0; - uint64_t off; - size_t pltsz = 0, pltentsz; if (read_ehdr64(P, &ehdr, &phnum, addr) != 0 || read_dynamic_phdr64(P, &ehdr, phnum, &phdr, addr) != 0) return (NULL); - if (ehdr.e_type == ET_DYN) - phdr.p_vaddr += addr; - - if ((dp = malloc(phdr.p_filesz)) == NULL) - return (NULL); - - if (Pread(P, dp, phdr.p_filesz, phdr.p_vaddr) != - phdr.p_filesz) - goto bad64; - - for (i = 0; i < phdr.p_filesz / sizeof (Elf64_Dyn); i++) { - switch (dp[i].d_tag) { - /* - * For the .plt section. - */ - case DT_PLTGOT: - d[DI_PLTGOT] = &dp[i]; - continue; - case DT_JMPREL: - d[DI_JMPREL] = &dp[i]; - continue; - case DT_PLTRELSZ: - d[DI_PLTRELSZ] = &dp[i]; - continue; - case DT_PLTREL: - d[DI_PLTREL] = &dp[i]; - continue; - default: - continue; - - /* - * For the .dynsym section. - */ - case DT_SYMTAB: - d[DI_SYMTAB] = &dp[i]; - break; - case DT_HASH: - d[DI_HASH] = &dp[i]; - break; - case DT_SYMENT: - d[DI_SYMENT] = &dp[i]; - break; - - /* - * For the .dynstr section. - */ - case DT_STRTAB: - d[DI_STRTAB] = &dp[i]; - break; - case DT_STRSZ: - d[DI_STRSZ] = &dp[i]; - break; - } - - dcount++; - } - - /* - * We need all of those dynamic entries in order to put - * together a complete set of elf sections, but we'll - * let the PLT section slide if need be. The dynsym- and - * dynstr-related dynamic entries are mandatory in both - * executables and shared objects so if one of those is - * missing, we're in some trouble and should abort. - */ - if (dcount + 4 != DI_NENT) { - dprintf("text section missing required dynamic " - "entries\n"); - goto bad64; - } - - if (ehdr.e_type == ET_DYN) { - if (d[DI_PLTGOT] != NULL) - d[DI_PLTGOT]->d_un.d_ptr += addr; - if (d[DI_JMPREL] != NULL) - d[DI_JMPREL]->d_un.d_ptr += addr; - d[DI_SYMTAB]->d_un.d_ptr += addr; - d[DI_HASH]->d_un.d_ptr += addr; - d[DI_STRTAB]->d_un.d_ptr += addr; - } - - /* elf header */ - size = sizeof (Elf64_Ehdr); - - /* program headers from in-core elf fragment */ - size += phnum * ehdr.e_phentsize; - - /* unused shdr, and .shstrtab section */ - size += sizeof (Elf64_Shdr); - size += sizeof (Elf64_Shdr); - size += roundup(sizeof (shstr), 8); - - /* .dynsym section */ - size += sizeof (Elf64_Shdr); - if (Pread(P, &nchain, sizeof (nchain), - d[DI_HASH]->d_un.d_ptr + 4) != sizeof (nchain)) - goto bad64; - size += sizeof (Elf64_Sym) * nchain; - - /* .dynstr section */ - size += sizeof (Elf64_Shdr); - size += roundup(d[DI_STRSZ]->d_un.d_val, 8); - - /* .dynamic section */ - size += sizeof (Elf64_Shdr); - size += roundup(phdr.p_filesz, 8); - - /* .plt section */ - if (d[DI_PLTGOT] != NULL && d[DI_JMPREL] != NULL && - d[DI_PLTRELSZ] != NULL && d[DI_PLTREL] != NULL) { - uintptr_t penult, ult; - uintptr_t jmprel = d[DI_JMPREL]->d_un.d_ptr; - size_t pltrelsz = d[DI_PLTRELSZ]->d_un.d_val; - - if (d[DI_PLTREL]->d_un.d_val == DT_RELA) { - uint_t ndx = pltrelsz / sizeof (Elf64_Rela) - 2; - Elf64_Rela r[2]; - - if (Pread(P, r, sizeof (r), jmprel + - sizeof (r[0]) * ndx) != sizeof (r)) { - dprintf("Pread jmprel DT_RELA at %p " - "failed\n", - (void *)(jmprel + - sizeof (r[0]) * ndx)); - goto bad64; - } - - penult = r[0].r_offset; - ult = r[1].r_offset; - - } else if (d[DI_PLTREL]->d_un.d_val == DT_REL) { - uint_t ndx = pltrelsz / sizeof (Elf64_Rel) - 2; - Elf64_Rel r[2]; - - if (Pread(P, r, sizeof (r), jmprel + - sizeof (r[0]) * ndx) != sizeof (r)) { - dprintf("Pread jmprel DT_REL at %p " - "failed\n", - (void *)(jmprel + - sizeof (r[0]) * ndx)); - goto bad64; - } - - penult = r[0].r_offset; - ult = r[1].r_offset; - } else { - dprintf("DT_PLTREL value %p unknown\n", - (void *)d[DI_PLTREL]->d_un.d_ptr); - goto bad64; - } - - pltentsz = ult - penult; - - if (ehdr.e_type == ET_DYN) - ult += addr; - - pltsz = ult - d[DI_PLTGOT]->d_un.d_ptr + pltentsz; - - size += sizeof (Elf64_Shdr); - size += roundup(pltsz, 8); - } - - if ((elfdata = calloc(1, size)) == NULL) - goto bad64; - - /* LINTED - alignment */ - ep = (Elf64_Ehdr *)elfdata; - (void) memcpy(ep, &ehdr, offsetof(Elf64_Ehdr, e_phoff)); - - ep->e_ehsize = sizeof (Elf64_Ehdr); - ep->e_phoff = sizeof (Elf64_Ehdr); - ep->e_phentsize = ehdr.e_phentsize; - ep->e_phnum = phnum; - ep->e_shoff = ep->e_phoff + phnum * ep->e_phentsize; - ep->e_shentsize = sizeof (Elf64_Shdr); - ep->e_shnum = (pltsz == 0) ? 5 : 6; - ep->e_shstrndx = 1; - - /* LINTED - alignment */ - sp = (Elf64_Shdr *)(elfdata + ep->e_shoff); - off = ep->e_shoff + ep->e_shentsize * ep->e_shnum; - - /* - * Copying the program headers directly from the process's - * address space is a little suspect, but since we only - * use them for their address and size values, this is fine. - */ - if (Pread(P, &elfdata[ep->e_phoff], phnum * ep->e_phentsize, - addr + ehdr.e_phoff) != phnum * ep->e_phentsize) { - free(elfdata); - goto bad64; - } - - /* - * The first elf section is always skipped. - */ - sp++; - - /* - * Section Header[1] sh_name: .shstrtab - */ - sp->sh_name = 0; - sp->sh_type = SHT_STRTAB; - sp->sh_flags = SHF_STRINGS; - sp->sh_addr = 0; - sp->sh_offset = off; - sp->sh_size = sizeof (shstr); - sp->sh_link = 0; - sp->sh_info = 0; - sp->sh_addralign = 1; - sp->sh_entsize = 0; - - (void) memcpy(&elfdata[off], shstr, sizeof (shstr)); - off += roundup(sp->sh_size, 8); - sp++; - - /* - * Section Header[2] sh_name: .dynsym - */ - sp->sh_name = 10; - sp->sh_type = SHT_DYNSYM; - sp->sh_flags = SHF_ALLOC; - sp->sh_addr = d[DI_SYMTAB]->d_un.d_ptr; - if (ehdr.e_type == ET_DYN) - sp->sh_addr -= addr; - sp->sh_offset = off; - sp->sh_size = nchain * sizeof (Elf64_Sym); - sp->sh_link = 3; - sp->sh_info = 1; - sp->sh_addralign = 8; - sp->sh_entsize = sizeof (Elf64_Sym); - - if (Pread(P, &elfdata[off], sp->sh_size, - d[DI_SYMTAB]->d_un.d_ptr) != sp->sh_size) { - free(elfdata); - goto bad64; - } - - off += roundup(sp->sh_size, 8); - sp++; - - /* - * Section Header[3] sh_name: .dynstr - */ - sp->sh_name = 18; - sp->sh_type = SHT_STRTAB; - sp->sh_flags = SHF_ALLOC | SHF_STRINGS; - sp->sh_addr = d[DI_STRTAB]->d_un.d_ptr; - if (ehdr.e_type == ET_DYN) - sp->sh_addr -= addr; - sp->sh_offset = off; - sp->sh_size = d[DI_STRSZ]->d_un.d_val; - sp->sh_link = 0; - sp->sh_info = 0; - sp->sh_addralign = 1; - sp->sh_entsize = 0; - - if (Pread(P, &elfdata[off], sp->sh_size, - d[DI_STRTAB]->d_un.d_ptr) != sp->sh_size) { - free(elfdata); - goto bad64; - } - off += roundup(sp->sh_size, 8); - sp++; - - /* - * Section Header[4] sh_name: .dynamic - */ - sp->sh_name = 26; - sp->sh_type = SHT_DYNAMIC; - sp->sh_flags = SHF_WRITE | SHF_ALLOC; - sp->sh_addr = phdr.p_vaddr; - if (ehdr.e_type == ET_DYN) - sp->sh_addr -= addr; - sp->sh_offset = off; - sp->sh_size = phdr.p_filesz; - sp->sh_link = 3; - sp->sh_info = 0; - sp->sh_addralign = 8; - sp->sh_entsize = sizeof (Elf64_Dyn); - - (void) memcpy(&elfdata[off], dp, sp->sh_size); - off += roundup(sp->sh_size, 8); - sp++; - - /* - * Section Header[5] sh_name: .plt - */ - if (pltsz != 0) { - sp->sh_name = 35; - sp->sh_type = SHT_PROGBITS; - sp->sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR; - sp->sh_addr = d[DI_PLTGOT]->d_un.d_ptr; - if (ehdr.e_type == ET_DYN) - sp->sh_addr -= addr; - sp->sh_offset = off; - sp->sh_size = pltsz; - sp->sh_link = 0; - sp->sh_info = 0; - sp->sh_addralign = 8; - sp->sh_entsize = pltentsz; - - if (Pread(P, &elfdata[off], sp->sh_size, - d[DI_PLTGOT]->d_un.d_ptr) != sp->sh_size) { - free(elfdata); - goto bad64; - } - off += roundup(sp->sh_size, 8); - sp++; - } - - free(dp); - goto good; - -bad64: - free(dp); - return (NULL); -#endif /* _LP64 */ - } -good: - if ((elf = elf_memory(elfdata, size)) == NULL) { - free(elfdata); - return (NULL); + elf = fake_elf64(P, fptr, addr, &ehdr, phnum, &phdr); +#endif } - fptr->file_elfmem = elfdata; - return (elf); } @@ -2169,23 +1434,46 @@ byname_cmp(const void *aa, const void *bb) return (strcmp(aname, bname)); } +/* + * Given a symbol index, look up the corresponding symbol from the + * given symbol table. + * + * This function allows the caller to treat the symbol table as a single + * logical entity even though there may be 2 actual ELF symbol tables + * involved. See the comments in Pcontrol.h for details. + */ +static GElf_Sym * +symtab_getsym(sym_tbl_t *symtab, int ndx, GElf_Sym *dst) +{ + /* If index is in range of primary symtab, look it up there */ + if (ndx >= symtab->sym_symn_aux) { + return (gelf_getsym(symtab->sym_data_pri, + ndx - symtab->sym_symn_aux, dst)); + } + + /* Not in primary: Look it up in the auxiliary symtab */ + return (gelf_getsym(symtab->sym_data_aux, ndx, dst)); +} + void optimize_symtab(sym_tbl_t *symtab) { GElf_Sym *symp, *syms; uint_t i, *indexa, *indexb; - Elf_Data *data; size_t symn, strsz, count; - if (symtab == NULL || symtab->sym_data == NULL || + if (symtab == NULL || symtab->sym_data_pri == NULL || symtab->sym_byaddr != NULL) return; - data = symtab->sym_data; symn = symtab->sym_symn; strsz = symtab->sym_strsz; symp = syms = malloc(sizeof (GElf_Sym) * symn); + if (symp == NULL) { + dprintf("optimize_symtab: failed to malloc symbol array"); + return; + } /* * First record all the symbols into a table and count up the ones @@ -2193,7 +1481,7 @@ optimize_symtab(sym_tbl_t *symtab) * the st_name to an illegal value. */ for (i = 0, count = 0; i < symn; i++, symp++) { - if (gelf_getsym(data, i, symp) != NULL && + if (symtab_getsym(symtab, i, symp) != NULL && symp->st_name < strsz && IS_DATA_TYPE(GELF_ST_TYPE(symp->st_info))) count++; @@ -2208,7 +1496,17 @@ optimize_symtab(sym_tbl_t *symtab) symtab->sym_count = count; indexa = symtab->sym_byaddr = calloc(sizeof (uint_t), count); indexb = symtab->sym_byname = calloc(sizeof (uint_t), count); - + if (indexa == NULL || indexb == NULL) { + dprintf( + "optimize_symtab: failed to malloc symbol index arrays"); + symtab->sym_count = 0; + if (indexa != NULL) { /* First alloc succeeded. Free it */ + free(indexa); + symtab->sym_byaddr = NULL; + } + free(syms); + return; + } for (i = 0, symp = syms; i < symn; i++, symp++) { if (symp->st_name < strsz) *indexa++ = *indexb++ = i; @@ -2398,7 +1696,8 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) /* * Now iterate through the section cache in order to locate info - * for the .symtab, .dynsym, .dynamic, .plt, and .SUNW_ctf sections: + * for the .symtab, .dynsym, .SUNW_ldynsym, .dynamic, .plt, + * and .SUNW_ctf sections: */ for (i = 1, cp = cache + 1; i < nshdrs; i++, cp++) { GElf_Shdr *shp = &cp->c_shdr; @@ -2416,22 +1715,37 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) * with an equivalent one. In either case, this * check isn't essential, but it's a good idea. */ - if (symp->sym_data == NULL) { + if (symp->sym_data_pri == NULL) { dprintf("Symbol table found for %s\n", objectfile); - symp->sym_data = cp->c_data; - symp->sym_symn = shp->sh_size / shp->sh_entsize; + symp->sym_data_pri = cp->c_data; + symp->sym_symn += + shp->sh_size / shp->sh_entsize; symp->sym_strs = cache[shp->sh_link].c_data->d_buf; symp->sym_strsz = cache[shp->sh_link].c_data->d_size; - symp->sym_hdr = cp->c_shdr; + symp->sym_hdr_pri = cp->c_shdr; symp->sym_strhdr = cache[shp->sh_link].c_shdr; } else { dprintf("Symbol table already there for %s\n", objectfile); } - + } else if (shp->sh_type == SHT_SUNW_LDYNSYM) { + /* .SUNW_ldynsym section is auxiliary to .dynsym */ + if (fptr->file_dynsym.sym_data_aux == NULL) { + dprintf(".SUNW_ldynsym symbol table" + " found for %s\n", objectfile); + fptr->file_dynsym.sym_data_aux = cp->c_data; + fptr->file_dynsym.sym_symn_aux = + shp->sh_size / shp->sh_entsize; + fptr->file_dynsym.sym_symn += + fptr->file_dynsym.sym_symn_aux; + fptr->file_dynsym.sym_hdr_aux = cp->c_shdr; + } else { + dprintf(".SUNW_ldynsym symbol table already" + " there for %s\n", objectfile); + } } else if (shp->sh_type == SHT_DYNAMIC) { dyn = cp; } else if (strcmp(cp->c_name, ".plt") == 0) { @@ -2777,12 +2091,11 @@ sym_prefer(GElf_Sym *sym1, char *name1, GElf_Sym *sym2, char *name2) static GElf_Sym * sym_by_addr(sym_tbl_t *symtab, GElf_Addr addr, GElf_Sym *symp, uint_t *idp) { - Elf_Data *data = symtab->sym_data; GElf_Sym sym, osym; uint_t i, oid, *byaddr = symtab->sym_byaddr; int min, max, mid, omid, found = 0; - if (data == NULL) + if (symtab->sym_data_pri == NULL || symtab->sym_count == 0) return (NULL); min = 0; @@ -2797,7 +2110,7 @@ sym_by_addr(sym_tbl_t *symtab, GElf_Addr addr, GElf_Sym *symp, uint_t *idp) mid = (max + min) / 2; i = byaddr[mid]; - (void) gelf_getsym(data, i, &sym); + (void) symtab_getsym(symtab, i, &sym); if (addr >= sym.st_value && addr < sym.st_value + sym.st_size && @@ -2829,7 +2142,7 @@ sym_by_addr(sym_tbl_t *symtab, GElf_Addr addr, GElf_Sym *symp, uint_t *idp) break; oid = byaddr[--omid]; - (void) gelf_getsym(data, oid, &osym); + (void) symtab_getsym(symtab, oid, &osym); } while (addr >= osym.st_value && addr < sym.st_value + osym.st_size && osym.st_value == sym.st_value); @@ -2846,12 +2159,12 @@ sym_by_addr(sym_tbl_t *symtab, GElf_Addr addr, GElf_Sym *symp, uint_t *idp) static GElf_Sym * sym_by_name(sym_tbl_t *symtab, const char *name, GElf_Sym *symp, uint_t *idp) { - Elf_Data *data = symtab->sym_data; char *strs = symtab->sym_strs; uint_t i, *byname = symtab->sym_byname; int min, mid, max, cmp; - if (data == NULL || strs == NULL) + if (symtab->sym_data_pri == NULL || strs == NULL || + symtab->sym_count == 0) return (NULL); min = 0; @@ -2861,7 +2174,7 @@ sym_by_name(sym_tbl_t *symtab, const char *name, GElf_Sym *symp, uint_t *idp) mid = (max + min) / 2; i = byname[mid]; - (void) gelf_getsym(data, i, symp); + (void) symtab_getsym(symtab, i, symp); if ((cmp = strcmp(name, strs + symp->st_name)) == 0) { if (idp != NULL) @@ -3013,7 +2326,7 @@ Pxlookup_by_name( lmid != fptr->file_lo->rl_lmident) continue; - if (fptr->file_symtab.sym_data != NULL && + if (fptr->file_symtab.sym_data_pri != NULL && sym_by_name(&fptr->file_symtab, sname, symp, &id)) { if (sip != NULL) { sip->prs_id = id; @@ -3023,7 +2336,7 @@ Pxlookup_by_name( sip->prs_lmid = fptr->file_lo == NULL ? LM_ID_BASE : fptr->file_lo->rl_lmident; } - } else if (fptr->file_dynsym.sym_data != NULL && + } else if (fptr->file_dynsym.sym_data_pri != NULL && sym_by_name(&fptr->file_dynsym, sname, symp, &id)) { if (sip != NULL) { sip->prs_id = id; @@ -3187,7 +2500,6 @@ Psymbol_iter_com(struct ps_prochandle *P, Lmid_t lmid, const char *object_name, map_info_t *mptr; file_info_t *fptr; sym_tbl_t *symtab; - Elf_Data *data; size_t symn; const char *strs; size_t strsz; @@ -3222,14 +2534,10 @@ Psymbol_iter_com(struct ps_prochandle *P, Lmid_t lmid, const char *object_name, si.prs_lmid = fptr->file_lo == NULL ? LM_ID_BASE : fptr->file_lo->rl_lmident; - data = symtab->sym_data; symn = symtab->sym_symn; strs = symtab->sym_strs; strsz = symtab->sym_strsz; - if (data == NULL || strs == NULL) - return (-1); - switch (order) { case PRO_NATURAL: map = NULL; @@ -3247,11 +2555,14 @@ Psymbol_iter_com(struct ps_prochandle *P, Lmid_t lmid, const char *object_name, return (-1); } + if (symtab->sym_data_pri == NULL || strs == NULL || count == 0) + return (-1); + rv = 0; for (i = 0; i < count; i++) { ndx = map == NULL ? i : map[i]; - if (gelf_getsym(data, ndx, &sym) != NULL) { + if (symtab_getsym(symtab, ndx, &sym) != NULL) { uint_t s_bind, s_type, type; if (sym.st_name >= strsz) /* invalid st_name */ diff --git a/usr/src/lib/libproc/common/Psymtab_machelf.h b/usr/src/lib/libproc/common/Psymtab_machelf.h new file mode 100644 index 0000000000..fdf311e8bf --- /dev/null +++ b/usr/src/lib/libproc/common/Psymtab_machelf.h @@ -0,0 +1,48 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _PSYMTAB_MACHELF_H +#define _PSYMTAB_MACHELF_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + + +extern Elf *fake_elf32(struct ps_prochandle *P, file_info_t *fptr, + uintptr_t addr, Elf32_Ehdr *ehdr, uint_t phnum, Elf32_Phdr *phdr); +#ifdef _LP64 +extern Elf *fake_elf64(struct ps_prochandle *P, file_info_t *fptr, + uintptr_t addr, Elf64_Ehdr *ehdr, uint_t phnum, Elf64_Phdr *phdr); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* _PSYMTAB_MACHELF_H */ diff --git a/usr/src/lib/libproc/common/Psymtab_machelf32.c b/usr/src/lib/libproc/common/Psymtab_machelf32.c new file mode 100644 index 0000000000..69a583dfc0 --- /dev/null +++ b/usr/src/lib/libproc/common/Psymtab_machelf32.c @@ -0,0 +1,637 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <memory.h> +#include <sys/sysmacros.h> +#include <sys/machelf.h> + +#include "Pcontrol.h" +#include "Psymtab_machelf.h" + + +/* + * This file contains code for use by Psymtab.c that is compiled once + * for each supported ELFCLASS. + * + * When processing ELF files, it is common to encounter a situation where + * a program with one ELFCLASS (32 or 64-bit) is required to examine a + * file with a different ELFCLASS. For example, the 32-bit linker (ld) may + * be used to link a 64-bit program. The simplest solution to this problem + * is to duplicate each such piece of code, modifying only the data types, + * and to use if statements to select the code to run. The problem with + * doing it that way is that the resulting code is difficult to maintain. + * It is inevitable that the copies will not always get modified identically, + * and will drift apart. The only robust solution is to generate the + * multiple instances of code automatically from a single piece of code. + * + * The solution used within the Solaris linker is to write the code once, + * using the data types defined in sys/machelf.h, and then to compile that + * code twice, once with _ELF64 defined (to generate ELFCLASS64 code) and + * once without (to generate ELFCLASS32). We use the same approach here. + * + * Note that the _ELF64 definition does not refer to the ELFCLASS of + * the resulting code, but rather, to the ELFCLASS of the data it + * examines. By repeating the above double-compilation for both 32-bit + * and 64-bit builds, we end up with 4 instances, which collectively + * can handle any combination of program and ELF data class: + * + * \ Compilation class + * \ 32 64 + * \------------------ + * | + * 32 | X X + * ELF Data Class | + * 64 | X X + */ + + + +/* + * Read data from the specified process and construct an in memory + * image of an ELF file that will let us use libelf for most of the + * work we need to later (e.g. symbol table lookups). This is used + * in cases where no usable on-disk image for the process is available. + * We need sections for the dynsym, dynstr, and plt, and we need + * the program headers from the text section. The former is used in + * Pbuild_file_symtab(); the latter is used in several functions in + * Pcore.c to reconstruct the origin of each mapping from the load + * object that spawned it. + * + * Here are some useful pieces of elf trivia that will help + * to elucidate this code. + * + * All the information we need about the dynstr can be found in these + * two entries in the dynamic section: + * + * DT_STRTAB base of dynstr + * DT_STRSZ size of dynstr + * + * So deciphering the dynstr is pretty straightforward. + * + * The dynsym is a little trickier. + * + * DT_SYMTAB base of dynsym + * DT_SYMENT size of a dynstr entry (Elf{32,64}_Sym) + * DT_HASH base of hash table for dynamic lookups + * + * The DT_SYMTAB entry gives us any easy way of getting to the base + * of the dynsym, but getting the size involves rooting around in the + * dynamic lookup hash table. Here's the layout of the hash table: + * + * +-------------------+ + * | nbucket | All values are 32-bit + * +-------------------+ (Elf32_Word or Elf64_Word) + * | nchain | + * +-------------------+ + * | bucket[0] | + * | . . . | + * | bucket[nbucket-1] | + * +-------------------+ + * | chain[0] | + * | . . . | + * | chain[nchain-1] | + * +-------------------+ + * (figure 5-12 from the SYS V Generic ABI) + * + * Symbols names are hashed into a particular bucket which contains + * an index into the symbol table. Each entry in the symbol table + * has a corresponding entry in the chain table which tells the + * consumer where the next entry in the hash chain is. We can use + * the nchain field to find out the size of the dynsym. + * + * If there is a dynsym present, there may also be an optional + * section called the SUNW_ldynsym that augments the dynsym by + * providing local function symbols. When the Solaris linker lays + * out a file that has both of these sections, it makes sure that + * the data for the two sections is adjacent with the SUNW_ldynsym + * in front. This allows the runtime linker to treat these two + * symbol tables as being a single larger table. There are two + * items in the dynamic section for this: + * + * DT_SUNW_SYMTAB base of the SUNW_ldynsym + * DT_SUNW_SYMSZ total size of SUNW_ldynsym and dynsym + * added together. We can figure out the + * size of the SUNW_ldynsym section by + * subtracting the size of the dynsym + * (described above) from this value. + * + * We can figure out the size of the .plt section, but it takes some + * doing. We need to use the following information: + * + * DT_PLTGOT base of the PLT + * DT_JMPREL base of the PLT's relocation section + * DT_PLTRELSZ size of the PLT's relocation section + * DT_PLTREL type of the PLT's relocation section + * + * We can use the relocation section to figure out the address of the + * last entry and subtract off the value of DT_PLTGOT to calculate + * the size of the PLT. + * + * For more information, check out the System V Generic ABI. + */ + + +/* + * The fake_elfXX() function generated by this file uses the following + * string as the string table for the section names. Since it is critical + * to count correctly, and to improve readability, the SHSTR_NDX_ macros + * supply the proper offset for each name within the string. + */ +static char shstr[] = + ".shstrtab\0.dynsym\0.dynstr\0.dynamic\0.plt\0.SUNW_ldynsym"; + +/* Offsets within shstr for each name */ +#define SHSTR_NDX_shstrtab 0 +#define SHSTR_NDX_dynsym 10 +#define SHSTR_NDX_dynstr 18 +#define SHSTR_NDX_dynamic 26 +#define SHSTR_NDX_plt 35 +#define SHSTR_NDX_SUNW_ldynsym 40 + + +/* + * Section header alignment for 32 and 64-bit ELF files differs + */ +#ifdef _ELF64 +#define SH_ADDRALIGN 8 +#else +#define SH_ADDRALIGN 4 +#endif + +#ifdef _ELF64 +Elf * +fake_elf64(struct ps_prochandle *P, file_info_t *fptr, uintptr_t addr, + Ehdr *ehdr, uint_t phnum, Phdr *phdr) +#else +Elf * +fake_elf32(struct ps_prochandle *P, file_info_t *fptr, uintptr_t addr, + Ehdr *ehdr, uint_t phnum, Phdr *phdr) +#endif +{ + enum { + DI_PLTGOT, + DI_JMPREL, + DI_PLTRELSZ, + DI_PLTREL, + DI_SYMTAB, + DI_HASH, + DI_SYMENT, + DI_STRTAB, + DI_STRSZ, + DI_SUNW_SYMTAB, + DI_SUNW_SYMSZ, + DI_NENT + }; + /* + * Mask of dynamic options that must be present in a well + * formed dynamic section. We need all of these in order to + * put together a complete set of elf sections. They are + * mandatory in both executables and shared objects so if one + * of them is missing, we're in some trouble and should abort. + * The PLT items are expected, but we will let them slide if + * need be. The DI_SUNW_SYM* items are completely optional, so + * we use them if they are present and ignore them otherwise. + */ + const int di_req_mask = (1 << DI_SYMTAB) | (1 << DI_HASH) | + (1 << DI_SYMENT) | (1 << DI_STRTAB) | (1 << DI_STRSZ); + int di_mask = 0; + size_t size = 0; + caddr_t elfdata = NULL; + Elf *elf; + size_t dynsym_size, ldynsym_size; + int dynstr_shndx; + Ehdr *ep; + Shdr *sp; + Dyn *dp; + Dyn *d[DI_NENT] = { 0 }; + uint_t i; + Off off; + size_t pltsz = 0, pltentsz; + + + if (ehdr->e_type == ET_DYN) + phdr->p_vaddr += addr; + + if ((dp = malloc(phdr->p_filesz)) == NULL) + goto bad; + + if (Pread(P, dp, phdr->p_filesz, phdr->p_vaddr) != phdr->p_filesz) + goto bad; + +#ifndef _ELF64 + /* + * Allow librtld_db the opportunity to "fix" the program + * headers, if it needs to, before we process them. + */ + if (P->rap != NULL && ehdr->e_type == ET_DYN) { + rd_fix_phdrs(P->rap, dp, phdr->p_filesz, addr); + } +#endif + + /* + * Iterate over the items in the dynamic section, grabbing + * the address of items we want and saving them in dp[]. + */ + for (i = 0; i < phdr->p_filesz / sizeof (Dyn); i++) { + switch (dp[i].d_tag) { + /* For the .plt section */ + case DT_PLTGOT: + d[DI_PLTGOT] = &dp[i]; + break; + case DT_JMPREL: + d[DI_JMPREL] = &dp[i]; + break; + case DT_PLTRELSZ: + d[DI_PLTRELSZ] = &dp[i]; + break; + case DT_PLTREL: + d[DI_PLTREL] = &dp[i]; + break; + + /* For the .dynsym section */ + case DT_SYMTAB: + d[DI_SYMTAB] = &dp[i]; + di_mask |= (1 << DI_SYMTAB); + break; + case DT_HASH: + d[DI_HASH] = &dp[i]; + di_mask |= (1 << DI_HASH); + break; + case DT_SYMENT: + d[DI_SYMENT] = &dp[i]; + di_mask |= (1 << DI_SYMENT); + break; + case DT_SUNW_SYMTAB: + d[DI_SUNW_SYMTAB] = &dp[i]; + break; + case DT_SUNW_SYMSZ: + d[DI_SUNW_SYMSZ] = &dp[i]; + break; + + /* For the .dynstr section */ + case DT_STRTAB: + d[DI_STRTAB] = &dp[i]; + di_mask |= (1 << DI_STRTAB); + break; + case DT_STRSZ: + d[DI_STRSZ] = &dp[i]; + di_mask |= (1 << DI_STRSZ); + break; + } + } + + /* Ensure all required entries were collected */ + if ((di_mask & di_req_mask) != di_req_mask) { + dprintf("text section missing required dynamic entries\n"); + goto bad; + } + + if (ehdr->e_type == ET_DYN) { + if (d[DI_PLTGOT] != NULL) + d[DI_PLTGOT]->d_un.d_ptr += addr; + if (d[DI_JMPREL] != NULL) + d[DI_JMPREL]->d_un.d_ptr += addr; + d[DI_SYMTAB]->d_un.d_ptr += addr; + d[DI_HASH]->d_un.d_ptr += addr; + d[DI_STRTAB]->d_un.d_ptr += addr; + if (d[DI_SUNW_SYMTAB] != NULL) + d[DI_SUNW_SYMTAB]->d_un.d_ptr += addr; + } + + /* SUNW_ldynsym must be adjacent to dynsym. Ignore if not */ + if ((d[DI_SUNW_SYMTAB] != NULL) && (d[DI_SUNW_SYMSZ] != NULL) && + ((d[DI_SYMTAB]->d_un.d_ptr <= d[DI_SUNW_SYMTAB]->d_un.d_ptr) || + (d[DI_SYMTAB]->d_un.d_ptr >= (d[DI_SUNW_SYMTAB]->d_un.d_ptr + + d[DI_SUNW_SYMSZ]->d_un.d_val)))) { + d[DI_SUNW_SYMTAB] = NULL; + d[DI_SUNW_SYMSZ] = NULL; + } + + /* elf header */ + size = sizeof (Ehdr); + + /* program headers from in-core elf fragment */ + size += phnum * ehdr->e_phentsize; + + /* unused shdr, and .shstrtab section */ + size += sizeof (Shdr); + size += sizeof (Shdr); + size += roundup(sizeof (shstr), SH_ADDRALIGN); + + /* + * .dynsym and .SUNW_ldynsym sections. + * + * The string table section used for the symbol table and + * dynamic sections lies immediately after the dynsym, so the + * presence of SUNW_ldynsym changes the dynstr section index. + */ + if (d[DI_SUNW_SYMTAB] != NULL) { + size += sizeof (Shdr); /* SUNW_ldynsym shdr */ + ldynsym_size = (size_t)d[DI_SUNW_SYMSZ]->d_un.d_val; + dynsym_size = ldynsym_size - (d[DI_SYMTAB]->d_un.d_ptr + - d[DI_SUNW_SYMTAB]->d_un.d_ptr); + ldynsym_size -= dynsym_size; + dynstr_shndx = 4; + } else { + Word nchain; + + if (Pread(P, &nchain, sizeof (nchain), + d[DI_HASH]->d_un.d_ptr + sizeof (nchain)) != + sizeof (nchain)) { + dprintf("Pread of .dynsym at %lx failed\n", + (long)(d[DI_HASH]->d_un.d_val + sizeof (nchain))); + goto bad; + } + dynsym_size = sizeof (Sym) * nchain; + ldynsym_size = 0; + dynstr_shndx = 3; + } + size += sizeof (Shdr) + ldynsym_size + dynsym_size; + + /* .dynstr section */ + size += sizeof (Shdr); + size += roundup(d[DI_STRSZ]->d_un.d_val, SH_ADDRALIGN); + + /* .dynamic section */ + size += sizeof (Shdr); + size += roundup(phdr->p_filesz, SH_ADDRALIGN); + + /* .plt section */ + if (d[DI_PLTGOT] != NULL && d[DI_JMPREL] != NULL && + d[DI_PLTRELSZ] != NULL && d[DI_PLTREL] != NULL) { + uintptr_t penult, ult; + uintptr_t jmprel = d[DI_JMPREL]->d_un.d_ptr; + size_t pltrelsz = d[DI_PLTRELSZ]->d_un.d_val; + + if (d[DI_PLTREL]->d_un.d_val == DT_RELA) { + uint_t ndx = pltrelsz / sizeof (Rela) - 2; + Rela r[2]; + + if (Pread(P, r, sizeof (r), jmprel + + sizeof (r[0]) * ndx) != sizeof (r)) { + dprintf("Pread of DT_RELA failed\n"); + goto bad; + } + + penult = r[0].r_offset; + ult = r[1].r_offset; + + } else if (d[DI_PLTREL]->d_un.d_val == DT_REL) { + uint_t ndx = pltrelsz / sizeof (Rel) - 2; + Rel r[2]; + + if (Pread(P, r, sizeof (r), jmprel + + sizeof (r[0]) * ndx) != sizeof (r)) { + dprintf("Pread of DT_REL failed\n"); + goto bad; + } + + penult = r[0].r_offset; + ult = r[1].r_offset; + } else { + dprintf(".plt: unknown jmprel value\n"); + goto bad; + } + + pltentsz = ult - penult; + + if (ehdr->e_type == ET_DYN) + ult += addr; + + pltsz = ult - d[DI_PLTGOT]->d_un.d_ptr + pltentsz; + + size += sizeof (Shdr); + size += roundup(pltsz, SH_ADDRALIGN); + } + + if ((elfdata = calloc(1, size)) == NULL) + goto bad; + + /* LINTED - alignment */ + ep = (Ehdr *)elfdata; + (void) memcpy(ep, ehdr, offsetof(Ehdr, e_phoff)); + + ep->e_ehsize = sizeof (Ehdr); + ep->e_phoff = sizeof (Ehdr); + ep->e_phentsize = ehdr->e_phentsize; + ep->e_phnum = phnum; + ep->e_shoff = ep->e_phoff + phnum * ep->e_phentsize; + ep->e_shentsize = sizeof (Shdr); + /* + * Plt and SUNW_ldynsym sections are optional. C logical + * binary operators return a 0 or 1 value, so the following + * adds 1 for each optional section present. + */ + ep->e_shnum = 5 + (pltsz != 0) + (d[DI_SUNW_SYMTAB] != NULL); + ep->e_shstrndx = 1; + + /* LINTED - alignment */ + sp = (Shdr *)(elfdata + ep->e_shoff); + off = ep->e_shoff + ep->e_shentsize * ep->e_shnum; + + /* + * Copying the program headers directly from the process's + * address space is a little suspect, but since we only + * use them for their address and size values, this is fine. + */ + if (Pread(P, &elfdata[ep->e_phoff], phnum * ep->e_phentsize, + addr + ehdr->e_phoff) != phnum * ep->e_phentsize) { + dprintf("failed to read program headers\n"); + goto bad; + } + + /* + * The first elf section is always skipped. + */ + sp++; + + /* + * Section Header: .shstrtab + */ + sp->sh_name = SHSTR_NDX_shstrtab; + sp->sh_type = SHT_STRTAB; + sp->sh_flags = SHF_STRINGS; + sp->sh_addr = 0; + sp->sh_offset = off; + sp->sh_size = sizeof (shstr); + sp->sh_link = 0; + sp->sh_info = 0; + sp->sh_addralign = 1; + sp->sh_entsize = 0; + + (void) memcpy(&elfdata[off], shstr, sizeof (shstr)); + off += roundup(sp->sh_size, SH_ADDRALIGN); + sp++; + + /* + * Section Header: .SUNW_ldynsym + */ + if (d[DI_SUNW_SYMTAB] != NULL) { + sp->sh_name = SHSTR_NDX_SUNW_ldynsym; + sp->sh_type = SHT_SUNW_LDYNSYM; + sp->sh_flags = SHF_ALLOC; + sp->sh_addr = d[DI_SUNW_SYMTAB]->d_un.d_ptr; + if (ehdr->e_type == ET_DYN) + sp->sh_addr -= addr; + sp->sh_offset = off; + sp->sh_size = ldynsym_size; + sp->sh_link = dynstr_shndx; + /* Index of 1st global in table that has none == # items */ + sp->sh_info = sp->sh_size / sizeof (Sym); + sp->sh_addralign = SH_ADDRALIGN; + sp->sh_entsize = sizeof (Sym); + + if (Pread(P, &elfdata[off], sp->sh_size, + d[DI_SUNW_SYMTAB]->d_un.d_ptr) != sp->sh_size) { + dprintf("failed to read .SUNW_ldynsym at %lx\n", + (long)d[DI_SUNW_SYMTAB]->d_un.d_ptr); + goto bad; + } + off += sp->sh_size; + /* No need to round up ldynsym data. Dynsym data is same type */ + sp++; + } + + /* + * Section Header: .dynsym + */ + sp->sh_name = SHSTR_NDX_dynsym; + sp->sh_type = SHT_DYNSYM; + sp->sh_flags = SHF_ALLOC; + sp->sh_addr = d[DI_SYMTAB]->d_un.d_ptr; + if (ehdr->e_type == ET_DYN) + sp->sh_addr -= addr; + sp->sh_offset = off; + sp->sh_size = dynsym_size; + sp->sh_link = dynstr_shndx; + sp->sh_info = 1; /* Index of 1st global in table */ + sp->sh_addralign = SH_ADDRALIGN; + sp->sh_entsize = sizeof (Sym); + + if (Pread(P, &elfdata[off], sp->sh_size, + d[DI_SYMTAB]->d_un.d_ptr) != sp->sh_size) { + dprintf("failed to read .dynsym at %lx\n", + (long)d[DI_SYMTAB]->d_un.d_ptr); + goto bad; + } + + off += roundup(sp->sh_size, SH_ADDRALIGN); + sp++; + + /* + * Section Header: .dynstr + */ + sp->sh_name = SHSTR_NDX_dynstr; + sp->sh_type = SHT_STRTAB; + sp->sh_flags = SHF_ALLOC | SHF_STRINGS; + sp->sh_addr = d[DI_STRTAB]->d_un.d_ptr; + if (ehdr->e_type == ET_DYN) + sp->sh_addr -= addr; + sp->sh_offset = off; + sp->sh_size = d[DI_STRSZ]->d_un.d_val; + sp->sh_link = 0; + sp->sh_info = 0; + sp->sh_addralign = 1; + sp->sh_entsize = 0; + + if (Pread(P, &elfdata[off], sp->sh_size, + d[DI_STRTAB]->d_un.d_ptr) != sp->sh_size) { + dprintf("failed to read .dynstr\n"); + goto bad; + } + off += roundup(sp->sh_size, SH_ADDRALIGN); + sp++; + + /* + * Section Header: .dynamic + */ + sp->sh_name = SHSTR_NDX_dynamic; + sp->sh_type = SHT_DYNAMIC; + sp->sh_flags = SHF_WRITE | SHF_ALLOC; + sp->sh_addr = phdr->p_vaddr; + if (ehdr->e_type == ET_DYN) + sp->sh_addr -= addr; + sp->sh_offset = off; + sp->sh_size = phdr->p_filesz; + sp->sh_link = dynstr_shndx; + sp->sh_info = 0; + sp->sh_addralign = SH_ADDRALIGN; + sp->sh_entsize = sizeof (Dyn); + + (void) memcpy(&elfdata[off], dp, sp->sh_size); + off += roundup(sp->sh_size, SH_ADDRALIGN); + sp++; + + /* + * Section Header: .plt + */ + if (pltsz != 0) { + sp->sh_name = SHSTR_NDX_plt; + sp->sh_type = SHT_PROGBITS; + sp->sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR; + sp->sh_addr = d[DI_PLTGOT]->d_un.d_ptr; + if (ehdr->e_type == ET_DYN) + sp->sh_addr -= addr; + sp->sh_offset = off; + sp->sh_size = pltsz; + sp->sh_link = 0; + sp->sh_info = 0; + sp->sh_addralign = SH_ADDRALIGN; + sp->sh_entsize = pltentsz; + + if (Pread(P, &elfdata[off], sp->sh_size, + d[DI_PLTGOT]->d_un.d_ptr) != sp->sh_size) { + dprintf("failed to read .plt\n"); + goto bad; + } + off += roundup(sp->sh_size, SH_ADDRALIGN); + sp++; + } + + free(dp); + if ((elf = elf_memory(elfdata, size)) == NULL) { + free(elfdata); + return (NULL); + } + + fptr->file_elfmem = elfdata; + + return (elf); + +bad: + if (dp != NULL) + free(dp); + if (elfdata != NULL) + free(elfdata); + return (NULL); + + +} diff --git a/usr/src/lib/libproc/common/Psymtab_machelf64.c b/usr/src/lib/libproc/common/Psymtab_machelf64.c new file mode 100644 index 0000000000..d2c2348cea --- /dev/null +++ b/usr/src/lib/libproc/common/Psymtab_machelf64.c @@ -0,0 +1,34 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Defining _ELF64 causes the code in Psymtab_machelf32.c to generate + * the ELFCLASS64 version of the code contained in that file. + */ +#define _ELF64 +#include "Psymtab_machelf32.c" diff --git a/usr/src/lib/libproc/i386/Pisadep.c b/usr/src/lib/libproc/i386/Pisadep.c index f60a2a8fbc..f8334149d7 100644 --- a/usr/src/lib/libproc/i386/Pisadep.c +++ b/usr/src/lib/libproc/i386/Pisadep.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -70,7 +69,7 @@ Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr) if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) && (i = ELF32_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) { - Elf_Data *data = fp->file_dynsym.sym_data; + Elf_Data *data = fp->file_dynsym.sym_data_pri; Elf32_Sym *symp = &(((Elf32_Sym *)data->d_buf)[i]); return (fp->file_dynsym.sym_strs + symp->st_name); diff --git a/usr/src/lib/libproc/sparc/Pisadep.c b/usr/src/lib/libproc/sparc/Pisadep.c index 0c2d35668e..2edf8c024e 100644 --- a/usr/src/lib/libproc/sparc/Pisadep.c +++ b/usr/src/lib/libproc/sparc/Pisadep.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -75,7 +74,7 @@ Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr) if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) && (i = ELF32_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) { - Elf_Data *data = fp->file_dynsym.sym_data; + Elf_Data *data = fp->file_dynsym.sym_data_pri; Elf32_Sym *symp = &(((Elf32_Sym *)data->d_buf)[i]); return (fp->file_dynsym.sym_strs + symp->st_name); diff --git a/usr/src/lib/libproc/sparcv9/Makefile b/usr/src/lib/libproc/sparcv9/Makefile index b74d317152..1e20da114e 100644 --- a/usr/src/lib/libproc/sparcv9/Makefile +++ b/usr/src/lib/libproc/sparcv9/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,12 +19,15 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # +# This is a 64-bit build, and as such needs 64-bit ELF support +CMNOBJS64 = Psymtab_machelf64.o + include ../Makefile.com include ../../Makefile.lib.64 diff --git a/usr/src/lib/libproc/sparcv9/Pisadep.c b/usr/src/lib/libproc/sparcv9/Pisadep.c index 94ca44c9ea..6d7284a939 100644 --- a/usr/src/lib/libproc/sparcv9/Pisadep.c +++ b/usr/src/lib/libproc/sparcv9/Pisadep.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -99,7 +98,7 @@ Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr) if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) && (i = ELF64_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) { - Elf_Data *data = fp->file_dynsym.sym_data; + Elf_Data *data = fp->file_dynsym.sym_data_pri; Elf64_Sym *symp = &(((Elf64_Sym *)data->d_buf)[i]); return (fp->file_dynsym.sym_strs + symp->st_name); @@ -116,7 +115,7 @@ Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr) if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) && (i = ELF32_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) { - Elf_Data *data = fp->file_dynsym.sym_data; + Elf_Data *data = fp->file_dynsym.sym_data_pri; Elf32_Sym *symp = &(((Elf32_Sym *)data->d_buf)[i]); return (fp->file_dynsym.sym_strs + symp->st_name); |