Пример #1
0
bool
Disassembler::Disassemble
(
    Debugger &debugger,
    const ArchSpec &arch,
    const ExecutionContext &exe_ctx,
    uint32_t num_mixed_context_lines,
    bool show_bytes,
    Stream &strm
)
{
    AddressRange range;
    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();
        }

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

    return Disassemble(debugger, arch, exe_ctx, range, num_mixed_context_lines, show_bytes, strm);
}
Пример #2
0
bool
Block::GetRangeContainingAddress (const Address& addr, AddressRange &range)
{
    Function *function = CalculateSymbolContextFunction();
    if (function)
    {
        const AddressRange &func_range = function->GetAddressRange();
        if (addr.GetSection() == func_range.GetBaseAddress().GetSection())
        {
            const addr_t addr_offset = addr.GetOffset();
            const addr_t func_offset = func_range.GetBaseAddress().GetOffset();
            if (addr_offset >= func_offset && addr_offset < func_offset + func_range.GetByteSize())
            {
                addr_t offset = addr_offset - func_offset;
                
                const Range *range_ptr = m_ranges.FindEntryThatContains (offset);

                if (range_ptr)
                {
                    range.GetBaseAddress() = func_range.GetBaseAddress();
                    range.GetBaseAddress().SetOffset(func_offset + range_ptr->GetRangeBase());
                    range.SetByteSize(range_ptr->GetByteSize());
                    return true;
                }
            }
        }
    }
    range.Clear();
    return false;
}
bool UnwindAssembly_x86::FirstNonPrologueInsn(
    AddressRange &func, const ExecutionContext &exe_ctx,
    Address &first_non_prologue_insn) {

  if (!func.GetBaseAddress().IsValid())
    return false;

  Target *target = exe_ctx.GetTargetPtr();
  if (target == nullptr)
    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 (target->ReadMemory(func.GetBaseAddress(), prefer_file_cache,
                         function_text.data(), func.GetByteSize(),
                         error) == func.GetByteSize()) {
    size_t offset;
    if (m_assembly_inspection_engine->FindFirstNonPrologueInstruction(
            function_text.data(), func.GetByteSize(), offset)) {
      first_non_prologue_insn = func.GetBaseAddress();
      first_non_prologue_insn.Slide(offset);
    }
    return true;
  }
  return false;
}
Пример #4
0
size_t
Disassembler::ParseInstructions (const ExecutionContext *exe_ctx,
                                 const AddressRange &range,
                                 Stream *error_strm_ptr,
                                 bool prefer_file_cache)
{
    if (exe_ctx)
    {
        Target *target = exe_ctx->GetTargetPtr();
        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;
        lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
        const size_t bytes_read = target->ReadMemory (range.GetBaseAddress(),
                                                      prefer_file_cache, 
                                                      heap_buffer->GetBytes(), 
                                                      heap_buffer->GetByteSize(), 
                                                      error,
                                                      &load_addr);
        
        if (bytes_read > 0)
        {
            if (bytes_read != heap_buffer->GetByteSize())
                heap_buffer->SetByteSize (bytes_read);
            DataExtractor data (data_sp, 
                                m_arch.GetByteOrder(),
                                m_arch.GetAddressByteSize());
            const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
            return DecodeInstructions (range.GetBaseAddress(), data, 0, UINT32_MAX, false, data_from_file);
        }
        else if (error_strm_ptr)
        {
            const char *error_cstr = error.AsCString();
            if (error_cstr)
            {
                error_strm_ptr->Printf("error: %s\n", error_cstr);
            }
        }
    }
    else if (error_strm_ptr)
    {
        error_strm_ptr->PutCString("error: invalid execution context\n");
    }
    return 0;
}
Пример #5
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);
}
Пример #6
0
lldb::DisassemblerSP
Disassembler::DisassembleRange
(
    const ArchSpec &arch,
    const char *plugin_name,
    const char *flavor,
    const ExecutionContext &exe_ctx,
    const AddressRange &range,
    bool prefer_file_cache
)
{
    lldb::DisassemblerSP disasm_sp;
    if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid())
    {
        disasm_sp = Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(), arch, flavor, plugin_name);

        if (disasm_sp)
        {
            size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, NULL, prefer_file_cache);
            if (bytes_disassembled == 0)
                disasm_sp.reset();
        }
    }
    return disasm_sp;
}
Пример #7
0
bool
Disassembler::Disassemble
(
    Debugger &debugger,
    const ArchSpec &arch,
    const char *plugin_name,
    const char *flavor,
    const ExecutionContext &exe_ctx,
    const AddressRange &disasm_range,
    uint32_t num_instructions,
    uint32_t num_mixed_context_lines,
    uint32_t options,
    Stream &strm
)
{
    if (disasm_range.GetByteSize())
    {
        lldb::DisassemblerSP disasm_sp (Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(), arch, flavor, plugin_name));

        if (disasm_sp.get())
        {
            AddressRange range;
            ResolveAddress (exe_ctx, disasm_range.GetBaseAddress(), range.GetBaseAddress());
            range.SetByteSize (disasm_range.GetByteSize());
            const bool prefer_file_cache = false;
            size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, &strm, prefer_file_cache);
            if (bytes_disassembled == 0)
                return false;

            bool result = PrintInstructions (disasm_sp.get(),
                                             debugger,
                                             arch,
                                             exe_ctx,
                                             num_instructions,
                                             num_mixed_context_lines,
                                             options,
                                             strm);
            
            // 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();
            return result;
        }
    }
    return false;
}
Пример #8
0
bool
Block::GetRangeAtIndex (uint32_t range_idx, AddressRange &range)
{
    if (range_idx < m_ranges.GetSize())
    {
        Function *function = CalculateSymbolContextFunction();
        if (function)
        {
            const Range &vm_range = m_ranges.GetEntryRef(range_idx);
            range.GetBaseAddress() = function->GetAddressRange().GetBaseAddress();
            range.GetBaseAddress().Slide(vm_range.GetRangeBase ());
            range.SetByteSize (vm_range.GetByteSize());
            return true;
        }
    }
    return false;
}
Пример #9
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;
}
Пример #10
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;
}
Пример #11
0
ThreadPlanSP
DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop)
{
    LogSP log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
    ThreadPlanSP thread_plan_sp;

    StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
    const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol);
    Symbol *sym = context.symbol;

    if (sym == NULL || !sym->IsTrampoline())
        return thread_plan_sp;

    const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled);
    if (!sym_name)
        return thread_plan_sp;

    SymbolContextList target_symbols;
    Target &target = thread.GetProcess().GetTarget();
    ModuleList &images = target.GetImages();

    images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols);
    size_t num_targets = target_symbols.GetSize();
    if (!num_targets)
        return thread_plan_sp;

    typedef std::vector<lldb::addr_t> AddressVector;
    AddressVector addrs;
    for (size_t i = 0; i < num_targets; ++i)
    {
        SymbolContext context;
        AddressRange range;
        if (target_symbols.GetContextAtIndex(i, context))
        {
            context.GetAddressRange(eSymbolContextEverything, 0, false, range);
            lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target);
            if (addr != LLDB_INVALID_ADDRESS)
                addrs.push_back(addr);
        }
    }

    if (addrs.size() > 0) 
    {
        AddressVector::iterator start = addrs.begin();
        AddressVector::iterator end = addrs.end();

        std::sort(start, end);
        addrs.erase(std::unique(start, end), end);
        thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop));
    }

    return thread_plan_sp;
}
Пример #12
0
bool
Disassembler::Disassemble
(
    Debugger &debugger,
    const ArchSpec &arch,
    const char *plugin_name,
    const ExecutionContext &exe_ctx,
    const AddressRange &disasm_range,
    uint32_t num_instructions,
    uint32_t num_mixed_context_lines,
    uint32_t options,
    Stream &strm
)
{
    if (disasm_range.GetByteSize())
    {
        std::auto_ptr<Disassembler> disasm_ap (Disassembler::FindPlugin(arch, plugin_name));

        if (disasm_ap.get())
        {
            AddressRange range;
            ResolveAddress (exe_ctx, disasm_range.GetBaseAddress(), range.GetBaseAddress());
            range.SetByteSize (disasm_range.GetByteSize());
            
            size_t bytes_disassembled = disasm_ap->ParseInstructions (&exe_ctx, range, &strm);
            if (bytes_disassembled == 0)
                return false;

            return PrintInstructions (disasm_ap.get(),
                                      debugger,
                                      arch,
                                      exe_ctx,
                                      num_instructions,
                                      num_mixed_context_lines,
                                      options,
                                      strm);
        }
    }
    return false;
}
bool UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly(
    AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {
  if (!func.GetBaseAddress().IsValid() || func.GetByteSize() == 0)
    return false;
  if (m_assembly_inspection_engine == nullptr)
    return false;
  ProcessSP process_sp(thread.GetProcess());
  if (process_sp.get() == 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->GetNonCallSiteUnwindPlanFromAssembly(
        function_text.data(), func.GetByteSize(), func, unwind_plan);
  }
  return false;
}
Пример #14
0
bool
SymbolContext::GetAddressRange (uint32_t scope, 
                                uint32_t range_idx, 
                                bool use_inline_block_range,
                                AddressRange &range) const
{
    if ((scope & eSymbolContextLineEntry) && line_entry.IsValid())
    {
        range = line_entry.range;
        return true;
    }
    
    if ((scope & eSymbolContextBlock) && (block != NULL))
    {
        if (use_inline_block_range)
        {
            Block *inline_block = block->GetContainingInlinedBlock();
            if (inline_block)
                return inline_block->GetRangeAtIndex (range_idx, range);
        }
        else
        {
            return block->GetRangeAtIndex (range_idx, range);
        }
    }

    if ((scope & eSymbolContextFunction) && (function != NULL))
    {
        if (range_idx == 0)
        {
            range = function->GetAddressRange();
            return true;
        }            
    } 
    
    if ((scope & eSymbolContextSymbol) && (symbol != NULL))
    {
        if (range_idx == 0)
        {
            if (symbol->ValueIsAddress())
            {
                range.GetBaseAddress() = symbol->GetAddress();
                range.SetByteSize (symbol->GetByteSize());
                return true;
            }
        }
    }
    range.Clear();
    return false;
}
Пример #15
0
lldb::SBAddress
SBBlock::GetRangeStartAddress (uint32_t idx)
{
    lldb::SBAddress sb_addr;
    if (m_opaque_ptr)
    {
        AddressRange range;
        if (m_opaque_ptr->GetRangeAtIndex(idx, range))
        {
            sb_addr.ref() = range.GetBaseAddress();
        }
    }
    return sb_addr;
}
Пример #16
0
lldb::SBAddress
SBBlock::GetRangeEndAddress (uint32_t idx)
{
    lldb::SBAddress sb_addr;
    if (m_opaque_ptr)
    {
        AddressRange range;
        if (m_opaque_ptr->GetRangeAtIndex(idx, range))
        {
            sb_addr.ref() = range.GetBaseAddress();
            sb_addr.ref().Slide(range.GetByteSize());
        }
    }
    return sb_addr;
}
Пример #17
0
bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
    AddressRange &range, Thread &thread, UnwindPlan &unwind_plan) {
  std::vector<uint8_t> function_text(range.GetByteSize());
  ProcessSP process_sp(thread.GetProcess());
  if (process_sp) {
    Error error;
    const bool prefer_file_cache = true;
    if (process_sp->GetTarget().ReadMemory(
            range.GetBaseAddress(), prefer_file_cache, function_text.data(),
            range.GetByteSize(), error) != range.GetByteSize()) {
      return false;
    }
  }
  return GetNonCallSiteUnwindPlanFromAssembly(
      range, function_text.data(), function_text.size(), unwind_plan);
}
Пример #18
0
llvm::Optional<AddressRange> UnwindTable::GetAddressRange(const Address &addr,
                                                          SymbolContext &sc) {
  AddressRange range;

  // First check the symbol context
  if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
                         false, range) &&
      range.GetBaseAddress().IsValid())
    return range;

  // Does the eh_frame unwind info has a function bounds for this addr?
  if (m_eh_frame_up && m_eh_frame_up->GetAddressRange(addr, range))
    return range;

  // Try debug_frame as well
  if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range))
    return range;

  return llvm::None;
}
Пример #19
0
FuncUnwindersSP
UnwindTable::GetFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc)
{
    FuncUnwindersSP no_unwind_found;

    Initialize();

    // There is an UnwindTable per object file, so we can safely use file handles
    addr_t file_addr = addr.GetFileAddress();
    iterator end = m_unwinds.end ();
    iterator insert_pos = end;
    if (!m_unwinds.empty())
    {
        insert_pos = m_unwinds.lower_bound (file_addr);
        iterator pos = insert_pos;
        if ((pos == m_unwinds.end ()) || (pos != m_unwinds.begin() && pos->second->GetFunctionStartAddress() != addr))
            --pos;

        if (pos->second->ContainsAddress (addr))
            return pos->second;
    }

    AddressRange range;
    if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, false, range) || !range.GetBaseAddress().IsValid())
    {
        // Does the eh_frame unwind info has a function bounds for this addr?
        if (m_eh_frame == NULL || !m_eh_frame->GetAddressRange (addr, range))
        {
            return no_unwind_found;
        }
    }

    FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, m_assembly_profiler, range));
    m_unwinds.insert (insert_pos, std::make_pair(range.GetBaseAddress().GetFileAddress(), func_unwinder_sp));
