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
173
174
175
176
177
178
179
180
181
182
183
184
185
|
#pragma once
#include "substitute-internal.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#ifdef __GNUC__
#define alloca(size) __builtin_alloca(size)
#else
extern void * alloca (size_t __size);
#endif
#define INLINE __attribute__((always_inline))
#define NOINLINE __attribute__((noinline))
static INLINE inline void unaligned_w64(void *ptr, uint64_t val) {
__builtin_memcpy(ptr, &val, 8);
}
static INLINE inline void unaligned_w32(void *ptr, uint32_t val) {
__builtin_memcpy(ptr, &val, 4);
}
static INLINE inline void unaligned_w16(void *ptr, uint16_t val) {
__builtin_memcpy(ptr, &val, 2);
}
static INLINE inline uint64_t unaligned_r64(const void *ptr) {
uint64_t val;
__builtin_memcpy(&val, ptr, 8);
return val;
}
static INLINE inline uint32_t unaligned_r32(const void *ptr) {
uint32_t val;
__builtin_memcpy(&val, ptr, 4);
return val;
}
static INLINE inline uint16_t unaligned_r16(const void *ptr) {
uint16_t val;
__builtin_memcpy(&val, ptr, 2);
return val;
}
struct bitslice_run {
int inpos, outpos, len;
};
struct bitslice {
int nruns;
const struct bitslice_run *runs;
};
static inline int sext(unsigned val, int bits) {
return val & (1 << (bits - 1)) ? ((int)val - (1 << bits)) : (int)val;
}
static inline unsigned bs_get(struct bitslice bs, unsigned op) {
unsigned ret = 0;
for(int i = 0; i < bs.nruns; i++) {
const struct bitslice_run *run = &bs.runs[i];
unsigned val = (op >> run->inpos) & ((1 << run->len) - 1);
ret |= val << run->outpos;
}
return ret;
}
static inline unsigned bs_set(struct bitslice bs, unsigned new, unsigned op) {
for(int i = 0; i < bs.nruns; i++) {
const struct bitslice_run *run = &bs.runs[i];
unsigned mask = (1 << run->len) - 1;
unsigned val = (new >> run->outpos) & mask;
op = (op & ~(mask << run->inpos)) | (val << run->inpos);
}
return op;
}
static inline struct bitslice bs_slice_(struct bitslice bs,
struct bitslice_run *runs,
int lo, int size) {
int nruns = 0;
for(int i = 0; i < bs.nruns; i++) {
struct bitslice_run inr = bs.runs[i];
inr.outpos -= lo;
if(inr.outpos < 0) {
inr.len += inr.outpos;
inr.inpos -= inr.outpos;
inr.outpos = 0;
}
if(inr.outpos + inr.len > size)
inr.len = size - inr.outpos;
if(inr.len > 0)
runs[nruns++] = (struct bitslice_run) {inr.inpos, inr.outpos, inr.len};
}
return (struct bitslice) {nruns, runs};
}
#define bs_slice(bs, lo, size) \
bs_slice_(bs, alloca((bs).nruns * sizeof(struct bitslice_run)), lo, size)
enum pcrel_load_mode {
PLM_ADR, /* just want the address */
PLM_U8, PLM_S8,
PLM_U16, PLM_S16,
PLM_U32, PLM_S32,
PLM_U64,
PLM_U128, /* i.e. LDRD */
PLM_U32_SIMD,
PLM_U64_SIMD,
PLM_U128_SIMD,
};
static const struct bitslice null_bs = { 0, NULL };
static const unsigned null_op = -0x100;
#define r(nn) nn, false, true
#define rs(nn, l, s) bs_slice(nn, l, s), false, true
#define rout(nn) nn, true, true
#define rsout(nn, l, s) bs_slice(nn, l, s), true, true
#define rnull null_bs, false, false
#define data(...) data_flags(0, __VA_ARGS__)
#define data_flags(...) data_(__VA_ARGS__, rnull, rnull, rnull, rnull)
#define data_(...) data__(__VA_ARGS__)
#define data__(fl, b1, o1, v1, b2, o2, v2, b3, o3, v3, b4, o4, v4, ...) do { \
unsigned op = ctx->base.op; \
P(data)(ctx, \
v1 ? bs_get(b1, op) : null_op, \
v2 ? bs_get(b2, op) : null_op, \
v3 ? bs_get(b3, op) : null_op, \
v4 ? bs_get(b4, op) : null_op, \
(o1 << 0) | \
(o2 << 1) | \
(o3 << 2) | \
(o4 << 3) | \
fl); \
if (DIS_MAY_MODIFY && ctx->base.modify) { \
uint32_t new = ctx->base.op; \
new = bs_set(b1, ctx->base.newval[0], new); \
new = bs_set(b2, ctx->base.newval[1], new); \
new = bs_set(b3, ctx->base.newval[2], new); \
new = bs_set(b4, ctx->base.newval[3], new); \
*(uint32_t *) ctx->base.newop = new; \
} \
return; \
} while (0)
#ifndef TARGET_DIS_SUPPORTED
#error "no disassembler for the target architecture yet"
#endif
static inline void op64(void **codep, uint64_t op) {
unaligned_w64(*codep, op);
*codep += 8;
}
static inline void op32(void **codep, uint32_t op) {
unaligned_w32(*codep, op);
*codep += 4;
}
static inline void op16(void **codep, uint16_t op) {
unaligned_w16(*codep, op);
*codep += 2;
}
static inline void op8(void **codep, uint8_t op) {
*(uint8_t *) *codep = op;
(*codep)++;
}
#define CC_CONDITIONAL 0x100
#define CC_CALL 0x200
struct dis_ctx_base {
uint_tptr pc;
const void *ptr;
#if defined(TARGET_x86_64) || defined(TARGET_i386)
uint8_t newop[32];
#else
uint8_t newop[4];
uint32_t op;
#endif
uint32_t newval[4];
bool modify;
int op_size, newop_size;
};
#include stringify(TARGET_DIR/arch-dis.h)
|