1 | //===-- DWARFCallFrameInfo.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 "lldb/Symbol/DWARFCallFrameInfo.h" |
10 | #include "lldb/Core/Debugger.h" |
11 | #include "lldb/Core/Module.h" |
12 | #include "lldb/Core/Section.h" |
13 | #include "lldb/Core/dwarf.h" |
14 | #include "lldb/Host/Host.h" |
15 | #include "lldb/Symbol/ObjectFile.h" |
16 | #include "lldb/Symbol/UnwindPlan.h" |
17 | #include "lldb/Target/RegisterContext.h" |
18 | #include "lldb/Target/Thread.h" |
19 | #include "lldb/Utility/ArchSpec.h" |
20 | #include "lldb/Utility/LLDBLog.h" |
21 | #include "lldb/Utility/Log.h" |
22 | #include "lldb/Utility/Timer.h" |
23 | #include <cstring> |
24 | #include <list> |
25 | #include <optional> |
26 | |
27 | using namespace lldb; |
28 | using namespace lldb_private; |
29 | using namespace lldb_private::dwarf; |
30 | |
31 | // GetDwarfEHPtr |
32 | // |
33 | // Used for calls when the value type is specified by a DWARF EH Frame pointer |
34 | // encoding. |
35 | static uint64_t |
36 | (const DataExtractor &DE, offset_t *offset_ptr, |
37 | uint32_t eh_ptr_enc, addr_t pc_rel_addr, addr_t text_addr, |
38 | addr_t data_addr) //, BSDRelocs *data_relocs) const |
39 | { |
40 | if (eh_ptr_enc == DW_EH_PE_omit) |
41 | return ULLONG_MAX; // Value isn't in the buffer... |
42 | |
43 | uint64_t baseAddress = 0; |
44 | uint64_t addressValue = 0; |
45 | const uint32_t addr_size = DE.GetAddressByteSize(); |
46 | assert(addr_size == 4 || addr_size == 8); |
47 | |
48 | bool signExtendValue = false; |
49 | // Decode the base part or adjust our offset |
50 | switch (eh_ptr_enc & 0x70) { |
51 | case DW_EH_PE_pcrel: |
52 | signExtendValue = true; |
53 | baseAddress = *offset_ptr; |
54 | if (pc_rel_addr != LLDB_INVALID_ADDRESS) |
55 | baseAddress += pc_rel_addr; |
56 | // else |
57 | // Log::GlobalWarning ("PC relative pointer encoding found with |
58 | // invalid pc relative address."); |
59 | break; |
60 | |
61 | case DW_EH_PE_textrel: |
62 | signExtendValue = true; |
63 | if (text_addr != LLDB_INVALID_ADDRESS) |
64 | baseAddress = text_addr; |
65 | // else |
66 | // Log::GlobalWarning ("text relative pointer encoding being |
67 | // decoded with invalid text section address, setting base address |
68 | // to zero."); |
69 | break; |
70 | |
71 | case DW_EH_PE_datarel: |
72 | signExtendValue = true; |
73 | if (data_addr != LLDB_INVALID_ADDRESS) |
74 | baseAddress = data_addr; |
75 | // else |
76 | // Log::GlobalWarning ("data relative pointer encoding being |
77 | // decoded with invalid data section address, setting base address |
78 | // to zero."); |
79 | break; |
80 | |
81 | case DW_EH_PE_funcrel: |
82 | signExtendValue = true; |
83 | break; |
84 | |
85 | case DW_EH_PE_aligned: { |
86 | // SetPointerSize should be called prior to extracting these so the pointer |
87 | // size is cached |
88 | assert(addr_size != 0); |
89 | if (addr_size) { |
90 | // Align to a address size boundary first |
91 | uint32_t alignOffset = *offset_ptr % addr_size; |
92 | if (alignOffset) |
93 | offset_ptr += addr_size - alignOffset; |
94 | } |
95 | } break; |
96 | |
97 | default: |
98 | break; |
99 | } |
100 | |
101 | // Decode the value part |
102 | switch (eh_ptr_enc & DW_EH_PE_MASK_ENCODING) { |
103 | case DW_EH_PE_absptr: { |
104 | addressValue = DE.GetAddress(offset_ptr); |
105 | // if (data_relocs) |
106 | // addressValue = data_relocs->Relocate(*offset_ptr - |
107 | // addr_size, *this, addressValue); |
108 | } break; |
109 | case DW_EH_PE_uleb128: |
110 | addressValue = DE.GetULEB128(offset_ptr); |
111 | break; |
112 | case DW_EH_PE_udata2: |
113 | addressValue = DE.GetU16(offset_ptr); |
114 | break; |
115 | case DW_EH_PE_udata4: |
116 | addressValue = DE.GetU32(offset_ptr); |
117 | break; |
118 | case DW_EH_PE_udata8: |
119 | addressValue = DE.GetU64(offset_ptr); |
120 | break; |
121 | case DW_EH_PE_sleb128: |
122 | addressValue = DE.GetSLEB128(offset_ptr); |
123 | break; |
124 | case DW_EH_PE_sdata2: |
125 | addressValue = (int16_t)DE.GetU16(offset_ptr); |
126 | break; |
127 | case DW_EH_PE_sdata4: |
128 | addressValue = (int32_t)DE.GetU32(offset_ptr); |
129 | break; |
130 | case DW_EH_PE_sdata8: |
131 | addressValue = (int64_t)DE.GetU64(offset_ptr); |
132 | break; |
133 | default: |
134 | // Unhandled encoding type |
135 | assert(eh_ptr_enc); |
136 | break; |
137 | } |
138 | |
139 | // Since we promote everything to 64 bit, we may need to sign extend |
140 | if (signExtendValue && addr_size < sizeof(baseAddress)) { |
141 | uint64_t sign_bit = 1ull << ((addr_size * 8ull) - 1ull); |
142 | if (sign_bit & addressValue) { |
143 | uint64_t mask = ~sign_bit + 1; |
144 | addressValue |= mask; |
145 | } |
146 | } |
147 | return baseAddress + addressValue; |
148 | } |
149 | |
150 | DWARFCallFrameInfo::DWARFCallFrameInfo(ObjectFile &objfile, |
151 | SectionSP §ion_sp, Type type) |
152 | : m_objfile(objfile), m_section_sp(section_sp), m_type(type) {} |
153 | |
154 | bool DWARFCallFrameInfo::GetUnwindPlan(const Address &addr, |
155 | UnwindPlan &unwind_plan) { |
156 | return GetUnwindPlan(range: AddressRange(addr, 1), unwind_plan); |
157 | } |
158 | |
159 | bool DWARFCallFrameInfo::GetUnwindPlan(const AddressRange &range, |
160 | UnwindPlan &unwind_plan) { |
161 | FDEEntryMap::Entry fde_entry; |
162 | Address addr = range.GetBaseAddress(); |
163 | |
164 | // Make sure that the Address we're searching for is the same object file as |
165 | // this DWARFCallFrameInfo, we only store File offsets in m_fde_index. |
166 | ModuleSP module_sp = addr.GetModule(); |
167 | if (module_sp.get() == nullptr || module_sp->GetObjectFile() == nullptr || |
168 | module_sp->GetObjectFile() != &m_objfile) |
169 | return false; |
170 | |
171 | if (std::optional<FDEEntryMap::Entry> entry = GetFirstFDEEntryInRange(range)) |
172 | return FDEToUnwindPlan(offset: entry->data, startaddr: addr, unwind_plan); |
173 | return false; |
174 | } |
175 | |
176 | bool DWARFCallFrameInfo::GetAddressRange(Address addr, AddressRange &range) { |
177 | |
178 | // Make sure that the Address we're searching for is the same object file as |
179 | // this DWARFCallFrameInfo, we only store File offsets in m_fde_index. |
180 | ModuleSP module_sp = addr.GetModule(); |
181 | if (module_sp.get() == nullptr || module_sp->GetObjectFile() == nullptr || |
182 | module_sp->GetObjectFile() != &m_objfile) |
183 | return false; |
184 | |
185 | if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted()) |
186 | return false; |
187 | GetFDEIndex(); |
188 | FDEEntryMap::Entry *fde_entry = |
189 | m_fde_index.FindEntryThatContains(addr: addr.GetFileAddress()); |
190 | if (!fde_entry) |
191 | return false; |
192 | |
193 | range = AddressRange(fde_entry->base, fde_entry->size, |
194 | m_objfile.GetSectionList()); |
195 | return true; |
196 | } |
197 | |
198 | std::optional<DWARFCallFrameInfo::FDEEntryMap::Entry> |
199 | DWARFCallFrameInfo::GetFirstFDEEntryInRange(const AddressRange &range) { |
200 | if (!m_section_sp || m_section_sp->IsEncrypted()) |
201 | return std::nullopt; |
202 | |
203 | GetFDEIndex(); |
204 | |
205 | addr_t start_file_addr = range.GetBaseAddress().GetFileAddress(); |
206 | const FDEEntryMap::Entry *fde = |
207 | m_fde_index.FindEntryThatContainsOrFollows(addr: start_file_addr); |
208 | if (fde && fde->DoesIntersect( |
209 | rhs: FDEEntryMap::Range(start_file_addr, range.GetByteSize()))) |
210 | return *fde; |
211 | |
212 | return std::nullopt; |
213 | } |
214 | |
215 | void DWARFCallFrameInfo::GetFunctionAddressAndSizeVector( |
216 | FunctionAddressAndSizeVector &function_info) { |
217 | GetFDEIndex(); |
218 | const size_t count = m_fde_index.GetSize(); |
219 | function_info.Clear(); |
220 | if (count > 0) |
221 | function_info.Reserve(size: count); |
222 | for (size_t i = 0; i < count; ++i) { |
223 | const FDEEntryMap::Entry *func_offset_data_entry = |
224 | m_fde_index.GetEntryAtIndex(i); |
225 | if (func_offset_data_entry) { |
226 | FunctionAddressAndSizeVector::Entry function_offset_entry( |
227 | func_offset_data_entry->base, func_offset_data_entry->size); |
228 | function_info.Append(entry: function_offset_entry); |
229 | } |
230 | } |
231 | } |
232 | |
233 | const DWARFCallFrameInfo::CIE * |
234 | DWARFCallFrameInfo::GetCIE(dw_offset_t cie_offset) { |
235 | cie_map_t::iterator pos = m_cie_map.find(x: cie_offset); |
236 | |
237 | if (pos != m_cie_map.end()) { |
238 | // Parse and cache the CIE |
239 | if (pos->second == nullptr) |
240 | pos->second = ParseCIE(cie_offset); |
241 | |
242 | return pos->second.get(); |
243 | } |
244 | return nullptr; |
245 | } |
246 | |
247 | DWARFCallFrameInfo::CIESP |
248 | DWARFCallFrameInfo::ParseCIE(const dw_offset_t cie_offset) { |
249 | CIESP cie_sp(new CIE(cie_offset)); |
250 | lldb::offset_t offset = cie_offset; |
251 | if (!m_cfi_data_initialized) |
252 | GetCFIData(); |
253 | uint32_t length = m_cfi_data.GetU32(offset_ptr: &offset); |
254 | dw_offset_t cie_id, end_offset; |
255 | bool is_64bit = (length == UINT32_MAX); |
256 | if (is_64bit) { |
257 | length = m_cfi_data.GetU64(offset_ptr: &offset); |
258 | cie_id = m_cfi_data.GetU64(offset_ptr: &offset); |
259 | end_offset = cie_offset + length + 12; |
260 | } else { |
261 | cie_id = m_cfi_data.GetU32(offset_ptr: &offset); |
262 | end_offset = cie_offset + length + 4; |
263 | } |
264 | if (length > 0 && ((m_type == DWARF && cie_id == UINT32_MAX) || |
265 | (m_type == EH && cie_id == 0ul))) { |
266 | size_t i; |
267 | // cie.offset = cie_offset; |
268 | // cie.length = length; |
269 | // cie.cieID = cieID; |
270 | cie_sp->ptr_encoding = DW_EH_PE_absptr; // default |
271 | cie_sp->version = m_cfi_data.GetU8(offset_ptr: &offset); |
272 | if (cie_sp->version > CFI_VERSION4) { |
273 | Debugger::ReportError( |
274 | message: llvm::formatv(Fmt: "CIE parse error: CFI version {0} is not supported" , |
275 | Vals&: cie_sp->version)); |
276 | return nullptr; |
277 | } |
278 | |
279 | for (i = 0; i < CFI_AUG_MAX_SIZE; ++i) { |
280 | cie_sp->augmentation[i] = m_cfi_data.GetU8(offset_ptr: &offset); |
281 | if (cie_sp->augmentation[i] == '\0') { |
282 | // Zero out remaining bytes in augmentation string |
283 | for (size_t j = i + 1; j < CFI_AUG_MAX_SIZE; ++j) |
284 | cie_sp->augmentation[j] = '\0'; |
285 | |
286 | break; |
287 | } |
288 | } |
289 | |
290 | if (i == CFI_AUG_MAX_SIZE && |
291 | cie_sp->augmentation[CFI_AUG_MAX_SIZE - 1] != '\0') { |
292 | Debugger::ReportError(message: llvm::formatv( |
293 | Fmt: "CIE parse error: CIE augmentation string was too large " |
294 | "for the fixed sized buffer of {0} bytes." , |
295 | Vals: CFI_AUG_MAX_SIZE)); |
296 | return nullptr; |
297 | } |
298 | |
299 | // m_cfi_data uses address size from target architecture of the process may |
300 | // ignore these fields? |
301 | if (m_type == DWARF && cie_sp->version >= CFI_VERSION4) { |
302 | cie_sp->address_size = m_cfi_data.GetU8(offset_ptr: &offset); |
303 | cie_sp->segment_size = m_cfi_data.GetU8(offset_ptr: &offset); |
304 | } |
305 | |
306 | cie_sp->code_align = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
307 | cie_sp->data_align = (int32_t)m_cfi_data.GetSLEB128(offset_ptr: &offset); |
308 | |
309 | cie_sp->return_addr_reg_num = |
310 | m_type == DWARF && cie_sp->version >= CFI_VERSION3 |
311 | ? static_cast<uint32_t>(m_cfi_data.GetULEB128(offset_ptr: &offset)) |
312 | : m_cfi_data.GetU8(offset_ptr: &offset); |
313 | |
314 | if (cie_sp->augmentation[0]) { |
315 | // Get the length of the eh_frame augmentation data which starts with a |
316 | // ULEB128 length in bytes |
317 | const size_t aug_data_len = (size_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
318 | const size_t aug_data_end = offset + aug_data_len; |
319 | const size_t aug_str_len = strlen(s: cie_sp->augmentation); |
320 | // A 'z' may be present as the first character of the string. |
321 | // If present, the Augmentation Data field shall be present. The contents |
322 | // of the Augmentation Data shall be interpreted according to other |
323 | // characters in the Augmentation String. |
324 | if (cie_sp->augmentation[0] == 'z') { |
325 | // Extract the Augmentation Data |
326 | size_t aug_str_idx = 0; |
327 | for (aug_str_idx = 1; aug_str_idx < aug_str_len; aug_str_idx++) { |
328 | char aug = cie_sp->augmentation[aug_str_idx]; |
329 | switch (aug) { |
330 | case 'L': |
331 | // Indicates the presence of one argument in the Augmentation Data |
332 | // of the CIE, and a corresponding argument in the Augmentation |
333 | // Data of the FDE. The argument in the Augmentation Data of the |
334 | // CIE is 1-byte and represents the pointer encoding used for the |
335 | // argument in the Augmentation Data of the FDE, which is the |
336 | // address of a language-specific data area (LSDA). The size of the |
337 | // LSDA pointer is specified by the pointer encoding used. |
338 | cie_sp->lsda_addr_encoding = m_cfi_data.GetU8(offset_ptr: &offset); |
339 | break; |
340 | |
341 | case 'P': |
342 | // Indicates the presence of two arguments in the Augmentation Data |
343 | // of the CIE. The first argument is 1-byte and represents the |
344 | // pointer encoding used for the second argument, which is the |
345 | // address of a personality routine handler. The size of the |
346 | // personality routine pointer is specified by the pointer encoding |
347 | // used. |
348 | // |
349 | // The address of the personality function will be stored at this |
350 | // location. Pre-execution, it will be all zero's so don't read it |
351 | // until we're trying to do an unwind & the reloc has been |
352 | // resolved. |
353 | { |
354 | uint8_t arg_ptr_encoding = m_cfi_data.GetU8(offset_ptr: &offset); |
355 | const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress(); |
356 | cie_sp->personality_loc = GetGNUEHPointer( |
357 | DE: m_cfi_data, offset_ptr: &offset, eh_ptr_enc: arg_ptr_encoding, pc_rel_addr, |
358 | LLDB_INVALID_ADDRESS, LLDB_INVALID_ADDRESS); |
359 | } |
360 | break; |
361 | |
362 | case 'R': |
363 | // A 'R' may be present at any position after the |
364 | // first character of the string. The Augmentation Data shall |
365 | // include a 1 byte argument that represents the pointer encoding |
366 | // for the address pointers used in the FDE. Example: 0x1B == |
367 | // DW_EH_PE_pcrel | DW_EH_PE_sdata4 |
368 | cie_sp->ptr_encoding = m_cfi_data.GetU8(offset_ptr: &offset); |
369 | break; |
370 | } |
371 | } |
372 | } else if (strcmp(s1: cie_sp->augmentation, s2: "eh" ) == 0) { |
373 | // If the Augmentation string has the value "eh", then the EH Data |
374 | // field shall be present |
375 | } |
376 | |
377 | // Set the offset to be the end of the augmentation data just in case we |
378 | // didn't understand any of the data. |
379 | offset = (uint32_t)aug_data_end; |
380 | } |
381 | |
382 | if (end_offset > offset) { |
383 | cie_sp->inst_offset = offset; |
384 | cie_sp->inst_length = end_offset - offset; |
385 | } |
386 | while (offset < end_offset) { |
387 | uint8_t inst = m_cfi_data.GetU8(offset_ptr: &offset); |
388 | uint8_t primary_opcode = inst & 0xC0; |
389 | uint8_t extended_opcode = inst & 0x3F; |
390 | |
391 | if (!HandleCommonDwarfOpcode(primary_opcode, extended_opcode, |
392 | data_align: cie_sp->data_align, offset, |
393 | row&: cie_sp->initial_row)) |
394 | break; // Stop if we hit an unrecognized opcode |
395 | } |
396 | } |
397 | |
398 | return cie_sp; |
399 | } |
400 | |
401 | void DWARFCallFrameInfo::GetCFIData() { |
402 | if (!m_cfi_data_initialized) { |
403 | Log *log = GetLog(mask: LLDBLog::Unwind); |
404 | if (log) |
405 | m_objfile.GetModule()->LogMessage(log, format: "Reading EH frame info" ); |
406 | m_objfile.ReadSectionData(section: m_section_sp.get(), section_data&: m_cfi_data); |
407 | m_cfi_data_initialized = true; |
408 | } |
409 | } |
410 | // Scan through the eh_frame or debug_frame section looking for FDEs and noting |
411 | // the start/end addresses of the functions and a pointer back to the |
412 | // function's FDE for later expansion. Internalize CIEs as we come across them. |
413 | |
414 | void DWARFCallFrameInfo::GetFDEIndex() { |
415 | if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted()) |
416 | return; |
417 | |
418 | if (m_fde_index_initialized) |
419 | return; |
420 | |
421 | std::lock_guard<std::mutex> guard(m_fde_index_mutex); |
422 | |
423 | if (m_fde_index_initialized) // if two threads hit the locker |
424 | return; |
425 | |
426 | LLDB_SCOPED_TIMERF("%s - %s" , LLVM_PRETTY_FUNCTION, |
427 | m_objfile.GetFileSpec().GetFilename().AsCString("" )); |
428 | |
429 | bool clear_address_zeroth_bit = false; |
430 | if (ArchSpec arch = m_objfile.GetArchitecture()) { |
431 | if (arch.GetTriple().getArch() == llvm::Triple::arm || |
432 | arch.GetTriple().getArch() == llvm::Triple::thumb) |
433 | clear_address_zeroth_bit = true; |
434 | } |
435 | |
436 | lldb::offset_t offset = 0; |
437 | if (!m_cfi_data_initialized) |
438 | GetCFIData(); |
439 | while (m_cfi_data.ValidOffsetForDataOfSize(offset, length: 8)) { |
440 | const dw_offset_t current_entry = offset; |
441 | dw_offset_t cie_id, next_entry, cie_offset; |
442 | uint32_t len = m_cfi_data.GetU32(offset_ptr: &offset); |
443 | bool is_64bit = (len == UINT32_MAX); |
444 | if (is_64bit) { |
445 | len = m_cfi_data.GetU64(offset_ptr: &offset); |
446 | cie_id = m_cfi_data.GetU64(offset_ptr: &offset); |
447 | next_entry = current_entry + len + 12; |
448 | cie_offset = current_entry + 12 - cie_id; |
449 | } else { |
450 | cie_id = m_cfi_data.GetU32(offset_ptr: &offset); |
451 | next_entry = current_entry + len + 4; |
452 | cie_offset = current_entry + 4 - cie_id; |
453 | } |
454 | |
455 | if (next_entry > m_cfi_data.GetByteSize() + 1) { |
456 | Debugger::ReportError(message: llvm::formatv(Fmt: "Invalid fde/cie next entry offset " |
457 | "of {0:x} found in cie/fde at {1:x}" , |
458 | Vals&: next_entry, Vals: current_entry)); |
459 | // Don't trust anything in this eh_frame section if we find blatantly |
460 | // invalid data. |
461 | m_fde_index.Clear(); |
462 | m_fde_index_initialized = true; |
463 | return; |
464 | } |
465 | |
466 | // An FDE entry contains CIE_pointer in debug_frame in same place as cie_id |
467 | // in eh_frame. CIE_pointer is an offset into the .debug_frame section. So, |
468 | // variable cie_offset should be equal to cie_id for debug_frame. |
469 | // FDE entries with cie_id == 0 shouldn't be ignored for it. |
470 | if ((cie_id == 0 && m_type == EH) || cie_id == UINT32_MAX || len == 0) { |
471 | auto cie_sp = ParseCIE(cie_offset: current_entry); |
472 | if (!cie_sp) { |
473 | // Cannot parse, the reason is already logged |
474 | m_fde_index.Clear(); |
475 | m_fde_index_initialized = true; |
476 | return; |
477 | } |
478 | |
479 | m_cie_map[current_entry] = std::move(cie_sp); |
480 | offset = next_entry; |
481 | continue; |
482 | } |
483 | |
484 | if (m_type == DWARF) |
485 | cie_offset = cie_id; |
486 | |
487 | if (cie_offset > m_cfi_data.GetByteSize()) { |
488 | Debugger::ReportError(message: llvm::formatv(Fmt: "Invalid cie offset of {0:x} " |
489 | "found in cie/fde at {1:x}" , |
490 | Vals&: cie_offset, Vals: current_entry)); |
491 | // Don't trust anything in this eh_frame section if we find blatantly |
492 | // invalid data. |
493 | m_fde_index.Clear(); |
494 | m_fde_index_initialized = true; |
495 | return; |
496 | } |
497 | |
498 | const CIE *cie = GetCIE(cie_offset); |
499 | if (cie) { |
500 | const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress(); |
501 | const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS; |
502 | const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS; |
503 | |
504 | lldb::addr_t addr = |
505 | GetGNUEHPointer(DE: m_cfi_data, offset_ptr: &offset, eh_ptr_enc: cie->ptr_encoding, pc_rel_addr, |
506 | text_addr, data_addr); |
507 | if (clear_address_zeroth_bit) |
508 | addr &= ~1ull; |
509 | |
510 | lldb::addr_t length = GetGNUEHPointer( |
511 | DE: m_cfi_data, offset_ptr: &offset, eh_ptr_enc: cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, |
512 | pc_rel_addr, text_addr, data_addr); |
513 | FDEEntryMap::Entry fde(addr, length, current_entry); |
514 | m_fde_index.Append(entry: fde); |
515 | } else { |
516 | Debugger::ReportError(message: llvm::formatv( |
517 | Fmt: "unable to find CIE at {0:x} for cie_id = {1:x} for entry at {2:x}." , |
518 | Vals&: cie_offset, Vals&: cie_id, Vals: current_entry)); |
519 | } |
520 | offset = next_entry; |
521 | } |
522 | m_fde_index.Sort(); |
523 | m_fde_index_initialized = true; |
524 | } |
525 | |
526 | bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset, |
527 | Address startaddr, |
528 | UnwindPlan &unwind_plan) { |
529 | Log *log = GetLog(mask: LLDBLog::Unwind); |
530 | lldb::offset_t offset = dwarf_offset; |
531 | lldb::offset_t current_entry = offset; |
532 | |
533 | if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted()) |
534 | return false; |
535 | |
536 | if (!m_cfi_data_initialized) |
537 | GetCFIData(); |
538 | |
539 | uint32_t length = m_cfi_data.GetU32(offset_ptr: &offset); |
540 | dw_offset_t cie_offset; |
541 | bool is_64bit = (length == UINT32_MAX); |
542 | if (is_64bit) { |
543 | length = m_cfi_data.GetU64(offset_ptr: &offset); |
544 | cie_offset = m_cfi_data.GetU64(offset_ptr: &offset); |
545 | } else { |
546 | cie_offset = m_cfi_data.GetU32(offset_ptr: &offset); |
547 | } |
548 | |
549 | // FDE entries with zeroth cie_offset may occur for debug_frame. |
550 | assert(!(m_type == EH && 0 == cie_offset) && cie_offset != UINT32_MAX); |
551 | |
552 | // Translate the CIE_id from the eh_frame format, which is relative to the |
553 | // FDE offset, into a __eh_frame section offset |
554 | if (m_type == EH) { |
555 | unwind_plan.SetSourceName("eh_frame CFI" ); |
556 | cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset; |
557 | unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); |
558 | } else { |
559 | unwind_plan.SetSourceName("DWARF CFI" ); |
560 | // In theory the debug_frame info should be valid at all call sites |
561 | // ("asynchronous unwind info" as it is sometimes called) but in practice |
562 | // gcc et al all emit call frame info for the prologue and call sites, but |
563 | // not for the epilogue or all the other locations during the function |
564 | // reliably. |
565 | unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); |
566 | } |
567 | unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); |
568 | |
569 | const CIE *cie = GetCIE(cie_offset); |
570 | assert(cie != nullptr); |
571 | |
572 | const dw_offset_t end_offset = current_entry + length + (is_64bit ? 12 : 4); |
573 | |
574 | const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress(); |
575 | const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS; |
576 | const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS; |
577 | lldb::addr_t range_base = |
578 | GetGNUEHPointer(DE: m_cfi_data, offset_ptr: &offset, eh_ptr_enc: cie->ptr_encoding, pc_rel_addr, |
579 | text_addr, data_addr); |
580 | lldb::addr_t range_len = GetGNUEHPointer( |
581 | DE: m_cfi_data, offset_ptr: &offset, eh_ptr_enc: cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, |
582 | pc_rel_addr, text_addr, data_addr); |
583 | AddressRange range(range_base, m_objfile.GetAddressByteSize(), |
584 | m_objfile.GetSectionList()); |
585 | range.SetByteSize(range_len); |
586 | |
587 | addr_t lsda_data_file_address = LLDB_INVALID_ADDRESS; |
588 | |
589 | if (cie->augmentation[0] == 'z') { |
590 | uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
591 | if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit) { |
592 | offset_t saved_offset = offset; |
593 | lsda_data_file_address = |
594 | GetGNUEHPointer(DE: m_cfi_data, offset_ptr: &offset, eh_ptr_enc: cie->lsda_addr_encoding, |
595 | pc_rel_addr, text_addr, data_addr); |
596 | if (offset - saved_offset != aug_data_len) { |
597 | // There is more in the augmentation region than we know how to process; |
598 | // don't read anything. |
599 | lsda_data_file_address = LLDB_INVALID_ADDRESS; |
600 | } |
601 | offset = saved_offset; |
602 | } |
603 | offset += aug_data_len; |
604 | } |
605 | unwind_plan.SetUnwindPlanForSignalTrap( |
606 | strchr(s: cie->augmentation, c: 'S') ? eLazyBoolYes : eLazyBoolNo); |
607 | |
608 | Address lsda_data; |
609 | Address personality_function_ptr; |
610 | |
611 | if (lsda_data_file_address != LLDB_INVALID_ADDRESS && |
612 | cie->personality_loc != LLDB_INVALID_ADDRESS) { |
613 | m_objfile.GetModule()->ResolveFileAddress(vm_addr: lsda_data_file_address, |
614 | so_addr&: lsda_data); |
615 | m_objfile.GetModule()->ResolveFileAddress(vm_addr: cie->personality_loc, |
616 | so_addr&: personality_function_ptr); |
617 | } |
618 | |
619 | if (lsda_data.IsValid() && personality_function_ptr.IsValid()) { |
620 | unwind_plan.SetLSDAAddress(lsda_data); |
621 | unwind_plan.SetPersonalityFunctionPtr(personality_function_ptr); |
622 | } |
623 | |
624 | uint32_t code_align = cie->code_align; |
625 | int32_t data_align = cie->data_align; |
626 | |
627 | unwind_plan.SetPlanValidAddressRange(range); |
628 | UnwindPlan::Row *cie_initial_row = new UnwindPlan::Row; |
629 | *cie_initial_row = cie->initial_row; |
630 | UnwindPlan::RowSP row(cie_initial_row); |
631 | |
632 | unwind_plan.SetRegisterKind(GetRegisterKind()); |
633 | unwind_plan.SetReturnAddressRegister(cie->return_addr_reg_num); |
634 | |
635 | std::vector<UnwindPlan::RowSP> stack; |
636 | |
637 | UnwindPlan::Row::RegisterLocation reg_location; |
638 | while (m_cfi_data.ValidOffset(offset) && offset < end_offset) { |
639 | uint8_t inst = m_cfi_data.GetU8(offset_ptr: &offset); |
640 | uint8_t primary_opcode = inst & 0xC0; |
641 | uint8_t extended_opcode = inst & 0x3F; |
642 | |
643 | if (!HandleCommonDwarfOpcode(primary_opcode, extended_opcode, data_align, |
644 | offset, row&: *row)) { |
645 | if (primary_opcode) { |
646 | switch (primary_opcode) { |
647 | case DW_CFA_advance_loc: // (Row Creation Instruction) |
648 | { // 0x40 - high 2 bits are 0x1, lower 6 bits are delta |
649 | // takes a single argument that represents a constant delta. The |
650 | // required action is to create a new table row with a location value |
651 | // that is computed by taking the current entry's location value and |
652 | // adding (delta * code_align). All other values in the new row are |
653 | // initially identical to the current row. |
654 | unwind_plan.AppendRow(row_sp: row); |
655 | UnwindPlan::Row *newrow = new UnwindPlan::Row; |
656 | *newrow = *row.get(); |
657 | row.reset(p: newrow); |
658 | row->SlideOffset(offset: extended_opcode * code_align); |
659 | break; |
660 | } |
661 | |
662 | case DW_CFA_restore: { // 0xC0 - high 2 bits are 0x3, lower 6 bits are |
663 | // register |
664 | // takes a single argument that represents a register number. The |
665 | // required action is to change the rule for the indicated register |
666 | // to the rule assigned it by the initial_instructions in the CIE. |
667 | uint32_t reg_num = extended_opcode; |
668 | // We only keep enough register locations around to unwind what is in |
669 | // our thread, and these are organized by the register index in that |
670 | // state, so we need to convert our eh_frame register number from the |
671 | // EH frame info, to a register index |
672 | |
673 | if (unwind_plan.IsValidRowIndex(idx: 0) && |
674 | unwind_plan.GetRowAtIndex(idx: 0)->GetRegisterInfo(reg_num, |
675 | register_location&: reg_location)) |
676 | row->SetRegisterInfo(reg_num, register_location: reg_location); |
677 | else { |
678 | // If the register was not set in the first row, remove the |
679 | // register info to keep the unmodified value from the caller. |
680 | row->RemoveRegisterInfo(reg_num); |
681 | } |
682 | break; |
683 | } |
684 | } |
685 | } else { |
686 | switch (extended_opcode) { |
687 | case DW_CFA_set_loc: // 0x1 (Row Creation Instruction) |
688 | { |
689 | // DW_CFA_set_loc takes a single argument that represents an address. |
690 | // The required action is to create a new table row using the |
691 | // specified address as the location. All other values in the new row |
692 | // are initially identical to the current row. The new location value |
693 | // should always be greater than the current one. |
694 | unwind_plan.AppendRow(row_sp: row); |
695 | UnwindPlan::Row *newrow = new UnwindPlan::Row; |
696 | *newrow = *row.get(); |
697 | row.reset(p: newrow); |
698 | row->SetOffset(m_cfi_data.GetAddress(offset_ptr: &offset) - |
699 | startaddr.GetFileAddress()); |
700 | break; |
701 | } |
702 | |
703 | case DW_CFA_advance_loc1: // 0x2 (Row Creation Instruction) |
704 | { |
705 | // takes a single uword argument that represents a constant delta. |
706 | // This instruction is identical to DW_CFA_advance_loc except for the |
707 | // encoding and size of the delta argument. |
708 | unwind_plan.AppendRow(row_sp: row); |
709 | UnwindPlan::Row *newrow = new UnwindPlan::Row; |
710 | *newrow = *row.get(); |
711 | row.reset(p: newrow); |
712 | row->SlideOffset(offset: m_cfi_data.GetU8(offset_ptr: &offset) * code_align); |
713 | break; |
714 | } |
715 | |
716 | case DW_CFA_advance_loc2: // 0x3 (Row Creation Instruction) |
717 | { |
718 | // takes a single uword argument that represents a constant delta. |
719 | // This instruction is identical to DW_CFA_advance_loc except for the |
720 | // encoding and size of the delta argument. |
721 | unwind_plan.AppendRow(row_sp: row); |
722 | UnwindPlan::Row *newrow = new UnwindPlan::Row; |
723 | *newrow = *row.get(); |
724 | row.reset(p: newrow); |
725 | row->SlideOffset(offset: m_cfi_data.GetU16(offset_ptr: &offset) * code_align); |
726 | break; |
727 | } |
728 | |
729 | case DW_CFA_advance_loc4: // 0x4 (Row Creation Instruction) |
730 | { |
731 | // takes a single uword argument that represents a constant delta. |
732 | // This instruction is identical to DW_CFA_advance_loc except for the |
733 | // encoding and size of the delta argument. |
734 | unwind_plan.AppendRow(row_sp: row); |
735 | UnwindPlan::Row *newrow = new UnwindPlan::Row; |
736 | *newrow = *row.get(); |
737 | row.reset(p: newrow); |
738 | row->SlideOffset(offset: m_cfi_data.GetU32(offset_ptr: &offset) * code_align); |
739 | break; |
740 | } |
741 | |
742 | case DW_CFA_restore_extended: // 0x6 |
743 | { |
744 | // takes a single unsigned LEB128 argument that represents a register |
745 | // number. This instruction is identical to DW_CFA_restore except for |
746 | // the encoding and size of the register argument. |
747 | uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
748 | if (unwind_plan.IsValidRowIndex(idx: 0) && |
749 | unwind_plan.GetRowAtIndex(idx: 0)->GetRegisterInfo(reg_num, |
750 | register_location&: reg_location)) |
751 | row->SetRegisterInfo(reg_num, register_location: reg_location); |
752 | break; |
753 | } |
754 | |
755 | case DW_CFA_remember_state: // 0xA |
756 | { |
757 | // These instructions define a stack of information. Encountering the |
758 | // DW_CFA_remember_state instruction means to save the rules for |
759 | // every register on the current row on the stack. Encountering the |
760 | // DW_CFA_restore_state instruction means to pop the set of rules off |
761 | // the stack and place them in the current row. (This operation is |
762 | // useful for compilers that move epilogue code into the body of a |
763 | // function.) |
764 | stack.push_back(x: row); |
765 | UnwindPlan::Row *newrow = new UnwindPlan::Row; |
766 | *newrow = *row.get(); |
767 | row.reset(p: newrow); |
768 | break; |
769 | } |
770 | |
771 | case DW_CFA_restore_state: // 0xB |
772 | { |
773 | // These instructions define a stack of information. Encountering the |
774 | // DW_CFA_remember_state instruction means to save the rules for |
775 | // every register on the current row on the stack. Encountering the |
776 | // DW_CFA_restore_state instruction means to pop the set of rules off |
777 | // the stack and place them in the current row. (This operation is |
778 | // useful for compilers that move epilogue code into the body of a |
779 | // function.) |
780 | if (stack.empty()) { |
781 | LLDB_LOG(log, |
782 | "DWARFCallFrameInfo::{0}(dwarf_offset: " |
783 | "{1:x16}, startaddr: [{2:x16}] encountered " |
784 | "DW_CFA_restore_state but state stack " |
785 | "is empty. Corrupt unwind info?" , |
786 | __FUNCTION__, dwarf_offset, startaddr.GetFileAddress()); |
787 | break; |
788 | } |
789 | lldb::addr_t offset = row->GetOffset(); |
790 | row = stack.back(); |
791 | stack.pop_back(); |
792 | row->SetOffset(offset); |
793 | break; |
794 | } |
795 | |
796 | case DW_CFA_GNU_args_size: // 0x2e |
797 | { |
798 | // The DW_CFA_GNU_args_size instruction takes an unsigned LEB128 |
799 | // operand representing an argument size. This instruction specifies |
800 | // the total of the size of the arguments which have been pushed onto |
801 | // the stack. |
802 | |
803 | // TODO: Figure out how we should handle this. |
804 | m_cfi_data.GetULEB128(offset_ptr: &offset); |
805 | break; |
806 | } |
807 | |
808 | case DW_CFA_val_offset: // 0x14 |
809 | case DW_CFA_val_offset_sf: // 0x15 |
810 | default: |
811 | break; |
812 | } |
813 | } |
814 | } |
815 | } |
816 | unwind_plan.AppendRow(row_sp: row); |
817 | |
818 | return true; |
819 | } |
820 | |
821 | bool DWARFCallFrameInfo::HandleCommonDwarfOpcode(uint8_t primary_opcode, |
822 | uint8_t extended_opcode, |
823 | int32_t data_align, |
824 | lldb::offset_t &offset, |
825 | UnwindPlan::Row &row) { |
826 | UnwindPlan::Row::RegisterLocation reg_location; |
827 | |
828 | if (primary_opcode) { |
829 | switch (primary_opcode) { |
830 | case DW_CFA_offset: { // 0x80 - high 2 bits are 0x2, lower 6 bits are |
831 | // register |
832 | // takes two arguments: an unsigned LEB128 constant representing a |
833 | // factored offset and a register number. The required action is to |
834 | // change the rule for the register indicated by the register number to |
835 | // be an offset(N) rule with a value of (N = factored offset * |
836 | // data_align). |
837 | uint8_t reg_num = extended_opcode; |
838 | int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(offset_ptr: &offset) * data_align; |
839 | reg_location.SetAtCFAPlusOffset(op_offset); |
840 | row.SetRegisterInfo(reg_num, register_location: reg_location); |
841 | return true; |
842 | } |
843 | } |
844 | } else { |
845 | switch (extended_opcode) { |
846 | case DW_CFA_nop: // 0x0 |
847 | return true; |
848 | |
849 | case DW_CFA_offset_extended: // 0x5 |
850 | { |
851 | // takes two unsigned LEB128 arguments representing a register number and |
852 | // a factored offset. This instruction is identical to DW_CFA_offset |
853 | // except for the encoding and size of the register argument. |
854 | uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
855 | int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(offset_ptr: &offset) * data_align; |
856 | UnwindPlan::Row::RegisterLocation reg_location; |
857 | reg_location.SetAtCFAPlusOffset(op_offset); |
858 | row.SetRegisterInfo(reg_num, register_location: reg_location); |
859 | return true; |
860 | } |
861 | |
862 | case DW_CFA_undefined: // 0x7 |
863 | { |
864 | // takes a single unsigned LEB128 argument that represents a register |
865 | // number. The required action is to set the rule for the specified |
866 | // register to undefined. |
867 | uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
868 | UnwindPlan::Row::RegisterLocation reg_location; |
869 | reg_location.SetUndefined(); |
870 | row.SetRegisterInfo(reg_num, register_location: reg_location); |
871 | return true; |
872 | } |
873 | |
874 | case DW_CFA_same_value: // 0x8 |
875 | { |
876 | // takes a single unsigned LEB128 argument that represents a register |
877 | // number. The required action is to set the rule for the specified |
878 | // register to same value. |
879 | uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
880 | UnwindPlan::Row::RegisterLocation reg_location; |
881 | reg_location.SetSame(); |
882 | row.SetRegisterInfo(reg_num, register_location: reg_location); |
883 | return true; |
884 | } |
885 | |
886 | case DW_CFA_register: // 0x9 |
887 | { |
888 | // takes two unsigned LEB128 arguments representing register numbers. The |
889 | // required action is to set the rule for the first register to be the |
890 | // second register. |
891 | uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
892 | uint32_t other_reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
893 | UnwindPlan::Row::RegisterLocation reg_location; |
894 | reg_location.SetInRegister(other_reg_num); |
895 | row.SetRegisterInfo(reg_num, register_location: reg_location); |
896 | return true; |
897 | } |
898 | |
899 | case DW_CFA_def_cfa: // 0xC (CFA Definition Instruction) |
900 | { |
901 | // Takes two unsigned LEB128 operands representing a register number and |
902 | // a (non-factored) offset. The required action is to define the current |
903 | // CFA rule to use the provided register and offset. |
904 | uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
905 | int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
906 | row.GetCFAValue().SetIsRegisterPlusOffset(reg_num, offset: op_offset); |
907 | return true; |
908 | } |
909 | |
910 | case DW_CFA_def_cfa_register: // 0xD (CFA Definition Instruction) |
911 | { |
912 | // takes a single unsigned LEB128 argument representing a register |
913 | // number. The required action is to define the current CFA rule to use |
914 | // the provided register (but to keep the old offset). |
915 | uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
916 | row.GetCFAValue().SetIsRegisterPlusOffset(reg_num, |
917 | offset: row.GetCFAValue().GetOffset()); |
918 | return true; |
919 | } |
920 | |
921 | case DW_CFA_def_cfa_offset: // 0xE (CFA Definition Instruction) |
922 | { |
923 | // Takes a single unsigned LEB128 operand representing a (non-factored) |
924 | // offset. The required action is to define the current CFA rule to use |
925 | // the provided offset (but to keep the old register). |
926 | int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
927 | row.GetCFAValue().SetIsRegisterPlusOffset( |
928 | reg_num: row.GetCFAValue().GetRegisterNumber(), offset: op_offset); |
929 | return true; |
930 | } |
931 | |
932 | case DW_CFA_def_cfa_expression: // 0xF (CFA Definition Instruction) |
933 | { |
934 | size_t block_len = (size_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
935 | const uint8_t *block_data = |
936 | static_cast<const uint8_t *>(m_cfi_data.GetData(offset_ptr: &offset, length: block_len)); |
937 | row.GetCFAValue().SetIsDWARFExpression(opcodes: block_data, len: block_len); |
938 | return true; |
939 | } |
940 | |
941 | case DW_CFA_expression: // 0x10 |
942 | { |
943 | // Takes two operands: an unsigned LEB128 value representing a register |
944 | // number, and a DW_FORM_block value representing a DWARF expression. The |
945 | // required action is to change the rule for the register indicated by |
946 | // the register number to be an expression(E) rule where E is the DWARF |
947 | // expression. That is, the DWARF expression computes the address. The |
948 | // value of the CFA is pushed on the DWARF evaluation stack prior to |
949 | // execution of the DWARF expression. |
950 | uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
951 | uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
952 | const uint8_t *block_data = |
953 | static_cast<const uint8_t *>(m_cfi_data.GetData(offset_ptr: &offset, length: block_len)); |
954 | UnwindPlan::Row::RegisterLocation reg_location; |
955 | reg_location.SetAtDWARFExpression(opcodes: block_data, len: block_len); |
956 | row.SetRegisterInfo(reg_num, register_location: reg_location); |
957 | return true; |
958 | } |
959 | |
960 | case DW_CFA_offset_extended_sf: // 0x11 |
961 | { |
962 | // takes two operands: an unsigned LEB128 value representing a register |
963 | // number and a signed LEB128 factored offset. This instruction is |
964 | // identical to DW_CFA_offset_extended except that the second operand is |
965 | // signed and factored. |
966 | uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
967 | int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(offset_ptr: &offset) * data_align; |
968 | UnwindPlan::Row::RegisterLocation reg_location; |
969 | reg_location.SetAtCFAPlusOffset(op_offset); |
970 | row.SetRegisterInfo(reg_num, register_location: reg_location); |
971 | return true; |
972 | } |
973 | |
974 | case DW_CFA_def_cfa_sf: // 0x12 (CFA Definition Instruction) |
975 | { |
976 | // Takes two operands: an unsigned LEB128 value representing a register |
977 | // number and a signed LEB128 factored offset. This instruction is |
978 | // identical to DW_CFA_def_cfa except that the second operand is signed |
979 | // and factored. |
980 | uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
981 | int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(offset_ptr: &offset) * data_align; |
982 | row.GetCFAValue().SetIsRegisterPlusOffset(reg_num, offset: op_offset); |
983 | return true; |
984 | } |
985 | |
986 | case DW_CFA_def_cfa_offset_sf: // 0x13 (CFA Definition Instruction) |
987 | { |
988 | // takes a signed LEB128 operand representing a factored offset. This |
989 | // instruction is identical to DW_CFA_def_cfa_offset except that the |
990 | // operand is signed and factored. |
991 | int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(offset_ptr: &offset) * data_align; |
992 | uint32_t cfa_regnum = row.GetCFAValue().GetRegisterNumber(); |
993 | row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: cfa_regnum, offset: op_offset); |
994 | return true; |
995 | } |
996 | |
997 | case DW_CFA_val_expression: // 0x16 |
998 | { |
999 | // takes two operands: an unsigned LEB128 value representing a register |
1000 | // number, and a DW_FORM_block value representing a DWARF expression. The |
1001 | // required action is to change the rule for the register indicated by |
1002 | // the register number to be a val_expression(E) rule where E is the |
1003 | // DWARF expression. That is, the DWARF expression computes the value of |
1004 | // the given register. The value of the CFA is pushed on the DWARF |
1005 | // evaluation stack prior to execution of the DWARF expression. |
1006 | uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
1007 | uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(offset_ptr: &offset); |
1008 | const uint8_t *block_data = |
1009 | (const uint8_t *)m_cfi_data.GetData(offset_ptr: &offset, length: block_len); |
1010 | reg_location.SetIsDWARFExpression(opcodes: block_data, len: block_len); |
1011 | row.SetRegisterInfo(reg_num, register_location: reg_location); |
1012 | return true; |
1013 | } |
1014 | } |
1015 | } |
1016 | return false; |
1017 | } |
1018 | |
1019 | void DWARFCallFrameInfo::ForEachFDEEntries( |
1020 | const std::function<bool(lldb::addr_t, uint32_t, dw_offset_t)> &callback) { |
1021 | GetFDEIndex(); |
1022 | |
1023 | for (size_t i = 0, c = m_fde_index.GetSize(); i < c; ++i) { |
1024 | const FDEEntryMap::Entry &entry = m_fde_index.GetEntryRef(i); |
1025 | if (!callback(entry.base, entry.size, entry.data)) |
1026 | break; |
1027 | } |
1028 | } |
1029 | |