1 //===-- UnwindTable.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/UnwindTable.h"
11 
12 #include <stdio.h>
13 
14 #include "lldb/lldb-forward.h"
15 
16 #include "lldb/Core/Module.h"
17 #include "lldb/Core/Section.h"
18 //#include "lldb/Core/StreamFile.h"
19 #include "lldb/Symbol/ObjectFile.h"
20 #include "lldb/Symbol/FuncUnwinders.h"
21 #include "lldb/Symbol/SymbolContext.h"
22 #include "lldb/Symbol/DWARFCallFrameInfo.h"
23 #include "lldb/Utility/UnwindAssemblyProfiler.h"
24 
25 // There is one UnwindTable object per ObjectFile.
26 // It contains a list of Unwind objects -- one per function, populated lazily -- for the ObjectFile.
27 // Each Unwind object has multiple UnwindPlans for different scenarios.
28 
29 using namespace lldb;
30 using namespace lldb_private;
31 
32 UnwindTable::UnwindTable (ObjectFile& objfile) :
33     m_object_file (objfile),
34     m_unwinds (),
35     m_initialized (false),
36     m_assembly_profiler (NULL),
37     m_eh_frame (NULL)
38 {
39 }
40 
41 // We can't do some of this initialization when the ObjectFile is running its ctor; delay doing it
42 // until needed for something.
43 
44 void
45 UnwindTable::Initialize ()
46 {
47     if (m_initialized)
48         return;
49 
50     SectionList* sl = m_object_file.GetSectionList ();
51     if (sl)
52     {
53         SectionSP sect = sl->FindSectionByType (eSectionTypeEHFrame, true);
54         if (sect.get())
55         {
56             m_eh_frame = new DWARFCallFrameInfo(m_object_file, sect, eRegisterKindGCC, true);
57         }
58     }
59 
60     ArchSpec arch;
61     if (m_object_file.GetArchitecture (arch))
62     {
63         m_assembly_profiler = UnwindAssemblyProfiler::FindPlugin (arch);
64         m_initialized = true;
65     }
66 }
67 
68 UnwindTable::~UnwindTable ()
69 {
70     if (m_eh_frame)
71         delete m_eh_frame;
72 }
73 
74 FuncUnwindersSP
75 UnwindTable::GetFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc)
76 {
77     FuncUnwindersSP no_unwind_found;
78 
79     Initialize();
80 
81     // There is an UnwindTable per object file, so we can safely use file handles
82     addr_t file_addr = addr.GetFileAddress();
83     iterator end = m_unwinds.end ();
84     iterator insert_pos = end;
85     if (!m_unwinds.empty())
86     {
87         insert_pos = m_unwinds.lower_bound (file_addr);
88         iterator pos = insert_pos;
89         if ((pos == m_unwinds.end ()) || (pos != m_unwinds.begin() && pos->second->GetFunctionStartAddress() != addr))
90             --pos;
91 
92         if (pos->second->ContainsAddress (addr))
93             return pos->second;
94     }
95 
96     AddressRange range;
97     if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, range) || !range.GetBaseAddress().IsValid())
98     {
99         // Does the eh_frame unwind info has a function bounds for this addr?
100         if (m_eh_frame == NULL || !m_eh_frame->GetAddressRange (addr, range))
101         {
102             return no_unwind_found;
103         }
104     }
105 
106     FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, m_assembly_profiler, range));
107     m_unwinds.insert (insert_pos, std::make_pair(range.GetBaseAddress().GetFileAddress(), func_unwinder_sp));
108 //    StreamFile s(stdout);
109 //    Dump (s);
110     return func_unwinder_sp;
111 }
112 
113 void
114 UnwindTable::Dump (Stream &s)
115 {
116     s.Printf("UnwindTable for %s/%s:\n", m_object_file.GetFileSpec().GetDirectory().GetCString(), m_object_file.GetFileSpec().GetFilename().GetCString());
117     const_iterator begin = m_unwinds.begin();
118     const_iterator end = m_unwinds.end();
119     for (const_iterator pos = begin; pos != end; ++pos)
120     {
121         s.Printf ("[%zu] 0x%16.16llx\n", std::distance (begin, pos), pos->first);
122     }
123     s.EOL();
124 }
125 
126 DWARFCallFrameInfo *
127 UnwindTable::GetEHFrameInfo ()
128 {
129     Initialize();
130     return m_eh_frame;
131 }
132