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.GetProcess().GetTarget());
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                                                    Target& target,
157                                                    Thread* thread,
158                                                    Address& first_non_prologue_insn)
159 {
160     return false;
161 }
162 
163 UnwindAssembly *
164 UnwindAssemblyInstEmulation::CreateInstance (const ArchSpec &arch)
165 {
166     std::auto_ptr<EmulateInstruction> inst_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypePrologueEpilogue, NULL));
167     // Make sure that all prologue instructions are handled
168     if (inst_emulator_ap.get())
169         return new UnwindAssemblyInstEmulation (arch, inst_emulator_ap.release());
170     return NULL;
171 }
172 
173 
174 //------------------------------------------------------------------
175 // PluginInterface protocol in UnwindAssemblyParser_x86
176 //------------------------------------------------------------------
177 
178 const char *
179 UnwindAssemblyInstEmulation::GetPluginName()
180 {
181     return "UnwindAssemblyInstEmulation";
182 }
183 
184 const char *
185 UnwindAssemblyInstEmulation::GetShortPluginName()
186 {
187     return "unwindassembly.inst-emulation";
188 }
189 
190 
191 uint32_t
192 UnwindAssemblyInstEmulation::GetPluginVersion()
193 {
194     return 1;
195 }
196 
197 void
198 UnwindAssemblyInstEmulation::Initialize()
199 {
200     PluginManager::RegisterPlugin (GetPluginNameStatic(),
201                                    GetPluginDescriptionStatic(),
202                                    CreateInstance);
203 }
204 
205 void
206 UnwindAssemblyInstEmulation::Terminate()
207 {
208     PluginManager::UnregisterPlugin (CreateInstance);
209 }
210 
211 
212 const char *
213 UnwindAssemblyInstEmulation::GetPluginNameStatic()
214 {
215     return "UnwindAssemblyInstEmulation";
216 }
217 
218 const char *
219 UnwindAssemblyInstEmulation::GetPluginDescriptionStatic()
220 {
221     return "Instruction emulation based unwind information.";
222 }
223 
224 
225 uint64_t
226 UnwindAssemblyInstEmulation::MakeRegisterKindValuePair (const RegisterInfo &reg_info)
227 {
228     uint32_t reg_kind, reg_num;
229     if (EmulateInstruction::GetBestRegisterKindAndNumber (&reg_info, reg_kind, reg_num))
230         return (uint64_t)reg_kind << 24 | reg_num;
231     return 0ull;
232 }
233 
234 void
235 UnwindAssemblyInstEmulation::SetRegisterValue (const RegisterInfo &reg_info, const RegisterValue &reg_value)
236 {
237     m_register_values[MakeRegisterKindValuePair (reg_info)] = reg_value;
238 }
239 
240 bool
241 UnwindAssemblyInstEmulation::GetRegisterValue (const RegisterInfo &reg_info, RegisterValue &reg_value)
242 {
243     const uint64_t reg_id = MakeRegisterKindValuePair (reg_info);
244     RegisterValueMap::const_iterator pos = m_register_values.find(reg_id);
245     if (pos != m_register_values.end())
246     {
247         reg_value = pos->second;
248         return true; // We had a real value that comes from an opcode that wrote
249                      // to it...
250     }
251     // We are making up a value that is recognizable...
252     reg_value.SetUInt(reg_id, reg_info.byte_size);
253     return false;
254 }
255 
256 
257 size_t
258 UnwindAssemblyInstEmulation::ReadMemory (EmulateInstruction *instruction,
259                                          void *baton,
260                                          const EmulateInstruction::Context &context,
261                                          lldb::addr_t addr,
262                                          void *dst,
263                                          size_t dst_len)
264 {
265     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
266 
267     if (log && log->GetVerbose ())
268     {
269         StreamString strm;
270         strm.Printf ("UnwindAssemblyInstEmulation::ReadMemory    (addr = 0x%16.16llx, dst = %p, dst_len = %zu, context = ",
271                      addr,
272                      dst,
273                      dst_len);
274         context.Dump(strm, instruction);
275         log->PutCString (strm.GetData ());
276     }
277     return dst_len;
278 }
279 
280 size_t
281 UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
282                                           void *baton,
283                                           const EmulateInstruction::Context &context,
284                                           lldb::addr_t addr,
285                                           const void *dst,
286                                           size_t dst_len)
287 {
288     if (baton && dst && dst_len)
289         return ((UnwindAssemblyInstEmulation *)baton)->WriteMemory (instruction, context, addr, dst, dst_len);
290     return 0;
291 }
292 
293 size_t
294 UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
295                                           const EmulateInstruction::Context &context,
296                                           lldb::addr_t addr,
297                                           const void *dst,
298                                           size_t dst_len)
299 {
300     DataExtractor data (dst,
301                         dst_len,
302                         instruction->GetArchitecture ().GetByteOrder(),
303                         instruction->GetArchitecture ().GetAddressByteSize());
304 
305     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
306 
307     if (log && log->GetVerbose ())
308     {
309         StreamString strm;
310 
311         strm.PutCString ("UnwindAssemblyInstEmulation::WriteMemory   (");
312         data.Dump(&strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, addr, 0, 0);
313         strm.PutCString (", context = ");
314         context.Dump(strm, instruction);
315         log->PutCString (strm.GetData());
316     }
317 
318     const bool can_replace = true;
319     const bool cant_replace = false;
320 
321     switch (context.type)
322     {
323         default:
324         case EmulateInstruction::eContextInvalid:
325         case EmulateInstruction::eContextReadOpcode:
326         case EmulateInstruction::eContextImmediate:
327         case EmulateInstruction::eContextAdjustBaseRegister:
328         case EmulateInstruction::eContextRegisterPlusOffset:
329         case EmulateInstruction::eContextAdjustPC:
330         case EmulateInstruction::eContextRegisterStore:
331         case EmulateInstruction::eContextRegisterLoad:
332         case EmulateInstruction::eContextRelativeBranchImmediate:
333         case EmulateInstruction::eContextAbsoluteBranchRegister:
334         case EmulateInstruction::eContextSupervisorCall:
335         case EmulateInstruction::eContextTableBranchReadMemory:
336         case EmulateInstruction::eContextWriteRegisterRandomBits:
337         case EmulateInstruction::eContextWriteMemoryRandomBits:
338         case EmulateInstruction::eContextArithmetic:
339         case EmulateInstruction::eContextAdvancePC:
340         case EmulateInstruction::eContextReturnFromException:
341         case EmulateInstruction::eContextPopRegisterOffStack:
342         case EmulateInstruction::eContextAdjustStackPointer:
343             break;
344 
345         case EmulateInstruction::eContextPushRegisterOnStack:
346             {
347                 uint32_t reg_num = LLDB_INVALID_REGNUM;
348                 bool is_return_address_reg = false;
349                 const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
350                 if (context.info_type == EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset)
351                 {
352                     reg_num = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[unwind_reg_kind];
353                     if (context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA)
354                         is_return_address_reg = true;
355                 }
356                 else
357                 {
358                     assert (!"unhandled case, add code to handle this!");
359                 }
360 
361                 if (reg_num != LLDB_INVALID_REGNUM)
362                 {
363                     if (m_pushed_regs.find (reg_num) == m_pushed_regs.end())
364                     {
365                         m_pushed_regs[reg_num] = addr;
366                         const int32_t offset = addr - m_initial_sp;
367                         m_curr_row.SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace);
368                         if (is_return_address_reg)
369                         {
370                             // This push was pushing the return address register,
371                             // so this is also how we will unwind the PC...
372                             RegisterInfo pc_reg_info;
373                             if (instruction->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
374                             {
375                                 uint32_t pc_reg_num = pc_reg_info.kinds[unwind_reg_kind];
376                                 if (pc_reg_num != LLDB_INVALID_REGNUM)
377                                     m_curr_row.SetRegisterLocationToAtCFAPlusOffset (pc_reg_num, offset, can_replace);
378                             }
379                         }
380                     }
381                 }
382             }
383             break;
384 
385     }
386 
387     return dst_len;
388 }
389 
390 bool
391 UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
392                                            void *baton,
393                                            const RegisterInfo *reg_info,
394                                            RegisterValue &reg_value)
395 {
396 
397     if (baton && reg_info)
398         return ((UnwindAssemblyInstEmulation *)baton)->ReadRegister (instruction, reg_info, reg_value);
399     return false;
400 }
401 bool
402 UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
403                                            const RegisterInfo *reg_info,
404                                            RegisterValue &reg_value)
405 {
406     bool synthetic = GetRegisterValue (*reg_info, reg_value);
407 
408     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
409 
410     if (log && log->GetVerbose ())
411     {
412 
413         StreamString strm;
414         strm.Printf ("UnwindAssemblyInstEmulation::ReadRegister  (name = \"%s\") => synthetic_value = %i, value = ", reg_info->name, synthetic);
415         reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
416         log->PutCString(strm.GetData());
417     }
418     return true;
419 }
420 
421 bool
422 UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
423                                             void *baton,
424                                             const EmulateInstruction::Context &context,
425                                             const RegisterInfo *reg_info,
426                                             const RegisterValue &reg_value)
427 {
428     if (baton && reg_info)
429         return ((UnwindAssemblyInstEmulation *)baton)->WriteRegister (instruction, context, reg_info, reg_value);
430     return false;
431 }
432 bool
433 UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
434                                             const EmulateInstruction::Context &context,
435                                             const RegisterInfo *reg_info,
436                                             const RegisterValue &reg_value)
437 {
438     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
439 
440     if (log && log->GetVerbose ())
441     {
442 
443         StreamString strm;
444         strm.Printf ("UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", reg_info->name);
445         reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
446         strm.PutCString (", context = ");
447         context.Dump(strm, instruction);
448         log->PutCString(strm.GetData());
449     }
450 
451     const bool must_replace = true;
452     SetRegisterValue (*reg_info, reg_value);
453 
454     switch (context.type)
455     {
456         default:
457         case EmulateInstruction::eContextInvalid:
458         case EmulateInstruction::eContextReadOpcode:
459         case EmulateInstruction::eContextImmediate:
460         case EmulateInstruction::eContextAdjustBaseRegister:
461         case EmulateInstruction::eContextRegisterPlusOffset:
462         case EmulateInstruction::eContextAdjustPC:
463         case EmulateInstruction::eContextRegisterStore:
464         case EmulateInstruction::eContextRegisterLoad:
465         case EmulateInstruction::eContextRelativeBranchImmediate:
466         case EmulateInstruction::eContextAbsoluteBranchRegister:
467         case EmulateInstruction::eContextSupervisorCall:
468         case EmulateInstruction::eContextTableBranchReadMemory:
469         case EmulateInstruction::eContextWriteRegisterRandomBits:
470         case EmulateInstruction::eContextWriteMemoryRandomBits:
471         case EmulateInstruction::eContextArithmetic:
472         case EmulateInstruction::eContextAdvancePC:
473         case EmulateInstruction::eContextReturnFromException:
474         case EmulateInstruction::eContextPushRegisterOnStack:
475 //            {
476 //                const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
477 //                if (reg_num != LLDB_INVALID_REGNUM)
478 //                {
479 //                    const bool can_replace_only_if_unspecified = true;
480 //
481 //                    m_curr_row.SetRegisterLocationToUndefined (reg_num,
482 //                                                               can_replace_only_if_unspecified,
483 //                                                               can_replace_only_if_unspecified);
484 //                }
485 //            }
486             break;
487 
488         case EmulateInstruction::eContextPopRegisterOffStack:
489             {
490                 const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
491                 if (reg_num != LLDB_INVALID_REGNUM)
492                 {
493                     m_curr_row.SetRegisterLocationToSame (reg_num, must_replace);
494                 }
495             }
496             break;
497 
498         case EmulateInstruction::eContextSetFramePointer:
499             if (!m_fp_is_cfa)
500             {
501                 m_fp_is_cfa = true;
502                 m_cfa_reg_info = *reg_info;
503                 const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
504                 assert (cfa_reg_num != LLDB_INVALID_REGNUM);
505                 m_curr_row.SetCFARegister(cfa_reg_num);
506                 m_curr_row.SetCFAOffset(m_initial_sp - reg_value.GetAsUInt64());
507             }
508             break;
509 
510         case EmulateInstruction::eContextAdjustStackPointer:
511             // If we have created a frame using the frame pointer, don't follow
512             // subsequent adjustments to the stack pointer.
513             if (!m_fp_is_cfa)
514             {
515                 m_curr_row.SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64());
516             }
517             break;
518     }
519     return true;
520 }
521 
522 
523