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_eh_frame (NULL),
37     m_assembly_profiler (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     ConstString str;
62     m_object_file.GetTargetTriple (str);
63     arch.SetArchFromTargetTriple (str.GetCString());
64     m_assembly_profiler = UnwindAssemblyProfiler::FindPlugin (arch);
65 
66     m_initialized = true;
67 }
68 
69 UnwindTable::~UnwindTable ()
70 {
71     if (m_eh_frame)
72         delete m_eh_frame;
73 }
74 
75 FuncUnwindersSP
76 UnwindTable::GetFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc)
77 {
78     FuncUnwindersSP no_unwind_found;
79 
80     Initialize();
81 
82     // There is an UnwindTable per object file, so we can safely use file handles
83     addr_t file_addr = addr.GetFileAddress();
84     iterator end = m_unwinds.end ();
85     iterator insert_pos = end;
86     if (!m_unwinds.empty())
87     {
88         insert_pos = m_unwinds.lower_bound (file_addr);
89         iterator pos = insert_pos;
90         if ((pos == m_unwinds.end ()) || (pos != m_unwinds.begin() && pos->second->GetFunctionStartAddress() != addr))
91             --pos;
92 
93         if (pos->second->ContainsAddress (addr))
94             return pos->second;
95     }
96 
97     AddressRange range;
98     if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, range) || !range.GetBaseAddress().IsValid())
99     {
100         // Does the eh_frame unwind info has a function bounds for this addr?
101         if (m_eh_frame == NULL || !m_eh_frame->GetAddressRange (addr, range))
102         {
103             return no_unwind_found;
104         }
105     }
106 
107     FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, m_assembly_profiler, range));
108     m_unwinds.insert (insert_pos, std::make_pair(range.GetBaseAddress().GetFileAddress(), func_unwinder_sp));
109 //    StreamFile s(stdout);
110 //    Dump (s);
111     return func_unwinder_sp;
112 }
113 
114 void
115 UnwindTable::Dump (Stream &s)
116 {
117     s.Printf("UnwindTable for %s/%s:\n", m_object_file.GetFileSpec().GetDirectory().GetCString(), m_object_file.GetFileSpec().GetFilename().GetCString());
118     const_iterator begin = m_unwinds.begin();
119     const_iterator end = m_unwinds.end();
120     for (const_iterator pos = begin; pos != end; ++pos)
121     {
122         s.Printf ("[%zu] 0x%16.16llx\n", std::distance (begin, pos), pos->first);
123     }
124     s.EOL();
125 }
126 
127 DWARFCallFrameInfo *
128 UnwindTable::GetEHFrameInfo ()
129 {
130     Initialize();
131     return m_eh_frame;
132 }
133