1 /* $NetBSD: backtrace.c,v 1.6 2015/09/25 19:27:31 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 __RCSID("$NetBSD: backtrace.c,v 1.6 2015/09/25 19:27:31 christos Exp $");
34 #include <sys/param.h>
51 #define SELF "/proc/self/exe"
53 #include <sys/sysctl.h>
54 #define SELF "/proc/curproc/file"
60 const char *pathname
= SELF
;
61 #ifdef KERN_PROC_PATHNAME
62 static const int name
[] = {
63 CTL_KERN
, KERN_PROC_ARGS
, -1, KERN_PROC_PATHNAME
,
65 char path
[MAXPATHLEN
];
69 if (sysctl(name
, __arraycount(name
), path
, &len
, NULL
, 0) != -1)
72 return open(pathname
, flags
);
76 static int __printflike(4, 5)
77 rasprintf(char **buf
, size_t *bufsiz
, size_t offs
, const char *fmt
, ...)
83 if (*buf
&& offs
< *bufsiz
) {
88 len
= vsnprintf(*buf
+ offs
, *bufsiz
- offs
, fmt
, ap
);
91 if (len
< 0 || (size_t)len
+ 1 < *bufsiz
- offs
)
93 nbufsiz
= MAX(*bufsiz
+ 512, (size_t)len
+ 1);
95 nbufsiz
= MAX(offs
, *bufsiz
) + 512;
97 nbuf
= realloc(*buf
, nbufsiz
);
109 * %d = symbol_address - address
110 * %D = if symbol_address == address "" else +%d
114 format_string(char **buf
, size_t *bufsiz
, size_t offs
, const char *fmt
,
115 Dl_info
*dli
, const void *addr
)
117 ptrdiff_t diff
= (const char *)addr
- (const char *)dli
->dli_saddr
;
121 for (; *fmt
; fmt
++) {
126 len
= rasprintf(buf
, bufsiz
, o
, "%p", addr
);
129 len
= rasprintf(buf
, bufsiz
, o
, "%s", dli
->dli_sname
);
133 len
= rasprintf(buf
, bufsiz
, o
, "+0x%tx", diff
);
138 len
= rasprintf(buf
, bufsiz
, o
, "0x%tx", diff
);
141 len
= rasprintf(buf
, bufsiz
, o
, "%s", dli
->dli_fname
);
145 len
= rasprintf(buf
, bufsiz
, o
, "%c", *fmt
);
156 format_address(symtab_t
*st
, char **buf
, size_t *bufsiz
, size_t offs
,
157 const char *fmt
, const void *addr
)
161 memset(&dli
, 0, sizeof(dli
));
162 (void)dladdr(addr
, &dli
);
164 symtab_find(st
, addr
, &dli
);
166 if (dli
.dli_sname
== NULL
)
167 dli
.dli_sname
= "???";
168 if (dli
.dli_fname
== NULL
)
169 dli
.dli_fname
= "???";
170 if (dli
.dli_saddr
== NULL
)
171 dli
.dli_saddr
= (void *)(intptr_t)addr
;
173 return format_string(buf
, bufsiz
, offs
, fmt
, &dli
, addr
);
177 backtrace_symbols_fmt(void *const *trace
, size_t len
, const char *fmt
)
180 static const size_t slen
= sizeof(char *) + 64; /* estimate */
185 if ((fd
= open_self(O_RDONLY
)) != -1)
186 st
= symtab_create(fd
, -1, STT_FUNC
);
190 if ((ptr
= calloc(len
, slen
)) == NULL
)
193 size_t psize
= len
* slen
;
194 size_t offs
= len
* sizeof(char *);
196 /* We store only offsets in the first pass because of realloc */
197 for (size_t i
= 0; i
< len
; i
++) {
199 ((char **)(void *)ptr
)[i
] = (void *)offs
;
200 x
= format_address(st
, &ptr
, &psize
, offs
, fmt
, trace
[i
]);
208 assert(offs
< psize
);
211 /* Change offsets to pointers */
212 for (size_t j
= 0; j
< len
; j
++)
213 ((char **)(void *)ptr
)[j
] += (intptr_t)ptr
;
224 backtrace_symbols_fd_fmt(void *const *trace
, size_t len
, int fd
,
227 char **s
= backtrace_symbols_fmt(trace
, len
, fmt
);
230 for (size_t i
= 0; i
< len
; i
++)
231 if (dprintf(fd
, "%s\n", s
[i
]) < 0)
237 static const char fmt
[] = "%a <%n%D> at %f";
240 backtrace_symbols(void *const *trace
, size_t len
)
242 return backtrace_symbols_fmt(trace
, len
, fmt
);
246 backtrace_symbols_fd(void *const *trace
, size_t len
, int fd
)
248 return backtrace_symbols_fd_fmt(trace
, len
, fd
, fmt
);