File indexing completed on 2025-05-11 08:24:15
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #define TARGET_DEBUG 0
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
0045
0046
0047 typedef struct {
0048 rtems_chain_node node;
0049 rtems_id id;
0050 CPU_Exception_frame* frame;
0051 rtems_rx_cond cond;
0052 } rtems_debugger_exception;
0053
0054 #if TARGET_DEBUG
0055 #include <rtems/bspIo.h>
0056 static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
0057 static void
0058 target_printk(const char* format, ...)
0059 {
0060 rtems_interrupt_lock_context lock_context;
0061 va_list ap;
0062 va_start(ap, format);
0063 rtems_debugger_printk_lock(&lock_context);
0064 vprintk(format, ap);
0065 rtems_debugger_printk_unlock(&lock_context);
0066 va_end(ap);
0067 }
0068 #else
0069 #define target_printk(_fmt, ...)
0070 #endif
0071
0072 int
0073 rtems_debugger_target_create(void)
0074 {
0075 if (rtems_debugger->target == NULL) {
0076 rtems_debugger_target* target;
0077 int r;
0078
0079 target = calloc(1, sizeof(rtems_debugger_target));
0080 if (target == NULL) {
0081 errno = ENOMEM;
0082 return -1;
0083 }
0084
0085 r = rtems_debugger_target_configure(target);
0086 if (r < 0) {
0087 free(target);
0088 return -1;
0089 }
0090
0091 if (target->breakpoint_size > RTEMS_DEBUGGER_TARGET_SWBREAK_MAX_SIZE) {
0092 free(target);
0093 rtems_debugger_printf("error: rtems-db: target: breakpoint size too big\n");
0094 return -1;
0095 }
0096
0097 r = rtems_debugger_block_create(&target->swbreaks,
0098 RTEMS_DEBUGGER_TARGET_SWBREAK_NUM,
0099 sizeof(rtems_debugger_target_swbreak));
0100 if (r < 0) {
0101 free(target);
0102 return -1;
0103 }
0104
0105 rtems_debugger->target = target;
0106 }
0107
0108 return 0;
0109 }
0110
0111 int
0112 rtems_debugger_target_destroy(void)
0113 {
0114 if (rtems_debugger->target != NULL) {
0115 rtems_debugger_target* target = rtems_debugger->target;
0116 rtems_debugger_target_swbreak_remove();
0117 rtems_debugger_target_disable();
0118 rtems_debugger_block_destroy(&target->swbreaks);
0119 free(target);
0120 rtems_debugger->target = NULL;
0121 }
0122 return 0;
0123 }
0124
0125 uint32_t
0126 rtems_debugger_target_capabilities(void)
0127 {
0128 if (rtems_debugger->target != NULL)
0129
0130 return rtems_debugger->target->capabilities;
0131 return 0;
0132 }
0133
0134 size_t
0135 rtems_debugger_target_reg_num(void)
0136 {
0137 rtems_debugger_target* target = rtems_debugger->target;
0138 if (target != NULL)
0139 return target->reg_num;
0140 return 0;
0141 }
0142
0143 size_t
0144 rtems_debugger_target_reg_size(size_t reg)
0145 {
0146 rtems_debugger_target* target = rtems_debugger->target;
0147 if (target != NULL && reg < target->reg_num)
0148 return target->reg_offset[reg + 1] - target->reg_offset[reg];
0149 return 0;
0150 }
0151
0152 size_t
0153 rtems_debugger_target_reg_offset(size_t reg)
0154 {
0155 rtems_debugger_target* target = rtems_debugger->target;
0156 if (target != NULL && reg < target->reg_num)
0157 return target->reg_offset[reg];
0158 return 0;
0159 }
0160
0161 size_t
0162 rtems_debugger_target_reg_table_size(void)
0163 {
0164 rtems_debugger_target* target = rtems_debugger->target;
0165 if (target != NULL)
0166 return target->reg_offset[target->reg_num];
0167 return 0;
0168 }
0169
0170 bool
0171 rtems_debugger_target_swbreak_is_configured( uintptr_t addr )
0172 {
0173 size_t i;
0174 rtems_debugger_target_swbreak *swbreaks;
0175 rtems_debugger_target *target = rtems_debugger->target;
0176
0177 if ( target == NULL ) {
0178 return false;
0179 }
0180
0181 swbreaks = target->swbreaks.block;
0182
0183 if ( swbreaks == NULL ) {
0184 return false;
0185 }
0186
0187 for ( i = 0; i < target->swbreaks.level; ++i ) {
0188 if ( (uintptr_t) swbreaks[ i ].address == addr ) {
0189 return true;
0190 }
0191 }
0192
0193 return false;
0194 }
0195
0196 int
0197 rtems_debugger_target_swbreak_control(bool insert, uintptr_t addr, DB_UINT kind)
0198 {
0199 rtems_debugger_target* target = rtems_debugger->target;
0200 rtems_debugger_target_swbreak* swbreaks;
0201 size_t swbreak_size;
0202 uint8_t* loc = (void*) addr;
0203 size_t i;
0204 int r;
0205
0206 if (target == NULL || target->swbreaks.block == NULL ||
0207 kind != target->breakpoint_size) {
0208 errno = EIO;
0209 return -1;
0210 }
0211
0212 swbreaks = target->swbreaks.block;
0213 swbreak_size =
0214 sizeof(rtems_debugger_target_swbreak) + target->breakpoint_size;
0215
0216 for (i = 0; i < target->swbreaks.level; ++i) {
0217 if (loc == swbreaks[i].address) {
0218 size_t remaining;
0219 if (!insert) {
0220 if (target->code_writer != NULL) {
0221 r = target->code_writer(loc,
0222 &swbreaks[i].contents[0],
0223 target->breakpoint_size);
0224 if (r < 0) {
0225 return r;
0226 }
0227 } else {
0228 if (target->breakpoint_size > 4) {
0229 memcpy(loc, &swbreaks[i].contents[0], target->breakpoint_size);
0230 } else {
0231 switch (target->breakpoint_size) {
0232 case 4:
0233 loc[3] = swbreaks[i].contents[3];
0234 case 3:
0235 loc[2] = swbreaks[i].contents[2];
0236 case 2:
0237 loc[1] = swbreaks[i].contents[1];
0238 case 1:
0239 loc[0] = swbreaks[i].contents[0];
0240 break;
0241 }
0242 }
0243 rtems_debugger_target_cache_sync(&swbreaks[i]);
0244 }
0245 --target->swbreaks.level;
0246 remaining = (target->swbreaks.level - i) * swbreak_size;
0247 memmove(&swbreaks[i], &swbreaks[i + 1], remaining);
0248 }
0249 return 0;
0250 }
0251 }
0252
0253 if (!insert)
0254 return 0;
0255
0256 r = rtems_debugger_block_resize(&target->swbreaks);
0257 if (r < 0)
0258 return -1;
0259
0260 swbreaks = target->swbreaks.block;
0261
0262 swbreaks[target->swbreaks.level].address = loc;
0263 if (target->breakpoint_size > 4)
0264 memcpy(&swbreaks[target->swbreaks.level].contents[0],
0265 loc,
0266 target->breakpoint_size);
0267 else {
0268 uint8_t* contents = &swbreaks[target->swbreaks.level].contents[0];
0269 switch (target->breakpoint_size) {
0270 case 4:
0271 contents[3] = loc[3];
0272 case 3:
0273 contents[2] = loc[2];
0274 case 2:
0275 contents[1] = loc[1];
0276 case 1:
0277 contents[0] = loc[0];
0278 break;
0279 }
0280 }
0281 ++target->swbreaks.level;
0282
0283 return 0;
0284 }
0285
0286 int
0287 rtems_debugger_target_swbreak_insert(void)
0288 {
0289 rtems_debugger_target* target = rtems_debugger->target;
0290 int r = -1;
0291 if (target != NULL && target->swbreaks.block != NULL) {
0292 rtems_debugger_target_swbreak* swbreaks = target->swbreaks.block;
0293 size_t i;
0294 r = 0;
0295 for (i = 0; i < target->swbreaks.level; ++i) {
0296 uint8_t* loc = swbreaks[i].address;
0297 if (rtems_debugger_verbose())
0298 rtems_debugger_printf("rtems-db: bp: in: %p\n", swbreaks[i].address);
0299 if (target->code_writer != NULL) {
0300 r = target->code_writer(loc,
0301 &target->breakpoint[0],
0302 target->breakpoint_size);
0303 if (r < 0) {
0304 return r;
0305 }
0306 } else {
0307 if (target->breakpoint_size > 4) {
0308 memcpy(loc, &target->breakpoint[0], target->breakpoint_size);
0309 } else {
0310 if (rtems_debugger_verbose())
0311 rtems_debugger_printf("rtems-db: bp: in: %p %p %d %d %d\n",
0312 loc, &target->breakpoint[0],
0313 (int) target->breakpoint_size,
0314 (int) i, (int) target->swbreaks.level);
0315 switch (target->breakpoint_size) {
0316 case 4:
0317 loc[3] = target->breakpoint[3];
0318 case 3:
0319 loc[2] = target->breakpoint[2];
0320 case 2:
0321 loc[1] = target->breakpoint[1];
0322 case 1:
0323 loc[0] = target->breakpoint[0];
0324 break;
0325 }
0326 }
0327 r = rtems_debugger_target_cache_sync(&swbreaks[i]);
0328 }
0329 }
0330 }
0331 return r;
0332 }
0333
0334 int
0335 rtems_debugger_target_swbreak_remove(void)
0336 {
0337 rtems_debugger_target* target = rtems_debugger->target;
0338 int r = -1;
0339 if (target != NULL && target->swbreaks.block != NULL) {
0340 rtems_debugger_target* target = rtems_debugger->target;
0341 rtems_debugger_target_swbreak* swbreaks = target->swbreaks.block;
0342 size_t i;
0343 r = 0;
0344 for (i = 0; i < target->swbreaks.level; ++i) {
0345 uint8_t* loc = swbreaks[i].address;
0346 uint8_t* contents = &swbreaks[i].contents[0];
0347 if (rtems_debugger_verbose())
0348 rtems_debugger_printf("rtems-db: bp: out: %p\n", swbreaks[i].address);
0349 if (target->code_writer != NULL) {
0350 r = target->code_writer(loc, contents, target->breakpoint_size);
0351 if (r < 0) {
0352 return r;
0353 }
0354 } else {
0355 if (target->breakpoint_size > 4) {
0356 memcpy(loc, contents, target->breakpoint_size);
0357 } else {
0358 switch (target->breakpoint_size) {
0359 case 4:
0360 loc[3] = contents[3];
0361 case 3:
0362 loc[2] = contents[2];
0363 case 2:
0364 loc[1] = contents[1];
0365 case 1:
0366 loc[0] = contents[0];
0367 break;
0368 }
0369 }
0370 r = rtems_debugger_target_cache_sync(&swbreaks[i]);
0371 }
0372 }
0373 }
0374 return r;
0375 }
0376
0377 static rtems_debugger_target_exc_action
0378 rtems_debugger_soft_step_and_continue(CPU_Exception_frame* frame)
0379 {
0380 uintptr_t break_address;
0381 rtems_debugger_target *target = rtems_debugger->target;
0382 Thread_Control *thread = _Thread_Get_executing();
0383 const rtems_id tid = thread->Object.id;
0384 rtems_debugger_thread fake_debugger_thread;
0385
0386
0387
0388
0389
0390 if ((target->capabilities & RTEMS_DEBUGGER_TARGET_CAP_SWBREAK) == 0) {
0391 target_printk("rtems-db: exception in an interrupt, cascading\n");
0392 rtems_debugger_unlock();
0393 return rtems_debugger_target_exc_cascade;
0394 }
0395
0396 break_address = rtems_debugger_target_frame_pc( frame );
0397 if ( rtems_debugger_target_swbreak_is_configured( break_address ) == false ) {
0398 target_printk("rtems-db: exception in an interrupt, cascading\n");
0399 rtems_debugger_unlock();
0400 return rtems_debugger_target_exc_cascade;
0401 }
0402
0403
0404
0405
0406 rtems_debugger_target_swbreak_control(
0407 false,
0408 break_address,
0409 target->breakpoint_size
0410 );
0411
0412
0413
0414
0415 target->step_tid = tid;
0416 target->step_bp_address = break_address;
0417
0418
0419
0420
0421 fake_debugger_thread.flags |= RTEMS_DEBUGGER_THREAD_FLAG_STEP;
0422 fake_debugger_thread.frame = frame;
0423 target_printk("rtems-db: stepping to the next instruction\n");
0424 rtems_debugger_target_thread_stepping(&fake_debugger_thread);
0425
0426
0427
0428
0429 return rtems_debugger_target_exc_step;
0430 }
0431
0432 rtems_debugger_target_exc_action
0433 rtems_debugger_target_exception(CPU_Exception_frame* frame)
0434 {
0435 rtems_debugger_target *target = rtems_debugger->target;
0436 Thread_Control* thread = _Thread_Get_executing();
0437 const rtems_id tid = thread->Object.id;
0438
0439
0440
0441
0442 if (target->step_bp_address != 0 && target->step_tid == tid) {
0443 rtems_debugger_target_swbreak_control(
0444 true,
0445 target->step_bp_address,
0446 rtems_debugger->target->breakpoint_size
0447 );
0448 target->step_bp_address = 0;
0449 target->step_tid = 0;
0450
0451
0452
0453
0454 target_printk("rtems-db: resuming after step\n");
0455 rtems_debugger_unlock();
0456 return rtems_debugger_target_exc_consumed;
0457 }
0458
0459 rtems_debugger_lock();
0460
0461 if (!rtems_interrupt_is_in_progress()) {
0462 rtems_debugger_threads* threads = rtems_debugger->threads;
0463 rtems_id* excludes;
0464 uintptr_t pc;
0465 const rtems_debugger_thread_stepper* stepper;
0466 rtems_debugger_exception target_exception;
0467 size_t i;
0468
0469 target_printk("[} tid:%08" PRIx32 ": thread:%08" PRIxPTR
0470 " frame:%08" PRIxPTR "\n",
0471 tid, (intptr_t) thread, (intptr_t) frame);
0472
0473
0474
0475
0476
0477 if (tid == rtems_debugger->server_task ||
0478 tid == rtems_debugger->events_task) {
0479 bool memory_access = rtems_debugger_target_is_memory_access();
0480 rtems_debugger_unlock();
0481
0482
0483
0484 if (memory_access) {
0485 target_printk("[} server fault: memory access\n");
0486 longjmp(rtems_debugger->target->access_return, -1);
0487 }
0488 rtems_debugger_printf("rtems-db: server exception (report)\n");
0489 rtems_debugger_target_exception_print(frame);
0490 rtems_debugger_server_crash();
0491 return rtems_debugger_target_exc_cascade;
0492 }
0493
0494
0495
0496
0497 excludes = rtems_debugger_thread_excludes(threads);
0498 for (i = 0; i < threads->excludes.level; ++i) {
0499 if (tid == excludes[i]) {
0500
0501
0502
0503
0504
0505
0506
0507 target_printk("[} tid:%08" PRIx32 ": excluded\n", tid);
0508 rtems_debugger_unlock();
0509 return rtems_debugger_target_exc_cascade;
0510 }
0511 }
0512
0513
0514
0515
0516 pc = rtems_debugger_target_frame_pc(frame);
0517 stepper = rtems_debugger_thread_is_stepping(tid, pc);
0518 if (stepper != NULL) {
0519 stepper->thread->frame = frame;
0520 rtems_debugger_target_thread_stepping(stepper->thread);
0521 target_printk("[} tid:%08" PRIx32 ": stepping\n", tid);
0522 rtems_debugger_unlock();
0523 return rtems_debugger_target_exc_step;
0524 }
0525
0526 target_printk("[} tid:%08" PRIx32 ": suspending\n", tid);
0527
0528
0529
0530
0531
0532 rtems_chain_initialize_node(&target_exception.node);
0533 target_exception.frame = frame;
0534 target_exception.id = tid;
0535 _Condition_Initialize(&target_exception.cond);
0536
0537 rtems_chain_append_unprotected(&rtems_debugger->exception_threads,
0538 &target_exception.node);
0539
0540
0541
0542
0543 rtems_debugger_server_events_signal();
0544
0545
0546
0547
0548
0549 _Condition_Wait_recursive(&target_exception.cond, &rtems_debugger->lock);
0550
0551
0552
0553
0554 rtems_debugger_unlock();
0555
0556 target_printk("[} tid:%08" PRIx32 ": resuming\n", tid);
0557
0558 return rtems_debugger_target_exc_consumed;
0559 }
0560
0561 target_printk("[} tid:%08" PRIx32 ": exception in interrupt context\n", tid);
0562
0563
0564
0565
0566 return rtems_debugger_soft_step_and_continue(frame);
0567 }
0568
0569 void
0570 rtems_debugger_target_exception_thread(rtems_debugger_thread* thread)
0571 {
0572 rtems_chain_node* node;
0573 thread->frame = NULL;
0574 thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION;
0575 for (node = rtems_chain_first(&rtems_debugger->exception_threads);
0576 !rtems_chain_is_tail(&rtems_debugger->exception_threads, node);
0577 node = rtems_chain_next(node)) {
0578 rtems_debugger_exception* target_exception = (rtems_debugger_exception*) node;
0579 if (target_exception->id == thread->id) {
0580 thread->frame = target_exception->frame;
0581 thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION;
0582 }
0583 }
0584 }
0585
0586 void
0587 rtems_debugger_target_exception_thread_resume(rtems_debugger_thread* thread)
0588 {
0589 rtems_chain_node* node;
0590 for (node = rtems_chain_first(&rtems_debugger->exception_threads);
0591 !rtems_chain_is_tail(&rtems_debugger->exception_threads, node);
0592 node = rtems_chain_next(node)) {
0593 rtems_debugger_exception* target_exception = (rtems_debugger_exception*) node;
0594 if (target_exception->id == thread->id) {
0595 rtems_chain_extract(node);
0596 thread->frame = NULL;
0597 thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION;
0598 _Condition_Signal(&target_exception->cond);
0599 break;
0600 }
0601 }
0602 }
0603
0604 int
0605 rtems_debugger_target_start_memory_access(void)
0606 {
0607 rtems_debugger_target* target = rtems_debugger->target;
0608 target->memory_access = true;
0609 return setjmp(target->access_return);
0610 }
0611
0612 void
0613 rtems_debugger_target_end_memory_access(void)
0614 {
0615 rtems_debugger->target->memory_access = false;
0616 }
0617
0618 bool
0619 rtems_debugger_target_is_memory_access(void)
0620 {
0621 return rtems_debugger->target->memory_access;
0622 }