mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-08 07:23:33 +00:00
9208c83f7a
- add vdso dump utility - tests now log stack usage - rename g_ftrace to __ftrace - make internal spinlocks go faster - add conformant c11 atomics library - function tracing now logs stack usage - make function call tracing thread safe - add -X unsecure (no ssl) mode to redbean - munmap() has more consistent behavior now - pacify fsync() calls on python unit tests - make --strace flag work better in redbean - start minimizing and documenting compiler flags
304 lines
8.5 KiB
C
304 lines
8.5 KiB
C
/*-*- 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 2022 Justine Alexandra Roberts Tunney │
|
|
│ │
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
|
│ │
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/calls/strace.internal.h"
|
|
#include "libc/nexgen32e/rdtsc.h"
|
|
#include "libc/runtime/runtime.h"
|
|
#include "libc/str/str.h"
|
|
#include "libc/time/clockstonanos.internal.h"
|
|
#include "tool/plinko/lib/char.h"
|
|
#include "tool/plinko/lib/plinko.h"
|
|
#include "tool/plinko/lib/print.h"
|
|
#include "tool/plinko/lib/printf.h"
|
|
|
|
static inline long GetVarInt(va_list va, signed char t) {
|
|
if (t <= 0) return va_arg(va, int);
|
|
return va_arg(va, long);
|
|
}
|
|
|
|
static int PrintStr(int fd, const char *s, int cols) {
|
|
int n, j, k = 0, i = 0;
|
|
n = strlen(s);
|
|
k += PrintIndent(fd, +cols - n);
|
|
while (i < n) k += PrintChar(fd, s[i++]);
|
|
k += PrintIndent(fd, -cols - n);
|
|
return k;
|
|
}
|
|
|
|
int Printf(const char *f, ...) {
|
|
int n;
|
|
va_list va;
|
|
va_start(va, f);
|
|
n = Vfnprintf(f, va, 1, 0);
|
|
va_end(va);
|
|
return n;
|
|
}
|
|
|
|
int Fprintf(int fd, const char *f, ...) {
|
|
int n;
|
|
va_list va;
|
|
va_start(va, f);
|
|
n = Vfnprintf(f, va, fd, 0);
|
|
va_end(va);
|
|
return n;
|
|
}
|
|
|
|
int Fnprintf(int fd, int n, const char *f, ...) {
|
|
va_list va;
|
|
va_start(va, f);
|
|
n = Vfnprintf(f, va, fd, n);
|
|
va_end(va);
|
|
return n;
|
|
}
|
|
|
|
int Vfprintf(const char *f, va_list va, int fd) {
|
|
return Vfnprintf(f, va, fd, 0);
|
|
}
|
|
|
|
int Vfnprintf(const char *f, va_list va, int fd, int n) {
|
|
enum { kPlain, kEsc, kCsi };
|
|
static int recursive;
|
|
dword t, u;
|
|
const char *s;
|
|
signed char type;
|
|
char quot, ansi, gotr, pdot, zero;
|
|
int b, c, i, x, y, si, prec, cols, sign;
|
|
gotr = false;
|
|
t = rdtsc();
|
|
--__ftrace;
|
|
--__strace;
|
|
++recursive;
|
|
for (ansi = 0;;) {
|
|
for (;;) {
|
|
if (!(c = *f++ & 0377) || c == L'%') break;
|
|
if (c >= 0300) {
|
|
for (b = 0200; c & b; b >>= 1) {
|
|
c ^= b;
|
|
}
|
|
while ((*f & 0300) == 0200) {
|
|
c <<= 6;
|
|
c |= *f++ & 0177;
|
|
}
|
|
}
|
|
switch (ansi) {
|
|
case kPlain:
|
|
if (c == 033) {
|
|
ansi = kEsc;
|
|
} else if (c != L'\n' && c != L'\r') {
|
|
n += GetMonospaceCharacterWidth(c);
|
|
} else {
|
|
n = 0;
|
|
}
|
|
break;
|
|
case kEsc:
|
|
if (c == '[') {
|
|
ansi = kCsi;
|
|
} else {
|
|
ansi = kPlain;
|
|
}
|
|
break;
|
|
case kCsi:
|
|
if (0x40 <= c && c <= 0x7e) {
|
|
ansi = kPlain;
|
|
}
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
EmitFormatByte:
|
|
PrintChar(fd, c);
|
|
}
|
|
if (!c) break;
|
|
prec = 0;
|
|
pdot = 0;
|
|
cols = 0;
|
|
quot = 0;
|
|
type = 0;
|
|
zero = 0;
|
|
sign = 1;
|
|
for (;;) {
|
|
switch ((c = *f++)) {
|
|
default:
|
|
goto EmitFormatByte;
|
|
case L'n':
|
|
PrintNewline(fd);
|
|
n = 0;
|
|
break;
|
|
case L'l':
|
|
++type;
|
|
continue;
|
|
case L'0':
|
|
case L'1':
|
|
case L'2':
|
|
case L'3':
|
|
case L'4':
|
|
case L'5':
|
|
case L'6':
|
|
case L'7':
|
|
case L'8':
|
|
case L'9':
|
|
si = pdot ? prec : cols;
|
|
si *= 10;
|
|
si += c - '0';
|
|
goto UpdateCols;
|
|
case L'*':
|
|
si = va_arg(va, int);
|
|
UpdateCols:
|
|
if (pdot) {
|
|
prec = si;
|
|
} else {
|
|
if (si < 0) {
|
|
si = -si;
|
|
sign = -1;
|
|
} else if (!si) {
|
|
zero = 1;
|
|
}
|
|
cols = si;
|
|
}
|
|
continue;
|
|
case L'-':
|
|
sign = -1;
|
|
continue;
|
|
case L'.':
|
|
pdot = 1;
|
|
continue;
|
|
case L'_':
|
|
case L',':
|
|
case L'\'':
|
|
quot = c;
|
|
continue;
|
|
case L'I':
|
|
if (depth >= 0) {
|
|
n += PrintDepth(fd, depth);
|
|
} else {
|
|
n += PrintIndent(fd, sp * 2);
|
|
}
|
|
break;
|
|
case L'J':
|
|
if (depth >= 0) {
|
|
n += PrintDepth(fd, depth - 1);
|
|
} else {
|
|
n += PrintIndent(fd, (sp - 1) * 2);
|
|
}
|
|
break;
|
|
case L'V':
|
|
y = depth >= 0 ? depth : sp;
|
|
if (y) {
|
|
n += PrintIndent(fd, (y - 1) * 2);
|
|
n += PrintChar(fd, L'├');
|
|
n += PrintChar(fd, L'─');
|
|
}
|
|
break;
|
|
case L'W':
|
|
y = depth >= 0 ? depth : sp;
|
|
if (y) {
|
|
n += PrintIndent(fd, (y - 1) * 2);
|
|
n += PrintChar(fd, L'│');
|
|
n += PrintChar(fd, L' ');
|
|
}
|
|
break;
|
|
case L'X':
|
|
y = depth >= 0 ? depth : sp;
|
|
if (y) {
|
|
n += PrintIndent(fd, (y - 1) * 2);
|
|
n += PrintChar(fd, L'└');
|
|
n += PrintChar(fd, L'─');
|
|
}
|
|
break;
|
|
case L'p':
|
|
if (simpler) goto SimplePrint;
|
|
// fallthrough
|
|
case L'P':
|
|
n += PrettyPrint(fd, va_arg(va, int),
|
|
MAX(0, depth > 0 ? n - depth * 3 : n));
|
|
break;
|
|
case L'T':
|
|
PrintTree(fd, va_arg(va, int), n);
|
|
break;
|
|
case L'R':
|
|
gotr = true;
|
|
n += PrintInt(fd, ClocksToNanos(tick, t), cols * sign, quot, zero, 10,
|
|
true);
|
|
break;
|
|
case L'S':
|
|
SimplePrint:
|
|
n += Print(fd, va_arg(va, int));
|
|
break;
|
|
case L'A':
|
|
y = va_arg(va, int);
|
|
x = va_arg(va, int);
|
|
n += PrintChar(fd, L'[');
|
|
n += PrintArgs(fd, y, x, 0);
|
|
n += PrintChar(fd, L']');
|
|
break;
|
|
case L'K':
|
|
if ((b = va_arg(va, int)) < 0) {
|
|
PrintChar(fd, L'(');
|
|
for (;;) {
|
|
n += Print(fd, Car(Car(b)));
|
|
if ((b = Cdr(b)) >= 0) break;
|
|
PrintChar(fd, L' ');
|
|
}
|
|
PrintChar(fd, L')');
|
|
} else {
|
|
n += Print(fd, b);
|
|
}
|
|
break;
|
|
case L'd':
|
|
n += PrintInt(fd, GetVarInt(va, type), cols * sign, quot, zero, 10,
|
|
true);
|
|
break;
|
|
case L'u':
|
|
n +=
|
|
PrintInt(fd, GetVarInt(va, type), cols * sign, quot, zero, 10, 0);
|
|
break;
|
|
case L'b':
|
|
n += PrintInt(fd, GetVarInt(va, type), cols * sign, quot, zero, 2, 0);
|
|
break;
|
|
case L'o':
|
|
n += PrintInt(fd, GetVarInt(va, type), cols * sign, quot, zero, 8, 0);
|
|
break;
|
|
case L'x':
|
|
n +=
|
|
PrintInt(fd, GetVarInt(va, type), cols * sign, quot, zero, 16, 0);
|
|
break;
|
|
case L's':
|
|
s = va_arg(va, const char *);
|
|
if (!s) s = "NULL";
|
|
n += PrintStr(fd, s, cols * sign);
|
|
break;
|
|
case L'c':
|
|
n += PrintChar(fd, va_arg(va, int));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
--recursive;
|
|
++__ftrace;
|
|
++__strace;
|
|
if (!recursive) {
|
|
u = rdtsc();
|
|
if (gotr) {
|
|
tick = u;
|
|
} else {
|
|
tick -= u >= t ? u - t : ~t + u + 1;
|
|
}
|
|
}
|
|
return n;
|
|
}
|