diff options
Diffstat (limited to 'usr/src/lib/libproc/common/Psymtab.c')
-rw-r--r-- | usr/src/lib/libproc/common/Psymtab.c | 133 |
1 files changed, 99 insertions, 34 deletions
diff --git a/usr/src/lib/libproc/common/Psymtab.c b/usr/src/lib/libproc/common/Psymtab.c index c8c00fb761..d3fe42f180 100644 --- a/usr/src/lib/libproc/common/Psymtab.c +++ b/usr/src/lib/libproc/common/Psymtab.c @@ -26,6 +26,7 @@ #pragma ident "%Z%%M% %I% %E% SMI" +#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <stddef.h> @@ -287,15 +288,20 @@ map_iter(const rd_loadobj_t *lop, void *cd) dprintf("encountered rd object at %p\n", (void *)lop->rl_base); - if ((mptr = Paddr2mptr(P, lop->rl_base)) == NULL) + if ((mptr = Paddr2mptr(P, lop->rl_base)) == NULL) { + dprintf("map_iter: base address doesn't match any mapping\n"); return (1); /* Base address does not match any mapping */ + } if ((fptr = mptr->map_file) == NULL && - (fptr = file_info_new(P, mptr)) == NULL) + (fptr = file_info_new(P, mptr)) == NULL) { + dprintf("map_iter: failed to allocate a new file_info_t\n"); return (1); /* Failed to allocate a new file_info_t */ + } if ((fptr->file_lo == NULL) && (fptr->file_lo = malloc(sizeof (rd_loadobj_t))) == NULL) { + dprintf("map_iter: failed to allocate rd_loadobj_t\n"); file_info_free(P, fptr); return (1); /* Failed to allocate rd_loadobj_t */ } @@ -314,6 +320,9 @@ map_iter(const rd_loadobj_t *lop, void *cd) if (Pread_string(P, buf, sizeof (buf), lop->rl_nameaddr) > 0) { if ((fptr->file_lname = strdup(buf)) != NULL) fptr->file_lbase = basename(fptr->file_lname); + } else { + dprintf("map_iter: failed to read string at %p\n", + (void *)lop->rl_nameaddr); } dprintf("loaded rd object %s lmid %lx\n", @@ -341,17 +350,13 @@ map_set(struct ps_prochandle *P, map_info_t *mptr, const char *lname) (void) memset(fptr->file_lo, 0, sizeof (rd_loadobj_t)); fptr->file_lo->rl_base = mptr->map_pmap.pr_vaddr; fptr->file_lo->rl_bend = - mptr->map_pmap.pr_vaddr + mptr->map_pmap.pr_size; + mptr->map_pmap.pr_vaddr + mptr->map_pmap.pr_size; fptr->file_lo->rl_plt_base = fptr->file_plt_base; fptr->file_lo->rl_plt_size = fptr->file_plt_size; - if (fptr->file_lname) { - free(fptr->file_lname); - fptr->file_lname = NULL; - } - - if ((fptr->file_lname = strdup(lname)) != NULL) + if (fptr->file_lname == NULL && + (fptr->file_lname = strdup(lname)) != NULL) fptr->file_lbase = basename(fptr->file_lname); } @@ -385,7 +390,7 @@ load_static_maps(struct ps_prochandle *P) void Pupdate_maps(struct ps_prochandle *P) { - char mapfile[64]; + char mapfile[PATH_MAX]; int mapfd; struct stat statb; prmap_t *Pmap = NULL; @@ -401,7 +406,8 @@ Pupdate_maps(struct ps_prochandle *P) Preadauxvec(P); - (void) sprintf(mapfile, "/proc/%d/map", (int)P->pid); + (void) snprintf(mapfile, sizeof (mapfile), "%s/%d/map", + procfs_path, (int)P->pid); if ((mapfd = open(mapfile, O_RDONLY)) < 0 || fstat(mapfd, &statb) != 0 || statb.st_size < sizeof (prmap_t) || @@ -803,7 +809,8 @@ Preadauxvec(struct ps_prochandle *P) P->nauxv = 0; } - (void) sprintf(auxfile, "/proc/%d/auxv", (int)P->pid); + (void) snprintf(auxfile, sizeof (auxfile), "%s/%d/auxv", + procfs_path, (int)P->pid); if ((fd = open(auxfile, O_RDONLY)) < 0) return; @@ -928,7 +935,7 @@ build_map_symtab(struct ps_prochandle *P, map_info_t *mptr) * fptr->file_map to be set in Pbuild_file_symtab. librtld_db may be * unaware of what's going on in the rare case that a legitimate ELF * file has been mmap(2)ed into the process address space *without* - * the use of dlopen(3x). Why would this happen? See pwdx ... :) + * the use of dlopen(3x). */ if (fptr->file_map == NULL) fptr->file_map = mptr; @@ -1128,6 +1135,11 @@ found_shdr: dyn.d_tag == DT_CHECKSUM) goto found_cksum; } + + /* + * The in-memory ELF has no DT_CHECKSUM section, but we will report it + * as matching the file anyhow. + */ return (0); found_cksum: @@ -1321,7 +1333,7 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr) uint32_t off; size_t pltsz = 0, pltentsz; - if (read_ehdr32(P, &ehdr, &phnum, addr) != 0 || + if ((read_ehdr32(P, &ehdr, &phnum, addr) != 0) || read_dynamic_phdr32(P, &ehdr, phnum, &phdr, addr) != 0) return (NULL); @@ -1337,6 +1349,14 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr) return (NULL); } + /* + * 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) { /* @@ -1422,8 +1442,11 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr) /* .dynsym section */ size += sizeof (Elf32_Shdr); if (Pread(P, &nchain, sizeof (nchain), - d[DI_HASH]->d_un.d_ptr + 4) != 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 */ @@ -1446,8 +1469,10 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr) Elf32_Rela r[2]; if (Pread(P, r, sizeof (r), jmprel + - sizeof (r[0]) * ndx) != sizeof (r)) + 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; @@ -1457,12 +1482,15 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr) Elf32_Rel r[2]; if (Pread(P, r, sizeof (r), jmprel + - sizeof (r[0]) * ndx) != sizeof (r)) + 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; } @@ -1505,6 +1533,7 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr) 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; } @@ -1550,6 +1579,8 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr) 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; } @@ -1575,6 +1606,7 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr) 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); @@ -1620,6 +1652,7 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr) 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); @@ -1768,8 +1801,13 @@ bad32: Elf64_Rela r[2]; if (Pread(P, r, sizeof (r), jmprel + - sizeof (r[0]) * ndx) != sizeof (r)) + 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; @@ -1779,12 +1817,19 @@ bad32: Elf64_Rel r[2]; if (Pread(P, r, sizeof (r), jmprel + - sizeof (r[0]) * ndx) != sizeof (r)) + 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; } @@ -2172,7 +2217,8 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) fptr->file_lname ? fptr->file_lname : fptr->file_pname); } else { (void) snprintf(objectfile, sizeof (objectfile), - "/proc/%d/object/%s", (int)P->pid, fptr->file_pname); + "%s/%d/object/%s", + procfs_path, (int)P->pid, fptr->file_pname); } /* @@ -2203,8 +2249,10 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) elf_getshstrndx(elf, &shstrndx) == 0 || (scn = elf_getscn(elf, shstrndx)) == NULL || (shdata = elf_getdata(scn, NULL)) == NULL) { + int err = elf_errno(); + dprintf("failed to process ELF file %s: %s\n", - objectfile, elf_errmsg(elf_errno())); + objectfile, (err == 0) ? "<null>" : elf_errmsg(err)); if ((elf = fake_elf(P, fptr)) == NULL || elf_kind(elf) != ELF_K_ELF || @@ -2264,14 +2312,22 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) * pointer, and name. We use this for handling sh_link values below. */ for (cp = cache + 1, scn = NULL; scn = elf_nextscn(elf, scn); cp++) { - if (gelf_getshdr(scn, &cp->c_shdr) == NULL) + if (gelf_getshdr(scn, &cp->c_shdr) == NULL) { + dprintf("Pbuild_file_symtab: Failed to get section " + "header\n"); goto bad; /* Failed to get section header */ + } - if ((cp->c_data = elf_getdata(scn, NULL)) == NULL) + if ((cp->c_data = elf_getdata(scn, NULL)) == NULL) { + dprintf("Pbuild_file_symtab: Failed to get section " + "data\n"); goto bad; /* Failed to get section data */ + } - if (cp->c_shdr.sh_name >= shdata->d_size) + if (cp->c_shdr.sh_name >= shdata->d_size) { + dprintf("Pbuild_file_symtab: corrupt section name"); goto bad; /* Corrupt section name */ + } cp->c_name = (const char *)shdata->d_buf + cp->c_shdr.sh_name; } @@ -2286,7 +2342,6 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) if (shp->sh_type == SHT_SYMTAB || shp->sh_type == SHT_DYNSYM) { sym_tbl_t *symp = shp->sh_type == SHT_SYMTAB ? &fptr->file_symtab : &fptr->file_dynsym; - /* * It's possible that the we already got the symbol * table from the core file itself. Either the file @@ -2298,6 +2353,8 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) * check isn't essential, but it's a good idea. */ if (symp->sym_data == 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_strs = @@ -2306,14 +2363,15 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) cache[shp->sh_link].c_data->d_size; symp->sym_hdr = 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_DYNAMIC) { dyn = cp; - } else if (strcmp(cp->c_name, ".plt") == 0) { plt = cp; - } else if (strcmp(cp->c_name, ".SUNW_ctf") == 0) { /* * Skip over bogus CTF sections so they don't come back @@ -2347,8 +2405,8 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) if (fptr->file_etype == ET_DYN) { fptr->file_dyn_base = fptr->file_map->map_pmap.pr_vaddr - fptr->file_map->map_pmap.pr_offset; - dprintf("setting file_dyn_base for %s to %p\n", - objectfile, (void *)fptr->file_dyn_base); + dprintf("setting file_dyn_base for %s to %lx\n", + objectfile, (long)fptr->file_dyn_base); } /* @@ -2371,8 +2429,8 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) */ if (fptr->file_etype == ET_DYN && fptr->file_lo->rl_base != fptr->file_dyn_base) { - dprintf("resetting file_dyn_base for %s to %p\n", - objectfile, (void *)fptr->file_lo->rl_base); + dprintf("resetting file_dyn_base for %s to %lx\n", + objectfile, (long)fptr->file_lo->rl_base); fptr->file_dyn_base = fptr->file_lo->rl_base; } @@ -2408,6 +2466,8 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) for (i = 0; i < ndyn; i++) { if (gelf_getdyn(dyn->c_data, i, &d) != NULL && d.d_tag == DT_JMPREL) { + dprintf("DT_JMPREL is %p\n", + (void *)(uintptr_t)d.d_un.d_ptr); fptr->file_jmp_rel = d.d_un.d_ptr + fptr->file_dyn_base; break; @@ -2533,6 +2593,13 @@ object_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *objname) uint_t i; /* + * If we have no rtld_db, then always treat a request as one for all + * link maps. + */ + if (P->rap == NULL) + lmid = PR_LMID_EVERY; + + /* * First pass: look for exact matches of the entire pathname or * basename (cases 1 and 2 above): */ @@ -2610,10 +2677,8 @@ object_name_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *name) mptr = P->map_exec; else if (name == PR_OBJ_LDSO) mptr = P->map_ldso; - else if (Prd_agent(P) != NULL || P->state == PS_IDLE) - mptr = object_to_map(P, lmid, name); else - mptr = NULL; + mptr = object_to_map(P, lmid, name); return (mptr); } |