summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.c64
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.h1
-rw-r--r--usr/src/lib/libproc/common/Pcore.c102
-rw-r--r--usr/src/lib/libproc/common/Psymtab.c215
-rw-r--r--usr/src/lib/libproc/common/libproc.h2
5 files changed, 271 insertions, 113 deletions
diff --git a/usr/src/lib/libproc/common/Pcontrol.c b/usr/src/lib/libproc/common/Pcontrol.c
index 6cf0c45891..9e3c26fc04 100644
--- a/usr/src/lib/libproc/common/Pcontrol.c
+++ b/usr/src/lib/libproc/common/Pcontrol.c
@@ -55,6 +55,9 @@
#include "P32ton.h"
int _libproc_debug; /* set non-zero to enable debugging printfs */
+int _libproc_no_qsort; /* set non-zero to inhibit sorting */
+ /* of symbol tables */
+
sigset_t blockable_sigs; /* signals to block when we need to be safe */
static int minfd; /* minimum file descriptor returned by dupfd(fd, 0) */
char procfs_path[PATH_MAX] = "/proc";
@@ -93,6 +96,7 @@ void
_libproc_init(void)
{
_libproc_debug = getenv("LIBPROC_DEBUG") != NULL;
+ _libproc_no_qsort = getenv("LIBPROC_NO_QSORT") != NULL;
(void) sigfillset(&blockable_sigs);
(void) sigdelset(&blockable_sigs, SIGKILL);
@@ -359,7 +363,7 @@ Pxcreate(const char *file, /* executable file name */
* to get the information later.
*/
(void) Pread_string(P, execpath, sizeof (execpath),
- (off_t)P->status.pr_lwp.pr_sysarg[0]);
+ (off_t)P->status.pr_lwp.pr_sysarg[0]);
if (path != NULL)
(void) strncpy(path, execpath, len);
/*
@@ -1556,23 +1560,23 @@ prldump(const char *caller, lwpstatus_t *lsp)
break;
case PR_SIGNALLED:
dprintf("%s: SIGNALLED %s\n", caller,
- proc_signame(lsp->pr_what, name, sizeof (name)));
+ proc_signame(lsp->pr_what, name, sizeof (name)));
break;
case PR_FAULTED:
dprintf("%s: FAULTED %s\n", caller,
- proc_fltname(lsp->pr_what, name, sizeof (name)));
+ proc_fltname(lsp->pr_what, name, sizeof (name)));
break;
case PR_SYSENTRY:
dprintf("%s: SYSENTRY %s\n", caller,
- proc_sysname(lsp->pr_what, name, sizeof (name)));
+ proc_sysname(lsp->pr_what, name, sizeof (name)));
break;
case PR_SYSEXIT:
dprintf("%s: SYSEXIT %s\n", caller,
- proc_sysname(lsp->pr_what, name, sizeof (name)));
+ proc_sysname(lsp->pr_what, name, sizeof (name)));
break;
case PR_JOBCONTROL:
dprintf("%s: JOBCONTROL %s\n", caller,
- proc_signame(lsp->pr_what, name, sizeof (name)));
+ proc_signame(lsp->pr_what, name, sizeof (name)));
break;
case PR_SUSPENDED:
dprintf("%s: SUSPENDED\n", caller);
@@ -1884,8 +1888,8 @@ Psetrun(struct ps_prochandle *P,
int sbits = (PR_DSTOP | PR_ISTOP | PR_ASLEEP);
long ctl[1 + /* PCCFAULT */
- 1 + sizeof (siginfo_t)/sizeof (long) + /* PCSSIG/PCCSIG */
- 2 ]; /* PCRUN */
+ 1 + sizeof (siginfo_t)/sizeof (long) + /* PCSSIG/PCCSIG */
+ 2 ]; /* PCRUN */
long *ctlp = ctl;
size_t size;
@@ -2036,7 +2040,7 @@ int
Psetbkpt(struct ps_prochandle *P, uintptr_t address, ulong_t *saved)
{
long ctl[1 + sizeof (priovec_t) / sizeof (long) + /* PCREAD */
- 1 + sizeof (priovec_t) / sizeof (long)]; /* PCWRITE */
+ 1 + sizeof (priovec_t) / sizeof (long)]; /* PCWRITE */
long *ctlp = ctl;
size_t size;
priovec_t *iovp;
@@ -2129,15 +2133,15 @@ execute_bkpt(
ulong_t saved) /* the saved instruction */
{
long ctl[
- 1 + sizeof (sigset_t) / sizeof (long) + /* PCSHOLD */
- 1 + sizeof (fltset_t) / sizeof (long) + /* PCSFAULT */
- 1 + sizeof (priovec_t) / sizeof (long) + /* PCWRITE */
- 2 + /* PCRUN */
- 1 + /* PCWSTOP */
- 1 + /* PCCFAULT */
- 1 + sizeof (priovec_t) / sizeof (long) + /* PCWRITE */
- 1 + sizeof (fltset_t) / sizeof (long) + /* PCSFAULT */
- 1 + sizeof (sigset_t) / sizeof (long)]; /* PCSHOLD */
+ 1 + sizeof (sigset_t) / sizeof (long) + /* PCSHOLD */
+ 1 + sizeof (fltset_t) / sizeof (long) + /* PCSFAULT */
+ 1 + sizeof (priovec_t) / sizeof (long) + /* PCWRITE */
+ 2 + /* PCRUN */
+ 1 + /* PCWSTOP */
+ 1 + /* PCCFAULT */
+ 1 + sizeof (priovec_t) / sizeof (long) + /* PCWRITE */
+ 1 + sizeof (fltset_t) / sizeof (long) + /* PCSFAULT */
+ 1 + sizeof (sigset_t) / sizeof (long)]; /* PCSHOLD */
long *ctlp = ctl;
sigset_t unblock;
size_t size;
@@ -2231,8 +2235,8 @@ Pxecbkpt(struct ps_prochandle *P, ulong_t saved)
Psync(P);
error = execute_bkpt(ctlfd,
- &P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold,
- P->status.pr_lwp.pr_reg[R_PC], saved);
+ &P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold,
+ P->status.pr_lwp.pr_reg[R_PC], saved);
rv = Pstopstatus(P, PCNULL, 0);
if (error != 0) {
@@ -2425,7 +2429,7 @@ Pxecwapt(struct ps_prochandle *P, const prwatch_t *wp)
Psync(P);
error = execute_wapt(ctlfd,
- &P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold, wp);
+ &P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold, wp);
rv = Pstopstatus(P, PCNULL, 0);
if (error != 0) {
@@ -2820,7 +2824,7 @@ retry:
for (i = 0; i < P->core->core_nlwp; i++, lwp = list_prev(lwp)) {
sp = (lwp->lwp_psinfo.pr_sname == 'Z')? NULL :
- &lwp->lwp_status;
+ &lwp->lwp_status;
if ((rv = func(cd, sp, &lwp->lwp_psinfo)) != 0)
break;
}
@@ -3040,9 +3044,9 @@ Lgrab(struct ps_prochandle *P, lwpid_t lwpid, int *perr)
L->lwp_ctlfd = fd;
L->lwp_state =
- ((L->lwp_status.pr_flags & (PR_STOPPED|PR_ISTOP))
- == (PR_STOPPED|PR_ISTOP))?
- PS_STOP : PS_RUN;
+ ((L->lwp_status.pr_flags & (PR_STOPPED|PR_ISTOP))
+ == (PR_STOPPED|PR_ISTOP))?
+ PS_STOP : PS_RUN;
*perr = 0;
(void) mutex_unlock(&P->proc_lock);
@@ -3412,8 +3416,8 @@ Lsetrun(struct ps_lwphandle *L,
int sbits = (PR_DSTOP | PR_ISTOP | PR_ASLEEP);
long ctl[1 + /* PCCFAULT */
- 1 + sizeof (siginfo_t)/sizeof (long) + /* PCSSIG/PCCSIG */
- 2 ]; /* PCRUN */
+ 1 + sizeof (siginfo_t)/sizeof (long) + /* PCSSIG/PCCSIG */
+ 2 ]; /* PCRUN */
long *ctlp = ctl;
size_t size;
@@ -3503,8 +3507,8 @@ Lxecbkpt(struct ps_lwphandle *L, ulong_t saved)
Lsync(L);
error = execute_bkpt(L->lwp_ctlfd,
- &P->status.pr_flttrace, &L->lwp_status.pr_lwphold,
- L->lwp_status.pr_reg[R_PC], saved);
+ &P->status.pr_flttrace, &L->lwp_status.pr_lwphold,
+ L->lwp_status.pr_reg[R_PC], saved);
rv = Lstopstatus(L, PCNULL, 0);
if (error != 0) {
@@ -3539,7 +3543,7 @@ Lxecwapt(struct ps_lwphandle *L, const prwatch_t *wp)
Lsync(L);
error = execute_wapt(L->lwp_ctlfd,
- &P->status.pr_flttrace, &L->lwp_status.pr_lwphold, wp);
+ &P->status.pr_flttrace, &L->lwp_status.pr_lwphold, wp);
rv = Lstopstatus(L, PCNULL, 0);
if (error != 0) {
diff --git a/usr/src/lib/libproc/common/Pcontrol.h b/usr/src/lib/libproc/common/Pcontrol.h
index 5a4d606c9d..b195db3b63 100644
--- a/usr/src/lib/libproc/common/Pcontrol.h
+++ b/usr/src/lib/libproc/common/Pcontrol.h
@@ -263,6 +263,7 @@ extern char *Pfindexec(struct ps_prochandle *, const char *,
int (*)(const char *, void *), void *);
extern int getlwpstatus(struct ps_prochandle *, lwpid_t, lwpstatus_t *);
int Pstopstatus(struct ps_prochandle *, long, uint32_t);
+extern file_info_t *file_info_new(struct ps_prochandle *, map_info_t *);
extern int Padd_mapping(struct ps_prochandle *, off64_t, file_info_t *,
prmap_t *);
diff --git a/usr/src/lib/libproc/common/Pcore.c b/usr/src/lib/libproc/common/Pcore.c
index b4cfea717a..ca109c8158 100644
--- a/usr/src/lib/libproc/common/Pcore.c
+++ b/usr/src/lib/libproc/common/Pcore.c
@@ -1382,29 +1382,28 @@ core_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P)
return (1); /* No mapping; advance to next mapping */
}
- if ((fp = mp->map_file) == NULL) {
- if ((fp = malloc(sizeof (file_info_t))) == NULL) {
- P->core->core_errno = errno;
- dprintf("failed to malloc mapping data\n");
- return (0); /* Abort */
- }
-
- (void) memset(fp, 0, sizeof (file_info_t));
-
- list_link(fp, &P->file_head);
- mp->map_file = fp;
- P->num_files++;
-
- fp->file_ref = 1;
- fp->file_fd = -1;
+ /*
+ * Create a new file_info_t for this mapping, and therefore for
+ * this load object.
+ *
+ * If there's an ELF header at the beginning of this mapping,
+ * file_info_new() will try to use its section headers to
+ * identify any other mappings that belong to this load object.
+ */
+ if ((fp = mp->map_file) == NULL &&
+ (fp = file_info_new(P, mp)) == NULL) {
+ P->core->core_errno = errno;
+ dprintf("failed to malloc mapping data\n");
+ return (0); /* Abort */
}
+ fp->file_map = mp;
+ /* Create a local copy of the load object representation */
if ((fp->file_lo = malloc(sizeof (rd_loadobj_t))) == NULL) {
P->core->core_errno = errno;
dprintf("failed to malloc mapping data\n");
return (0); /* Abort */
}
-
*fp->file_lo = *rlp;
if (fp->file_lname == NULL &&
@@ -1444,51 +1443,60 @@ core_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P)
if (fp->file_lname != NULL)
fp->file_lbase = basename(fp->file_lname);
- /*
- * Associate the file and the mapping, and attempt to build
- * a symbol table for this file.
- */
- (void) strcpy(fp->file_pname, mp->map_pmap.pr_mapname);
- fp->file_map = mp;
-
- Pbuild_file_symtab(P, fp);
-
- if (fp->file_elf == NULL) {
- dprintf("core_iter_mapping: no symtab - going to next\n");
- return (1); /* No symbol table; advance to next mapping */
- }
+ /* Associate the file and the mapping. */
+ (void) strncpy(fp->file_pname, mp->map_pmap.pr_mapname, PRMAPSZ);
+ fp->file_pname[PRMAPSZ - 1] = '\0';
/*
- * Locate the start of a data segment associated with this file.
- * Starting with that data segment, name all mappings that
- * fall within this file's address range after the file and
- * establish their mp->map_file links.
+ * If no section headers were available then we'll have to
+ * identify this load object's other mappings with what we've
+ * got: the start and end of the object's corresponding
+ * address space.
*/
- if ((mp = core_find_data(P, fp->file_elf, fp->file_lo)) != NULL) {
- dprintf("found data for %s at %p (pr_offset 0x%llx)\n",
- fp->file_pname, (void *)fp->file_lo->rl_data_base,
- mp->map_pmap.pr_offset);
+ if (fp->file_saddrs == NULL) {
+ for (mp = fp->file_map + 1; mp < P->mappings + P->map_count &&
+ mp->map_pmap.pr_vaddr < rlp->rl_bend; mp++) {
- for (; mp < P->mappings + P->map_count; mp++) {
- if (mp->map_pmap.pr_vaddr > fp->file_lo->rl_bend)
- break;
if (mp->map_file == NULL) {
- dprintf("%s: associating segment at %p\n",
+ dprintf("core_iter_mapping %s: associating "
+ "segment at %p\n",
fp->file_pname,
(void *)mp->map_pmap.pr_vaddr);
mp->map_file = fp;
fp->file_ref++;
} else {
- dprintf("%s: segment at %p already associated "
- "with %s\n", fp->file_pname,
+ dprintf("core_iter_mapping %s: segment at "
+ "%p already associated with %s\n",
+ fp->file_pname,
(void *)mp->map_pmap.pr_vaddr,
- mp->map_file->file_pname);
+ (mp == fp->file_map ? "this file" :
+ mp->map_file->file_pname));
}
+ }
+ }
- if (!(mp->map_pmap.pr_mflags & MA_BREAK))
- (void) strcpy(mp->map_pmap.pr_mapname,
- fp->file_pname);
+ /* Ensure that all this file's mappings are named. */
+ for (mp = fp->file_map; mp < P->mappings + P->map_count &&
+ mp->map_file == fp; mp++) {
+ if (mp->map_pmap.pr_mapname[0] == '\0' &&
+ !(mp->map_pmap.pr_mflags & MA_BREAK)) {
+ (void) strncpy(mp->map_pmap.pr_mapname, fp->file_pname,
+ PRMAPSZ);
+ mp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
}
+ }
+
+ /* Attempt to build a symbol table for this file. */
+ Pbuild_file_symtab(P, fp);
+ if (fp->file_elf == NULL)
+ dprintf("core_iter_mapping: no symtab for %s\n",
+ fp->file_pname);
+
+ /* Locate the start of a data segment associated with this file. */
+ if ((mp = core_find_data(P, fp->file_elf, fp->file_lo)) != NULL) {
+ dprintf("found data for %s at %p (pr_offset 0x%llx)\n",
+ fp->file_pname, (void *)fp->file_lo->rl_data_base,
+ mp->map_pmap.pr_offset);
} else {
dprintf("core_iter_mapping: no data found for %s\n",
fp->file_pname);
diff --git a/usr/src/lib/libproc/common/Psymtab.c b/usr/src/lib/libproc/common/Psymtab.c
index 35107c546b..0b98622759 100644
--- a/usr/src/lib/libproc/common/Psymtab.c
+++ b/usr/src/lib/libproc/common/Psymtab.c
@@ -171,13 +171,13 @@ get_saddrs(struct ps_prochandle *P, uintptr_t ehdr_start, uint_t *n)
/*
* Allocation function for a new file_info_t
*/
-static file_info_t *
+file_info_t *
file_info_new(struct ps_prochandle *P, map_info_t *mptr)
{
file_info_t *fptr;
map_info_t *mp;
- uintptr_t addr;
- uint_t i, j;
+ uintptr_t mstart, mend, sstart, send;
+ uint_t i;
if ((fptr = calloc(1, sizeof (file_info_t))) == NULL)
return (NULL);
@@ -201,22 +201,38 @@ file_info_new(struct ps_prochandle *P, map_info_t *mptr)
&fptr->file_nsaddrs)) == NULL)
return (fptr);
- i = j = 0;
mp = P->mappings;
- while (j < P->map_count && i < fptr->file_nsaddrs) {
- addr = fptr->file_saddrs[i];
- if (addr >= mp->map_pmap.pr_vaddr &&
- addr < mp->map_pmap.pr_vaddr + mp->map_pmap.pr_size &&
- mp->map_file == NULL) {
- mp->map_file = fptr;
- fptr->file_ref++;
- }
+ i = 0;
+ while (mp < P->mappings + P->map_count && i < fptr->file_nsaddrs) {
- if (addr < mp->map_pmap.pr_vaddr + mp->map_pmap.pr_size) {
- i++;
+ /* Calculate the start and end of the mapping and section */
+ mstart = mp->map_pmap.pr_vaddr;
+ mend = mp->map_pmap.pr_vaddr + mp->map_pmap.pr_size;
+ sstart = fptr->file_saddrs[i];
+ send = fptr->file_saddrs[i + 1];
+
+ if (mend <= sstart) {
+ /* This mapping is below the current section */
+ mp++;
+ } else if (mstart >= send) {
+ /* This mapping is above the current section */
+ i += 2;
} else {
+ /* This mapping overlaps the current section */
+ if (mp->map_file == NULL) {
+ dprintf("file_info_new: associating "
+ "segment at %p\n",
+ (void *)mp->map_pmap.pr_vaddr);
+ mp->map_file = fptr;
+ fptr->file_ref++;
+ } else {
+ dprintf("file_info_new: segment at %p "
+ "already associated with %s\n",
+ (void *)mp->map_pmap.pr_vaddr,
+ (mp == mptr ? "this file" :
+ mp->map_file->file_pname));
+ }
mp++;
- j++;
}
}
@@ -596,9 +612,17 @@ Paddr_to_text_map(struct ps_prochandle *P, uintptr_t addr)
file_info_t *fptr = build_map_symtab(P, mptr);
const prmap_t *pmp = &mptr->map_pmap;
+ /*
+ * Assume that if rl_data_base is NULL, it means that no
+ * data section was found for this load object, and that
+ * a section must be text. Otherwise, a section will be
+ * text unless it ends above the start of the data
+ * section.
+ */
if (fptr != NULL && fptr->file_lo != NULL &&
- fptr->file_lo->rl_base >= pmp->pr_vaddr &&
- fptr->file_lo->rl_base < pmp->pr_vaddr + pmp->pr_size)
+ (fptr->file_lo->rl_data_base == NULL ||
+ pmp->pr_vaddr + pmp->pr_size <
+ fptr->file_lo->rl_data_base))
return (pmp);
}
@@ -906,6 +930,7 @@ is_mapping_in_file(struct ps_prochandle *P, map_info_t *mptr, file_info_t *fptr)
prmap_t *pmap = &mptr->map_pmap;
rd_loadobj_t *lop = fptr->file_lo;
uint_t i;
+ uintptr_t mstart, mend, sstart, send;
/*
* We can get for free the start address of the text and data
@@ -927,7 +952,7 @@ is_mapping_in_file(struct ps_prochandle *P, map_info_t *mptr, file_info_t *fptr)
* only one will be seen to enclose that section's start address.
* Thus, to be rigorous, we ask not whether this mapping encloses
* the start of a section, but whether there exists a section that
- * encloses the start of this mapping.
+ * overlaps this mapping.
*
* If we don't already have the section addresses, and we successfully
* get them, then we cache them in case we come here again.
@@ -936,10 +961,14 @@ is_mapping_in_file(struct ps_prochandle *P, map_info_t *mptr, file_info_t *fptr)
(fptr->file_saddrs = get_saddrs(P,
fptr->file_map->map_pmap.pr_vaddr, &fptr->file_nsaddrs)) == NULL)
return (0);
+
+ mstart = mptr->map_pmap.pr_vaddr;
+ mend = mptr->map_pmap.pr_vaddr + mptr->map_pmap.pr_size;
for (i = 0; i < fptr->file_nsaddrs; i += 2) {
- /* Does this section enclose the start of the mapping? */
- if (fptr->file_saddrs[i] <= pmap->pr_vaddr &&
- fptr->file_saddrs[i + 1] > pmap->pr_vaddr)
+ /* Does this section overlap the mapping? */
+ sstart = fptr->file_saddrs[i];
+ send = fptr->file_saddrs[i + 1];
+ if (!(mend <= sstart || mstart >= send))
return (1);
}
@@ -1513,18 +1542,31 @@ optimize_symtab(sym_tbl_t *symtab)
}
/*
- * Sort the two tables according to the appropriate criteria.
+ * Sort the two tables according to the appropriate criteria,
+ * unless the user has overridden this behaviour.
+ *
+ * An example where we might not sort the tables is the relatively
+ * unusual case of a process with very large symbol tables in which
+ * we perform few lookups. In such a case the total time would be
+ * dominated by the sort. It is difficult to determine a priori
+ * how many lookups an arbitrary client will perform, and
+ * hence whether the symbol tables should be sorted. We therefore
+ * sort the tables by default, but provide the user with a
+ * "chicken switch" in the form of the LIBPROC_NO_QSORT
+ * environment variable.
*/
- (void) mutex_lock(&sort_mtx);
- sort_strs = symtab->sym_strs;
- sort_syms = syms;
+ if (!_libproc_no_qsort) {
+ (void) mutex_lock(&sort_mtx);
+ sort_strs = symtab->sym_strs;
+ sort_syms = syms;
- qsort(symtab->sym_byaddr, count, sizeof (uint_t), byaddr_cmp);
- qsort(symtab->sym_byname, count, sizeof (uint_t), byname_cmp);
+ qsort(symtab->sym_byaddr, count, sizeof (uint_t), byaddr_cmp);
+ qsort(symtab->sym_byname, count, sizeof (uint_t), byname_cmp);
- sort_strs = NULL;
- sort_syms = NULL;
- (void) mutex_unlock(&sort_mtx);
+ sort_strs = NULL;
+ sort_syms = NULL;
+ (void) mutex_unlock(&sort_mtx);
+ }
free(syms);
}
@@ -2084,12 +2126,11 @@ sym_prefer(GElf_Sym *sym1, char *name1, GElf_Sym *sym2, char *name2)
}
/*
- * Look up a symbol by address in the specified symbol table.
- * Adjustment to 'addr' must already have been made for the
- * offset of the symbol if this is a dynamic library symbol table.
+ * Use a binary search to do the work of sym_by_addr().
*/
static GElf_Sym *
-sym_by_addr(sym_tbl_t *symtab, GElf_Addr addr, GElf_Sym *symp, uint_t *idp)
+sym_by_addr_binary(sym_tbl_t *symtab, GElf_Addr addr, GElf_Sym *symp,
+ uint_t *idp)
{
GElf_Sym sym, osym;
uint_t i, oid, *byaddr = symtab->sym_byaddr;
@@ -2154,10 +2195,70 @@ sym_by_addr(sym_tbl_t *symtab, GElf_Addr addr, GElf_Sym *symp, uint_t *idp)
}
/*
- * Look up a symbol by name in the specified symbol table.
+ * Use a linear search to do the work of sym_by_addr().
*/
static GElf_Sym *
-sym_by_name(sym_tbl_t *symtab, const char *name, GElf_Sym *symp, uint_t *idp)
+sym_by_addr_linear(sym_tbl_t *symtab, GElf_Addr addr, GElf_Sym *symbolp,
+ uint_t *idp)
+{
+ size_t symn = symtab->sym_symn;
+ char *strs = symtab->sym_strs;
+ GElf_Sym sym, *symp = NULL;
+ GElf_Sym osym, *osymp = NULL;
+ int i, id;
+
+ if (symtab->sym_data_pri == NULL || symn == 0 || strs == NULL)
+ return (NULL);
+
+ for (i = 0; i < symn; i++) {
+ if ((symp = symtab_getsym(symtab, i, &sym)) != NULL) {
+ if (addr >= sym.st_value &&
+ addr < sym.st_value + sym.st_size) {
+ if (osymp)
+ symp = sym_prefer(
+ symp, strs + symp->st_name,
+ osymp, strs + osymp->st_name);
+ if (symp != osymp) {
+ osym = sym;
+ osymp = &osym;
+ id = i;
+ }
+ }
+ }
+ }
+ if (osymp) {
+ *symbolp = osym;
+ if (idp)
+ *idp = id;
+ return (symbolp);
+ }
+ return (NULL);
+}
+
+/*
+ * Look up a symbol by address in the specified symbol table.
+ * Adjustment to 'addr' must already have been made for the
+ * offset of the symbol if this is a dynamic library symbol table.
+ *
+ * Use a linear or a binary search depending on whether or not we
+ * chose to sort the table in optimize_symtab().
+ */
+static GElf_Sym *
+sym_by_addr(sym_tbl_t *symtab, GElf_Addr addr, GElf_Sym *symp, uint_t *idp)
+{
+ if (_libproc_no_qsort) {
+ return (sym_by_addr_linear(symtab, addr, symp, idp));
+ } else {
+ return (sym_by_addr_binary(symtab, addr, symp, idp));
+ }
+}
+
+/*
+ * Use a binary search to do the work of sym_by_name().
+ */
+static GElf_Sym *
+sym_by_name_binary(sym_tbl_t *symtab, const char *name, GElf_Sym *symp,
+ uint_t *idp)
{
char *strs = symtab->sym_strs;
uint_t i, *byname = symtab->sym_byname;
@@ -2192,6 +2293,48 @@ sym_by_name(sym_tbl_t *symtab, const char *name, GElf_Sym *symp, uint_t *idp)
}
/*
+ * Use a linear search to do the work of sym_by_name().
+ */
+static GElf_Sym *
+sym_by_name_linear(sym_tbl_t *symtab, const char *name, GElf_Sym *symp,
+ uint_t *idp)
+{
+ size_t symn = symtab->sym_symn;
+ char *strs = symtab->sym_strs;
+ int i;
+
+ if (symtab->sym_data_pri == NULL || symn == 0 || strs == NULL)
+ return (NULL);
+
+ for (i = 0; i < symn; i++) {
+ if (symtab_getsym(symtab, i, symp) &&
+ strcmp(name, strs + symp->st_name) == 0) {
+ if (idp)
+ *idp = i;
+ return (symp);
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * Look up a symbol by name in the specified symbol table.
+ *
+ * Use a linear or a binary search depending on whether or not we
+ * chose to sort the table in optimize_symtab().
+ */
+static GElf_Sym *
+sym_by_name(sym_tbl_t *symtab, const char *name, GElf_Sym *symp, uint_t *idp)
+{
+ if (_libproc_no_qsort) {
+ return (sym_by_name_linear(symtab, name, symp, idp));
+ } else {
+ return (sym_by_name_binary(symtab, name, symp, idp));
+ }
+}
+
+/*
* Search the process symbol tables looking for a symbol whose
* value to value+size contain the address specified by addr.
* Return values are:
diff --git a/usr/src/lib/libproc/common/libproc.h b/usr/src/lib/libproc/common/libproc.h
index d12fda05e3..07c6ee1622 100644
--- a/usr/src/lib/libproc/common/libproc.h
+++ b/usr/src/lib/libproc/common/libproc.h
@@ -82,6 +82,8 @@ struct ps_prochandle;
struct ps_lwphandle;
extern int _libproc_debug; /* set non-zero to enable debugging fprintfs */
+extern int _libproc_no_qsort; /* set non-zero to inhibit sorting */
+ /* of symbol tables */
#if defined(__sparc)
#define R_RVAL1 R_O0 /* register holding a function return value */