1 //===-- UnwindAssemblyInstEmulation.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 "UnwindAssemblyInstEmulation.h"
11 
12 #include "llvm-c/EnhancedDisassembly.h"
13 
14 #include "lldb/Core/Address.h"
15 #include "lldb/Core/ArchSpec.h"
16 #include "lldb/Core/DataBufferHeap.h"
17 #include "lldb/Core/Disassembler.h"
18 #include "lldb/Core/Error.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Core/PluginManager.h"
21 #include "lldb/Core/StreamString.h"
22 #include "lldb/Target/ExecutionContext.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/Thread.h"
25 #include "lldb/Target/Target.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 
31 
32 //-----------------------------------------------------------------------------------------------
33 //  UnwindAssemblyParser_x86 method definitions
34 //-----------------------------------------------------------------------------------------------
35 
36 bool
37 UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& range,
38                                                                    Thread& thread,
39                                                                    UnwindPlan& unwind_plan)
40 {
41     if (range.GetByteSize() > 0 &&
42         range.GetBaseAddress().IsValid() &&
43         m_inst_emulator_ap.get())
44     {
45 
46         // The the instruction emulation subclass setup the unwind plan for the
47         // first instruction.
48         m_inst_emulator_ap->CreateFunctionEntryUnwind (unwind_plan);
49 
50         // CreateFunctionEntryUnwind should have created the first row. If it
51         // doesn't, then we are done.
52         if (unwind_plan.GetRowCount() == 0)
53             return false;
54 
55         ExecutionContext exe_ctx;
56         thread.CalculateExecutionContext(exe_ctx);
57         DisassemblerSP disasm_sp (Disassembler::DisassembleRange (m_arch,
58                                                                   NULL,
59                                                                   exe_ctx,
60                                                                   range));
61 
62         LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
63 
64         if (disasm_sp)
65         {
66 
67             m_range_ptr = ⦥
68             m_thread_ptr = &thread;
69             m_unwind_plan_ptr = &unwind_plan;
70 
71             const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
72             const bool show_address = true;
73             const bool show_bytes = true;
74             const bool raw = false;
75             // Initialize the CFA with a known value. In the 32 bit case
76             // it will be 0x80000000, and in the 64 bit case 0x8000000000000000.
77             // We use the address byte size to be safe for any future addresss sizes
78             m_inst_emulator_ap->GetRegisterInfo (unwind_plan.GetRegisterKind(),
79                                                  unwind_plan.GetInitialCFARegister(),
80                                                  m_cfa_reg_info);
81 
82             m_fp_is_cfa = false;
83             m_register_values.clear();
84             m_pushed_regs.clear();
85 
86             m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
87             RegisterValue cfa_reg_value;
88             cfa_reg_value.SetUInt (m_initial_sp, m_cfa_reg_info.byte_size);
89             SetRegisterValue (m_cfa_reg_info, cfa_reg_value);
90 
91             const InstructionList &inst_list = disasm_sp->GetInstructionList ();
92             const size_t num_instructions = inst_list.GetSize();
93             if (num_instructions > 0)
94             {
95                 Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
96                 const addr_t base_addr = inst->GetAddress().GetFileAddress();
97                 // Initialize the current row with the one row that was created
98                 // from the CreateFunctionEntryUnwind call above...
99                 m_curr_row = unwind_plan.GetLastRow();
100 
101                 for (size_t idx=0; idx<num_instructions; ++idx)
102                 {
103                     inst = inst_list.GetInstructionAtIndex (idx).get();
104                     if (inst)
105                     {
106 
107                         if (log && log->GetVerbose ())
108                         {
109                             StreamString strm;
110                             inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, &exe_ctx, raw);
111                             log->PutCString (strm.GetData());
112                         }
113 
114                         m_inst_emulator_ap->SetInstruction (inst->GetOpcode(),
115                                                             inst->GetAddress(),
116                                                             exe_ctx.GetTargetPtr());
117 
118                         m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);
119 
120                         if (unwind_plan.GetLastRow() != m_curr_row)
121                         {
122                             // Be sure to not edit the offset unless our row has changed
123                             // so that the "!=" call above doesn't trigger every time
124                             m_curr_row.SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
125                             // Append the new row
126                             unwind_plan.AppendRow (m_curr_row);
127                         }
128                     }
129                 }
130             }
131         }
132 
133         if (log && log->GetVerbose ())
134         {
135             StreamString strm;
136             lldb::addr_t base_addr = range.GetBaseAddress().GetLoadAddress(thread.CalculateTarget().get());
137             strm.Printf ("Resulting unwind rows for [0x%llx - 0x%llx):", base_addr, base_addr + range.GetByteSize());
138             unwind_plan.Dump(strm, &thread, base_addr);
139             log->PutCString (strm.GetData());
140         }
141         return unwind_plan.GetRowCount() > 0;
142     }
143     return false;
144 }
145 
146 bool
147 UnwindAssemblyInstEmulation::GetFastUnwindPlan (AddressRange& func,
148                                                 Thread& thread,
149                                                 UnwindPlan &unwind_plan)
150 {
151     return false;
152 }
153 
154 bool
155 UnwindAssemblyInstEmulation::FirstNonPrologueInsn (AddressRange& func,
156                                                    const ExecutionContext &exe_ctx,
157                                                    Address& first_non_prologue_insn)
158 {
159     return false;
160 }
161 
162 UnwindAssembly *
163 UnwindAssemblyInstEmulation::CreateInstance (const ArchSpec &arch)
164 {
165     std::auto_ptr<EmulateInstruction> inst_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypePrologueEpilogue, NULL));
166     // Make sure that all prologue instructions are handled
167     if (inst_emulator_ap.get())
168         return new UnwindAssemblyInstEmulation (arch, inst_emulator_ap.release());
169     return NULL;
170 }
171 
172 
173 //------------------------------------------------------------------
174 // PluginInterface protocol in UnwindAssemblyParser_x86
175 //------------------------------------------------------------------
176 
177 const char *
178 UnwindAssemblyInstEmulation::GetPluginName()
179 {
180     return "UnwindAssemblyInstEmulation";
181 }
182 
183 const char *
184 UnwindAssemblyInstEmulation::GetShortPluginName()
185 {
186     return "unwindassembly.inst-emulation";
187 }
188 
189 
190 uint32_t
191 UnwindAssemblyInstEmulation::GetPluginVersion()
192 {
193     return 1;
194 }
195 
196 void
197 UnwindAssemblyInstEmulation::Initialize()
198 {
199     PluginManager::RegisterPlugin (GetPluginNameStatic(),
200                                    GetPluginDescriptionStatic(),
201                                    CreateInstance);
202 }
203 
204 void
205 UnwindAssemblyInstEmulation::Terminate()
206 {
207     PluginManager::UnregisterPlugin (CreateInstance);
208 }
209 
210 
211 const char *
212 UnwindAssemblyInstEmulation::GetPluginNameStatic()
213 {
214     return "UnwindAssemblyInstEmulation";
215 }
216 
217 const char *
218 UnwindAssemblyInstEmulation::GetPluginDescriptionStatic()
219 {
220     return "Instruction emulation based unwind information.";
221 }
222 
223 
224 uint64_t
225 UnwindAssemblyInstEmulation::MakeRegisterKindValuePair (const RegisterInfo &reg_info)
226 {
227     uint32_t reg_kind, reg_num;
228     if (EmulateInstruction::GetBestRegisterKindAndNumber (&reg_info, reg_kind, reg_num))
229         return (uint64_t)reg_kind << 24 | reg_num;
230     return 0ull;
231 }
232 
233 void
234 UnwindAssemblyInstEmulation::SetRegisterValue (const RegisterInfo &reg_info, const RegisterValue &reg_value)
235 {
236     m_register_values[MakeRegisterKindValuePair (reg_info)] = reg_value;
237 }
238 
239 bool
240 UnwindAssemblyInstEmulation::GetRegisterValue (const RegisterInfo &reg_info, RegisterValue &reg_value)
241 {
242     const uint64_t reg_id = MakeRegisterKindValuePair (reg_info);
243     RegisterValueMap::const_iterator pos = m_register_values.find(reg_id);
244     if (pos != m_register_values.end())
245     {
246         reg_value = pos->second;
247         return true; // We had a real value that comes from an opcode that wrote
248                      // to it...
249     }
250     // We are making up a value that is recognizable...
251     reg_value.SetUInt(reg_id, reg_info.byte_size);
252     return false;
253 }
254 
255 
256 size_t
257 UnwindAssemblyInstEmulation::ReadMemory (EmulateInstruction *instruction,
258                                          void *baton,
259                                          const EmulateInstruction::Context &context,
260                                          lldb::addr_t addr,
261                                          void *dst,
262                                          size_t dst_len)
263 {
264     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
265 
266     if (log && log->GetVerbose ())
267     {
268         StreamString strm;
269         strm.Printf ("UnwindAssemblyInstEmulation::ReadMemory    (addr = 0x%16.16llx, dst = %p, dst_len = %zu, context = ",
270                      addr,
271                      dst,
272                      dst_len);
273         context.Dump(strm, instruction);
274         log->PutCString (strm.GetData ());
275     }
276     return dst_len;
277 }
278 
279 size_t
280 UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
281                                           void *baton,
282                                           const EmulateInstruction::Context &context,
283                                           lldb::addr_t addr,
284                                           const void *dst,
285                                           size_t dst_len)
286 {
287     if (baton && dst && dst_len)
288         return ((UnwindAssemblyInstEmulation *)baton)->WriteMemory (instruction, context, addr, dst, dst_len);
289     return 0;
290 }
291 
292 size_t
293 UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
294                                           const EmulateInstruction::Context &context,
295                                           lldb::addr_t addr,
296                                           const void *dst,
297                                           size_t dst_len)
298 {
299     DataExtractor data (dst,
300                         dst_len,
301                         instruction->GetArchitecture ().GetByteOrder(),
302                         instruction->GetArchitecture ().GetAddressByteSize());
303 
304     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
305 
306     if (log && log->GetVerbose ())
307     {
308         StreamString strm;
309 
310         strm.PutCString ("UnwindAssemblyInstEmulation::WriteMemory   (");
311         data.Dump(&strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, addr, 0, 0);
312         strm.PutCString (", context = ");
313         context.Dump(strm, instruction);
314         log->PutCString (strm.GetData());
315     }
316 
317     const bool can_replace = true;
318     const bool cant_replace = false;
319 
320     switch (context.type)
321     {
322         default:
323         case EmulateInstruction::eContextInvalid:
324         case EmulateInstruction::eContextReadOpcode:
325         case EmulateInstruction::eContextImmediate:
326         case EmulateInstruction::eContextAdjustBaseRegister:
327         case EmulateInstruction::eContextRegisterPlusOffset:
328         case EmulateInstruction::eContextAdjustPC:
329         case EmulateInstruction::eContextRegisterStore:
330         case EmulateInstruction::eContextRegisterLoad:
331         case EmulateInstruction::eContextRelativeBranchImmediate:
332         case EmulateInstruction::eContextAbsoluteBranchRegister:
333         case EmulateInstruction::eContextSupervisorCall:
334         case EmulateInstruction::eContextTableBranchReadMemory:
335         case EmulateInstruction::eContextWriteRegisterRandomBits:
336         case EmulateInstruction::eContextWriteMemoryRandomBits:
337         case EmulateInstruction::eContextArithmetic:
338         case EmulateInstruction::eContextAdvancePC:
339         case EmulateInstruction::eContextReturnFromException:
340         case EmulateInstruction::eContextPopRegisterOffStack:
341         case EmulateInstruction::eContextAdjustStackPointer:
342             break;
343 
344         case EmulateInstruction::eContextPushRegisterOnStack:
345             {
346                 uint32_t reg_num = LLDB_INVALID_REGNUM;
347                 bool is_return_address_reg = false;
348                 const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
349                 if (context.info_type == EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset)
350                 {
351                     reg_num = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[unwind_reg_kind];
352                     if (context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA)
353                         is_return_address_reg = true;
354                 }
355                 else
356                 {
357                     assert (!"unhandled case, add code to handle this!");
358                 }
359 
360                 if (reg_num != LLDB_INVALID_REGNUM)
361                 {
362                     if (m_pushed_regs.find (reg_num) == m_pushed_regs.end())
363                     {
364                         m_pushed_regs[reg_num] = addr;
365                         const int32_t offset = addr - m_initial_sp;
366                         m_curr_row.SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace);
367                         if (is_return_address_reg)
368                         {
369                             // This push was pushing the return address register,
370                             // so this is also how we will unwind the PC...
371                             RegisterInfo pc_reg_info;
372                             if (instruction->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
373                             {
374                                 uint32_t pc_reg_num = pc_reg_info.kinds[unwind_reg_kind];
375                                 if (pc_reg_num != LLDB_INVALID_REGNUM)
376                                     m_curr_row.SetRegisterLocationToAtCFAPlusOffset (pc_reg_num, offset, can_replace);
377                             }
378                         }
379                     }
380                 }
381             }
382             break;
383 
384     }
385 
386     return dst_len;
387 }
388 
389 bool
390 UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
391                                            void *baton,
392                                            const RegisterInfo *reg_info,
393                                            RegisterValue &reg_value)
394 {
395 
396     if (baton && reg_info)
397         return ((UnwindAssemblyInstEmulation *)baton)->ReadRegister (instruction, reg_info, reg_value);
398     return false;
399 }
400 bool
401 UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
402                                            const RegisterInfo *reg_info,
403                                            RegisterValue &reg_value)
404 {
405     bool synthetic = GetRegisterValue (*reg_info, reg_value);
406 
407     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
408 
409     if (log && log->GetVerbose ())
410     {
411 
412         StreamString strm;
413         strm.Printf ("UnwindAssemblyInstEmulation::ReadRegister  (name = \"%s\") => synthetic_value = %i, value = ", reg_info->name, synthetic);
414         reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
415         log->PutCString(strm.GetData());
416     }
417     return true;
418 }
419 
420 bool
421 UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
422                                             void *baton,
423                                             const EmulateInstruction::Context &context,
424                                             const RegisterInfo *reg_info,
425                                             const RegisterValue &reg_value)
426 {
427     if (baton && reg_info)
428         return ((UnwindAssemblyInstEmulation *)baton)->WriteRegister (instruction, context, reg_info, reg_value);
429     return false;
430 }
431 bool
432 UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
433                                             const EmulateInstruction::Context &context,
434                                             const RegisterInfo *reg_info,
435                                             const RegisterValue &reg_value)
436 {
437     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
438 
439     if (log && log->GetVerbose ())
440     {
441 
442         StreamString strm;
443         strm.Printf ("UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", reg_info->name);
444         reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
445         strm.PutCString (", context = ");
446         context.Dump(strm, instruction);
447         log->PutCString(strm.GetData());
448     }
449 
450     const bool must_replace = true;
451     SetRegisterValue (*reg_info, reg_value);
452 
453     switch (context.type)
454     {
455         default:
456         case EmulateInstruction::eContextInvalid:
457         case EmulateInstruction::eContextReadOpcode:
458         case EmulateInstruction::eContextImmediate:
459         case EmulateInstruction::eContextAdjustBaseRegister:
460         case EmulateInstruction::eContextRegisterPlusOffset:
461         case EmulateInstruction::eContextAdjustPC:
462         case EmulateInstruction::eContextRegisterStore:
463         case EmulateInstruction::eContextRegisterLoad:
464         case EmulateInstruction::eContextRelativeBranchImmediate:
465         case EmulateInstruction::eContextAbsoluteBranchRegister:
466         case EmulateInstruction::eContextSupervisorCall:
467         case EmulateInstruction::eContextTableBranchReadMemory:
468         case EmulateInstruction::eContextWriteRegisterRandomBits:
469         case EmulateInstruction::eContextWriteMemoryRandomBits:
470         case EmulateInstruction::eContextArithmetic:
471         case EmulateInstruction::eContextAdvancePC:
472         case EmulateInstruction::eContextReturnFromException:
473         case EmulateInstruction::eContextPushRegisterOnStack:
474 //            {
475 //                const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
476 //                if (reg_num != LLDB_INVALID_REGNUM)
477 //                {
478 //                    const bool can_replace_only_if_unspecified = true;
479 //
480 //                    m_curr_row.SetRegisterLocationToUndefined (reg_num,
481 //                                                               can_replace_only_if_unspecified,
482 //                                                               can_replace_only_if_unspecified);
483 //                }
484 //            }
485             break;
486 
487         case EmulateInstruction::eContextPopRegisterOffStack:
488             {
489                 const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
490                 if (reg_num != LLDB_INVALID_REGNUM)
491                 {
492                     m_curr_row.SetRegisterLocationToSame (reg_num, must_replace);
493                 }
494             }
495             break;
496 
497         case EmulateInstruction::eContextSetFramePointer:
498             if (!m_fp_is_cfa)
499             {
500                 m_fp_is_cfa = true;
501                 m_cfa_reg_info = *reg_info;
502                 const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
503                 assert (cfa_reg_num != LLDB_INVALID_REGNUM);
504                 m_curr_row.SetCFARegister(cfa_reg_num);
505                 m_curr_row.SetCFAOffset(m_initial_sp - reg_value.GetAsUInt64());
506             }
507             break;
508 
509         case EmulateInstruction::eContextAdjustStackPointer:
510             // If we have created a frame using the frame pointer, don't follow
511             // subsequent adjustments to the stack pointer.
512             if (!m_fp_is_cfa)
513             {
514                 m_curr_row.SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64());
515             }
516             break;
517     }
518     return true;
519 }
520 
521 
522