]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/symbols.c
0d1b3065b904ea4cd606532d459b73af81a76b24
[apple/xnu.git] / osfmk / kern / symbols.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*-
30 * Copyright (c) 2004 Networks Associates Technology, Inc.
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 */
54
55 #include <mach/mach_types.h>
56 #include <mach-o/mach_header.h>
57 #include <mach-o/nlist.h>
58 #include <mach/kmod.h>
59 #include <libsa/stdlib.h>
60 #include <kern/misc_protos.h>
61
62 static const struct nlist *
63 syms_find(const struct nlist *syms, int nsyms, vm_offset_t addr,
64 vm_offset_t *ofs)
65 {
66 const struct nlist *best = 0;
67 int i;
68
69 for (i = 0; i < nsyms; i++) {
70 int st = syms[i].n_type & N_TYPE;
71
72 if (st == N_SECT || st == N_ABS) {
73 if (syms[i].n_value == addr) {
74 *ofs = 0;
75 return (syms+i);
76 }
77 else if (syms[i].n_value < addr &&
78 (best == 0 ||
79 (syms[i].n_value > best->n_value))) {
80 *ofs = addr - syms[i].n_value;
81 best = syms+i;
82 }
83 }
84 }
85
86 return (best);
87 }
88
89 static const char *
90 syms_getname(const struct symtab_command *sc, const char *ss,
91 const struct nlist *sp)
92 {
93 if (sp->n_un.n_strx == 0)
94 return ("");
95 else if ((unsigned)sp->n_un.n_strx > sc->strsize)
96 return ("*bad string*");
97 else
98 return (ss + sp->n_un.n_strx);
99 }
100
101 /* Search for a symbol in the given object file, which must either
102 * have a LINKEDIT segment or have been read directly into memory
103 * and isload passed as 1.
104
105 * If mh has a LINKEDIT segment, an object file loaded in the normal
106 * way will have the symbol table available at the load address.
107 */
108
109 static const char *
110 syms_nameforaddr1(const struct mach_header *mh, int isload,
111 vm_offset_t addr, vm_offset_t *ofs)
112 {
113 const struct symtab_command *sc = NULL;
114 const struct segment_command *le = NULL;
115 const struct segment_command *p;
116 const struct segment_command *sym = NULL;
117 const struct nlist *syms;
118 const char *strings;
119 unsigned int i;
120
121 p = (const struct segment_command *) (&mh[1]);
122
123 for (i = 0; i < mh->ncmds; i++) {
124 if (p->cmd == LC_SYMTAB)
125 sc = (const struct symtab_command *) p;
126 else if (p->cmd == LC_SEGMENT &&
127 !strncmp(p->segname, "__LINKEDIT", sizeof(p->segname)))
128 le = p;
129
130 /* only try to find a name for an address that came from
131 * a text section.
132 */
133 if (p->cmd == LC_SEGMENT &&
134 addr >= p->vmaddr && addr < p->vmaddr + p->vmsize) {
135 unsigned int j;
136
137 const struct section *sp = (const struct section *)
138 (((const char *) p) + sizeof(struct segment_command));
139
140 for (j = 0; j < p->nsects; j++) {
141 if (addr >= sp[j].addr &&
142 addr < sp[j].addr + sp[j].size &&
143 !strncmp (sp[j].sectname, "__text",
144 sizeof(sp[j].sectname))) {
145 sym = p;
146 break;
147 }
148 }
149 }
150 p = (const struct segment_command *)
151 (((const char *) p) + p->cmdsize);
152 }
153
154 if (sc == 0 || sym == NULL)
155 return (NULL);
156
157 if (!isload) {
158 syms = (const struct nlist *) (((const char *) mh) + sc->symoff);
159 strings = ((const char *) mh) + sc->stroff;
160 }
161 else if (le) {
162 syms = (const struct nlist *) le->vmaddr;
163 strings = (const char *)
164 (le->vmaddr + sc->nsyms * sizeof(struct nlist));
165 } else
166 return (NULL);
167
168 const struct nlist *sp = syms_find(syms, sc->nsyms, addr, ofs);
169 if (sp)
170 return syms_getname(sc, strings, sp);
171
172 return (NULL);
173 }
174
175 extern struct mach_header _mh_execute_header;
176 extern kmod_info_t *kmod;
177
178 /* Search for a symbol and return the name, offset, and module in which the
179 * address was found. A null module means the kernel itself.
180 */
181
182 const char *
183 syms_nameforaddr(vm_offset_t addr, vm_offset_t *ofs, kmod_info_t **km)
184 {
185 const char *name = NULL;
186
187 name = syms_nameforaddr1(&_mh_execute_header, 1, addr, ofs);
188 if (name) {
189 *km = NULL;
190 return (name);
191 }
192
193 return (NULL);
194 }
195
196 int snprintf(char *, size_t, const char *, ...);
197
198 /* Format the results of calling syms_nameforaddr into a single string.
199 * The buffer must be at least 13 bytes long; 80 is recommended.
200 */
201
202 int
203 syms_formataddr(vm_offset_t addr, char *out, vm_offset_t outsize)
204 {
205 vm_offset_t ofs;
206 kmod_info_t *k = NULL;
207 const char *name;
208
209 name = syms_nameforaddr(addr, &ofs, &k);
210
211 if (ofs > 0x100000)
212 name = NULL;
213
214 if (name != NULL) {
215 if (k != NULL)
216 snprintf(out, outsize, "0x%08X <%s:%s + %d>", addr,
217 k->name, name, ofs);
218 else
219 snprintf(out, outsize, "0x%08X <%s + %d>", addr, name,
220 ofs);
221
222 return (1);
223 }
224 else {
225 snprintf(out, outsize, "0x%08X", addr);
226 return (0);
227 }
228 }