blob: 23ca1324ab06b7110db4d3966d9f10d7f2ac4bca [file] [log] [blame]
Jason Molendafbcb7f22010-09-10 07:49:16 +00001//===-- UnwindPlan.cpp ----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/Symbol/UnwindPlan.h"
Greg Clayton79ea8782011-04-26 23:48:45 +000011
Greg Claytonf5e56de2010-09-14 23:36:40 +000012#include "lldb/Target/Process.h"
Jason Molendafbcb7f22010-09-10 07:49:16 +000013#include "lldb/Target/RegisterContext.h"
Greg Claytonf5e56de2010-09-14 23:36:40 +000014#include "lldb/Target/Thread.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000015#include "lldb/Utility/ConstString.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000016#include "lldb/Utility/Log.h"
Jason Molendafbcb7f22010-09-10 07:49:16 +000017
18using namespace lldb;
19using namespace lldb_private;
20
Kate Stoneb9c1b512016-09-06 20:57:50 +000021bool UnwindPlan::Row::RegisterLocation::
22operator==(const UnwindPlan::Row::RegisterLocation &rhs) const {
23 if (m_type == rhs.m_type) {
24 switch (m_type) {
25 case unspecified:
26 case undefined:
27 case same:
28 return true;
Greg Clayton31f1d2f2011-05-11 18:39:18 +000029
Kate Stoneb9c1b512016-09-06 20:57:50 +000030 case atCFAPlusOffset:
31 case isCFAPlusOffset:
32 return m_location.offset == rhs.m_location.offset;
Jason Molendafbcb7f22010-09-10 07:49:16 +000033
Kate Stoneb9c1b512016-09-06 20:57:50 +000034 case inOtherRegister:
35 return m_location.reg_num == rhs.m_location.reg_num;
Jason Molendafbcb7f22010-09-10 07:49:16 +000036
Kate Stoneb9c1b512016-09-06 20:57:50 +000037 case atDWARFExpression:
Pavel Labathab970f52015-02-23 10:19:16 +000038 case isDWARFExpression:
Kate Stoneb9c1b512016-09-06 20:57:50 +000039 if (m_location.expr.length == rhs.m_location.expr.length)
40 return !memcmp(m_location.expr.opcodes, rhs.m_location.expr.opcodes,
41 m_location.expr.length);
42 break;
Pavel Labathab970f52015-02-23 10:19:16 +000043 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000044 }
45 return false;
Pavel Labathab970f52015-02-23 10:19:16 +000046}
47
Kate Stoneb9c1b512016-09-06 20:57:50 +000048// This function doesn't copy the dwarf expression bytes; they must remain in
Adrian Prantl05097242018-04-30 16:49:04 +000049// allocated memory for the lifespan of this UnwindPlan object.
Kate Stoneb9c1b512016-09-06 20:57:50 +000050void UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression(
51 const uint8_t *opcodes, uint32_t len) {
52 m_type = atDWARFExpression;
53 m_location.expr.opcodes = opcodes;
54 m_location.expr.length = len;
Jason Molendafbcb7f22010-09-10 07:49:16 +000055}
56
Kate Stoneb9c1b512016-09-06 20:57:50 +000057// This function doesn't copy the dwarf expression bytes; they must remain in
Adrian Prantl05097242018-04-30 16:49:04 +000058// allocated memory for the lifespan of this UnwindPlan object.
Kate Stoneb9c1b512016-09-06 20:57:50 +000059void UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression(
60 const uint8_t *opcodes, uint32_t len) {
61 m_type = isDWARFExpression;
62 m_location.expr.opcodes = opcodes;
63 m_location.expr.length = len;
64}
65
66void UnwindPlan::Row::RegisterLocation::Dump(Stream &s,
67 const UnwindPlan *unwind_plan,
68 const UnwindPlan::Row *row,
69 Thread *thread,
70 bool verbose) const {
71 switch (m_type) {
72 case unspecified:
73 if (verbose)
74 s.PutCString("=<unspec>");
Jason Molendafbcb7f22010-09-10 07:49:16 +000075 else
Kate Stoneb9c1b512016-09-06 20:57:50 +000076 s.PutCString("=!");
77 break;
78 case undefined:
79 if (verbose)
80 s.PutCString("=<undef>");
81 else
82 s.PutCString("=?");
83 break;
84 case same:
85 s.PutCString("= <same>");
86 break;
87
88 case atCFAPlusOffset:
89 case isCFAPlusOffset: {
90 s.PutChar('=');
91 if (m_type == atCFAPlusOffset)
92 s.PutChar('[');
93 s.Printf("CFA%+d", m_location.offset);
94 if (m_type == atCFAPlusOffset)
95 s.PutChar(']');
96 } break;
97
98 case inOtherRegister: {
99 const RegisterInfo *other_reg_info = nullptr;
100 if (unwind_plan)
101 other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num);
102 if (other_reg_info)
103 s.Printf("=%s", other_reg_info->name);
104 else
105 s.Printf("=reg(%u)", m_location.reg_num);
106 } break;
107
108 case atDWARFExpression:
109 case isDWARFExpression: {
110 s.PutChar('=');
111 if (m_type == atDWARFExpression)
112 s.PutCString("[dwarf-expr]");
113 else
114 s.PutCString("dwarf-expr");
115 } break;
116 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000117}
118
Kate Stoneb9c1b512016-09-06 20:57:50 +0000119static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,
120 Thread *thread, uint32_t reg_num) {
121 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num);
122 if (reg_info)
123 s.PutCString(reg_info->name);
124 else
125 s.Printf("reg(%u)", reg_num);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000126}
127
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128bool UnwindPlan::Row::CFAValue::
129operator==(const UnwindPlan::Row::CFAValue &rhs) const {
130 if (m_type == rhs.m_type) {
131 switch (m_type) {
132 case unspecified:
133 return true;
134
135 case isRegisterPlusOffset:
136 return m_value.reg.offset == rhs.m_value.reg.offset;
137
138 case isRegisterDereferenced:
139 return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
140
141 case isDWARFExpression:
142 if (m_value.expr.length == rhs.m_value.expr.length)
143 return !memcmp(m_value.expr.opcodes, rhs.m_value.expr.opcodes,
144 m_value.expr.length);
145 break;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000146 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 }
148 return false;
149}
150
151void UnwindPlan::Row::CFAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
152 Thread *thread) const {
153 switch (m_type) {
154 case isRegisterPlusOffset:
155 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
156 s.Printf("%+3d", m_value.reg.offset);
157 break;
158 case isRegisterDereferenced:
159 s.PutChar('[');
160 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
161 s.PutChar(']');
162 break;
163 case isDWARFExpression:
164 s.PutCString("dwarf-expr");
165 break;
166 default:
167 s.PutCString("unspecified");
168 break;
169 }
170}
171
172void UnwindPlan::Row::Clear() {
173 m_cfa_value.SetUnspecified();
174 m_offset = 0;
175 m_register_locations.clear();
176}
177
178void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
179 Thread *thread, addr_t base_addr) const {
180 if (base_addr != LLDB_INVALID_ADDRESS)
181 s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
182 else
183 s.Printf("%4" PRId64 ": CFA=", GetOffset());
184
185 m_cfa_value.Dump(s, unwind_plan, thread);
186 s.Printf(" => ");
187 for (collection::const_iterator idx = m_register_locations.begin();
188 idx != m_register_locations.end(); ++idx) {
189 DumpRegisterName(s, unwind_plan, thread, idx->first);
190 const bool verbose = false;
191 idx->second.Dump(s, unwind_plan, this, thread, verbose);
192 s.PutChar(' ');
193 }
194 s.EOL();
195}
196
197UnwindPlan::Row::Row() : m_offset(0), m_cfa_value(), m_register_locations() {}
198
199bool UnwindPlan::Row::GetRegisterInfo(
200 uint32_t reg_num,
201 UnwindPlan::Row::RegisterLocation &register_location) const {
202 collection::const_iterator pos = m_register_locations.find(reg_num);
203 if (pos != m_register_locations.end()) {
204 register_location = pos->second;
205 return true;
206 }
207 return false;
208}
209
210void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) {
211 collection::const_iterator pos = m_register_locations.find(reg_num);
212 if (pos != m_register_locations.end()) {
213 m_register_locations.erase(pos);
214 }
215}
216
217void UnwindPlan::Row::SetRegisterInfo(
218 uint32_t reg_num,
219 const UnwindPlan::Row::RegisterLocation register_location) {
220 m_register_locations[reg_num] = register_location;
221}
222
223bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,
224 int32_t offset,
225 bool can_replace) {
226 if (!can_replace &&
227 m_register_locations.find(reg_num) != m_register_locations.end())
Jason Molendafbcb7f22010-09-10 07:49:16 +0000228 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000229 RegisterLocation reg_loc;
230 reg_loc.SetAtCFAPlusOffset(offset);
231 m_register_locations[reg_num] = reg_loc;
232 return true;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000233}
234
Kate Stoneb9c1b512016-09-06 20:57:50 +0000235bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,
236 int32_t offset,
237 bool can_replace) {
238 if (!can_replace &&
239 m_register_locations.find(reg_num) != m_register_locations.end())
240 return false;
241 RegisterLocation reg_loc;
242 reg_loc.SetIsCFAPlusOffset(offset);
243 m_register_locations[reg_num] = reg_loc;
244 return true;
Jason Molenda34549b82015-01-13 06:04:04 +0000245}
246
Kate Stoneb9c1b512016-09-06 20:57:50 +0000247bool UnwindPlan::Row::SetRegisterLocationToUndefined(
248 uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) {
249 collection::iterator pos = m_register_locations.find(reg_num);
250 collection::iterator end = m_register_locations.end();
251
252 if (pos != end) {
253 if (!can_replace)
254 return false;
255 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
256 return false;
257 }
258 RegisterLocation reg_loc;
259 reg_loc.SetUndefined();
260 m_register_locations[reg_num] = reg_loc;
261 return true;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000262}
263
Kate Stoneb9c1b512016-09-06 20:57:50 +0000264bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num,
265 bool can_replace) {
266 if (!can_replace &&
267 m_register_locations.find(reg_num) != m_register_locations.end())
268 return false;
269 RegisterLocation reg_loc;
270 reg_loc.SetUnspecified();
271 m_register_locations[reg_num] = reg_loc;
272 return true;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000273}
274
Kate Stoneb9c1b512016-09-06 20:57:50 +0000275bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num,
276 uint32_t other_reg_num,
277 bool can_replace) {
278 if (!can_replace &&
279 m_register_locations.find(reg_num) != m_register_locations.end())
280 return false;
281 RegisterLocation reg_loc;
282 reg_loc.SetInRegister(other_reg_num);
283 m_register_locations[reg_num] = reg_loc;
284 return true;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000285}
286
Kate Stoneb9c1b512016-09-06 20:57:50 +0000287bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,
288 bool must_replace) {
289 if (must_replace &&
290 m_register_locations.find(reg_num) == m_register_locations.end())
291 return false;
292 RegisterLocation reg_loc;
293 reg_loc.SetSame();
294 m_register_locations[reg_num] = reg_loc;
295 return true;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000296}
297
Kate Stoneb9c1b512016-09-06 20:57:50 +0000298bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
299 return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
300 m_register_locations == rhs.m_register_locations;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000301}
302
Kate Stoneb9c1b512016-09-06 20:57:50 +0000303void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) {
304 if (m_row_list.empty() ||
305 m_row_list.back()->GetOffset() != row_sp->GetOffset())
306 m_row_list.push_back(row_sp);
307 else
308 m_row_list.back() = row_sp;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000309}
310
Kate Stoneb9c1b512016-09-06 20:57:50 +0000311void UnwindPlan::InsertRow(const UnwindPlan::RowSP &row_sp,
312 bool replace_existing) {
313 collection::iterator it = m_row_list.begin();
314 while (it != m_row_list.end()) {
315 RowSP row = *it;
316 if (row->GetOffset() >= row_sp->GetOffset())
317 break;
318 it++;
319 }
320 if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
321 m_row_list.insert(it, row_sp);
322 else if (replace_existing)
323 *it = row_sp;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000324}
325
Kate Stoneb9c1b512016-09-06 20:57:50 +0000326UnwindPlan::RowSP UnwindPlan::GetRowForFunctionOffset(int offset) const {
327 RowSP row;
328 if (!m_row_list.empty()) {
329 if (offset == -1)
330 row = m_row_list.back();
331 else {
332 collection::const_iterator pos, end = m_row_list.end();
333 for (pos = m_row_list.begin(); pos != end; ++pos) {
334 if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
335 row = *pos;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000336 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000337 break;
338 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000339 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000340 }
341 return row;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000342}
343
Kate Stoneb9c1b512016-09-06 20:57:50 +0000344bool UnwindPlan::IsValidRowIndex(uint32_t idx) const {
345 return idx < m_row_list.size();
Jason Molendafbcb7f22010-09-10 07:49:16 +0000346}
347
Kate Stoneb9c1b512016-09-06 20:57:50 +0000348const UnwindPlan::RowSP UnwindPlan::GetRowAtIndex(uint32_t idx) const {
349 if (idx < m_row_list.size())
350 return m_row_list[idx];
351 else {
352 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
353 if (log)
354 log->Printf("error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index "
355 "(number rows is %u)",
356 idx, (uint32_t)m_row_list.size());
357 return UnwindPlan::RowSP();
358 }
359}
360
361const UnwindPlan::RowSP UnwindPlan::GetLastRow() const {
362 if (m_row_list.empty()) {
363 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
364 if (log)
365 log->Printf("UnwindPlan::GetLastRow() when rows are empty");
366 return UnwindPlan::RowSP();
367 }
368 return m_row_list.back();
369}
370
371int UnwindPlan::GetRowCount() const { return m_row_list.size(); }
372
373void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) {
374 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
375 m_plan_valid_address_range = range;
376}
377
378bool UnwindPlan::PlanValidAtAddress(Address addr) {
379 // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
380 if (GetRowCount() == 0) {
381 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
382 if (log) {
383 StreamString s;
384 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
385 log->Printf("UnwindPlan is invalid -- no unwind rows for UnwindPlan "
386 "'%s' at address %s",
387 m_source_name.GetCString(), s.GetData());
388 } else {
389 log->Printf(
390 "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
391 m_source_name.GetCString());
392 }
Greg Claytond28fae82016-07-12 23:07:50 +0000393 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000394 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000395 }
396
397 // If the 0th Row of unwind instructions is missing, or if it doesn't provide
398 // a register to use to find the Canonical Frame Address, this is not a valid
399 // UnwindPlan.
400 if (GetRowAtIndex(0).get() == nullptr ||
401 GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
402 Row::CFAValue::unspecified) {
403 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
404 if (log) {
405 StreamString s;
406 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
407 log->Printf("UnwindPlan is invalid -- no CFA register defined in row 0 "
408 "for UnwindPlan '%s' at address %s",
409 m_source_name.GetCString(), s.GetData());
410 } else {
411 log->Printf("UnwindPlan is invalid -- no CFA register defined in row 0 "
412 "for UnwindPlan '%s'",
413 m_source_name.GetCString());
414 }
415 }
416 return false;
417 }
418
419 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() ||
420 m_plan_valid_address_range.GetByteSize() == 0)
421 return true;
422
423 if (!addr.IsValid())
424 return true;
425
426 if (m_plan_valid_address_range.ContainsFileAddress(addr))
427 return true;
428
429 return false;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000430}
431
Kate Stoneb9c1b512016-09-06 20:57:50 +0000432void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
433 if (!m_source_name.IsEmpty()) {
434 s.Printf("This UnwindPlan originally sourced from %s\n",
435 m_source_name.GetCString());
436 }
437 if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) {
438 TargetSP target_sp(thread->CalculateTarget());
439 addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get());
440 addr_t personality_func_load_addr =
441 m_personality_func_addr.GetLoadAddress(target_sp.get());
442
443 if (lsda_load_addr != LLDB_INVALID_ADDRESS &&
444 personality_func_load_addr != LLDB_INVALID_ADDRESS) {
445 s.Printf("LSDA address 0x%" PRIx64
446 ", personality routine is at address 0x%" PRIx64 "\n",
447 lsda_load_addr, personality_func_load_addr);
Jason Molendaab4f1922010-10-25 11:12:07 +0000448 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000449 }
450 s.Printf("This UnwindPlan is sourced from the compiler: ");
451 switch (m_plan_is_sourced_from_compiler) {
452 case eLazyBoolYes:
453 s.Printf("yes.\n");
454 break;
455 case eLazyBoolNo:
456 s.Printf("no.\n");
457 break;
458 case eLazyBoolCalculate:
459 s.Printf("not specified.\n");
460 break;
461 }
462 s.Printf("This UnwindPlan is valid at all instruction locations: ");
463 switch (m_plan_is_valid_at_all_instruction_locations) {
464 case eLazyBoolYes:
465 s.Printf("yes.\n");
466 break;
467 case eLazyBoolNo:
468 s.Printf("no.\n");
469 break;
470 case eLazyBoolCalculate:
471 s.Printf("not specified.\n");
472 break;
473 }
474 if (m_plan_valid_address_range.GetBaseAddress().IsValid() &&
475 m_plan_valid_address_range.GetByteSize() > 0) {
476 s.PutCString("Address range of this UnwindPlan: ");
477 TargetSP target_sp(thread->CalculateTarget());
478 m_plan_valid_address_range.Dump(&s, target_sp.get(),
479 Address::DumpStyleSectionNameOffset);
480 s.EOL();
481 }
482 collection::const_iterator pos, begin = m_row_list.begin(),
483 end = m_row_list.end();
484 for (pos = begin; pos != end; ++pos) {
485 s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos));
486 (*pos)->Dump(s, this, thread, base_addr);
487 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000488}
Jason Molendaab4f1922010-10-25 11:12:07 +0000489
Kate Stoneb9c1b512016-09-06 20:57:50 +0000490void UnwindPlan::SetSourceName(const char *source) {
491 m_source_name = ConstString(source);
Jason Molendaab4f1922010-10-25 11:12:07 +0000492}
493
Kate Stoneb9c1b512016-09-06 20:57:50 +0000494ConstString UnwindPlan::GetSourceName() const { return m_source_name; }
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000495
Kate Stoneb9c1b512016-09-06 20:57:50 +0000496const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread,
497 uint32_t unwind_reg) const {
498 if (thread) {
499 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
500 if (reg_ctx) {
501 uint32_t reg;
502 if (m_register_kind == eRegisterKindLLDB)
503 reg = unwind_reg;
504 else
505 reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind,
506 unwind_reg);
507 if (reg != LLDB_INVALID_REGNUM)
508 return reg_ctx->GetRegisterInfoAtIndex(reg);
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000509 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000510 }
511 return nullptr;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000512}