8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / cmd / sgs / librtld_db / demo / common / syms.c
blob3805c642e0d336b30189f2c8dd87fab6ed2b21f9
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <stdio.h>
27 #include <string.h>
28 #include <libelf.h>
29 #include "rdb.h"
32 * Given a symbol index, look up the corresponding symbol from the
33 * given symbol table.
35 * This function allows the caller to treat the symbol table as a single
36 * logical entity even though there may be 2 actual ELF symbol tables
37 * involved. See the comments in Pcontrol.h for details.
39 static GElf_Sym *
40 symtab_getsym(sym_tbl_t *symtab, int ndx, GElf_Sym *dst)
42 /* If index is in range of primary symtab, look it up there */
43 if (ndx >= symtab->st_symn_aux) {
44 return (gelf_getsym(symtab->st_syms_pri,
45 ndx - symtab->st_symn_aux, dst));
48 /* Not in primary: Look it up in the auxiliary symtab */
49 return (gelf_getsym(symtab->st_syms_aux, ndx, dst));
52 retc_t
53 str_map_sym(const char *symname, map_info_t *mp, GElf_Sym *symptr, char **str)
55 sym_tbl_t *symp;
56 char *strs;
57 int i;
59 if (mp->mi_symtab.st_syms_pri)
60 symp = &(mp->mi_symtab);
61 else if (mp->mi_dynsym.st_syms_pri)
62 symp = &(mp->mi_dynsym);
63 else
64 return (RET_FAILED);
66 strs = symp->st_strs;
68 for (i = 0; i < (int)symp->st_symn; i++) {
69 GElf_Sym sym;
71 if (symtab_getsym(symp, i, &sym) == NULL) {
72 (void) printf("symtab_getsym(): %s\n", elf_errmsg(-1));
73 return (RET_FAILED);
76 if (sym.st_name == 0)
77 continue;
78 if ((sym.st_shndx == SHN_UNDEF) ||
79 (strcmp(strs + sym.st_name, symname) != 0))
80 continue;
81 *symptr = sym;
82 if (str != NULL)
83 *str = (char *)strs + symptr->st_name;
84 if ((mp->mi_flags & FLG_MI_EXEC) == 0)
85 symptr->st_value += (GElf_Addr)(mp->mi_addr);
86 return (RET_OK);
89 return (RET_FAILED);
93 * If two syms are of equal value this routine will
94 * favor one over the other based off of it's symbol
95 * type.
97 static GElf_Sym
98 sym_swap(GElf_Sym * s1, GElf_Sym * s2)
100 int t1 = GELF_ST_TYPE(s1->st_info);
101 int t2 = GELF_ST_TYPE(s2->st_info);
103 if ((t1 == STT_FUNC) || (t2 == STT_FUNC)) {
104 if (t1 == STT_FUNC)
105 return (*s1);
106 return (*s2);
109 if ((t1 == STT_OBJECT) || (t2 == STT_OBJECT)) {
110 if (t1 == STT_OBJECT)
111 return (*s1);
112 return (*s2);
115 if ((t1 == STT_OBJECT) || (t2 == STT_OBJECT)) {
116 if (t1 == STT_OBJECT)
117 return (*s1);
118 return (*s2);
120 return (*s1);
123 static retc_t
124 addr_map_sym(map_info_t *mp, ulong_t addr, GElf_Sym *symptr, char **str)
126 sym_tbl_t *symp;
127 GElf_Sym sym;
128 GElf_Sym *symr = NULL;
129 GElf_Sym *lsymr = NULL;
130 GElf_Sym rsym;
131 GElf_Sym lsym;
132 ulong_t baseaddr = 0;
133 int i;
135 if ((mp->mi_flags & FLG_MI_EXEC) == 0)
136 baseaddr = (ulong_t)mp->mi_addr;
138 if (mp->mi_symtab.st_syms_pri)
139 symp = &(mp->mi_symtab);
140 else if (mp->mi_dynsym.st_syms_pri)
141 symp = &(mp->mi_dynsym);
142 else
143 return (RET_FAILED);
146 * normalize address
148 addr -= baseaddr;
149 for (i = 0; i < (int)symp->st_symn; i++) {
150 ulong_t svalue;
152 if (symtab_getsym(symp, i, &sym) == NULL) {
153 (void) printf("symtab_getsym(): %s\n", elf_errmsg(-1));
154 return (RET_FAILED);
156 if ((sym.st_name == 0) || (sym.st_shndx == SHN_UNDEF))
157 continue;
159 svalue = (ulong_t)sym.st_value;
161 if (svalue <= addr) {
163 * track both the best local and best
164 * global fit for this address. Later
165 * we will favor the global over the local
167 if ((GELF_ST_BIND(sym.st_info) == STB_LOCAL) &&
168 ((lsymr == NULL) ||
169 (svalue >= (ulong_t)lsymr->st_value))) {
170 if (lsymr && (lsymr->st_value == svalue))
171 *lsymr = sym_swap(lsymr, &sym);
172 else {
173 lsymr = &lsym;
174 *lsymr = sym;
176 } else if ((symr == NULL) ||
177 (svalue >= (ulong_t)symr->st_value)) {
178 if (symr && (symr->st_value == svalue))
179 *symr = sym_swap(symr, &sym);
180 else {
181 symr = &rsym;
182 *symr = sym;
187 if ((symr == NULL) && (lsymr == NULL))
188 return (RET_FAILED);
190 if (lsymr) {
192 * If a possible local symbol was found should
193 * we use it.
195 if (symr && (lsymr->st_value > symr->st_value))
196 symr = lsymr;
197 else if (symr == NULL)
198 symr = lsymr;
201 *symptr = *symr;
202 *str = (char *)(symp->st_strs + symptr->st_name);
203 symptr->st_value += baseaddr;
204 return (RET_OK);
207 retc_t
208 addr_to_sym(struct ps_prochandle *ph, ulong_t addr,
209 GElf_Sym *symp, char **str)
211 map_info_t *mip;
213 if ((mip = addr_to_map(ph, addr)) == NULL)
214 return (RET_FAILED);
216 return (addr_map_sym(mip, addr, symp, str));
219 retc_t
220 str_to_sym(struct ps_prochandle *ph, const char *name, GElf_Sym *symp)
222 map_info_t *mip;
224 if (ph->pp_lmaplist.ml_head == NULL) {
225 if (str_map_sym(name, &(ph->pp_ldsomap), symp, NULL) == RET_OK)
226 return (RET_OK);
228 return (str_map_sym(name, &(ph->pp_execmap), symp, NULL));
231 for (mip = ph->pp_lmaplist.ml_head; mip; mip = mip->mi_next)
232 if (str_map_sym(name, mip, symp, NULL) == RET_OK)
233 return (RET_OK);
235 return (RET_FAILED);