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>
49 #define SELF "/proc/self/exe"
51 #include <sys/sysctl.h>
52 #define SELF "/proc/curproc/file"
58 const char *pathname
= SELF
;
59 #ifdef KERN_PROC_PATHNAME
60 static const int name
[] = {
61 CTL_KERN
, KERN_PROC
, KERN_PROC_PATHNAME
, -1,
63 char path
[MAXPATHLEN
];
67 if (sysctl(name
, 4, path
, &len
, NULL
, 0) != -1)
70 return open(pathname
, flags
);
74 static int __printflike(4, 5)
75 rasprintf(char **buf
, size_t *bufsiz
, size_t offs
, const char *fmt
, ...)
81 if (*buf
&& offs
< *bufsiz
) {
86 len
= vsnprintf(*buf
+ offs
, *bufsiz
- offs
, fmt
, ap
);
89 if (len
< 0 || (size_t)len
+ 1 < *bufsiz
- offs
)
91 nbufsiz
= MAX(*bufsiz
+ 512, (size_t)len
+ 1);
93 nbufsiz
= MAX(offs
, *bufsiz
) + 512;
95 nbuf
= realloc(*buf
, nbufsiz
);
107 * %d = symbol_address - address
108 * %D = if symbol_address == address "" else +%d
112 format_string(char **buf
, size_t *bufsiz
, size_t offs
, const char *fmt
,
113 Dl_info
*dli
, const void *addr
)
115 ptrdiff_t diff
= (const char *)addr
- (const char *)dli
->dli_saddr
;
119 for (; *fmt
; fmt
++) {
124 len
= rasprintf(buf
, bufsiz
, o
, "%p", addr
);
127 len
= rasprintf(buf
, bufsiz
, o
, "%s", dli
->dli_sname
);
131 len
= rasprintf(buf
, bufsiz
, o
, "+0x%tx", diff
);
136 len
= rasprintf(buf
, bufsiz
, o
, "0x%tx", diff
);
139 len
= rasprintf(buf
, bufsiz
, o
, "%s", dli
->dli_fname
);
143 len
= rasprintf(buf
, bufsiz
, o
, "%c", *fmt
);
154 format_address(symtab_t
*st
, char **buf
, size_t *bufsiz
, size_t offs
,
155 const char *fmt
, const void *addr
)
159 memset(&dli
, 0, sizeof(dli
));
160 (void)dladdr(addr
, &dli
);
162 symtab_find(st
, addr
, &dli
);
164 if (dli
.dli_sname
== NULL
)
165 dli
.dli_sname
= "???";
166 if (dli
.dli_fname
== NULL
)
167 dli
.dli_fname
= "???";
168 if (dli
.dli_saddr
== NULL
)
169 dli
.dli_saddr
= (void *)(intptr_t)addr
;
171 return format_string(buf
, bufsiz
, offs
, fmt
, &dli
, addr
);
175 backtrace_symbols_fmt(void *const *trace
, size_t len
, const char *fmt
)
178 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
)
193 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
);