UnwindAssemblyInstEmulation.cpp revision 2d9b29b4bdc88d319761cac07f1692eef95c2a72
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//  UnwindAssemblyParser_x86 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            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
146bool
147UnwindAssemblyInstEmulation::GetFastUnwindPlan (AddressRange& func,
148                                                Thread& thread,
149                                                UnwindPlan &unwind_plan)
150{
151    return false;
152}
153
154bool
155UnwindAssemblyInstEmulation::FirstNonPrologueInsn (AddressRange& func,
156                                                   Target& target,
157                                                   Thread* thread,
158                                                   Address& first_non_prologue_insn)
159{
160    return false;
161}
162
163UnwindAssembly *
164UnwindAssemblyInstEmulation::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
178const char *
179UnwindAssemblyInstEmulation::GetPluginName()
180{
181    return "UnwindAssemblyInstEmulation";
182}
183
184const char *
185UnwindAssemblyInstEmulation::GetShortPluginName()
186{
187    return "unwindassembly.inst-emulation";
188}
189
190
191uint32_t
192UnwindAssemblyInstEmulation::GetPluginVersion()
193{
194    return 1;
195}
196
197void
198UnwindAssemblyInstEmulation::Initialize()
199{
200    PluginManager::RegisterPlugin (GetPluginNameStatic(),
201                                   GetPluginDescriptionStatic(),
202                                   CreateInstance);
203}
204
205void
206UnwindAssemblyInstEmulation::Terminate()
207{
208    PluginManager::UnregisterPlugin (CreateInstance);
209}
210
211
212const char *
213UnwindAssemblyInstEmulation::GetPluginNameStatic()
214{
215    return "UnwindAssemblyInstEmulation";
216}
217
218const char *
219UnwindAssemblyInstEmulation::GetPluginDescriptionStatic()
220{
221    return "Instruction emulation based unwind information.";
222}
223
224
225uint64_t
226UnwindAssemblyInstEmulation::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
234void
235UnwindAssemblyInstEmulation::SetRegisterValue (const RegisterInfo &reg_info, const RegisterValue &reg_value)
236{
237    m_register_values[MakeRegisterKindValuePair (reg_info)] = reg_value;
238}
239
240bool
241UnwindAssemblyInstEmulation::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
257size_t
258UnwindAssemblyInstEmulation::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
280size_t
281UnwindAssemblyInstEmulation::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
293size_t
294UnwindAssemblyInstEmulation::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
390bool
391UnwindAssemblyInstEmulation::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}
401bool
402UnwindAssemblyInstEmulation::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
421bool
422UnwindAssemblyInstEmulation::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}
432bool
433UnwindAssemblyInstEmulation::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