dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libm / common / m9x / __fex_sym.c
blob66f1056b3659e8112c040dbe2a24562a5f496c26
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 2011 Nexenta Systems, Inc. All rights reserved.
26 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
30 #include <elf.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <procfs.h>
36 #include <string.h>
37 #include <sys/stat.h>
39 #if defined(__sparcv9) || defined(__amd64)
41 #define Elf_Ehdr Elf64_Ehdr
42 #define Elf_Phdr Elf64_Phdr
43 #define Elf_Shdr Elf64_Shdr
44 #define Elf_Sym Elf64_Sym
45 #define ELF_ST_BIND ELF64_ST_BIND
46 #define ELF_ST_TYPE ELF64_ST_TYPE
48 #else
50 #define Elf_Ehdr Elf32_Ehdr
51 #define Elf_Phdr Elf32_Phdr
52 #define Elf_Shdr Elf32_Shdr
53 #define Elf_Sym Elf32_Sym
54 #define ELF_ST_BIND ELF32_ST_BIND
55 #define ELF_ST_TYPE ELF32_ST_TYPE
57 #endif /* __sparcv9 */
59 /* semi-permanent data established by __fex_sym_init */
60 static prmap_t *pm = NULL; /* prmap_t array */
61 static int npm = 0; /* number of entries in pm */
63 /* transient data modified by __fex_sym */
64 static prmap_t *lpm = NULL; /* prmap_t found in last call */
65 static Elf_Phdr *ph = NULL; /* program header array */
66 static int phsize = 0; /* size of ph */
67 static int nph; /* number of entries in ph */
68 static char *stbuf = NULL; /* symbol and string table buffer */
69 static int stbufsize = 0; /* size of stbuf */
70 static int stoffset; /* offset of string table in stbuf */
71 static int nsyms; /* number of symbols in stbuf */
73 /* get a current prmap_t list (must call this before each stack trace) */
74 void
75 __fex_sym_init()
77 struct stat statbuf;
78 long n;
79 int i;
81 /* clear out the previous prmap_t list */
82 free(pm);
83 pm = lpm = NULL;
84 npm = 0;
86 /* get the current prmap_t list */
87 if (stat("/proc/self/map", &statbuf) < 0 || statbuf.st_size <= 0 ||
88 (pm = (prmap_t*)malloc(statbuf.st_size)) == NULL)
89 return;
90 if ((i = open("/proc/self/map", O_RDONLY)) < 0)
92 free(pm);
93 pm = NULL;
94 return;
96 n = read(i, pm, statbuf.st_size);
97 close(i);
98 if (n != statbuf.st_size)
100 free(pm);
101 pm = NULL;
103 else
104 npm = (int) (n / sizeof(prmap_t));
107 /* read ELF program headers and symbols; return -1 on error, 0 otherwise */
108 static int
109 __fex_read_syms(int fd)
111 Elf_Ehdr h;
112 Elf_Shdr *sh;
113 int i, size;
115 /* read the ELF header */
116 if (read(fd, &h, sizeof(h)) != sizeof(h))
117 return -1;
118 if (h.e_ident[EI_MAG0] != ELFMAG0 ||
119 h.e_ident[EI_MAG1] != ELFMAG1 ||
120 h.e_ident[EI_MAG2] != ELFMAG2 ||
121 h.e_ident[EI_MAG3] != ELFMAG3 ||
122 h.e_phentsize != sizeof(Elf_Phdr) ||
123 h.e_shentsize != sizeof(Elf_Shdr))
124 return -1;
126 /* get space for the program headers */
127 size = h.e_phnum * h.e_phentsize;
128 if (size > phsize)
130 free(ph);
131 phsize = nph = 0;
132 if ((ph = (Elf_Phdr*)malloc(size)) == NULL)
133 return -1;
134 phsize = size;
137 /* read the program headers */
138 if (lseek(fd, h.e_phoff, SEEK_SET) != h.e_phoff ||
139 read(fd, ph, size) != (ssize_t)size)
141 nph = 0;
142 return -1;
144 nph = h.e_phnum;
146 /* read the section headers */
147 size = h.e_shnum * h.e_shentsize;
148 if ((sh = (Elf_Shdr*)malloc(size)) == NULL)
149 return -1;
150 if (lseek(fd, h.e_shoff, SEEK_SET) != h.e_shoff ||
151 read(fd, sh, size) != (ssize_t)size)
153 free(sh);
154 return -1;
157 /* find the symtab section header */
158 for (i = 0; i < h.e_shnum; i++)
160 if (sh[i].sh_type == SHT_SYMTAB)
161 break; /* assume there is only one */
163 if (i == h.e_shnum || sh[i].sh_size == 0 ||
164 sh[i].sh_entsize != sizeof(Elf_Sym) ||
165 sh[i].sh_link < 1 || sh[i].sh_link >= h.e_shnum ||
166 sh[sh[i].sh_link].sh_type != SHT_STRTAB ||
167 sh[sh[i].sh_link].sh_size == 0)
169 free(sh);
170 return -1;
173 /* get space for the symbol and string tables */
174 size = (int) (sh[i].sh_size + sh[sh[i].sh_link].sh_size);
175 if (size > stbufsize)
177 free(stbuf);
178 stbufsize = nsyms = 0;
179 if ((stbuf = (char*)malloc(size)) == NULL)
181 free(sh);
182 return -1;
184 stbufsize = size;
187 /* read the symbol and string tables */
188 if (lseek(fd, sh[i].sh_offset, SEEK_SET) != sh[i].sh_offset ||
189 read(fd, stbuf, sh[i].sh_size) != sh[i].sh_size ||
190 lseek(fd, sh[sh[i].sh_link].sh_offset, SEEK_SET) !=
191 sh[sh[i].sh_link].sh_offset ||
192 read(fd, stbuf + sh[i].sh_size, sh[sh[i].sh_link].sh_size) !=
193 sh[sh[i].sh_link].sh_size)
195 free(sh);
196 return (-1);
198 nsyms = (int) (sh[i].sh_size / sh[i].sh_entsize);
199 stoffset = (int) sh[i].sh_size;
201 free(sh);
202 return (0);
205 /* find the symbol corresponding to the given text address;
206 return NULL on error, symbol address otherwise */
207 char *
208 __fex_sym(char *a, char **name)
210 Elf_Sym *s;
211 unsigned long fo, va, value;
212 int fd, i, j, nm;
213 char fname[PRMAPSZ+20];
215 /* see if the last prmap_t found contains the indicated address */
216 if (lpm)
218 if (a >= (char*)lpm->pr_vaddr && a < (char*)lpm->pr_vaddr +
219 lpm->pr_size)
220 goto cont;
223 /* look for a prmap_t that contains the indicated address */
224 for (i = 0; i < npm; i++)
226 if (a >= (char*)pm[i].pr_vaddr && a < (char*)pm[i].pr_vaddr +
227 pm[i].pr_size)
228 break;
230 if (i == npm)
231 return NULL;
233 /* get an open file descriptor for the mapped object */
234 if (pm[i].pr_mapname[0] == '\0')
235 return NULL;
236 strcpy(fname, "/proc/self/object/");
237 strncat(fname, pm[i].pr_mapname, PRMAPSZ);
238 fd = open(fname, O_RDONLY);
239 if (fd < 0)
240 return NULL;
242 /* read the program headers and symbols */
243 lpm = NULL;
244 j = __fex_read_syms(fd);
245 close(fd);
246 if (j < 0)
247 return NULL;
248 lpm = &pm[i];
250 cont:
251 /* compute the file offset corresponding to the mapped address */
252 fo = (a - (char*)lpm->pr_vaddr) + lpm->pr_offset;
254 /* find the program header containing the file offset */
255 for (i = 0; i < nph; i++)
257 if (ph[i].p_type == PT_LOAD && fo >= ph[i].p_offset &&
258 fo < ph[i].p_offset + ph[i].p_filesz)
259 break;
261 if (i == nph)
262 return NULL;
264 /* compute the virtual address corresponding to the file offset */
265 va = (fo - ph[i].p_offset) + ph[i].p_vaddr;
267 /* find the symbol in this segment with the highest value
268 less than or equal to the virtual address */
269 s = (Elf_Sym*)stbuf;
270 value = nm = 0;
271 for (j = 0; j < nsyms; j++)
273 if (s[j].st_name == 0 || s[j].st_shndx == SHN_UNDEF ||
274 (ELF_ST_BIND(s[j].st_info) != STB_LOCAL &&
275 ELF_ST_BIND(s[j].st_info) != STB_GLOBAL &&
276 ELF_ST_BIND(s[j].st_info) != STB_WEAK) ||
277 (ELF_ST_TYPE(s[j].st_info) != STT_NOTYPE &&
278 ELF_ST_TYPE(s[j].st_info) != STT_OBJECT &&
279 ELF_ST_TYPE(s[j].st_info) != STT_FUNC))
281 continue;
284 if (s[j].st_value < ph[i].p_vaddr || s[j].st_value >= ph[i].p_vaddr
285 + ph[i].p_memsz)
287 continue;
290 if (s[j].st_value < value || s[j].st_value > va)
291 continue;
293 value = s[j].st_value;
294 nm = s[j].st_name;
296 if (nm == 0)
297 return NULL;
299 /* pass back the name and return the mapped address of the symbol */
300 *name = stbuf + stoffset + nm;
301 fo = (value - ph[i].p_vaddr) + ph[i].p_offset;
302 return (char*)lpm->pr_vaddr + (fo - lpm->pr_offset);