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