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