//    StreamFile s(stdout);
//    Dump (s);
    return func_unwinder_sp;
}
Пример #20
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;
}
bool UnwindAssembly_x86::GetFastUnwindPlan(AddressRange &func, Thread &thread,
                                           UnwindPlan &unwind_plan) {
  // if prologue is
  //   55     pushl %ebp
  //   89 e5  movl %esp, %ebp
  //  or
  //   55        pushq %rbp
  //   48 89 e5  movq %rsp, %rbp

  // We should pull in the ABI architecture default unwind plan and return that

  llvm::SmallVector<uint8_t, 4> opcode_data;

  ProcessSP process_sp = thread.GetProcess();
  if (process_sp) {
    Target &target(process_sp->GetTarget());
    const bool prefer_file_cache = true;
    Status error;
    if (target.ReadMemory(func.GetBaseAddress(), prefer_file_cache,
                          opcode_data.data(), 4, error) == 4) {
      uint8_t i386_push_mov[] = {0x55, 0x89, 0xe5};
      uint8_t x86_64_push_mov[] = {0x55, 0x48, 0x89, 0xe5};

      if (memcmp(opcode_data.data(), i386_push_mov, sizeof(i386_push_mov)) ==
              0 ||
          memcmp(opcode_data.data(), x86_64_push_mov,
                 sizeof(x86_64_push_mov)) == 0) {
        ABISP abi_sp = process_sp->GetABI();
        if (abi_sp) {
          return abi_sp->CreateDefaultUnwindPlan(unwind_plan);
        }
      }
    }
  }
  return false;
}
Пример #22
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();
}
Пример #24
0
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;
}
Пример #25
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;
}
size_t
UnwindMacOSXFrameBackchain::GetStackFrameData_i386 (const ExecutionContext &exe_ctx)
{
    m_cursors.clear();
    
    Frame *first_frame = exe_ctx.GetFramePtr();

    Process *process = exe_ctx.GetProcessPtr();
    if (process == NULL)
        return 0;
    
    std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;

    struct Frame_i386
    {
        uint32_t fp;
        uint32_t pc;
    };

    RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
    assert (reg_ctx);

    Cursor cursor;
    cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
    cursor.fp = reg_ctx->GetFP (0);
    
    Frame_i386 frame = { static_cast<uint32_t>(cursor.fp), static_cast<uint32_t>(cursor.pc) };

    m_cursors.push_back(cursor);

    const size_t k_frame_size = sizeof(frame);
    Error error;
    while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
    {
        // Read both the FP and PC (8 bytes)
        if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
            break;
        if (frame.pc >= 0x1000)
        {
            cursor.pc = frame.pc;
            cursor.fp = frame.fp;
            m_cursors.push_back (cursor);
        }
    }
    if (!m_cursors.empty())
    {
        lldb::addr_t first_frame_pc = m_cursors.front().pc;
        if (first_frame_pc != LLDB_INVALID_ADDRESS)
        {
            const uint32_t resolve_scope = eSymbolContextModule |
                                           eSymbolContextCompUnit |
                                           eSymbolContextFunction |
                                           eSymbolContextSymbol;

            SymbolContext first_frame_sc (first_frame->GetSymbolContext(resolve_scope));
            const AddressRange *addr_range_ptr = NULL;
            AddressRange range;
            if (first_frame_sc.function)
                addr_range_ptr = &first_frame_sc.function->GetAddressRange();
            else if (first_frame_sc.symbol)
            {
                range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
                range.SetByteSize (first_frame_sc.symbol->GetByteSize());
                addr_range_ptr = &range;
            }

            if (addr_range_ptr)
            {
                if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
                {
                    // We are at the first instruction, so we can recover the
                    // previous PC by dereferencing the SP
                    lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
                    // Read the real second frame return address into frame.pc
                    if (first_frame_sp && process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
                    {
                        cursor.fp = m_cursors.front().fp;
                        cursor.pc = frame.pc;           // Set the new second frame PC

                        // Insert the second frame
                        m_cursors.insert(m_cursors.begin()+1, cursor);
                        
                        m_cursors.front().fp = first_frame_sp;
                    }
                }
            }
        }
    }
//    uint32_t i=0;
//    printf("      PC                 FP\n");
//    printf("      ------------------ ------------------ \n");
//    for (i=0; i<m_cursors.size(); ++i)
//    {
//        printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i, m_cursors[i].pc, m_cursors[i].fp);
//    }
    return m_cursors.size();
}
Пример #27
0
void
UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
{
   if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
       m_plan_valid_address_range = range;
}
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;
}
Пример #29
0
bool
SymbolContext::GetParentOfInlinedScope (const Address &curr_frame_pc, 
                                        SymbolContext &next_frame_sc, 
                                        Address &next_frame_pc) const
{
    next_frame_sc.Clear(false);
    next_frame_pc.Clear();

    if (block)
    {
        //const addr_t curr_frame_file_addr = curr_frame_pc.GetFileAddress();
        
        // In order to get the parent of an inlined function we first need to
        // see if we are in an inlined block as "this->block" could be an 
        // inlined block, or a parent of "block" could be. So lets check if
        // this block or one of this blocks parents is an inlined function.
        Block *curr_inlined_block = block->GetContainingInlinedBlock();
        if (curr_inlined_block)
        {
            // "this->block" is contained in an inline function block, so to
            // get the scope above the inlined block, we get the parent of the
            // inlined block itself
            Block *next_frame_block = curr_inlined_block->GetParent();
            // Now calculate the symbol context of the containing block
            next_frame_block->CalculateSymbolContext (&next_frame_sc);
            
            // If we get here we weren't able to find the return line entry using the nesting of the blocks and
            // the line table.  So just use the call site info from our inlined block.
            
            AddressRange range;
            if (curr_inlined_block->GetRangeContainingAddress (curr_frame_pc, range))
            {
                // To see there this new frame block it, we need to look at the
                // call site information from 
                const InlineFunctionInfo* curr_inlined_block_inlined_info = curr_inlined_block->GetInlinedFunctionInfo();
                next_frame_pc = range.GetBaseAddress();
                next_frame_sc.line_entry.range.GetBaseAddress() = next_frame_pc;
                next_frame_sc.line_entry.file = curr_inlined_block_inlined_info->GetCallSite().GetFile();
                next_frame_sc.line_entry.line = curr_inlined_block_inlined_info->GetCallSite().GetLine();
                next_frame_sc.line_entry.column = curr_inlined_block_inlined_info->GetCallSite().GetColumn();
                return true;
            }
            else
            {
                Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS));

                if (log)
                {
                    log->Printf ("warning: inlined block 0x%8.8" PRIx64 " doesn't have a range that contains file address 0x%" PRIx64,
                                 curr_inlined_block->GetID(), curr_frame_pc.GetFileAddress());
                }
#ifdef LLDB_CONFIGURATION_DEBUG
                else
                {
                    ObjectFile *objfile = NULL;
                    if (module_sp)
                    {
                        SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor();
                        if (symbol_vendor)
                        {
                            SymbolFile *symbol_file = symbol_vendor->GetSymbolFile();
                            if (symbol_file)
                                objfile = symbol_file->GetObjectFile();
                        }
                    }
                    if (objfile)
                    {
                        Host::SystemLog (Host::eSystemLogWarning, 
                                         "warning: inlined block 0x%8.8" PRIx64 " doesn't have a range that contains file address 0x%" PRIx64 " in %s\n",
                                         curr_inlined_block->GetID(), 
                                         curr_frame_pc.GetFileAddress(),
                                         objfile->GetFileSpec().GetPath().c_str());
                    }
                    else
                    {
                        Host::SystemLog (Host::eSystemLogWarning, 
                                         "warning: inlined block 0x%8.8" PRIx64 " doesn't have a range that contains file address 0x%" PRIx64 "\n",
                                         curr_inlined_block->GetID(), 
                                         curr_frame_pc.GetFileAddress());
                    }
                }
#endif
            }
        }
    }
    
    return false;
}
Пример #30
0
FuncUnwindersSP
UnwindTable::GetUncachedFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc)
{
    FuncUnwindersSP no_unwind_found;
    Initialize();

    AddressRange range;
    if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, false, range) || !range.GetBaseAddress().IsValid())
    {
        // Does the eh_frame unwind info has a function bounds for this addr?
        if (m_eh_frame == NULL || !m_eh_frame->GetAddressRange (addr, range))
        {
            return no_unwind_found;
        }
    }

    FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, m_assembly_profiler, range));
    return func_unwinder_sp;
}