diff --git a/include/panic.h b/include/panic.h index d7f612c..08b7561 100644 --- a/include/panic.h +++ b/include/panic.h @@ -3,11 +3,11 @@ #define _PANIC_STR(x) _PANIC_STR2(x) #define _PANIC_STR2(x) #x -#define panic(msg, ...) _panic_impl(_PANIC_STR(__LINE__), __FILE__, msg, ## __VA_ARGS__) -#define kassert(val, msg, ...) do { if (!(val)) { panic(msg, ## __VA_ARGS__); } } while(0) +#define panic(...) _panic_impl(_PANIC_STR(__LINE__), __FILE__, __VA_ARGS__) +#define kassert(val, ...) do { if (!(val)) { panic(__VA_ARGS__); } } while(0) -__attribute__((noreturn,format(printf, 3, 4))) -void _panic_impl(char *line, char *file, char *msg, ...); +__attribute__((format(printf, 3, 4))) +_Noreturn void _panic_impl(char *line, char *file, char *format, ...); -__attribute__((noreturn,format(printf, 3, 4))) -void _panic_interrupt(void *ip, void *bp, char *msg, ...); +__attribute__((format(printf, 3, 4))) +_Noreturn void panic_interrupt(void *ip, void *bp, char *format, ...); diff --git a/src/arch/amd64/acpi.c b/src/arch/amd64/acpi.c index d476ac8..e262a99 100644 --- a/src/arch/amd64/acpi.c +++ b/src/arch/amd64/acpi.c @@ -6,7 +6,6 @@ #include "bindings.h" #include "memory.h" -#include "serial.h" /* global state, idk a better way rn */ struct acpi_state state; @@ -208,7 +207,7 @@ static void *acpi_find_table_rsdt(struct rsdt *rsdt, const char *identifier, int memcpy(buf, h->signature, 4); buf[4] = '\n'; buf[5] = '\0'; - serial_out_str(buf); + kputs(buf); if (!strncmp(h->signature, identifier, ident_len)) return (void *)h; } diff --git a/src/arch/amd64/backtrace.c b/src/arch/amd64/backtrace.c index a5e8ffd..9e1c9d7 100644 --- a/src/arch/amd64/backtrace.c +++ b/src/arch/amd64/backtrace.c @@ -1,6 +1,5 @@ #include #include -#include "serial.h" struct stackframe { struct stackframe *rbp; @@ -36,17 +35,10 @@ void log_backtrace() { void log_backtrace_ex(void *ip, void *bp) { struct stackframe *frame = bp; - char buf[20]; - serial_out_str("Stack trace:\n"); - ultoa((size_t)ip, buf, 16); - serial_out_str(" 0x"); - serial_out_str(buf); - serial_out_str("\n"); + kputs("Stack trace:\n"); + kprintf(" %#lx\n", (size_t)ip); while (frame) { - ultoa((size_t)frame->rip, buf, 16); - serial_out_str(" 0x"); - serial_out_str(buf); - serial_out_str("\n"); + kprintf(" %#lx\n", (size_t)frame->rip); frame = frame->rbp; } diff --git a/src/arch/amd64/debugger.c b/src/arch/amd64/debugger.c index 2356e4a..a1fa968 100644 --- a/src/arch/amd64/debugger.c +++ b/src/arch/amd64/debugger.c @@ -1,7 +1,7 @@ #include #include -#include #include +#include #include "debugger.h" struct dr6 { @@ -73,183 +73,217 @@ struct breakpoint { uint8_t rw; uint8_t used; uint8_t enable; + uint8_t instr_len; }; -static size_t dbg_steps = 0; +static int dbg_steps = 0; static int dbg_continue = 0; static struct breakpoint bkps[4] = {{0}, {0}, {0}, {0}}; -static void dbg_putc(char c) { - serial_out(c); -} - -static void dbg_puts(char *msg) { - serial_out_str(msg); -} - -static char dbg_getc() { - return serial_in(); +static size_t debugger_read(char *buf, size_t len) { + char *p = buf; + size_t result; + while (p < buf + len - 1) { + char ch = serial_in(); + switch (ch) { + case '\r': + goto end; + case '\x7f': + if (p > buf) { + p--; + kputs("\x08 \x08"); + } + break; + default: + kputc(ch); + *p++ = ch; + } + } +end: + result = p - buf; + kputc('\n'); + for(; p < buf + len; p++) { + *p = 0; + } + return result; } static void debugger_msg(int cause, struct dr6 dr6) { - char buf[24]; switch (cause) { case DEBUG_INT3: - dbg_puts("dbg: reached int3"); + kputs("dbg: reached int3"); break; case DEBUG_FAULT: - dbg_puts("dbg: a fault occured"); + kputs("dbg: a fault occured"); break; case DEBUG_DBG: if (dr6.bs) - dbg_puts("dbg: finished steps"); - else if (dr6.b0) - dbg_puts("dbg: reached breakpoint 0"); + kputs("dbg: finished steps"); + if (dr6.b0) + kputs("dbg: reached breakpoint 0"); else if (dr6.b1) - dbg_puts("dbg: reached breakpoint 1"); + kputs("dbg: reached breakpoint 1"); else if (dr6.b2) - dbg_puts("dbg: reached breakpoint 2"); + kputs("dbg: reached breakpoint 2"); else if (dr6.b3) - dbg_puts("dbg: reached breakpoint 3"); + kputs("dbg: reached breakpoint 3"); } if (dbg_steps > 0) { - ultoa(dbg_steps, buf, 10); - dbg_puts(" ("); - dbg_puts(buf); - dbg_puts(" steps left)"); + kprintf(" (%d steps left)", dbg_steps); } if (dbg_continue > 0) { - dbg_puts(" (paused continue)"); + kputs(" (paused continue)"); } - dbg_puts("\n"); -} - -static void debugger_print_reg(char *name, uint64_t val) { - char buf[24]; - char *end; - dbg_puts(name); - dbg_puts(": 0x"); - - end = ultoa(val, buf, 16); - for (int i = 0; i < 16 - (end - buf); i++) { - dbg_putc('0'); - } - dbg_puts(buf); - - dbg_puts(" ("); - end = ultoa(val, buf, 10); - dbg_puts(buf); - dbg_puts(")\n"); + kputs("\n"); } static void debugger_print_regs(struct isr_regs *state) { - debugger_print_reg("rax", state->rax); - debugger_print_reg("rbx", state->rbx); - debugger_print_reg("rcx", state->rcx); - debugger_print_reg("rdx", state->rdx); - debugger_print_reg("rsi", state->rsi); - debugger_print_reg("rdi", state->rdi); - debugger_print_reg("rsp", state->rsp); - debugger_print_reg("rbp", state->rbp); - debugger_print_reg("r8 ", state->r8 ); - debugger_print_reg("r9 ", state->r9 ); - debugger_print_reg("r10", state->r10); - debugger_print_reg("r11", state->r11); - debugger_print_reg("r12", state->r12); - debugger_print_reg("r13", state->r13); - debugger_print_reg("r14", state->r14); - debugger_print_reg("r15", state->r15); - dbg_puts("---\n"); - debugger_print_reg("rip", state->rip); - dbg_puts("---\n"); - debugger_print_reg("rflags", state->rflags); + kprintf("rax: %#016lx (%lu)\n", state->rax, state->rax); + kprintf("rbx: %#016lx (%lu)\n", state->rbx, state->rbx); + kprintf("rcx: %#016lx (%lu)\n", state->rcx, state->rcx); + kprintf("rdx: %#016lx (%lu)\n", state->rdx, state->rdx); + kprintf("rsi: %#016lx (%lu)\n", state->rsi, state->rsi); + kprintf("rdi: %#016lx (%lu)\n", state->rdi, state->rdi); + kprintf("rsp: %#016lx (%lu)\n", state->rsp, state->rsp); + kprintf("rbp: %#016lx (%lu)\n", state->rbp, state->rbp); + kprintf("r8 : %#016lx (%lu)\n", state->r8 , state->r8 ); + kprintf("r9 : %#016lx (%lu)\n", state->r9 , state->r9 ); + kprintf("r10: %#016lx (%lu)\n", state->r10, state->r10); + kprintf("r11: %#016lx (%lu)\n", state->r11, state->r11); + kprintf("r12: %#016lx (%lu)\n", state->r12, state->r12); + kprintf("r13: %#016lx (%lu)\n", state->r13, state->r13); + kprintf("r14: %#016lx (%lu)\n", state->r14, state->r14); + kprintf("r15: %#016lx (%lu)\n", state->r15, state->r15); + kputs("---\n"); + kprintf("rip: %#016lx (%lu)\n", state->rip, state->rip); + kputs("---\n"); + kprintf("rflags: %#016lx (%lu)\n", state->rflags, state->rflags); struct rflags *rflags = (struct rflags *)state->rflags; - dbg_puts("rflags: "); - if(rflags->cf) dbg_puts("CF "); - if(rflags->pf) dbg_puts("PF "); - if(rflags->af) dbg_puts("AF "); - if(rflags->zf) dbg_puts("ZF "); - if(rflags->sf) dbg_puts("SF "); - if(rflags->tf) dbg_puts("TF "); - if(rflags->if_) dbg_puts("IF "); - if(rflags->df) dbg_puts("DF "); - if(rflags->of) dbg_puts("OF "); - if(rflags->iopl) dbg_puts("IOPL "); - if(rflags->nt) dbg_puts("NT "); - if(rflags->md) dbg_puts("MD "); - if(rflags->rf) dbg_puts("RF "); - if(rflags->vm) dbg_puts("VM "); - if(rflags->ac) dbg_puts("AC "); - if(rflags->vif) dbg_puts("VIF "); - if(rflags->vip) dbg_puts("VIP "); - if(rflags->id) dbg_puts("ID "); - dbg_putc('\n'); + kputs("rflags: "); + if(rflags->cf) kputs("CF "); + if(rflags->pf) kputs("PF "); + if(rflags->af) kputs("AF "); + if(rflags->zf) kputs("ZF "); + if(rflags->sf) kputs("SF "); + if(rflags->tf) kputs("TF "); + if(rflags->if_) kputs("IF "); + if(rflags->df) kputs("DF "); + if(rflags->of) kputs("OF "); + if(rflags->iopl) kputs("IOPL "); + if(rflags->nt) kputs("NT "); + if(rflags->md) kputs("MD "); + if(rflags->rf) kputs("RF "); + if(rflags->vm) kputs("VM "); + if(rflags->ac) kputs("AC "); + if(rflags->vif) kputs("VIF "); + if(rflags->vip) kputs("VIP "); + if(rflags->id) kputs("ID "); + kputs("\n"); } #define PROMPT_LEN 60 -static int debugger_handle_bkp_cmd(char *buf) { - if (buf[0] == 'l') { +static int debugger_handle_bkp_cmd(char *msg) { + if (msg[0] == 'l') { // list breakpoints - char buf[20]; for (int i = 0; i < 4; i++) { - dbg_puts("breakpoint "); - dbg_putc('0' + i); - dbg_puts(": "); struct breakpoint bkp = bkps[i]; if(!bkp.used) { - dbg_puts("unset\n"); + kprintf("breakpoint %d: unset\n", i); continue; } - dbg_puts(" 0x"); - ultoa(bkp.addr, buf, 16); - dbg_puts(buf); - dbg_puts(" len="); - switch (bkp.len) { - case 0x0: dbg_putc('1'); break; - case 0x1: dbg_putc('2'); break; - case 0x2: dbg_putc('8'); break; - case 0x3: dbg_putc('4'); break; - } - dbg_puts(" trigger="); - switch (bkp.rw) { - case 0x0: dbg_puts("x "); break; - case 0x1: dbg_puts("w "); break; - case 0x2: dbg_puts("io"); break; - case 0x3: dbg_puts("rw"); break; - } - dbg_puts(bkp.enable ? " enabled" : " disabled"); + const char *lenstrs[] = {"1", "2", "8", "4"}; + const char *rwstrs[] = {"x ", "w ", "io", "rw"}; + kprintf( + "breakpoint %d: %#016lx len=%s trigger=%s instrlen=%01d %s\n", + i, + bkp.addr, + lenstrs[bkp.len], + rwstrs[bkp.rw], + bkp.instr_len, + bkp.enable ? " enabled" : " disabled" + ); } return 1; - } else if (buf[0] == 'd') { + } else if (msg[0] == 'd') { // disable breakpoints bkps[0].enable = 0; bkps[1].enable = 0; bkps[2].enable = 0; bkps[3].enable = 0; + kputs("disabled breakpoints\n"); return 1; - } else if (buf[0] == 'c') { + } else if (msg[0] == 'c') { // clear breakpoints bkps[0].used = 0; bkps[1].used = 0; bkps[2].used = 0; bkps[3].used = 0; + kputs("cleared breakpoints\n"); return 1; - } else if (buf[0] <= '0' && buf[0] >= '3') { - dbg_puts("invalid breakpoint command\n"); + } else if (msg[0] <= '0' && msg[0] >= '3') { + kputs("invalid breakpoint command\n"); + return 1; + } + char buf[64]; + int id = msg[0] - '0'; + switch (msg[1]) { + case 'e': + bkps[id].enable = bkps[id].used; + kprintf("enabled breakpoint %d\n", id); + return 1; + case 'd': + bkps[id].enable = 0; + kprintf("disabled breakpoint %d\n", id); + return 1; + case 'c': + bkps[id].used = 0; + kprintf("cleared breakpoint %d\n", id); + return 1; + case 'a': + kputs("addr> 0x"); + debugger_read(buf, 64); + bkps[id].addr = strtoll(buf, NULL, 16); + kputs("len (1/2/4/8)> "); + debugger_read(buf, 64); + switch (buf[0]) { + case '1': bkps[id].len = 0x0; break; + case '2': bkps[id].len = 0x1; break; + case '8': bkps[id].len = 0x2; break; + case '4': bkps[id].len = 0x3; break; + default: bkps[id].len = 0x0; break; + } + kputs("cond (x/w/io/rw)> "); + debugger_read(buf, 64); + switch ((int)buf[0] * 256 + (int)buf[1]) { + case (int)'x'*256 + (int)0: bkps[id].rw = 0x0; break; + case (int)'w'*256 + (int)0: bkps[id].rw = 0x1; break; + case (int)'i'*256 + (int)'o': bkps[id].rw = 0x2; break; + case (int)'r'*256 + (int)'w': bkps[id].rw = 0x3; break; + default: bkps[id].len = 0x0; break; + } + kputs("instr len (1..15)> "); + debugger_read(buf, 64); + bkps[id].instr_len = strtoi(buf, NULL, 10); + kputs("enable (y/n)> "); + debugger_read(buf, 64); + bkps[id].used = 1; + bkps[id].enable = !(buf[0] == 'n' || buf[0] == 'N'); + kprintf("added breakpoint %d\n", id); + return 1; + default: + kputs("invalid breakpoint command\n"); return 1; } - // TODO set breakpoints - return 1; } static void debugger_load_bkps() { struct dr7 dr7; __asm__ volatile ("mov %%dr7, %0" : "=r"(dr7)); dr7.g0 = bkps[0].enable & bkps[0].used; - dr7.g1 = bkps[1].enable & bkps[0].used; - dr7.g2 = bkps[2].enable & bkps[0].used; - dr7.g3 = bkps[3].enable & bkps[0].used; + dr7.g1 = bkps[1].enable & bkps[1].used; + dr7.g2 = bkps[2].enable & bkps[2].used; + dr7.g3 = bkps[3].enable & bkps[3].used; dr7.l0 = 0; dr7.l1 = 0; dr7.l2 = 0; @@ -263,19 +297,16 @@ static void debugger_load_bkps() { dr7.len2 = bkps[2].len; dr7.len3 = bkps[3].len; __asm__ volatile ("mov %0, %%dr7" : : "r"(dr7)); + __asm__ volatile ("mov %0, %%dr0" : : "r"(bkps[0].addr)); + __asm__ volatile ("mov %0, %%dr1" : : "r"(bkps[1].addr)); + __asm__ volatile ("mov %0, %%dr2" : : "r"(bkps[2].addr)); + __asm__ volatile ("mov %0, %%dr3" : : "r"(bkps[3].addr)); } static int debugger_prompt(struct isr_regs *state) { - char buf[PROMPT_LEN]; - char *p = buf; - dbg_puts("dbg> "); - while ((*p = dbg_getc()) != '\r' && p < buf + PROMPT_LEN - 1) { - dbg_putc(*p++); - } - dbg_putc('\n'); - for(; p < buf + PROMPT_LEN; p++) { - *p = 0; - } + kputs("dbg> "); + char buf[64]; + debugger_read(buf, 64); struct rflags *rflags = (struct rflags *)&state->rflags; @@ -283,7 +314,7 @@ static int debugger_prompt(struct isr_regs *state) { case '\0': // nothing entered return 1; case 'h': // help - dbg_puts("see debugger.c for help information\n"); + kputs("see debugger.c for help information\n"); return 1; case 'q': // quit return 0; @@ -302,6 +333,36 @@ static int debugger_prompt(struct isr_regs *state) { dbg_steps = atol(buf + 1) - 1; //if (dbg_steps < 0) dbg_steps = 0; return 0; + case 'm': // memory + { + kputs("addr> 0x"); + debugger_read(buf, 64); + uint64_t start = (~0xF) & strtoll(buf, NULL, 16); + + kputs("len> 0x"); + debugger_read(buf, 64); + uint64_t len = (~0xF) & strtoll(buf, NULL, 16); + + for (uint64_t a = start; a <= start + len; a += 0x10) { + kprintf("%08lx: ", a); + for (uint64_t b = 0; b < 0x10; b++) { + kprintf("%02x ", *(uint8_t *)(a + b)); + if (b % 0x08 == 7) { + kputc(' '); + } + } + kputs("|"); + for (uint64_t b = 0; b < 0x10; b++) { + uint8_t ch = *(uint8_t *)(a + b); + if (ch < 0x20 || ch >= 0x7f) { + ch = '.'; + } + kputc(ch); + } + kputs("|\n"); + } + return 1; + } case 'b': // breakpoints { int res = debugger_handle_bkp_cmd(buf+1); @@ -309,7 +370,7 @@ static int debugger_prompt(struct isr_regs *state) { return res; } default: - dbg_puts("unknown command\n"); + kputs("unknown command\n"); return 1; } } @@ -318,9 +379,7 @@ void debugger(struct isr_regs *state, int cause) { struct dr6 dr6; __asm__ volatile ("mov %%dr6, %0" : "=r"(dr6)); - if (dr6.b0 || dr6.b1 || dr6.b2 || dr6.b3) { - - } else { + if (!(dr6.b0 || dr6.b1 || dr6.b2 || dr6.b3)) { if (dr6.bs && dbg_steps > 0) { dbg_steps--; return; @@ -333,11 +392,22 @@ void debugger(struct isr_regs *state, int cause) { debugger_msg(cause, dr6); + kputs("hi\n"); + dbg_steps = 0; dbg_continue = 0; - struct rflags *rflags = (struct rflags *)&state->rflags; - rflags->tf = 0; + ((struct rflags *)&state->rflags)->tf = 0; + + if (dr6.b0) { + state->rip += bkps[0].instr_len; + } else if (dr6.b1) { + state->rip += bkps[1].instr_len; + } else if (dr6.b2) { + state->rip += bkps[2].instr_len; + } else if (dr6.b3) { + state->rip += bkps[3].instr_len; + } while (debugger_prompt(state)); } diff --git a/src/arch/amd64/fb.c b/src/arch/amd64/fb.c index 8484f29..8560166 100644 --- a/src/arch/amd64/fb.c +++ b/src/arch/amd64/fb.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include diff --git a/src/arch/amd64/idt.c b/src/arch/amd64/idt.c index a2ee2a7..d33c795 100644 --- a/src/arch/amd64/idt.c +++ b/src/arch/amd64/idt.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include "debugger.h" @@ -74,48 +73,48 @@ void idt_init(void) { // Intel manual vol 3 ch 6.3.1 char *EXCEPTIONS[] = { - "0x00 Division Error", - "0x01 Debug", - "0x02 NMI", - "0x03 Breakpoint", - "0x04 Overflow", - "0x05 BOUND Range Exceeded", - "0x06 Invalid Opcode", - "0x07 Device Not Available", - "0x08 Double Fault", - "0x09 Coprocessor Segment Overrun", - "0x0A Invalid TSS", - "0x0B Segment Not Present", - "0x0C Stack-Segment Fault", - "0x0D General Protection Fault", - "0x0E Page Fault", - "0x0F Reserved", - "0x10 x87 Floating-Point Error", - "0x11 Alignment Check", - "0x12 Machine Check", - "0x13 SIMD Floaing-Point Exception", - "0x14 Virtualization Exception", - "0x15 Control Protection Exception", - "0x16 Reserved", - "0x17 Reserved", - "0x18 Reserved", - "0x19 Reserved", - "0x1A Reserved", - "0x1B Reserved", - "0x1C Hypervisor Injection Exception", - "0x1D VMM Communication Exception", - "0x1E Security Exception", - "0x1F Reserved", + "Division Error", + "Debug", + "NMI", + "Breakpoint", + "Overflow", + "BOUND Range Exceeded", + "Invalid Opcode", + "Device Not Available", + "Double Fault", + "Coprocessor Segment Overrun", + "Invalid TSS", + "Segment Not Present", + "Stack-Segment Fault", + "General Protection Fault", + "Page Fault", + "Reserved", + "x87 Floating-Point Error", + "Alignment Check", + "Machine Check", + "SIMD Floaing-Point Exception", + "Virtualization Exception", + "Control Protection Exception", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Hypervisor Injection Exception", + "VMM Communication Exception", + "Security Exception", + "Reserved", }; void idt_exception_handler(uint64_t exception, uint64_t code, struct isr_regs *state) { - // breakpoint interrupt - if (exception == 0x03) { - debugger(state, DEBUG_INT3); - return; - } else if (exception == 0x01) { + switch (exception) { + case 0x01: // debug debugger(state, DEBUG_DBG); return; + case 0x03: // breakpoint + debugger(state, DEBUG_INT3); + return; } char custom[64]; @@ -124,12 +123,12 @@ void idt_exception_handler(uint64_t exception, uint64_t code, struct isr_regs *s // page faults store the offending address in cr2 if (exception == 0x0E) { strcat(custom, "\nPage fault address: 0x"); - void *addr; - __asm__ volatile ("mov %%cr2, %0" : "=r"(addr)); - ultoa((size_t)addr, custom + 23, 16); + uint64_t cr2; + __asm__ volatile ("mov %%cr2, %0" : "=r"(cr2)); + ultoa((size_t)cr2, custom + 23, 16); } - _panic_interrupt( + panic_interrupt( (void *)state->rip, (void *)state->rbp, "Exception %s\nError code 0x%lu%s", @@ -149,7 +148,7 @@ void idt_pic_timer(void) { // print a message once we know the timer works // but avoid spamming the logs if (counter == 3) { - serial_out_str("pic timer!\n"); + kputs("pic timer!\n"); } if (counter <= 3) { counter++; diff --git a/src/arch/amd64/panic.c b/src/arch/amd64/panic.c index fa750bc..6c35727 100644 --- a/src/arch/amd64/panic.c +++ b/src/arch/amd64/panic.c @@ -1,31 +1,34 @@ #include #include #include + #include #include "bindings.h" -void _panic_impl(char *line, char *file, char *format, ...) { +_Noreturn void _panic_impl(char *line, char *file, char *format, ...) { cli(); va_list list; - va_start(list, msg); + va_start(list, format); kprintf("\n\n!!! PANIC !!!\n"); kprintf("In file %s at line %s:\n", file, line); kvprintf(format, list); kprintf("\n\n"); + log_backtrace(); while (1) { halt(); } } -void _panic_interrupt(void *ip, void *bp, char *format, ...) { - cli(); +_Noreturn void panic_interrupt(void *ip, void *bp, char *msg, ...) { va_list list; va_start(list, msg); - kprintf("\n\n!!! PANIC !!!\n"); - kvprintf(format, list); - kprintf("\n\n"); + cli(); + kputs("\n\n!!! PANIC !!!\n"); + kvprintf(msg, list); + kputs("\n\n"); + log_backtrace_ex(ip, bp); while (1) { halt(); diff --git a/src/kmain.c b/src/kmain.c index bc1d225..7ae9d01 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -20,6 +19,7 @@ void kmain(struct boot_info *info) { *(char *)(0xB8000 + 0x144) = 'h'; *(char *)(0xB8000 + 0x146) = 'i'; + while (1) { __asm__("hlt;"); // loop so we dont halt diff --git a/src/print.c b/src/print.c index 712df30..4adfcf7 100644 --- a/src/print.c +++ b/src/print.c @@ -344,7 +344,7 @@ static void print_unum( bool space_pre = (flag & FLG_LEFT_ALIGN) || !(flag & FLG_ZERO); - if (!space_pre && radix == 16 && flag & FLG_ALTERNATE) { + if (!space_pre && radix == 16 && (flag & FLG_ALTERNATE)) { char x = base + ('x' - 'a'); serial_out('0'); serial_out(x); @@ -371,6 +371,12 @@ static void print_unum( if (flag & FLG_ZERO) zero_padded = true; } + + if (space_pre && radix == 16 && (flag & FLG_ALTERNATE)) { + char x = base + ('x' - 'a'); + serial_out('0'); + serial_out(x); + } if (space_pre && radix == 16 && flag & FLG_ALTERNATE) { char x = base + ('x' - 'a');