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