1 //===-- 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"
11 
12 #include "lldb/Core/ConstString.h"
13 #include "lldb/Target/Process.h"
14 #include "lldb/Target/RegisterContext.h"
15 #include "lldb/Target/Thread.h"
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 
20 bool
operator ==(const UnwindPlan::Row::RegisterLocation & rhs) const21 UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
22 {
23     if (m_type == rhs.m_type)
24     {
25         switch (m_type)
26         {
27             case unspecified:
28             case undefined:
29             case same:
30                 return true;
31 
32             case atCFAPlusOffset:
33             case isCFAPlusOffset:
34                 return m_location.offset == rhs.m_location.offset;
35 
36             case inOtherRegister:
37                 return m_location.reg_num == rhs.m_location.reg_num;
38 
39             case atDWARFExpression:
40             case isDWARFExpression:
41                 if (m_location.expr.length == rhs.m_location.expr.length)
42                     return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length);
43                 break;
44         }
45     }
46     return false;
47 }
48 
49 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
50 // memory for the lifespan of this UnwindPlan object.
51 void
SetAtDWARFExpression(const uint8_t * opcodes,uint32_t len)52 UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len)
53 {
54     m_type = atDWARFExpression;
55     m_location.expr.opcodes = opcodes;
56     m_location.expr.length = len;
57 }
58 
59 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
60 // memory for the lifespan of this UnwindPlan object.
61 void
SetIsDWARFExpression(const uint8_t * opcodes,uint32_t len)62 UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
63 {
64     m_type = isDWARFExpression;
65     m_location.expr.opcodes = opcodes;
66     m_location.expr.length = len;
67 }
68 
69 void
Dump(Stream & s,const UnwindPlan * unwind_plan,const UnwindPlan::Row * row,Thread * thread,bool verbose) const70 UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_plan, const UnwindPlan::Row* row, Thread* thread, bool verbose) const
71 {
72     switch (m_type)
73     {
74         case unspecified:
75             if (verbose)
76                 s.PutCString ("=<unspec>");
77             else
78                 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             {
93                 s.PutChar('=');
94                 if (m_type == atCFAPlusOffset)
95                     s.PutChar('[');
96                 if (verbose)
97                     s.Printf ("CFA%+d", m_location.offset);
98 
99                 if (unwind_plan && row)
100                 {
101                     const uint32_t cfa_reg = row->GetCFARegister();
102                     const RegisterInfo *cfa_reg_info = unwind_plan->GetRegisterInfo (thread, cfa_reg);
103                     const int32_t offset = row->GetCFAOffset() + m_location.offset;
104                     if (verbose)
105                     {
106                         if (cfa_reg_info)
107                             s.Printf (" (%s%+d)",  cfa_reg_info->name, offset);
108                         else
109                             s.Printf (" (reg(%u)%+d)",  cfa_reg, offset);
110                     }
111                     else
112                     {
113                         if (cfa_reg_info)
114                             s.Printf ("%s",  cfa_reg_info->name);
115                         else
116                             s.Printf ("reg(%u)",  cfa_reg);
117                         if (offset != 0)
118                             s.Printf ("%+d", offset);
119                     }
120                 }
121                 if (m_type == atCFAPlusOffset)
122                     s.PutChar(']');
123             }
124             break;
125 
126         case inOtherRegister:
127             {
128                 const RegisterInfo *other_reg_info = NULL;
129                 if (unwind_plan)
130                     other_reg_info = unwind_plan->GetRegisterInfo (thread, m_location.reg_num);
131                 if (other_reg_info)
132                     s.Printf ("=%s", other_reg_info->name);
133                 else
134                     s.Printf ("=reg(%u)", m_location.reg_num);
135             }
136             break;
137 
138         case atDWARFExpression:
139         case isDWARFExpression:
140             {
141                 s.PutChar('=');
142                 if (m_type == atDWARFExpression)
143                     s.PutCString("[dwarf-expr]");
144                 else
145                     s.PutCString("dwarf-expr");
146             }
147             break;
148 
149     }
150 }
151 
152 void
Clear()153 UnwindPlan::Row::Clear ()
154 {
155     m_offset = 0;
156     m_cfa_reg_num = LLDB_INVALID_REGNUM;
157     m_cfa_offset = 0;
158     m_register_locations.clear();
159 }
160 
161 void
Dump(Stream & s,const UnwindPlan * unwind_plan,Thread * thread,addr_t base_addr) const162 UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const
163 {
164     const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister());
165 
166     if (base_addr != LLDB_INVALID_ADDRESS)
167         s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
168     else
169         s.Printf ("0x%8.8" PRIx64 ": CFA=", GetOffset());
170 
171     if (reg_info)
172         s.Printf ("%s", reg_info->name);
173     else
174         s.Printf ("reg(%u)", GetCFARegister());
175     s.Printf ("%+3d => ", GetCFAOffset ());
176     for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
177     {
178         reg_info = unwind_plan->GetRegisterInfo (thread, idx->first);
179         if (reg_info)
180             s.Printf ("%s", reg_info->name);
181         else
182             s.Printf ("reg(%u)", idx->first);
183         const bool verbose = false;
184         idx->second.Dump(s, unwind_plan, this, thread, verbose);
185         s.PutChar (' ');
186     }
187     s.EOL();
188 }
189 
Row()190 UnwindPlan::Row::Row() :
191     m_offset(0),
192     m_cfa_reg_num(LLDB_INVALID_REGNUM),
193     m_cfa_offset(0),
194     m_register_locations()
195 {
196 }
197 
198 bool
GetRegisterInfo(uint32_t reg_num,UnwindPlan::Row::RegisterLocation & register_location) const199 UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const
200 {
201     collection::const_iterator pos = m_register_locations.find(reg_num);
202     if (pos != m_register_locations.end())
203     {
204         register_location = pos->second;
205         return true;
206     }
207     return false;
208 }
209 
210 void
SetRegisterInfo(uint32_t reg_num,const UnwindPlan::Row::RegisterLocation register_location)211 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
212 {
213     m_register_locations[reg_num] = register_location;
214 }
215 
216 bool
SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)217 UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
218 {
219     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
220         return false;
221     RegisterLocation reg_loc;
222     reg_loc.SetAtCFAPlusOffset(offset);
223     m_register_locations[reg_num] = reg_loc;
224     return true;
225 }
226 
227 bool
SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)228 UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
229 {
230     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
231         return false;
232     RegisterLocation reg_loc;
233     reg_loc.SetIsCFAPlusOffset(offset);
234     m_register_locations[reg_num] = reg_loc;
235     return true;
236 }
237 
238 bool
SetRegisterLocationToUndefined(uint32_t reg_num,bool can_replace,bool can_replace_only_if_unspecified)239 UnwindPlan::Row::SetRegisterLocationToUndefined (uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified)
240 {
241     collection::iterator pos = m_register_locations.find(reg_num);
242     collection::iterator end = m_register_locations.end();
243 
244     if (pos != end)
245     {
246         if (!can_replace)
247             return false;
248         if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
249             return false;
250     }
251     RegisterLocation reg_loc;
252     reg_loc.SetUndefined();
253     m_register_locations[reg_num] = reg_loc;
254     return true;
255 }
256 
257 bool
SetRegisterLocationToUnspecified(uint32_t reg_num,bool can_replace)258 UnwindPlan::Row::SetRegisterLocationToUnspecified (uint32_t reg_num, bool can_replace)
259 {
260     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
261         return false;
262     RegisterLocation reg_loc;
263     reg_loc.SetUnspecified();
264     m_register_locations[reg_num] = reg_loc;
265     return true;
266 }
267 
268 bool
SetRegisterLocationToRegister(uint32_t reg_num,uint32_t other_reg_num,bool can_replace)269 UnwindPlan::Row::SetRegisterLocationToRegister (uint32_t reg_num,
270                                                 uint32_t other_reg_num,
271                                                 bool can_replace)
272 {
273     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
274         return false;
275     RegisterLocation reg_loc;
276     reg_loc.SetInRegister(other_reg_num);
277     m_register_locations[reg_num] = reg_loc;
278     return true;
279 }
280 
281 bool
SetRegisterLocationToSame(uint32_t reg_num,bool must_replace)282 UnwindPlan::Row::SetRegisterLocationToSame (uint32_t reg_num, bool must_replace)
283 {
284     if (must_replace && m_register_locations.find(reg_num) == m_register_locations.end())
285         return false;
286     RegisterLocation reg_loc;
287     reg_loc.SetSame();
288     m_register_locations[reg_num] = reg_loc;
289     return true;
290 }
291 
292 void
SetCFARegister(uint32_t reg_num)293 UnwindPlan::Row::SetCFARegister (uint32_t reg_num)
294 {
295     m_cfa_reg_num = reg_num;
296 }
297 
298 bool
operator ==(const UnwindPlan::Row & rhs) const299 UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const
300 {
301     if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset)
302         return false;
303     return m_register_locations == rhs.m_register_locations;
304 }
305 
306 void
AppendRow(const UnwindPlan::RowSP & row_sp)307 UnwindPlan::AppendRow (const UnwindPlan::RowSP &row_sp)
308 {
309     if (m_row_list.empty() || m_row_list.back()->GetOffset() != row_sp->GetOffset())
310         m_row_list.push_back(row_sp);
311     else
312         m_row_list.back() = row_sp;
313 }
314 
315 UnwindPlan::RowSP
GetRowForFunctionOffset(int offset) const316 UnwindPlan::GetRowForFunctionOffset (int offset) const
317 {
318     RowSP row;
319     if (!m_row_list.empty())
320     {
321         if (offset == -1)
322             row = m_row_list.back();
323         else
324         {
325             collection::const_iterator pos, end = m_row_list.end();
326             for (pos = m_row_list.begin(); pos != end; ++pos)
327             {
328                 if ((*pos)->GetOffset() <= offset)
329                     row = *pos;
330                 else
331                     break;
332             }
333         }
334     }
335     return row;
336 }
337 
338 bool
IsValidRowIndex(uint32_t idx) const339 UnwindPlan::IsValidRowIndex (uint32_t idx) const
340 {
341     return idx < m_row_list.size();
342 }
343 
344 const UnwindPlan::RowSP
GetRowAtIndex(uint32_t idx) const345 UnwindPlan::GetRowAtIndex (uint32_t idx) const
346 {
347     // You must call IsValidRowIndex(idx) first before calling this!!!
348     assert (idx < m_row_list.size());
349     return m_row_list[idx];
350 }
351 
352 const UnwindPlan::RowSP
GetLastRow() const353 UnwindPlan::GetLastRow () const
354 {
355     // You must call GetRowCount() first to make sure there is at least one row
356     assert (!m_row_list.empty());
357     return m_row_list.back();
358 }
359 
360 int
GetRowCount() const361 UnwindPlan::GetRowCount () const
362 {
363     return m_row_list.size ();
364 }
365 
366 void
SetPlanValidAddressRange(const AddressRange & range)367 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
368 {
369    if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
370        m_plan_valid_address_range = range;
371 }
372 
373 bool
PlanValidAtAddress(Address addr)374 UnwindPlan::PlanValidAtAddress (Address addr)
375 {
376     if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
377         return true;
378 
379     if (!addr.IsValid())
380         return true;
381 
382     if (m_plan_valid_address_range.ContainsFileAddress (addr))
383         return true;
384 
385     return false;
386 }
387 
388 void
Dump(Stream & s,Thread * thread,lldb::addr_t base_addr) const389 UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
390 {
391     if (!m_source_name.IsEmpty())
392     {
393         s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
394     }
395     if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
396     {
397         s.PutCString ("Address range of this UnwindPlan: ");
398         TargetSP target_sp(thread->CalculateTarget());
399         m_plan_valid_address_range.Dump (&s, target_sp.get(), Address::DumpStyleSectionNameOffset);
400         s.EOL();
401     }
402     collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end();
403     for (pos = begin; pos != end; ++pos)
404     {
405         s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos));
406         (*pos)->Dump(s, this, thread, base_addr);
407     }
408 }
409 
410 void
SetSourceName(const char * source)411 UnwindPlan::SetSourceName (const char *source)
412 {
413     m_source_name = ConstString (source);
414 }
415 
416 ConstString
GetSourceName() const417 UnwindPlan::GetSourceName () const
418 {
419     return m_source_name;
420 }
421 
422 const RegisterInfo *
GetRegisterInfo(Thread * thread,uint32_t unwind_reg) const423 UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
424 {
425     if (thread)
426     {
427         RegisterContext *reg_ctx = thread->GetRegisterContext().get();
428         if (reg_ctx)
429         {
430             uint32_t reg;
431             if (m_register_kind == eRegisterKindLLDB)
432                 reg = unwind_reg;
433             else
434                 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg);
435             if (reg != LLDB_INVALID_REGNUM)
436                 return reg_ctx->GetRegisterInfoAtIndex (reg);
437         }
438     }
439     return NULL;
440 }
441 
442