1 //===-- FuncUnwinders.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/Core/AddressRange.h"
11 #include "lldb/Core/Address.h"
12 #include "lldb/Symbol/FuncUnwinders.h"
13 #include "lldb/Symbol/DWARFCallFrameInfo.h"
14 #include "lldb/Symbol/CompactUnwindInfo.h"
15 #include "lldb/Symbol/ObjectFile.h"
16 #include "lldb/Symbol/UnwindPlan.h"
17 #include "lldb/Symbol/UnwindTable.h"
18 #include "lldb/Target/ABI.h"
19 #include "lldb/Target/ExecutionContext.h"
20 #include "lldb/Target/Process.h"
21 #include "lldb/Target/Thread.h"
22 #include "lldb/Target/Target.h"
23 #include "lldb/Target/UnwindAssembly.h"
24 
25 using namespace lldb;
26 using namespace lldb_private;
27 
28 
29 FuncUnwinders::FuncUnwinders (UnwindTable& unwind_table, AddressRange range) :
30     m_unwind_table (unwind_table),
31     m_range (range),
32     m_mutex (Mutex::eMutexTypeRecursive),
33     m_unwind_plan_call_site_sp (),
34     m_unwind_plan_non_call_site_sp (),
35     m_unwind_plan_fast_sp (),
36     m_unwind_plan_arch_default_sp (),
37     m_tried_unwind_at_call_site (false),
38     m_tried_unwind_at_non_call_site (false),
39     m_tried_unwind_fast (false),
40     m_tried_unwind_arch_default (false),
41     m_tried_unwind_arch_default_at_func_entry (false),
42     m_first_non_prologue_insn ()
43 {
44 }
45 
46 FuncUnwinders::~FuncUnwinders ()
47 {
48 }
49 
50 UnwindPlanSP
51 FuncUnwinders::GetUnwindPlanAtCallSite (Target &target, int current_offset)
52 {
53     Mutex::Locker locker (m_mutex);
54     if (m_tried_unwind_at_call_site == false && m_unwind_plan_call_site_sp.get() == nullptr)
55     {
56         m_tried_unwind_at_call_site = true;
57 
58         // We have cases (e.g. with _sigtramp on Mac OS X) where the hand-written eh_frame unwind info for a
59         // function does not cover the entire range of the function and so the FDE only lists a subset of the
60         // address range.  If we try to look up the unwind info by the starting address of the function
61         // (i.e. m_range.GetBaseAddress()) we may not find the eh_frame FDE.  We need to use the actual byte offset
62         // into the function when looking it up.
63 
64         if (m_range.GetBaseAddress().IsValid())
65         {
66             Address current_pc (m_range.GetBaseAddress ());
67             if (current_offset != -1)
68                 current_pc.SetOffset (current_pc.GetOffset() + current_offset);
69 
70             CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo();
71             if (compact_unwind)
72             {
73                 m_unwind_plan_call_site_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
74                 if (!compact_unwind->GetUnwindPlan (target, current_pc, *m_unwind_plan_call_site_sp))
75                     m_unwind_plan_call_site_sp.reset();
76             }
77             if (m_unwind_plan_call_site_sp.get() == nullptr)
78             {
79                 DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
80                 if (eh_frame)
81                 {
82                     m_unwind_plan_call_site_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
83                     if (!eh_frame->GetUnwindPlan (current_pc, *m_unwind_plan_call_site_sp))
84                         m_unwind_plan_call_site_sp.reset();
85                 }
86             }
87         }
88     }
89     return m_unwind_plan_call_site_sp;
90 }
91 
92 UnwindPlanSP
93 FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int current_offset)
94 {
95     Mutex::Locker locker (m_mutex);
96     if (m_tried_unwind_at_non_call_site == false && m_unwind_plan_non_call_site_sp.get() == nullptr)
97     {
98         UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
99         if (assembly_profiler_sp)
100         {
101             if (target.GetArchitecture().GetCore() == ArchSpec::eCore_x86_32_i386
102                 || target.GetArchitecture().GetCore() == ArchSpec::eCore_x86_64_x86_64
103                 || target.GetArchitecture().GetCore() == ArchSpec::eCore_x86_64_x86_64h)
104             {
105                 // For 0th frame on i386 & x86_64, we fetch eh_frame and try using assembly profiler
106                 // to augment it into asynchronous unwind table.
107                 DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
108                 if (eh_frame)
109                 {
110                     UnwindPlanSP unwind_plan (new UnwindPlan (lldb::eRegisterKindGeneric));
111                     if (m_range.GetBaseAddress().IsValid())
112                     {
113                         Address current_pc (m_range.GetBaseAddress ());
114                         if (current_offset != -1)
115                             current_pc.SetOffset (current_pc.GetOffset() + current_offset);
116                         if (eh_frame->GetUnwindPlan (current_pc, *unwind_plan))
117                         {
118                             if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite (m_range, thread, *unwind_plan))
119                             {
120                                 m_unwind_plan_non_call_site_sp = unwind_plan;
121                                 return m_unwind_plan_non_call_site_sp;
122                             }
123                         }
124                     }
125                 }
126             }
127 
128             m_unwind_plan_non_call_site_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
129             if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_plan_non_call_site_sp))
130                 m_unwind_plan_non_call_site_sp.reset();
131         }
132     }
133     return m_unwind_plan_non_call_site_sp;
134 }
135 
136 UnwindPlanSP
137 FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
138 {
139     Mutex::Locker locker (m_mutex);
140     if (m_tried_unwind_fast == false && m_unwind_plan_fast_sp.get() == nullptr)
141     {
142         m_tried_unwind_fast = true;
143         UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
144         if (assembly_profiler_sp)
145         {
146             m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
147             if (!assembly_profiler_sp->GetFastUnwindPlan (m_range, thread, *m_unwind_plan_fast_sp))
148                 m_unwind_plan_fast_sp.reset();
149         }
150     }
151     return m_unwind_plan_fast_sp;
152 }
153 
154 UnwindPlanSP
155 FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread)
156 {
157     Mutex::Locker locker (m_mutex);
158     if (m_tried_unwind_arch_default == false && m_unwind_plan_arch_default_sp.get() == nullptr)
159     {
160         m_tried_unwind_arch_default = true;
161         Address current_pc;
162         ProcessSP process_sp (thread.CalculateProcess());
163         if (process_sp)
164         {
165             ABI *abi = process_sp->GetABI().get();
166             if (abi)
167             {
168                 m_unwind_plan_arch_default_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
169                 if (m_unwind_plan_arch_default_sp)
170                     abi->CreateDefaultUnwindPlan(*m_unwind_plan_arch_default_sp);
171             }
172         }
173     }
174 
175     return m_unwind_plan_arch_default_sp;
176 }
177 
178 UnwindPlanSP
179 FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry (Thread& thread)
180 {
181     Mutex::Locker locker (m_mutex);
182     if (m_tried_unwind_arch_default_at_func_entry == false
183         && m_unwind_plan_arch_default_at_func_entry_sp.get() == nullptr)
184     {
185         m_tried_unwind_arch_default_at_func_entry = true;
186         Address current_pc;
187         ProcessSP process_sp (thread.CalculateProcess());
188         if (process_sp)
189         {
190             ABI *abi = process_sp->GetABI().get();
191             if (abi)
192             {
193                 m_unwind_plan_arch_default_at_func_entry_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
194                 if (m_unwind_plan_arch_default_at_func_entry_sp)
195                     abi->CreateFunctionEntryUnwindPlan(*m_unwind_plan_arch_default_at_func_entry_sp);
196             }
197         }
198     }
199 
200     return m_unwind_plan_arch_default_at_func_entry_sp;
201 }
202 
203 
204 Address&
205 FuncUnwinders::GetFirstNonPrologueInsn (Target& target)
206 {
207     if (m_first_non_prologue_insn.IsValid())
208         return m_first_non_prologue_insn;
209     ExecutionContext exe_ctx (target.shared_from_this(), false);
210     UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
211     if (assembly_profiler_sp)
212         assembly_profiler_sp->FirstNonPrologueInsn (m_range, exe_ctx, m_first_non_prologue_insn);
213     return m_first_non_prologue_insn;
214 }
215 
216 const Address&
217 FuncUnwinders::GetFunctionStartAddress () const
218 {
219     return m_range.GetBaseAddress();
220 }
221 
222 lldb::UnwindAssemblySP
223 FuncUnwinders::GetUnwindAssemblyProfiler ()
224 {
225     UnwindAssemblySP assembly_profiler_sp;
226     ArchSpec arch;
227     if (m_unwind_table.GetArchitecture (arch))
228     {
229         assembly_profiler_sp = UnwindAssembly::FindPlugin (arch);
230     }
231     return assembly_profiler_sp;
232 }
233 
234 Address
235 FuncUnwinders::GetLSDAAddress (Target &target)
236 {
237     Address lsda_addr;
238     Mutex::Locker locker (m_mutex);
239 
240     GetUnwindPlanAtCallSite (target, -1);
241 
242     if (m_unwind_plan_call_site_sp && m_unwind_plan_call_site_sp->GetLSDAAddress().IsValid())
243     {
244         lsda_addr = m_unwind_plan_call_site_sp->GetLSDAAddress().IsValid();
245     }
246 
247     return lsda_addr;
248 }
249 
250 
251 Address
252 FuncUnwinders::GetPersonalityRoutinePtrAddress (Target &target)
253 {
254     Address personality_addr;
255     Mutex::Locker locker (m_mutex);
256 
257     GetUnwindPlanAtCallSite (target, -1);
258 
259     if (m_unwind_plan_call_site_sp && m_unwind_plan_call_site_sp->GetPersonalityFunctionPtr().IsValid())
260     {
261         personality_addr = m_unwind_plan_call_site_sp->GetPersonalityFunctionPtr().IsValid();
262     }
263 
264     return personality_addr;
265 }
266