1 /* $NetBSD: backtrace.c,v 1.3 2013/08/29 14:58:56 christos Exp $ */
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 #include <sys/param.h>
50 #define SELF "/proc/self/exe"
52 #include <sys/sysctl.h>
53 #define SELF "/proc/curproc/file"
59 const char *pathname
= SELF
;
60 #ifdef KERN_PROC_PATHNAME
61 static const int name
[] = {
62 CTL_KERN
, KERN_PROC
, -1, KERN_PROC_PATHNAME
,
64 char path
[MAXPATHLEN
];
68 if (sysctl(name
, 4, path
, &len
, NULL
, 0) != -1)
71 return open(pathname
, flags
);
75 static int __printflike(4, 5)
76 rasprintf(char **buf
, size_t *bufsiz
, size_t offs
, const char *fmt
, ...)
82 if (*buf
&& offs
< *bufsiz
) {
87 len
= vsnprintf(*buf
+ offs
, *bufsiz
- offs
, fmt
, ap
);
90 if (len
< 0 || (size_t)len
+ 1 < *bufsiz
- offs
)
92 nbufsiz
= MAX(*bufsiz
+ 512, (size_t)len
+ 1);
94 nbufsiz
= MAX(offs
, *bufsiz
) + 512;
96 nbuf
= realloc(*buf
, nbufsiz
);
108 * %d = symbol_address - address
109 * %D = if symbol_address == address "" else +%d
113 format_string(char **buf
, size_t *bufsiz
, size_t offs
, const char *fmt
,
114 Dl_info
*dli
, const void *addr
)
116 ptrdiff_t diff
= (const char *)addr
- (const char *)dli
->dli_saddr
;
120 for (; *fmt
; fmt
++) {
125 len
= rasprintf(buf
, bufsiz
, o
, "%p", addr
);
128 len
= rasprintf(buf
, bufsiz
, o
, "%s", dli
->dli_sname
);
132 len
= rasprintf(buf
, bufsiz
, o
, "+0x%tx", diff
);
137 len
= rasprintf(buf
, bufsiz
, o
, "0x%tx", diff
);
140 len
= rasprintf(buf
, bufsiz
, o
, "%s", dli
->dli_fname
);
144 len
= rasprintf(buf
, bufsiz
, o
, "%c", *fmt
);
155 format_address(symtab_t
*st
, char **buf
, size_t *bufsiz
, size_t offs
,
156 const char *fmt
, const void *addr
)
160 memset(&dli
, 0, sizeof(dli
));
161 (void)dladdr(addr
, &dli
);
163 symtab_find(st
, addr
, &dli
);
165 if (dli
.dli_sname
== NULL
)
166 dli
.dli_sname
= "???";
167 if (dli
.dli_fname
== NULL
)
168 dli
.dli_fname
= "???";
169 if (dli
.dli_saddr
== NULL
)
170 dli
.dli_saddr
= (void *)(intptr_t)addr
;
172 return format_string(buf
, bufsiz
, offs
, fmt
, &dli
, addr
);
176 backtrace_symbols_fmt(void *const *trace
, size_t len
, const char *fmt
)
179 static const size_t slen
= sizeof(char *) + 64; /* estimate */
184 if ((fd
= open_self(O_RDONLY
)) != -1)
185 st
= symtab_create(fd
, -1, STT_FUNC
);
189 if ((ptr
= calloc(len
, slen
)) == NULL
)
192 size_t psize
= len
* slen
;
193 size_t offs
= len
* sizeof(char *);
195 /* We store only offsets in the first pass because of realloc */
196 for (size_t i
= 0; i
< len
; i
++) {
198 ((char **)(void *)ptr
)[i
] = (void *)offs
;
199 x
= format_address(st
, &ptr
, &psize
, offs
, fmt
, trace
[i
]);
207 assert(offs
< psize
);
210 /* Change offsets to pointers */
211 for (size_t j
= 0; j
< len
; j
++)
212 ((char **)(void *)ptr
)[j
] += (intptr_t)ptr
;
223 backtrace_symbols_fd_fmt(void *const *trace
, size_t len
, int fd
,
226 char **s
= backtrace_symbols_fmt(trace
, len
, fmt
);
229 for (size_t i
= 0; i
< len
; i
++)
230 if (dprintf(fd
, "%s\n", s
[i
]) < 0)
236 static const char fmt
[] = "%a <%n%D> at %f";
239 backtrace_symbols(void *const *trace
, size_t len
)
241 return backtrace_symbols_fmt(trace
, len
, fmt
);
245 backtrace_symbols_fd(void *const *trace
, size_t len
, int fd
)
247 return backtrace_symbols_fd_fmt(trace
, len
, fd
, fmt
);