mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-24 03:20:30 +00:00
Get address sanitizer mostly working
This commit is contained in:
parent
1f1f3cd477
commit
7327c345f9
149 changed files with 3777 additions and 3457 deletions
370
libc/log/asan.c
Normal file
370
libc/log/asan.c
Normal file
|
@ -0,0 +1,370 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/conv/itoa.h"
|
||||
#include "libc/log/asan.h"
|
||||
#include "libc/log/backtrace.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/hook/hook.h"
|
||||
#include "libc/runtime/directmap.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.h"
|
||||
#include "libc/runtime/missioncritical.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "third_party/dlmalloc/dlmalloc.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Address Sanitizer Runtime.
|
||||
*
|
||||
* Someone brilliant at Google figured out a way to improve upon memory
|
||||
* protection. Rather than invent another Java or Rust they changed GCC
|
||||
* so it can emit fast code, that checks the validity of each memory op
|
||||
* with byte granularity, by probing shadow memory.
|
||||
*
|
||||
* AddressSanitizer dedicates one-eighth of the virtual address space
|
||||
* to its shadow memory and uses a direct mapping with a scale and
|
||||
* offset to translate an application address to its corresponding
|
||||
* shadow address. Given the application memory address Addr, the
|
||||
* address of the shadow byte is computed as (Addr>>3)+Offset."
|
||||
*
|
||||
* We use the following encoding for each shadow byte: 0 means that
|
||||
* all 8 bytes of the corresponding application memory region are
|
||||
* addressable; k (1 ≤ k ≤ 7) means that the first k bytes are
|
||||
* addressible; any negative value indicates that the entire 8-byte
|
||||
* word is unaddressable. We use different negative values to
|
||||
* distinguish between different kinds of unaddressable memory (heap
|
||||
* redzones, stack redzones, global redzones, freed memory).
|
||||
*
|
||||
* Here's what the generated code looks like for 64-bit reads:
|
||||
*
|
||||
* movq %addr,%tmp
|
||||
* shrq $3,%tmp
|
||||
* cmpb $0,0x7fff8000(%tmp)
|
||||
* jnz abort
|
||||
* movq (%addr),%dst
|
||||
*/
|
||||
|
||||
#define HOOK(HOOK, IMPL) \
|
||||
if (weaken(HOOK)) { \
|
||||
*weaken(HOOK) = IMPL; \
|
||||
}
|
||||
|
||||
struct AsanSourceLocation {
|
||||
const char *filename;
|
||||
int line;
|
||||
int column;
|
||||
};
|
||||
|
||||
struct AsanAccessInfo {
|
||||
const char *addr;
|
||||
const char *first_bad_addr;
|
||||
size_t size;
|
||||
bool iswrite;
|
||||
unsigned long ip;
|
||||
};
|
||||
|
||||
struct AsanGlobal {
|
||||
const char *addr;
|
||||
size_t size;
|
||||
size_t size_with_redzone;
|
||||
const void *name;
|
||||
const void *module_name;
|
||||
unsigned long has_cxx_init;
|
||||
struct AsanSourceLocation *location;
|
||||
char *odr_indicator;
|
||||
};
|
||||
|
||||
static bool __asan_is_mapped(void *p) {
|
||||
int x, i;
|
||||
x = (intptr_t)p >> 16;
|
||||
i = FindMemoryInterval(&_mmi, x);
|
||||
return i < _mmi.i && x >= _mmi.p[i].x && x <= _mmi.p[i].y;
|
||||
}
|
||||
|
||||
void __asan_map_shadow(void *addr, size_t size) {
|
||||
int i, n, x;
|
||||
char *a, *b;
|
||||
struct DirectMap sm;
|
||||
a = (char *)ROUNDDOWN(SHADOW((intptr_t)addr), FRAMESIZE);
|
||||
b = (char *)ROUNDDOWN(SHADOW((intptr_t)addr + size - 1), FRAMESIZE);
|
||||
for (; a <= b; a += FRAMESIZE) {
|
||||
if (!__asan_is_mapped(a)) {
|
||||
sm = DirectMap(a, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
if (sm.addr == MAP_FAILED ||
|
||||
TrackMemoryInterval(&_mmi, (intptr_t)a >> 16, (intptr_t)a >> 16,
|
||||
sm.maphandle) == -1) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t __asan_malloc_usable_size(const void *vp) {
|
||||
char *s;
|
||||
size_t n;
|
||||
for (n = 0, s = (char *)SHADOW((intptr_t)vp);; ++s) {
|
||||
if (!*s) {
|
||||
n += 8;
|
||||
} else if (*s > 0) {
|
||||
n += *s & 7;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void *__asan_allocate(size_t align, size_t size, int underrun, int overrun) {
|
||||
char *p, *s;
|
||||
size_t q, r, i;
|
||||
if (!(p = dlmemalign(align, ROUNDUP(size, 8) + 16))) return NULL;
|
||||
s = (char *)SHADOW((intptr_t)p - 16);
|
||||
q = size / 8;
|
||||
r = size % 8;
|
||||
*s++ = underrun;
|
||||
*s++ = underrun;
|
||||
memset(s, 0, q);
|
||||
s += q;
|
||||
if (r) *s++ = r;
|
||||
*s++ = overrun;
|
||||
*s++ = overrun;
|
||||
return p;
|
||||
}
|
||||
|
||||
void __asan_deallocate(char *p, int kind) {
|
||||
char *s;
|
||||
size_t n;
|
||||
s = (char *)SHADOW((intptr_t)p);
|
||||
n = dlmalloc_usable_size(p);
|
||||
n /= 8;
|
||||
memset(s, kind, n);
|
||||
dlfree(p);
|
||||
}
|
||||
|
||||
void __asan_free(void *vp) {
|
||||
__asan_deallocate(vp, kAsanHeapFree);
|
||||
}
|
||||
|
||||
void *__asan_memalign(size_t align, size_t size) {
|
||||
return __asan_allocate(align, size, kAsanHeapUnderrun, kAsanHeapOverrun);
|
||||
}
|
||||
|
||||
void *__asan_malloc(size_t size) {
|
||||
return __asan_memalign(16, size);
|
||||
}
|
||||
|
||||
void *__asan_calloc(size_t n, size_t m) {
|
||||
char *p;
|
||||
size_t size;
|
||||
if (__builtin_mul_overflow(n, m, &size)) size = -1;
|
||||
if ((p = __asan_malloc(size))) memset(p, 0, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *__asan_realloc(void *p, size_t n) {
|
||||
char *p2;
|
||||
if (p) {
|
||||
if (n) {
|
||||
if ((p2 = __asan_malloc(n))) {
|
||||
memcpy(p2, p, min(n, dlmalloc_usable_size(p)));
|
||||
__asan_deallocate(p, kAsanRelocated);
|
||||
}
|
||||
} else {
|
||||
__asan_free(p);
|
||||
p2 = NULL;
|
||||
}
|
||||
} else {
|
||||
p2 = __asan_malloc(n);
|
||||
}
|
||||
return p2;
|
||||
}
|
||||
|
||||
void *__asan_valloc(size_t n) {
|
||||
return __asan_memalign(PAGESIZE, n);
|
||||
}
|
||||
|
||||
void *__asan_pvalloc(size_t n) {
|
||||
return __asan_valloc(ROUNDUP(n, PAGESIZE));
|
||||
}
|
||||
|
||||
void __asan_poison(intptr_t addr, size_t size, size_t redsize, int kind) {
|
||||
char *s;
|
||||
intptr_t p;
|
||||
size_t a, b, w;
|
||||
w = (intptr_t)addr & 7;
|
||||
p = (intptr_t)addr - w;
|
||||
a = w + size;
|
||||
b = w + redsize;
|
||||
s = (char *)SHADOW(p + a);
|
||||
if (a & 7) *s++ = a & 7;
|
||||
memset(s, kind, (b - ROUNDUP(a, 8)) >> 3);
|
||||
}
|
||||
|
||||
void __asan_register_globals(struct AsanGlobal g[], int n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
__asan_poison((intptr_t)g[i].addr, g[i].size, g[i].size_with_redzone,
|
||||
kAsanGlobalOverrun);
|
||||
}
|
||||
}
|
||||
|
||||
void __asan_report_memory_fault(uint8_t *addr, int size, const char *kind) {
|
||||
char *p, *s, ibuf[21], buf[256];
|
||||
switch (*(char *)SHADOW((intptr_t)addr)) {
|
||||
case kAsanStackFree:
|
||||
s = "stack use after release";
|
||||
break;
|
||||
case kAsanHeapFree:
|
||||
s = "heap use after free";
|
||||
break;
|
||||
case kAsanRelocated:
|
||||
s = "heap use after relocate";
|
||||
break;
|
||||
case kAsanHeapUnderrun:
|
||||
s = "heap underrun";
|
||||
break;
|
||||
case kAsanHeapOverrun:
|
||||
s = "heap overrun";
|
||||
break;
|
||||
case kAsanStackUnderrun:
|
||||
s = "stack underflow";
|
||||
break;
|
||||
case kAsanStackOverrun:
|
||||
s = "stack overflow";
|
||||
break;
|
||||
case kAsanAllocaOverrun:
|
||||
s = "alloca overflow";
|
||||
break;
|
||||
case kAsanUnscoped:
|
||||
s = "unscoped";
|
||||
break;
|
||||
default:
|
||||
s = "poisoned";
|
||||
break;
|
||||
}
|
||||
p = buf;
|
||||
p = stpcpy(p, "error: ");
|
||||
p = stpcpy(p, s);
|
||||
p = stpcpy(p, " ");
|
||||
uint64toarray_radix10(size, ibuf);
|
||||
p = stpcpy(p, ibuf);
|
||||
p = stpcpy(p, "-byte ");
|
||||
p = stpcpy(p, kind);
|
||||
p = stpcpy(p, " at 0x");
|
||||
uint64toarray_fixed16((intptr_t)addr, ibuf, 48);
|
||||
p = stpcpy(p, ibuf);
|
||||
p = stpcpy(p, "\n");
|
||||
__print(buf, p - buf);
|
||||
PrintBacktraceUsingSymbols(stderr, __builtin_frame_address(0),
|
||||
getsymboltable());
|
||||
DebugBreak();
|
||||
_Exit(66);
|
||||
}
|
||||
|
||||
void *__asan_stack_malloc(size_t size, int classid) {
|
||||
return __asan_allocate(32, size, kAsanStackUnderrun, kAsanStackOverrun);
|
||||
}
|
||||
|
||||
void __asan_stack_free(char *p, size_t size, int classid) {
|
||||
return __asan_deallocate(p, kAsanStackFree);
|
||||
}
|
||||
|
||||
void __asan_report_load_n(uint8_t *addr, int size) {
|
||||
__asan_report_memory_fault(addr, size, "load");
|
||||
}
|
||||
|
||||
void __asan_report_store_n(uint8_t *addr, int size) {
|
||||
__asan_report_memory_fault(addr, size, "store");
|
||||
}
|
||||
|
||||
void __asan_poison_stack_memory(uintptr_t p, size_t n) {
|
||||
memset((char *)SHADOW(p), kAsanUnscoped, n >> 3);
|
||||
if (n & 7) *(char *)SHADOW(p + n) = 8 - (n & 7);
|
||||
}
|
||||
|
||||
void __asan_unpoison_stack_memory(uintptr_t p, size_t n) {
|
||||
memset((char *)SHADOW(p), 0, n >> 3);
|
||||
if (n & 7) *(char *)SHADOW(p + n) = n & 7;
|
||||
}
|
||||
|
||||
void __asan_loadN(intptr_t ptr, size_t size) {
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
void __asan_storeN(intptr_t ptr, size_t size) {
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
void __asan_alloca_poison(intptr_t addr, size_t size) {
|
||||
__asan_poison(addr, size, size + 32, kAsanAllocaOverrun);
|
||||
}
|
||||
|
||||
void __asan_allocas_unpoison(uintptr_t top, uintptr_t bottom) {
|
||||
memset((char *)SHADOW(top), 0, (bottom - top) >> 3);
|
||||
}
|
||||
|
||||
void *__asan_addr_is_in_fake_stack(void *fakestack, void *addr, void **beg,
|
||||
void **end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *__asan_get_current_fake_stack(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __asan_install_malloc_hooks(void) {
|
||||
HOOK(hook$free, __asan_free);
|
||||
HOOK(hook$malloc, __asan_malloc);
|
||||
HOOK(hook$calloc, __asan_calloc);
|
||||
HOOK(hook$valloc, __asan_valloc);
|
||||
HOOK(hook$pvalloc, __asan_pvalloc);
|
||||
HOOK(hook$realloc, __asan_realloc);
|
||||
HOOK(hook$memalign, __asan_memalign);
|
||||
HOOK(hook$malloc_usable_size, __asan_malloc_usable_size);
|
||||
}
|
||||
|
||||
void __asan_init(int argc, char *argv[], char **envp, intptr_t *auxv) {
|
||||
int i;
|
||||
static bool once;
|
||||
register intptr_t rsp asm("rsp");
|
||||
if (!once) {
|
||||
__asan_map_shadow(_base, _end - _base);
|
||||
__asan_map_shadow((void *)ROUNDDOWN(rsp, STACKSIZE), STACKSIZE);
|
||||
for (i = 0; i < argc; ++i) __asan_map_shadow(argv[i], strlen(argv[i]));
|
||||
for (; *envp; ++envp) __asan_map_shadow(*envp, strlen(*envp));
|
||||
__asan_map_shadow(auxv, sizeof(intptr_t) * 2);
|
||||
__asan_install_malloc_hooks();
|
||||
once = true;
|
||||
}
|
||||
}
|
||||
|
||||
const void *const g_asan_ctor[] initarray = {getsymboltable};
|
21
libc/log/asan.h
Normal file
21
libc/log/asan.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_LOG_ASAN_H_
|
||||
#define COSMOPOLITAN_LIBC_LOG_ASAN_H_
|
||||
|
||||
#define kAsanScale 3
|
||||
#define kAsanMagic 0x7fff8000
|
||||
#define kAsanHeapFree -1
|
||||
#define kAsanStackFree -2
|
||||
#define kAsanRelocated -3
|
||||
#define kAsanHeapUnderrun -4
|
||||
#define kAsanHeapOverrun -5
|
||||
#define kAsanGlobalOverrun -6
|
||||
#define kAsanStackUnderrun -7
|
||||
#define kAsanStackOverrun -8
|
||||
#define kAsanAllocaOverrun -9
|
||||
#define kAsanUnscoped -10
|
||||
|
||||
#define SHADOW(x) (((x) >> kAsanScale) + kAsanMagic)
|
||||
|
||||
void __asan_map_shadow(void *, size_t);
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_LOG_ASAN_H_ */
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/gdb.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/stackframe.h"
|
||||
#include "libc/nexgen32e/vendor.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/log/backtrace.h"
|
||||
|
||||
void backtrace(FILE *f) {
|
||||
showbacktrace(f, __builtin_frame_address(0));
|
||||
|
|
15
libc/log/backtrace.h
Normal file
15
libc/log/backtrace.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_LOG_BACKTRACE_H_
|
||||
#define COSMOPOLITAN_LIBC_LOG_BACKTRACE_H_
|
||||
#include "libc/nexgen32e/stackframe.h"
|
||||
#include "libc/runtime/symbols.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void showbacktrace(FILE *, const struct StackFrame *);
|
||||
int PrintBacktraceUsingSymbols(FILE *, const struct StackFrame *,
|
||||
struct SymbolTable *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_LOG_BACKTRACE_H_ */
|
|
@ -26,6 +26,7 @@
|
|||
#include "libc/conv/conv.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/backtrace.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
@ -37,54 +38,7 @@
|
|||
#define kBacktraceMaxFrames 128
|
||||
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (16 + 1))
|
||||
|
||||
static char *FormatAddress(FILE *f, const struct SymbolTable *st, intptr_t addr,
|
||||
char *out, unsigned size, bool symbolic) {
|
||||
int64_t addend;
|
||||
const char *name;
|
||||
const struct Symbol *symbol;
|
||||
if (st->count && ((intptr_t)addr >= (intptr_t)&_base &&
|
||||
(intptr_t)addr <= (intptr_t)&_end && symbolic)) {
|
||||
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
|
||||
st->count, addr - st->addr_base - 1)];
|
||||
addend = addr - st->addr_base - symbol->addr_rva;
|
||||
name = &st->name_base[symbol->name_rva];
|
||||
snprintf(out, size, "%s%c%#x", name, addend >= 0 ? '+' : '-', abs(addend));
|
||||
} else {
|
||||
snprintf(out, size, "%p", addr);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp,
|
||||
char buf[hasatleast kBacktraceBufSize]) {
|
||||
size_t gi;
|
||||
intptr_t addr;
|
||||
struct Garbages *garbage;
|
||||
struct SymbolTable *symbols;
|
||||
const struct StackFrame *frame;
|
||||
if ((symbols = getsymboltable())) {
|
||||
garbage = weaken(g_garbage);
|
||||
gi = garbage ? garbage->i : 0;
|
||||
for (frame = bp; frame; frame = frame->next) {
|
||||
addr = frame->addr;
|
||||
if (addr == weakaddr("CollectGarbage")) {
|
||||
do {
|
||||
--gi;
|
||||
} while ((addr = garbage->p[gi].ret) == weakaddr("CollectGarbage"));
|
||||
}
|
||||
fprintf(f, "%p %p %s\n", frame, addr,
|
||||
FormatAddress(f, symbols, addr, buf, kBacktraceBufSize, true));
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int PrintBacktraceUsingAddr2line(
|
||||
FILE *f, const struct StackFrame *bp,
|
||||
char buf[hasatleast kBacktraceBufSize],
|
||||
char *argv[hasatleast kBacktraceMaxFrames]) {
|
||||
static int PrintBacktraceUsingAddr2line(FILE *f, const struct StackFrame *bp) {
|
||||
ssize_t got;
|
||||
intptr_t addr;
|
||||
size_t i, j, gi;
|
||||
|
@ -92,6 +46,7 @@ static int PrintBacktraceUsingAddr2line(
|
|||
struct Garbages *garbage;
|
||||
const struct StackFrame *frame;
|
||||
const char *debugbin, *p1, *p2, *p3, *addr2line;
|
||||
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
|
||||
if (!(debugbin = finddebugbinary()) || !(addr2line = GetAddr2linePath())) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -148,24 +103,20 @@ static int PrintBacktraceUsingAddr2line(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static noinline int PrintBacktrace(FILE *f, const struct StackFrame *bp,
|
||||
char *argv[hasatleast kBacktraceMaxFrames],
|
||||
char buf[hasatleast kBacktraceBufSize]) {
|
||||
static int PrintBacktrace(FILE *f, const struct StackFrame *bp) {
|
||||
if (!IsTiny()) {
|
||||
if (PrintBacktraceUsingAddr2line(f, bp, buf, argv) != -1) {
|
||||
if (PrintBacktraceUsingAddr2line(f, bp) != -1) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return PrintBacktraceUsingSymbols(f, bp, buf);
|
||||
return PrintBacktraceUsingSymbols(f, bp, getsymboltable());
|
||||
}
|
||||
|
||||
void showbacktrace(FILE *f, const struct StackFrame *bp) {
|
||||
static bool noreentry;
|
||||
char *argv[kBacktraceMaxFrames];
|
||||
char buf[kBacktraceBufSize];
|
||||
if (!noreentry) {
|
||||
noreentry = true;
|
||||
PrintBacktrace(f, bp, argv, buf);
|
||||
PrintBacktrace(f, bp);
|
||||
noreentry = 0;
|
||||
}
|
||||
}
|
||||
|
|
69
libc/log/backtrace3.c
Normal file
69
libc/log/backtrace3.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/bisectcarleft.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/backtrace.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/gc.h"
|
||||
#include "libc/nexgen32e/stackframe.h"
|
||||
#include "libc/runtime/symbols.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
static char *FormatAddress(FILE *f, const struct SymbolTable *st, intptr_t addr,
|
||||
char *out, unsigned size, bool symbolic) {
|
||||
int64_t addend;
|
||||
const char *name;
|
||||
const struct Symbol *symbol;
|
||||
if (st->count && ((intptr_t)addr >= (intptr_t)&_base &&
|
||||
(intptr_t)addr <= (intptr_t)&_end && symbolic)) {
|
||||
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
|
||||
st->count, addr - st->addr_base - 1)];
|
||||
addend = addr - st->addr_base - symbol->addr_rva;
|
||||
name = &st->name_base[symbol->name_rva];
|
||||
snprintf(out, size, "%s%c%#x", name, addend >= 0 ? '+' : '-', ABS(addend));
|
||||
} else {
|
||||
snprintf(out, size, "%p", addr);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp,
|
||||
struct SymbolTable *symbols) {
|
||||
size_t gi;
|
||||
char buf[256];
|
||||
intptr_t addr;
|
||||
struct Garbages *garbage;
|
||||
const struct StackFrame *frame;
|
||||
if (!symbols) return -1;
|
||||
garbage = weaken(g_garbage);
|
||||
gi = garbage ? garbage->i : 0;
|
||||
for (frame = bp; frame; frame = frame->next) {
|
||||
addr = frame->addr;
|
||||
if (addr == weakaddr("CollectGarbage")) {
|
||||
do {
|
||||
--gi;
|
||||
} while ((addr = garbage->p[gi].ret) == weakaddr("CollectGarbage"));
|
||||
}
|
||||
fprintf(f, "%p %p %s\n", frame, addr,
|
||||
FormatAddress(f, symbols, addr, buf, sizeof(buf), true));
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -28,13 +28,14 @@
|
|||
*/
|
||||
nodiscard char *commandvenv(const char *var, const char *cmd) {
|
||||
const char *exepath;
|
||||
char pathbuf[PATH_MAX];
|
||||
if ((exepath = getenv(var))) {
|
||||
if (!isempty(exepath) && access(exepath, X_OK) != -1) {
|
||||
return exepath;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else if ((exepath = commandv(cmd))) {
|
||||
} else if ((exepath = commandv(cmd, pathbuf))) {
|
||||
return exepath;
|
||||
} else {
|
||||
return NULL;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/gdb.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/stackframe.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.h"
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
struct sigset;
|
||||
struct winsize;
|
||||
struct StackFrame;
|
||||
typedef struct FILE FILE;
|
||||
|
||||
extern FILE *g_logfile;
|
||||
|
@ -51,7 +50,6 @@ void showcrashreports(void);
|
|||
void callexitontermination(struct sigset *);
|
||||
bool32 IsDebuggerPresent(bool);
|
||||
bool isrunningundermake(void);
|
||||
void showbacktrace(FILE *, const struct StackFrame *);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § liblog » logging ─╬─│┼
|
||||
|
|
|
@ -8,7 +8,6 @@ LIBC_LOG = $(LIBC_LOG_A_DEPS) $(LIBC_LOG_A)
|
|||
LIBC_LOG_A = o/$(MODE)/libc/log/log.a
|
||||
LIBC_LOG_A_FILES := \
|
||||
$(wildcard libc/log/thunks/*) \
|
||||
$(wildcard libc/log/elf/*) \
|
||||
$(wildcard libc/log/*)
|
||||
LIBC_LOG_A_HDRS = $(filter %.h,$(LIBC_LOG_A_FILES))
|
||||
LIBC_LOG_A_SRCS_C = $(filter %.c,$(LIBC_LOG_A_FILES))
|
||||
|
@ -38,6 +37,7 @@ LIBC_LOG_A_DIRECTDEPS = \
|
|||
LIBC_TINYMATH \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNELBASE \
|
||||
LIBC_MEM \
|
||||
LIBC_RAND \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STDIO \
|
||||
|
@ -60,17 +60,10 @@ $(LIBC_LOG_A).pkg: \
|
|||
$(LIBC_LOG_A_OBJS) \
|
||||
$(foreach x,$(LIBC_LOG_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/libc/log/die.o \
|
||||
o/$(MODE)/libc/log/perror.o \
|
||||
o/$(MODE)/libc/log/ftrace.o \
|
||||
o/$(MODE)/libc/log/ubsan.o \
|
||||
o/$(MODE)/libc/log/symbols.o \
|
||||
o/$(MODE)/libc/log/backtrace.o \
|
||||
o/$(MODE)/libc/log/oncrash.o \
|
||||
o/$(MODE)/libc/log/shadowargs.o \
|
||||
o/$(MODE)/libc/log/thunks/__check_fail_ndebug.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
$(NO_MAGIC)
|
||||
$(LIBC_LOG_A_OBJS): \
|
||||
OVERRIDE_CFLAGS += \
|
||||
$(NO_MAGIC) \
|
||||
-fwrapv
|
||||
|
||||
LIBC_LOG_LIBS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)))
|
||||
LIBC_LOG_SRCS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)_SRCS))
|
||||
|
|
|
@ -23,10 +23,12 @@
|
|||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/backtrace.h"
|
||||
#include "libc/log/gdb.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/stackframe.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
@ -163,7 +165,6 @@ relegated static void ShowCrashReport(int err, FILE *f, int sig,
|
|||
}
|
||||
fputc('\n', f);
|
||||
fflush(f);
|
||||
memsummary(fileno(f));
|
||||
ShowMemoryMappings(fileno(f));
|
||||
}
|
||||
|
||||
|
|
298
libc/log/somanyasan.S
Normal file
298
libc/log/somanyasan.S
Normal file
|
@ -0,0 +1,298 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
.privileged
|
||||
.source __FILE__
|
||||
|
||||
/ @fileoverview Address Sanitizer Thunks
|
||||
/
|
||||
/ This has tiny code size and reduces API surface area
|
||||
/ since ASAN has the same stylistic hugeness as UBSAN.
|
||||
/ We also guard all the functions, against reentrancy.
|
||||
|
||||
__asan_load1:
|
||||
push $1
|
||||
jmp OnLoad
|
||||
.endfn __asan_load1,globl
|
||||
__asan_load2:
|
||||
push $2
|
||||
jmp OnLoad
|
||||
.endfn __asan_load2,globl
|
||||
__asan_load4:
|
||||
push $4
|
||||
jmp OnLoad
|
||||
.endfn __asan_load4,globl
|
||||
__asan_load8:
|
||||
push $8
|
||||
jmp OnLoad
|
||||
.endfn __asan_load8,globl
|
||||
__asan_load16:
|
||||
push $16
|
||||
jmp OnLoad
|
||||
.endfn __asan_load16,globl
|
||||
__asan_load32:
|
||||
push $32
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn __asan_load32,globl
|
||||
OnLoad: pop %rsi
|
||||
ezlea __asan_loadN,ax
|
||||
jmp __asan_report_noreentry
|
||||
.endfn OnStore
|
||||
|
||||
__asan_store1:
|
||||
push $1
|
||||
jmp OnStore
|
||||
.endfn __asan_store1,globl
|
||||
__asan_store2:
|
||||
push $2
|
||||
jmp OnStore
|
||||
.endfn __asan_store2,globl
|
||||
__asan_store4:
|
||||
push $4
|
||||
jmp OnStore
|
||||
.endfn __asan_store4,globl
|
||||
__asan_store8:
|
||||
push $8
|
||||
jmp OnStore
|
||||
.endfn __asan_store8,globl
|
||||
__asan_store16:
|
||||
push $16
|
||||
jmp OnStore
|
||||
.endfn __asan_store16,globl
|
||||
__asan_store32:
|
||||
push $32
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn __asan_store32,globl
|
||||
OnStore:pop %rsi
|
||||
ezlea __asan_storeN,ax
|
||||
jmp __asan_report_noreentry
|
||||
.endfn OnStore
|
||||
|
||||
__asan_report_load1:
|
||||
push $1
|
||||
jmp OnReportLoad
|
||||
.endfn __asan_report_load1,globl
|
||||
__asan_report_load2:
|
||||
push $2
|
||||
jmp OnReportLoad
|
||||
.endfn __asan_report_load2,globl
|
||||
__asan_report_load4:
|
||||
push $4
|
||||
jmp OnReportLoad
|
||||
.endfn __asan_report_load4,globl
|
||||
__asan_report_load8:
|
||||
push $8
|
||||
jmp OnReportLoad
|
||||
.endfn __asan_report_load8,globl
|
||||
__asan_report_load16:
|
||||
push $16
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn __asan_report_load16,globl
|
||||
OnReportLoad:
|
||||
pop %rsi
|
||||
ezlea __asan_report_load_n,ax
|
||||
jmp __asan_report_noreentry
|
||||
.endfn OnReportLoad
|
||||
|
||||
__asan_report_store1:
|
||||
push $1
|
||||
jmp ReportStore
|
||||
.endfn __asan_report_store1,globl
|
||||
__asan_report_store2:
|
||||
push $2
|
||||
jmp ReportStore
|
||||
.endfn __asan_report_store2,globl
|
||||
__asan_report_store4:
|
||||
push $4
|
||||
jmp ReportStore
|
||||
.endfn __asan_report_store4,globl
|
||||
__asan_report_store8:
|
||||
push $8
|
||||
jmp ReportStore
|
||||
.endfn __asan_report_store8,globl
|
||||
__asan_report_store16:
|
||||
push $16
|
||||
jmp ReportStore
|
||||
.endfn __asan_report_store16,globl
|
||||
__asan_report_store32:
|
||||
push $32
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn __asan_report_store32,globl
|
||||
ReportStore:
|
||||
pop %rsi
|
||||
ezlea __asan_report_store_n,ax
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn ReportStore
|
||||
|
||||
__asan_report_noreentry:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
cmpb $0,noreentry(%rip)
|
||||
jnz 2f
|
||||
incb noreentry(%rip)
|
||||
call *%rax
|
||||
decb noreentry(%rip)
|
||||
pop %rbp
|
||||
ret
|
||||
2: call abort
|
||||
.endfn __asan_report_noreentry
|
||||
|
||||
__asan_stack_free_0:
|
||||
push $0
|
||||
jmp OnStackFree
|
||||
.endfn __asan_stack_free_0,globl
|
||||
__asan_stack_free_1:
|
||||
push $1
|
||||
jmp OnStackFree
|
||||
.endfn __asan_stack_free_1,globl
|
||||
__asan_stack_free_2:
|
||||
push $2
|
||||
jmp OnStackFree
|
||||
.endfn __asan_stack_free_2,globl
|
||||
__asan_stack_free_3:
|
||||
push $3
|
||||
jmp OnStackFree
|
||||
.endfn __asan_stack_free_3,globl
|
||||
__asan_stack_free_4:
|
||||
push $4
|
||||
jmp OnStackFree
|
||||
.endfn __asan_stack_free_4,globl
|
||||
__asan_stack_free_5:
|
||||
push $5
|
||||
jmp OnStackFree
|
||||
.endfn __asan_stack_free_5,globl
|
||||
__asan_stack_free_6:
|
||||
push $6
|
||||
jmp OnStackFree
|
||||
.endfn __asan_stack_free_6,globl
|
||||
__asan_stack_free_7:
|
||||
push $7
|
||||
jmp OnStackFree
|
||||
.endfn __asan_stack_free_7,globl
|
||||
__asan_stack_free_8:
|
||||
push $8
|
||||
jmp OnStackFree
|
||||
.endfn __asan_stack_free_8,globl
|
||||
__asan_stack_free_9:
|
||||
push $9
|
||||
jmp OnStackFree
|
||||
.endfn __asan_stack_free_9,globl
|
||||
__asan_stack_free_10:
|
||||
push $10
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn __asan_stack_free_10,globl
|
||||
OnStackFree:
|
||||
pop %rdx
|
||||
jmp __asan_stack_free
|
||||
.endfn OnStackFree
|
||||
|
||||
__asan_stack_malloc_0:
|
||||
push $0
|
||||
jmp OnStackMalloc
|
||||
.endfn __asan_stack_malloc_0,globl
|
||||
__asan_stack_malloc_1:
|
||||
push $1
|
||||
jmp OnStackMalloc
|
||||
.endfn __asan_stack_malloc_1,globl
|
||||
__asan_stack_malloc_2:
|
||||
push $2
|
||||
jmp OnStackMalloc
|
||||
.endfn __asan_stack_malloc_2,globl
|
||||
__asan_stack_malloc_3:
|
||||
push $3
|
||||
jmp OnStackMalloc
|
||||
.endfn __asan_stack_malloc_3,globl
|
||||
__asan_stack_malloc_4:
|
||||
push $4
|
||||
jmp OnStackMalloc
|
||||
.endfn __asan_stack_malloc_4,globl
|
||||
__asan_stack_malloc_5:
|
||||
push $5
|
||||
jmp OnStackMalloc
|
||||
.endfn __asan_stack_malloc_5,globl
|
||||
__asan_stack_malloc_6:
|
||||
push $6
|
||||
jmp OnStackMalloc
|
||||
.endfn __asan_stack_malloc_6,globl
|
||||
__asan_stack_malloc_7:
|
||||
push $7
|
||||
jmp OnStackMalloc
|
||||
.endfn __asan_stack_malloc_7,globl
|
||||
__asan_stack_malloc_8:
|
||||
push $8
|
||||
jmp OnStackMalloc
|
||||
.endfn __asan_stack_malloc_8,globl
|
||||
__asan_stack_malloc_9:
|
||||
push $9
|
||||
jmp OnStackMalloc
|
||||
.endfn __asan_stack_malloc_9,globl
|
||||
__asan_stack_malloc_10:
|
||||
push $10
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn __asan_stack_malloc_10,globl
|
||||
OnStackMalloc:
|
||||
pop %rsi
|
||||
jmp __asan_stack_malloc
|
||||
.endfn OnStackMalloc
|
||||
|
||||
__asan_handle_no_return:
|
||||
ret
|
||||
.endfn __asan_handle_no_return,globl
|
||||
|
||||
__asan_before_dynamic_init:
|
||||
ret
|
||||
.endfn __asan_before_dynamic_init,globl
|
||||
|
||||
__asan_after_dynamic_init:
|
||||
ret
|
||||
.endfn __asan_after_dynamic_init,globl
|
||||
|
||||
__asan_unregister_globals:
|
||||
ret
|
||||
.endfn __asan_unregister_globals,globl
|
||||
|
||||
__asan_version_mismatch_check_v8:
|
||||
ret
|
||||
.endfn __asan_version_mismatch_check_v8,globl
|
||||
|
||||
/ Initializes Address Sanitizer runtime earlier if linked.
|
||||
.init.start 301,_init_asan
|
||||
push %rdi
|
||||
push %rsi
|
||||
mov %r12,%rdi
|
||||
mov %r13,%rsi
|
||||
mov %r14,%rdx
|
||||
mov %r15,%rcx
|
||||
call __asan_init
|
||||
pop %rsi
|
||||
pop %rdi
|
||||
.init.end 301,_init_asan
|
||||
|
||||
.rodata.cst4
|
||||
__asan_option_detect_stack_use_after_return:
|
||||
.long 1
|
||||
.endobj __asan_option_detect_stack_use_after_return,globl
|
||||
.previous
|
||||
|
||||
.bss
|
||||
noreentry:
|
||||
.byte 0
|
||||
.endobj noreentry
|
||||
.previous
|
Loading…
Add table
Add a link
Reference in a new issue