aboutsummaryrefslogtreecommitdiff
path: root/Marlin/src/HAL/shared/backtrace/unwinder.h
blob: 157808d540da43a85d70bb433cef970ba0d17194 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/***************************************************************************
 * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
 * Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
 *
 * This program is PUBLIC DOMAIN.
 * This means that there is no copyright and anyone is able to take a copy
 * for free and use it as they wish, with or without modifications, and in
 * any context, commerically or otherwise. The only limitation is that I
 * don't guarantee that the software is fit for any purpose or accept any
 * liability for its use or misuse - this software is without warranty.
 **************************************************************************/
/** \file
 * Interface to the ARM stack unwinding module.
 **************************************************************************/

#pragma once

#include <stdint.h>

/** \def UNW_DEBUG
 * If this define is set, additional information will be produced while
 * unwinding the stack to allow debug of the unwind module itself.
 */
/* #define UNW_DEBUG 1 */

/***************************************************************************
 * Type Definitions
 **************************************************************************/

/** Possible results for UnwindStart to return.
 */
typedef enum {
  /** Unwinding was successful and complete. */
  UNWIND_SUCCESS = 0,

  /** Not an error: More frames are available. */
  UNWIND_MORE_AVAILABLE = 1,

  /** Unsupported DWARF unwind personality. */
  UNWIND_UNSUPPORTED_DWARF_PERSONALITY = -1,

  /** Refused to perform unwind. */
  UNWIND_REFUSED = -2,

  /** Reached an invalid SP. */
  UNWIND_INVALID_SP = -3,

  /** Reached an invalid PC */
  UNWIND_INVALID_PC = -4,

  /** Unsupported DWARF instruction */
  UNWIND_UNSUPPORTED_DWARF_INSTR = -5,

  /** More than UNW_MAX_INSTR_COUNT instructions were interpreted. */
  UNWIND_EXHAUSTED = -6,

  /** Unwinding stopped because the reporting func returned false. */
  UNWIND_TRUNCATED = -7,

  /** Read data was found to be inconsistent. */
  UNWIND_INCONSISTENT = -8,

  /** Unsupported instruction or data found. */
  UNWIND_UNSUPPORTED = -9,

  /** General failure. */
  UNWIND_FAILURE = -10,

  /** Illegal instruction. */
  UNWIND_ILLEGAL_INSTR = -11,

  /** Unwinding hit the reset vector. */
  UNWIND_RESET = -12,

  /** Failed read for an instruction word. */
  UNWIND_IREAD_W_FAIL = -13,

  /** Failed read for an instruction half-word. */
  UNWIND_IREAD_H_FAIL = -14,

  /** Failed read for an instruction byte. */
  UNWIND_IREAD_B_FAIL = -15,

  /** Failed read for a data word. */
  UNWIND_DREAD_W_FAIL = -16,

  /** Failed read for a data half-word. */
  UNWIND_DREAD_H_FAIL = -17,

  /** Failed read for a data byte. */
  UNWIND_DREAD_B_FAIL = -18,

  /** Failed write for a data word. */
  UNWIND_DWRITE_W_FAIL = -19

} UnwResult;

/** A backtrace report */
typedef struct {
  uint32_t function;  /** Starts address of function */
  const char *name;   /** Function name, or null if not available */
  uint32_t address;   /** PC on that function */
} UnwReport;

/** Type for function pointer for result callback.
 * The function is passed two parameters, the first is a void * pointer,
 * and the second is the return address of the function.  The bottom bit
 * of the passed address indicates the execution mode; if it is set,
 * the execution mode at the return address is Thumb, otherwise it is
 * ARM.
 *
 * The return value of this function determines whether unwinding should
 * continue or not.  If true is returned, unwinding will continue and the
 * report function maybe called again in future.  If false is returned,
 * unwinding will stop with UnwindStart() returning UNWIND_TRUNCATED.
 */
typedef bool (*UnwindReportFunc)(void* data, const UnwReport* bte);

/** Structure that holds memory callback function pointers.
 */
typedef struct {

  /** Report an unwind result. */
  UnwindReportFunc report;

  /** Read a 32 bit word from memory.
   * The memory address to be read is passed as \a address, and
   * \a *val is expected to be populated with the read value.
   * If the address cannot or should not be read, false can be
   * returned to indicate that unwinding should stop.  If true
   * is returned, \a *val is assumed to be valid and unwinding
   * will continue.
   */
  bool (*readW)(const uint32_t address, uint32_t *val);

  /** Read a 16 bit half-word from memory.
   * This function has the same usage as for readW, but is expected
   * to read only a 16 bit value.
   */
  bool (*readH)(const uint32_t address, uint16_t *val);

  /** Read a byte from memory.
   * This function has the same usage as for readW, but is expected
   * to read only an 8 bit value.
   */
  bool (*readB)(const uint32_t address, uint8_t  *val);

  #ifdef UNW_DEBUG
    /** Print a formatted line for debug. */
    void (*printf)(const char *format, ...);
  #endif
} UnwindCallbacks;

/* A frame */
typedef struct {
  uint32_t fp;
  uint32_t sp;
  uint32_t lr;
  uint32_t pc;
} UnwindFrame;

/** Start unwinding the current stack.
 * This will unwind the stack starting at the PC value supplied to in the
 * link register (i.e. not a normal register) and the stack pointer value
 * supplied.
 *
 * -If the program was compiled with -funwind-tables it will use them to
 * perform the traceback. Otherwise, brute force will be employed
 * -If the program was compiled with -mpoke-function-name, then you will
 * get function names in the traceback. Otherwise, you will not.
 */
UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data);