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
|
/***************************************************************************
* ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
*
* 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 Description: Internal interface between the ARM unwinding sub-modules.
**************************************************************************/
#pragma once
#include "unwinder.h"
/** The maximum number of instructions to interpet in a function.
* Unwinding will be unconditionally stopped and UNWIND_EXHAUSTED returned
* if more than this number of instructions are interpreted in a single
* function without unwinding a stack frame. This prevents infinite loops
* or corrupted program memory from preventing unwinding from progressing.
*/
#define UNW_MAX_INSTR_COUNT 500
/** The size of the hash used to track reads and writes to memory.
* This should be a prime value for efficiency.
*/
#define MEM_HASH_SIZE 31
/***************************************************************************
* Type Definitions
**************************************************************************/
typedef enum {
/** Invalid value. */
REG_VAL_INVALID = 0x00,
REG_VAL_FROM_STACK = 0x01,
REG_VAL_FROM_MEMORY = 0x02,
REG_VAL_FROM_CONST = 0x04,
REG_VAL_ARITHMETIC = 0x80
} RegValOrigin;
/** Type for tracking information about a register.
* This stores the register value, as well as other data that helps unwinding.
*/
typedef struct {
/** The value held in the register. */
uint32_t v;
/** The origin of the register value.
* This is used to track how the value in the register was loaded.
*/
int o; /* (RegValOrigin) */
} RegData;
/** Structure used to track reads and writes to memory.
* This structure is used as a hash to store a small number of writes
* to memory.
*/
typedef struct {
/** Memory contents. */
uint32_t v[MEM_HASH_SIZE];
/** Address at which v[n] represents. */
uint32_t a[MEM_HASH_SIZE];
/** Indicates whether the data in v[n] and a[n] is occupied.
* Each bit represents one hash value.
*/
uint8_t used[(MEM_HASH_SIZE + 7) / 8];
/** Indicates whether the data in v[n] is valid.
* This allows a[n] to be set, but for v[n] to be marked as invalid.
* Specifically this is needed for when an untracked register value
* is written to memory.
*/
uint8_t tracked[(MEM_HASH_SIZE + 7) / 8];
} MemData;
/** Structure that is used to keep track of unwinding meta-data.
* This data is passed between all the unwinding functions.
*/
typedef struct {
/** The register values and meta-data. */
RegData regData[16];
/** Memory tracking data. */
MemData memData;
/** Pointer to the callback functions */
const UnwindCallbacks *cb;
/** Pointer to pass to the report function. */
const void *reportData;
} UnwState;
/***************************************************************************
* Macros
**************************************************************************/
#define M_IsOriginValid(v) !!((v) & 0x7F)
#define M_Origin2Str(v) ((v) ? "VALID" : "INVALID")
#ifdef UNW_DEBUG
#define UnwPrintd1(a) state->cb->printf(a)
#define UnwPrintd2(a,b) state->cb->printf(a,b)
#define UnwPrintd3(a,b,c) state->cb->printf(a,b,c)
#define UnwPrintd4(a,b,c,d) state->cb->printf(a,b,c,d)
#define UnwPrintd5(a,b,c,d,e) state->cb->printf(a,b,c,d,e)
#define UnwPrintd6(a,b,c,d,e,f) state->cb->printf(a,b,c,d,e,f)
#define UnwPrintd7(a,b,c,d,e,f,g) state->cb->printf(a,b,c,d,e,f,g)
#define UnwPrintd8(a,b,c,d,e,f,g,h) state->cb->printf(a,b,c,d,e,f,g,h)
#else
#define UnwPrintd1(a)
#define UnwPrintd2(a,b)
#define UnwPrintd3(a,b,c)
#define UnwPrintd4(a,b,c,d)
#define UnwPrintd5(a,b,c,d,e)
#define UnwPrintd6(a,b,c,d,e,f)
#define UnwPrintd7(a,b,c,d,e,f,g)
#define UnwPrintd8(a,b,c,d,e,f,g,h)
#endif
/***************************************************************************
* Function Prototypes
**************************************************************************/
UnwResult UnwStartArm(UnwState * const state);
UnwResult UnwStartThumb(UnwState * const state);
void UnwInvalidateRegisterFile(RegData *regFile);
void UnwInitState(UnwState * const state, const UnwindCallbacks *cb, void *rptData, uint32_t pcValue, uint32_t spValue);
bool UnwReportRetAddr(UnwState * const state, uint32_t addr);
bool UnwMemWriteRegister(UnwState * const state, const uint32_t addr, const RegData * const reg);
bool UnwMemReadRegister(UnwState * const state, const uint32_t addr, RegData * const reg);
void UnwMemHashGC(UnwState * const state);
|