Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:15

0001 /*
0002  * Copyright (c) 2016 Chris Johns <chrisj@rtems.org>.
0003  * All rights reserved.
0004  *
0005  * Redistribution and use in source and binary forms, with or without
0006  * modification, are permitted provided that the following conditions
0007  * are met:
0008  * 1. Redistributions of source code must retain the above copyright
0009  *    notice, this list of conditions and the following disclaimer.
0010  * 2. Redistributions in binary form must reproduce the above copyright
0011  *    notice, this list of conditions and the following disclaimer in the
0012  *    documentation and/or other materials provided with the distribution.
0013  *
0014  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
0015  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0016  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0017  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
0018  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0019  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0020  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0021  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0022  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0023  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0024  * SUCH DAMAGE.
0025  */
0026 
0027 #define TARGET_DEBUG 1
0028 
0029 #ifdef HAVE_CONFIG_H
0030 #include "config.h"
0031 #endif
0032 
0033 #include <errno.h>
0034 #include <inttypes.h>
0035 #include <stdlib.h>
0036 
0037 #include <rtems.h>
0038 #include <rtems/score/threadimpl.h>
0039 
0040 #include "rtems-debugger-target.h"
0041 #include "rtems-debugger-threads.h"
0042 
0043 /*
0044  * Hardware breakpoints. Limited by hardware
0045  */
0046 #define RTEMS_DEBUGGER_HWBREAK_NUM 4
0047 
0048 /*
0049  * Number of registers.
0050  */
0051 #define RTEMS_DEBUGGER_NUMREGS 16
0052 
0053 /*
0054  * Number of bytes per register.
0055  */
0056 #define RTEMS_DEBUGGER_REG_BYTES 4
0057 
0058 /*
0059  * Debugger registers layout.
0060  */
0061 #define REG_EAX    0
0062 #define REG_ECX    1
0063 #define REG_EDX    2
0064 #define REG_EBX    3
0065 #define REG_ESP    4
0066 #define REG_EBP    5
0067 #define REG_ESI    6
0068 #define REG_EDI    7
0069 #define REG_PC     8
0070 #define REG_EIP    REG_PC
0071 #define REG_PS     9
0072 #define REG_EFLAGS REG_PS
0073 #define REG_CS     10
0074 #define REG_SS     11
0075 #define REG_DS     12
0076 #define REG_ES     13
0077 #define REG_FS     14
0078 #define REG_GS     15
0079 
0080 /**
0081  * Register offset table with the total as the last entry.
0082  *
0083  * Check this table in gdb with the command:
0084  *
0085  *   maint print registers
0086  */
0087 static const size_t i386_reg_offsets[RTEMS_DEBUGGER_NUMREGS + 1] =
0088 {
0089   0,   /* REG_EAX    4 uint32_t */
0090   4,   /* REG_ECX    4 uint32_t */
0091   8,   /* REG_EDX    4 uint32_t */
0092   12,  /* REG_EBX    4 uint32_t */
0093   16,  /* REG_ESP    4 uint32_t */
0094   20,  /* REG_EBP    4 uint32_t */
0095   24,  /* REG_ESI    4 uint32_t */
0096   28,  /* REG_EDI    4 uint32_t */
0097   32,  /* REG_EIP    4 *1 */
0098   36,  /* REG_EFLAGS 4 uint32_t */
0099   40,  /* REG_CS     4 uint32_t */
0100   44,  /* REG_SS     4 uint32_t */
0101   48,  /* REG_DS     4 uint32_t */
0102   52,  /* REG_ES     4 uint32_t */
0103   56,  /* REG_FS     4 uint32_t */
0104   60,  /* REG_GS     4 uint32_t */
0105   64   /* total size */
0106 };
0107 
0108 /*
0109  * Number of bytes of registers.
0110  */
0111 #define RTEMS_DEBUGGER_NUMREGBYTES i386_reg_offsets[RTEMS_DEBUGGER_NUMREGS]
0112 
0113 /**
0114  * The int 3 opcode.
0115  */
0116 #define TARGET_BKPT 0xcc
0117 
0118 static const uint8_t breakpoint[1] = { TARGET_BKPT };
0119 
0120 /*
0121  * Get a copy of a register.
0122  */
0123 #define GET_REG(_r, _v) asm volatile("pushl %%" #_r "; popl %0" : "=rm" (_v))
0124 
0125 /*
0126  * A function to get a segment register.
0127  */
0128 static inline uint32_t
0129 get_seg_reg(size_t reg)
0130 {
0131   int v = 0;
0132   switch (reg) {
0133     case REG_CS:
0134       GET_REG(CS, v);
0135       break;
0136     case REG_SS:
0137       GET_REG(SS, v);
0138       break;
0139     case REG_DS:
0140       GET_REG(DS, v);
0141       break;
0142     case REG_ES:
0143       GET_REG(ES, v);
0144       break;
0145     case REG_FS:
0146       GET_REG(FS, v);
0147       break;
0148     case REG_GS:
0149       GET_REG(GS, v);
0150       break;
0151   }
0152   return v & 0xffff;
0153 }
0154 
0155 /**
0156  * Target lock.
0157  */
0158 RTEMS_INTERRUPT_LOCK_DEFINE(static, target_lock, "target_lock")
0159 
0160 /**
0161  * The orginal exception handler.
0162  */
0163 static void (*orig_currentExcHandler)(CPU_Exception_frame* frame);
0164 
0165 #if TARGET_DEBUG
0166 #include <rtems/bspIo.h>
0167 static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
0168 static void
0169 target_printk(const char* format, ...)
0170 {
0171   va_list ap;
0172   va_start(ap, format);
0173   vprintk(format, ap);
0174   va_end(ap);
0175 }
0176 #else
0177 #define target_printk(_fmt, ...)
0178 #endif
0179 
0180 #if TODO
0181 /**
0182  * Target description.
0183  */
0184 static const char* const target_xml =
0185 "<?xml version=\"1.0\">                        \
0186  <!DOCTYPE target SYSTEM \"gdb-target.dtd\">   \
0187  <target version=\"1.0\">                      \
0188   <architecture>i386</architecture>            \
0189   <xi:include href=\"32bit-core.xml\"/>        \
0190   <xi:include href=\"32bit-sse.xml\"/>         \
0191 </target>";
0192 #endif
0193 
0194 int
0195 rtems_debugger_target_configure(rtems_debugger_target* target)
0196 {
0197   target->capabilities = (RTEMS_DEBUGGER_TARGET_CAP_SWBREAK);
0198   target->reg_num = RTEMS_DEBUGGER_NUMREGS;
0199   target->reg_offset = i386_reg_offsets;
0200   target->breakpoint = &breakpoint[0];
0201   target->breakpoint_size = sizeof(breakpoint);
0202   return 0;
0203 }
0204 
0205 static void
0206 target_exception(CPU_Exception_frame* frame)
0207 {
0208   target_printk("[} frame = %08" PRIx32 " sig=%d (%" PRIx32 ")\n",
0209                 (uint32_t) frame,
0210                 rtems_debugger_target_exception_to_signal(frame),
0211                 frame->idtIndex);
0212   target_printk("[} EAX = %" PRIx32 " EBX = %" PRIx32 \
0213                 " ECX = %" PRIx32 " EDX = %" PRIx32 "\n",
0214                 frame->eax, frame->ebx, frame->ecx, frame->edx);
0215   target_printk("[} ESI = %" PRIx32 " EDI = %" PRIx32           \
0216                 " EBP = %" PRIx32 " ESP = %" PRIx32 "\n",
0217                 frame->esi, frame->edi, frame->ebp, frame->esp0);
0218   target_printk("[} EIP = %" PRIx32"\n", frame->eip);
0219 
0220   frame->eflags &= ~EFLAGS_TRAP;
0221 
0222   switch (rtems_debugger_target_exception(frame)) {
0223   case rtems_debugger_target_exc_consumed:
0224   default:
0225     break;
0226   case rtems_debugger_target_exc_step:
0227     frame->eflags |= EFLAGS_TRAP;
0228     break;
0229   case rtems_debugger_target_exc_cascade:
0230     orig_currentExcHandler(frame);
0231     break;
0232   }
0233 }
0234 
0235 static bool
0236 rtems_debugger_is_int_reg(size_t reg)
0237 {
0238   const size_t size = i386_reg_offsets[reg + 1] - i386_reg_offsets[reg];
0239   return size == RTEMS_DEBUGGER_REG_BYTES;
0240 }
0241 
0242 static void
0243 rtems_debugger_set_int_reg(rtems_debugger_thread* thread,
0244                            size_t                 reg,
0245                            const uint32_t         value)
0246 {
0247   const size_t offset = i386_reg_offsets[reg];
0248   /*
0249    * Use memcpy to avoid alignment issues.
0250    */
0251   memcpy(&thread->registers[offset], &value, sizeof(uint32_t));
0252 }
0253 
0254 static const uint32_t
0255 rtems_debugger_get_int_reg(rtems_debugger_thread* thread, size_t reg)
0256 {
0257   const size_t offset = i386_reg_offsets[reg];
0258   uint32_t     value;
0259   memcpy(&value, &thread->registers[offset], sizeof(uint32_t));
0260   return value;
0261 }
0262 
0263 int
0264 rtems_debugger_target_enable(void)
0265 {
0266   rtems_interrupt_lock_context lock_context;
0267   rtems_interrupt_lock_acquire(&target_lock, &lock_context);
0268   if (orig_currentExcHandler == NULL) {
0269     orig_currentExcHandler = _currentExcHandler;
0270     _currentExcHandler = target_exception;
0271   }
0272   rtems_interrupt_lock_release(&target_lock, &lock_context);
0273   return 0;
0274 }
0275 
0276 int
0277 rtems_debugger_target_disable(void)
0278 {
0279   rtems_interrupt_lock_context lock_context;
0280   rtems_interrupt_lock_acquire(&target_lock, &lock_context);
0281   if (orig_currentExcHandler != NULL)
0282     _currentExcHandler = orig_currentExcHandler;
0283   rtems_interrupt_lock_release(&target_lock, &lock_context);
0284   return 0;
0285 }
0286 
0287 int
0288 rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
0289 {
0290   if (!rtems_debugger_thread_flag(thread,
0291                                   RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID)) {
0292     size_t i;
0293 
0294     for (i = 0; i < rtems_debugger_target_reg_num(); ++i) {
0295       if (rtems_debugger_is_int_reg(i))
0296         rtems_debugger_set_int_reg(thread, i, 0xdeaddead);
0297     }
0298 
0299     if (thread->frame) {
0300       CPU_Exception_frame* frame = thread->frame;
0301 
0302       rtems_debugger_set_int_reg(thread, REG_EAX,    frame->eax);
0303       rtems_debugger_set_int_reg(thread, REG_ECX,    frame->ecx);
0304       rtems_debugger_set_int_reg(thread, REG_EDX,    frame->edx);
0305       rtems_debugger_set_int_reg(thread, REG_EBX,    frame->ebx);
0306       rtems_debugger_set_int_reg(thread, REG_ESP,    frame->esp0);
0307       rtems_debugger_set_int_reg(thread, REG_EBP,    frame->ebp);
0308       rtems_debugger_set_int_reg(thread, REG_ESI,    frame->esi);
0309       rtems_debugger_set_int_reg(thread, REG_EDI,    frame->edi);
0310       rtems_debugger_set_int_reg(thread, REG_EIP,    frame->eip);
0311       rtems_debugger_set_int_reg(thread, REG_EFLAGS, frame->eflags);
0312       rtems_debugger_set_int_reg(thread, REG_CS,     frame->cs);
0313 
0314       /*
0315        * Get the signal from the frame.
0316        */
0317       thread->signal = rtems_debugger_target_exception_to_signal(frame);
0318     }
0319     else {
0320       rtems_debugger_set_int_reg(thread, REG_EBX,    thread->tcb->Registers.ebx);
0321       rtems_debugger_set_int_reg(thread, REG_ESI,    thread->tcb->Registers.esi);
0322       rtems_debugger_set_int_reg(thread, REG_EDI,    thread->tcb->Registers.edi);
0323       rtems_debugger_set_int_reg(thread, REG_EFLAGS, thread->tcb->Registers.eflags);
0324       rtems_debugger_set_int_reg(thread, REG_ESP,    (intptr_t) thread->tcb->Registers.esp);
0325       rtems_debugger_set_int_reg(thread, REG_EBP,    (intptr_t) thread->tcb->Registers.ebp);
0326       rtems_debugger_set_int_reg(thread, REG_EIP,    *((DB_UINT*) thread->tcb->Registers.esp));
0327       rtems_debugger_set_int_reg(thread, REG_EAX,    (intptr_t) thread);
0328 
0329       rtems_debugger_set_int_reg(thread, REG_CS, get_seg_reg(REG_CS));
0330 
0331       /*
0332        * Blocked threads have no signal.
0333        */
0334       thread->signal = 0;
0335     }
0336 
0337     rtems_debugger_set_int_reg(thread, REG_SS, get_seg_reg(REG_SS));
0338     rtems_debugger_set_int_reg(thread, REG_DS, get_seg_reg(REG_DS));
0339     rtems_debugger_set_int_reg(thread, REG_ES, get_seg_reg(REG_ES));
0340     rtems_debugger_set_int_reg(thread, REG_FS, get_seg_reg(REG_FS));
0341     rtems_debugger_set_int_reg(thread, REG_GS, get_seg_reg(REG_GS));
0342 
0343     thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID;
0344     thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
0345   }
0346 
0347   return 0;
0348 }
0349 
0350 int
0351 rtems_debugger_target_write_regs(rtems_debugger_thread* thread)
0352 {
0353   if (rtems_debugger_thread_flag(thread,
0354                                  RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY)) {
0355     /*
0356      * Only write to debugger controlled threads. Do not touch the registers
0357      * for threads blocked in the context switcher.
0358      */
0359     if (rtems_debugger_thread_flag(thread,
0360                                    RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) {
0361       CPU_Exception_frame* frame = thread->frame;
0362       frame->eax    = rtems_debugger_get_int_reg(thread, REG_EAX);
0363       frame->ecx    = rtems_debugger_get_int_reg(thread, REG_ECX);
0364       frame->edx    = rtems_debugger_get_int_reg(thread, REG_EDX);
0365       frame->ebx    = rtems_debugger_get_int_reg(thread, REG_EBX);
0366       frame->esp0   = rtems_debugger_get_int_reg(thread, REG_ESP);
0367       frame->ebp    = rtems_debugger_get_int_reg(thread, REG_EBP);
0368       frame->esi    = rtems_debugger_get_int_reg(thread, REG_ESI);
0369       frame->edi    = rtems_debugger_get_int_reg(thread, REG_EDI);
0370       frame->eip    = rtems_debugger_get_int_reg(thread, REG_EIP);
0371       frame->eflags = rtems_debugger_get_int_reg(thread, REG_EFLAGS);
0372       frame->cs     = rtems_debugger_get_int_reg(thread, REG_CS);
0373     }
0374     thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
0375   }
0376   return 0;
0377 }
0378 
0379 uintptr_t
0380 rtems_debugger_target_reg_pc(rtems_debugger_thread* thread)
0381 {
0382   int r;
0383   r = rtems_debugger_target_read_regs(thread);
0384   if (r >= 0) {
0385     return rtems_debugger_get_int_reg(thread, REG_EIP);
0386   }
0387   return 0;
0388 }
0389 
0390 uintptr_t
0391 rtems_debugger_target_frame_pc(CPU_Exception_frame* frame)
0392 {
0393   return (uintptr_t) frame->eip;
0394 }
0395 
0396 uintptr_t
0397 rtems_debugger_target_reg_sp(rtems_debugger_thread* thread)
0398 {
0399   int r;
0400   r = rtems_debugger_target_read_regs(thread);
0401   if (r >= 0) {
0402     return rtems_debugger_get_int_reg(thread, REG_ESP);
0403   }
0404   return 0;
0405 }
0406 
0407 uintptr_t
0408 rtems_debugger_target_tcb_sp(rtems_debugger_thread* thread)
0409 {
0410   return (DB_UINT) thread->tcb->Registers.esp;
0411 }
0412 
0413 int
0414 rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread)
0415 {
0416   if (rtems_debugger_thread_flag(thread,
0417                                  (RTEMS_DEBUGGER_THREAD_FLAG_STEP |
0418                                   RTEMS_DEBUGGER_THREAD_FLAG_STEPPING))) {
0419     CPU_Exception_frame* frame = thread->frame;
0420     /*
0421      * Single step instructions with interrupts masked to avoid stepping into
0422      * an interrupt handler.
0423      */
0424     if ((frame->eflags & EFLAGS_INTR_ENABLE) == 0)
0425       thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED;
0426     else
0427       frame->eflags &= ~EFLAGS_INTR_ENABLE;
0428     frame->eflags |= EFLAGS_TRAP;
0429   }
0430   return 0;
0431 }
0432 
0433 int
0434 rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame)
0435 {
0436   int sig = RTEMS_DEBUGGER_SIGNAL_HUP;
0437   switch (frame->idtIndex) {
0438   case 1:  /* debug exception */
0439   case 3:  /* breakpoint int3 */
0440     sig = RTEMS_DEBUGGER_SIGNAL_TRAP;
0441     break;
0442   case 4:  /* int overflow    */
0443   case 5:  /* out-of-bounds   */
0444     sig = RTEMS_DEBUGGER_SIGNAL_URG;
0445     break;
0446   case 6:  /* invalid opcode  */
0447     sig = RTEMS_DEBUGGER_SIGNAL_ILL;
0448     break;
0449   case 8:  /* double fault    */
0450   case 16: /* fp error        */
0451     sig = RTEMS_DEBUGGER_SIGNAL_EMT;
0452     break;
0453   case 0:  /* divide by zero  */
0454   case 7:  /* FPU not avail.  */
0455     sig = RTEMS_DEBUGGER_SIGNAL_FPE;
0456     break;
0457   case 9:  /* i387 seg overr. */
0458   case 10: /* Invalid TSS     */
0459   case 11: /* seg. not pres.  */
0460   case 12: /* stack except.   */
0461   case 13: /* general prot.   */
0462   case 14: /* page fault      */
0463   case 17: /* alignment check */
0464     sig = RTEMS_DEBUGGER_SIGNAL_SEGV;
0465     break;
0466   case 2:  /* NMI             */
0467   case 18: /* machine check   */
0468     sig = RTEMS_DEBUGGER_SIGNAL_BUS;
0469     break;
0470   default:
0471     break;
0472   }
0473   return sig;
0474 }
0475 
0476 void
0477 rtems_debugger_target_exception_print(CPU_Exception_frame* frame)
0478 {
0479   rtems_debugger_printf(" EAX = %" PRIx32 " EBX = %" PRIx32           \
0480                         " ECX = %" PRIx32 " EDX = %" PRIx32 "\n",
0481                         frame->eax, frame->ebx, frame->ecx, frame->edx);
0482   rtems_debugger_printf(" ESI = %" PRIx32 " EDI = %" PRIx32           \
0483                         " EBP = %" PRIx32 " ESP = %" PRIx32 "\n",
0484                         frame->esi, frame->edi, frame->ebp, frame->esp0);
0485   rtems_debugger_printf(" EIP = %" PRIx32"\n", frame->eip);
0486 }
0487 
0488 int
0489 rtems_debugger_target_hwbreak_insert(void)
0490 {
0491   /*
0492    * Do nothing, load on exit of the exception handler.
0493    */
0494   return 0;
0495 }
0496 
0497 int
0498 rtems_debugger_target_hwbreak_remove(void)
0499 {
0500   return 0;
0501 }
0502 
0503 int
0504 rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint wp,
0505                                       bool                             insert,
0506                                       uintptr_t                        addr,
0507                                       DB_UINT                          kind)
0508 {
0509   /*
0510    * To do.
0511    */
0512   return 0;
0513 }
0514 
0515 int
0516 rtems_debugger_target_cache_sync(rtems_debugger_target_swbreak* swbreak)
0517 {
0518   /*
0519    * Nothing to do on an i386.
0520    */
0521   return 0;
0522 }