Пример #1
0
bool
Disassembler::Disassemble
(
    Debugger &debugger,
    const ArchSpec &arch,
    const char *plugin_name,
    const char *flavor,
    const ExecutionContext &exe_ctx,
    uint32_t num_instructions,
    uint32_t num_mixed_context_lines,
    uint32_t options,
    Stream &strm
)
{
    AddressRange range;
    StackFrame *frame = exe_ctx.GetFramePtr();
    if (frame)
    {
        SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
        if (sc.function)
        {
            range = sc.function->GetAddressRange();
        }
        else if (sc.symbol && sc.symbol->ValueIsAddress())
        {
            range.GetBaseAddress() = sc.symbol->GetAddress();
            range.SetByteSize (sc.symbol->GetByteSize());
        }
        else
        {
            range.GetBaseAddress() = frame->GetFrameCodeAddress();
        }

        if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
            range.SetByteSize (DEFAULT_DISASM_BYTE_SIZE);
    }

    return Disassemble (debugger, 
                        arch, 
                        plugin_name,
                        flavor,
                        exe_ctx, 
                        range, 
                        num_instructions, 
                        num_mixed_context_lines, 
                        options, 
                        strm);
}
Пример #2
0
bool AddressRange::Extend(const AddressRange &rhs_range) {
  addr_t lhs_end_addr = GetBaseAddress().GetFileAddress() + GetByteSize();
  addr_t rhs_base_addr = rhs_range.GetBaseAddress().GetFileAddress();

  if (!ContainsFileAddress(rhs_range.GetBaseAddress()) &&
      lhs_end_addr != rhs_base_addr)
    // The ranges don't intersect at all on the right side of this range.
    return false;

  addr_t rhs_end_addr = rhs_base_addr + rhs_range.GetByteSize();
  if (lhs_end_addr >= rhs_end_addr)
    // The rhs range totally overlaps this one, nothing to add.
    return false;

  m_byte_size += rhs_end_addr - lhs_end_addr;
  return true;
}
Пример #3
0
size_t
Disassembler::ParseInstructions
(
    const ExecutionContext *exe_ctx,
    const AddressRange &range,
    DataExtractor& data
)
{
    Target *target = exe_ctx->target;

    const addr_t byte_size = range.GetByteSize();
    if (target == NULL || byte_size == 0 || !range.GetBaseAddress().IsValid())
        return 0;

    DataBufferHeap *heap_buffer = new DataBufferHeap (byte_size, '\0');
    DataBufferSP data_sp(heap_buffer);

    Error error;
    const size_t bytes_read = target->ReadMemory (range.GetBaseAddress(), heap_buffer->GetBytes(), heap_buffer->GetByteSize(), error);
    
    if (bytes_read > 0)
    {
        if (bytes_read != heap_buffer->GetByteSize())
            heap_buffer->SetByteSize (bytes_read);

        data.SetData(data_sp);
        if (exe_ctx->process)
        {
            data.SetByteOrder(exe_ctx->process->GetByteOrder());
            data.SetAddressByteSize(exe_ctx->process->GetAddressByteSize());
        }
        else
        {
            data.SetByteOrder(target->GetArchitecture().GetDefaultEndian());
            data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
        }
        return DecodeInstructions (data, 0, UINT32_MAX);
    }

    return 0;
}
Пример #4
0
lldb::DisassemblerSP
Disassembler::DisassembleRange
(
    const ArchSpec &arch,
    const char *plugin_name,
    const ExecutionContext &exe_ctx,
    const AddressRange &range
)
{
    lldb::DisassemblerSP disasm_sp;
    if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid())
    {
        disasm_sp.reset (Disassembler::FindPlugin(arch, plugin_name));

        if (disasm_sp)
        {
            size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, NULL);
            if (bytes_disassembled == 0)
                disasm_sp.reset();
        }
    }
    return disasm_sp;
}
Пример #5
0
void
UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
{
   if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
       m_plan_valid_address_range = range;
}
Пример #6
0
//----------------------------------------------------------------------
// ThreadPlanStepOut: Step out of the current frame
//----------------------------------------------------------------------
ThreadPlanStepOut::ThreadPlanStepOut(
    Thread &thread, SymbolContext *context, bool first_insn, bool stop_others,
    Vote stop_vote, Vote run_vote, uint32_t frame_idx,
    LazyBool step_out_avoids_code_without_debug_info,
    bool continue_to_next_branch, bool gather_return_value)
    : ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, stop_vote,
                 run_vote),
      ThreadPlanShouldStopHere(this), m_step_from_insn(LLDB_INVALID_ADDRESS),
      m_return_bp_id(LLDB_INVALID_BREAK_ID),
      m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others),
      m_immediate_step_from_function(nullptr),
      m_calculate_return_value(gather_return_value) {
  SetFlagsToDefault();
  SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);

  m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);

  StackFrameSP return_frame_sp(m_thread.GetStackFrameAtIndex(frame_idx + 1));
  StackFrameSP immediate_return_from_sp(
      m_thread.GetStackFrameAtIndex(frame_idx));

  if (!return_frame_sp || !immediate_return_from_sp)
    return; // we can't do anything here.  ValidatePlan() will return false.

  m_step_out_to_id = return_frame_sp->GetStackID();
  m_immediate_step_from_id = immediate_return_from_sp->GetStackID();

  // If the frame directly below the one we are returning to is inlined, we have
  // to be
  // a little more careful.  It is non-trivial to determine the real "return
  // code address" for
  // an inlined frame, so we have to work our way to that frame and then step
  // out.
  if (immediate_return_from_sp && immediate_return_from_sp->IsInlined()) {
    if (frame_idx > 0) {
      // First queue a plan that gets us to this inlined frame, and when we get
      // there we'll queue a second
      // plan that walks us out of this frame.
      m_step_out_to_inline_plan_sp.reset(new ThreadPlanStepOut(
          m_thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion,
          frame_idx - 1, eLazyBoolNo, continue_to_next_branch));
      static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())
          ->SetShouldStopHereCallbacks(nullptr, nullptr);
      m_step_out_to_inline_plan_sp->SetPrivate(true);
    } else {
      // If we're already at the inlined frame we're stepping through, then just
      // do that now.
      QueueInlinedStepPlan(false);
    }
  } else if (return_frame_sp) {
    // Find the return address and set a breakpoint there:
    // FIXME - can we do this more securely if we know first_insn?

    Address return_address(return_frame_sp->GetFrameCodeAddress());
    if (continue_to_next_branch) {
      SymbolContext return_address_sc;
      AddressRange range;
      Address return_address_decr_pc = return_address;
      if (return_address_decr_pc.GetOffset() > 0)
        return_address_decr_pc.Slide(-1);

      return_address_decr_pc.CalculateSymbolContext(
          &return_address_sc, lldb::eSymbolContextLineEntry);
      if (return_address_sc.line_entry.IsValid()) {
        range =
            return_address_sc.line_entry.GetSameLineContiguousAddressRange();
        if (range.GetByteSize() > 0) {
          return_address =
              m_thread.GetProcess()->AdvanceAddressToNextBranchInstruction(
                  return_address, range);
        }
      }
    }
    m_return_addr =
        return_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget());

    if (m_return_addr == LLDB_INVALID_ADDRESS)
      return;

    Breakpoint *return_bp = m_thread.CalculateTarget()
                                ->CreateBreakpoint(m_return_addr, true, false)
                                .get();
    if (return_bp != nullptr) {
      return_bp->SetThreadID(m_thread.GetID());
      m_return_bp_id = return_bp->GetID();
      return_bp->SetBreakpointKind("step-out");
    }

    if (immediate_return_from_sp) {
      const SymbolContext &sc =
          immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction);
      if (sc.function) {
        m_immediate_step_from_function = sc.function;
      }
    }
  }
}
Пример #7
0
bool
CommandObjectDisassemble::Execute
(
    CommandInterpreter &interpreter,
    Args& command,
    CommandReturnObject &result
)
{
    Target *target = interpreter.GetDebugger().GetCurrentTarget().get();
    if (target == NULL)
    {
        result.AppendError ("invalid target, set executable file using 'file' command");
        result.SetStatus (eReturnStatusFailed);
        return false;
    }

    ArchSpec arch(target->GetArchitecture());
    if (!arch.IsValid())
    {
        result.AppendError ("target needs valid architecure in order to be able to disassemble");
        result.SetStatus (eReturnStatusFailed);
        return false;
    }

    Disassembler *disassembler = Disassembler::FindPlugin(arch);

    if (disassembler == NULL)
    {
        result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for %s architecture.\n", arch.AsCString());
        result.SetStatus (eReturnStatusFailed);
        return false;
    }

    result.SetStatus (eReturnStatusSuccessFinishResult);

    if (command.GetArgumentCount() != 0)
    {
        result.AppendErrorWithFormat ("\"disassemble\" doesn't take any arguments.\n");
        result.SetStatus (eReturnStatusFailed);
        return false;
    }
    ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext());

    if (m_options.show_mixed && m_options.num_lines_context == 0)
        m_options.num_lines_context = 3;

    if (!m_options.m_func_name.empty())
    {
        ConstString name(m_options.m_func_name.c_str());
        
        if (Disassembler::Disassemble (interpreter.GetDebugger(), 
                                       arch,
                                       exe_ctx,
                                       name,
                                       NULL,    // Module *
                                       m_options.show_mixed ? m_options.num_lines_context : 0,
                                       m_options.show_bytes,
                                       result.GetOutputStream()))
        {
            result.SetStatus (eReturnStatusSuccessFinishResult);
        }
        else
        {
            result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
            result.SetStatus (eReturnStatusFailed);
        }
    } 
    else
    {
        AddressRange range;
        if (m_options.m_start_addr != LLDB_INVALID_ADDRESS)
        {
            range.GetBaseAddress().SetOffset (m_options.m_start_addr);
            if (m_options.m_end_addr != LLDB_INVALID_ADDRESS)
            {
                if (m_options.m_end_addr < m_options.m_start_addr)
                {
                    result.AppendErrorWithFormat ("End address before start address.\n");
                    result.SetStatus (eReturnStatusFailed);
                    return false;            
                }
                range.SetByteSize (m_options.m_end_addr - m_options.m_start_addr);
            }
            else
                range.SetByteSize (DEFAULT_DISASM_BYTE_SIZE);
        } 
        else
        {
            if (exe_ctx.frame)
            {
                SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
                if (sc.function)
                    range = sc.function->GetAddressRange();
                else if (sc.symbol && sc.symbol->GetAddressRangePtr())
                    range = *sc.symbol->GetAddressRangePtr();
                else
                    range.GetBaseAddress() = exe_ctx.frame->GetPC();
            }
            else
            {
                result.AppendError ("invalid frame");
                result.SetStatus (eReturnStatusFailed);
                return false;
            }
        }
        if (range.GetByteSize() == 0)
            range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);

        if (Disassembler::Disassemble (interpreter.GetDebugger(), 
                                       arch,
                                       exe_ctx,
                                       range,
                                       m_options.show_mixed ? m_options.num_lines_context : 0,
                                       m_options.show_bytes,
                                       result.GetOutputStream()))
        {
            result.SetStatus (eReturnStatusSuccessFinishResult);
        }
        else
        {
            result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8llx.\n", m_options.m_start_addr);
            result.SetStatus (eReturnStatusFailed);            
        }
    }

    return result.Succeeded();
}
bool
CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
{
    Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
    if (target == NULL)
    {
        result.AppendError ("invalid target, create a debug target using the 'target create' command");
        result.SetStatus (eReturnStatusFailed);
        return false;
    }
    if (!m_options.arch.IsValid())
        m_options.arch = target->GetArchitecture();

    if (!m_options.arch.IsValid())
    {
        result.AppendError ("use the --arch option or set the target architecure to disassemble");
        result.SetStatus (eReturnStatusFailed);
        return false;
    }

    const char *plugin_name = m_options.GetPluginName ();
    const char *flavor_string = m_options.GetFlavorString();

    DisassemblerSP disassembler = Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);

    if (!disassembler)
    {
        if (plugin_name)
        {
            result.AppendErrorWithFormat ("Unable to find Disassembler plug-in named '%s' that supports the '%s' architecture.\n",
                                          plugin_name,
                                          m_options.arch.GetArchitectureName());
        }
        else
            result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for the '%s' architecture.\n", 
                                          m_options.arch.GetArchitectureName());
        result.SetStatus (eReturnStatusFailed);
        return false;
    }
    else if (flavor_string != NULL && !disassembler->FlavorValidForArchSpec(m_options.arch, flavor_string))
        result.AppendWarningWithFormat("invalid disassembler flavor \"%s\", using default.\n", flavor_string);

    result.SetStatus (eReturnStatusSuccessFinishResult);

    if (command.GetArgumentCount() != 0)
    {
        result.AppendErrorWithFormat ("\"disassemble\" arguments are specified as options.\n");
        GetOptions()->GenerateOptionUsage (result.GetErrorStream(), this);
        result.SetStatus (eReturnStatusFailed);
        return false;
    }
    
    if (m_options.show_mixed && m_options.num_lines_context == 0)
        m_options.num_lines_context = 1;

    // Always show the PC in the disassembly
    uint32_t options = Disassembler::eOptionMarkPCAddress;

    // Mark the source line for the current PC only if we are doing mixed source and assembly
    if (m_options.show_mixed)
        options |= Disassembler::eOptionMarkPCSourceLine;

    if (m_options.show_bytes)
        options |= Disassembler::eOptionShowBytes;

    if (m_options.raw)
        options |= Disassembler::eOptionRawOuput;

    if (!m_options.func_name.empty())
    {
        ConstString name(m_options.func_name.c_str());
        
        if (Disassembler::Disassemble (m_interpreter.GetDebugger(), 
                                       m_options.arch,
                                       plugin_name,
                                       flavor_string,
                                       m_exe_ctx,
                                       name,
                                       NULL,    // Module *
                                       m_options.num_instructions,
                                       m_options.show_mixed ? m_options.num_lines_context : 0,
                                       options,
                                       result.GetOutputStream()))
        {
            result.SetStatus (eReturnStatusSuccessFinishResult);
        }
        else
        {
            result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
            result.SetStatus (eReturnStatusFailed);
        }
    } 
    else
    {
        std::vector<AddressRange> ranges;
        AddressRange range;
        StackFrame *frame = m_exe_ctx.GetFramePtr();
        if (m_options.frame_line)
        {
            if (frame == NULL)
            {
                result.AppendError ("Cannot disassemble around the current line without a selected frame.\n");
                result.SetStatus (eReturnStatusFailed);
                return false;
            }
            LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
            if (pc_line_entry.IsValid())
            {
                range = pc_line_entry.range;
            }
            else
            {
                m_options.at_pc = true; // No line entry, so just disassemble around the current pc
                m_options.show_mixed = false;
            }
        }
        else if (m_options.current_function)
        {
            if (frame == NULL)
            {
                result.AppendError ("Cannot disassemble around the current function without a selected frame.\n");
                result.SetStatus (eReturnStatusFailed);
                return false;
            }
            Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
            if (symbol)
            {
                range.GetBaseAddress() = symbol->GetAddress();
                range.SetByteSize(symbol->GetByteSize());
            }
        }

        // Did the "m_options.frame_line" find a valid range already? If so
        // skip the rest...
        if (range.GetByteSize() == 0)
        {
            if (m_options.at_pc)
            {
                if (frame == NULL)
                {
                    result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n");
                    result.SetStatus (eReturnStatusFailed);
                    return false;
                }
                range.GetBaseAddress() = frame->GetFrameCodeAddress();
                if (m_options.num_instructions == 0)
                {
                    // Disassembling at the PC always disassembles some number of instructions (not the whole function).
                    m_options.num_instructions = DEFAULT_DISASM_NUM_INS;
                }
                ranges.push_back(range);
            }
            else
            {
                range.GetBaseAddress().SetOffset (m_options.start_addr);
                if (range.GetBaseAddress().IsValid())
                {
                    if (m_options.end_addr != LLDB_INVALID_ADDRESS)
                    {
                        if (m_options.end_addr <= m_options.start_addr)
                        {
                            result.AppendErrorWithFormat ("End address before start address.\n");
                            result.SetStatus (eReturnStatusFailed);
                            return false;            
                        }
                        range.SetByteSize (m_options.end_addr - m_options.start_addr);
                    }
                    ranges.push_back(range);
                }
                else
                {
                    if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS 
                        && target)
                    {
                        if (!target->GetSectionLoadList().IsEmpty())
                        {
                            bool failed = false;
                            Address symbol_containing_address;
                            if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address))
                            {
                                ModuleSP module_sp (symbol_containing_address.GetModule());
                                SymbolContext sc;
                                bool resolve_tail_call_address = true; // PC can be one past the address range of the function.
                                module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc,
                                                                           resolve_tail_call_address);
                                if (sc.function || sc.symbol)
                                {
                                    sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
                                }
                                else
                                {
                                    failed = true;
                                }
                            }
                            else
                            {
                                failed = true;
                            }
                            if (failed)
                            {
                                result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr);
                                result.SetStatus (eReturnStatusFailed);
                                return false;
                            }
                            ranges.push_back(range);
                        }
                        else
                        {
                            for (lldb::ModuleSP module_sp : target->GetImages().Modules())
                            {
                                lldb::addr_t file_addr = m_options.symbol_containing_addr;
                                Address file_address;
                                if (module_sp->ResolveFileAddress(file_addr, file_address))
                                {
                                    SymbolContext sc;
                                    bool resolve_tail_call_address = true; // PC can be one past the address range of the function.
                                    module_sp->ResolveSymbolContextForAddress (file_address, eSymbolContextEverything, sc, resolve_tail_call_address);
                                    if (sc.function || sc.symbol)
                                    {
                                        sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
                                        ranges.push_back(range);
                                    }
                                }
                            }
                            
                        }
                    }
                }
            }
        }
        else
            ranges.push_back(range);

        if (m_options.num_instructions != 0)
        {
            if (ranges.size() == 0)
            {
                // The default action is to disassemble the current frame function.
                if (frame)
                {
                    SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
                    if (sc.function)
                        range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress();
                    else if (sc.symbol && sc.symbol->ValueIsAddress())
                        range.GetBaseAddress() = sc.symbol->GetAddress();
                    else
                        range.GetBaseAddress() = frame->GetFrameCodeAddress();
                }
                
                if (!range.GetBaseAddress().IsValid())
                {
                    result.AppendError ("invalid frame");
                    result.SetStatus (eReturnStatusFailed);
                    return false;
                }
            }
            
            bool print_sc_header = ranges.size() > 1;
            for (AddressRange cur_range : ranges)
            {
                if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
                                               m_options.arch,
                                               plugin_name,
                                               flavor_string,
                                               m_exe_ctx,
                                               cur_range.GetBaseAddress(),
                                               m_options.num_instructions,
                                               m_options.show_mixed ? m_options.num_lines_context : 0,
                                               options,
                                               result.GetOutputStream()))
                {
                    result.SetStatus (eReturnStatusSuccessFinishResult);
                }
                else
                {
                    if (m_options.start_addr != LLDB_INVALID_ADDRESS)
                        result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
                    else if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS)
                        result.AppendErrorWithFormat ("Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n", m_options.symbol_containing_addr);
                    result.SetStatus (eReturnStatusFailed);
                }
            }
            if (print_sc_header)
                result.AppendMessage("\n");
        }
        else
        {
            if (ranges.size() == 0)
            {
                // The default action is to disassemble the current frame function.
                if (frame)
                {
                    SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
                    if (sc.function)
                        range = sc.function->GetAddressRange();
                    else if (sc.symbol && sc.symbol->ValueIsAddress())
                    {
                        range.GetBaseAddress() = sc.symbol->GetAddress();
                        range.SetByteSize (sc.symbol->GetByteSize());
                    }
                    else
                        range.GetBaseAddress() = frame->GetFrameCodeAddress();
                }
                else
                {
                    result.AppendError ("invalid frame");
                    result.SetStatus (eReturnStatusFailed);
                    return false;
                }
                ranges.push_back(range);
            }
            
            bool print_sc_header = ranges.size() > 1;
            for (AddressRange cur_range : ranges)
            {
                if (cur_range.GetByteSize() == 0)
                    cur_range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);

                if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
                                               m_options.arch,
                                               plugin_name,
                                               flavor_string,
                                               m_exe_ctx,
                                               cur_range,
                                               m_options.num_instructions,
                                               m_options.show_mixed ? m_options.num_lines_context : 0,
                                               options,
                                               result.GetOutputStream()))
                {
                    result.SetStatus (eReturnStatusSuccessFinishResult);
                }
                else
                {
                    result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
                    result.SetStatus (eReturnStatusFailed);            
                }
                if (print_sc_header)
                    result.AppendMessage("\n");
            }
        }
    }

    return result.Succeeded();
}
bool
UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& range, 
                                                                   Thread& thread, 
                                                                   UnwindPlan& unwind_plan)
{
    if (range.GetByteSize() > 0 && 
        range.GetBaseAddress().IsValid() &&
        m_inst_emulator_ap.get())
    {
     
        // The instruction emulation subclass setup the unwind plan for the
        // first instruction.
        m_inst_emulator_ap->CreateFunctionEntryUnwind (unwind_plan);

        // CreateFunctionEntryUnwind should have created the first row. If it
        // doesn't, then we are done.
        if (unwind_plan.GetRowCount() == 0)
            return false;
        
        ExecutionContext exe_ctx;
        thread.CalculateExecutionContext(exe_ctx);
        const bool prefer_file_cache = true;
        DisassemblerSP disasm_sp (Disassembler::DisassembleRange (m_arch,
                                                                  NULL,
                                                                  NULL,
                                                                  exe_ctx,
                                                                  range,
                                                                  prefer_file_cache));
        
        Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));

        if (disasm_sp)
        {
            
            m_range_ptr = &range;
            m_thread_ptr = &thread;
            m_unwind_plan_ptr = &unwind_plan;

            const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
            const bool show_address = true;
            const bool show_bytes = true;
            m_inst_emulator_ap->GetRegisterInfo (unwind_plan.GetRegisterKind(), 
                                                 unwind_plan.GetInitialCFARegister(), 
                                                 m_cfa_reg_info);
            
            m_fp_is_cfa = false;
            m_register_values.clear();
            m_pushed_regs.clear();

            // Initialize the CFA with a known value. In the 32 bit case
            // it will be 0x80000000, and in the 64 bit case 0x8000000000000000.
            // We use the address byte size to be safe for any future address sizes
            m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
            RegisterValue cfa_reg_value;
            cfa_reg_value.SetUInt (m_initial_sp, m_cfa_reg_info.byte_size);
            SetRegisterValue (m_cfa_reg_info, cfa_reg_value);

            const InstructionList &inst_list = disasm_sp->GetInstructionList ();
            const size_t num_instructions = inst_list.GetSize();

            if (num_instructions > 0)
            {
                Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
                const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();

                // Map for storing the unwind plan row and the value of the registers at a given offset.
                // When we see a forward branch we add a new entry to this map with the actual unwind plan
                // row and register context for the target address of the branch as the current data have
                // to be valid for the target address of the branch too if we are in the same function.
                std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>> saved_unwind_states;

                // Make a copy of the current instruction Row and save it in m_curr_row
                // so we can add updates as we process the instructions.  
                UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();
                UnwindPlan::Row *newrow = new UnwindPlan::Row;
                if (last_row.get())
                    *newrow = *last_row.get();
                m_curr_row.reset(newrow);

                // Add the initial state to the save list with offset 0.
                saved_unwind_states.insert({0, {last_row, m_register_values}});

                // cache the pc register number (in whatever register numbering this UnwindPlan uses) for
                // quick reference during instruction parsing.
                uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
                RegisterInfo pc_reg_info;
                if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
                    pc_reg_num = pc_reg_info.kinds[unwind_plan.GetRegisterKind()];
                else
                    pc_reg_num = LLDB_INVALID_REGNUM;

                // cache the return address register number (in whatever register numbering this UnwindPlan uses) for
                // quick reference during instruction parsing.
                uint32_t ra_reg_num = LLDB_INVALID_REGNUM;
                RegisterInfo ra_reg_info;
                if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info))
                    ra_reg_num = ra_reg_info.kinds[unwind_plan.GetRegisterKind()];
                else
                    ra_reg_num = LLDB_INVALID_REGNUM;

                for (size_t idx=0; idx<num_instructions; ++idx)
                {
                    m_curr_row_modified = false;
                    m_forward_branch_offset = 0;

                    inst = inst_list.GetInstructionAtIndex (idx).get();
                    if (inst)
                    {
                        lldb::addr_t current_offset = inst->GetAddress().GetFileAddress() - base_addr;
                        auto it = saved_unwind_states.upper_bound(current_offset);
                        assert(it != saved_unwind_states.begin() && "Unwind row for the function entry missing");
                        --it; // Move it to the row corresponding to the current offset

                        // If the offset of m_curr_row don't match with the offset we see in saved_unwind_states
                        // then we have to update m_curr_row and m_register_values based on the saved values. It
                        // is happenning after we processed an epilogue and a return to caller instruction.
                        if (it->second.first->GetOffset() != m_curr_row->GetOffset())
                        {
                            UnwindPlan::Row *newrow = new UnwindPlan::Row;
                            *newrow = *it->second.first;
                            m_curr_row.reset(newrow);
                            m_register_values = it->second.second;;
                        }

                        if (log && log->GetVerbose ())
                        {
                            StreamString strm;
                            lldb_private::FormatEntity::Entry format;
                            FormatEntity::Parse("${frame.pc}: ", format);
                            inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL, NULL, NULL, &format, 0);
                            log->PutCString (strm.GetData());
                        }

                        m_inst_emulator_ap->SetInstruction (inst->GetOpcode(), 
                                                            inst->GetAddress(), 
                                                            exe_ctx.GetTargetPtr());

                        m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);

                        // If the current instruction is a branch forward then save the current CFI information
                        // for the offset where we are branching.
                        if (m_forward_branch_offset != 0 && range.ContainsFileAddress(inst->GetAddress().GetFileAddress() + m_forward_branch_offset))
                        {
                            auto newrow = std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
                            newrow->SetOffset(current_offset + m_forward_branch_offset);
                            saved_unwind_states.insert({current_offset + m_forward_branch_offset, {newrow, m_register_values}});
                            unwind_plan.InsertRow(newrow);
                        }

                        // Were there any changes to the CFI while evaluating this instruction?
                        if (m_curr_row_modified)
                        {
                            // Save the modified row if we don't already have a CFI row in the currennt address
                            if (saved_unwind_states.count(current_offset + inst->GetOpcode().GetByteSize()) == 0)
                            {
                                m_curr_row->SetOffset (current_offset + inst->GetOpcode().GetByteSize());
                                unwind_plan.InsertRow (m_curr_row);
                                saved_unwind_states.insert({current_offset + inst->GetOpcode().GetByteSize(), {m_curr_row, m_register_values}});

                                // Allocate a new Row for m_curr_row, copy the current state into it
                                UnwindPlan::Row *newrow = new UnwindPlan::Row;
                                *newrow = *m_curr_row.get();
                                m_curr_row.reset(newrow);
                            }
                        }
                    }
                }
            }
            // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
            // I'll fix that but for now, just clear the list and it will go away nicely.
            disasm_sp->GetInstructionList().Clear();
        }
        
        if (log && log->GetVerbose ())
        {
            StreamString strm;
            lldb::addr_t base_addr = range.GetBaseAddress().GetLoadAddress(thread.CalculateTarget().get());
            strm.Printf ("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):", base_addr, base_addr + range.GetByteSize());
            unwind_plan.Dump(strm, &thread, base_addr);
            log->PutCString (strm.GetData());
        }
        return unwind_plan.GetRowCount() > 0;
    }
    return false;
}
bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite(
    AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {
  bool do_augment_unwindplan = true;

  UnwindPlan::RowSP first_row = unwind_plan.GetRowForFunctionOffset(0);
  UnwindPlan::RowSP last_row = unwind_plan.GetRowForFunctionOffset(-1);

  int wordsize = 8;
  ProcessSP process_sp(thread.GetProcess());
  if (process_sp.get() == nullptr)
    return false;

  wordsize = process_sp->GetTarget().GetArchitecture().GetAddressByteSize();

  RegisterNumber sp_regnum(thread, eRegisterKindGeneric,
                           LLDB_REGNUM_GENERIC_SP);
  RegisterNumber pc_regnum(thread, eRegisterKindGeneric,
                           LLDB_REGNUM_GENERIC_PC);

  // Does this UnwindPlan describe the prologue?  I want to see that the CFA is
  // set in terms of the stack pointer plus an offset, and I want to see that
  // rip is retrieved at the CFA-wordsize. If there is no description of the
  // prologue, don't try to augment this eh_frame unwinder code, fall back to
  // assembly parsing instead.

  if (first_row->GetCFAValue().GetValueType() !=
          UnwindPlan::Row::FAValue::isRegisterPlusOffset ||
      RegisterNumber(thread, unwind_plan.GetRegisterKind(),
                     first_row->GetCFAValue().GetRegisterNumber()) !=
          sp_regnum ||
      first_row->GetCFAValue().GetOffset() != wordsize) {
    return false;
  }
  UnwindPlan::Row::RegisterLocation first_row_pc_loc;
  if (!first_row->GetRegisterInfo(
          pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()),
          first_row_pc_loc) ||
      !first_row_pc_loc.IsAtCFAPlusOffset() ||
      first_row_pc_loc.GetOffset() != -wordsize) {
    return false;
  }

  // It looks like the prologue is described. Is the epilogue described?  If it
  // is, no need to do any augmentation.

  if (first_row != last_row &&
      first_row->GetOffset() != last_row->GetOffset()) {
    // The first & last row have the same CFA register and the same CFA offset
    // value and the CFA register is esp/rsp (the stack pointer).

    // We're checking that both of them have an unwind rule like "CFA=esp+4" or
    // CFA+rsp+8".

    if (first_row->GetCFAValue().GetValueType() ==
            last_row->GetCFAValue().GetValueType() &&
        first_row->GetCFAValue().GetRegisterNumber() ==
            last_row->GetCFAValue().GetRegisterNumber() &&
        first_row->GetCFAValue().GetOffset() ==
            last_row->GetCFAValue().GetOffset()) {
      // Get the register locations for eip/rip from the first & last rows. Are
      // they both CFA plus an offset?  Is it the same offset?

      UnwindPlan::Row::RegisterLocation last_row_pc_loc;
      if (last_row->GetRegisterInfo(
              pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()),
              last_row_pc_loc)) {
        if (last_row_pc_loc.IsAtCFAPlusOffset() &&
            first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset()) {

          // One last sanity check:  Is the unwind rule for getting the caller
          // pc value "deref the CFA-4" or "deref the CFA-8"?

          // If so, we have an UnwindPlan that already describes the epilogue
          // and we don't need to modify it at all.

          if (first_row_pc_loc.GetOffset() == -wordsize) {
            do_augment_unwindplan = false;
          }
        }
      }
    }
  }

  if (do_augment_unwindplan) {
    if (!func.GetBaseAddress().IsValid() || func.GetByteSize() == 0)
      return false;
    if (m_assembly_inspection_engine == nullptr)
      return false;
    const bool prefer_file_cache = true;
    std::vector<uint8_t> function_text(func.GetByteSize());
    Status error;
    if (process_sp->GetTarget().ReadMemory(
            func.GetBaseAddress(), prefer_file_cache, function_text.data(),
            func.GetByteSize(), error) == func.GetByteSize()) {
      RegisterContextSP reg_ctx(thread.GetRegisterContext());
      m_assembly_inspection_engine->Initialize(reg_ctx);
      return m_assembly_inspection_engine->AugmentUnwindPlanFromCallSite(
          function_text.data(), func.GetByteSize(), func, unwind_plan, reg_ctx);
    }
  }

  return false;
}
Пример #11
0
bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
    AddressRange &range, uint8_t *opcode_data, size_t opcode_size,
    UnwindPlan &unwind_plan) {
  if (opcode_data == nullptr || opcode_size == 0)
    return false;

  if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid() &&
      m_inst_emulator_ap.get()) {

    // The instruction emulation subclass setup the unwind plan for the
    // first instruction.
    m_inst_emulator_ap->CreateFunctionEntryUnwind(unwind_plan);

    // CreateFunctionEntryUnwind should have created the first row. If it
    // doesn't, then we are done.
    if (unwind_plan.GetRowCount() == 0)
      return false;

    const bool prefer_file_cache = true;
    DisassemblerSP disasm_sp(Disassembler::DisassembleBytes(
        m_arch, NULL, NULL, range.GetBaseAddress(), opcode_data, opcode_size,
        99999, prefer_file_cache));

    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));

    if (disasm_sp) {

      m_range_ptr = &range;
      m_unwind_plan_ptr = &unwind_plan;

      const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
      const bool show_address = true;
      const bool show_bytes = true;
      m_inst_emulator_ap->GetRegisterInfo(unwind_plan.GetRegisterKind(),
                                          unwind_plan.GetInitialCFARegister(),
                                          m_cfa_reg_info);

      m_fp_is_cfa = false;
      m_register_values.clear();
      m_pushed_regs.clear();

      // Initialize the CFA with a known value. In the 32 bit case
      // it will be 0x80000000, and in the 64 bit case 0x8000000000000000.
      // We use the address byte size to be safe for any future address sizes
      m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
      RegisterValue cfa_reg_value;
      cfa_reg_value.SetUInt(m_initial_sp, m_cfa_reg_info.byte_size);
      SetRegisterValue(m_cfa_reg_info, cfa_reg_value);

      const InstructionList &inst_list = disasm_sp->GetInstructionList();
      const size_t num_instructions = inst_list.GetSize();

      if (num_instructions > 0) {
        Instruction *inst = inst_list.GetInstructionAtIndex(0).get();
        const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();

        // Map for storing the unwind plan row and the value of the registers at
        // a given offset.
        // When we see a forward branch we add a new entry to this map with the
        // actual unwind plan
        // row and register context for the target address of the branch as the
        // current data have
        // to be valid for the target address of the branch too if we are in the
        // same function.
        std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>>
            saved_unwind_states;

        // Make a copy of the current instruction Row and save it in m_curr_row
        // so we can add updates as we process the instructions.
        UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();
        UnwindPlan::Row *newrow = new UnwindPlan::Row;
        if (last_row.get())
          *newrow = *last_row.get();
        m_curr_row.reset(newrow);

        // Add the initial state to the save list with offset 0.
        saved_unwind_states.insert({0, {last_row, m_register_values}});

        // cache the pc register number (in whatever register numbering this
        // UnwindPlan uses) for
        // quick reference during instruction parsing.
        RegisterInfo pc_reg_info;
        m_inst_emulator_ap->GetRegisterInfo(
            eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info);

        // cache the return address register number (in whatever register
        // numbering this UnwindPlan uses) for
        // quick reference during instruction parsing.
        RegisterInfo ra_reg_info;
        m_inst_emulator_ap->GetRegisterInfo(
            eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info);

        // The architecture dependent condition code of the last processed
        // instruction.
        EmulateInstruction::InstructionCondition last_condition =
            EmulateInstruction::UnconditionalCondition;
        lldb::addr_t condition_block_start_offset = 0;

        for (size_t idx = 0; idx < num_instructions; ++idx) {
          m_curr_row_modified = false;
          m_forward_branch_offset = 0;

          inst = inst_list.GetInstructionAtIndex(idx).get();
          if (inst) {
            lldb::addr_t current_offset =
                inst->GetAddress().GetFileAddress() - base_addr;
            auto it = saved_unwind_states.upper_bound(current_offset);
            assert(it != saved_unwind_states.begin() &&
                   "Unwind row for the function entry missing");
            --it; // Move it to the row corresponding to the current offset

            // If the offset of m_curr_row don't match with the offset we see in
            // saved_unwind_states
            // then we have to update m_curr_row and m_register_values based on
            // the saved values. It
            // is happenning after we processed an epilogue and a return to
            // caller instruction.
            if (it->second.first->GetOffset() != m_curr_row->GetOffset()) {
              UnwindPlan::Row *newrow = new UnwindPlan::Row;
              *newrow = *it->second.first;
              m_curr_row.reset(newrow);
              m_register_values = it->second.second;
            }

            m_inst_emulator_ap->SetInstruction(inst->GetOpcode(),
                                               inst->GetAddress(), nullptr);

            if (last_condition !=
                m_inst_emulator_ap->GetInstructionCondition()) {
              if (m_inst_emulator_ap->GetInstructionCondition() !=
                      EmulateInstruction::UnconditionalCondition &&
                  saved_unwind_states.count(current_offset) == 0) {
                // If we don't have a saved row for the current offset then save
                // our
                // current state because we will have to restore it after the
                // conditional block.
                auto new_row =
                    std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
                saved_unwind_states.insert(
                    {current_offset, {new_row, m_register_values}});
              }

              // If the last instruction was conditional with a different
              // condition
              // then the then current condition then restore the condition.
              if (last_condition !=
                  EmulateInstruction::UnconditionalCondition) {
                const auto &saved_state =
                    saved_unwind_states.at(condition_block_start_offset);
                m_curr_row =
                    std::make_shared<UnwindPlan::Row>(*saved_state.first);
                m_curr_row->SetOffset(current_offset);
                m_register_values = saved_state.second;
                bool replace_existing =
                    true; // The last instruction might already
                          // created a row for this offset and
                          // we want to overwrite it.
                unwind_plan.InsertRow(
                    std::make_shared<UnwindPlan::Row>(*m_curr_row),
                    replace_existing);
              }

              // We are starting a new conditional block at the catual offset
              condition_block_start_offset = current_offset;
            }

            if (log && log->GetVerbose()) {
              StreamString strm;
              lldb_private::FormatEntity::Entry format;
              FormatEntity::Parse("${frame.pc}: ", format);
              inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address,
                         show_bytes, NULL, NULL, NULL, &format, 0);
              log->PutString(strm.GetString());
            }

            last_condition = m_inst_emulator_ap->GetInstructionCondition();

            m_inst_emulator_ap->EvaluateInstruction(
                eEmulateInstructionOptionIgnoreConditions);

            // If the current instruction is a branch forward then save the
            // current CFI information
            // for the offset where we are branching.
            if (m_forward_branch_offset != 0 &&
                range.ContainsFileAddress(inst->GetAddress().GetFileAddress() +
                                          m_forward_branch_offset)) {
              auto newrow =
                  std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
              newrow->SetOffset(current_offset + m_forward_branch_offset);
              saved_unwind_states.insert(
                  {current_offset + m_forward_branch_offset,
                   {newrow, m_register_values}});
              unwind_plan.InsertRow(newrow);
            }

            // Were there any changes to the CFI while evaluating this
            // instruction?
            if (m_curr_row_modified) {
              // Save the modified row if we don't already have a CFI row in the
              // currennt address
              if (saved_unwind_states.count(
                      current_offset + inst->GetOpcode().GetByteSize()) == 0) {
                m_curr_row->SetOffset(current_offset +
                                      inst->GetOpcode().GetByteSize());
                unwind_plan.InsertRow(m_curr_row);
                saved_unwind_states.insert(
                    {current_offset + inst->GetOpcode().GetByteSize(),
                     {m_curr_row, m_register_values}});

                // Allocate a new Row for m_curr_row, copy the current state
                // into it
                UnwindPlan::Row *newrow = new UnwindPlan::Row;
                *newrow = *m_curr_row.get();
                m_curr_row.reset(newrow);
              }
            }
          }
        }
      }
    }

    if (log && log->GetVerbose()) {
      StreamString strm;
      lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress();
      strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",
                  base_addr, base_addr + range.GetByteSize());
      unwind_plan.Dump(strm, nullptr, base_addr);
      log->PutString(strm.GetString());
    }
    return unwind_plan.GetRowCount() > 0;
  }
  return false;
}
Пример #12
0
bool
Disassembler::Disassemble
(
    Debugger &debugger,
    const ArchSpec &arch,
    const ExecutionContext &exe_ctx,
    const AddressRange &disasm_range,
    uint32_t num_mixed_context_lines,
    bool show_bytes,
    Stream &strm
)
{
    if (disasm_range.GetByteSize())
    {
        Disassembler *disassembler = Disassembler::FindPlugin(arch);

        if (disassembler)
        {
            AddressRange range(disasm_range);
            
            Process *process = exe_ctx.process;

            // If we weren't passed in a section offset address range,
            // try and resolve it to something
            if (range.GetBaseAddress().IsSectionOffset() == false)
            {
                if (process && process->IsAlive())
                {
                    process->ResolveLoadAddress (range.GetBaseAddress().GetOffset(), range.GetBaseAddress());
                }
                else if (exe_ctx.target)
                {
                    exe_ctx.target->GetImages().ResolveFileAddress (range.GetBaseAddress().GetOffset(), range.GetBaseAddress());
                }
            }


            DataExtractor data;
            size_t bytes_disassembled = disassembler->ParseInstructions (&exe_ctx, range, data);
            if (bytes_disassembled == 0)
            {
                return false;
            }
            else
            {
                // We got some things disassembled...
                size_t num_instructions = disassembler->GetInstructionList().GetSize();
                uint32_t offset = 0;
                SymbolContext sc;
                SymbolContext prev_sc;
                AddressRange sc_range;
                if (num_mixed_context_lines)
                    strm.IndentMore ();


                Address addr(range.GetBaseAddress());
    
                // We extract the section to make sure we don't transition out
                // of the current section when disassembling
                const Section *addr_section = addr.GetSection();
                Module *range_module = range.GetBaseAddress().GetModule();

                for (size_t i=0; i<num_instructions; ++i)
                {
                    Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i);
                    if (inst)
                    {
                        addr_t file_addr = addr.GetFileAddress();
                        if (addr_section == NULL || addr_section->ContainsFileAddress (file_addr) == false)
                        {
                            if (range_module)
                                range_module->ResolveFileAddress (file_addr, addr);
                            else if (exe_ctx.target)
                                exe_ctx.target->GetImages().ResolveFileAddress (file_addr, addr);
                                
                            addr_section = addr.GetSection();
                        }

                        prev_sc = sc;

                        if (addr_section)
                        {
                            Module *module = addr_section->GetModule();
                            uint32_t resolved_mask = module->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
                            if (resolved_mask)
                            {
                                if (prev_sc.function != sc.function || prev_sc.symbol != sc.symbol)
                                {
                                    if (prev_sc.function || prev_sc.symbol)
                                        strm.EOL();

                                    strm << sc.module_sp->GetFileSpec().GetFilename();
                                    
                                    if (sc.function)
                                        strm << '`' << sc.function->GetMangled().GetName();
                                    else if (sc.symbol)
                                        strm << '`' << sc.symbol->GetMangled().GetName();
                                    strm << ":\n";
                                }

                                if (num_mixed_context_lines && !sc_range.ContainsFileAddress (addr))
                                {
                                    sc.GetAddressRange (eSymbolContextEverything, sc_range);
                                        
                                    if (sc != prev_sc)
                                    {
                                        if (offset != 0)
                                            strm.EOL();

                                        sc.DumpStopContext(&strm, process, addr);

                                        if (sc.comp_unit && sc.line_entry.IsValid())
                                        {
                                            debugger.GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.line_entry.file,
                                                                                                           sc.line_entry.line,
                                                                                                           num_mixed_context_lines,
                                                                                                           num_mixed_context_lines,
                                                                                                           num_mixed_context_lines ? "->" : "",
                                                                                                           &strm);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                sc.Clear();
                            }
                        }
                        if (num_mixed_context_lines)
                            strm.IndentMore ();
                        strm.Indent();
                        size_t inst_byte_size = inst->GetByteSize();
                        inst->Dump(&strm, &addr, show_bytes ? &data : NULL, offset, exe_ctx, show_bytes);
                        strm.EOL();
                        offset += inst_byte_size;
                        
                        addr.SetOffset (addr.GetOffset() + inst_byte_size);

                        if (num_mixed_context_lines)
                            strm.IndentLess ();
                    }
                    else
                    {
                        break;
                    }
                }
                if (num_mixed_context_lines)
                    strm.IndentLess ();

            }
        }
        return true;
    }
    return false;
}
Пример #13
0
bool
UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& range, 
                                                                   Thread& thread, 
                                                                   UnwindPlan& unwind_plan)
{
    if (range.GetByteSize() > 0 && 
        range.GetBaseAddress().IsValid() &&
        m_inst_emulator_ap.get())
    {
     
        // The the instruction emulation subclass setup the unwind plan for the
        // first instruction.
        m_inst_emulator_ap->CreateFunctionEntryUnwind (unwind_plan);

        // CreateFunctionEntryUnwind should have created the first row. If it
        // doesn't, then we are done.
        if (unwind_plan.GetRowCount() == 0)
            return false;
        
        ExecutionContext exe_ctx;
        thread.CalculateExecutionContext(exe_ctx);
        DisassemblerSP disasm_sp (Disassembler::DisassembleRange (m_arch,
                                                                  NULL,
                                                                  exe_ctx,
                                                                  range));
        
        LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));

        if (disasm_sp)
        {
            
            m_range_ptr = &range;
            m_thread_ptr = &thread;
            m_unwind_plan_ptr = &unwind_plan;

            const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
            const bool show_address = true;
            const bool show_bytes = true;
            const bool raw = false;
            // Initialize the CFA with a known value. In the 32 bit case
            // it will be 0x80000000, and in the 64 bit case 0x8000000000000000.
            // We use the address byte size to be safe for any future addresss sizes
            m_inst_emulator_ap->GetRegisterInfo (unwind_plan.GetRegisterKind(), 
                                                 unwind_plan.GetInitialCFARegister(), 
                                                 m_cfa_reg_info);
            
            m_fp_is_cfa = false;
            m_register_values.clear();
            m_pushed_regs.clear();

            m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
            RegisterValue cfa_reg_value;
            cfa_reg_value.SetUInt (m_initial_sp, m_cfa_reg_info.byte_size);
            SetRegisterValue (m_cfa_reg_info, cfa_reg_value);
                
            const InstructionList &inst_list = disasm_sp->GetInstructionList ();
            const size_t num_instructions = inst_list.GetSize();
            if (num_instructions > 0)
            {
                Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
                const addr_t base_addr = inst->GetAddress().GetFileAddress();
                // Initialize the current row with the one row that was created
                // from the CreateFunctionEntryUnwind call above...
                m_curr_row = unwind_plan.GetLastRow();

                for (size_t idx=0; idx<num_instructions; ++idx)
                {
                    inst = inst_list.GetInstructionAtIndex (idx).get();
                    if (inst)
                    {

                        if (log && log->GetVerbose ())
                        {
                            StreamString strm;
                            inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, &exe_ctx, raw);
                            log->PutCString (strm.GetData());
                        }

                        m_inst_emulator_ap->SetInstruction (inst->GetOpcode(), 
                                                            inst->GetAddress(), 
                                                            exe_ctx.GetTargetPtr());

                        m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);
                        
                        if (unwind_plan.GetLastRow() != m_curr_row)
                        {
                            // Be sure to not edit the offset unless our row has changed
                            // so that the "!=" call above doesn't trigger every time
                            m_curr_row.SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
                            // Append the new row
                            unwind_plan.AppendRow (m_curr_row);
                        }
                    }
                }
            }
        }
        
        if (log && log->GetVerbose ())
        {
            StreamString strm;
            lldb::addr_t base_addr = range.GetBaseAddress().GetLoadAddress(&thread.GetProcess().GetTarget());
            strm.Printf ("Resulting unwind rows for [0x%llx - 0x%llx):", base_addr, base_addr + range.GetByteSize());
            unwind_plan.Dump(strm, &thread, base_addr);
            log->PutCString (strm.GetData());
        }
        return unwind_plan.GetRowCount() > 0;
    }
    return false;
}
bool
UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& range, 
                                                                   Thread& thread, 
                                                                   UnwindPlan& unwind_plan)
{
    if (range.GetByteSize() > 0 && 
        range.GetBaseAddress().IsValid() &&
        m_inst_emulator_ap.get())
    {
     
        // The instruction emulation subclass setup the unwind plan for the
        // first instruction.
        m_inst_emulator_ap->CreateFunctionEntryUnwind (unwind_plan);

        // CreateFunctionEntryUnwind should have created the first row. If it
        // doesn't, then we are done.
        if (unwind_plan.GetRowCount() == 0)
            return false;
        
        ExecutionContext exe_ctx;
        thread.CalculateExecutionContext(exe_ctx);
        const bool prefer_file_cache = true;
        DisassemblerSP disasm_sp (Disassembler::DisassembleRange (m_arch,
                                                                  NULL,
                                                                  NULL,
                                                                  exe_ctx,
                                                                  range,
                                                                  prefer_file_cache));
        
        Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));

        if (disasm_sp)
        {
            
            m_range_ptr = &range;
            m_thread_ptr = &thread;
            m_unwind_plan_ptr = &unwind_plan;

            const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
            const bool show_address = true;
            const bool show_bytes = true;
            m_inst_emulator_ap->GetRegisterInfo (unwind_plan.GetRegisterKind(), 
                                                 unwind_plan.GetInitialCFARegister(), 
                                                 m_cfa_reg_info);
            
            m_fp_is_cfa = false;
            m_register_values.clear();
            m_pushed_regs.clear();

            // Initialize the CFA with a known value. In the 32 bit case
            // it will be 0x80000000, and in the 64 bit case 0x8000000000000000.
            // We use the address byte size to be safe for any future address sizes
            m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
            RegisterValue cfa_reg_value;
            cfa_reg_value.SetUInt (m_initial_sp, m_cfa_reg_info.byte_size);
            SetRegisterValue (m_cfa_reg_info, cfa_reg_value);

            const InstructionList &inst_list = disasm_sp->GetInstructionList ();
            const size_t num_instructions = inst_list.GetSize();

            if (num_instructions > 0)
            {
                Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
                const addr_t base_addr = inst->GetAddress().GetFileAddress();

                // Make a copy of the current instruction Row and save it in m_curr_row
                // so we can add updates as we process the instructions.  
                UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();
                UnwindPlan::Row *newrow = new UnwindPlan::Row;
                if (last_row.get())
                    *newrow = *last_row.get();
                m_curr_row.reset(newrow);

                // Once we've seen the initial prologue instructions complete, save a
                // copy of the CFI at that point into prologue_completed_row for possible
                // use later.
                int instructions_since_last_prologue_insn = 0;     // # of insns since last CFI was update

                bool reinstate_prologue_next_instruction = false;  // Next iteration, re-install the prologue row of CFI

                bool last_instruction_restored_return_addr_reg = false;  // re-install the prologue row of CFI if the next instruction is a branch immediate

                bool return_address_register_has_been_saved = false; // if we've seen the ra register get saved yet

                UnwindPlan::RowSP prologue_completed_row;          // copy of prologue row of CFI

                // cache the pc register number (in whatever register numbering this UnwindPlan uses) for
                // quick reference during instruction parsing.
                uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
                RegisterInfo pc_reg_info;
                if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
                    pc_reg_num = pc_reg_info.kinds[unwind_plan.GetRegisterKind()];
                else
                    pc_reg_num = LLDB_INVALID_REGNUM;

                // cache the return address register number (in whatever register numbering this UnwindPlan uses) for
                // quick reference during instruction parsing.
                uint32_t ra_reg_num = LLDB_INVALID_REGNUM;
                RegisterInfo ra_reg_info;
                if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info))
                    ra_reg_num = ra_reg_info.kinds[unwind_plan.GetRegisterKind()];
                else
                    ra_reg_num = LLDB_INVALID_REGNUM;

                for (size_t idx=0; idx<num_instructions; ++idx)
                {
                    m_curr_row_modified = false;
                    m_curr_insn_restored_a_register = false;
                    inst = inst_list.GetInstructionAtIndex (idx).get();
                    if (inst)
                    {
                        if (log && log->GetVerbose ())
                        {
                            StreamString strm;
                            inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL);
                            log->PutCString (strm.GetData());
                        }

                        m_inst_emulator_ap->SetInstruction (inst->GetOpcode(), 
                                                            inst->GetAddress(), 
                                                            exe_ctx.GetTargetPtr());

                        m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);

                        // Were there any changes to the CFI while evaluating this instruction?
                        if (m_curr_row_modified)
                        {
                            reinstate_prologue_next_instruction = false;
                            m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
                            // Append the new row
                            unwind_plan.AppendRow (m_curr_row);

                            // Allocate a new Row for m_curr_row, copy the current state into it
                            UnwindPlan::Row *newrow = new UnwindPlan::Row;
                            *newrow = *m_curr_row.get();
                            m_curr_row.reset(newrow);

                            // If m_curr_insn_restored_a_register == true, we're looking at an epilogue instruction.
                            // Set instructions_since_last_prologue_insn to a very high number so we don't append 
                            // any of these epilogue instructions to our prologue_complete row.
                            if (m_curr_insn_restored_a_register == false && instructions_since_last_prologue_insn < 8)
                              instructions_since_last_prologue_insn = 0;
                            else
                              instructions_since_last_prologue_insn = 99;

                            UnwindPlan::Row::RegisterLocation pc_regloc;
                            UnwindPlan::Row::RegisterLocation ra_regloc;

                            // While parsing the instructions of this function, if we've ever
                            // seen the return address register (aka lr on arm) in a non-IsSame() state,
                            // it has been saved on the stack.  If it's ever back to IsSame(), we've
                            // executed an epilogue.
                            if (ra_reg_num != LLDB_INVALID_REGNUM
                                && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
                                && !ra_regloc.IsSame())
                            {
                                return_address_register_has_been_saved = true;
                            }

                            // If the caller's pc is "same", we've just executed an epilogue and we return to the caller
                            // after this instruction completes executing.
                            // If there are any instructions past this, there must have been flow control over this
                            // epilogue so we'll reinstate the original prologue setup instructions.
                            if (prologue_completed_row.get()
                                && pc_reg_num != LLDB_INVALID_REGNUM 
                                && m_curr_row->GetRegisterInfo (pc_reg_num, pc_regloc)
                                && pc_regloc.IsSame())
                            {
                                if (log && log->GetVerbose())
                                    log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- pc is <same>, restore prologue instructions.");
                                reinstate_prologue_next_instruction = true;
                            }
                            else if (prologue_completed_row.get()
                                     && return_address_register_has_been_saved
                                     && ra_reg_num != LLDB_INVALID_REGNUM
                                     && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
                                     && ra_regloc.IsSame())
                            {
                                if (log && log->GetVerbose())
                                    log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- lr is <same>, restore prologue instruction if the next instruction is a branch immediate.");
                                last_instruction_restored_return_addr_reg = true;
                            }
                        }
                        else
                        {
                            // If the previous instruction was a return-to-caller (epilogue), and we're still executing
                            // instructions in this function, there must be a code path that jumps over that epilogue.
                            // Also detect the case where we epilogue & branch imm to another function (tail-call opt)
                            // instead of a normal pop lr-into-pc exit.
                            // Reinstate the frame setup from the prologue.
                            if (reinstate_prologue_next_instruction
                                || (m_curr_insn_is_branch_immediate && last_instruction_restored_return_addr_reg))
                            {
                                if (log && log->GetVerbose())
                                    log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- Reinstating prologue instruction set");
                                UnwindPlan::Row *newrow = new UnwindPlan::Row;
                                *newrow = *prologue_completed_row.get();
                                m_curr_row.reset(newrow);
                                m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
                                unwind_plan.AppendRow(m_curr_row);

                                newrow = new UnwindPlan::Row;
                                *newrow = *m_curr_row.get();
                                m_curr_row.reset(newrow);

                                reinstate_prologue_next_instruction = false;
                                last_instruction_restored_return_addr_reg = false; 
                                m_curr_insn_is_branch_immediate = false;
                            }

                            // clear both of these if either one wasn't set
                            if (last_instruction_restored_return_addr_reg)
                            {
                                last_instruction_restored_return_addr_reg = false;
                            }
                            if (m_curr_insn_is_branch_immediate)
                            {
                                m_curr_insn_is_branch_immediate = false;
                            }
 
                            // Stop updating the prologue instructions if we've seen 8 non-prologue instructions
                            // in a row.
                            if (instructions_since_last_prologue_insn++ < 8)
                            {
                                UnwindPlan::Row *newrow = new UnwindPlan::Row;
                                *newrow = *m_curr_row.get();
                                prologue_completed_row.reset(newrow);
                                if (log && log->GetVerbose())
                                    log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- saving a copy of the current row as the prologue row.");
                            }
                        }
                    }
                }
            }
            // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
            // I'll fix that but for now, just clear the list and it will go away nicely.
            disasm_sp->GetInstructionList().Clear();
        }
        
        if (log && log->GetVerbose ())
        {
            StreamString strm;
            lldb::addr_t base_addr = range.GetBaseAddress().GetLoadAddress(thread.CalculateTarget().get());
            strm.Printf ("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):", base_addr, base_addr + range.GetByteSize());
            unwind_plan.Dump(strm, &thread, base_addr);
            log->PutCString (strm.GetData());
        }
        return unwind_plan.GetRowCount() > 0;
    }
    return false;
}