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 #include "lldb/Target/Process.h"
12 #include "lldb/Target/RegisterContext.h"
13 #include "lldb/Target/Thread.h"
14 #include "lldb/Core/ConstString.h"
15 
16 using namespace lldb;
17 using namespace lldb_private;
18 
19 bool
20 UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
21 {
22     if (m_type != rhs.m_type)
23         return false;
24     if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset)
25         return m_location.offset == rhs.m_location.offset;
26     if (m_type == inOtherRegister)
27         return m_location.reg_num == rhs.m_location.reg_num;
28     if (m_type == atDWARFExpression || m_type == isDWARFExpression)
29         if (m_location.expr.length == rhs.m_location.expr.length)
30             return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length);
31     return false;
32 }
33 
34 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
35 // memory for the lifespan of this UnwindPlan object.
36 void
37 UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len)
38 {
39     m_type = atDWARFExpression;
40     m_location.expr.opcodes = opcodes;
41     m_location.expr.length = len;
42 }
43 
44 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
45 // memory for the lifespan of this UnwindPlan object.
46 void
47 UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
48 {
49     m_type = isDWARFExpression;
50     m_location.expr.opcodes = opcodes;
51     m_location.expr.length = len;
52 }
53 
54 void
55 UnwindPlan::Row::RegisterLocation::SetUnspecified ()
56 {
57     m_type = unspecified;
58 }
59 
60 void
61 UnwindPlan::Row::RegisterLocation::SetUndefined ()
62 {
63     m_type = isUndefined;
64 }
65 
66 void
67 UnwindPlan::Row::RegisterLocation::SetSame ()
68 {
69     m_type = isSame;
70 }
71 
72 
73 void
74 UnwindPlan::Row::RegisterLocation::SetAtCFAPlusOffset (int32_t offset)
75 {
76     m_type = atCFAPlusOffset;
77     m_location.offset = offset;
78 }
79 
80 void
81 UnwindPlan::Row::RegisterLocation::SetIsCFAPlusOffset (int32_t offset)
82 {
83     m_type = isCFAPlusOffset;
84     m_location.offset = offset;
85 }
86 
87 void
88 UnwindPlan::Row::RegisterLocation::SetInRegister (uint32_t reg_num)
89 {
90     m_type = inOtherRegister;
91     m_location.reg_num = reg_num;
92 }
93 
94 void
95 UnwindPlan::Row::RegisterLocation::Dump (Stream &s) const
96 {
97     switch (m_type)
98     {
99         case unspecified:
100             s.PutCString ("unspecified");
101             break;
102         case isUndefined:
103             s.PutCString ("isUndefined");
104             break;
105         case isSame:
106             s.PutCString ("isSame");
107             break;
108         case atCFAPlusOffset:
109             s.Printf ("atCFAPlusOffset %d", m_location.offset);
110             break;
111         case isCFAPlusOffset:
112             s.Printf ("isCFAPlusOffset %d", m_location.offset);
113             break;
114         case inOtherRegister:
115             s.Printf ("inOtherRegister %d", m_location.reg_num);
116             break;
117         case atDWARFExpression:
118             s.PutCString ("atDWARFExpression");
119             break;
120         case isDWARFExpression:
121             s.PutCString ("isDWARFExpression");
122             break;
123     }
124 }
125 
126 void
127 UnwindPlan::Row::Clear ()
128 {
129     m_offset = 0;
130     m_cfa_reg_num = 0;
131     m_cfa_offset = 0;
132     m_register_locations.clear();
133 }
134 
135 void
136 UnwindPlan::Row::Dump (Stream& s, int register_kind, Thread* thread) const
137 {
138     RegisterContext *reg_ctx = NULL;
139     const RegisterInfo *rinfo = NULL;
140     int translated_regnum;
141     if (thread && thread->GetRegisterContext())
142         reg_ctx = thread->GetRegisterContext().get();
143 
144     s.Printf ("offset %ld, CFA reg ", (long) GetOffset());
145     if (reg_ctx
146         && (translated_regnum = reg_ctx->ConvertRegisterKindToRegisterNumber (register_kind, GetCFARegister())) != -1
147         && (rinfo = reg_ctx->GetRegisterInfoAtIndex (translated_regnum)) != NULL
148         && rinfo->name != NULL
149         && rinfo->name[0] != '\0')
150     {
151         s.Printf ("%s, ", rinfo->name);
152     }
153     else
154     {
155         s.Printf ("%d, ", (int)(int)  GetCFARegister());
156     }
157     s.Printf ("CFA offset %d", (int) GetCFAOffset ());
158     for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
159     {
160         s.PutCString (" [");
161         bool printed_name = false;
162         if (reg_ctx)
163         {
164             translated_regnum = reg_ctx->ConvertRegisterKindToRegisterNumber (register_kind, idx->first);
165             rinfo = reg_ctx->GetRegisterInfoAtIndex (translated_regnum);
166             if (rinfo && rinfo->name)
167             {
168                 s.Printf ("%s ", rinfo->name);
169                 printed_name = true;
170             }
171         }
172         if (!printed_name)
173         {
174             s.Printf ("reg %d ", idx->first);
175         }
176         idx->second.Dump(s);
177         s.PutCString ("]");
178     }
179     s.EOL();
180 }
181 
182 UnwindPlan::Row::Row() :
183     m_offset(0),
184     m_cfa_reg_num(0),
185     m_cfa_offset(0),
186     m_register_locations()
187 {
188 }
189 
190 bool
191 UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const
192 {
193     collection::const_iterator pos = m_register_locations.find(reg_num);
194     if (pos != m_register_locations.end())
195     {
196         register_location = pos->second;
197         return true;
198     }
199     return false;
200 }
201 
202 void
203 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
204 {
205     m_register_locations[reg_num] = register_location;
206 }
207 
208 
209 void
210 UnwindPlan::AppendRow (const UnwindPlan::Row &row)
211 {
212     if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset())
213         m_row_list.push_back(row);
214     else
215         m_row_list.back() = row;
216 }
217 
218 const UnwindPlan::Row *
219 UnwindPlan::GetRowForFunctionOffset (int offset) const
220 {
221     const UnwindPlan::Row *row_ptr = NULL;
222     if (!m_row_list.empty())
223     {
224         if (offset == -1)
225             row_ptr = &m_row_list.back();
226         else
227         {
228             collection::const_iterator pos, end = m_row_list.end();
229             for (pos = m_row_list.begin(); pos != end; ++pos)
230             {
231                 if (pos->GetOffset() <= offset)
232                     row_ptr = &*pos;
233                 else
234                     break;
235             }
236         }
237     }
238     return row_ptr;
239 }
240 
241 bool
242 UnwindPlan::IsValidRowIndex (uint32_t idx) const
243 {
244     return idx < m_row_list.size();
245 }
246 
247 const UnwindPlan::Row&
248 UnwindPlan::GetRowAtIndex (uint32_t idx) const
249 {
250     // You must call IsValidRowIndex(idx) first before calling this!!!
251     assert (idx < m_row_list.size());
252     return m_row_list[idx];
253 }
254 
255 int
256 UnwindPlan::GetRowCount () const
257 {
258     return m_row_list.size ();
259 }
260 
261 void
262 UnwindPlan::SetRegisterKind (uint32_t rk)
263 {
264     m_register_kind = rk;
265 }
266 
267 uint32_t
268 UnwindPlan::GetRegisterKind (void) const
269 {
270     return m_register_kind;
271 }
272 
273 void
274 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
275 {
276    if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
277        m_plan_valid_address_range = range;
278 }
279 
280 bool
281 UnwindPlan::PlanValidAtAddress (Address addr)
282 {
283     if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
284         return true;
285 
286     if (!addr.IsValid())
287         return true;
288 
289     if (m_plan_valid_address_range.ContainsFileAddress (addr))
290         return true;
291 
292     return false;
293 }
294 
295 void
296 UnwindPlan::Dump (Stream& s, Thread *thread) const
297 {
298     if (!m_source_name.IsEmpty())
299     {
300         s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
301     }
302     if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
303     {
304         s.PutCString ("Address range of this UnwindPlan: ");
305         m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset);
306         s.EOL();
307     }
308     else
309     {
310         s.PutCString ("No valid address range recorded for this UnwindPlan.\n");
311     }
312     s.Printf ("UnwindPlan register kind %d", m_register_kind);
313     switch (m_register_kind)
314     {
315         case eRegisterKindGCC:      s.PutCString (" [eRegisterKindGCC]"); break;
316         case eRegisterKindDWARF:    s.PutCString (" [eRegisterKindDWARF]"); break;
317         case eRegisterKindGeneric:  s.PutCString (" [eRegisterKindGeneric]"); break;
318         case eRegisterKindGDB:      s.PutCString (" [eRegisterKindGDB]"); break;
319         case eRegisterKindLLDB:     s.PutCString (" [eRegisterKindLLDB]"); break;
320         default: break;
321     }
322     s.EOL();
323     for (int i = 0; IsValidRowIndex (i); i++)
324     {
325         s.Printf ("UnwindPlan row at index %d: ", i);
326         m_row_list[i].Dump(s, m_register_kind, thread);
327     }
328 }
329 
330 void
331 UnwindPlan::SetSourceName (const char *source)
332 {
333     m_source_name = ConstString (source);
334 }
335 
336 ConstString
337 UnwindPlan::GetSourceName () const
338 {
339     return m_source_name;
340 }
341