1/** \file 2 * \brief x86-specific parts of in-kernel GDB stub. 3 * 4 * This file implements x86 architecture support for the kernel-side GDB stubs. 5 */ 6 7/* 8 * Copyright (c) 2007, 2008, 2010, ETH Zurich. 9 * All rights reserved. 10 * 11 * This file is distributed under the terms in the attached LICENSE file. 12 * If you do not find this file, copies can be found by writing to: 13 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 14 */ 15 16#include <kernel.h> 17#include <stdio.h> 18#include <paging_kernel_arch.h> 19#include <gdb_stub.h> 20#include <arch_gdb_stub.h> 21#include <barrelfish_kpi/cpu.h> 22 23#ifdef __k1om__ 24#define KERNEL_STACK_SIZE K1OM_KERNEL_STACK_SIZE 25#define MEMORY_OFFSET K1OM_MEMORY_OFFSET 26#define KERNEL_STACK k1om_kernel_stack 27#else 28#define KERNEL_STACK_SIZE X86_64_KERNEL_STACK_SIZE 29#define MEMORY_OFFSET X86_64_MEMORY_OFFSET 30#define KERNEL_STACK x86_64_kernel_stack 31#endif 32 33/** \brief GDB register save area / frame. 34 * 35 * Stores pointer to current save frame used by GDB. Used to read/modify 36 * register contents, and reloaded when program execution resumes. */ 37uintptr_t *gdb_arch_registers; 38 39/** \brief Separate stack area for the stub to run on */ 40static uintptr_t gdb_stack[KERNEL_STACK_SIZE/sizeof(uintptr_t)]; 41/** \brief Pointer to top of GDB stack area. */ 42uintptr_t * SNT gdb_stack_top = &gdb_stack[KERNEL_STACK_SIZE/sizeof(uintptr_t)]; 43 44/** \brief Converts exception vector to signal number. 45 * 46 * This function takes an x86 exception vector and attempts to 47 * translate this number into a Unix-compatible signal value. 48 */ 49static int exception_to_signal(int vector) 50{ 51 switch (vector) { 52 case 0: return 8; // divide by zero 53 case 1: return 5; // debug exception 54 case 3: return 5; // breakpoint 55 case 4: return 16; // into instruction (overflow) 56 case 5: return 16; // bound instruction 57 case 6: return 4; // Invalid opcode 58 case 7: return 8; // coprocessor not available 59 case 8: return 7; // double fault 60 case 9: return 11; // coprocessor segment overrun 61 case 10: return 11; // Invalid TSS 62 case 11: return 11; // Segment not present 63 case 12: return 11; // stack exception 64 case 13: return 11; // general protection 65 case 14: return 11; // page fault 66 case 16: return 7; // coprocessor error 67 default: return 7; // "software generated" 68 } 69} 70 71__asm__ ( 72 ".global gdb_handle_exception \n" 73 "gdb_handle_exception: \n" 74 "mov gdb_stack_top(%rip), %rsp \n" 75 "jmp gdb_handle_exception_onstack \n" 76); 77 78/** \brief Entry point for an exception; we are now on our own stack. 79 * 80 * This function sets up the GDB-format register save frame, constructs the 81 * initial message to the remote GDB and calls into the generic debugger entry 82 * point. 83 */ 84void gdb_handle_exception_onstack(int vector, uintptr_t * NONNULL 85 COUNT(GDB_X86_64_NUM_REGS) save_area) __attribute__((noreturn)); 86void gdb_handle_exception_onstack(int vector, uintptr_t * NONNULL 87 COUNT(GDB_X86_64_NUM_REGS) save_area) 88{ 89 /* sanity check that we didn't trap inside the debugger... 90 * if we did, we're definitely hosed now! */ 91 if (save_area[GDB_X86_64_RSP_REG] >= (lvaddr_t)&gdb_stack && 92 save_area[GDB_X86_64_RSP_REG] <= (lvaddr_t)gdb_stack_top) { 93 panic("Nested exception within GDB stub"); 94 } 95 96 /* were we in user mode at the time of the trap? */ 97 if ((save_area[GDB_X86_64_CS_REG] & 0x3) != 0) { 98 printk(LOG_NOTE, 99 "Entered from user-mode (at least, CPL in CS is non-zero)\n"); 100 101 /* while we're checking the stack pointer, sanity check that it's 102 * within the normal kernel stack region */ 103 } else if (save_area[GDB_X86_64_RSP_REG] < (lvaddr_t)&KERNEL_STACK || 104 save_area[GDB_X86_64_RSP_REG] > (lvaddr_t)&KERNEL_STACK + 105 KERNEL_STACK_SIZE) { 106 printk(LOG_WARN, "BIG FAT WARNING: kernel stack pointer (0x%lx) is " 107 "invalid!\n", save_area[GDB_X86_64_RSP_REG]); 108 printk(LOG_WARN, "Boldly attempting to continue into GDB anyway...\n"); 109 } 110 111 char buffer[64]; 112 int signal = exception_to_signal(vector); 113 114#if 0 // this is broken, because the register data needs to be in LE byte order 115 // T <signal> RSP:<stack ptr>; RIP:<inst ptr>; 116 int r = snprintf(buffer, sizeof(buffer), "T%02hhx%x:%lx;%x:%lx;", signal, 117 RSP_REG, save_area[RSP_REG], 118 RIP_REG, save_area[RIP_REG]); 119#else 120 int r = snprintf(buffer, sizeof(buffer), "S%02x", signal); 121#endif 122 assert(r < sizeof(buffer)); 123 if (r >= sizeof(buffer)) { 124 // ensure termination in the case of overflow 125 buffer[sizeof(buffer) - 1] = '\0'; 126 } 127 128 gdb_arch_registers = save_area; 129 gdb_stub_entry(signal, buffer); 130} 131 132/** \brief Get the value of a single register in the frame. 133 * \param regnum register number (as defined by the #gdb_register_nums enum) 134 * \param value pointer to location in which to return current value 135 * \return Zero on success, nonzero on failure (invalid regnum). 136 */ 137int gdb_arch_get_register(int regnum, uintptr_t *value) 138{ 139 if (regnum < 0 || regnum >= GDB_X86_64_NUM_REGS) { 140 return -1; 141 } 142 143 *value = gdb_arch_registers[regnum]; 144 return 0; 145} 146 147/** \brief Set the value of a single register in the frame. 148 * \param regnum register number (as defined by the #gdb_register_nums enum) 149 * \param value new value 150 * \return Zero on success, nonzero on failure (invalid regnum). 151 */ 152int gdb_arch_set_register(int regnum, uintptr_t value) 153{ 154 if (regnum < 0 || regnum >= GDB_X86_64_NUM_REGS) { 155 return -1; 156 } 157 158 gdb_arch_registers[regnum] = value; 159 return 0; 160} 161 162/** \brief Resume execution. 163 * 164 * Resumes execution with the CPU state stored in the #gdb_arch_registers frame. 165 */ 166void gdb_resume(void) __attribute__((noreturn)); 167 168__asm__ ( 169 ".global gdb_resume \n" 170 "gdb_resume: \n" 171 /* load address (in PIC manner) of register frame */ 172 "movq gdb_arch_registers(%rip), %r15\n" 173 /* setup stack for iretq below */ 174 "movq (19*8)(%r15), %rax \n" // SS 175 "pushq %rax \n" 176 "movq (7*8)(%r15), %rax \n" // RSP 177 "pushq %rax \n" 178 "movq (17*8)(%r15), %rax \n" // EFLAGS 179 "pushq %rax \n" 180 "movq (18*8)(%r15), %rax \n" // CS 181 "pushq %rax \n" 182 "movq (16*8)(%r15), %rax \n" // EIP 183 "pushq %rax \n" 184 /* load remaining registers directly */ 185 "movq (0*8)(%r15), %rax \n" 186 "movq (1*8)(%r15), %rbx \n" 187 "movq (2*8)(%r15), %rcx \n" 188 "movq (3*8)(%r15), %rdx \n" 189 "movq (4*8)(%r15), %rsi \n" 190 "movq (5*8)(%r15), %rdi \n" 191 "movq (6*8)(%r15), %rbp \n" 192 "movq (8*8)(%r15), %r8 \n" 193 "movq (9*8)(%r15), %r9 \n" 194 "movq (10*8)(%r15), %r10 \n" 195 "movq (11*8)(%r15), %r11 \n" 196 "movq (12*8)(%r15), %r12 \n" 197 "movq (13*8)(%r15), %r13 \n" 198 "movq (14*8)(%r15), %r14 \n" 199 "movq (15*8)(%r15), %r15 \n" 200 /* return! */ 201 "iretq \n" 202); 203 204/** \brief Resume program execution. 205 * \param addr Address to resume at, or 0 to continue at last address. 206 */ 207void gdb_arch_continue(lvaddr_t addr) 208{ 209 if (addr != 0) { 210 gdb_arch_registers[GDB_X86_64_RIP_REG] = addr; 211 } 212 213 /* clear the trace bit */ 214 gdb_arch_registers[GDB_X86_64_EFLAGS_REG] &= ~0x100; // XXX 215 216 gdb_resume(); /* doesn't return */ 217} 218 219/** \brief Single-step program execution. 220 * \param addr Address to resume at, or 0 to continue at last address. 221 */ 222void gdb_arch_single_step(lvaddr_t addr) 223{ 224 if (addr != 0) { 225 gdb_arch_registers[GDB_X86_64_RIP_REG] = addr; 226 } 227 228 /* set the trace bit for single-step */ 229 gdb_arch_registers[GDB_X86_64_EFLAGS_REG] |= 0x100; // XXX 230 231 gdb_resume(); /* doesn't return */ 232} 233 234/** \brief Ensures that the page containing addr is mapped. 235 * \return Zero on success, negative on failure. 236 */ 237static int ensure_mapping(lvaddr_t addr) 238{ 239 static lpaddr_t lastaddr; 240 241 /* check if address is in kernel image */ 242 if (addr >= (lvaddr_t)&_start_kernel && addr < (lvaddr_t)&_end_kernel) { 243 return 0; 244 } 245 246 /* if address is outside "physical" memory region, fail the access */ 247 if (addr < MEMORY_OFFSET) { 248 return -1; 249 } 250 251 /* we now know we have a valid "physical memory" region address */ 252 lpaddr_t paddr = mem_to_local_phys(addr); 253 paddr -= paddr & X86_64_MEM_PAGE_MASK; // page-align 254 255 /* quick and dirty optimisation: if this address is on the same page as 256 * the last time we were called, return immediately */ 257 if (lastaddr == paddr && lastaddr != 0) { 258 return 0; 259 } 260 261 int r = paging_x86_64_map_memory(paddr, X86_64_MEM_PAGE_SIZE); 262 if (r < 0) { 263 return r; 264 } 265 266 lastaddr = paddr; 267 return 0; 268} 269 270/** \brief Writes a byte to an arbitrary address in kernel memory. 271 * \return Zero on success, nonzero on error (invalid address) 272 */ 273int gdb_arch_write_byte(uint8_t *addr, uint8_t val) 274{ 275 int r = ensure_mapping((lvaddr_t)addr); 276 if (r < 0) { 277 return r; 278 } 279 280 *addr = val; 281 return 0; 282} 283 284/** \brief Reads a byte from an arbitrary address in kernel memory. 285 * \return Zero on success, nonzero on error (invalid address) 286 */ 287int gdb_arch_read_byte(uint8_t *addr, uint8_t *val) 288{ 289 int r = ensure_mapping((lvaddr_t)addr); 290 if (r < 0) { 291 return r; 292 } 293 294 *val = *addr; 295 return 0; 296} 297