mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-05 10:48:29 +00:00
Initial import
This commit is contained in:
commit
c91b3c5006
14915 changed files with 590219 additions and 0 deletions
214
libc/log/oncrash.c
Normal file
214
libc/log/oncrash.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*-*- 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/calls/sigbits.h"
|
||||
#include "libc/calls/struct/utsname.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/gdb.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
STATIC_YOINK("ftoa");
|
||||
STATIC_YOINK("ntoa");
|
||||
STATIC_YOINK("stoa");
|
||||
|
||||
/**
|
||||
* @fileoverview Abnormal termination handling & GUI debugging.
|
||||
* @see libc/onkill.c
|
||||
*/
|
||||
|
||||
struct siginfo;
|
||||
|
||||
aligned(1) const char kGregOrder[17] = {13, 11, 8, 14, 12, 9, 10, 15, 16,
|
||||
0, 1, 2, 3, 4, 5, 6, 7};
|
||||
aligned(1) const char kGregNames[17][4] = {
|
||||
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", "RDI",
|
||||
"RSI", "RBP", "RBX", "RDX", "RAX", "RCX", "RSP", "RIP"};
|
||||
aligned(1) const char kGodHatesFlags[12][2] = {
|
||||
"CF", "VF", "PF", "RF", "AF", "KF", "ZF", "SF", "TF", "IF", "DF", "OF"};
|
||||
aligned(1) const char kCrashSigNames[8][5] = {"QUIT", "FPE", "ILL", "SEGV",
|
||||
"TRAP", "ABRT", "BUS"};
|
||||
|
||||
int kCrashSigs[8];
|
||||
struct sigaction g_oldcrashacts[8];
|
||||
|
||||
relegated static const char *tinystrsignal(int sig) {
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||
if (kCrashSigs[i] && sig == kCrashSigs[i]) {
|
||||
return kCrashSigNames[i];
|
||||
}
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
relegated static void showfunctioncalls(FILE *f, ucontext_t *ctx) {
|
||||
fputc('\n', f);
|
||||
struct StackFrame *bp;
|
||||
struct StackFrame goodframe;
|
||||
if (ctx && ctx->uc_mcontext.rip && ctx->uc_mcontext.rbp) {
|
||||
goodframe.next = (struct StackFrame *)ctx->uc_mcontext.rbp;
|
||||
goodframe.addr = ctx->uc_mcontext.rip;
|
||||
bp = &goodframe;
|
||||
showbacktrace(f, bp);
|
||||
}
|
||||
}
|
||||
|
||||
relegated static void describecpuflags(FILE *f, unsigned efl) {
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAYLEN(kGodHatesFlags); ++i) {
|
||||
if (efl & 1) {
|
||||
fputc(' ', f);
|
||||
fputc(kGodHatesFlags[i][0], f);
|
||||
fputc(kGodHatesFlags[i][1], f);
|
||||
}
|
||||
efl >>= 1;
|
||||
}
|
||||
(fprintf)(f, " %s%d\n", "IOPL", efl & 3);
|
||||
}
|
||||
|
||||
relegated static void showgeneralregisters(FILE *f, ucontext_t *ctx) {
|
||||
size_t i, j, k;
|
||||
long double st;
|
||||
fputc('\n', f);
|
||||
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
|
||||
if (j > 0) {
|
||||
fputc(' ', f);
|
||||
}
|
||||
(fprintf)(f, "%-3s %016lx", kGregNames[(unsigned)kGregOrder[i]],
|
||||
ctx->uc_mcontext.gregs[(unsigned)kGregOrder[i]]);
|
||||
if (++j == 3) {
|
||||
j = 0;
|
||||
memcpy(&st, (char *)&ctx->fpustate.st[k], sizeof(st));
|
||||
(fprintf)(f, " %s(%zu) %Lf", "ST", k, st);
|
||||
++k;
|
||||
fputc('\r', f);
|
||||
fputc('\n', f);
|
||||
}
|
||||
}
|
||||
fflush(stderr);
|
||||
describecpuflags(f, ctx->uc_mcontext.gregs[REG_EFL]);
|
||||
}
|
||||
|
||||
relegated static void showsseregisters(FILE *f, ucontext_t *ctx) {
|
||||
size_t i;
|
||||
fputc('\n', f);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
(fprintf)(f, VEIL("r", "%s%-2zu %016lx%016lx %s%-2d %016lx%016lx\n"), "XMM",
|
||||
i + 0, ctx->fpustate.xmm[i + 0].u64[0],
|
||||
ctx->fpustate.xmm[i + 0].u64[1], "XMM", i + 8,
|
||||
ctx->fpustate.xmm[i + 8].u64[0], ctx->fpustate.xmm[i + 8].u64[1]);
|
||||
}
|
||||
}
|
||||
|
||||
relegated static void showmemorymappings(FILE *f) {
|
||||
int c;
|
||||
FILE *f2;
|
||||
if (!IsTiny()) {
|
||||
showmappings(f);
|
||||
if (IsLinux()) {
|
||||
if ((f2 = fopen("/proc/self/maps", "r"))) {
|
||||
while ((c = fgetc(f2)) != -1) {
|
||||
if (fputc(c, f) == -1) break;
|
||||
}
|
||||
}
|
||||
fclose(f2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
relegated static void showcrashreport(int err, FILE *f, int sig,
|
||||
ucontext_t *ctx) {
|
||||
struct utsname names;
|
||||
(fprintf)(f, VEIL("r", "\n%serror%s: Uncaught SIG%s\n %s\n %s\n"), RED2,
|
||||
RESET, tinystrsignal(sig), getauxval(AT_EXECFN), strerror(err));
|
||||
if (uname(&names) != -1) {
|
||||
(fprintf)(f, VEIL("r", " %s %s %s %s\n"), names.sysname, names.nodename,
|
||||
names.release, names.version);
|
||||
}
|
||||
showfunctioncalls(f, ctx);
|
||||
if (ctx) {
|
||||
showgeneralregisters(f, ctx);
|
||||
showsseregisters(f, ctx);
|
||||
}
|
||||
fputc('\n', f);
|
||||
memsummary(f);
|
||||
showmemorymappings(f);
|
||||
}
|
||||
|
||||
relegated static void restoredefaultcrashsignalhandlers(void) {
|
||||
size_t i;
|
||||
sigset_t ss;
|
||||
sigemptyset(&ss);
|
||||
sigprocmask(SIG_SETMASK, &ss, NULL);
|
||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||
if (kCrashSigs[i]) sigaction(kCrashSigs[i], &g_oldcrashacts[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crashes in a developer-friendly human-centric way.
|
||||
*
|
||||
* We first try to launch GDB if it's an interactive development
|
||||
* session. Otherwise we show a really good crash report, sort of like
|
||||
* Python, that includes filenames and line numbers. Many editors, e.g.
|
||||
* Emacs, will even recognize its syntax for quick hopping to the
|
||||
* failing line. That's only possible if the the .com.dbg file is in the
|
||||
* same folder. If the concomitant debug binary can't be found, we
|
||||
* simply print addresses which may be cross-referenced using objdump.
|
||||
*
|
||||
* This function never returns, except for traps w/ human supervision.
|
||||
*/
|
||||
relegated void oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
|
||||
intptr_t rip;
|
||||
int gdbpid, err;
|
||||
static bool once;
|
||||
err = errno;
|
||||
g_runstate |= RUNSTATE_BROKEN;
|
||||
if (once) abort();
|
||||
once = true;
|
||||
/* TODO(jart): Needs translation for ucontext_t and possibly siginfo_t. */
|
||||
if (IsFreebsd() || IsOpenbsd()) ctx = NULL;
|
||||
rip = ctx ? ctx->uc_mcontext.rip : 0;
|
||||
if ((gdbpid = IsDebuggerPresent(true))) {
|
||||
DebugBreak();
|
||||
} else if (isterminalinarticulate() || isrunningundermake()) {
|
||||
gdbpid = -1;
|
||||
} else {
|
||||
restoredefaultcrashsignalhandlers();
|
||||
gdbpid =
|
||||
attachdebugger(((sig == SIGTRAP || sig == SIGQUIT) &&
|
||||
(rip >= (intptr_t)&_base && rip < (intptr_t)&_etext))
|
||||
? rip
|
||||
: 0);
|
||||
}
|
||||
if (gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT)) return;
|
||||
showcrashreport(err, stderr, sig, ctx);
|
||||
quick_exit(128 + sig);
|
||||
unreachable;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue