/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- x86AssemblyInspectionEngine.cpp -----------------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "x86AssemblyInspectionEngine.h" |
10 | | |
11 | | #include <memory> |
12 | | |
13 | | #include "llvm-c/Disassembler.h" |
14 | | |
15 | | #include "lldb/Core/Address.h" |
16 | | #include "lldb/Symbol/UnwindPlan.h" |
17 | | #include "lldb/Target/RegisterContext.h" |
18 | | #include "lldb/Target/UnwindAssembly.h" |
19 | | |
20 | | using namespace lldb_private; |
21 | | using namespace lldb; |
22 | | |
23 | | x86AssemblyInspectionEngine::x86AssemblyInspectionEngine(const ArchSpec &arch) |
24 | | : m_cur_insn(nullptr), m_machine_ip_regnum(LLDB_INVALID_REGNUM), |
25 | | m_machine_sp_regnum(LLDB_INVALID_REGNUM), |
26 | | m_machine_fp_regnum(LLDB_INVALID_REGNUM), |
27 | | m_machine_alt_fp_regnum(LLDB_INVALID_REGNUM), |
28 | | m_lldb_ip_regnum(LLDB_INVALID_REGNUM), |
29 | | m_lldb_sp_regnum(LLDB_INVALID_REGNUM), |
30 | | m_lldb_fp_regnum(LLDB_INVALID_REGNUM), |
31 | | m_lldb_alt_fp_regnum(LLDB_INVALID_REGNUM), m_reg_map(), m_arch(arch), |
32 | | m_cpu(k_cpu_unspecified), m_wordsize(-1), |
33 | 15.2k | m_register_map_initialized(false), m_disasm_context() { |
34 | 15.2k | m_disasm_context = |
35 | 15.2k | ::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), nullptr, |
36 | 15.2k | /*TagType=*/1, nullptr, nullptr); |
37 | 15.2k | } |
38 | | |
39 | 15.2k | x86AssemblyInspectionEngine::~x86AssemblyInspectionEngine() { |
40 | 15.2k | ::LLVMDisasmDispose(m_disasm_context); |
41 | 15.2k | } |
42 | | |
43 | 7.92k | void x86AssemblyInspectionEngine::Initialize(RegisterContextSP ®_ctx) { |
44 | 7.92k | m_cpu = k_cpu_unspecified; |
45 | 7.92k | m_wordsize = -1; |
46 | 7.92k | m_register_map_initialized = false; |
47 | | |
48 | 7.92k | const llvm::Triple::ArchType cpu = m_arch.GetMachine(); |
49 | 7.92k | if (cpu == llvm::Triple::x86) |
50 | 3 | m_cpu = k_i386; |
51 | 7.92k | else if (cpu == llvm::Triple::x86_64) |
52 | 7.92k | m_cpu = k_x86_64; |
53 | | |
54 | 7.92k | if (m_cpu == k_cpu_unspecified) |
55 | 0 | return; |
56 | | |
57 | 7.92k | if (reg_ctx.get() == nullptr) |
58 | 0 | return; |
59 | | |
60 | 7.92k | if (m_cpu == k_i386) { |
61 | 3 | m_machine_ip_regnum = k_machine_eip; |
62 | 3 | m_machine_sp_regnum = k_machine_esp; |
63 | 3 | m_machine_fp_regnum = k_machine_ebp; |
64 | 3 | m_machine_alt_fp_regnum = k_machine_ebx; |
65 | 3 | m_wordsize = 4; |
66 | | |
67 | 3 | struct lldb_reg_info reginfo; |
68 | 3 | reginfo.name = "eax"; |
69 | 3 | m_reg_map[k_machine_eax] = reginfo; |
70 | 3 | reginfo.name = "edx"; |
71 | 3 | m_reg_map[k_machine_edx] = reginfo; |
72 | 3 | reginfo.name = "esp"; |
73 | 3 | m_reg_map[k_machine_esp] = reginfo; |
74 | 3 | reginfo.name = "esi"; |
75 | 3 | m_reg_map[k_machine_esi] = reginfo; |
76 | 3 | reginfo.name = "eip"; |
77 | 3 | m_reg_map[k_machine_eip] = reginfo; |
78 | 3 | reginfo.name = "ecx"; |
79 | 3 | m_reg_map[k_machine_ecx] = reginfo; |
80 | 3 | reginfo.name = "ebx"; |
81 | 3 | m_reg_map[k_machine_ebx] = reginfo; |
82 | 3 | reginfo.name = "ebp"; |
83 | 3 | m_reg_map[k_machine_ebp] = reginfo; |
84 | 3 | reginfo.name = "edi"; |
85 | 3 | m_reg_map[k_machine_edi] = reginfo; |
86 | 7.92k | } else { |
87 | 7.92k | m_machine_ip_regnum = k_machine_rip; |
88 | 7.92k | m_machine_sp_regnum = k_machine_rsp; |
89 | 7.92k | m_machine_fp_regnum = k_machine_rbp; |
90 | 7.92k | m_machine_alt_fp_regnum = k_machine_rbx; |
91 | 7.92k | m_wordsize = 8; |
92 | | |
93 | 7.92k | struct lldb_reg_info reginfo; |
94 | 7.92k | reginfo.name = "rax"; |
95 | 7.92k | m_reg_map[k_machine_rax] = reginfo; |
96 | 7.92k | reginfo.name = "rdx"; |
97 | 7.92k | m_reg_map[k_machine_rdx] = reginfo; |
98 | 7.92k | reginfo.name = "rsp"; |
99 | 7.92k | m_reg_map[k_machine_rsp] = reginfo; |
100 | 7.92k | reginfo.name = "rsi"; |
101 | 7.92k | m_reg_map[k_machine_rsi] = reginfo; |
102 | 7.92k | reginfo.name = "r8"; |
103 | 7.92k | m_reg_map[k_machine_r8] = reginfo; |
104 | 7.92k | reginfo.name = "r10"; |
105 | 7.92k | m_reg_map[k_machine_r10] = reginfo; |
106 | 7.92k | reginfo.name = "r12"; |
107 | 7.92k | m_reg_map[k_machine_r12] = reginfo; |
108 | 7.92k | reginfo.name = "r14"; |
109 | 7.92k | m_reg_map[k_machine_r14] = reginfo; |
110 | 7.92k | reginfo.name = "rip"; |
111 | 7.92k | m_reg_map[k_machine_rip] = reginfo; |
112 | 7.92k | reginfo.name = "rcx"; |
113 | 7.92k | m_reg_map[k_machine_rcx] = reginfo; |
114 | 7.92k | reginfo.name = "rbx"; |
115 | 7.92k | m_reg_map[k_machine_rbx] = reginfo; |
116 | 7.92k | reginfo.name = "rbp"; |
117 | 7.92k | m_reg_map[k_machine_rbp] = reginfo; |
118 | 7.92k | reginfo.name = "rdi"; |
119 | 7.92k | m_reg_map[k_machine_rdi] = reginfo; |
120 | 7.92k | reginfo.name = "r9"; |
121 | 7.92k | m_reg_map[k_machine_r9] = reginfo; |
122 | 7.92k | reginfo.name = "r11"; |
123 | 7.92k | m_reg_map[k_machine_r11] = reginfo; |
124 | 7.92k | reginfo.name = "r13"; |
125 | 7.92k | m_reg_map[k_machine_r13] = reginfo; |
126 | 7.92k | reginfo.name = "r15"; |
127 | 7.92k | m_reg_map[k_machine_r15] = reginfo; |
128 | 7.92k | } |
129 | | |
130 | 7.92k | for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin(); |
131 | 142k | it != m_reg_map.end(); ++it134k ) { |
132 | 134k | const RegisterInfo *ri = reg_ctx->GetRegisterInfoByName(it->second.name); |
133 | 134k | if (ri) |
134 | 134k | it->second.lldb_regnum = ri->kinds[eRegisterKindLLDB]; |
135 | 134k | } |
136 | | |
137 | 7.92k | uint32_t lldb_regno; |
138 | 7.92k | if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno)) |
139 | 7.92k | m_lldb_sp_regnum = lldb_regno; |
140 | 7.92k | if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno)) |
141 | 7.92k | m_lldb_fp_regnum = lldb_regno; |
142 | 7.92k | if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno)) |
143 | 7.92k | m_lldb_alt_fp_regnum = lldb_regno; |
144 | 7.92k | if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno)) |
145 | 7.92k | m_lldb_ip_regnum = lldb_regno; |
146 | | |
147 | 7.92k | m_register_map_initialized = true; |
148 | 7.92k | } |
149 | | |
150 | | void x86AssemblyInspectionEngine::Initialize( |
151 | 62 | std::vector<lldb_reg_info> ®_info) { |
152 | 62 | m_cpu = k_cpu_unspecified; |
153 | 62 | m_wordsize = -1; |
154 | 62 | m_register_map_initialized = false; |
155 | | |
156 | 62 | const llvm::Triple::ArchType cpu = m_arch.GetMachine(); |
157 | 62 | if (cpu == llvm::Triple::x86) |
158 | 30 | m_cpu = k_i386; |
159 | 32 | else if (cpu == llvm::Triple::x86_64) |
160 | 32 | m_cpu = k_x86_64; |
161 | | |
162 | 62 | if (m_cpu == k_cpu_unspecified) |
163 | 0 | return; |
164 | | |
165 | 62 | if (m_cpu == k_i386) { |
166 | 30 | m_machine_ip_regnum = k_machine_eip; |
167 | 30 | m_machine_sp_regnum = k_machine_esp; |
168 | 30 | m_machine_fp_regnum = k_machine_ebp; |
169 | 30 | m_machine_alt_fp_regnum = k_machine_ebx; |
170 | 30 | m_wordsize = 4; |
171 | | |
172 | 30 | struct lldb_reg_info reginfo; |
173 | 30 | reginfo.name = "eax"; |
174 | 30 | m_reg_map[k_machine_eax] = reginfo; |
175 | 30 | reginfo.name = "edx"; |
176 | 30 | m_reg_map[k_machine_edx] = reginfo; |
177 | 30 | reginfo.name = "esp"; |
178 | 30 | m_reg_map[k_machine_esp] = reginfo; |
179 | 30 | reginfo.name = "esi"; |
180 | 30 | m_reg_map[k_machine_esi] = reginfo; |
181 | 30 | reginfo.name = "eip"; |
182 | 30 | m_reg_map[k_machine_eip] = reginfo; |
183 | 30 | reginfo.name = "ecx"; |
184 | 30 | m_reg_map[k_machine_ecx] = reginfo; |
185 | 30 | reginfo.name = "ebx"; |
186 | 30 | m_reg_map[k_machine_ebx] = reginfo; |
187 | 30 | reginfo.name = "ebp"; |
188 | 30 | m_reg_map[k_machine_ebp] = reginfo; |
189 | 30 | reginfo.name = "edi"; |
190 | 30 | m_reg_map[k_machine_edi] = reginfo; |
191 | 32 | } else { |
192 | 32 | m_machine_ip_regnum = k_machine_rip; |
193 | 32 | m_machine_sp_regnum = k_machine_rsp; |
194 | 32 | m_machine_fp_regnum = k_machine_rbp; |
195 | 32 | m_machine_alt_fp_regnum = k_machine_rbx; |
196 | 32 | m_wordsize = 8; |
197 | | |
198 | 32 | struct lldb_reg_info reginfo; |
199 | 32 | reginfo.name = "rax"; |
200 | 32 | m_reg_map[k_machine_rax] = reginfo; |
201 | 32 | reginfo.name = "rdx"; |
202 | 32 | m_reg_map[k_machine_rdx] = reginfo; |
203 | 32 | reginfo.name = "rsp"; |
204 | 32 | m_reg_map[k_machine_rsp] = reginfo; |
205 | 32 | reginfo.name = "rsi"; |
206 | 32 | m_reg_map[k_machine_rsi] = reginfo; |
207 | 32 | reginfo.name = "r8"; |
208 | 32 | m_reg_map[k_machine_r8] = reginfo; |
209 | 32 | reginfo.name = "r10"; |
210 | 32 | m_reg_map[k_machine_r10] = reginfo; |
211 | 32 | reginfo.name = "r12"; |
212 | 32 | m_reg_map[k_machine_r12] = reginfo; |
213 | 32 | reginfo.name = "r14"; |
214 | 32 | m_reg_map[k_machine_r14] = reginfo; |
215 | 32 | reginfo.name = "rip"; |
216 | 32 | m_reg_map[k_machine_rip] = reginfo; |
217 | 32 | reginfo.name = "rcx"; |
218 | 32 | m_reg_map[k_machine_rcx] = reginfo; |
219 | 32 | reginfo.name = "rbx"; |
220 | 32 | m_reg_map[k_machine_rbx] = reginfo; |
221 | 32 | reginfo.name = "rbp"; |
222 | 32 | m_reg_map[k_machine_rbp] = reginfo; |
223 | 32 | reginfo.name = "rdi"; |
224 | 32 | m_reg_map[k_machine_rdi] = reginfo; |
225 | 32 | reginfo.name = "r9"; |
226 | 32 | m_reg_map[k_machine_r9] = reginfo; |
227 | 32 | reginfo.name = "r11"; |
228 | 32 | m_reg_map[k_machine_r11] = reginfo; |
229 | 32 | reginfo.name = "r13"; |
230 | 32 | m_reg_map[k_machine_r13] = reginfo; |
231 | 32 | reginfo.name = "r15"; |
232 | 32 | m_reg_map[k_machine_r15] = reginfo; |
233 | 32 | } |
234 | | |
235 | 62 | for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin(); |
236 | 876 | it != m_reg_map.end(); ++it814 ) { |
237 | 6.24k | for (size_t i = 0; i < reg_info.size(); ++i5.43k ) { |
238 | 6.24k | if (::strcmp(reg_info[i].name, it->second.name) == 0) { |
239 | 814 | it->second.lldb_regnum = reg_info[i].lldb_regnum; |
240 | 814 | break; |
241 | 814 | } |
242 | 6.24k | } |
243 | 814 | } |
244 | | |
245 | 62 | uint32_t lldb_regno; |
246 | 62 | if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno)) |
247 | 62 | m_lldb_sp_regnum = lldb_regno; |
248 | 62 | if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno)) |
249 | 62 | m_lldb_fp_regnum = lldb_regno; |
250 | 62 | if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno)) |
251 | 62 | m_lldb_alt_fp_regnum = lldb_regno; |
252 | 62 | if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno)) |
253 | 62 | m_lldb_ip_regnum = lldb_regno; |
254 | | |
255 | 62 | m_register_map_initialized = true; |
256 | 62 | } |
257 | | |
258 | | // This function expects an x86 native register number (i.e. the bits stripped |
259 | | // out of the actual instruction), not an lldb register number. |
260 | | // |
261 | | // FIXME: This is ABI dependent, it shouldn't be hardcoded here. |
262 | | |
263 | 52.3k | bool x86AssemblyInspectionEngine::nonvolatile_reg_p(int machine_regno) { |
264 | 52.3k | if (m_cpu == k_i386) { |
265 | 51 | switch (machine_regno) { |
266 | 10 | case k_machine_ebx: |
267 | 33 | case k_machine_ebp: // not actually a nonvolatile but often treated as such |
268 | | // by convention |
269 | 39 | case k_machine_esi: |
270 | 45 | case k_machine_edi: |
271 | 45 | case k_machine_esp: |
272 | 45 | return true; |
273 | 6 | default: |
274 | 6 | return false; |
275 | 51 | } |
276 | 51 | } |
277 | 52.3k | if (m_cpu == k_x86_64) { |
278 | 52.3k | switch (machine_regno) { |
279 | 3.56k | case k_machine_rbx: |
280 | 3.56k | case k_machine_rsp: |
281 | 11.9k | case k_machine_rbp: // not actually a nonvolatile but often treated as such |
282 | | // by convention |
283 | 15.4k | case k_machine_r12: |
284 | 15.5k | case k_machine_r13: |
285 | 19.0k | case k_machine_r14: |
286 | 22.4k | case k_machine_r15: |
287 | 22.4k | return true; |
288 | 29.8k | default: |
289 | 29.8k | return false; |
290 | 52.3k | } |
291 | 52.3k | } |
292 | 0 | return false; |
293 | 52.3k | } |
294 | | |
295 | | // Macro to detect if this is a REX mode prefix byte. |
296 | 379k | #define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48) |
297 | | |
298 | | // The high bit which should be added to the source register number (the "R" |
299 | | // bit) |
300 | 195k | #define REX_W_SRCREG(opcode) (((opcode)&0x4) >> 2) |
301 | | |
302 | | // The high bit which should be added to the destination register number (the |
303 | | // "B" bit) |
304 | 195k | #define REX_W_DSTREG(opcode) ((opcode)&0x1) |
305 | | |
306 | | // pushq %rbp [0x55] |
307 | 0 | bool x86AssemblyInspectionEngine::push_rbp_pattern_p() { |
308 | 0 | uint8_t *p = m_cur_insn; |
309 | 0 | return *p == 0x55; |
310 | 0 | } |
311 | | |
312 | | // pushq $0 ; the first instruction in start() [0x6a 0x00] |
313 | 407k | bool x86AssemblyInspectionEngine::push_0_pattern_p() { |
314 | 407k | uint8_t *p = m_cur_insn; |
315 | 407k | return *p == 0x6a && *(p + 1) == 0x01.81k ; |
316 | 407k | } |
317 | | |
318 | | // pushq $0 |
319 | | // pushl $0 |
320 | 369k | bool x86AssemblyInspectionEngine::push_imm_pattern_p() { |
321 | 369k | uint8_t *p = m_cur_insn; |
322 | 369k | return *p == 0x68 || *p == 0x6a369k ; |
323 | 369k | } |
324 | | |
325 | | // pushl imm8(%esp) |
326 | | // |
327 | | // e.g. 0xff 0x74 0x24 0x20 - 'pushl 0x20(%esp)' (same byte pattern for 'pushq |
328 | | // 0x20(%rsp)' in an x86_64 program) |
329 | | // |
330 | | // 0xff (with opcode bits '6' in next byte, PUSH r/m32) 0x74 (ModR/M byte with |
331 | | // three bits used to specify the opcode) |
332 | | // mod == b01, opcode == b110, R/M == b100 |
333 | | // "+disp8" |
334 | | // 0x24 (SIB byte - scaled index = 0, r32 == esp) 0x20 imm8 value |
335 | | |
336 | 369k | bool x86AssemblyInspectionEngine::push_extended_pattern_p() { |
337 | 369k | if (*m_cur_insn == 0xff) { |
338 | | // Get the 3 opcode bits from the ModR/M byte |
339 | 12.8k | uint8_t opcode = (*(m_cur_insn + 1) >> 3) & 7; |
340 | 12.8k | if (opcode == 6) { |
341 | | // I'm only looking for 0xff /6 here - I |
342 | | // don't really care what value is being pushed, just that we're pushing |
343 | | // a 32/64 bit value on to the stack is enough. |
344 | 7 | return true; |
345 | 7 | } |
346 | 12.8k | } |
347 | 369k | return false; |
348 | 369k | } |
349 | | |
350 | | // instructions only valid in 32-bit mode: |
351 | | // 0x0e - push cs |
352 | | // 0x16 - push ss |
353 | | // 0x1e - push ds |
354 | | // 0x06 - push es |
355 | 369k | bool x86AssemblyInspectionEngine::push_misc_reg_p() { |
356 | 369k | uint8_t p = *m_cur_insn; |
357 | 369k | if (m_wordsize == 4) { |
358 | 80 | if (p == 0x0e || p == 0x1679 || p == 0x1e78 || p == 0x0677 ) |
359 | 4 | return true; |
360 | 80 | } |
361 | 369k | return false; |
362 | 369k | } |
363 | | |
364 | | // pushq %rbx |
365 | | // pushl %ebx |
366 | 405k | bool x86AssemblyInspectionEngine::push_reg_p(int ®no) { |
367 | 405k | uint8_t *p = m_cur_insn; |
368 | 405k | int regno_prefix_bit = 0; |
369 | | // If we have a rex prefix byte, check to see if a B bit is set |
370 | 405k | if (m_wordsize == 8 && (*p & 0xfe) == 0x40405k ) { |
371 | 18.1k | regno_prefix_bit = (*p & 1) << 3; |
372 | 18.1k | p++; |
373 | 18.1k | } |
374 | 405k | if (*p >= 0x50 && *p <= 0x57180k ) { |
375 | 13.0k | regno = (*p - 0x50) | regno_prefix_bit; |
376 | 13.0k | return true; |
377 | 13.0k | } |
378 | 392k | return false; |
379 | 405k | } |
380 | | |
381 | | // movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5] movl %esp, %ebp [0x8b |
382 | | // 0xec] or [0x89 0xe5] |
383 | 416k | bool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() { |
384 | 416k | uint8_t *p = m_cur_insn; |
385 | 416k | if (m_wordsize == 8 && *p == 0x48416k ) |
386 | 170k | p++; |
387 | 416k | if (*(p) == 0x8b && *(p + 1) == 0xec62.4k ) |
388 | 3 | return true; |
389 | 416k | if (*(p) == 0x89 && *(p + 1) == 0xe557.9k ) |
390 | 5.99k | return true; |
391 | 410k | return false; |
392 | 416k | } |
393 | | |
394 | | // movq %rsp, %rbx [0x48 0x8b 0xdc] or [0x48 0x89 0xe3] |
395 | | // movl %esp, %ebx [0x8b 0xdc] or [0x89 0xe3] |
396 | 410k | bool x86AssemblyInspectionEngine::mov_rsp_rbx_pattern_p() { |
397 | 410k | uint8_t *p = m_cur_insn; |
398 | 410k | if (m_wordsize == 8 && *p == 0x48410k ) |
399 | 164k | p++; |
400 | 410k | if (*(p) == 0x8b && *(p + 1) == 0xdc62.3k ) |
401 | 1 | return true; |
402 | 410k | if (*(p) == 0x89 && *(p + 1) == 0xe351.9k ) |
403 | 0 | return true; |
404 | 410k | return false; |
405 | 410k | } |
406 | | |
407 | | // movq %rbp, %rsp [0x48 0x8b 0xe5] or [0x48 0x89 0xec] |
408 | | // movl %ebp, %esp [0x8b 0xe5] or [0x89 0xec] |
409 | 409k | bool x86AssemblyInspectionEngine::mov_rbp_rsp_pattern_p() { |
410 | 409k | uint8_t *p = m_cur_insn; |
411 | 409k | if (m_wordsize == 8 && *p == 0x48408k ) |
412 | 162k | p++; |
413 | 409k | if (*(p) == 0x8b && *(p + 1) == 0xe562.3k ) |
414 | 1 | return true; |
415 | 409k | if (*(p) == 0x89 && *(p + 1) == 0xec51.9k ) |
416 | 1.73k | return true; |
417 | 407k | return false; |
418 | 409k | } |
419 | | |
420 | | // movq %rbx, %rsp [0x48 0x8b 0xe3] or [0x48 0x89 0xdc] |
421 | | // movl %ebx, %esp [0x8b 0xe3] or [0x89 0xdc] |
422 | 407k | bool x86AssemblyInspectionEngine::mov_rbx_rsp_pattern_p() { |
423 | 407k | uint8_t *p = m_cur_insn; |
424 | 407k | if (m_wordsize == 8 && *p == 0x48407k ) |
425 | 160k | p++; |
426 | 407k | if (*(p) == 0x8b && *(p + 1) == 0xe362.3k ) |
427 | 1 | return true; |
428 | 407k | if (*(p) == 0x89 && *(p + 1) == 0xdc50.2k ) |
429 | 0 | return true; |
430 | 407k | return false; |
431 | 407k | } |
432 | | |
433 | | // subq $0x20, %rsp |
434 | 379k | bool x86AssemblyInspectionEngine::sub_rsp_pattern_p(int &amount) { |
435 | 379k | uint8_t *p = m_cur_insn; |
436 | 379k | if (m_wordsize == 8 && *p == 0x48379k ) |
437 | 160k | p++; |
438 | | // 8-bit immediate operand |
439 | 379k | if (*p == 0x83 && *(p + 1) == 0xec16.5k ) { |
440 | 3.13k | amount = (int8_t) * (p + 2); |
441 | 3.13k | return true; |
442 | 3.13k | } |
443 | | // 32-bit immediate operand |
444 | 376k | if (*p == 0x81 && *(p + 1) == 0xec2.48k ) { |
445 | 2.06k | amount = (int32_t)extract_4(p + 2); |
446 | 2.06k | return true; |
447 | 2.06k | } |
448 | 374k | return false; |
449 | 376k | } |
450 | | |
451 | | // addq $0x20, %rsp |
452 | 374k | bool x86AssemblyInspectionEngine::add_rsp_pattern_p(int &amount) { |
453 | 374k | uint8_t *p = m_cur_insn; |
454 | 374k | if (m_wordsize == 8 && *p == 0x48374k ) |
455 | 155k | p++; |
456 | | // 8-bit immediate operand |
457 | 374k | if (*p == 0x83 && *(p + 1) == 0xc413.3k ) { |
458 | 4.78k | amount = (int8_t) * (p + 2); |
459 | 4.78k | return true; |
460 | 4.78k | } |
461 | | // 32-bit immediate operand |
462 | 369k | if (*p == 0x81 && *(p + 1) == 0xc4418 ) { |
463 | 328 | amount = (int32_t)extract_4(p + 2); |
464 | 328 | return true; |
465 | 328 | } |
466 | 369k | return false; |
467 | 369k | } |
468 | | |
469 | | // lea esp, [esp - 0x28] |
470 | | // lea esp, [esp + 0x28] |
471 | 369k | bool x86AssemblyInspectionEngine::lea_rsp_pattern_p(int &amount) { |
472 | 369k | uint8_t *p = m_cur_insn; |
473 | 369k | if (m_wordsize == 8 && *p == 0x48369k ) |
474 | 150k | p++; |
475 | | |
476 | | // Check opcode |
477 | 369k | if (*p != 0x8d) |
478 | 335k | return false; |
479 | | |
480 | | // 8 bit displacement |
481 | 33.9k | if (*(p + 1) == 0x64 && (*(p + 2) & 0x3f) == 0x240 ) { |
482 | 0 | amount = (int8_t) * (p + 3); |
483 | 0 | return true; |
484 | 0 | } |
485 | | |
486 | | // 32 bit displacement |
487 | 33.9k | if (*(p + 1) == 0xa4 && (*(p + 2) & 0x3f) == 0x240 ) { |
488 | 0 | amount = (int32_t)extract_4(p + 3); |
489 | 0 | return true; |
490 | 0 | } |
491 | | |
492 | 33.9k | return false; |
493 | 33.9k | } |
494 | | |
495 | | // lea -0x28(%ebp), %esp |
496 | | // (32-bit and 64-bit variants, 8-bit and 32-bit displacement) |
497 | 369k | bool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) { |
498 | 369k | uint8_t *p = m_cur_insn; |
499 | 369k | if (m_wordsize == 8 && *p == 0x48369k ) |
500 | 150k | p++; |
501 | | |
502 | | // Check opcode |
503 | 369k | if (*p != 0x8d) |
504 | 335k | return false; |
505 | 33.9k | ++p; |
506 | | |
507 | | // 8 bit displacement |
508 | 33.9k | if (*p == 0x65) { |
509 | 1.72k | amount = (int8_t)p[1]; |
510 | 1.72k | return true; |
511 | 1.72k | } |
512 | | |
513 | | // 32 bit displacement |
514 | 32.2k | if (*p == 0xa5) { |
515 | 0 | amount = (int32_t)extract_4(p + 1); |
516 | 0 | return true; |
517 | 0 | } |
518 | | |
519 | 32.2k | return false; |
520 | 32.2k | } |
521 | | |
522 | | // lea -0x28(%ebx), %esp |
523 | | // (32-bit and 64-bit variants, 8-bit and 32-bit displacement) |
524 | 367k | bool x86AssemblyInspectionEngine::lea_rbx_rsp_pattern_p(int &amount) { |
525 | 367k | uint8_t *p = m_cur_insn; |
526 | 367k | if (m_wordsize == 8 && *p == 0x48367k ) |
527 | 148k | p++; |
528 | | |
529 | | // Check opcode |
530 | 367k | if (*p != 0x8d) |
531 | 335k | return false; |
532 | 32.2k | ++p; |
533 | | |
534 | | // 8 bit displacement |
535 | 32.2k | if (*p == 0x63) { |
536 | 0 | amount = (int8_t)p[1]; |
537 | 0 | return true; |
538 | 0 | } |
539 | | |
540 | | // 32 bit displacement |
541 | 32.2k | if (*p == 0xa3) { |
542 | 0 | amount = (int32_t)extract_4(p + 1); |
543 | 0 | return true; |
544 | 0 | } |
545 | | |
546 | 32.2k | return false; |
547 | 32.2k | } |
548 | | |
549 | | // and -0xfffffff0, %esp |
550 | | // (32-bit and 64-bit variants, 8-bit and 32-bit displacement) |
551 | 410k | bool x86AssemblyInspectionEngine::and_rsp_pattern_p() { |
552 | 410k | uint8_t *p = m_cur_insn; |
553 | 410k | if (m_wordsize == 8 && *p == 0x48410k ) |
554 | 164k | p++; |
555 | | |
556 | 410k | if (*p != 0x81 && *p != 0x83408k ) |
557 | 390k | return false; |
558 | | |
559 | 20.7k | return *++p == 0xe4; |
560 | 410k | } |
561 | | |
562 | | // popq %rbx |
563 | | // popl %ebx |
564 | 392k | bool x86AssemblyInspectionEngine::pop_reg_p(int ®no) { |
565 | 392k | uint8_t *p = m_cur_insn; |
566 | 392k | int regno_prefix_bit = 0; |
567 | | // If we have a rex prefix byte, check to see if a B bit is set |
568 | 392k | if (m_wordsize == 8 && (*p & 0xfe) == 0x40392k ) { |
569 | 12.8k | regno_prefix_bit = (*p & 1) << 3; |
570 | 12.8k | p++; |
571 | 12.8k | } |
572 | 392k | if (*p >= 0x58 && *p <= 0x5f167k ) { |
573 | 12.8k | regno = (*p - 0x58) | regno_prefix_bit; |
574 | 12.8k | return true; |
575 | 12.8k | } |
576 | 379k | return false; |
577 | 392k | } |
578 | | |
579 | | // popq %rbp [0x5d] |
580 | | // popl %ebp [0x5d] |
581 | 60 | bool x86AssemblyInspectionEngine::pop_rbp_pattern_p() { |
582 | 60 | uint8_t *p = m_cur_insn; |
583 | 60 | return (*p == 0x5d); |
584 | 60 | } |
585 | | |
586 | | // instructions valid only in 32-bit mode: |
587 | | // 0x1f - pop ds |
588 | | // 0x07 - pop es |
589 | | // 0x17 - pop ss |
590 | 379k | bool x86AssemblyInspectionEngine::pop_misc_reg_p() { |
591 | 379k | uint8_t p = *m_cur_insn; |
592 | 379k | if (m_wordsize == 4) { |
593 | 115 | if (p == 0x1f || p == 0x07114 || p == 0x17113 ) |
594 | 3 | return true; |
595 | 115 | } |
596 | 379k | return false; |
597 | 379k | } |
598 | | |
599 | | // leave [0xc9] |
600 | 379k | bool x86AssemblyInspectionEngine::leave_pattern_p() { |
601 | 379k | uint8_t *p = m_cur_insn; |
602 | 379k | return (*p == 0xc9); |
603 | 379k | } |
604 | | |
605 | | // call $0 [0xe8 0x0 0x0 0x0 0x0] |
606 | 354k | bool x86AssemblyInspectionEngine::call_next_insn_pattern_p() { |
607 | 354k | uint8_t *p = m_cur_insn; |
608 | 354k | return (*p == 0xe8) && (*(p + 1) == 0x0)31.3k && (*(p + 2) == 0x0)91 && |
609 | 354k | (*(p + 3) == 0x0)24 && (*(p + 4) == 0x0)24 ; |
610 | 354k | } |
611 | | |
612 | | // Look for an instruction sequence storing a nonvolatile register on to the |
613 | | // stack frame. |
614 | | |
615 | | // movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0] |
616 | | // movl %eax, -0xc(%ebp) [0x89 0x45 0xf4] |
617 | | |
618 | | // The offset value returned in rbp_offset will be positive -- but it must be |
619 | | // subtraced from the frame base register to get the actual location. The |
620 | | // positive value returned for the offset is a convention used elsewhere for |
621 | | // CFA offsets et al. |
622 | | |
623 | | bool x86AssemblyInspectionEngine::mov_reg_to_local_stack_frame_p( |
624 | 379k | int ®no, int &rbp_offset) { |
625 | 379k | uint8_t *p = m_cur_insn; |
626 | 379k | int src_reg_prefix_bit = 0; |
627 | 379k | int target_reg_prefix_bit = 0; |
628 | | |
629 | 379k | if (m_wordsize == 8 && REX_W_PREFIX_P379k (*p)) { |
630 | 195k | src_reg_prefix_bit = REX_W_SRCREG(*p) << 3; |
631 | 195k | target_reg_prefix_bit = REX_W_DSTREG(*p) << 3; |
632 | 195k | if (target_reg_prefix_bit == 1) { |
633 | | // rbp/ebp don't need a prefix bit - we know this isn't the reg we care |
634 | | // about. |
635 | 0 | return false; |
636 | 0 | } |
637 | 195k | p++; |
638 | 195k | } |
639 | | |
640 | 379k | if (*p == 0x89) { |
641 | | /* Mask off the 3-5 bits which indicate the destination register |
642 | | if this is a ModR/M byte. */ |
643 | 76.8k | int opcode_destreg_masked_out = *(p + 1) & (~0x38); |
644 | | |
645 | | /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101 |
646 | | and three bits between them, e.g. 01nnn101 |
647 | | We're looking for a destination of ebp-disp8 or ebp-disp32. */ |
648 | 76.8k | int immsize; |
649 | 76.8k | if (opcode_destreg_masked_out == 0x45) |
650 | 9.51k | immsize = 2; |
651 | 67.2k | else if (opcode_destreg_masked_out == 0x85) |
652 | 16.9k | immsize = 4; |
653 | 50.3k | else |
654 | 50.3k | return false; |
655 | | |
656 | 26.4k | int offset = 0; |
657 | 26.4k | if (immsize == 2) |
658 | 9.51k | offset = (int8_t) * (p + 2); |
659 | 26.4k | if (immsize == 4) |
660 | 16.9k | offset = (uint32_t)extract_4(p + 2); |
661 | 26.4k | if (offset > 0) |
662 | 0 | return false; |
663 | | |
664 | 26.4k | regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit; |
665 | 26.4k | rbp_offset = offset > 0 ? offset0 : -offset; |
666 | 26.4k | return true; |
667 | 26.4k | } |
668 | 302k | return false; |
669 | 379k | } |
670 | | |
671 | | // Returns true if this is a jmp instruction where we can't |
672 | | // know the destination address statically. |
673 | | // |
674 | | // ff e0 jmpq *%rax |
675 | | // ff e1 jmpq *%rcx |
676 | | // ff 60 28 jmpq *0x28(%rax) |
677 | | // ff 60 60 jmpq *0x60(%rax) |
678 | 323k | bool x86AssemblyInspectionEngine::jmp_to_reg_p() { |
679 | 323k | if (*m_cur_insn != 0xff) |
680 | 310k | return false; |
681 | | |
682 | | // The second byte is a ModR/M /4 byte, strip off the registers |
683 | 12.8k | uint8_t second_byte_sans_reg = *(m_cur_insn + 1) & ~7; |
684 | | |
685 | | // [reg] |
686 | 12.8k | if (second_byte_sans_reg == 0x20) |
687 | 3 | return true; |
688 | | |
689 | | // [reg]+disp8 |
690 | 12.8k | if (second_byte_sans_reg == 0x60) |
691 | 0 | return true; |
692 | | |
693 | | // [reg]+disp32 |
694 | 12.8k | if (second_byte_sans_reg == 0xa0) |
695 | 0 | return true; |
696 | | |
697 | | // reg |
698 | 12.8k | if (second_byte_sans_reg == 0xe0) |
699 | 3.45k | return true; |
700 | | |
701 | 9.40k | return false; |
702 | 12.8k | } |
703 | | |
704 | | // Detect branches to fixed pc-relative offsets. |
705 | | // Returns the offset from the address of the next instruction |
706 | | // that may be branch/jumped to. |
707 | | // |
708 | | // Cannot determine the offset of a JMP that jumps to the address in |
709 | | // a register ("jmpq *%rax") or offset from a register value |
710 | | // ("jmpq *0x28(%rax)"), this method will return false on those |
711 | | // instructions. |
712 | | // |
713 | | // These instructions all end in either a relative 8/16/32 bit value |
714 | | // depending on the instruction and the current execution mode of the |
715 | | // inferior process. Once we know the size of the opcode instruction, |
716 | | // we can use the total instruction length to determine the size of |
717 | | // the relative offset without having to compute it correctly. |
718 | | |
719 | | bool x86AssemblyInspectionEngine::pc_rel_branch_or_jump_p ( |
720 | | const int instruction_length, int &offset) |
721 | 347k | { |
722 | 347k | int opcode_size = 0; |
723 | | |
724 | 347k | uint8_t b1 = m_cur_insn[0]; |
725 | | |
726 | 347k | switch (b1) { |
727 | 52 | case 0x77: // JA/JNBE rel8 |
728 | 3.49k | case 0x73: // JAE/JNB/JNC rel8 |
729 | 3.52k | case 0x72: // JB/JC/JNAE rel8 |
730 | 3.52k | case 0x76: // JBE/JNA rel8 |
731 | 3.52k | case 0xe3: // JCXZ/JECXZ/JRCXZ rel8 |
732 | 7.12k | case 0x74: // JE/JZ rel8 |
733 | 7.13k | case 0x7f: // JG/JNLE rel8 |
734 | 7.13k | case 0x7d: // JGE/JNL rel8 |
735 | 7.13k | case 0x7c: // JL/JNGE rel8 |
736 | 7.13k | case 0x7e: // JNG/JLE rel8 |
737 | 7.13k | case 0x71: // JNO rel8 |
738 | 7.13k | case 0x7b: // JNP/JPO rel8 |
739 | 7.14k | case 0x79: // JNS rel8 |
740 | 21.0k | case 0x75: // JNE/JNZ rel8 |
741 | 21.0k | case 0x70: // JO rel8 |
742 | 21.0k | case 0x7a: // JP/JPE rel8 |
743 | 21.0k | case 0x78: // JS rel8 |
744 | 21.2k | case 0xeb: // JMP rel8 |
745 | 34.5k | case 0xe9: // JMP rel16/rel32 |
746 | 34.5k | opcode_size = 1; |
747 | 34.5k | break; |
748 | 313k | default: |
749 | 313k | break; |
750 | 347k | } |
751 | 347k | if (b1 == 0x0f && opcode_size == 09.00k ) { |
752 | 9.00k | uint8_t b2 = m_cur_insn[1]; |
753 | 9.00k | switch (b2) { |
754 | 12 | case 0x87: // JA/JNBE rel16/rel32 |
755 | 16 | case 0x86: // JBE/JNA rel16/rel32 |
756 | 1.00k | case 0x84: // JE/JZ rel16/rel32 |
757 | 1.02k | case 0x8f: // JG/JNLE rel16/rel32 |
758 | 1.27k | case 0x8d: // JNL/JGE rel16/rel32 |
759 | 1.50k | case 0x8e: // JLE rel16/rel32 |
760 | 1.58k | case 0x82: // JB/JC/JNAE rel16/rel32 |
761 | 1.61k | case 0x83: // JAE/JNB/JNC rel16/rel32 |
762 | 3.35k | case 0x85: // JNE/JNZ rel16/rel32 |
763 | 3.37k | case 0x8c: // JL/JNGE rel16/rel32 |
764 | 3.37k | case 0x81: // JNO rel16/rel32 |
765 | 3.37k | case 0x8b: // JNP/JPO rel16/rel32 |
766 | 3.37k | case 0x89: // JNS rel16/rel32 |
767 | 3.37k | case 0x80: // JO rel16/rel32 |
768 | 3.37k | case 0x8a: // JP rel16/rel32 |
769 | 3.37k | case 0x88: // JS rel16/rel32 |
770 | 3.37k | opcode_size = 2; |
771 | 3.37k | break; |
772 | 5.63k | default: |
773 | 5.63k | break; |
774 | 9.00k | } |
775 | 9.00k | } |
776 | | |
777 | 347k | if (opcode_size == 0) |
778 | 309k | return false; |
779 | | |
780 | 37.9k | offset = 0; |
781 | 37.9k | if (instruction_length - opcode_size == 1) { |
782 | 21.2k | int8_t rel8 = (int8_t) *(m_cur_insn + opcode_size); |
783 | 21.2k | offset = rel8; |
784 | 21.2k | } else if (16.7k instruction_length - opcode_size == 216.7k ) { |
785 | 0 | int16_t rel16 = extract_2_signed (m_cur_insn + opcode_size); |
786 | 0 | offset = rel16; |
787 | 16.7k | } else if (instruction_length - opcode_size == 4) { |
788 | 16.7k | int32_t rel32 = extract_4_signed (m_cur_insn + opcode_size); |
789 | 16.7k | offset = rel32; |
790 | 16.7k | } else { |
791 | 0 | return false; |
792 | 0 | } |
793 | 37.9k | return true; |
794 | 37.9k | } |
795 | | |
796 | | // Returns true if this instruction is a intra-function branch or jump - |
797 | | // a branch/jump within the bounds of this same function. |
798 | | // Cannot predict where a jump through a register value ("jmpq *%rax") |
799 | | // will go, so it will return false on that instruction. |
800 | | bool x86AssemblyInspectionEngine::local_branch_p ( |
801 | | const addr_t current_func_text_offset, |
802 | | const AddressRange &func_range, |
803 | | const int instruction_length, |
804 | 18.9k | addr_t &target_insn_offset) { |
805 | 18.9k | int offset; |
806 | 18.9k | if (pc_rel_branch_or_jump_p (instruction_length, offset) && offset != 0) { |
807 | 13.4k | addr_t next_pc_value = current_func_text_offset + instruction_length; |
808 | 13.4k | if (offset < 0 && addr_t(-offset) > current_func_text_offset3.94k ) { |
809 | | // Branch target is before the start of this function |
810 | 5 | return false; |
811 | 5 | } |
812 | 13.4k | if (offset + next_pc_value > func_range.GetByteSize()) { |
813 | | // Branch targets outside this function's bounds |
814 | 7 | return false; |
815 | 7 | } |
816 | | // This instruction branches to target_insn_offset (byte offset into the function) |
817 | 13.4k | target_insn_offset = next_pc_value + offset; |
818 | 13.4k | return true; |
819 | 13.4k | } |
820 | 5.53k | return false; |
821 | 18.9k | } |
822 | | |
823 | | // Returns true if this instruction is a inter-function branch or jump - a |
824 | | // branch/jump to another function. |
825 | | // Cannot predict where a jump through a register value ("jmpq *%rax") |
826 | | // will go, so it will return false on that instruction. |
827 | | bool x86AssemblyInspectionEngine::non_local_branch_p ( |
828 | | const addr_t current_func_text_offset, |
829 | | const AddressRange &func_range, |
830 | 328k | const int instruction_length) { |
831 | 328k | int offset; |
832 | 328k | addr_t target_insn_offset; |
833 | 328k | if (pc_rel_branch_or_jump_p (instruction_length, offset)) { |
834 | 18.9k | return !local_branch_p(current_func_text_offset,func_range,instruction_length,target_insn_offset); |
835 | 18.9k | } |
836 | 309k | return false; |
837 | 328k | } |
838 | | |
839 | | // ret [0xc3] or [0xcb] or [0xc2 imm16] or [0xca imm16] |
840 | 346k | bool x86AssemblyInspectionEngine::ret_pattern_p() { |
841 | 346k | uint8_t *p = m_cur_insn; |
842 | 346k | return *p == 0xc3 || *p == 0xc2337k || *p == 0xca337k || *p == 0xcb337k ; |
843 | 346k | } |
844 | | |
845 | 0 | uint16_t x86AssemblyInspectionEngine::extract_2(uint8_t *b) { |
846 | 0 | uint16_t v = 0; |
847 | 0 | for (int i = 1; i >= 0; i--) |
848 | 0 | v = (v << 8) | b[i]; |
849 | 0 | return v; |
850 | 0 | } |
851 | | |
852 | 0 | int16_t x86AssemblyInspectionEngine::extract_2_signed(uint8_t *b) { |
853 | 0 | int16_t v = 0; |
854 | 0 | for (int i = 1; i >= 0; i--) |
855 | 0 | v = (v << 8) | b[i]; |
856 | 0 | return v; |
857 | 0 | } |
858 | | |
859 | 19.2k | uint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) { |
860 | 19.2k | uint32_t v = 0; |
861 | 96.4k | for (int i = 3; i >= 0; i--77.1k ) |
862 | 77.1k | v = (v << 8) | b[i]; |
863 | 19.2k | return v; |
864 | 19.2k | } |
865 | | |
866 | 16.7k | int32_t x86AssemblyInspectionEngine::extract_4_signed(uint8_t *b) { |
867 | 16.7k | int32_t v = 0; |
868 | 83.6k | for (int i = 3; i >= 0; i--66.9k ) |
869 | 66.9k | v = (v << 8) | b[i]; |
870 | 16.7k | return v; |
871 | 16.7k | } |
872 | | |
873 | | |
874 | | bool x86AssemblyInspectionEngine::instruction_length(uint8_t *insn_p, |
875 | | int &length, |
876 | 416k | uint32_t buffer_remaining_bytes) { |
877 | | |
878 | 416k | uint32_t max_op_byte_size = std::min(buffer_remaining_bytes, m_arch.GetMaximumOpcodeByteSize()); |
879 | 416k | llvm::SmallVector<uint8_t, 32> opcode_data; |
880 | 416k | opcode_data.resize(max_op_byte_size); |
881 | | |
882 | 416k | char out_string[512]; |
883 | 416k | const size_t inst_size = |
884 | 416k | ::LLVMDisasmInstruction(m_disasm_context, insn_p, max_op_byte_size, 0, |
885 | 416k | out_string, sizeof(out_string)); |
886 | | |
887 | 416k | length = inst_size; |
888 | 416k | return true; |
889 | 416k | } |
890 | | |
891 | | bool x86AssemblyInspectionEngine::machine_regno_to_lldb_regno( |
892 | 54.4k | int machine_regno, uint32_t &lldb_regno) { |
893 | 54.4k | MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.find(machine_regno); |
894 | 54.4k | if (it != m_reg_map.end()) { |
895 | 54.4k | lldb_regno = it->second.lldb_regnum; |
896 | 54.4k | return true; |
897 | 54.4k | } |
898 | 0 | return false; |
899 | 54.4k | } |
900 | | |
901 | | bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( |
902 | | uint8_t *data, size_t size, AddressRange &func_range, |
903 | 7.98k | UnwindPlan &unwind_plan) { |
904 | 7.98k | unwind_plan.Clear(); |
905 | | |
906 | 7.98k | if (data == nullptr || size == 0) |
907 | 0 | return false; |
908 | | |
909 | 7.98k | if (!m_register_map_initialized) |
910 | 0 | return false; |
911 | | |
912 | 7.98k | addr_t current_func_text_offset = 0; |
913 | 7.98k | int current_sp_bytes_offset_from_fa = 0; |
914 | 7.98k | bool is_aligned = false; |
915 | 7.98k | UnwindPlan::Row::RegisterLocation initial_regloc; |
916 | 7.98k | UnwindPlan::RowSP row(new UnwindPlan::Row); |
917 | | |
918 | 7.98k | unwind_plan.SetPlanValidAddressRange(func_range); |
919 | 7.98k | unwind_plan.SetRegisterKind(eRegisterKindLLDB); |
920 | | |
921 | | // At the start of the function, find the CFA by adding wordsize to the SP |
922 | | // register |
923 | 7.98k | row->SetOffset(current_func_text_offset); |
924 | 7.98k | row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, m_wordsize); |
925 | | |
926 | | // caller's stack pointer value before the call insn is the CFA address |
927 | 7.98k | initial_regloc.SetIsCFAPlusOffset(0); |
928 | 7.98k | row->SetRegisterInfo(m_lldb_sp_regnum, initial_regloc); |
929 | | |
930 | | // saved instruction pointer can be found at CFA - wordsize. |
931 | 7.98k | current_sp_bytes_offset_from_fa = m_wordsize; |
932 | 7.98k | initial_regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa); |
933 | 7.98k | row->SetRegisterInfo(m_lldb_ip_regnum, initial_regloc); |
934 | | |
935 | 7.98k | unwind_plan.AppendRow(row); |
936 | | |
937 | | // Allocate a new Row, populate it with the existing Row contents. |
938 | 7.98k | UnwindPlan::Row *newrow = new UnwindPlan::Row; |
939 | 7.98k | *newrow = *row.get(); |
940 | 7.98k | row.reset(newrow); |
941 | | |
942 | | // Track which registers have been saved so far in the prologue. If we see |
943 | | // another push of that register, it's not part of the prologue. The register |
944 | | // numbers used here are the machine register #'s (i386_register_numbers, |
945 | | // x86_64_register_numbers). |
946 | 7.98k | std::vector<bool> saved_registers(32, false); |
947 | | |
948 | | // Once the prologue has completed we'll save a copy of the unwind |
949 | | // instructions If there is an epilogue in the middle of the function, after |
950 | | // that epilogue we'll reinstate the unwind setup -- we assume that some code |
951 | | // path jumps over the mid-function epilogue |
952 | | |
953 | 7.98k | UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI |
954 | 7.98k | int prologue_completed_sp_bytes_offset_from_cfa = 0; // The sp value before the |
955 | | // epilogue started executed |
956 | 7.98k | bool prologue_completed_is_aligned = false; |
957 | 7.98k | std::vector<bool> prologue_completed_saved_registers; |
958 | | |
959 | 424k | while (current_func_text_offset < size) { |
960 | 416k | int stack_offset, insn_len; |
961 | 416k | int machine_regno; // register numbers masked directly out of instructions |
962 | 416k | uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB |
963 | | // numbering scheme |
964 | | |
965 | 416k | bool in_epilogue = false; // we're in the middle of an epilogue sequence |
966 | 416k | bool row_updated = false; // The UnwindPlan::Row 'row' has been updated |
967 | | |
968 | 416k | m_cur_insn = data + current_func_text_offset; |
969 | 416k | if (!instruction_length(m_cur_insn, insn_len, size - current_func_text_offset) |
970 | 416k | || insn_len == 0 |
971 | 416k | || insn_len > kMaxInstructionByteSize416k ) { |
972 | | // An unrecognized/junk instruction |
973 | 55 | break; |
974 | 55 | } |
975 | | |
976 | 416k | auto &cfa_value = row->GetCFAValue(); |
977 | 416k | auto &afa_value = row->GetAFAValue(); |
978 | 416k | auto fa_value_ptr = is_aligned ? &afa_value17.3k : &cfa_value399k ; |
979 | | |
980 | 416k | if (mov_rsp_rbp_pattern_p()) { |
981 | 5.99k | if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { |
982 | 5.99k | fa_value_ptr->SetIsRegisterPlusOffset( |
983 | 5.99k | m_lldb_fp_regnum, fa_value_ptr->GetOffset()); |
984 | 5.99k | row_updated = true; |
985 | 5.99k | } |
986 | 5.99k | } |
987 | | |
988 | 410k | else if (mov_rsp_rbx_pattern_p()) { |
989 | 1 | if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { |
990 | 1 | fa_value_ptr->SetIsRegisterPlusOffset( |
991 | 1 | m_lldb_alt_fp_regnum, fa_value_ptr->GetOffset()); |
992 | 1 | row_updated = true; |
993 | 1 | } |
994 | 1 | } |
995 | | |
996 | 410k | else if (and_rsp_pattern_p()) { |
997 | 1.72k | current_sp_bytes_offset_from_fa = 0; |
998 | 1.72k | afa_value.SetIsRegisterPlusOffset( |
999 | 1.72k | m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); |
1000 | 1.72k | fa_value_ptr = &afa_value; |
1001 | 1.72k | is_aligned = true; |
1002 | 1.72k | row_updated = true; |
1003 | 1.72k | } |
1004 | | |
1005 | 409k | else if (mov_rbp_rsp_pattern_p()) { |
1006 | 1.73k | if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum1.72k ) |
1007 | 1.72k | { |
1008 | 1.72k | is_aligned = false; |
1009 | 1.72k | fa_value_ptr = &cfa_value; |
1010 | 1.72k | afa_value.SetUnspecified(); |
1011 | 1.72k | row_updated = true; |
1012 | 1.72k | } |
1013 | 1.73k | if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) |
1014 | 1.73k | current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); |
1015 | 1.73k | } |
1016 | | |
1017 | 407k | else if (mov_rbx_rsp_pattern_p()) { |
1018 | 1 | if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) |
1019 | 1 | { |
1020 | 1 | is_aligned = false; |
1021 | 1 | fa_value_ptr = &cfa_value; |
1022 | 1 | afa_value.SetUnspecified(); |
1023 | 1 | row_updated = true; |
1024 | 1 | } |
1025 | 1 | if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) |
1026 | 1 | current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); |
1027 | 1 | } |
1028 | | |
1029 | | // This is the start() function (or a pthread equivalent), it starts with a |
1030 | | // pushl $0x0 which puts the saved pc value of 0 on the stack. In this |
1031 | | // case we want to pretend we didn't see a stack movement at all -- |
1032 | | // normally the saved pc value is already on the stack by the time the |
1033 | | // function starts executing. |
1034 | 407k | else if (push_0_pattern_p()) { |
1035 | 1.81k | } |
1036 | | |
1037 | 405k | else if (push_reg_p(machine_regno)) { |
1038 | 13.0k | current_sp_bytes_offset_from_fa += m_wordsize; |
1039 | | // the PUSH instruction has moved the stack pointer - if the FA is set |
1040 | | // in terms of the stack pointer, we need to add a new row of |
1041 | | // instructions. |
1042 | 13.0k | if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { |
1043 | 4.32k | fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); |
1044 | 4.32k | row_updated = true; |
1045 | 4.32k | } |
1046 | | // record where non-volatile (callee-saved, spilled) registers are saved |
1047 | | // on the stack |
1048 | 13.0k | if (nonvolatile_reg_p(machine_regno) && |
1049 | 13.0k | machine_regno_to_lldb_regno(machine_regno, lldb_regno)11.3k && |
1050 | 13.0k | !saved_registers[machine_regno]11.3k ) { |
1051 | 11.3k | UnwindPlan::Row::RegisterLocation regloc; |
1052 | 11.3k | if (is_aligned) |
1053 | 1 | regloc.SetAtAFAPlusOffset(-current_sp_bytes_offset_from_fa); |
1054 | 11.3k | else |
1055 | 11.3k | regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa); |
1056 | 11.3k | row->SetRegisterInfo(lldb_regno, regloc); |
1057 | 11.3k | saved_registers[machine_regno] = true; |
1058 | 11.3k | row_updated = true; |
1059 | 11.3k | } |
1060 | 13.0k | } |
1061 | | |
1062 | 392k | else if (pop_reg_p(machine_regno)) { |
1063 | 12.8k | current_sp_bytes_offset_from_fa -= m_wordsize; |
1064 | | |
1065 | 12.8k | if (nonvolatile_reg_p(machine_regno) && |
1066 | 12.8k | machine_regno_to_lldb_regno(machine_regno, lldb_regno)11.1k && |
1067 | 12.8k | saved_registers[machine_regno]11.1k ) { |
1068 | 11.1k | saved_registers[machine_regno] = false; |
1069 | 11.1k | row->RemoveRegisterInfo(lldb_regno); |
1070 | | |
1071 | 11.1k | if (lldb_regno == fa_value_ptr->GetRegisterNumber()) { |
1072 | 4.15k | fa_value_ptr->SetIsRegisterPlusOffset( |
1073 | 4.15k | m_lldb_sp_regnum, fa_value_ptr->GetOffset()); |
1074 | 4.15k | } |
1075 | | |
1076 | 11.1k | in_epilogue = true; |
1077 | 11.1k | row_updated = true; |
1078 | 11.1k | } |
1079 | | |
1080 | | // the POP instruction has moved the stack pointer - if the FA is set in |
1081 | | // terms of the stack pointer, we need to add a new row of instructions. |
1082 | 12.8k | if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { |
1083 | 5.91k | fa_value_ptr->SetIsRegisterPlusOffset( |
1084 | 5.91k | m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); |
1085 | 5.91k | row_updated = true; |
1086 | 5.91k | } |
1087 | 12.8k | } |
1088 | | |
1089 | 379k | else if (pop_misc_reg_p()) { |
1090 | 3 | current_sp_bytes_offset_from_fa -= m_wordsize; |
1091 | 3 | if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { |
1092 | 3 | fa_value_ptr->SetIsRegisterPlusOffset( |
1093 | 3 | m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); |
1094 | 3 | row_updated = true; |
1095 | 3 | } |
1096 | 3 | } |
1097 | | |
1098 | | // The LEAVE instruction moves the value from rbp into rsp and pops a value |
1099 | | // off the stack into rbp (restoring the caller's rbp value). It is the |
1100 | | // opposite of ENTER, or 'push rbp, mov rsp rbp'. |
1101 | 379k | else if (leave_pattern_p()) { |
1102 | 61 | if (saved_registers[m_machine_fp_regnum]) { |
1103 | 59 | saved_registers[m_machine_fp_regnum] = false; |
1104 | 59 | row->RemoveRegisterInfo(m_lldb_fp_regnum); |
1105 | | |
1106 | 59 | row_updated = true; |
1107 | 59 | } |
1108 | | |
1109 | 61 | if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum0 ) |
1110 | 0 | { |
1111 | 0 | is_aligned = false; |
1112 | 0 | fa_value_ptr = &cfa_value; |
1113 | 0 | afa_value.SetUnspecified(); |
1114 | 0 | row_updated = true; |
1115 | 0 | } |
1116 | | |
1117 | 61 | if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) |
1118 | 57 | { |
1119 | 57 | fa_value_ptr->SetIsRegisterPlusOffset( |
1120 | 57 | m_lldb_sp_regnum, fa_value_ptr->GetOffset()); |
1121 | | |
1122 | 57 | current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); |
1123 | 57 | } |
1124 | | |
1125 | 61 | current_sp_bytes_offset_from_fa -= m_wordsize; |
1126 | | |
1127 | 61 | if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { |
1128 | 61 | fa_value_ptr->SetIsRegisterPlusOffset( |
1129 | 61 | m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); |
1130 | 61 | row_updated = true; |
1131 | 61 | } |
1132 | | |
1133 | 61 | in_epilogue = true; |
1134 | 61 | } |
1135 | | |
1136 | 379k | else if (mov_reg_to_local_stack_frame_p(machine_regno, stack_offset) && |
1137 | 379k | nonvolatile_reg_p(machine_regno)26.4k && |
1138 | 379k | machine_regno_to_lldb_regno(machine_regno, lldb_regno)37 && |
1139 | 379k | !saved_registers[machine_regno]37 ) { |
1140 | 12 | saved_registers[machine_regno] = true; |
1141 | | |
1142 | 12 | UnwindPlan::Row::RegisterLocation regloc; |
1143 | | |
1144 | | // stack_offset for 'movq %r15, -80(%rbp)' will be 80. In the Row, we |
1145 | | // want to express this as the offset from the FA. If the frame base is |
1146 | | // rbp (like the above instruction), the FA offset for rbp is probably |
1147 | | // 16. So we want to say that the value is stored at the FA address - |
1148 | | // 96. |
1149 | 12 | if (is_aligned) |
1150 | 1 | regloc.SetAtAFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset())); |
1151 | 11 | else |
1152 | 11 | regloc.SetAtCFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset())); |
1153 | | |
1154 | 12 | row->SetRegisterInfo(lldb_regno, regloc); |
1155 | | |
1156 | 12 | row_updated = true; |
1157 | 12 | } |
1158 | | |
1159 | 379k | else if (sub_rsp_pattern_p(stack_offset)) { |
1160 | 5.20k | current_sp_bytes_offset_from_fa += stack_offset; |
1161 | 5.20k | if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { |
1162 | 1.75k | fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); |
1163 | 1.75k | row_updated = true; |
1164 | 1.75k | } |
1165 | 5.20k | } |
1166 | | |
1167 | 374k | else if (add_rsp_pattern_p(stack_offset)) { |
1168 | 5.10k | current_sp_bytes_offset_from_fa -= stack_offset; |
1169 | 5.10k | if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { |
1170 | 38 | fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); |
1171 | 38 | row_updated = true; |
1172 | 38 | } |
1173 | 5.10k | in_epilogue = true; |
1174 | 5.10k | } |
1175 | | |
1176 | 369k | else if (push_extended_pattern_p() || push_imm_pattern_p()369k || |
1177 | 369k | push_misc_reg_p()369k ) { |
1178 | 15 | current_sp_bytes_offset_from_fa += m_wordsize; |
1179 | 15 | if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { |
1180 | 15 | fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); |
1181 | 15 | row_updated = true; |
1182 | 15 | } |
1183 | 15 | } |
1184 | | |
1185 | 369k | else if (lea_rsp_pattern_p(stack_offset)) { |
1186 | 0 | current_sp_bytes_offset_from_fa -= stack_offset; |
1187 | 0 | if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { |
1188 | 0 | fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); |
1189 | 0 | row_updated = true; |
1190 | 0 | } |
1191 | 0 | if (stack_offset > 0) |
1192 | 0 | in_epilogue = true; |
1193 | 0 | } |
1194 | | |
1195 | 369k | else if (lea_rbp_rsp_pattern_p(stack_offset)) { |
1196 | 1.72k | if (is_aligned && |
1197 | 1.72k | cfa_value.GetRegisterNumber() == m_lldb_fp_regnum4 ) { |
1198 | 4 | is_aligned = false; |
1199 | 4 | fa_value_ptr = &cfa_value; |
1200 | 4 | afa_value.SetUnspecified(); |
1201 | 4 | row_updated = true; |
1202 | 4 | } |
1203 | 1.72k | if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) { |
1204 | 1.72k | current_sp_bytes_offset_from_fa = |
1205 | 1.72k | fa_value_ptr->GetOffset() - stack_offset; |
1206 | 1.72k | } |
1207 | 1.72k | } |
1208 | | |
1209 | 367k | else if (lea_rbx_rsp_pattern_p(stack_offset)) { |
1210 | 0 | if (is_aligned && |
1211 | 0 | cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) { |
1212 | 0 | is_aligned = false; |
1213 | 0 | fa_value_ptr = &cfa_value; |
1214 | 0 | afa_value.SetUnspecified(); |
1215 | 0 | row_updated = true; |
1216 | 0 | } |
1217 | 0 | if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) { |
1218 | 0 | current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset() - stack_offset; |
1219 | 0 | } |
1220 | 0 | } |
1221 | | |
1222 | 367k | else if (prologue_completed_row.get() && |
1223 | 367k | (332k ret_pattern_p()332k || |
1224 | 332k | non_local_branch_p (current_func_text_offset, func_range, insn_len)328k || |
1225 | 332k | jmp_to_reg_p()323k )) { |
1226 | | // Check if the current instruction is the end of an epilogue sequence, |
1227 | | // and if so, re-instate the prologue-completed unwind state. |
1228 | | |
1229 | | // The current instruction is a branch/jump outside this function, |
1230 | | // a ret, or a jump through a register value which we cannot |
1231 | | // determine the effcts of. Verify that the stack frame state |
1232 | | // has been unwound to the same as it was at function entry to avoid |
1233 | | // mis-identifying a JMP instruction as an epilogue. |
1234 | 13.2k | UnwindPlan::Row::RegisterLocation sp, pc; |
1235 | 13.2k | if (row->GetRegisterInfo(m_lldb_sp_regnum, sp) && |
1236 | 13.2k | row->GetRegisterInfo(m_lldb_ip_regnum, pc)) { |
1237 | | // Any ret instruction variant is definitely indicative of an |
1238 | | // epilogue; for other insn patterns verify that we're back to |
1239 | | // the original unwind state. |
1240 | 13.2k | if (ret_pattern_p() || |
1241 | 13.2k | (9.00k sp.IsCFAPlusOffset()9.00k && sp.GetOffset() == 09.00k && |
1242 | 13.2k | pc.IsAtCFAPlusOffset()9.00k && pc.GetOffset() == -m_wordsize9.00k )) { |
1243 | | // Reinstate the saved prologue setup for any instructions that come |
1244 | | // after the epilogue |
1245 | | |
1246 | 13.2k | UnwindPlan::Row *newrow = new UnwindPlan::Row; |
1247 | 13.2k | *newrow = *prologue_completed_row.get(); |
1248 | 13.2k | row.reset(newrow); |
1249 | 13.2k | current_sp_bytes_offset_from_fa = |
1250 | 13.2k | prologue_completed_sp_bytes_offset_from_cfa; |
1251 | 13.2k | is_aligned = prologue_completed_is_aligned; |
1252 | | |
1253 | 13.2k | saved_registers.clear(); |
1254 | 13.2k | saved_registers.resize(prologue_completed_saved_registers.size(), false); |
1255 | 436k | for (size_t i = 0; i < prologue_completed_saved_registers.size(); ++i423k ) { |
1256 | 423k | saved_registers[i] = prologue_completed_saved_registers[i]; |
1257 | 423k | } |
1258 | | |
1259 | 13.2k | in_epilogue = true; |
1260 | 13.2k | row_updated = true; |
1261 | 13.2k | } |
1262 | 13.2k | } |
1263 | 13.2k | } |
1264 | | |
1265 | | // call next instruction |
1266 | | // call 0 |
1267 | | // => pop %ebx |
1268 | | // This is used in i386 programs to get the PIC base address for finding |
1269 | | // global data |
1270 | 354k | else if (call_next_insn_pattern_p()) { |
1271 | 24 | current_sp_bytes_offset_from_fa += m_wordsize; |
1272 | 24 | if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { |
1273 | 3 | fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); |
1274 | 3 | row_updated = true; |
1275 | 3 | } |
1276 | 24 | } |
1277 | | |
1278 | 416k | if (row_updated) { |
1279 | 48.7k | if (current_func_text_offset + insn_len < size) { |
1280 | 45.1k | row->SetOffset(current_func_text_offset + insn_len); |
1281 | 45.1k | unwind_plan.AppendRow(row); |
1282 | | // Allocate a new Row, populate it with the existing Row contents. |
1283 | 45.1k | newrow = new UnwindPlan::Row; |
1284 | 45.1k | *newrow = *row.get(); |
1285 | 45.1k | row.reset(newrow); |
1286 | 45.1k | } |
1287 | 48.7k | } |
1288 | | |
1289 | 416k | if (!in_epilogue && row_updated387k ) { |
1290 | | // If we're not in an epilogue sequence, save the updated Row |
1291 | 24.3k | UnwindPlan::Row *newrow = new UnwindPlan::Row; |
1292 | 24.3k | *newrow = *row.get(); |
1293 | 24.3k | prologue_completed_row.reset(newrow); |
1294 | | |
1295 | 24.3k | prologue_completed_saved_registers.clear(); |
1296 | 24.3k | prologue_completed_saved_registers.resize(saved_registers.size(), false); |
1297 | 802k | for (size_t i = 0; i < saved_registers.size(); ++i778k ) { |
1298 | 778k | prologue_completed_saved_registers[i] = saved_registers[i]; |
1299 | 778k | } |
1300 | 24.3k | } |
1301 | | |
1302 | | // We may change the sp value without adding a new Row necessarily -- keep |
1303 | | // track of it either way. |
1304 | 416k | if (!in_epilogue) { |
1305 | 387k | prologue_completed_sp_bytes_offset_from_cfa = |
1306 | 387k | current_sp_bytes_offset_from_fa; |
1307 | 387k | prologue_completed_is_aligned = is_aligned; |
1308 | 387k | } |
1309 | | |
1310 | 416k | m_cur_insn = m_cur_insn + insn_len; |
1311 | 416k | current_func_text_offset += insn_len; |
1312 | 416k | } |
1313 | | |
1314 | 7.98k | unwind_plan.SetSourceName("assembly insn profiling"); |
1315 | 7.98k | unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); |
1316 | 7.98k | unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); |
1317 | 7.98k | unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); |
1318 | | |
1319 | 7.98k | return true; |
1320 | 7.98k | } |
1321 | | |
1322 | | bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite( |
1323 | | uint8_t *data, size_t size, AddressRange &func_range, |
1324 | 10 | UnwindPlan &unwind_plan, RegisterContextSP ®_ctx) { |
1325 | 10 | Address addr_start = func_range.GetBaseAddress(); |
1326 | 10 | if (!addr_start.IsValid()) |
1327 | 0 | return false; |
1328 | | |
1329 | | // We either need a live RegisterContext, or we need the UnwindPlan to |
1330 | | // already be in the lldb register numbering scheme. |
1331 | 10 | if (reg_ctx.get() == nullptr && |
1332 | 10 | unwind_plan.GetRegisterKind() != eRegisterKindLLDB3 ) |
1333 | 0 | return false; |
1334 | | |
1335 | | // Is original unwind_plan valid? |
1336 | | // unwind_plan should have at least one row which is ABI-default (CFA |
1337 | | // register is sp), and another row in mid-function. |
1338 | 10 | if (unwind_plan.GetRowCount() < 2) |
1339 | 2 | return false; |
1340 | | |
1341 | 8 | UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex(0); |
1342 | 8 | if (first_row->GetOffset() != 0) |
1343 | 0 | return false; |
1344 | 8 | uint32_t cfa_reg = first_row->GetCFAValue().GetRegisterNumber(); |
1345 | 8 | if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) { |
1346 | 5 | cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( |
1347 | 5 | unwind_plan.GetRegisterKind(), |
1348 | 5 | first_row->GetCFAValue().GetRegisterNumber()); |
1349 | 5 | } |
1350 | 8 | if (cfa_reg != m_lldb_sp_regnum || |
1351 | 8 | first_row->GetCFAValue().GetOffset() != m_wordsize) |
1352 | 0 | return false; |
1353 | | |
1354 | 8 | UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset(-1); |
1355 | | |
1356 | 8 | size_t offset = 0; |
1357 | 8 | int row_id = 1; |
1358 | 8 | bool unwind_plan_updated = false; |
1359 | 8 | UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row)); |
1360 | | |
1361 | | // After a mid-function epilogue we will need to re-insert the original |
1362 | | // unwind rules so unwinds work for the remainder of the function. These |
1363 | | // aren't common with clang/gcc on x86 but it is possible. |
1364 | 8 | bool reinstate_unwind_state = false; |
1365 | | |
1366 | 98 | while (offset < size) { |
1367 | 90 | m_cur_insn = data + offset; |
1368 | 90 | int insn_len; |
1369 | 90 | if (!instruction_length(m_cur_insn, insn_len, size - offset) || |
1370 | 90 | insn_len == 0 || insn_len > kMaxInstructionByteSize) { |
1371 | | // An unrecognized/junk instruction. |
1372 | 0 | break; |
1373 | 0 | } |
1374 | | |
1375 | | // Advance offsets. |
1376 | 90 | offset += insn_len; |
1377 | | |
1378 | | // offset is pointing beyond the bounds of the function; stop looping. |
1379 | 90 | if (offset >= size) |
1380 | 8 | continue; |
1381 | | |
1382 | 82 | if (reinstate_unwind_state) { |
1383 | 0 | UnwindPlan::RowSP new_row(new UnwindPlan::Row()); |
1384 | 0 | *new_row = *original_last_row; |
1385 | 0 | new_row->SetOffset(offset); |
1386 | 0 | unwind_plan.AppendRow(new_row); |
1387 | 0 | row = std::make_shared<UnwindPlan::Row>(); |
1388 | 0 | *row = *new_row; |
1389 | 0 | reinstate_unwind_state = false; |
1390 | 0 | unwind_plan_updated = true; |
1391 | 0 | continue; |
1392 | 0 | } |
1393 | | |
1394 | | // If we already have one row for this instruction, we can continue. |
1395 | 101 | while (82 row_id < unwind_plan.GetRowCount() && |
1396 | 101 | unwind_plan.GetRowAtIndex(row_id)->GetOffset() <= offset30 ) { |
1397 | 19 | row_id++; |
1398 | 19 | } |
1399 | 82 | UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex(row_id - 1); |
1400 | 82 | if (original_row->GetOffset() == offset) { |
1401 | 17 | *row = *original_row; |
1402 | 17 | continue; |
1403 | 17 | } |
1404 | | |
1405 | 65 | if (row_id == 0) { |
1406 | | // If we are here, compiler didn't generate CFI for prologue. This won't |
1407 | | // happen to GCC or clang. In this case, bail out directly. |
1408 | 0 | return false; |
1409 | 0 | } |
1410 | | |
1411 | | // Inspect the instruction to check if we need a new row for it. |
1412 | 65 | cfa_reg = row->GetCFAValue().GetRegisterNumber(); |
1413 | 65 | if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) { |
1414 | 56 | cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( |
1415 | 56 | unwind_plan.GetRegisterKind(), |
1416 | 56 | row->GetCFAValue().GetRegisterNumber()); |
1417 | 56 | } |
1418 | 65 | if (cfa_reg == m_lldb_sp_regnum) { |
1419 | | // CFA register is sp. |
1420 | | |
1421 | | // call next instruction |
1422 | | // call 0 |
1423 | | // => pop %ebx |
1424 | 5 | if (call_next_insn_pattern_p()) { |
1425 | 0 | row->SetOffset(offset); |
1426 | 0 | row->GetCFAValue().IncOffset(m_wordsize); |
1427 | |
|
1428 | 0 | UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); |
1429 | 0 | unwind_plan.InsertRow(new_row); |
1430 | 0 | unwind_plan_updated = true; |
1431 | 0 | continue; |
1432 | 0 | } |
1433 | | |
1434 | | // push/pop register |
1435 | 5 | int regno; |
1436 | 5 | if (push_reg_p(regno)) { |
1437 | 0 | row->SetOffset(offset); |
1438 | 0 | row->GetCFAValue().IncOffset(m_wordsize); |
1439 | |
|
1440 | 0 | UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); |
1441 | 0 | unwind_plan.InsertRow(new_row); |
1442 | 0 | unwind_plan_updated = true; |
1443 | 0 | continue; |
1444 | 0 | } |
1445 | 5 | if (pop_reg_p(regno)) { |
1446 | | // Technically, this might be a nonvolatile register recover in |
1447 | | // epilogue. We should reset RegisterInfo for the register. But in |
1448 | | // practice, previous rule for the register is still valid... So we |
1449 | | // ignore this case. |
1450 | | |
1451 | 1 | row->SetOffset(offset); |
1452 | 1 | row->GetCFAValue().IncOffset(-m_wordsize); |
1453 | | |
1454 | 1 | UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); |
1455 | 1 | unwind_plan.InsertRow(new_row); |
1456 | 1 | unwind_plan_updated = true; |
1457 | 1 | continue; |
1458 | 1 | } |
1459 | | |
1460 | 4 | if (pop_misc_reg_p()) { |
1461 | 0 | row->SetOffset(offset); |
1462 | 0 | row->GetCFAValue().IncOffset(-m_wordsize); |
1463 | |
|
1464 | 0 | UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); |
1465 | 0 | unwind_plan.InsertRow(new_row); |
1466 | 0 | unwind_plan_updated = true; |
1467 | 0 | continue; |
1468 | 0 | } |
1469 | | |
1470 | | // push imm |
1471 | 4 | if (push_imm_pattern_p()) { |
1472 | 0 | row->SetOffset(offset); |
1473 | 0 | row->GetCFAValue().IncOffset(m_wordsize); |
1474 | 0 | UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); |
1475 | 0 | unwind_plan.InsertRow(new_row); |
1476 | 0 | unwind_plan_updated = true; |
1477 | 0 | continue; |
1478 | 0 | } |
1479 | | |
1480 | | // push extended |
1481 | 4 | if (push_extended_pattern_p() || push_misc_reg_p()) { |
1482 | 0 | row->SetOffset(offset); |
1483 | 0 | row->GetCFAValue().IncOffset(m_wordsize); |
1484 | 0 | UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); |
1485 | 0 | unwind_plan.InsertRow(new_row); |
1486 | 0 | unwind_plan_updated = true; |
1487 | 0 | continue; |
1488 | 0 | } |
1489 | | |
1490 | | // add/sub %rsp/%esp |
1491 | 4 | int amount; |
1492 | 4 | if (add_rsp_pattern_p(amount)) { |
1493 | 1 | row->SetOffset(offset); |
1494 | 1 | row->GetCFAValue().IncOffset(-amount); |
1495 | | |
1496 | 1 | UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); |
1497 | 1 | unwind_plan.InsertRow(new_row); |
1498 | 1 | unwind_plan_updated = true; |
1499 | 1 | continue; |
1500 | 1 | } |
1501 | 3 | if (sub_rsp_pattern_p(amount)) { |
1502 | 1 | row->SetOffset(offset); |
1503 | 1 | row->GetCFAValue().IncOffset(amount); |
1504 | | |
1505 | 1 | UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); |
1506 | 1 | unwind_plan.InsertRow(new_row); |
1507 | 1 | unwind_plan_updated = true; |
1508 | 1 | continue; |
1509 | 1 | } |
1510 | | |
1511 | | // lea %rsp, [%rsp + $offset] |
1512 | 2 | if (lea_rsp_pattern_p(amount)) { |
1513 | 0 | row->SetOffset(offset); |
1514 | 0 | row->GetCFAValue().IncOffset(-amount); |
1515 | |
|
1516 | 0 | UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); |
1517 | 0 | unwind_plan.InsertRow(new_row); |
1518 | 0 | unwind_plan_updated = true; |
1519 | 0 | continue; |
1520 | 0 | } |
1521 | | |
1522 | 2 | if (ret_pattern_p()) { |
1523 | 0 | reinstate_unwind_state = true; |
1524 | 0 | continue; |
1525 | 0 | } |
1526 | 60 | } else if (cfa_reg == m_lldb_fp_regnum) { |
1527 | | // CFA register is fp. |
1528 | | |
1529 | | // The only case we care about is epilogue: |
1530 | | // [0x5d] pop %rbp/%ebp |
1531 | | // => [0xc3] ret |
1532 | 60 | if (pop_rbp_pattern_p() || leave_pattern_p()54 ) { |
1533 | 6 | m_cur_insn++; |
1534 | 6 | if (ret_pattern_p()) { |
1535 | 6 | row->SetOffset(offset); |
1536 | 6 | row->GetCFAValue().SetIsRegisterPlusOffset( |
1537 | 6 | first_row->GetCFAValue().GetRegisterNumber(), m_wordsize); |
1538 | | |
1539 | 6 | UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); |
1540 | 6 | unwind_plan.InsertRow(new_row); |
1541 | 6 | unwind_plan_updated = true; |
1542 | 6 | reinstate_unwind_state = true; |
1543 | 6 | continue; |
1544 | 6 | } |
1545 | 6 | } |
1546 | 60 | } else { |
1547 | | // CFA register is not sp or fp. |
1548 | | |
1549 | | // This must be hand-written assembly. |
1550 | | // Just trust eh_frame and assume we have finished. |
1551 | 0 | break; |
1552 | 0 | } |
1553 | 65 | } |
1554 | | |
1555 | 8 | unwind_plan.SetPlanValidAddressRange(func_range); |
1556 | 8 | if (unwind_plan_updated) { |
1557 | 7 | std::string unwind_plan_source(unwind_plan.GetSourceName().AsCString()); |
1558 | 7 | unwind_plan_source += " plus augmentation from assembly parsing"; |
1559 | 7 | unwind_plan.SetSourceName(unwind_plan_source.c_str()); |
1560 | 7 | unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); |
1561 | 7 | unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); |
1562 | 7 | } |
1563 | 8 | return true; |
1564 | 8 | } |
1565 | | |
1566 | | bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction( |
1567 | 0 | uint8_t *data, size_t size, size_t &offset) { |
1568 | 0 | offset = 0; |
1569 | |
|
1570 | 0 | if (!m_register_map_initialized) |
1571 | 0 | return false; |
1572 | | |
1573 | 0 | while (offset < size) { |
1574 | 0 | int regno; |
1575 | 0 | int insn_len; |
1576 | 0 | int scratch; |
1577 | |
|
1578 | 0 | m_cur_insn = data + offset; |
1579 | 0 | if (!instruction_length(m_cur_insn, insn_len, size - offset) |
1580 | 0 | || insn_len > kMaxInstructionByteSize |
1581 | 0 | || insn_len == 0) { |
1582 | | // An error parsing the instruction, i.e. probably data/garbage - stop |
1583 | | // scanning |
1584 | 0 | break; |
1585 | 0 | } |
1586 | | |
1587 | 0 | if (push_rbp_pattern_p() || mov_rsp_rbp_pattern_p() || |
1588 | 0 | sub_rsp_pattern_p(scratch) || push_reg_p(regno) || |
1589 | 0 | mov_reg_to_local_stack_frame_p(regno, scratch) || |
1590 | 0 | (lea_rsp_pattern_p(scratch) && offset == 0)) { |
1591 | 0 | offset += insn_len; |
1592 | 0 | continue; |
1593 | 0 | } |
1594 | | // |
1595 | | // Unknown non-prologue instruction - stop scanning |
1596 | 0 | break; |
1597 | 0 | } |
1598 | |
|
1599 | 0 | return true; |
1600 | 0 | } |