2020-06-12 17:30:41 +03:00
|
|
|
#include "arch/amd64/multiboot2.h"
|
2020-06-18 16:32:01 +03:00
|
|
|
#include "sys/console.h"
|
2019-09-18 23:22:09 +03:00
|
|
|
#include "sys/string.h"
|
2019-09-16 12:40:00 +03:00
|
|
|
#include "sys/debug.h"
|
2019-10-21 16:14:34 +03:00
|
|
|
#include "sys/ctype.h"
|
2019-03-23 13:12:50 +02:00
|
|
|
#include "sys/attr.h"
|
2019-10-10 19:29:05 +03:00
|
|
|
#include "sys/spin.h"
|
2020-01-22 15:31:57 +02:00
|
|
|
#include "sys/config.h"
|
2020-08-11 01:32:03 +03:00
|
|
|
#include "sys/syms.h"
|
2020-04-10 11:02:10 +03:00
|
|
|
#include "sys/assert.h"
|
2020-06-12 17:30:41 +03:00
|
|
|
#include "sys/mm.h"
|
|
|
|
|
2019-09-18 23:22:09 +03:00
|
|
|
#include <stdint.h>
|
2019-03-23 13:12:50 +02:00
|
|
|
|
|
|
|
#if defined(ARCH_AMD64)
|
2020-02-04 12:45:15 +02:00
|
|
|
#include "arch/amd64/hw/rs232.h"
|
|
|
|
#include "arch/amd64/hw/con.h"
|
2019-03-23 13:12:50 +02:00
|
|
|
#endif
|
|
|
|
|
2020-07-24 14:35:47 +03:00
|
|
|
void debug_backtrace(int level, uintptr_t rbp, int depth, int limit) {
|
2020-01-29 20:12:52 +02:00
|
|
|
// Typical layout:
|
|
|
|
// rbp + 08 == rip
|
|
|
|
// rbp + 00 == rbp_1
|
|
|
|
|
|
|
|
if (!limit) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-30 13:24:00 +02:00
|
|
|
if ((rbp & 0xFFFFFF0000000000) != 0xFFFFFF0000000000) {
|
2020-07-24 14:35:47 +03:00
|
|
|
debugs(level, "-- %rbp is not from kernel space\n");
|
2020-01-30 13:24:00 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-29 20:12:52 +02:00
|
|
|
uintptr_t rip = ((uintptr_t *) rbp)[1];
|
|
|
|
uintptr_t rbp_next = ((uintptr_t *) rbp)[0];
|
|
|
|
|
|
|
|
uintptr_t base;
|
|
|
|
const char *name;
|
|
|
|
|
2020-08-11 01:32:03 +03:00
|
|
|
if (ksym_find_location(rip, &name, &base) == 0) {
|
2020-07-24 14:35:47 +03:00
|
|
|
debugf(level, "%d: %p <%s + %04x>\n", depth, rip, name, rip - base);
|
2020-01-29 20:12:52 +02:00
|
|
|
} else {
|
2020-07-24 14:35:47 +03:00
|
|
|
debugf(level, "%d: %p (unknown)\n", depth, rip);
|
2020-01-29 20:12:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rbp_next == 0) {
|
2020-07-24 14:35:47 +03:00
|
|
|
debugs(level, "-- End of frame chain\n");
|
2020-01-29 20:12:52 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-24 14:35:47 +03:00
|
|
|
debug_backtrace(level, rbp_next, depth + 1, limit - 1);
|
2020-01-29 20:12:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
////
|
|
|
|
|
2019-03-23 13:12:50 +02:00
|
|
|
static const char *s_debug_xs_set0 = "0123456789abcdef";
|
|
|
|
static const char *s_debug_xs_set1 = "0123456789ABCDEF";
|
|
|
|
|
2019-10-10 19:29:05 +03:00
|
|
|
// Don't know if it's a best idea, but at least guarantees
|
|
|
|
// non-overlapping debug lines
|
|
|
|
static spin_t debug_spin = 0;
|
|
|
|
|
2019-09-30 10:39:38 +03:00
|
|
|
void fmtsiz(char *out, size_t sz) {
|
|
|
|
static const char sizs[] = "KMGTPE???";
|
|
|
|
size_t f = sz, r = 0;
|
|
|
|
int pwr = 0;
|
|
|
|
size_t l = 0;
|
|
|
|
|
|
|
|
while (f >= 1536) {
|
|
|
|
r = ((f % 1024) * 10) / 1024;
|
|
|
|
f /= 1024;
|
|
|
|
++pwr;
|
|
|
|
}
|
|
|
|
|
|
|
|
debug_ds(f, out, 0, 0);
|
|
|
|
l = strlen(out);
|
|
|
|
|
|
|
|
if (pwr) {
|
|
|
|
out[l++] = '.';
|
|
|
|
out[l++] = '0' + r;
|
|
|
|
|
|
|
|
out[l++] = sizs[pwr - 1];
|
|
|
|
|
|
|
|
out[l++] = 'i';
|
|
|
|
}
|
|
|
|
|
|
|
|
out[l++] = 'B';
|
|
|
|
out[l++] = 0;
|
|
|
|
}
|
|
|
|
|
2019-03-23 13:12:50 +02:00
|
|
|
void debugc(int level, char c) {
|
|
|
|
#if defined(ARCH_AMD64)
|
2020-01-22 15:31:57 +02:00
|
|
|
if (DEBUG_SERIAL(level) & kernel_config[CFG_DEBUG]) {
|
|
|
|
rs232_send(RS232_COM1, c);
|
|
|
|
}
|
2020-06-18 16:32:01 +03:00
|
|
|
if (DEBUG_DISP(level) & kernel_config[CFG_DEBUG]) {
|
|
|
|
console_default_putc(c);
|
|
|
|
}
|
2019-03-23 13:12:50 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void debugs(int level, const char *s) {
|
|
|
|
char c;
|
|
|
|
while ((c = *(s++))) {
|
|
|
|
debugc(level, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void debugspl(int level, const char *s, char p, size_t c) {
|
|
|
|
size_t l = strlen(s);
|
|
|
|
for (size_t i = l; i < c; ++i) {
|
|
|
|
debugc(level, p);
|
|
|
|
}
|
|
|
|
debugs(level, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void debugspr(int level, const char *s, char p, size_t c) {
|
|
|
|
size_t l = strlen(s);
|
|
|
|
debugs(level, s);
|
|
|
|
for (size_t i = l; i < c; ++i) {
|
|
|
|
debugc(level, p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void debugsp(int level, const char *s, char padc, int padl) {
|
|
|
|
if (padl > 0) {
|
|
|
|
debugspl(level, s, padc, padl);
|
|
|
|
} else {
|
|
|
|
debugspr(level, s, padc, -padl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void debug_ds(int64_t x, char *res, int s, int sz) {
|
|
|
|
if (!x) {
|
|
|
|
res[0] = '0';
|
|
|
|
res[1] = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int c;
|
|
|
|
uint64_t v;
|
|
|
|
|
|
|
|
if (sz) {
|
|
|
|
if (s && x < 0) {
|
|
|
|
v = (uint64_t) -x;
|
|
|
|
} else {
|
|
|
|
s = 0;
|
|
|
|
v = (uint64_t) x;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (s && ((int32_t) x) < 0) {
|
|
|
|
v = (uint64_t) -((int32_t) x);
|
|
|
|
} else {
|
|
|
|
s = 0;
|
|
|
|
v = (uint64_t) x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c = 0;
|
|
|
|
|
|
|
|
while (v) {
|
|
|
|
res[c++] = '0' + v % 10;
|
|
|
|
v /= 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s) {
|
|
|
|
res[c++] = '-';
|
|
|
|
}
|
|
|
|
|
|
|
|
res[c] = 0;
|
|
|
|
|
|
|
|
for (int i = 0, j = c - 1; i < j; ++i, --j) {
|
|
|
|
res[i] ^= res[j];
|
|
|
|
res[j] ^= res[i];
|
|
|
|
res[i] ^= res[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void debug_xs(uint64_t v, char *res, const char *set) {
|
|
|
|
if (!v) {
|
|
|
|
res[0] = '0';
|
|
|
|
res[1] = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int c = 0;
|
|
|
|
|
|
|
|
while (v) {
|
|
|
|
res[c++] = set[v & 0xF];
|
|
|
|
v >>= 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
res[c] = 0;
|
|
|
|
|
|
|
|
for (int i = 0, j = c - 1; i < j; ++i, --j) {
|
|
|
|
res[i] ^= res[j];
|
|
|
|
res[j] ^= res[i];
|
|
|
|
res[i] ^= res[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void debugf(int level, const char *f, ...) {
|
|
|
|
va_list args;
|
|
|
|
va_start(args, f);
|
|
|
|
debugfv(level, f, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
void debugfv(int level, const char *fmt, va_list args) {
|
2019-10-11 19:55:31 +03:00
|
|
|
uintptr_t irq;
|
|
|
|
spin_lock_irqsave(&debug_spin, &irq);
|
2019-10-10 19:29:05 +03:00
|
|
|
|
2019-03-23 13:12:50 +02:00
|
|
|
char c;
|
|
|
|
union {
|
|
|
|
const char *v_string;
|
|
|
|
char v_char;
|
|
|
|
int32_t v_int32;
|
|
|
|
uint32_t v_uint32;
|
|
|
|
int64_t v_int64;
|
|
|
|
uint64_t v_uint64;
|
|
|
|
uintptr_t v_ptr;
|
|
|
|
} value;
|
|
|
|
char buf[64];
|
|
|
|
char padc;
|
|
|
|
int padn;
|
|
|
|
int padd;
|
|
|
|
|
|
|
|
while ((c = *fmt)) {
|
|
|
|
switch (c) {
|
|
|
|
case '%':
|
|
|
|
c = *(++fmt);
|
|
|
|
|
|
|
|
padc = ' ';
|
|
|
|
padd = 1;
|
|
|
|
padn = 0;
|
|
|
|
if (c == '0') {
|
|
|
|
padc = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '-') {
|
|
|
|
padd = -1;
|
|
|
|
c = *(++fmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (c >= '0' && c <= '9') {
|
|
|
|
padn *= 10;
|
|
|
|
padn += padd * (int) (c - '0');
|
|
|
|
c = *(++fmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case 'l':
|
|
|
|
c = *(++fmt);
|
|
|
|
switch (c) {
|
|
|
|
case 'd':
|
|
|
|
value.v_int64 = va_arg(args, int64_t);
|
|
|
|
debug_ds(value.v_int64, buf, 1, 1);
|
|
|
|
debugsp(level, buf, padc, padn);
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
value.v_uint64 = va_arg(args, uint64_t);
|
|
|
|
debug_ds(value.v_uint64, buf, 0, 1);
|
|
|
|
debugsp(level, buf, padc, padn);
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
value.v_uint64 = va_arg(args, uint64_t);
|
|
|
|
debug_xs(value.v_uint64, buf, s_debug_xs_set0);
|
|
|
|
debugsp(level, buf, padc, padn);
|
|
|
|
break;
|
|
|
|
case 'X':
|
|
|
|
value.v_uint64 = va_arg(args, uint64_t);
|
|
|
|
debug_xs(value.v_uint64, buf, s_debug_xs_set1);
|
|
|
|
debugsp(level, buf, padc, padn);
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
value.v_uint64 = va_arg(args, uint64_t);
|
|
|
|
debugc(level, '0');
|
|
|
|
debugc(level, 'x');
|
|
|
|
debug_xs(value.v_uint64, buf, s_debug_xs_set0);
|
|
|
|
debugspl(level, buf, '0', sizeof(uint64_t) * 2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
debugc(level, '%');
|
|
|
|
debugc(level, 'l');
|
|
|
|
debugc(level, c);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
// char is promoted to int
|
|
|
|
value.v_char = va_arg(args, int);
|
|
|
|
debugc(level, value.v_char);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
value.v_int64 = va_arg(args, int32_t);
|
|
|
|
debug_ds(value.v_int64 & 0xFFFFFFFF, buf, 1, 0);
|
|
|
|
debugsp(level, buf, padc, padn);
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
value.v_uint64 = va_arg(args, uint32_t);
|
|
|
|
debug_ds(value.v_uint64 & 0xFFFFFFFF, buf, 0, 0);
|
|
|
|
debugsp(level, buf, padc, padn);
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
value.v_uint64 = va_arg(args, uint32_t);
|
|
|
|
debug_xs(value.v_uint64 & 0xFFFFFFFF, buf, s_debug_xs_set0);
|
|
|
|
debugsp(level, buf, padc, padn);
|
|
|
|
break;
|
|
|
|
case 'X':
|
|
|
|
value.v_uint64 = va_arg(args, uint32_t);
|
|
|
|
debug_xs(value.v_uint64 & 0xFFFFFFFF, buf, s_debug_xs_set1);
|
|
|
|
debugsp(level, buf, padc, padn);
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
value.v_ptr = va_arg(args, uintptr_t);
|
|
|
|
debugc(level, '0');
|
|
|
|
debugc(level, 'x');
|
|
|
|
debug_xs(value.v_ptr, buf, s_debug_xs_set0);
|
|
|
|
debugspl(level, buf, '0', sizeof(uintptr_t) * 2);
|
|
|
|
break;
|
2019-09-30 10:39:38 +03:00
|
|
|
case 'S':
|
|
|
|
value.v_ptr = va_arg(args, uintptr_t);
|
|
|
|
fmtsiz(buf, value.v_ptr);
|
|
|
|
debugsp(level, buf, padc, padn);
|
|
|
|
break;
|
2019-03-23 13:12:50 +02:00
|
|
|
case 's':
|
|
|
|
value.v_string = va_arg(args, const char *);
|
|
|
|
debugsp(level, value.v_string ? value.v_string : "(null)", padc, padn);
|
|
|
|
break;
|
2020-01-27 11:40:23 +02:00
|
|
|
case '%':
|
|
|
|
debugc(level, '%');
|
|
|
|
break;
|
2019-03-23 13:12:50 +02:00
|
|
|
default:
|
|
|
|
debugc(level, '%');
|
|
|
|
debugc(level, c);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
debugc(level, c);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
++fmt;
|
|
|
|
}
|
2019-10-10 19:29:05 +03:00
|
|
|
|
2019-10-11 19:55:31 +03:00
|
|
|
spin_release_irqrestore(&debug_spin, &irq);
|
2019-03-23 13:12:50 +02:00
|
|
|
}
|
|
|
|
|
2019-10-21 16:14:34 +03:00
|
|
|
void debug_dump(int level, const void *block, size_t count) {
|
|
|
|
size_t n_lines = (count + 15) / 16;
|
|
|
|
const char *bytes = block;
|
|
|
|
|
|
|
|
for (size_t l = 0; l < n_lines; ++l) {
|
2020-01-23 16:27:20 +02:00
|
|
|
debugf(level, "%08X: ", l * 16);
|
|
|
|
|
2019-10-21 16:14:34 +03:00
|
|
|
for (size_t i = 0; i < 8; ++i) {
|
|
|
|
if (i * 2 + l * 16 < count) {
|
|
|
|
uint16_t word = *(const uint16_t *) (bytes + i * 2 + l * 16);
|
|
|
|
|
|
|
|
debugc(level, s_debug_xs_set1[(word >> 4) & 0xF]);
|
|
|
|
debugc(level, s_debug_xs_set1[word & 0xF]);
|
|
|
|
|
|
|
|
debugc(level, s_debug_xs_set1[word >> 12]);
|
|
|
|
debugc(level, s_debug_xs_set1[(word >> 8) & 0xF]);
|
|
|
|
} else {
|
|
|
|
debugc(level, ' ');
|
|
|
|
debugc(level, ' ');
|
|
|
|
debugc(level, ' ');
|
|
|
|
debugc(level, ' ');
|
|
|
|
}
|
|
|
|
debugc(level, ' ');
|
|
|
|
}
|
|
|
|
|
|
|
|
debugc(level, '|');
|
|
|
|
debugc(level, ' ');
|
|
|
|
for (size_t i = 0; i < 16; ++i) {
|
|
|
|
if (i + l * 16 < count) {
|
|
|
|
char c = bytes[i + l * 16];
|
|
|
|
|
|
|
|
if (isprint(c)) {
|
|
|
|
debugc(level, c);
|
|
|
|
} else if (c != 0) {
|
|
|
|
debugc(level, ' ');
|
|
|
|
} else {
|
|
|
|
debugc(level, '.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
debugc(level, '\n');
|
|
|
|
}
|
|
|
|
}
|
2020-05-25 12:03:17 +03:00
|
|
|
|
|
|
|
uintptr_t __stack_chk_guard = 0x8BAD1DEA6EA11743;
|
|
|
|
__attribute__((noreturn)) void __stack_chk_fail(void) {
|
|
|
|
panic("Stack smashing detected\n");
|
|
|
|
}
|