[lld][WebAssembly] Perform data relocations during start function
[llvm-project.git] / lldb / source / Symbol / UnwindPlan.cpp
blob5547998691db4df4214a4d983dcd1657bd84ffd4
1 //===-- UnwindPlan.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 //===----------------------------------------------------------------------===//
9 #include "lldb/Symbol/UnwindPlan.h"
11 #include "lldb/Target/Process.h"
12 #include "lldb/Target/RegisterContext.h"
13 #include "lldb/Target/Target.h"
14 #include "lldb/Target/Thread.h"
15 #include "lldb/Utility/ConstString.h"
16 #include "lldb/Utility/Log.h"
17 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
19 using namespace lldb;
20 using namespace lldb_private;
22 bool UnwindPlan::Row::RegisterLocation::
23 operator==(const UnwindPlan::Row::RegisterLocation &rhs) const {
24 if (m_type == rhs.m_type) {
25 switch (m_type) {
26 case unspecified:
27 case undefined:
28 case same:
29 return true;
31 case atCFAPlusOffset:
32 case isCFAPlusOffset:
33 case atAFAPlusOffset:
34 case isAFAPlusOffset:
35 return m_location.offset == rhs.m_location.offset;
37 case inOtherRegister:
38 return m_location.reg_num == rhs.m_location.reg_num;
40 case atDWARFExpression:
41 case isDWARFExpression:
42 if (m_location.expr.length == rhs.m_location.expr.length)
43 return !memcmp(m_location.expr.opcodes, rhs.m_location.expr.opcodes,
44 m_location.expr.length);
45 break;
48 return false;
51 // This function doesn't copy the dwarf expression bytes; they must remain in
52 // allocated memory for the lifespan of this UnwindPlan object.
53 void UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression(
54 const uint8_t *opcodes, uint32_t len) {
55 m_type = atDWARFExpression;
56 m_location.expr.opcodes = opcodes;
57 m_location.expr.length = len;
60 // This function doesn't copy the dwarf expression bytes; they must remain in
61 // allocated memory for the lifespan of this UnwindPlan object.
62 void UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression(
63 const uint8_t *opcodes, uint32_t len) {
64 m_type = isDWARFExpression;
65 m_location.expr.opcodes = opcodes;
66 m_location.expr.length = len;
69 static llvm::Optional<std::pair<lldb::ByteOrder, uint32_t>>
70 GetByteOrderAndAddrSize(Thread *thread) {
71 if (!thread)
72 return llvm::None;
73 ProcessSP process_sp = thread->GetProcess();
74 if (!process_sp)
75 return llvm::None;
76 ArchSpec arch = process_sp->GetTarget().GetArchitecture();
77 return std::make_pair(arch.GetByteOrder(), arch.GetAddressByteSize());
80 static void DumpDWARFExpr(Stream &s, llvm::ArrayRef<uint8_t> expr, Thread *thread) {
81 if (auto order_and_width = GetByteOrderAndAddrSize(thread)) {
82 llvm::DataExtractor data(expr, order_and_width->first == eByteOrderLittle,
83 order_and_width->second);
84 llvm::DWARFExpression(data, order_and_width->second, llvm::dwarf::DWARF32)
85 .print(s.AsRawOstream(), llvm::DIDumpOptions(), nullptr, nullptr);
86 } else
87 s.PutCString("dwarf-expr");
90 void UnwindPlan::Row::RegisterLocation::Dump(Stream &s,
91 const UnwindPlan *unwind_plan,
92 const UnwindPlan::Row *row,
93 Thread *thread,
94 bool verbose) const {
95 switch (m_type) {
96 case unspecified:
97 if (verbose)
98 s.PutCString("=<unspec>");
99 else
100 s.PutCString("=!");
101 break;
102 case undefined:
103 if (verbose)
104 s.PutCString("=<undef>");
105 else
106 s.PutCString("=?");
107 break;
108 case same:
109 s.PutCString("= <same>");
110 break;
112 case atCFAPlusOffset:
113 case isCFAPlusOffset: {
114 s.PutChar('=');
115 if (m_type == atCFAPlusOffset)
116 s.PutChar('[');
117 s.Printf("CFA%+d", m_location.offset);
118 if (m_type == atCFAPlusOffset)
119 s.PutChar(']');
120 } break;
122 case atAFAPlusOffset:
123 case isAFAPlusOffset: {
124 s.PutChar('=');
125 if (m_type == atAFAPlusOffset)
126 s.PutChar('[');
127 s.Printf("AFA%+d", m_location.offset);
128 if (m_type == atAFAPlusOffset)
129 s.PutChar(']');
130 } break;
132 case inOtherRegister: {
133 const RegisterInfo *other_reg_info = nullptr;
134 if (unwind_plan)
135 other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num);
136 if (other_reg_info)
137 s.Printf("=%s", other_reg_info->name);
138 else
139 s.Printf("=reg(%u)", m_location.reg_num);
140 } break;
142 case atDWARFExpression:
143 case isDWARFExpression: {
144 s.PutChar('=');
145 if (m_type == atDWARFExpression)
146 s.PutChar('[');
147 DumpDWARFExpr(
148 s, llvm::makeArrayRef(m_location.expr.opcodes, m_location.expr.length),
149 thread);
150 if (m_type == atDWARFExpression)
151 s.PutChar(']');
152 } break;
156 static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,
157 Thread *thread, uint32_t reg_num) {
158 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num);
159 if (reg_info)
160 s.PutCString(reg_info->name);
161 else
162 s.Printf("reg(%u)", reg_num);
165 bool UnwindPlan::Row::FAValue::
166 operator==(const UnwindPlan::Row::FAValue &rhs) const {
167 if (m_type == rhs.m_type) {
168 switch (m_type) {
169 case unspecified:
170 case isRaSearch:
171 return m_value.ra_search_offset == rhs.m_value.ra_search_offset;
173 case isRegisterPlusOffset:
174 return m_value.reg.offset == rhs.m_value.reg.offset;
176 case isRegisterDereferenced:
177 return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
179 case isDWARFExpression:
180 if (m_value.expr.length == rhs.m_value.expr.length)
181 return !memcmp(m_value.expr.opcodes, rhs.m_value.expr.opcodes,
182 m_value.expr.length);
183 break;
186 return false;
189 void UnwindPlan::Row::FAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
190 Thread *thread) const {
191 switch (m_type) {
192 case isRegisterPlusOffset:
193 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
194 s.Printf("%+3d", m_value.reg.offset);
195 break;
196 case isRegisterDereferenced:
197 s.PutChar('[');
198 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
199 s.PutChar(']');
200 break;
201 case isDWARFExpression:
202 DumpDWARFExpr(s,
203 llvm::makeArrayRef(m_value.expr.opcodes, m_value.expr.length),
204 thread);
205 break;
206 case unspecified:
207 s.PutCString("unspecified");
208 break;
209 case isRaSearch:
210 s.Printf("RaSearch@SP%+d", m_value.ra_search_offset);
211 break;
215 void UnwindPlan::Row::Clear() {
216 m_cfa_value.SetUnspecified();
217 m_afa_value.SetUnspecified();
218 m_offset = 0;
219 m_unspecified_registers_are_undefined = false;
220 m_register_locations.clear();
223 void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
224 Thread *thread, addr_t base_addr) const {
225 if (base_addr != LLDB_INVALID_ADDRESS)
226 s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
227 else
228 s.Printf("%4" PRId64 ": CFA=", GetOffset());
230 m_cfa_value.Dump(s, unwind_plan, thread);
232 if (!m_afa_value.IsUnspecified()) {
233 s.Printf(" AFA=");
234 m_afa_value.Dump(s, unwind_plan, thread);
237 s.Printf(" => ");
238 for (collection::const_iterator idx = m_register_locations.begin();
239 idx != m_register_locations.end(); ++idx) {
240 DumpRegisterName(s, unwind_plan, thread, idx->first);
241 const bool verbose = false;
242 idx->second.Dump(s, unwind_plan, this, thread, verbose);
243 s.PutChar(' ');
247 UnwindPlan::Row::Row() : m_cfa_value(), m_afa_value(), m_register_locations() {}
249 bool UnwindPlan::Row::GetRegisterInfo(
250 uint32_t reg_num,
251 UnwindPlan::Row::RegisterLocation &register_location) const {
252 collection::const_iterator pos = m_register_locations.find(reg_num);
253 if (pos != m_register_locations.end()) {
254 register_location = pos->second;
255 return true;
257 if (m_unspecified_registers_are_undefined) {
258 register_location.SetUndefined();
259 return true;
261 return false;
264 void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) {
265 collection::const_iterator pos = m_register_locations.find(reg_num);
266 if (pos != m_register_locations.end()) {
267 m_register_locations.erase(pos);
271 void UnwindPlan::Row::SetRegisterInfo(
272 uint32_t reg_num,
273 const UnwindPlan::Row::RegisterLocation register_location) {
274 m_register_locations[reg_num] = register_location;
277 bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,
278 int32_t offset,
279 bool can_replace) {
280 if (!can_replace &&
281 m_register_locations.find(reg_num) != m_register_locations.end())
282 return false;
283 RegisterLocation reg_loc;
284 reg_loc.SetAtCFAPlusOffset(offset);
285 m_register_locations[reg_num] = reg_loc;
286 return true;
289 bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,
290 int32_t offset,
291 bool can_replace) {
292 if (!can_replace &&
293 m_register_locations.find(reg_num) != m_register_locations.end())
294 return false;
295 RegisterLocation reg_loc;
296 reg_loc.SetIsCFAPlusOffset(offset);
297 m_register_locations[reg_num] = reg_loc;
298 return true;
301 bool UnwindPlan::Row::SetRegisterLocationToUndefined(
302 uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) {
303 collection::iterator pos = m_register_locations.find(reg_num);
304 collection::iterator end = m_register_locations.end();
306 if (pos != end) {
307 if (!can_replace)
308 return false;
309 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
310 return false;
312 RegisterLocation reg_loc;
313 reg_loc.SetUndefined();
314 m_register_locations[reg_num] = reg_loc;
315 return true;
318 bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num,
319 bool can_replace) {
320 if (!can_replace &&
321 m_register_locations.find(reg_num) != m_register_locations.end())
322 return false;
323 RegisterLocation reg_loc;
324 reg_loc.SetUnspecified();
325 m_register_locations[reg_num] = reg_loc;
326 return true;
329 bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num,
330 uint32_t other_reg_num,
331 bool can_replace) {
332 if (!can_replace &&
333 m_register_locations.find(reg_num) != m_register_locations.end())
334 return false;
335 RegisterLocation reg_loc;
336 reg_loc.SetInRegister(other_reg_num);
337 m_register_locations[reg_num] = reg_loc;
338 return true;
341 bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,
342 bool must_replace) {
343 if (must_replace &&
344 m_register_locations.find(reg_num) == m_register_locations.end())
345 return false;
346 RegisterLocation reg_loc;
347 reg_loc.SetSame();
348 m_register_locations[reg_num] = reg_loc;
349 return true;
352 bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
353 return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
354 m_afa_value == rhs.m_afa_value &&
355 m_unspecified_registers_are_undefined ==
356 rhs.m_unspecified_registers_are_undefined &&
357 m_register_locations == rhs.m_register_locations;
360 void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) {
361 if (m_row_list.empty() ||
362 m_row_list.back()->GetOffset() != row_sp->GetOffset())
363 m_row_list.push_back(row_sp);
364 else
365 m_row_list.back() = row_sp;
368 void UnwindPlan::InsertRow(const UnwindPlan::RowSP &row_sp,
369 bool replace_existing) {
370 collection::iterator it = m_row_list.begin();
371 while (it != m_row_list.end()) {
372 RowSP row = *it;
373 if (row->GetOffset() >= row_sp->GetOffset())
374 break;
375 it++;
377 if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
378 m_row_list.insert(it, row_sp);
379 else if (replace_existing)
380 *it = row_sp;
383 UnwindPlan::RowSP UnwindPlan::GetRowForFunctionOffset(int offset) const {
384 RowSP row;
385 if (!m_row_list.empty()) {
386 if (offset == -1)
387 row = m_row_list.back();
388 else {
389 collection::const_iterator pos, end = m_row_list.end();
390 for (pos = m_row_list.begin(); pos != end; ++pos) {
391 if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
392 row = *pos;
393 else
394 break;
398 return row;
401 bool UnwindPlan::IsValidRowIndex(uint32_t idx) const {
402 return idx < m_row_list.size();
405 const UnwindPlan::RowSP UnwindPlan::GetRowAtIndex(uint32_t idx) const {
406 if (idx < m_row_list.size())
407 return m_row_list[idx];
408 else {
409 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
410 LLDB_LOGF(log,
411 "error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index "
412 "(number rows is %u)",
413 idx, (uint32_t)m_row_list.size());
414 return UnwindPlan::RowSP();
418 const UnwindPlan::RowSP UnwindPlan::GetLastRow() const {
419 if (m_row_list.empty()) {
420 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
421 LLDB_LOGF(log, "UnwindPlan::GetLastRow() when rows are empty");
422 return UnwindPlan::RowSP();
424 return m_row_list.back();
427 int UnwindPlan::GetRowCount() const { return m_row_list.size(); }
429 void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) {
430 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
431 m_plan_valid_address_range = range;
434 bool UnwindPlan::PlanValidAtAddress(Address addr) {
435 // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
436 if (GetRowCount() == 0) {
437 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
438 if (log) {
439 StreamString s;
440 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
441 LLDB_LOGF(log,
442 "UnwindPlan is invalid -- no unwind rows for UnwindPlan "
443 "'%s' at address %s",
444 m_source_name.GetCString(), s.GetData());
445 } else {
446 LLDB_LOGF(log,
447 "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
448 m_source_name.GetCString());
451 return false;
454 // If the 0th Row of unwind instructions is missing, or if it doesn't provide
455 // a register to use to find the Canonical Frame Address, this is not a valid
456 // UnwindPlan.
457 if (GetRowAtIndex(0).get() == nullptr ||
458 GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
459 Row::FAValue::unspecified) {
460 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
461 if (log) {
462 StreamString s;
463 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
464 LLDB_LOGF(log,
465 "UnwindPlan is invalid -- no CFA register defined in row 0 "
466 "for UnwindPlan '%s' at address %s",
467 m_source_name.GetCString(), s.GetData());
468 } else {
469 LLDB_LOGF(log,
470 "UnwindPlan is invalid -- no CFA register defined in row 0 "
471 "for UnwindPlan '%s'",
472 m_source_name.GetCString());
475 return false;
478 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() ||
479 m_plan_valid_address_range.GetByteSize() == 0)
480 return true;
482 if (!addr.IsValid())
483 return true;
485 if (m_plan_valid_address_range.ContainsFileAddress(addr))
486 return true;
488 return false;
491 void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
492 if (!m_source_name.IsEmpty()) {
493 s.Printf("This UnwindPlan originally sourced from %s\n",
494 m_source_name.GetCString());
496 if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) {
497 TargetSP target_sp(thread->CalculateTarget());
498 addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get());
499 addr_t personality_func_load_addr =
500 m_personality_func_addr.GetLoadAddress(target_sp.get());
502 if (lsda_load_addr != LLDB_INVALID_ADDRESS &&
503 personality_func_load_addr != LLDB_INVALID_ADDRESS) {
504 s.Printf("LSDA address 0x%" PRIx64
505 ", personality routine is at address 0x%" PRIx64 "\n",
506 lsda_load_addr, personality_func_load_addr);
509 s.Printf("This UnwindPlan is sourced from the compiler: ");
510 switch (m_plan_is_sourced_from_compiler) {
511 case eLazyBoolYes:
512 s.Printf("yes.\n");
513 break;
514 case eLazyBoolNo:
515 s.Printf("no.\n");
516 break;
517 case eLazyBoolCalculate:
518 s.Printf("not specified.\n");
519 break;
521 s.Printf("This UnwindPlan is valid at all instruction locations: ");
522 switch (m_plan_is_valid_at_all_instruction_locations) {
523 case eLazyBoolYes:
524 s.Printf("yes.\n");
525 break;
526 case eLazyBoolNo:
527 s.Printf("no.\n");
528 break;
529 case eLazyBoolCalculate:
530 s.Printf("not specified.\n");
531 break;
533 s.Printf("This UnwindPlan is for a trap handler function: ");
534 switch (m_plan_is_for_signal_trap) {
535 case eLazyBoolYes:
536 s.Printf("yes.\n");
537 break;
538 case eLazyBoolNo:
539 s.Printf("no.\n");
540 break;
541 case eLazyBoolCalculate:
542 s.Printf("not specified.\n");
543 break;
545 if (m_plan_valid_address_range.GetBaseAddress().IsValid() &&
546 m_plan_valid_address_range.GetByteSize() > 0) {
547 s.PutCString("Address range of this UnwindPlan: ");
548 TargetSP target_sp(thread->CalculateTarget());
549 m_plan_valid_address_range.Dump(&s, target_sp.get(),
550 Address::DumpStyleSectionNameOffset);
551 s.EOL();
553 collection::const_iterator pos, begin = m_row_list.begin(),
554 end = m_row_list.end();
555 for (pos = begin; pos != end; ++pos) {
556 s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos));
557 (*pos)->Dump(s, this, thread, base_addr);
558 s.Printf("\n");
562 void UnwindPlan::SetSourceName(const char *source) {
563 m_source_name = ConstString(source);
566 ConstString UnwindPlan::GetSourceName() const { return m_source_name; }
568 const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread,
569 uint32_t unwind_reg) const {
570 if (thread) {
571 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
572 if (reg_ctx) {
573 uint32_t reg;
574 if (m_register_kind == eRegisterKindLLDB)
575 reg = unwind_reg;
576 else
577 reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind,
578 unwind_reg);
579 if (reg != LLDB_INVALID_REGNUM)
580 return reg_ctx->GetRegisterInfoAtIndex(reg);
583 return nullptr;