Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSLibdebugger
0007  *
0008  * @brief MicroBlaze libdebugger implementation
0009  */
0010 
0011 /*
0012  * Copyright (C) 2022 On-Line Applications Research Corporation (OAR)
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #define TARGET_DEBUG 0
0037 
0038 #ifdef HAVE_CONFIG_H
0039 #include "config.h"
0040 #endif
0041 
0042 #include <errno.h>
0043 #include <inttypes.h>
0044 #include <stdlib.h>
0045 
0046 /* Defined by linkcmds.base */
0047 extern char bsp_section_text_begin[];
0048 extern char bsp_section_text_end[];
0049 extern char bsp_section_fast_text_begin[];
0050 extern char bsp_section_fast_text_end[];
0051 
0052 #include <rtems.h>
0053 #include <rtems/score/cpu.h>
0054 #include <rtems/score/threadimpl.h>
0055 #include <rtems/score/userextimpl.h>
0056 
0057 #include <rtems/debugger/rtems-debugger-bsp.h>
0058 
0059 #include "rtems-debugger-target.h"
0060 #include "rtems-debugger-threads.h"
0061 
0062 #if TARGET_DEBUG
0063 #include <rtems/bspIo.h>
0064 #endif
0065 
0066 /*
0067  * Number of registers.
0068  */
0069 #define RTEMS_DEBUGGER_NUMREGS 57
0070 
0071 /*
0072  * Number of bytes per type of register.
0073  */
0074 #define RTEMS_DEBUGGER_REG_BYTES    4
0075 
0076 /* Debugger registers layout. See microblaze-core.xml in GDB source. */
0077 #define REG_R0    0
0078 #define REG_R1    1
0079 #define REG_R2    2
0080 #define REG_R3    3
0081 #define REG_R4    4
0082 #define REG_R5    5
0083 #define REG_R6    6
0084 #define REG_R7    7
0085 #define REG_R8    8
0086 #define REG_R9    9
0087 #define REG_R10   10
0088 #define REG_R11   11
0089 #define REG_R12   12
0090 #define REG_R13   13
0091 #define REG_R14   14
0092 #define REG_R15   15
0093 #define REG_R16   16
0094 #define REG_R17   17
0095 #define REG_R18   18
0096 #define REG_R19   19
0097 #define REG_R20   20
0098 #define REG_R21   21
0099 #define REG_R22   22
0100 #define REG_R23   23
0101 #define REG_R24   24
0102 #define REG_R25   25
0103 #define REG_R26   26
0104 #define REG_R27   27
0105 #define REG_R28   28
0106 #define REG_R29   29
0107 #define REG_R30   30
0108 #define REG_R31   31
0109 #define REG_PC    32
0110 #define REG_MS    33
0111 #define REG_EA    34
0112 #define REG_ES    35
0113 #define REG_FS    36
0114 #define REG_BT    37
0115 #define REG_PV0   38
0116 #define REG_PV1   39
0117 #define REG_PV2   40
0118 #define REG_PV3   41
0119 #define REG_PV4   42
0120 #define REG_PV5   43
0121 #define REG_PV6   44
0122 #define REG_PV7   45
0123 #define REG_PV8   46
0124 #define REG_PV9   47
0125 #define REG_PV10  48
0126 #define REG_PV11  49
0127 #define REG_ED    50
0128 #define REG_PID   51
0129 #define REG_ZP    52
0130 #define REG_TBLX  53
0131 #define REG_TBLSX 54
0132 #define REG_TBLLO 55
0133 #define REG_TBLHI 56
0134 
0135 /**
0136  * Register offset table with the total as the last entry.
0137  *
0138  * Check this table in gdb with the command:
0139  *
0140  *   maint print registers
0141  */
0142 static const size_t microblaze_reg_offsets[ RTEMS_DEBUGGER_NUMREGS + 1 ] = {
0143   REG_R0 * 4,
0144   REG_R1 * 4,
0145   REG_R2 * 4,
0146   REG_R3 * 4,
0147   REG_R4 * 4,
0148   REG_R5 * 4,
0149   REG_R6 * 4,
0150   REG_R7 * 4,
0151   REG_R8 * 4,
0152   REG_R9 * 4,
0153   REG_R10 * 4,
0154   REG_R11 * 4,
0155   REG_R12 * 4,
0156   REG_R13 * 4,
0157   REG_R14 * 4,
0158   REG_R15 * 4,
0159   REG_R16 * 4,
0160   REG_R17 * 4,
0161   REG_R18 * 4,
0162   REG_R19 * 4,
0163   REG_R20 * 4,
0164   REG_R21 * 4,
0165   REG_R22 * 4,
0166   REG_R23 * 4,
0167   REG_R24 * 4,
0168   REG_R25 * 4,
0169   REG_R26 * 4,
0170   REG_R27 * 4,
0171   REG_R28 * 4,
0172   REG_R29 * 4,
0173   REG_R30 * 4,
0174   REG_R31 * 4,
0175   REG_PC * 4,
0176   REG_MS * 4,
0177   REG_EA * 4,
0178   REG_ES * 4,
0179   REG_FS * 4,
0180   REG_BT * 4,
0181   REG_PV0 * 4,
0182   REG_PV1 * 4,
0183   REG_PV2 * 4,
0184   REG_PV3 * 4,
0185   REG_PV4 * 4,
0186   REG_PV5 * 4,
0187   REG_PV6 * 4,
0188   REG_PV7 * 4,
0189   REG_PV8 * 4,
0190   REG_PV9 * 4,
0191   REG_PV10 * 4,
0192   REG_PV11 * 4,
0193   REG_ED * 4,
0194   REG_PID * 4,
0195   REG_ZP * 4,
0196   REG_TBLX * 4,
0197   REG_TBLSX * 4,
0198   REG_TBLLO * 4,
0199   REG_TBLHI * 4,
0200 /* Total size */
0201   REG_TBLHI * 4 + 4,
0202 };
0203 
0204 /*
0205  * Number of bytes of registers.
0206  */
0207 #define RTEMS_DEBUGGER_NUMREGBYTES \
0208   microblaze_reg_offsets[ RTEMS_DEBUGGER_NUMREGS ]
0209 
0210 /**
0211  * Print the exception frame.
0212  */
0213 #define EXC_FRAME_PRINT( _out, _prefix, _frame ) \
0214   do { \
0215     _out( \
0216       _prefix "  R0 = 0x%08" PRIx32 "  R1 = 0x%08" PRIx32 \
0217       "  R2 = 0x%08" PRIx32 "  R3 = 0x%08" PRIx32 "\n", \
0218       0, \
0219       _frame->r1, \
0220       _frame->r2, \
0221       _frame->r3 \
0222     ); \
0223     _out( \
0224       _prefix "  R4 = 0x%08" PRIx32 "  R5 = 0x%08" PRIx32 \
0225       "  R6 = 0x%08" PRIx32 "  R7 = 0x%08" PRIx32 "\n", \
0226       _frame->r4, \
0227       _frame->r5, \
0228       _frame->r6, \
0229       _frame->r7 \
0230     ); \
0231     _out( \
0232       _prefix "  R8 = 0x%08" PRIx32 "  R9 = 0x%08" PRIx32 \
0233       " R10 = 0x%08" PRIx32 " R11 = 0x%08" PRIx32 "\n", \
0234       _frame->r8, \
0235       _frame->r9, \
0236       _frame->r10, \
0237       _frame->r11 \
0238     ); \
0239     _out( \
0240       _prefix " R12 = 0x%08" PRIx32 " R13 = 0x%08" PRIx32 \
0241       " R14 = 0x%08" PRIxPTR " R15 = 0x%08" PRIxPTR "\n", \
0242       _frame->r12, \
0243       _frame->r13, \
0244       (uintptr_t) _frame->r14, \
0245       (uintptr_t) _frame->r15 \
0246     ); \
0247     _out( \
0248       _prefix " R16 = 0x%08" PRIxPTR " R17 = 0x%08" PRIxPTR \
0249       " R18 = 0x%08" PRIx32 " R19 = 0x%08" PRIx32 "\n", \
0250       (uintptr_t) _frame->r16, \
0251       (uintptr_t) _frame->r17, \
0252       _frame->r18, \
0253       _frame->r19 \
0254     ); \
0255     _out( \
0256       _prefix " R20 = 0x%08" PRIx32 " R21 = 0x%08" PRIx32 \
0257       " R22 = 0x%08" PRIx32 " R23 = 0x%08" PRIx32 "\n", \
0258       _frame->r20, \
0259       _frame->r21, \
0260       _frame->r22, \
0261       _frame->r23 \
0262     ); \
0263     _out( \
0264       _prefix " R24 = 0x%08" PRIx32 " R25 = 0x%08" PRIx32 \
0265       " R26 = 0x%08" PRIx32 " R27 = 0x%08" PRIx32 "\n", \
0266       _frame->r24, \
0267       _frame->r25, \
0268       _frame->r26, \
0269       _frame->r27 \
0270     ); \
0271     _out( \
0272       _prefix " R28 = 0x%08" PRIx32 " R29 = 0x%08" PRIx32 \
0273       " R30 = 0x%08" PRIxPTR " R31 = 0x%08" PRIxPTR "\n", \
0274       _frame->r28, \
0275       _frame->r29, \
0276       _frame->r30, \
0277       _frame->r31 \
0278     ); \
0279     _out( \
0280       _prefix " EAR = %p ESR = 0x%08" PRIx32 "\n", \
0281       _frame->ear, \
0282       _frame->esr \
0283     ); \
0284     _out( \
0285       _prefix "  PC = %p\n", \
0286       _frame->r16 \
0287     ); \
0288     _out( \
0289       _prefix " MSR = 0x%08" PRIx32 " En:%c%c%c%c Prog:%c%c%c Mode:%c%c Arith:%c%c\n", \
0290       _frame->msr, \
0291       ( _frame->msr & MICROBLAZE_MSR_IE ) != 0 ? 'I' : '-', \
0292       ( _frame->msr & MICROBLAZE_MSR_ICE ) != 0 ? 'C' : '-', \
0293       ( _frame->msr & MICROBLAZE_MSR_DCE ) != 0 ? 'D' : '-', \
0294       ( _frame->msr & MICROBLAZE_MSR_EE ) != 0 ? 'E' : '-', \
0295       ( _frame->msr & MICROBLAZE_MSR_BIP ) != 0 ? 'B' : '-', \
0296       ( _frame->msr & MICROBLAZE_MSR_FSL ) != 0 ? 'F' : '-', \
0297       ( _frame->msr & MICROBLAZE_MSR_EIP ) != 0 ? 'E' : '-', \
0298       ( _frame->msr & MICROBLAZE_MSR_UM ) != 0 ? 'U' : '-', \
0299       ( _frame->msr & MICROBLAZE_MSR_VM ) != 0 ? 'V' : '-', \
0300       ( _frame->msr & MICROBLAZE_MSR_C ) != 0 ? 'C' : '-', \
0301       ( _frame->msr & MICROBLAZE_MSR_DZO ) != 0 ? 'Z' : '-' \
0302     ); \
0303   } while ( 0 )
0304 
0305 /**
0306  * The breakpoint instruction can be intercepted on hardware by an active JTAG
0307  * connection. This instead uses an illegal opcode (0xdeadbeef) to trigger an
0308  * exception as a mechanism to call into the debugger.
0309  */
0310 static const uint8_t breakpoint[ 4 ] = { 0xef, 0xbe, 0xad, 0xde };
0311 
0312 /**
0313  * Target lock.
0314  */
0315 RTEMS_INTERRUPT_LOCK_DEFINE( static, target_lock, "target_lock" )
0316 
0317 /**
0318  * Is a session active?
0319  */
0320 static bool debug_session_active;
0321 
0322 /*
0323  * MicroBlaze debug hardware.
0324  */
0325 static uint8_t hw_breakpoints;
0326 static uint8_t hw_read_watchpoints;
0327 static uint8_t hw_write_watchpoints;
0328 
0329 /* Software breakpoints for single stepping */
0330 typedef struct {
0331   uint32_t *address;
0332 } microblaze_soft_step;
0333 
0334 microblaze_soft_step next_soft_break = { 0 };
0335 microblaze_soft_step target_soft_break = { 0 };
0336 
0337 static void set_soft_break(
0338   microblaze_soft_step *soft_break,
0339   uint32_t             *next_ins
0340 )
0341 {
0342   soft_break->address = next_ins;
0343   rtems_debugger_target_swbreak_control(
0344     true,
0345     (uintptr_t) soft_break->address,
0346     4
0347   );
0348 }
0349 
0350 static void restore_soft_step( microblaze_soft_step *bp )
0351 {
0352   /*
0353    * Only restore if the breakpoint is active and the instruction at the address
0354    * is the breakpoint instruction.
0355    */
0356   if ( bp->address != NULL ) {
0357     rtems_debugger_target_swbreak_control( false, (uintptr_t) bp->address, 4 );
0358   }
0359 
0360   bp->address = NULL;
0361 }
0362 
0363 /*
0364  * Target debugging support. Use this to debug the backend.
0365  */
0366 #if TARGET_DEBUG
0367 
0368 void rtems_debugger_printk_lock( rtems_interrupt_lock_context *lock_context );
0369 
0370 void rtems_debugger_printk_unlock(
0371   rtems_interrupt_lock_context *lock_context
0372 );
0373 
0374 static void target_printk( const char *format, ... ) RTEMS_PRINTFLIKE( 1, 2 );
0375 
0376 static void target_printk( const char *format, ... )
0377 {
0378   rtems_interrupt_lock_context lock_context;
0379   va_list                      ap;
0380 
0381   va_start( ap, format );
0382   rtems_debugger_printk_lock( &lock_context );
0383   vprintk( format, ap );
0384   rtems_debugger_printk_unlock( &lock_context );
0385   va_end( ap );
0386 }
0387 
0388 #else
0389 #define target_printk( _fmt, ... )
0390 #endif
0391 
0392 static int microblaze_debug_probe( rtems_debugger_target *target )
0393 {
0394   uint32_t    msr;
0395   uint32_t    pvr0;
0396   uint32_t    pvr3;
0397   const char *version = NULL;
0398 
0399   rtems_debugger_printf(
0400     "rtems-db: MicroBlaze\n"
0401   );
0402 
0403   _CPU_MSR_GET( msr );
0404 
0405   if ( ( msr & MICROBLAZE_MSR_PVR ) == 0 ) {
0406     rtems_debugger_printf(
0407       "rtems-db: Processor Version Registers not supported\n"
0408     );
0409     return 0;
0410   }
0411 
0412   _CPU_PVR0_GET( pvr0 );
0413 
0414   switch ( MICROBLAZE_PVR0_VERSION_GET( pvr0 ) ) {
0415    case 0x1:
0416      version = "v5.00.a";
0417      break;
0418    case 0x2:
0419      version = "v5.00.b";
0420      break;
0421    case 0x3:
0422      version = "v5.00.c";
0423      break;
0424    case 0x4:
0425      version = "v6.00.a";
0426      break;
0427    case 0x5:
0428      version = "v7.00.a";
0429      break;
0430    case 0x6:
0431      version = "v6.00.b";
0432      break;
0433    case 0x7:
0434      version = "v7.00.b";
0435      break;
0436    case 0x8:
0437      version = "v7.10.a";
0438      break;
0439   }
0440 
0441   rtems_debugger_printf(
0442     "rtems-db: Version: %s (%d)\n",
0443     version,
0444     MICROBLAZE_PVR0_VERSION_GET( pvr0 )
0445   );
0446 
0447   /* further PVR supported? */
0448   if ( ( pvr0 >> 31 ) == 0 ) {
0449     rtems_debugger_printf(
0450       "rtems-db: Further Processor Version Registers not supported\n"
0451     );
0452     return 0;
0453   }
0454 
0455   _CPU_PVR3_GET( pvr3 );
0456 
0457   hw_breakpoints = MICROBLAZE_PVR3_BP_GET( pvr3 );
0458   hw_read_watchpoints = MICROBLAZE_PVR3_RWP_GET( pvr3 );
0459   hw_write_watchpoints = MICROBLAZE_PVR3_WWP_GET( pvr3 );
0460 
0461   rtems_debugger_printf(
0462     "rtems-db: breakpoints:%" PRIu32
0463     " read watchpoints:%" PRIu32 " write watchpoints:%" PRIu32 "\n",
0464     hw_breakpoints,
0465     hw_read_watchpoints,
0466     hw_write_watchpoints
0467   );
0468 
0469   return 0;
0470 }
0471 
0472 int rtems_debugger_target_configure( rtems_debugger_target *target )
0473 {
0474   target->capabilities = ( RTEMS_DEBUGGER_TARGET_CAP_SWBREAK
0475     | RTEMS_DEBUGGER_TARGET_CAP_PURE_SWBREAK );
0476   target->reg_num = RTEMS_DEBUGGER_NUMREGS;
0477   target->reg_offset = microblaze_reg_offsets;
0478   target->breakpoint = &breakpoint[ 0 ];
0479   target->breakpoint_size = sizeof( breakpoint );
0480   return microblaze_debug_probe( target );
0481 }
0482 
0483 static void target_print_frame( CPU_Exception_frame *frame )
0484 {
0485   EXC_FRAME_PRINT( target_printk, "[} ", frame );
0486 }
0487 
0488 /* returns true if cascade is required */
0489 static bool target_exception( CPU_Exception_frame *frame )
0490 {
0491   target_print_frame( frame );
0492 
0493   switch ( rtems_debugger_target_exception( frame ) ) {
0494    case rtems_debugger_target_exc_consumed:
0495    default:
0496      break;
0497    case rtems_debugger_target_exc_step:
0498      break;
0499    case rtems_debugger_target_exc_cascade:
0500      target_printk( "rtems-db: unhandled exception: cascading\n" );
0501      /* Continue in fatal error handler chain */
0502      return true;
0503   }
0504 
0505   target_printk(
0506     "[} < resuming frame = %016" PRIxPTR "\n",
0507     (uintptr_t) frame
0508   );
0509   target_print_frame( frame );
0510 
0511   return false;
0512 }
0513 
0514 static void target_exception_handler( CPU_Exception_frame *ef )
0515 {
0516   if ( debug_session_active == false ) {
0517     /* Falls into fatal error handler */
0518     return;
0519   }
0520 
0521   /*
0522    * Blindly roll back R17 in the exception frame due to exceptions resuming at
0523    * the next instruction and not the instruction that caused the exception.
0524    * TODO(kmoore): This does not apply in all cases for MicroBlaze cores that
0525    *               have a MMU and can generate MMU exceptions.
0526    */
0527   ef->r17 = &ef->r17[ -1 ];
0528 
0529   /*
0530    * Remove single step software breakpoints since they will need to be
0531    * recalculated for the current instruction.
0532    */
0533   restore_soft_step( &next_soft_break );
0534   restore_soft_step( &target_soft_break );
0535 
0536   /* disable all software breakpoints */
0537   rtems_debugger_target_swbreak_remove();
0538 
0539   if ( target_exception( ef ) == true ) {
0540     /* Roll R17 forward for an accurate frame in the fatal error handler */
0541     ef->r17 = &ef->r17[ 1 ];
0542 
0543     /* Falls into fatal error handler */
0544     return;
0545   }
0546 
0547   /* Enable all software breakpoints including added single-step breakpoints */
0548   rtems_debugger_target_swbreak_insert();
0549 
0550   /* does not return */
0551   _CPU_Exception_resume( ef );
0552 }
0553 
0554 static void rtems_debugger_set_int_reg(
0555   rtems_debugger_thread *thread,
0556   size_t                 reg,
0557   const uint32_t         value
0558 )
0559 {
0560   const size_t offset = microblaze_reg_offsets[ reg ];
0561 
0562   memcpy( &thread->registers[ offset ], &value, sizeof( uint32_t ) );
0563 }
0564 
0565 static const uint32_t rtems_debugger_get_int_reg(
0566   rtems_debugger_thread *thread,
0567   size_t                 reg
0568 )
0569 {
0570   const size_t offset = microblaze_reg_offsets[ reg ];
0571   uint32_t     value;
0572 
0573   memcpy( &value, &thread->registers[ offset ], sizeof( uint32_t ) );
0574   return value;
0575 }
0576 
0577 static bool tid_is_excluded( const rtems_id tid )
0578 {
0579   rtems_debugger_threads *threads = rtems_debugger->threads;
0580   rtems_id               *excludes;
0581   size_t                  i;
0582 
0583   excludes = rtems_debugger_thread_excludes( threads );
0584 
0585   for ( i = 0; i < threads->excludes.level; ++i ) {
0586     if ( tid == excludes[ i ] ) {
0587       return true;
0588     }
0589   }
0590 
0591   /* DBSe is dynamically created and destroyed, so might not actually be in the excludes list */
0592   char name[ RTEMS_DEBUGGER_THREAD_NAME_SIZE ];
0593 
0594   rtems_object_get_name( tid, sizeof( name ), (char *) &name[ 0 ] );
0595 
0596   if ( strcmp( "DBSe", name ) == 0 ) {
0597     return true;
0598   }
0599 
0600   return false;
0601 }
0602 
0603 static void mb_thread_switch( Thread_Control *executing, Thread_Control *heir )
0604 {
0605   if ( tid_is_excluded( heir->Object.id ) == true ) {
0606     rtems_debugger_target_swbreak_remove();
0607     return;
0608   }
0609 
0610   /* Insert all software breaks */
0611   rtems_debugger_target_swbreak_insert();
0612 }
0613 
0614 User_extensions_Control mb_ext = {
0615   .Callouts = { .thread_switch = mb_thread_switch }
0616 };
0617 
0618 int rtems_debugger_target_enable( void )
0619 {
0620   debug_session_active = true;
0621   rtems_interrupt_lock_context lock_context;
0622 
0623   rtems_interrupt_lock_acquire( &target_lock, &lock_context );
0624 
0625   _MicroBlaze_Debug_install_handler( target_exception_handler, NULL );
0626   _MicroBlaze_Exception_install_handler( target_exception_handler, NULL );
0627   _User_extensions_Add_set( &mb_ext );
0628 
0629   rtems_interrupt_lock_release( &target_lock, &lock_context );
0630   return RTEMS_SUCCESSFUL;
0631 }
0632 
0633 int rtems_debugger_target_disable( void )
0634 {
0635   debug_session_active = false;
0636   rtems_interrupt_lock_context lock_context;
0637 
0638   rtems_interrupt_lock_acquire( &target_lock, &lock_context );
0639 
0640   _User_extensions_Remove_set( &mb_ext );
0641 
0642   rtems_interrupt_lock_release( &target_lock, &lock_context );
0643   return RTEMS_SUCCESSFUL;
0644 }
0645 
0646 int rtems_debugger_target_read_regs( rtems_debugger_thread *thread )
0647 {
0648   if (
0649     rtems_debugger_thread_flag(
0650       thread,
0651       RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID
0652     ) == 0
0653   ) {
0654     static const uintptr_t good_address = (uintptr_t) &good_address;
0655     int                    i;
0656 
0657     memset( &thread->registers[ 0 ], 0, RTEMS_DEBUGGER_NUMREGBYTES );
0658 
0659     /* set all integer register to a known valid address */
0660     for ( i = 0; i < RTEMS_DEBUGGER_NUMREGS; ++i ) {
0661       rtems_debugger_set_int_reg( thread, i, (uintptr_t) &good_address );
0662     }
0663 
0664     if ( thread->frame != NULL ) {
0665       CPU_Exception_frame *frame = thread->frame;
0666 
0667       *( (CPU_Exception_frame *) thread->registers ) = *frame;
0668       rtems_debugger_set_int_reg( thread, REG_R0, 0 );
0669       rtems_debugger_set_int_reg( thread, REG_R1, frame->r1 );
0670       rtems_debugger_set_int_reg( thread, REG_R2, frame->r2 );
0671       rtems_debugger_set_int_reg( thread, REG_R3, frame->r3 );
0672       rtems_debugger_set_int_reg( thread, REG_R4, frame->r4 );
0673       rtems_debugger_set_int_reg( thread, REG_R5, frame->r5 );
0674       rtems_debugger_set_int_reg( thread, REG_R6, frame->r6 );
0675       rtems_debugger_set_int_reg( thread, REG_R7, frame->r7 );
0676       rtems_debugger_set_int_reg( thread, REG_R8, frame->r8 );
0677       rtems_debugger_set_int_reg( thread, REG_R9, frame->r9 );
0678       rtems_debugger_set_int_reg( thread, REG_R10, frame->r10 );
0679       rtems_debugger_set_int_reg( thread, REG_R11, frame->r11 );
0680       rtems_debugger_set_int_reg( thread, REG_R12, frame->r12 );
0681       rtems_debugger_set_int_reg( thread, REG_R13, frame->r13 );
0682       rtems_debugger_set_int_reg( thread, REG_R14, (uintptr_t) frame->r14 );
0683       rtems_debugger_set_int_reg( thread, REG_R15, (uintptr_t) frame->r15 );
0684       rtems_debugger_set_int_reg( thread, REG_R16, (uintptr_t) frame->r16 );
0685       rtems_debugger_set_int_reg( thread, REG_R17, (uintptr_t) frame->r17 );
0686       rtems_debugger_set_int_reg( thread, REG_R18, frame->r18 );
0687       rtems_debugger_set_int_reg( thread, REG_R19, frame->r19 );
0688       rtems_debugger_set_int_reg( thread, REG_R20, frame->r20 );
0689       rtems_debugger_set_int_reg( thread, REG_R21, frame->r21 );
0690       rtems_debugger_set_int_reg( thread, REG_R22, frame->r22 );
0691       rtems_debugger_set_int_reg( thread, REG_R23, frame->r23 );
0692       rtems_debugger_set_int_reg( thread, REG_R24, frame->r24 );
0693       rtems_debugger_set_int_reg( thread, REG_R25, frame->r25 );
0694       rtems_debugger_set_int_reg( thread, REG_R26, frame->r26 );
0695       rtems_debugger_set_int_reg( thread, REG_R27, frame->r27 );
0696       rtems_debugger_set_int_reg( thread, REG_R28, frame->r28 );
0697       rtems_debugger_set_int_reg( thread, REG_R29, frame->r29 );
0698       rtems_debugger_set_int_reg( thread, REG_R30, frame->r30 );
0699       rtems_debugger_set_int_reg( thread, REG_R31, frame->r31 );
0700       rtems_debugger_set_int_reg(
0701         thread,
0702         REG_PC,
0703         rtems_debugger_target_frame_pc( frame )
0704       );
0705       rtems_debugger_set_int_reg( thread, REG_MS, frame->msr );
0706       rtems_debugger_set_int_reg( thread, REG_EA, (uintptr_t) frame->ear );
0707       rtems_debugger_set_int_reg( thread, REG_ES, frame->esr );
0708       rtems_debugger_set_int_reg( thread, REG_BT, (uintptr_t) frame->btr );
0709       /*
0710        * Get the signal from the frame.
0711        */
0712       thread->signal = rtems_debugger_target_exception_to_signal( frame );
0713     } else {
0714       rtems_debugger_set_int_reg(
0715         thread,
0716         REG_R1,
0717         thread->tcb->Registers.r1
0718       );
0719       rtems_debugger_set_int_reg(
0720         thread,
0721         REG_R13,
0722         thread->tcb->Registers.r13
0723       );
0724       rtems_debugger_set_int_reg(
0725         thread,
0726         REG_R14,
0727         thread->tcb->Registers.r14
0728       );
0729       rtems_debugger_set_int_reg(
0730         thread,
0731         REG_R15,
0732         thread->tcb->Registers.r15
0733       );
0734       rtems_debugger_set_int_reg(
0735         thread,
0736         REG_R16,
0737         thread->tcb->Registers.r16
0738       );
0739       rtems_debugger_set_int_reg(
0740         thread,
0741         REG_R17,
0742         thread->tcb->Registers.r17
0743       );
0744       rtems_debugger_set_int_reg(
0745         thread,
0746         REG_R18,
0747         thread->tcb->Registers.r18
0748       );
0749       rtems_debugger_set_int_reg(
0750         thread,
0751         REG_R19,
0752         thread->tcb->Registers.r19
0753       );
0754       rtems_debugger_set_int_reg(
0755         thread,
0756         REG_R20,
0757         thread->tcb->Registers.r20
0758       );
0759       rtems_debugger_set_int_reg(
0760         thread,
0761         REG_R21,
0762         thread->tcb->Registers.r21
0763       );
0764       rtems_debugger_set_int_reg(
0765         thread,
0766         REG_R22,
0767         thread->tcb->Registers.r22
0768       );
0769       rtems_debugger_set_int_reg(
0770         thread,
0771         REG_R23,
0772         thread->tcb->Registers.r23
0773       );
0774       rtems_debugger_set_int_reg(
0775         thread,
0776         REG_R24,
0777         thread->tcb->Registers.r24
0778       );
0779       rtems_debugger_set_int_reg(
0780         thread,
0781         REG_R25,
0782         thread->tcb->Registers.r25
0783       );
0784       rtems_debugger_set_int_reg(
0785         thread,
0786         REG_R26,
0787         thread->tcb->Registers.r26
0788       );
0789       rtems_debugger_set_int_reg(
0790         thread,
0791         REG_R27,
0792         thread->tcb->Registers.r27
0793       );
0794       rtems_debugger_set_int_reg(
0795         thread,
0796         REG_R28,
0797         thread->tcb->Registers.r28
0798       );
0799       rtems_debugger_set_int_reg(
0800         thread,
0801         REG_R29,
0802         thread->tcb->Registers.r29
0803       );
0804       rtems_debugger_set_int_reg(
0805         thread,
0806         REG_R30,
0807         thread->tcb->Registers.r30
0808       );
0809       rtems_debugger_set_int_reg(
0810         thread,
0811         REG_R31,
0812         thread->tcb->Registers.r31
0813       );
0814       rtems_debugger_set_int_reg(
0815         thread,
0816         REG_MS,
0817         (intptr_t) thread->tcb->Registers.rmsr
0818       );
0819       /*
0820        * Blocked threads have no signal.
0821        */
0822       thread->signal = 0;
0823     }
0824 
0825     thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID;
0826     thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
0827   }
0828 
0829   return 0;
0830 }
0831 
0832 int rtems_debugger_target_write_regs( rtems_debugger_thread *thread )
0833 {
0834   if (
0835     rtems_debugger_thread_flag(
0836       thread,
0837       RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY
0838     ) != 0
0839   ) {
0840     /*
0841      * Only write to debugger controlled exception threads. Do not touch the
0842      * registers for threads blocked in the context switcher.
0843      */
0844     if (
0845       rtems_debugger_thread_flag(
0846         thread,
0847         RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION
0848       ) != 0
0849     ) {
0850       CPU_Exception_frame *frame = thread->frame;
0851       frame->r1 = rtems_debugger_get_int_reg( thread, REG_R1 );
0852       frame->r2 = rtems_debugger_get_int_reg( thread, REG_R2 );
0853       frame->r3 = rtems_debugger_get_int_reg( thread, REG_R3 );
0854       frame->r4 = rtems_debugger_get_int_reg( thread, REG_R4 );
0855       frame->r5 = rtems_debugger_get_int_reg( thread, REG_R5 );
0856       frame->r6 = rtems_debugger_get_int_reg( thread, REG_R6 );
0857       frame->r7 = rtems_debugger_get_int_reg( thread, REG_R7 );
0858       frame->r8 = rtems_debugger_get_int_reg( thread, REG_R8 );
0859       frame->r9 = rtems_debugger_get_int_reg( thread, REG_R9 );
0860       frame->r10 = rtems_debugger_get_int_reg( thread, REG_R10 );
0861       frame->r11 = rtems_debugger_get_int_reg( thread, REG_R11 );
0862       frame->r12 = rtems_debugger_get_int_reg( thread, REG_R12 );
0863       frame->r13 = rtems_debugger_get_int_reg( thread, REG_R13 );
0864       frame->r14 = (uint32_t *) rtems_debugger_get_int_reg( thread, REG_R14 );
0865       frame->r15 = (uint32_t *) rtems_debugger_get_int_reg( thread, REG_R15 );
0866       frame->r16 = (uint32_t *) rtems_debugger_get_int_reg( thread, REG_R16 );
0867       frame->r17 = (uint32_t *) rtems_debugger_get_int_reg( thread, REG_R17 );
0868       frame->r18 = rtems_debugger_get_int_reg( thread, REG_R18 );
0869       frame->r19 = rtems_debugger_get_int_reg( thread, REG_R19 );
0870       frame->r20 = rtems_debugger_get_int_reg( thread, REG_R20 );
0871       frame->r21 = rtems_debugger_get_int_reg( thread, REG_R21 );
0872       frame->r22 = rtems_debugger_get_int_reg( thread, REG_R22 );
0873       frame->r23 = rtems_debugger_get_int_reg( thread, REG_R23 );
0874       frame->r24 = rtems_debugger_get_int_reg( thread, REG_R24 );
0875       frame->r25 = rtems_debugger_get_int_reg( thread, REG_R25 );
0876       frame->r26 = rtems_debugger_get_int_reg( thread, REG_R26 );
0877       frame->r27 = rtems_debugger_get_int_reg( thread, REG_R27 );
0878       frame->r28 = rtems_debugger_get_int_reg( thread, REG_R28 );
0879       frame->r29 = rtems_debugger_get_int_reg( thread, REG_R29 );
0880       frame->r30 = rtems_debugger_get_int_reg( thread, REG_R30 );
0881       frame->r31 = rtems_debugger_get_int_reg( thread, REG_R31 );
0882       frame->msr = rtems_debugger_get_int_reg( thread, REG_MS );
0883       frame->ear = (uint32_t *) rtems_debugger_get_int_reg( thread, REG_EA );
0884       frame->esr = rtems_debugger_get_int_reg( thread, REG_ES );
0885       frame->btr = (uint32_t *) rtems_debugger_get_int_reg( thread, REG_BT );
0886     }
0887 
0888     thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
0889   }
0890 
0891   return 0;
0892 }
0893 
0894 uintptr_t rtems_debugger_target_reg_pc( rtems_debugger_thread *thread )
0895 {
0896   return thread->tcb->Registers.r15;
0897 }
0898 
0899 uintptr_t rtems_debugger_target_frame_pc( CPU_Exception_frame *frame )
0900 {
0901   return (uintptr_t) _MicroBlaze_Get_return_address( frame );
0902 }
0903 
0904 uintptr_t rtems_debugger_target_reg_sp( rtems_debugger_thread *thread )
0905 {
0906   int r;
0907 
0908   r = rtems_debugger_target_read_regs( thread );
0909 
0910   if ( r >= 0 ) {
0911     return rtems_debugger_get_int_reg( thread, REG_R1 );
0912   }
0913 
0914   return 0;
0915 }
0916 
0917 uintptr_t rtems_debugger_target_tcb_sp( rtems_debugger_thread *thread )
0918 {
0919   return (uintptr_t) thread->tcb->Registers.r1;
0920 }
0921 
0922 #define IGROUP_MASK 0x3f
0923 
0924 static uint32_t get_igroup( uint32_t ins )
0925 {
0926   return ( ins >> 26 ) & IGROUP_MASK;
0927 }
0928 
0929 #define REGISTER_MASK 0x1f
0930 
0931 static uint32_t get_Ra( uint32_t ins )
0932 {
0933   return ( ins >> 16 ) & REGISTER_MASK;
0934 }
0935 
0936 static uint32_t get_Rb( uint32_t ins )
0937 {
0938   return ( ins >> 11 ) & REGISTER_MASK;
0939 }
0940 
0941 static uint32_t get_Rd( uint32_t ins )
0942 {
0943   return ( ins >> 21 ) & REGISTER_MASK;
0944 }
0945 
0946 #define IMM16_MASK 0xffff
0947 
0948 static int32_t get_Imm16( uint32_t ins )
0949 {
0950   int16_t base = (int16_t) ins & IMM16_MASK;
0951 
0952   return base;
0953 }
0954 
0955 #define IMM24_MASK 0xffffff
0956 
0957 static int32_t get_Imm24( uint32_t ins )
0958 {
0959   int32_t base = ins & IMM24_MASK;
0960 
0961   /* Sign-extend manually if necessary */
0962   if ( ( base & 0x800000 ) != 0 ) {
0963     base &= 0xFF000000;
0964   }
0965 
0966   return base;
0967 }
0968 
0969 static int64_t get_Imm( uint32_t ins )
0970 {
0971   if ( ( get_Rd( ins ) & 0x10 ) != 0 ) {
0972     return get_Imm24( ins );
0973   }
0974 
0975   return get_Imm16( ins );
0976 }
0977 
0978 #define IMM_GROUP 0x2c
0979 
0980 static bool is_imm( uint32_t ins )
0981 {
0982   return get_igroup( ins ) == IMM_GROUP;
0983 }
0984 
0985 #define RETURN_GROUP 0x2d
0986 
0987 static bool is_return( uint32_t ins )
0988 {
0989   return get_igroup( ins ) == RETURN_GROUP;
0990 }
0991 
0992 /* Unconditional branch */
0993 #define UBRANCH_GROUP 0x26
0994 
0995 static bool is_ubranch( uint32_t ins )
0996 {
0997   return get_igroup( ins ) == UBRANCH_GROUP;
0998 }
0999 
1000 /* Comparison branch */
1001 #define CBRANCH_GROUP 0x27
1002 
1003 static bool is_cbranch( uint32_t ins )
1004 {
1005   return get_igroup( ins ) == CBRANCH_GROUP;
1006 }
1007 
1008 /* Unconditional Immediate branch */
1009 #define UIBRANCH_GROUP 0x2e
1010 
1011 static bool is_uibranch( uint32_t ins )
1012 {
1013   /* Ra == 0x2 is a memory barrier which continues at the next instruction */
1014   return get_igroup( ins ) == UIBRANCH_GROUP && get_Ra( ins ) != 0x2;
1015 }
1016 
1017 /* Comparison Immediate branch */
1018 #define CIBRANCH_GROUP 0x2f
1019 
1020 static bool is_cibranch( uint32_t ins )
1021 {
1022   return get_igroup( ins ) == CIBRANCH_GROUP;
1023 }
1024 
1025 static bool branch_has_delay_slot( uint32_t ins )
1026 {
1027   if ( is_ubranch( ins ) == true && ( get_Ra( ins ) & 0x10 ) != 0 ) {
1028     return true;
1029   }
1030 
1031   if ( is_cbranch( ins ) == true && ( get_Ra( ins ) & 0x10 ) != 0 ) {
1032     return true;
1033   }
1034 
1035   if ( is_uibranch( ins ) == true && ( get_Ra( ins ) & 0x10 ) != 0 ) {
1036     return true;
1037   }
1038 
1039   if ( is_cibranch( ins ) == true && ( get_Rd( ins ) & 0x10 ) != 0 ) {
1040     return true;
1041   }
1042 
1043   return false;
1044 }
1045 
1046 /* All return instructions have a delay slot */
1047 
1048 static bool branch_is_absolute( uint32_t ins )
1049 {
1050   return ( is_ubranch( ins ) == true || is_uibranch( ins ) == true ) &&
1051          ( get_Ra( ins ) & 0x8 ) != 0;
1052 }
1053 
1054 /* All returns are absolute */
1055 
1056 static bool target_is_absolute( uint32_t ins )
1057 {
1058   return branch_is_absolute( ins ) == true || is_return( ins ) == true;
1059 }
1060 
1061 static bool is_branch( uint32_t ins )
1062 {
1063   if ( is_ubranch( ins ) == true ) {
1064     return true;
1065   }
1066 
1067   if ( is_cbranch( ins ) == true ) {
1068     return true;
1069   }
1070 
1071   if ( is_uibranch( ins ) == true ) {
1072     return true;
1073   }
1074 
1075   if ( is_cibranch( ins ) == true ) {
1076     return true;
1077   }
1078 
1079   return false;
1080 }
1081 
1082 #define BRK_RA 0xC
1083 
1084 static bool is_brk( uint32_t ins )
1085 {
1086   return ( is_ubranch( ins ) == true || is_uibranch( ins ) == true ) &&
1087          get_Ra( ins ) == BRK_RA;
1088 }
1089 
1090 static uint32_t get_register_value(
1091   CPU_Exception_frame *frame,
1092   uint32_t             target_register
1093 )
1094 {
1095   if ( target_register == 0 ) {
1096     return 0;
1097   }
1098 
1099   /* Assumes all registers are contiguous and accounted for */
1100   return ( &( frame->r1 ) )[ target_register - 1 ];
1101 }
1102 
1103 static void set_frame_pc( CPU_Exception_frame *frame, uint32_t *new_pc )
1104 {
1105   Per_CPU_Control *cpu_self = _Per_CPU_Get();
1106 
1107   /* Break in progress */
1108   if ( ( frame->msr & MICROBLAZE_MSR_BIP ) != 0 ) {
1109     frame->r16 = (uint32_t *) new_pc;
1110     return;
1111   }
1112 
1113   /* Exception in progress */
1114   if ( ( frame->msr & MICROBLAZE_MSR_EIP ) != 0 ) {
1115     frame->r17 = (uint32_t *) new_pc;
1116     return;
1117   }
1118 
1119   /* Interrupt in progress must be determined by stack pointer location */
1120   if (
1121     frame->r1 >= (uint32_t) cpu_self->interrupt_stack_low
1122     && frame->r1 < (uint32_t) cpu_self->interrupt_stack_high
1123   ) {
1124     frame->r14 = (uint32_t *) new_pc;
1125     return;
1126   }
1127 
1128   /* Default to normal link register */
1129   frame->r15 = (uint32_t *) new_pc;
1130 }
1131 
1132 static uint32_t bypass_swbreaks( uint32_t *addr )
1133 {
1134   rtems_debugger_target *target = rtems_debugger->target;
1135 
1136   if ( target != NULL && target->swbreaks.block != NULL ) {
1137     rtems_debugger_target_swbreak *swbreaks = target->swbreaks.block;
1138     size_t                         i;
1139 
1140     for ( i = 0; i < target->swbreaks.level; ++i ) {
1141       if ( swbreaks[ i ].address == addr ) {
1142         return *( (uint32_t *) &( swbreaks[ i ].contents[ 0 ] ) );
1143       }
1144     }
1145   }
1146 
1147   return *addr;
1148 }
1149 
1150 static int setup_single_step_breakpoints( CPU_Exception_frame *frame )
1151 {
1152   /*
1153    * It may be necessary to evaluate the current instruction and next immediate
1154    * instruction to determine the address of the "next" instruction and possible
1155    * branch target instructions
1156    */
1157   uint32_t *pc = (uint32_t *) rtems_debugger_target_frame_pc( frame );
1158   int64_t   imm = 0;
1159   uint32_t *resume_pc;
1160 
1161   /*
1162    * Normalize PC address to the real instruction and not any IMM. This deals
1163    * with a possible cascade of IMM.
1164    */
1165   while ( is_imm( bypass_swbreaks( pc ) ) == true ) {
1166     pc = &pc[ 1 ];
1167   }
1168 
1169   resume_pc = pc;
1170 
1171   /*
1172    * If execution ends up on a branch instruction that is preceeded by IMM, bad
1173    * things can happen since it's not possible to know if the IMM was actually
1174    * executed or something jumped to the branch directly. Exceptions treat IMM
1175    * as part of the following instruction, so the RTEMS debugger will do so as
1176    * well.
1177    */
1178   uint32_t bypass_ins = bypass_swbreaks( &pc[ -1 ] );
1179 
1180   if ( is_imm( bypass_ins ) == true ) {
1181     imm = get_Imm( bypass_ins );
1182     imm <<= 16;
1183     resume_pc = &pc[ -1 ];
1184   }
1185 
1186   uint32_t ins = bypass_swbreaks( pc );
1187   bool     needs_target_break = false;
1188   bool     needs_next_break = true;
1189 
1190   if ( is_brk( ins ) == true ) {
1191     /*
1192      * If the instruction being stepped is brk or brki, something bad has
1193      * happened. If this instruction is stepped, the target of the branch (the
1194      * debug vector) has a brki placed in it which results in an tight infinite
1195      * recursive call. Under normal circumstances, this shouldn't happen.
1196      */
1197     rtems_debugger_printf(
1198       "rtems-db: Unable to set single-step breakpoints for brk/brki instructions\n"
1199     );
1200 
1201     return -1;
1202   }
1203 
1204   if ( is_branch( ins ) == true ) {
1205     needs_target_break = true;
1206 
1207     /*
1208      * Unconditional branches (including returns) do not need to break on the
1209      * next instruction.
1210      */
1211     if (
1212       is_ubranch( ins ) == true
1213       || is_uibranch( ins ) == true
1214       || is_return( ins ) == true
1215     ) {
1216       needs_next_break = false;
1217     }
1218   }
1219 
1220   if ( is_return( ins ) == true ) {
1221     needs_target_break = true;
1222     needs_next_break = false;
1223   }
1224 
1225   if ( needs_next_break == true ) {
1226     uint32_t *next_ins = &pc[ 1 ];
1227 
1228     if ( branch_has_delay_slot( ins ) == true ) {
1229       next_ins = &pc[ 2 ];
1230     }
1231 
1232     if ( is_brk( *next_ins ) == false ) {
1233       /* setup next instruction software break */
1234       set_soft_break( &next_soft_break, next_ins );
1235     }
1236   }
1237 
1238   if ( imm != 0 ) {
1239     imm |= ( get_Imm16( ins ) & 0xFFFF );
1240   } else {
1241     imm = get_Imm16( ins );
1242   }
1243 
1244   if ( needs_target_break == true ) {
1245     /* Calculate target address */
1246     uintptr_t target_ins = 0;
1247 
1248     if ( target_is_absolute( ins ) == false ) {
1249       target_ins += (uintptr_t) pc;
1250     }
1251 
1252     if (
1253       is_uibranch( ins ) == true || is_cibranch( ins ) == true ||
1254       is_return( ins ) == true
1255     ) {
1256       target_ins += imm;
1257     }
1258 
1259     if ( is_return( ins ) == true ) {
1260       uint32_t target_register = get_Ra( ins );
1261       target_ins += get_register_value( frame, target_register );
1262     }
1263 
1264     if ( is_ubranch( ins ) == true || is_cbranch( ins ) == true ) {
1265       uint32_t target_register = get_Rb( ins );
1266       target_ins += get_register_value( frame, target_register );
1267     }
1268 
1269     if ( is_brk( *( (uint32_t *) target_ins ) ) == false ) {
1270       /* setup target instruction software break */
1271       set_soft_break( &target_soft_break, (uint32_t *) target_ins );
1272     }
1273   }
1274 
1275   /* Alter resume address */
1276   set_frame_pc( frame, resume_pc );
1277 
1278   return 0;
1279 }
1280 
1281 int rtems_debugger_target_thread_stepping( rtems_debugger_thread *thread )
1282 {
1283   CPU_Exception_frame *frame = thread->frame;
1284   int                  ret = 0;
1285 
1286   if (
1287     rtems_debugger_thread_flag(
1288       thread,
1289       RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR
1290     ) != 0
1291   ) {
1292     /* Especially on first startup, frame isn't guaranteed to be non-NULL */
1293     if ( frame == NULL ) {
1294       return -1;
1295     }
1296 
1297     /* set software breakpoint(s) here */
1298     ret = setup_single_step_breakpoints( frame );
1299   }
1300 
1301   return ret;
1302 }
1303 
1304 int rtems_debugger_target_exception_to_signal( CPU_Exception_frame *frame )
1305 {
1306   uint32_t BiP = frame->msr & MICROBLAZE_MSR_BIP;
1307   uint32_t EiP = frame->msr & MICROBLAZE_MSR_EIP;
1308 
1309   if ( BiP != 0 ) {
1310     return RTEMS_DEBUGGER_SIGNAL_TRAP;
1311   }
1312 
1313   if ( EiP != 0 ) {
1314     uint32_t EC = frame->esr & 0x1f;
1315 
1316     switch ( EC ) {
1317      case 0x0: /* FSL */
1318      case 0x1: /* Unaligned data access */
1319      case 0x3: /* instruction fetch */
1320      case 0x4: /* data bus error */
1321      case 0x10: /* MMU data storage */
1322      case 0x11: /* MMU instruction storage */
1323      case 0x12: /* MMU data TLB miss */
1324      case 0x13: /* MMU instruction TLB miss */
1325        return RTEMS_DEBUGGER_SIGNAL_SEGV;
1326 
1327      case 0x7: /* priveleged */
1328        return RTEMS_DEBUGGER_SIGNAL_TRAP;
1329 
1330      case 0x5: /* div/0 */
1331      case 0x6: /* FPU */
1332        return RTEMS_DEBUGGER_SIGNAL_FPE;
1333 
1334      case 0x2: /* illegal opcode (unknown instruction) */
1335 
1336        /* Check for the illegal opcode being used in place of brki */
1337        if ( rtems_debugger_target_swbreak_is_configured( (uintptr_t) frame->r17 ) ) {
1338          return RTEMS_DEBUGGER_SIGNAL_TRAP;
1339        }
1340 
1341      default:
1342        return RTEMS_DEBUGGER_SIGNAL_ILL;
1343     }
1344   }
1345 
1346   /* Default to SIGILL */
1347   return RTEMS_DEBUGGER_SIGNAL_ILL;
1348 }
1349 
1350 void rtems_debugger_target_exception_print( CPU_Exception_frame *frame )
1351 {
1352   EXC_FRAME_PRINT( rtems_debugger_printf, "", frame );
1353 }
1354 
1355 /*
1356  * Debug hardware is inaccessible to the CPU, so hardware breaks and watchpoints
1357  * are not supported.
1358  */
1359 int rtems_debugger_target_hwbreak_insert( void )
1360 {
1361   return 0;
1362 }
1363 
1364 int rtems_debugger_target_hwbreak_remove( void )
1365 {
1366   return 0;
1367 }
1368 
1369 int rtems_debugger_target_hwbreak_control(
1370   rtems_debugger_target_watchpoint wp,
1371   bool                             insert,
1372   uintptr_t                        addr,
1373   DB_UINT                          kind
1374 )
1375 {
1376   return 0;
1377 }
1378 
1379 int rtems_debugger_target_cache_sync( rtems_debugger_target_swbreak *swbreak )
1380 {
1381   /*
1382    * Flush the data cache and invalidate the instruction cache.
1383    */
1384   rtems_cache_flush_multiple_data_lines(
1385     swbreak->address,
1386     sizeof( breakpoint )
1387   );
1388   rtems_cache_instruction_sync_after_code_change(
1389     swbreak->address,
1390     sizeof( breakpoint )
1391   );
1392   return 0;
1393 }