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