blob: 4c0014348c42ce82d0129bd6ad52300f85441847 [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
49// allocated
50// memory for the lifespan of this UnwindPlan object.
51void UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression(
52 const uint8_t *opcodes, uint32_t len) {
53 m_type = atDWARFExpression;
54 m_location.expr.opcodes = opcodes;
55 m_location.expr.length = len;
Jason Molendafbcb7f22010-09-10 07:49:16 +000056}
57
Kate Stoneb9c1b512016-09-06 20:57:50 +000058// This function doesn't copy the dwarf expression bytes; they must remain in
59// allocated
60// memory for the lifespan of this UnwindPlan object.
61void UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression(
62 const uint8_t *opcodes, uint32_t len) {
63 m_type = isDWARFExpression;
64 m_location.expr.opcodes = opcodes;
65 m_location.expr.length = len;
66}
67
68void UnwindPlan::Row::RegisterLocation::Dump(Stream &s,
69 const UnwindPlan *unwind_plan,
70 const UnwindPlan::Row *row,
71 Thread *thread,
72 bool verbose) const {
73 switch (m_type) {
74 case unspecified:
75 if (verbose)
76 s.PutCString("=<unspec>");
Jason Molendafbcb7f22010-09-10 07:49:16 +000077 else
Kate Stoneb9c1b512016-09-06 20:57:50 +000078 s.PutCString("=!");
79 break;
80 case undefined:
81 if (verbose)
82 s.PutCString("=<undef>");
83 else
84 s.PutCString("=?");
85 break;
86 case same:
87 s.PutCString("= <same>");
88 break;
89
90 case atCFAPlusOffset:
91 case isCFAPlusOffset: {
92 s.PutChar('=');
93 if (m_type == atCFAPlusOffset)
94 s.PutChar('[');
95 s.Printf("CFA%+d", m_location.offset);
96 if (m_type == atCFAPlusOffset)
97 s.PutChar(']');
98 } break;
99
100 case inOtherRegister: {
101 const RegisterInfo *other_reg_info = nullptr;
102 if (unwind_plan)
103 other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num);
104 if (other_reg_info)
105 s.Printf("=%s", other_reg_info->name);
106 else
107 s.Printf("=reg(%u)", m_location.reg_num);
108 } break;
109
110 case atDWARFExpression:
111 case isDWARFExpression: {
112 s.PutChar('=');
113 if (m_type == atDWARFExpression)
114 s.PutCString("[dwarf-expr]");
115 else
116 s.PutCString("dwarf-expr");
117 } break;
118 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000119}
120
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,
122 Thread *thread, uint32_t reg_num) {
123 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num);
124 if (reg_info)
125 s.PutCString(reg_info->name);
126 else
127 s.Printf("reg(%u)", reg_num);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000128}
129
Kate Stoneb9c1b512016-09-06 20:57:50 +0000130bool UnwindPlan::Row::CFAValue::
131operator==(const UnwindPlan::Row::CFAValue &rhs) const {
132 if (m_type == rhs.m_type) {
133 switch (m_type) {
134 case unspecified:
135 return true;
136
137 case isRegisterPlusOffset:
138 return m_value.reg.offset == rhs.m_value.reg.offset;
139
140 case isRegisterDereferenced:
141 return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
142
143 case isDWARFExpression:
144 if (m_value.expr.length == rhs.m_value.expr.length)
145 return !memcmp(m_value.expr.opcodes, rhs.m_value.expr.opcodes,
146 m_value.expr.length);
147 break;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000148 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 }
150 return false;
151}
152
153void UnwindPlan::Row::CFAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
154 Thread *thread) const {
155 switch (m_type) {
156 case isRegisterPlusOffset:
157 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
158 s.Printf("%+3d", m_value.reg.offset);
159 break;
160 case isRegisterDereferenced:
161 s.PutChar('[');
162 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
163 s.PutChar(']');
164 break;
165 case isDWARFExpression:
166 s.PutCString("dwarf-expr");
167 break;
168 default:
169 s.PutCString("unspecified");
170 break;
171 }
172}
173
174void UnwindPlan::Row::Clear() {
175 m_cfa_value.SetUnspecified();
176 m_offset = 0;
177 m_register_locations.clear();
178}
179
180void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
181 Thread *thread, addr_t base_addr) const {
182 if (base_addr != LLDB_INVALID_ADDRESS)
183 s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
184 else
185 s.Printf("%4" PRId64 ": CFA=", GetOffset());
186
187 m_cfa_value.Dump(s, unwind_plan, thread);
188 s.Printf(" => ");
189 for (collection::const_iterator idx = m_register_locations.begin();
190 idx != m_register_locations.end(); ++idx) {
191 DumpRegisterName(s, unwind_plan, thread, idx->first);
192 const bool verbose = false;
193 idx->second.Dump(s, unwind_plan, this, thread, verbose);
194 s.PutChar(' ');
195 }
196 s.EOL();
197}
198
199UnwindPlan::Row::Row() : m_offset(0), m_cfa_value(), m_register_locations() {}
200
201bool UnwindPlan::Row::GetRegisterInfo(
202 uint32_t reg_num,
203 UnwindPlan::Row::RegisterLocation &register_location) const {
204 collection::const_iterator pos = m_register_locations.find(reg_num);
205 if (pos != m_register_locations.end()) {
206 register_location = pos->second;
207 return true;
208 }
209 return false;
210}
211
212void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) {
213 collection::const_iterator pos = m_register_locations.find(reg_num);
214 if (pos != m_register_locations.end()) {
215 m_register_locations.erase(pos);
216 }
217}
218
219void UnwindPlan::Row::SetRegisterInfo(
220 uint32_t reg_num,
221 const UnwindPlan::Row::RegisterLocation register_location) {
222 m_register_locations[reg_num] = register_location;
223}
224
225bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,
226 int32_t offset,
227 bool can_replace) {
228 if (!can_replace &&
229 m_register_locations.find(reg_num) != m_register_locations.end())
Jason Molendafbcb7f22010-09-10 07:49:16 +0000230 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000231 RegisterLocation reg_loc;
232 reg_loc.SetAtCFAPlusOffset(offset);
233 m_register_locations[reg_num] = reg_loc;
234 return true;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000235}
236
Kate Stoneb9c1b512016-09-06 20:57:50 +0000237bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,
238 int32_t offset,
239 bool can_replace) {
240 if (!can_replace &&
241 m_register_locations.find(reg_num) != m_register_locations.end())
242 return false;
243 RegisterLocation reg_loc;
244 reg_loc.SetIsCFAPlusOffset(offset);
245 m_register_locations[reg_num] = reg_loc;
246 return true;
Jason Molenda34549b82015-01-13 06:04:04 +0000247}
248
Kate Stoneb9c1b512016-09-06 20:57:50 +0000249bool UnwindPlan::Row::SetRegisterLocationToUndefined(
250 uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) {
251 collection::iterator pos = m_register_locations.find(reg_num);
252 collection::iterator end = m_register_locations.end();
253
254 if (pos != end) {
255 if (!can_replace)
256 return false;
257 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
258 return false;
259 }
260 RegisterLocation reg_loc;
261 reg_loc.SetUndefined();
262 m_register_locations[reg_num] = reg_loc;
263 return true;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000264}
265
Kate Stoneb9c1b512016-09-06 20:57:50 +0000266bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num,
267 bool can_replace) {
268 if (!can_replace &&
269 m_register_locations.find(reg_num) != m_register_locations.end())
270 return false;
271 RegisterLocation reg_loc;
272 reg_loc.SetUnspecified();
273 m_register_locations[reg_num] = reg_loc;
274 return true;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000275}
276
Kate Stoneb9c1b512016-09-06 20:57:50 +0000277bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num,
278 uint32_t other_reg_num,
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.SetInRegister(other_reg_num);
285 m_register_locations[reg_num] = reg_loc;
286 return true;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000287}
288
Kate Stoneb9c1b512016-09-06 20:57:50 +0000289bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,
290 bool must_replace) {
291 if (must_replace &&
292 m_register_locations.find(reg_num) == m_register_locations.end())
293 return false;
294 RegisterLocation reg_loc;
295 reg_loc.SetSame();
296 m_register_locations[reg_num] = reg_loc;
297 return true;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000298}
299
Kate Stoneb9c1b512016-09-06 20:57:50 +0000300bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
301 return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
302 m_register_locations == rhs.m_register_locations;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000303}
304
Kate Stoneb9c1b512016-09-06 20:57:50 +0000305void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) {
306 if (m_row_list.empty() ||
307 m_row_list.back()->GetOffset() != row_sp->GetOffset())
308 m_row_list.push_back(row_sp);
309 else
310 m_row_list.back() = row_sp;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000311}
312
Kate Stoneb9c1b512016-09-06 20:57:50 +0000313void UnwindPlan::InsertRow(const UnwindPlan::RowSP &row_sp,
314 bool replace_existing) {
315 collection::iterator it = m_row_list.begin();
316 while (it != m_row_list.end()) {
317 RowSP row = *it;
318 if (row->GetOffset() >= row_sp->GetOffset())
319 break;
320 it++;
321 }
322 if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
323 m_row_list.insert(it, row_sp);
324 else if (replace_existing)
325 *it = row_sp;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000326}
327
Kate Stoneb9c1b512016-09-06 20:57:50 +0000328UnwindPlan::RowSP UnwindPlan::GetRowForFunctionOffset(int offset) const {
329 RowSP row;
330 if (!m_row_list.empty()) {
331 if (offset == -1)
332 row = m_row_list.back();
333 else {
334 collection::const_iterator pos, end = m_row_list.end();
335 for (pos = m_row_list.begin(); pos != end; ++pos) {
336 if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
337 row = *pos;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000338 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000339 break;
340 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000341 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000342 }
343 return row;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000344}
345
Kate Stoneb9c1b512016-09-06 20:57:50 +0000346bool UnwindPlan::IsValidRowIndex(uint32_t idx) const {
347 return idx < m_row_list.size();
Jason Molendafbcb7f22010-09-10 07:49:16 +0000348}
349
Kate Stoneb9c1b512016-09-06 20:57:50 +0000350const UnwindPlan::RowSP UnwindPlan::GetRowAtIndex(uint32_t idx) const {
351 if (idx < m_row_list.size())
352 return m_row_list[idx];
353 else {
354 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
355 if (log)
356 log->Printf("error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index "
357 "(number rows is %u)",
358 idx, (uint32_t)m_row_list.size());
359 return UnwindPlan::RowSP();
360 }
361}
362
363const UnwindPlan::RowSP UnwindPlan::GetLastRow() const {
364 if (m_row_list.empty()) {
365 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
366 if (log)
367 log->Printf("UnwindPlan::GetLastRow() when rows are empty");
368 return UnwindPlan::RowSP();
369 }
370 return m_row_list.back();
371}
372
373int UnwindPlan::GetRowCount() const { return m_row_list.size(); }
374
375void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) {
376 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
377 m_plan_valid_address_range = range;
378}
379
380bool UnwindPlan::PlanValidAtAddress(Address addr) {
381 // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
382 if (GetRowCount() == 0) {
383 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
384 if (log) {
385 StreamString s;
386 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
387 log->Printf("UnwindPlan is invalid -- no unwind rows for UnwindPlan "
388 "'%s' at address %s",
389 m_source_name.GetCString(), s.GetData());
390 } else {
391 log->Printf(
392 "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
393 m_source_name.GetCString());
394 }
Greg Claytond28fae82016-07-12 23:07:50 +0000395 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000396 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000397 }
398
399 // If the 0th Row of unwind instructions is missing, or if it doesn't provide
400 // a register to use to find the Canonical Frame Address, this is not a valid
401 // UnwindPlan.
402 if (GetRowAtIndex(0).get() == nullptr ||
403 GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
404 Row::CFAValue::unspecified) {
405 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
406 if (log) {
407 StreamString s;
408 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
409 log->Printf("UnwindPlan is invalid -- no CFA register defined in row 0 "
410 "for UnwindPlan '%s' at address %s",
411 m_source_name.GetCString(), s.GetData());
412 } else {
413 log->Printf("UnwindPlan is invalid -- no CFA register defined in row 0 "
414 "for UnwindPlan '%s'",
415 m_source_name.GetCString());
416 }
417 }
418 return false;
419 }
420
421 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() ||
422 m_plan_valid_address_range.GetByteSize() == 0)
423 return true;
424
425 if (!addr.IsValid())
426 return true;
427
428 if (m_plan_valid_address_range.ContainsFileAddress(addr))
429 return true;
430
431 return false;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000432}
433
Kate Stoneb9c1b512016-09-06 20:57:50 +0000434void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
435 if (!m_source_name.IsEmpty()) {
436 s.Printf("This UnwindPlan originally sourced from %s\n",
437 m_source_name.GetCString());
438 }
439 if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) {
440 TargetSP target_sp(thread->CalculateTarget());
441 addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get());
442 addr_t personality_func_load_addr =
443 m_personality_func_addr.GetLoadAddress(target_sp.get());
444
445 if (lsda_load_addr != LLDB_INVALID_ADDRESS &&
446 personality_func_load_addr != LLDB_INVALID_ADDRESS) {
447 s.Printf("LSDA address 0x%" PRIx64
448 ", personality routine is at address 0x%" PRIx64 "\n",
449 lsda_load_addr, personality_func_load_addr);
Jason Molendaab4f1922010-10-25 11:12:07 +0000450 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000451 }
452 s.Printf("This UnwindPlan is sourced from the compiler: ");
453 switch (m_plan_is_sourced_from_compiler) {
454 case eLazyBoolYes:
455 s.Printf("yes.\n");
456 break;
457 case eLazyBoolNo:
458 s.Printf("no.\n");
459 break;
460 case eLazyBoolCalculate:
461 s.Printf("not specified.\n");
462 break;
463 }
464 s.Printf("This UnwindPlan is valid at all instruction locations: ");
465 switch (m_plan_is_valid_at_all_instruction_locations) {
466 case eLazyBoolYes:
467 s.Printf("yes.\n");
468 break;
469 case eLazyBoolNo:
470 s.Printf("no.\n");
471 break;
472 case eLazyBoolCalculate:
473 s.Printf("not specified.\n");
474 break;
475 }
476 if (m_plan_valid_address_range.GetBaseAddress().IsValid() &&
477 m_plan_valid_address_range.GetByteSize() > 0) {
478 s.PutCString("Address range of this UnwindPlan: ");
479 TargetSP target_sp(thread->CalculateTarget());
480 m_plan_valid_address_range.Dump(&s, target_sp.get(),
481 Address::DumpStyleSectionNameOffset);
482 s.EOL();
483 }
484 collection::const_iterator pos, begin = m_row_list.begin(),
485 end = m_row_list.end();
486 for (pos = begin; pos != end; ++pos) {
487 s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos));
488 (*pos)->Dump(s, this, thread, base_addr);
489 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000490}
Jason Molendaab4f1922010-10-25 11:12:07 +0000491
Kate Stoneb9c1b512016-09-06 20:57:50 +0000492void UnwindPlan::SetSourceName(const char *source) {
493 m_source_name = ConstString(source);
Jason Molendaab4f1922010-10-25 11:12:07 +0000494}
495
Kate Stoneb9c1b512016-09-06 20:57:50 +0000496ConstString UnwindPlan::GetSourceName() const { return m_source_name; }
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000497
Kate Stoneb9c1b512016-09-06 20:57:50 +0000498const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread,
499 uint32_t unwind_reg) const {
500 if (thread) {
501 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
502 if (reg_ctx) {
503 uint32_t reg;
504 if (m_register_kind == eRegisterKindLLDB)
505 reg = unwind_reg;
506 else
507 reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind,
508 unwind_reg);
509 if (reg != LLDB_INVALID_REGNUM)
510 return reg_ctx->GetRegisterInfoAtIndex(reg);
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000511 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000512 }
513 return nullptr;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000514}