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

5
Last change on this file since 2c09b71f was 2c09b71f, checked in by Chris Johns <chrisj@…>, on 04/08/19 at 03:17:08

libdebugger: Use an offset table to format GDB g packets.

Adding support for a register offset table lets FPU registers
be supported if added to the backend.

Closes #3733.

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