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
21 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
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
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
70 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
153 UnwindPlan::Row::Clear ()
154 {
155     m_offset = 0;
156     m_cfa_reg_num = 0;
157     m_cfa_offset = 0;
158     m_register_locations.clear();
159 }
160 
161 void
162 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.16llx: CFA=", base_addr + GetOffset());
168     else
169         s.Printf ("0x%8.8llx: 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 
190 UnwindPlan::Row::Row() :
191     m_offset(0),
192     m_cfa_reg_num(0),
193     m_cfa_offset(0),
194     m_register_locations()
195 {
196 }
197 
198 bool
199 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
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
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
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
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
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
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
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
293 UnwindPlan::Row::SetCFARegister (uint32_t reg_num)
294 {
295     m_cfa_reg_num = reg_num;
296 }
297 
298 void
299 UnwindPlan::AppendRow (const UnwindPlan::Row &row)
300 {
301     if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset())
302         m_row_list.push_back(row);
303     else
304         m_row_list.back() = row;
305 }
306 
307 const UnwindPlan::Row *
308 UnwindPlan::GetRowForFunctionOffset (int offset) const
309 {
310     const UnwindPlan::Row *row_ptr = NULL;
311     if (!m_row_list.empty())
312     {
313         if (offset == -1)
314             row_ptr = &m_row_list.back();
315         else
316         {
317             collection::const_iterator pos, end = m_row_list.end();
318             for (pos = m_row_list.begin(); pos != end; ++pos)
319             {
320                 if (pos->GetOffset() <= offset)
321                     row_ptr = &*pos;
322                 else
323                     break;
324             }
325         }
326     }
327     return row_ptr;
328 }
329 
330 bool
331 UnwindPlan::IsValidRowIndex (uint32_t idx) const
332 {
333     return idx < m_row_list.size();
334 }
335 
336 const UnwindPlan::Row&
337 UnwindPlan::GetRowAtIndex (uint32_t idx) const
338 {
339     // You must call IsValidRowIndex(idx) first before calling this!!!
340     assert (idx < m_row_list.size());
341     return m_row_list[idx];
342 }
343 
344 const UnwindPlan::Row&
345 UnwindPlan::GetLastRow () const
346 {
347     // You must call GetRowCount() first to make sure there is at least one row
348     assert (!m_row_list.empty());
349     return m_row_list.back();
350 }
351 
352 int
353 UnwindPlan::GetRowCount () const
354 {
355     return m_row_list.size ();
356 }
357 
358 void
359 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
360 {
361    if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
362        m_plan_valid_address_range = range;
363 }
364 
365 bool
366 UnwindPlan::PlanValidAtAddress (Address addr)
367 {
368     if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
369         return true;
370 
371     if (!addr.IsValid())
372         return true;
373 
374     if (m_plan_valid_address_range.ContainsFileAddress (addr))
375         return true;
376 
377     return false;
378 }
379 
380 void
381 UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
382 {
383     if (!m_source_name.IsEmpty())
384     {
385         s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
386     }
387     if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
388     {
389         s.PutCString ("Address range of this UnwindPlan: ");
390         m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset);
391         s.EOL();
392     }
393     else
394     {
395         s.PutCString ("No valid address range recorded for this UnwindPlan.\n");
396     }
397     s.Printf ("UnwindPlan register kind %d", m_register_kind);
398     switch (m_register_kind)
399     {
400         case eRegisterKindGCC:      s.PutCString (" [eRegisterKindGCC]"); break;
401         case eRegisterKindDWARF:    s.PutCString (" [eRegisterKindDWARF]"); break;
402         case eRegisterKindGeneric:  s.PutCString (" [eRegisterKindGeneric]"); break;
403         case eRegisterKindGDB:      s.PutCString (" [eRegisterKindGDB]"); break;
404         case eRegisterKindLLDB:     s.PutCString (" [eRegisterKindLLDB]"); break;
405         default: s.PutCString (" [eRegisterKind???]"); break;
406     }
407     s.EOL();
408     collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end();
409     for (pos = begin; pos != end; ++pos)
410     {
411         s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos));
412         pos->Dump(s, this, thread, base_addr);
413     }
414 }
415 
416 void
417 UnwindPlan::SetSourceName (const char *source)
418 {
419     m_source_name = ConstString (source);
420 }
421 
422 ConstString
423 UnwindPlan::GetSourceName () const
424 {
425     return m_source_name;
426 }
427 
428 const RegisterInfo *
429 UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
430 {
431     if (thread)
432     {
433         RegisterContext *reg_ctx = thread->GetRegisterContext().get();
434         if (reg_ctx)
435         {
436             uint32_t reg;
437             if (m_register_kind == eRegisterKindLLDB)
438                 reg = unwind_reg;
439             else
440                 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg);
441             if (reg != LLDB_INVALID_REGNUM)
442                 return reg_ctx->GetRegisterInfoAtIndex (reg);
443         }
444     }
445     return NULL;
446 }
447 
448