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