source: rtems/cpukit/libdebugger/rtems-debugger-arm.c @ b2353ed9

Last change on this file since b2353ed9 was b2353ed9, checked in by Chris Johns <chrisj@…>, on Jul 16, 2017 at 11:53:11 PM

libdebugger: Fixes to debugging, ARM support, locking, and gcc-7.1 warnings.

  • Add printk support to aid multi-core debugging.
  • Add lock trace to aid lock debugging.
  • Fixes to gcc-7.1 warnings.
  • Fixes from ticket #2879.
  • Add verbose command controls.
  • Change using the RTEMS sys/lock.h API to manage exception threads.
  • ARM hardware breakpoint fixes. Support for SMP stepping is not implemented, this requires use of the context id register.

Closes #2879.

  • Property mode set to 100644
File size: 43.1 KB
Line 
1/*
2 * Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#define TARGET_DEBUG 0
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <errno.h>
34#include <inttypes.h>
35#include <stdlib.h>
36
37#include <rtems.h>
38#include <rtems/score/threadimpl.h>
39
40#include <bsp/linker-symbols.h>
41
42#include "rtems-debugger-target.h"
43#include "rtems-debugger-threads.h"
44
45#if TARGET_DEBUG
46#include <rtems/bspIo.h>
47#endif
48
49/*
50 * ARM Variant controls.
51 */
52#if defined(__ARM_ARCH_7A__) || \
53    defined(__ARM_ARCH_7R__)
54  #define ARM_CP15 1
55#endif
56
57#if (defined(__ARM_ARCH_7M__) || \
58     defined(__ARM_ARCH_7EM__))
59  #define ARM_THUMB_ONLY 1
60#else
61  #define ARM_THUMB_ONLY 0
62#endif
63
64#if defined(ARM_MULTILIB_ARCH_V4)
65 #define ARM_PSR_HAS_INT_MASK 1
66 #define ARM_PSR_HAS_THUMB    1
67#else
68 #define ARM_PSR_HAS_INT_MASK 0
69 #define ARM_PSR_HAS_THUMB    0
70#endif
71
72#if ARM_CP15
73#include <libcpu/arm-cp15.h>
74#endif
75
76/**
77 * If thumb build of code switch the asm to thumb as required.
78 *
79 * If the variant only supports thumb insturctions disable the support.
80 */
81#define ARM_SWITCH_REG     uint32_t arm_switch_reg
82#define ARM_SWITCH_REG_ASM [arm_switch_reg] "=&r" (arm_switch_reg)
83#if !ARM_THUMB_ONLY && defined(__thumb__)
84  #define ASM_ARM_MODE   ".align 2\nbx pc\n.arm\n"
85  #define ASM_THUMB_MODE "add %[arm_switch_reg], pc, #1\nbx %[arm_switch_reg]\n.thumb\n"
86#else
87  #define ASM_ARM_MODE
88  #define ASM_THUMB_MODE
89#endif
90
91/*
92 * Hack to work around ARMv7-M not having a the T and I bits in the PSR.
93 *
94 * This needs to be fixed when real support for this ARM variant is added.
95 */
96#if !defined(ARM_PSR_I)
97  #define ARM_PSR_I 0
98#endif
99#if !defined(ARM_PSR_T)
100  #define ARM_PSR_T 0
101#endif
102
103/*
104 * The ARM has 2 interrupt bits.
105 */
106#define CPSR_IRQ_DISABLE 0x80    /* IIQ disabled when 1 */
107#define CPSR_FIQ_DISABLE 0x40    /* FIQ disabled when 1 */
108#define CPSR_INTS_MASK   (CPSR_IRQ_DISABLE | CPSR_FIQ_DISABLE)
109
110/*
111 * Software breakpoint block size.
112 */
113#define RTEMS_DEBUGGER_SWBREAK_NUM 64
114
115/*
116 * Number of registers.
117 */
118#define RTEMS_DEBUGGER_NUMREGS 26
119
120/*
121 * Number of bytes per register.
122 */
123#define RTEMS_DEBUGGER_REGBYTES 4
124
125/*
126 * Number of bytes of registers.
127 */
128#define RTEMS_DEBUGGER_NUMREGBYTES \
129  (RTEMS_DEBUGGER_NUMREGS * RTEMS_DEBUGGER_REGBYTES)
130
131/*
132 * Debugger registers layout.
133 */
134#define REG_R0    0
135#define REG_R1    1
136#define REG_R2    2
137#define REG_R3    3
138#define REG_R4    4
139#define REG_R5    5
140#define REG_R6    6
141#define REG_R7    7
142#define REG_R8    8
143#define REG_R9    9
144#define REG_R10   10
145#define REG_R11   11
146#define REG_R12   12
147#define REG_SP    13
148#define REG_LR    14
149#define REG_PC    15
150#define REG_CPSR  25
151
152/**
153 * The various status registers.
154 */
155#if defined(ARM_MULTILIB_ARCH_V4)
156 #define FRAME_SR frame->register_cpsr
157#elif defined(ARM_MULTILIB_ARCH_V7M)
158 #define FRAME_SR frame->register_xpsr
159#else
160 #error ARM architecture is not supported.
161#endif
162
163/**
164 * The breakpoint.
165 */
166#ifdef __thumb__
167 static const uint8_t breakpoint[2] = { 0x55, 0xbe };
168#else
169 static const uint8_t breakpoint[4] = { 0x75, 0xe0, 0x20, 0xe1 };
170#endif
171
172/**
173 * Target lock.
174 */
175RTEMS_INTERRUPT_LOCK_DEFINE(static, target_lock, "target_lock")
176
177/**
178 * Is a session active?
179 */
180static bool debug_session_active;
181
182/*
183 * ARM debug hardware.
184 */
185static int debug_version;
186static int debug_revision;;
187static int hw_breakpoints;
188static int hw_watchpoints;
189
190/**
191 * Hardware break and watch points.
192 */
193typedef struct
194{
195  bool                 enabled;
196  bool                 loaded;
197  void*                address;
198  size_t               length;
199  CPU_Exception_frame* frame;
200  uint32_t             control;
201  uint32_t             value;
202} arm_debug_hwbreak;
203
204#define ARM_HW_BREAKPOINT_MAX (16)
205#define ARM_HW_WATCHPOINT_MAX (16)
206
207/*
208 * Types of break points. Only the 2 we use listed.
209 */
210#define ARM_HW_BP_UNLINKED_INSTR_MATCH    (0x00)
211#define ARM_HW_BP_UNLINKED_INSTR_MISMATCH (0x04)
212
213/*
214 * Privilege levels.
215 */
216#define ARM_HW_BP_PRIV_PL0_SUP_SYS (0x00)
217#define ARM_HW_BP_PRIV_PL1_ONLY    (0x01)
218#define ARM_HW_BP_PRIV_PL0_ONLY    (0x02)
219#define ARM_HW_BP_PRIV_ALL_MODES   (0x03)
220
221static arm_debug_hwbreak hw_breaks[ARM_HW_BREAKPOINT_MAX];
222//static arm_debug_hwbreak hw_watches[ARM_HW_WATCHPOINT_MAX];
223
224#if TARGET_DEBUG
225void rtems_debugger_printk_lock(rtems_interrupt_lock_context* lock_context);
226void rtems_debugger_printk_unlock(rtems_interrupt_lock_context* lock_context);
227
228static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
229static void
230target_printk(const char* format, ...)
231{
232  rtems_interrupt_lock_context lock_context;
233  va_list ap;
234  va_start(ap, format);
235  rtems_debugger_printk_lock(&lock_context);
236  vprintk(format, ap);
237  rtems_debugger_printk_unlock(&lock_context);
238  va_end(ap);
239}
240static const char*
241mode_label(int mode)
242{
243  switch (mode) {
244  case 0x10:
245    return "USR";
246  case 0x11:
247    return "FIQ";
248  case 0x12:
249    return "IRQ";
250  case 0x13:
251    return "SVC";
252  case 0x16:
253    return "MON";
254  case 0x17:
255    return "ABT";
256  case 0x1a:
257    return "HYP";
258  case 0x1b:
259    return "UND";
260  case 0x1f:
261    return "SYS";
262  }
263  return "---";
264}
265#else
266#define target_printk(_fmt, ...)
267#define mode_labels(_m) NULL
268#endif
269
270/*
271 * CP register access.
272 */
273#define ARM_CP_INSTR(_opc, _cp, _op1, _val, _CRn, _CRm, _op2)           \
274  #_opc " p" #_cp ", " #_op1 ", %[" #_val "], c" #_CRn ", c" #_CRm ", " #_op2 "\n"
275
276#define ARM_CP_WRITE(_cp, _op1, _val, _CRn, _CRm, _op2)    \
277  do {                                                     \
278    ARM_SWITCH_REG;                                        \
279    asm volatile(                                          \
280      ASM_ARM_MODE                                         \
281      ARM_CP_INSTR(mcr, _cp, _op1, val, _CRn, _CRm, _op2)  \
282      ASM_THUMB_MODE                                       \
283      : ARM_SWITCH_REG_ASM                                 \
284      : [val] "r" (_val));                                 \
285  } while (0)
286
287#define ARM_CP_READ(_cp, _op1, _val, _CRn, _CRm, _op2)     \
288  do {                                                     \
289    ARM_SWITCH_REG;                                        \
290    asm volatile(                                          \
291      ASM_ARM_MODE                                         \
292      ARM_CP_INSTR(mrc, _cp, _op1, val, _CRn, _CRm, _op2)  \
293      ASM_THUMB_MODE                                       \
294      : ARM_SWITCH_REG_ASM,                                \
295        [val] "=&r" (_val));                               \
296  } while (0)
297
298/*
299 * Read and write a CP14 register.
300 *
301 * The software debug event registers are not easy to program because there are
302 * up to 32 registers and the instructions have to assembler for each of the 32
303 * registers, you cannot program it. This means there is a switch table to do
304 * this.
305 */
306#define ARM_CP14_WRITE(_val, _CRn, _CRm, _op2) \
307  ARM_CP_WRITE(14, 0, _val, _CRn, _CRm, _op2)
308
309#define ARM_CP14_READ(_val, _CRn, _CRm, _op2)  \
310  ARM_CP_READ(14, 0, _val, _CRn, _CRm, _op2)
311
312/*
313 * Read and write a CP15 register.
314 *
315 * The Context ID register is a process level context and used to scope
316 * hardware break points.
317 */
318#define ARM_CP15_WRITE(_val, _op1, _CRn, _CRm, _op2) \
319  ARM_CP_WRITE(15, _op1, _val, _CRn, _CRm, _op2)
320
321#define ARM_CP15_READ(_val, _op1, _CRn, _CRm, _op2)  \
322  ARM_CP_READ(15, _op1, _val, _CRn, _CRm, _op2)
323
324static int
325arm_debug_probe(rtems_debugger_target* target)
326{
327  #define ID_VALUE(_i, _h, _l) ((_i >> _l) & ((1 << ((_h - _l) + 1)) -1))
328  uint32_t          val;
329  const char*       vl = "[Invalid version]";
330  const char* const labels[] = {
331    "ARMv6 [v6]",
332    "ARMv6 [v6.1]",
333    "ARMv7 [v7, all CP14 registers]",
334    "ARMv7 [v7, baseline CP14 registers]",
335    "ARMv7 [v7.1]"
336  };
337  ARM_CP14_READ(val, 0, 0, 0);
338  debug_version = ID_VALUE(val, 19, 16);
339  if (debug_version < 1 || debug_version > 5) {
340    rtems_debugger_printf("rtems-db: arm debug: (v%d.%d) not supported\n",
341                          debug_version, debug_revision);
342    errno = EIO;
343    return -1;
344  }
345  vl = labels[debug_version - 1];
346  debug_revision = ID_VALUE(val, 3, 0);
347  hw_breakpoints = ID_VALUE(val, 27, 24);
348  hw_watchpoints = ID_VALUE(val, 31, 28);
349  rtems_debugger_printf("rtems-db: arm debug: (v%d.%d) %s breakpoints:%d watchpoints:%d\n",
350                        debug_version, debug_revision, vl,
351                        hw_breakpoints, hw_watchpoints);
352  ARM_CP14_READ(val, 0, 1, 0);
353  if ((val & (1 << 15)) == 0) {
354    switch (debug_version) {
355    case 1:
356    case 2:
357      ARM_CP14_WRITE(val | (1 << 15), 0, 1, 0);
358      break;
359    case 3:
360    case 4:
361    case 5:
362    default:
363      ARM_CP14_WRITE(val | (1 << 15), 0, 2, 2);
364      break;
365    }
366    ARM_CP14_READ(val, 0, 1, 0);
367    if ((val & (1 << 15)) == 0) {
368      rtems_debugger_printf("rtems-db: arm debug: cannot enter monitor mode\n");
369      errno = EIO;
370      return -1;
371    }
372  }
373  return 0;
374}
375
376static inline void
377arm_debug_break_setup(arm_debug_hwbreak* bp,
378                      uint32_t           address,
379                      uint32_t           type,
380                      uint32_t           byte_address_select,
381                      uint32_t           privilege)
382{
383  bp->control = (((type & 0xf) << 20) |
384                 ((byte_address_select & 0xf) << 5) |
385                 ((privilege & 0x3) << 1) | 1);
386  bp->value = (intptr_t) address;
387}
388
389static void
390arm_debug_break_write_control(int bp, uint32_t control)
391{
392  switch (bp) {
393  case 0:
394    ARM_CP14_WRITE(control, 0, 0, 5);
395    break;
396  case 1:
397    ARM_CP14_WRITE(control, 0, 1, 5);
398    break;
399  case 2:
400    ARM_CP14_WRITE(control, 0, 2, 5);
401    break;
402  case 3:
403    ARM_CP14_WRITE(control, 0, 3, 5);
404    break;
405  case 4:
406    ARM_CP14_WRITE(control, 0, 4, 5);
407    break;
408  case 5:
409    ARM_CP14_WRITE(control, 0, 5, 5);
410    break;
411  case 6:
412    ARM_CP14_WRITE(control, 0, 6, 5);
413    break;
414  case 7:
415    ARM_CP14_WRITE(control, 0, 7, 5);
416    break;
417  case 8:
418    ARM_CP14_WRITE(control, 0, 8, 5);
419    break;
420  case 9:
421    ARM_CP14_WRITE(control, 0, 9, 5);
422    break;
423  case 10:
424    ARM_CP14_WRITE(control, 0, 10, 5);
425    break;
426  case 11:
427    ARM_CP14_WRITE(control, 0, 11, 5);
428    break;
429  case 12:
430    ARM_CP14_WRITE(control, 0, 12, 5);
431    break;
432  case 13:
433    ARM_CP14_WRITE(control, 0, 13, 5);
434    break;
435  case 14:
436    ARM_CP14_WRITE(control, 0, 14, 5);
437    break;
438  case 15:
439    ARM_CP14_WRITE(control, 0, 15, 5);
440    break;
441  }
442}
443
444static void
445arm_debug_break_write_value(int bp, uint32_t value)
446{
447  switch (bp) {
448  case 0:
449    ARM_CP14_WRITE(value, 0, 0, 4);
450    break;
451  case 1:
452    ARM_CP14_WRITE(value, 0, 1, 4);
453    break;
454  case 2:
455    ARM_CP14_WRITE(value, 0, 2, 4);
456    break;
457  case 3:
458    ARM_CP14_WRITE(value, 0, 3, 4);
459    break;
460  case 4:
461    ARM_CP14_WRITE(value, 0, 4, 4);
462    break;
463  case 5:
464    ARM_CP14_WRITE(value, 0, 5, 4);
465    break;
466  case 6:
467    ARM_CP14_WRITE(value, 0, 6, 4);
468    break;
469  case 7:
470    ARM_CP14_WRITE(value, 0, 7, 4);
471    break;
472  case 8:
473    ARM_CP14_WRITE(value, 0, 8, 4);
474    break;
475  case 9:
476    ARM_CP14_WRITE(value, 0, 9, 4);
477    break;
478  case 10:
479    ARM_CP14_WRITE(value, 0, 10, 4);
480    break;
481  case 11:
482    ARM_CP14_WRITE(value, 0, 11, 4);
483    break;
484  case 12:
485    ARM_CP14_WRITE(value, 0, 12, 4);
486    break;
487  case 13:
488    ARM_CP14_WRITE(value, 0, 13, 4);
489    break;
490  case 14:
491    ARM_CP14_WRITE(value, 0, 14, 4);
492    break;
493  case 15:
494    ARM_CP14_WRITE(value, 0, 15, 4);
495    break;
496  }
497}
498
499static void
500arm_debug_break_clear(void)
501{
502  rtems_interrupt_lock_context lock_context;
503  arm_debug_hwbreak*           bp = &hw_breaks[0];
504  int                          i;
505  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
506  for (i = 0; i < hw_breakpoints; ++i, ++bp) {
507    bp->enabled = false;
508    bp->loaded = false;
509  }
510  rtems_interrupt_lock_release(&target_lock, &lock_context);
511}
512
513static inline void
514arm_debug_set_context_id(const uint32_t id)
515{
516  ARM_CP15_WRITE(id, 0, 13, 0, 1);
517}
518
519/*
520 * You can only load the hardware breaks points when in the SVC mode or the
521 * single step inverted break point will trigger.
522 */
523static void
524arm_debug_break_load(void)
525{
526  rtems_interrupt_lock_context lock_context;
527  arm_debug_hwbreak*            bp = &hw_breaks[0];
528  int                           i;
529  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
530  if (bp->enabled && !bp->loaded) {
531    arm_debug_set_context_id(0xdead1111);
532    arm_debug_break_write_value(0, bp->value);
533    arm_debug_break_write_control(0, bp->control);
534  }
535  ++bp;
536  for (i = 1; i < hw_breakpoints; ++i, ++bp) {
537    if (bp->enabled && !bp->loaded) {
538      bp->loaded = true;
539      arm_debug_break_write_value(i, bp->value);
540      arm_debug_break_write_control(i, bp->control);
541    }
542  }
543  rtems_interrupt_lock_release(&target_lock, &lock_context);
544}
545
546static void
547arm_debug_break_unload(void)
548{
549  rtems_interrupt_lock_context lock_context;
550  arm_debug_hwbreak*           bp = &hw_breaks[0];
551  int                i;
552  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
553  arm_debug_set_context_id(0);
554  for (i = 0; i < hw_breakpoints; ++i, ++bp) {
555    bp->loaded = false;
556    arm_debug_break_write_control(i, 0);
557  }
558  rtems_interrupt_lock_release(&target_lock, &lock_context);
559}
560
561#if NOT_USED_BUT_KEEPING
562static size_t
563arm_debug_break_length(void* pc)
564{
565  arm_debug_hwbreak* bp = &hw_breaks[0];
566  int                i;
567
568  for (i = 0; i < hw_breakpoints; ++i, ++bp) {
569    if (bp->enabled && bp->address == pc) {
570      return bp->length;
571    }
572  }
573  return sizeof(DB_UINT);
574}
575#endif
576
577int
578rtems_debugger_target_configure(rtems_debugger_target* target)
579{
580  target->capabilities = (RTEMS_DEBUGGER_TARGET_CAP_SWBREAK);
581  target->reg_num = RTEMS_DEBUGGER_NUMREGS;
582  target->reg_size = sizeof(uint32_t);
583  target->breakpoint = &breakpoint[0];
584  target->breakpoint_size = sizeof(breakpoint);
585  return arm_debug_probe(target);
586}
587
588static void
589target_exception(CPU_Exception_frame* frame)
590{
591#if TARGET_DEBUG
592  uint32_t ifsr = arm_cp15_get_instruction_fault_status();
593#endif
594
595  target_printk("[} frame = %08lx sig=%d vector=%x ifsr=%08lx pra=%08x\n",
596                (uint32_t) frame,
597                rtems_debugger_target_exception_to_signal(frame),
598                frame->vector, ifsr, (intptr_t) frame->register_pc);
599
600  if ((FRAME_SR & (1 <<  5)) == 0)
601    frame->register_pc = (void*) ((intptr_t) frame->register_pc - 8);
602  else
603    frame->register_pc = (void*) ((intptr_t) frame->register_pc - 4);
604
605  target_printk("[}  R0 = %08" PRIx32 "  R1 = %08" PRIx32       \
606                "  R2 = %08" PRIx32 "  R3 = %08" PRIx32 "\n",
607                frame->register_r0, frame->register_r1,
608                frame->register_r2, frame->register_r3);
609  target_printk("[}  R4 = %08" PRIx32 "  R5 = %08" PRIx32       \
610                "  R6 = %08" PRIx32 "  R7 = %08" PRIx32 "\n",
611                frame->register_r4, frame->register_r5,
612                frame->register_r6, frame->register_r7);
613  target_printk("[}  R8 = %08" PRIx32 "  R9 = %08" PRIx32       \
614                " R10 = %08" PRIx32 " R11 = %08" PRIx32 "\n",
615                frame->register_r8, frame->register_r9,
616                frame->register_r10, frame->register_r11);
617  target_printk("[} R12 = %08" PRIx32 "  SP = %08" PRIx32       \
618                "  LR = %08" PRIxPTR "  PC = %08" PRIxPTR "\n", \
619                frame->register_r12, frame->register_sp,
620                (intptr_t) frame->register_lr, (intptr_t) frame->register_pc);
621  target_printk("[}  CPSR = %08" PRIx32 " %c%c%c%c%c%c%c%c%c%c%c" \
622                " GE:%" PRIx32 " IT:%02" PRIx32 " M:%" PRIx32 " %s\n",
623                FRAME_SR,
624                (FRAME_SR & (1 << 31)) != 0 ? 'N' : '-',
625                (FRAME_SR & (1 << 30)) != 0 ? 'Z' : '-',
626                (FRAME_SR & (1 << 29)) != 0 ? 'C' : '-',
627                (FRAME_SR & (1 << 28)) != 0 ? 'V' : '-',
628                (FRAME_SR & (1 << 27)) != 0 ? 'Q' : '-',
629                (FRAME_SR & (1 << 24)) != 0 ? 'J' : '-',
630                (FRAME_SR & (1 <<  9)) != 0 ? 'E' : '-',
631                (FRAME_SR & (1 <<  8)) != 0 ? 'A' : '-',
632                (FRAME_SR & (1 <<  7)) != 0 ? 'I' : '-',
633                (FRAME_SR & (1 <<  6)) != 0 ? 'F' : '-',
634                (FRAME_SR & (1 <<  5)) != 0 ? 'T' : '-',
635                ((FRAME_SR >> (25 - 5)) & (0x3 << 5)) | ((FRAME_SR >> 10) & 0x1f),
636                (FRAME_SR >> 16) & 0xf,
637                FRAME_SR & 0x1f, mode_label(FRAME_SR & 0x1f));
638
639  arm_debug_break_clear();
640
641  if (!debug_session_active)
642    _ARM_Exception_default(frame);
643
644  switch (rtems_debugger_target_exception(frame)) {
645  case rtems_debugger_target_exc_consumed:
646  default:
647    break;
648  case rtems_debugger_target_exc_step:
649    FRAME_SR |= CPSR_INTS_MASK;
650    break;
651  case rtems_debugger_target_exc_cascade:
652    target_printk("rtems-db: unhandled exception: cascading\n");
653    _ARM_Exception_default(frame);
654    break;
655  }
656
657  target_printk("[} resuming frame = %08lx PC = %08" PRIxPTR " CPSR = %08" PRIx32 "\n",
658                (uint32_t) frame, (intptr_t) frame->register_pc, FRAME_SR);
659}
660
661/**
662 * Exception stack frame size.
663 *
664 * The size is the exception stack frame plus the CPSR from the exception. We
665 * save the CPSR and restore it when we exit the exception.
666 */
667#define EXCEPTION_FRAME_SIZE (sizeof(CPU_Exception_frame) + sizeof(uint32_t))
668
669/**
670 * Exception stack frame FPU offsets and sizes.
671 */
672#define EXCEPTION_FRAME_FPU_SIZE   ARM_VFP_CONTEXT_SIZE
673#define EXCEPTION_FRAME_FPU_OFFSET ARM_EXCEPTION_FRAME_VFP_CONTEXT_OFFSET
674
675/**
676 * Exception entry.
677 *
678 * We have switched from svc (or even user) to an exception mode. Save the
679 * current CPSR and create an exception frame on the exception's stack and then
680 * copy it to the thread's stack. Switch back to the thread's context and mode
681 * to handle the exception to avoid any stack checks thinking the stack is
682 * blown. This lets the thread be suspended.
683 *
684 * The entry is in two parts, the exception mode entry and the trhead mode
685 * entry. This lets us disable any hardware breakpoint support. We need to do
686 * this because it is enabled in PL0 mode.
687 *
688 * Note, the code currently assumes cp15 has been set up to match the
689 *       instruction set being used.
690 */
691#define EXCEPTION_ENTRY_EXC()                                           \
692  __asm__ volatile(                                                     \
693    ASM_ARM_MODE                                                        \
694    "sub  sp, %[frame_size]\n"           /* alloc the frame and CPSR */ \
695    "stm  sp, {r0-r12}\n"                            /* store r0-r12 */ \
696    "sub  sp, #4\n"                                                     \
697    "str  lr, [sp]\n"                           /* save the link reg */ \
698    ASM_THUMB_MODE                                                      \
699    : ARM_SWITCH_REG_ASM                                                \
700    : [frame_size] "i" (EXCEPTION_FRAME_SIZE)                           \
701    : "memory")
702
703/*
704 * FPU entry. Conditionally D16 or D32 support.
705 */
706#ifdef ARM_MULTILIB_VFP
707#ifdef ARM_MULTILIB_VFP_D32
708#define FPU_ENTRY_VFP_D32                                               \
709    "vstmia  r5!, {d16-d31}\n"
710#else  /* ARM_MULTILIB_VFP_D32 */
711#define FPU_ENTRY_VFP_D32                                               \
712    "mov    r3, #0\n"                                                   \
713    "mov    r4, #0\n"                                                   \
714    "adds   r6, r5, #128\n"                                             \
715    "3:\n"                                                              \
716    "stmia  r5!, {r3-r4}\n"                                             \
717    "cmp    r5, r6\n"                                                   \
718    "bne    3b\n"
719#endif /* ARM_MULTILIB_VFP_D32 */
720#define EXCEPTION_ENTRY_FPU(frame_fpu_size)                             \
721    "sub    sp, %[frame_fpu_size]\n" /* size includes alignment size */ \
722    "add    r5, sp, #4\n"                        /* up to align down */ \
723    "bic    r5, r5, #7\n"                     /* align the FPU frame */ \
724    "str    r5, [r2]\n"               /* store the FPU frame pointer */ \
725    "vmrs   r3, FPEXC\n"                                                \
726    "vmrs   r4, FPSCR\n"                                                \
727    "stmia  r5!, {r3-r4}\n"                                             \
728    "vstmia r5!, {d0-d15}\n"                                            \
729    FPU_ENTRY_VFP_D32
730#else  /* ARM_MULTILIB_VFP */
731#define EXCEPTION_ENTRY_FPU(frame_fpu_size)
732#endif /* ARM_MULTILIB_VFP */
733
734#define EXCEPTION_ENTRY_THREAD(_frame)                                  \
735  __asm__ volatile(                                                     \
736    ASM_ARM_MODE                                                        \
737    "ldr  lr, [sp]\n"                        /* recover the link reg */ \
738    "add  sp, #4\n"                                                     \
739    "add  r0, sp, %[r0_r12_size]\n"       /* get the sp in the frame */ \
740    "mrs  r1, spsr\n"                            /* get the saved sr */ \
741    "mov  r6, r1\n"                            /* stash it for later */ \
742    "bic  r1, r1, %[psr_t]\n"         /* clear thumb mode, not sure? */ \
743    "orr  r1, r1, %[psr_i]\n"                           /* mask irqs */ \
744    "mrs  r2, cpsr\n"                          /* get the current sr */ \
745    "str  r2, [sp, %[frame_cpsr]]\n"          /* save for exc return */ \
746    "msr  cpsr, r1\n"                         /* switch to user mode */ \
747    "mov  r3, sp\n"                         /* get the stack pointer */ \
748    "mov  r4, lr\n"                              /* get the link reg */ \
749    "msr  cpsr, r2\n"                            /* back to exc mode */ \
750    "mov  r5, lr\n"                                   /* get the PRA */ \
751    "stm  r0, {r3-r6}\n"                      /* save into the frame */ \
752    "sub  r4, r3, %[frame_size]\n"            /* destination address */ \
753    "mov  r6, r4\n"                                /* save the frame */ \
754    "sub  r4, #1\n"                          /* one before the start */ \
755    "add  r3, #1\n"                              /* one past the end */ \
756    "sub  r5, sp, #1\n"                            /* source address */ \
757    "1:\n"                                                              \
758    "ldrb r0, [r5, #1]!\n"                             /* get a byte */ \
759    "strb r0, [r4, #1]!\n"                           /* put the byte */ \
760    "cmp  r3, r4\n"                                      /* the end? */ \
761    "bne  1b\n"                                                         \
762    "add  sp, %[frame_size]\n"            /* free the frame and CPSR */ \
763    "mrs  r1, spsr\n"                   /* get the thread's saved sr */ \
764    "orr  r2, r1, %[psr_i]\n"                           /* mask irqs */ \
765    "msr  cpsr, r2\n"         /* switch back to the thread's context */ \
766    "sub  sp, %[frame_size]\n"          /* alloc in the thread stack */ \
767    "mov  %[o_frame], sp\n"                        /* save the frame */ \
768    "add  r2, sp, %[o_frame_fpu]\n"            /* get the FPU offset */ \
769    "mov  r3, #0\n"                                                     \
770    "str  r3, [r2]\n"                 /* clear the FPU frame pointer */ \
771    EXCEPTION_ENTRY_FPU(frame_fpu_size)                                 \
772    "bic  r1, r1, %[psr_i]\n"        /* clear irq mask, debug checks */ \
773    "msr  cpsr, r1\n"       /* restore the state with irq mask clear */ \
774    ASM_THUMB_MODE                                                      \
775    : ARM_SWITCH_REG_ASM,                                               \
776      [o_frame] "=r" (_frame)                                           \
777    : [psr_t] "i" (ARM_PSR_T),                                          \
778      [psr_i] "i" (ARM_PSR_I),                                          \
779      [r0_r12_size] "i" (13 * sizeof(uint32_t)),                        \
780      [frame_cpsr] "i" (EXCEPTION_FRAME_SIZE - sizeof(uint32_t)),       \
781      [frame_size] "i" (EXCEPTION_FRAME_SIZE),                          \
782      [o_frame_fpu] "i" (EXCEPTION_FRAME_FPU_OFFSET),                   \
783      [frame_fpu_size] "i" (EXCEPTION_FRAME_FPU_SIZE + 4)               \
784    : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory")
785
786/*
787 * FPU exit. Conditionally D16 or D32 support.
788 */
789#ifdef ARM_MULTILIB_VFP
790#ifdef ARM_MULTILIB_VFP_D32
791#define FPU_EXIT_VFP_D32                                                \
792    "vldmia r0, {d16-d31}\n"
793#else  /* ARM_MULTILIB_VFP_D32 */
794#define FPU_EXIT_VFP_D32
795#endif /* ARM_MULTILIB_VFP_D32 */
796#define EXCEPTION_EXIT_FPU(frame_fpu_size)                              \
797    "ldmia  r0!, {r1-r2}\n"                                             \
798    "vldmia r0!, {d0-d15}\n"                                            \
799    FPU_EXIT_VFP_D32                                                    \
800    "vmsr   FPEXC, r1\n"                                                \
801    "vmsr   FPSCR, r2\n"                                                \
802    "add    sp, %[frame_fpu_size]\n" /* size includes alignment size */
803#else  /* ARM_MULTILIB_VFP */
804#define EXCEPTION_EXIT_FPU(frame_fpu_size)
805#endif /* ARM_MULTILIB_VFP */
806
807/**
808 * Exception exit.
809 *
810 * The thread is to be resumed so we are still in the thread's mode. Copy the
811 * exception frame from the thread's stack back to the exception's stack and
812 * restore the thread's context before returning from the exception to the
813 * thread.
814 *
815 * Note, the code currently assumes cp15 has been set up to match the
816 *       instruction set being used.
817 */
818#define EXCEPTION_EXIT_THREAD(_frame)                                   \
819  __asm__ volatile(                                                     \
820    ASM_ARM_MODE                                                        \
821    "mov  r0, %[i_frame]\n"                         /* get the frame */ \
822    "ldr  r0, [r0, %[frame_fpu]]\n"     /* recover FPU frame pointer */ \
823    EXCEPTION_EXIT_FPU(frame_fpu_size)                                  \
824    "ldr  r2, [sp, %[frame_cpsr]]\n" /* recover exc CPSR from thread */ \
825    "mov  r0, sp\n"                  /* get the thread frame pointer */ \
826    "msr  cpsr, r2\n"            /* switch back to the exc's context */ \
827    "add  r3, sp, #1\n"                               /* get the end */ \
828    "sub  sp, %[frame_size]\n"                    /* alloc the frame */ \
829    "sub  r4, sp, #1\n"                       /* destination address */ \
830    "sub  r5, r0, #1\n"                            /* source address */ \
831    "1:\n"                                                              \
832    "ldrb r1, [r5, #1]!\n"                             /* get a byte */ \
833    "strb r1, [r4, #1]!\n"                           /* put the byte */ \
834    "cmp  r3, r4\n"                                      /* the end? */ \
835    "bne  1b\n"                                                         \
836    "add  r1, r0, %[r0_r12_size]\n"       /* get the sp in the frame */ \
837    "ldm  r1, {r3-r6}\n"                   /* recover from the frame */ \
838    "orr  r1, r6, %[psr_i]\n"  /* get the thread's psr and mask irqs */ \
839    "msr  cpsr, r1\n"                         /* switch to user mode */ \
840    "mov  sp, r3\n"                         /* set the stack pointer */ \
841    "mov  lr, r4\n"                              /* set the link reg */ \
842    "msr  cpsr, r2\n"            /* switch back to the exc's context */ \
843    "msr  spsr, r6\n"                       /* set the thread's CPSR */ \
844    "sub  sp, #4\n"                                                     \
845    "mov  lr, r5\n"                                    /* get the PC */ \
846    "str  lr, [sp]\n"                           /* save the link reg */ \
847    ASM_THUMB_MODE                                                      \
848    : ARM_SWITCH_REG_ASM                                                \
849    : [psr_i] "i" (ARM_PSR_I),                                          \
850      [r0_r12_size] "i" (13 * sizeof(uint32_t)),                        \
851      [frame_cpsr] "i" (EXCEPTION_FRAME_SIZE - sizeof(uint32_t)),       \
852      [frame_size] "i" (EXCEPTION_FRAME_SIZE),                          \
853      [frame_fpu] "i" (EXCEPTION_FRAME_FPU_OFFSET),                     \
854      [frame_fpu_size] "i" (EXCEPTION_FRAME_FPU_SIZE + 4),              \
855      [i_frame] "r" (_frame)                                            \
856    : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory")
857
858#define EXCEPTION_EXIT_EXC()                                            \
859  __asm__ volatile(                                                     \
860    ASM_ARM_MODE                                                        \
861    "ldr  lr, [sp]\n"                        /* recover the link reg */ \
862    "add  sp, #4\n"                                                     \
863    "ldm  sp, {r0-r12}\n"            /* restore the trhead's context */ \
864    "add  sp, %[frame_size]\n"                     /* free the frame */ \
865    "subs pc, lr, #0\n"                       /* return from the exc */ \
866    :                                                                   \
867    : [frame_size] "i" (EXCEPTION_FRAME_SIZE)                           \
868    : "memory")
869
870
871static void __attribute__((naked))
872target_exception_undefined_instruction(void)
873{
874  CPU_Exception_frame* frame;
875  ARM_SWITCH_REG;
876  EXCEPTION_ENTRY_EXC();
877  arm_debug_break_unload();
878  EXCEPTION_ENTRY_THREAD(frame);
879  frame->vector = 1;
880  target_exception(frame);
881  EXCEPTION_EXIT_THREAD(frame);
882  arm_debug_break_load();
883  EXCEPTION_EXIT_EXC();
884}
885
886static void __attribute__((naked))
887target_exception_supervisor_call(void)
888{
889  CPU_Exception_frame* frame;
890  ARM_SWITCH_REG;
891  /*
892   * The PC offset needs to be review so we move past a svc instruction. This
893   * can then used as a user breakpoint. The issue is this exception is used by
894   * the BKPT instruction in the prefetch abort handler to signal a TRAP.
895   */
896  EXCEPTION_ENTRY_EXC();
897  arm_debug_break_unload();
898  EXCEPTION_ENTRY_THREAD(frame);
899  frame->vector = 2;
900  target_exception(frame);
901  EXCEPTION_EXIT_THREAD(frame);
902  arm_debug_break_load();
903  EXCEPTION_EXIT_EXC();
904}
905
906static void __attribute__((naked))
907target_exception_prefetch_abort(void)
908{
909  CPU_Exception_frame* frame;
910  ARM_SWITCH_REG;
911  EXCEPTION_ENTRY_EXC();
912  arm_debug_break_unload();
913  EXCEPTION_ENTRY_THREAD(frame);
914#if ARM_CP15
915  if ((arm_cp15_get_instruction_fault_status() & 0x1f) == 0x02)
916    frame->vector = 2;
917  else
918    frame->vector = 3;
919#else
920  frame->vector = 3;
921#endif
922  target_exception(frame);
923  EXCEPTION_EXIT_THREAD(frame);
924  arm_debug_break_load();
925  EXCEPTION_EXIT_EXC();
926}
927
928static void __attribute__((naked))
929target_exception_data_abort(void)
930{
931  CPU_Exception_frame* frame;
932  ARM_SWITCH_REG;
933  EXCEPTION_ENTRY_EXC();
934  arm_debug_break_unload();
935  EXCEPTION_ENTRY_THREAD(frame);
936  frame->vector = 4;
937  target_exception(frame);
938  EXCEPTION_EXIT_THREAD(frame);
939  arm_debug_break_load();
940  EXCEPTION_EXIT_EXC();
941}
942
943#if ARM_CP15
944/**
945 * The init value for the text section.
946 */
947static uint32_t text_section_flags;
948
949static void
950rtems_debugger_target_set_vectors(void)
951{
952  void* text_begin;
953  void* text_end;
954  text_begin = &bsp_section_text_begin[0];
955  text_end = &bsp_section_text_end[0];
956  text_section_flags =
957    arm_cp15_set_translation_table_entries(text_begin,
958                                           text_end,
959                                           ARMV7_MMU_DATA_READ_WRITE_CACHED);
960  arm_cp15_set_exception_handler(ARM_EXCEPTION_UNDEF,
961                                 target_exception_undefined_instruction);
962  arm_cp15_set_exception_handler(ARM_EXCEPTION_SWI,
963                                 target_exception_supervisor_call);
964  arm_cp15_set_exception_handler(ARM_EXCEPTION_PREF_ABORT,
965                                 target_exception_prefetch_abort);
966  arm_cp15_set_exception_handler(ARM_EXCEPTION_DATA_ABORT,
967                                 target_exception_data_abort);
968}
969#else
970static void
971rtems_debugger_target_set_vectors(void)
972{
973  /*
974   * Dummy, please add support for your ARM variant.
975   */
976  void* ui = target_exception_undefined_instruction;
977  void* sc = target_exception_supervisor_call;
978  void* pa = target_exception_prefetch_abort;
979  void* da = target_exception_data_abort;
980  (void) ui;
981  (void) sc;
982  (void) pa;
983  (void) da;
984}
985#endif
986
987int
988rtems_debugger_target_enable(void)
989{
990  rtems_interrupt_lock_context lock_context;
991  debug_session_active = true;
992  arm_debug_break_unload();
993  arm_debug_break_clear();
994  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
995  rtems_debugger_target_set_vectors();
996  rtems_interrupt_lock_release(&target_lock, &lock_context);
997  return 0;
998}
999
1000int
1001rtems_debugger_target_disable(void)
1002{
1003  rtems_interrupt_lock_context lock_context;
1004#if DOES_NOT_WORK
1005  void*                        text_begin;
1006  void*                        text_end;
1007#endif
1008  arm_debug_break_unload();
1009  arm_debug_break_clear();
1010  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
1011  debug_session_active = false;
1012#if DOES_NOT_WORK
1013  text_begin = &bsp_section_text_begin[0];
1014  text_end = &bsp_section_text_end[0];
1015  arm_cp15_set_translation_table_entries(text_begin,
1016                                         text_end,
1017                                         text_section_flags);
1018#endif
1019  rtems_interrupt_lock_release(&target_lock, &lock_context);
1020  return 0;
1021}
1022
1023int
1024rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
1025{
1026  if (!rtems_debugger_thread_flag(thread,
1027                                  RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID)) {
1028    static const uint32_t good_address = (uint32_t) &good_address;
1029    uint32_t*             regs = &thread->registers[0];
1030    int                   i;
1031
1032    for (i = 0; i < RTEMS_DEBUGGER_NUMREGS; ++i)
1033      regs[i] = (uint32_t) &good_address;
1034
1035    if (thread->frame) {
1036      CPU_Exception_frame* frame = thread->frame;
1037
1038      /*
1039       * Assume interrupts are not masked and if masked set them to the saved
1040       * value.
1041       */
1042      FRAME_SR &= ~CPSR_INTS_MASK;
1043
1044      if (rtems_debugger_thread_flag(thread,
1045                                     RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED)) {
1046        FRAME_SR |=
1047          (thread->flags >> RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE) & CPSR_INTS_MASK;
1048        thread->flags = ~RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED;
1049      }
1050
1051      regs[REG_R0]   = frame->register_r0;
1052      regs[REG_R1]   = frame->register_r1;
1053      regs[REG_R2]   = frame->register_r2;
1054      regs[REG_R3]   = frame->register_r3;
1055      regs[REG_R4]   = frame->register_r4;
1056      regs[REG_R5]   = frame->register_r5;
1057      regs[REG_R6]   = frame->register_r6;
1058      regs[REG_R7]   = frame->register_r7;
1059      regs[REG_R8]   = frame->register_r8;
1060      regs[REG_R9]   = frame->register_r9;
1061      regs[REG_R10]  = frame->register_r10;
1062      regs[REG_R11]  = frame->register_r11;
1063      regs[REG_R12]  = frame->register_r12;
1064      regs[REG_SP]   = frame->register_sp;
1065      regs[REG_LR]   = (uint32_t) frame->register_lr;
1066      regs[REG_PC]   = (uint32_t) frame->register_pc;
1067      regs[REG_CPSR] = FRAME_SR;
1068      /*
1069       * Get the signal from the frame.
1070       */
1071      thread->signal = rtems_debugger_target_exception_to_signal(frame);
1072    }
1073    else {
1074#if defined(ARM_MULTILIB_ARCH_V4)
1075      regs[REG_R4]  = thread->tcb->Registers.register_r4;
1076      regs[REG_R5]  = thread->tcb->Registers.register_r5;
1077      regs[REG_R6]  = thread->tcb->Registers.register_r6;
1078      regs[REG_R7]  = thread->tcb->Registers.register_r7;
1079      regs[REG_R8]  = thread->tcb->Registers.register_r8;
1080      regs[REG_R9]  = thread->tcb->Registers.register_r9;
1081      regs[REG_R10] = thread->tcb->Registers.register_r10;
1082      regs[REG_R11] = thread->tcb->Registers.register_fp;
1083      regs[REG_LR]  = (intptr_t) thread->tcb->Registers.register_lr;
1084      regs[REG_PC]  = (intptr_t) thread->tcb->Registers.register_lr;
1085      regs[REG_SP]  = (intptr_t) thread->tcb->Registers.register_sp;
1086#elif defined(ARM_MULTILIB_ARCH_V7M)
1087      regs[REG_R4]  = thread->tcb->Registers.register_r4;
1088      regs[REG_R5]  = thread->tcb->Registers.register_r5;
1089      regs[REG_R6]  = thread->tcb->Registers.register_r6;
1090      regs[REG_R7]  = thread->tcb->Registers.register_r7;
1091      regs[REG_R8]  = thread->tcb->Registers.register_r8;
1092      regs[REG_R9]  = thread->tcb->Registers.register_r9;
1093      regs[REG_R10] = thread->tcb->Registers.register_r10;
1094      regs[REG_R11] = thread->tcb->Registers.register_r11;
1095      regs[REG_LR]  = (intptr_t) thread->tcb->Registers.register_lr;
1096      regs[REG_PC]  = (intptr_t) thread->tcb->Registers.register_lr;
1097      regs[REG_SP]  = (intptr_t) thread->tcb->Registers.register_sp;
1098#endif
1099      /*
1100       * Blocked threads have no signal.
1101       */
1102      thread->signal = 0;
1103    }
1104
1105    thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID;
1106    thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
1107  }
1108
1109  return 0;
1110}
1111
1112int
1113rtems_debugger_target_write_regs(rtems_debugger_thread* thread)
1114{
1115  if (rtems_debugger_thread_flag(thread,
1116                                 RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY)) {
1117    uint32_t* regs = &thread->registers[0];
1118
1119    /*
1120     * Only write to debugger controlled exception threads. Do not touch the
1121     * registers for threads blocked in the context switcher.
1122     */
1123    if (rtems_debugger_thread_flag(thread,
1124                                   RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) {
1125      CPU_Exception_frame* frame = thread->frame;
1126      frame->register_r0  = regs[REG_R0];
1127      frame->register_r1  = regs[REG_R1];
1128      frame->register_r2  = regs[REG_R2];
1129      frame->register_r3  = regs[REG_R3];
1130      frame->register_r4  = regs[REG_R4];
1131      frame->register_r5  = regs[REG_R5];
1132      frame->register_r6  = regs[REG_R6];
1133      frame->register_r7  = regs[REG_R7];
1134      frame->register_r8  = regs[REG_R8];
1135      frame->register_r9  = regs[REG_R9];
1136      frame->register_r10 = regs[REG_R10];
1137      frame->register_r11 = regs[REG_R11];
1138      frame->register_r12 = regs[REG_R12];
1139      frame->register_sp  = regs[REG_SP];
1140      frame->register_lr  = (void*) regs[REG_LR];
1141      frame->register_pc  = (void*) regs[REG_PC];
1142      FRAME_SR            = regs[REG_CPSR];
1143    }
1144    thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
1145  }
1146  return 0;
1147}
1148
1149DB_UINT
1150rtems_debugger_target_reg_pc(rtems_debugger_thread* thread)
1151{
1152  int r;
1153  r = rtems_debugger_target_read_regs(thread);
1154  if (r >= 0) {
1155    uint32_t* regs = &thread->registers[0];
1156    return regs[REG_PC];
1157  }
1158  return 0;
1159}
1160
1161DB_UINT
1162rtems_debugger_target_frame_pc(CPU_Exception_frame* frame)
1163{
1164  return (DB_UINT) frame->register_pc;
1165}
1166
1167DB_UINT
1168rtems_debugger_target_reg_sp(rtems_debugger_thread* thread)
1169{
1170  int r;
1171  r = rtems_debugger_target_read_regs(thread);
1172  if (r >= 0) {
1173    uint32_t* regs = &thread->registers[0];
1174    return regs[REG_SP];
1175  }
1176  return 0;
1177}
1178
1179DB_UINT
1180rtems_debugger_target_tcb_sp(rtems_debugger_thread* thread)
1181{
1182  return (DB_UINT) thread->tcb->Registers.register_sp;
1183}
1184
1185int
1186rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread)
1187{
1188  if (rtems_debugger_thread_flag(thread, RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR)) {
1189    /*
1190     * Single stepping and range stepping uses hardware debug breakpoint
1191     * 0. This is reserved for single stepping.
1192     */
1193    CPU_Exception_frame* frame = thread->frame;
1194    arm_debug_hwbreak*   bp = &hw_breaks[0];
1195    target_printk("[} stepping: %s\n", bp->enabled ? "yes" : "no");
1196    if (!bp->enabled) {
1197      const uint32_t addr = (intptr_t) frame->register_pc;
1198      const bool     thumb = (FRAME_SR & (1 << 5)) != 0 ? true : false;
1199      uint32_t       bas;
1200
1201      bp->enabled = true;
1202      bp->loaded = false;
1203      bp->address = frame->register_pc;
1204      bp->frame = frame;
1205      bp->length = sizeof(uint32_t);
1206
1207      if (thumb) {
1208        uint16_t instr = *((uint16_t*) frame->register_pc);
1209        switch (instr & 0xf800) {
1210        case 0xe800:
1211        case 0xf000:
1212        case 0xf800:
1213          break;
1214        default:
1215          bp->length = sizeof(uint16_t);
1216          break;
1217        }
1218      }
1219
1220      /*
1221       * See table C3-2 Effect of byte address selection on Breakpoint
1222       * generation and "Instruction address comparision programming
1223       * examples.
1224       */
1225      if (thumb) {
1226        if ((addr & (1 << 1)) == 0) {
1227          bas = 0x3; /* b0011 */
1228        }
1229        else {
1230          bas = 0xc; /* b1100 */
1231        }
1232      }
1233      else {
1234        bas = 0xf; /* b1111 */
1235      }
1236
1237      arm_debug_break_setup(bp,
1238                            addr & ~0x3,
1239                            ARM_HW_BP_UNLINKED_INSTR_MISMATCH,
1240                            bas,
1241                            ARM_HW_BP_PRIV_PL0_SUP_SYS);
1242
1243      /*
1244       * Save the interrupt state before stepping if set.
1245       */
1246#if ARM_PSR_HAS_INT_MASK
1247      if ((FRAME_SR & CPSR_INTS_MASK) != 0) {
1248        uint32_t int_state;
1249        int_state =
1250          (frame->register_cpsr & CPSR_INTS_MASK) << RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE;
1251        thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED | int_state;
1252      }
1253      /*
1254       * Mask the interrupt when stepping.
1255       */
1256      FRAME_SR |= CPSR_INTS_MASK;
1257#endif
1258    }
1259  }
1260  return 0;
1261}
1262
1263int
1264rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame)
1265{
1266  int sig = RTEMS_DEBUGGER_SIGNAL_HUP;
1267#if defined(ARM_MULTILIB_ARCH_V4)
1268  switch (frame->vector) {
1269  case ARM_EXCEPTION_RESET:
1270  case ARM_EXCEPTION_SWI:
1271    sig = RTEMS_DEBUGGER_SIGNAL_TRAP;
1272    break;
1273  case ARM_EXCEPTION_UNDEF:
1274    sig = RTEMS_DEBUGGER_SIGNAL_ILL;
1275    break;
1276  case ARM_EXCEPTION_FIQ:
1277    sig = RTEMS_DEBUGGER_SIGNAL_FPE;
1278    break;
1279  case ARM_EXCEPTION_PREF_ABORT:
1280  case ARM_EXCEPTION_DATA_ABORT:
1281    sig = RTEMS_DEBUGGER_SIGNAL_SEGV;
1282    break;
1283  case ARM_EXCEPTION_RESERVED:
1284  case ARM_EXCEPTION_IRQ:
1285    sig = RTEMS_DEBUGGER_SIGNAL_BUS;
1286    break;
1287  default:
1288    break;
1289  }
1290#endif
1291  return sig;
1292}
1293
1294int
1295rtems_debugger_target_hwbreak_insert(void)
1296{
1297  /*
1298   * Do nothing, load on exit of the exception handler.
1299   */
1300  return 0;
1301}
1302
1303int
1304rtems_debugger_target_hwbreak_remove(void)
1305{
1306  arm_debug_break_unload();
1307  return 0;
1308}
1309
1310int
1311rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint wp,
1312                                      bool                             insert,
1313                                      DB_UINT                          addr,
1314                                      DB_UINT                          kind)
1315{
1316  /*
1317   * To do.
1318   */
1319  return 0;
1320}
1321
1322int
1323rtems_debugger_target_cache_sync(rtems_debugger_target_swbreak* swbreak)
1324{
1325  /*
1326   * Flush the data cache and invalidate the instruction cache.
1327   */
1328  rtems_cache_flush_multiple_data_lines(swbreak->address,
1329                                        sizeof(breakpoint));
1330  rtems_cache_instruction_sync_after_code_change(swbreak->address,
1331                                                 sizeof(breakpoint));
1332  return 0;
1333}
Note: See TracBrowser for help on using the repository browser.