/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: backtrace.c,v 1.9 2025/01/23 12:08:12 christos Exp $");
for (; *fmt; fmt++) {
if (*fmt != '%')
goto printone;
switch (*++fmt) {
case 'a':
len = rasprintf(buf, bufsiz, o, "%p", addr);
break;
case 'n':
len = rasprintf(buf, bufsiz, o, "%s", dli->dli_sname);
break;
case 'D':
if (diff)
len = rasprintf(buf, bufsiz, o, "+0x%tx", diff);
else
len = 0;
break;
case 'd':
len = rasprintf(buf, bufsiz, o, "0x%tx", diff);
break;
case 'f':
len = rasprintf(buf, bufsiz, o, "%s", dli->dli_fname);
break;
default:
printone:
len = rasprintf(buf, bufsiz, o, "%c", *fmt);
break;
}
if (len == -1)
return -1;
o += len;
}
return o - offs;
}
if (fd != -1 || (fd = open_self(O_RDONLY)) != -1)
st = symtab_create(fd, -1, STT_FUNC);
else
st = NULL;
if ((ptr = calloc(len, slen)) == NULL)
goto out;
size_t psize = len * slen;
size_t offs = len * sizeof(char *);
/* We store only offsets in the first pass because of realloc */
for (size_t i = 0; i < len; i++) {
ssize_t x;
((char **)(void *)ptr)[i] = (void *)offs;
x = format_address(st, &ptr, &psize, offs, fmt, trace[i]);
if (x == -1) {
free(ptr);
ptr = NULL;
goto out;
}
offs += x;
ptr[offs++] = '\0';
assert(offs < psize);
}
/* Change offsets to pointers */
for (size_t j = 0; j < len; j++)
((char **)(void *)ptr)[j] += (intptr_t)ptr;