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]
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.
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
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) */
81 /* clear out the previous prmap_t list */
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
)
90 if ((i
= open("/proc/self/map", O_RDONLY
)) < 0)
96 n
= read(i
, pm
, statbuf
.st_size
);
98 if (n
!= statbuf
.st_size
)
104 npm
= (int) (n
/ sizeof(prmap_t
));
107 /* read ELF program headers and symbols; return -1 on error, 0 otherwise */
109 __fex_read_syms(int fd
)
115 /* read the ELF header */
116 if (read(fd
, &h
, sizeof(h
)) != sizeof(h
))
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
))
126 /* get space for the program headers */
127 size
= h
.e_phnum
* h
.e_phentsize
;
132 if ((ph
= (Elf_Phdr
*)malloc(size
)) == NULL
)
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
)
146 /* read the section headers */
147 size
= h
.e_shnum
* h
.e_shentsize
;
148 if ((sh
= (Elf_Shdr
*)malloc(size
)) == NULL
)
150 if (lseek(fd
, h
.e_shoff
, SEEK_SET
) != h
.e_shoff
||
151 read(fd
, sh
, size
) != (ssize_t
)size
)
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)
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
)
178 stbufsize
= nsyms
= 0;
179 if ((stbuf
= (char*)malloc(size
)) == NULL
)
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
)
198 nsyms
= (int) (sh
[i
].sh_size
/ sh
[i
].sh_entsize
);
199 stoffset
= (int) sh
[i
].sh_size
;
205 /* find the symbol corresponding to the given text address;
206 return NULL on error, symbol address otherwise */
208 __fex_sym(char *a
, char **name
)
211 unsigned long fo
, va
, value
;
213 char fname
[PRMAPSZ
+20];
215 /* see if the last prmap_t found contains the indicated address */
218 if (a
>= (char*)lpm
->pr_vaddr
&& a
< (char*)lpm
->pr_vaddr
+
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
+
233 /* get an open file descriptor for the mapped object */
234 if (pm
[i
].pr_mapname
[0] == '\0')
236 strcpy(fname
, "/proc/self/object/");
237 strncat(fname
, pm
[i
].pr_mapname
, PRMAPSZ
);
238 fd
= open(fname
, O_RDONLY
);
242 /* read the program headers and symbols */
244 j
= __fex_read_syms(fd
);
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
)
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 */
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
))
284 if (s
[j
].st_value
< ph
[i
].p_vaddr
|| s
[j
].st_value
>= ph
[i
].p_vaddr
290 if (s
[j
].st_value
< value
|| s
[j
].st_value
> va
)
293 value
= s
[j
].st_value
;
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
);