mirror of
https://github.com/intel/llvm.git
synced 2026-01-15 20:54:40 +08:00
by type ID (the most common type of type lookup). Changed the API logging a bit to always show the objects in the OBJECT(POINTER) format so it will be easy to locate all instances of an object or references to it when looking at logs. llvm-svn: 117641
1105 lines
34 KiB
C++
1105 lines
34 KiB
C++
//===-- Target.cpp ----------------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Target/Target.h"
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
// Other libraries and framework includes
|
|
// Project includes
|
|
#include "lldb/Breakpoint/BreakpointResolver.h"
|
|
#include "lldb/Breakpoint/BreakpointResolverAddress.h"
|
|
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
|
|
#include "lldb/Breakpoint/BreakpointResolverName.h"
|
|
#include "lldb/Core/DataBufferMemoryMap.h"
|
|
#include "lldb/Core/Event.h"
|
|
#include "lldb/Core/Log.h"
|
|
#include "lldb/Core/Timer.h"
|
|
#include "lldb/Core/StreamString.h"
|
|
#include "lldb/Host/Host.h"
|
|
#include "lldb/lldb-private-log.h"
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Core/Debugger.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
//----------------------------------------------------------------------
|
|
// Target constructor
|
|
//----------------------------------------------------------------------
|
|
Target::Target(Debugger &debugger) :
|
|
Broadcaster("Target"),
|
|
TargetInstanceSettings (*(Target::GetSettingsController().get())),
|
|
m_debugger (debugger),
|
|
m_images(),
|
|
m_section_load_list (),
|
|
m_breakpoint_list (false),
|
|
m_internal_breakpoint_list (true),
|
|
m_process_sp(),
|
|
m_triple(),
|
|
m_search_filter_sp(),
|
|
m_image_search_paths (ImageSearchPathsChanged, this),
|
|
m_scratch_ast_context_ap(NULL)
|
|
{
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
|
|
if (log)
|
|
log->Printf ("%p Target::Target()", this);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Destructor
|
|
//----------------------------------------------------------------------
|
|
Target::~Target()
|
|
{
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
|
|
if (log)
|
|
log->Printf ("%p Target::~Target()", this);
|
|
DeleteCurrentProcess ();
|
|
}
|
|
|
|
void
|
|
Target::Dump (Stream *s, lldb::DescriptionLevel description_level)
|
|
{
|
|
// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
|
|
if (description_level != lldb::eDescriptionLevelBrief)
|
|
{
|
|
s->Indent();
|
|
s->PutCString("Target\n");
|
|
s->IndentMore();
|
|
m_images.Dump(s);
|
|
m_breakpoint_list.Dump(s);
|
|
m_internal_breakpoint_list.Dump(s);
|
|
s->IndentLess();
|
|
}
|
|
else
|
|
{
|
|
s->Printf ("%s", GetExecutableModule()->GetFileSpec().GetFilename().GetCString());
|
|
}
|
|
}
|
|
|
|
void
|
|
Target::DeleteCurrentProcess ()
|
|
{
|
|
if (m_process_sp.get())
|
|
{
|
|
m_section_load_list.Clear();
|
|
if (m_process_sp->IsAlive())
|
|
m_process_sp->Destroy();
|
|
else
|
|
m_process_sp->Finalize();
|
|
|
|
// Do any cleanup of the target we need to do between process instances.
|
|
// NB It is better to do this before destroying the process in case the
|
|
// clean up needs some help from the process.
|
|
m_breakpoint_list.ClearAllBreakpointSites();
|
|
m_internal_breakpoint_list.ClearAllBreakpointSites();
|
|
m_process_sp.reset();
|
|
}
|
|
}
|
|
|
|
const lldb::ProcessSP &
|
|
Target::CreateProcess (Listener &listener, const char *plugin_name)
|
|
{
|
|
DeleteCurrentProcess ();
|
|
m_process_sp.reset(Process::FindPlugin(*this, plugin_name, listener));
|
|
return m_process_sp;
|
|
}
|
|
|
|
const lldb::ProcessSP &
|
|
Target::GetProcessSP () const
|
|
{
|
|
return m_process_sp;
|
|
}
|
|
|
|
lldb::TargetSP
|
|
Target::GetSP()
|
|
{
|
|
return m_debugger.GetTargetList().GetTargetSP(this);
|
|
}
|
|
|
|
BreakpointList &
|
|
Target::GetBreakpointList(bool internal)
|
|
{
|
|
if (internal)
|
|
return m_internal_breakpoint_list;
|
|
else
|
|
return m_breakpoint_list;
|
|
}
|
|
|
|
const BreakpointList &
|
|
Target::GetBreakpointList(bool internal) const
|
|
{
|
|
if (internal)
|
|
return m_internal_breakpoint_list;
|
|
else
|
|
return m_breakpoint_list;
|
|
}
|
|
|
|
BreakpointSP
|
|
Target::GetBreakpointByID (break_id_t break_id)
|
|
{
|
|
BreakpointSP bp_sp;
|
|
|
|
if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
|
|
bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
|
|
else
|
|
bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
|
|
|
|
return bp_sp;
|
|
}
|
|
|
|
BreakpointSP
|
|
Target::CreateBreakpoint (const FileSpec *containingModule, const FileSpec &file, uint32_t line_no, bool check_inlines, bool internal)
|
|
{
|
|
SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
|
|
BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine (NULL, file, line_no, check_inlines));
|
|
return CreateBreakpoint (filter_sp, resolver_sp, internal);
|
|
}
|
|
|
|
|
|
BreakpointSP
|
|
Target::CreateBreakpoint (lldb::addr_t addr, bool internal)
|
|
{
|
|
Address so_addr;
|
|
// Attempt to resolve our load address if possible, though it is ok if
|
|
// it doesn't resolve to section/offset.
|
|
|
|
// Try and resolve as a load address if possible
|
|
m_section_load_list.ResolveLoadAddress(addr, so_addr);
|
|
if (!so_addr.IsValid())
|
|
{
|
|
// The address didn't resolve, so just set this as an absolute address
|
|
so_addr.SetOffset (addr);
|
|
}
|
|
BreakpointSP bp_sp (CreateBreakpoint(so_addr, internal));
|
|
return bp_sp;
|
|
}
|
|
|
|
BreakpointSP
|
|
Target::CreateBreakpoint (Address &addr, bool internal)
|
|
{
|
|
TargetSP target_sp = this->GetSP();
|
|
SearchFilterSP filter_sp(new SearchFilter (target_sp));
|
|
BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr));
|
|
return CreateBreakpoint (filter_sp, resolver_sp, internal);
|
|
}
|
|
|
|
BreakpointSP
|
|
Target::CreateBreakpoint (FileSpec *containingModule, const char *func_name, uint32_t func_name_type_mask, bool internal)
|
|
{
|
|
BreakpointSP bp_sp;
|
|
if (func_name)
|
|
{
|
|
SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
|
|
BreakpointResolverSP resolver_sp (new BreakpointResolverName (NULL, func_name, func_name_type_mask, Breakpoint::Exact));
|
|
bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal);
|
|
}
|
|
return bp_sp;
|
|
}
|
|
|
|
|
|
SearchFilterSP
|
|
Target::GetSearchFilterForModule (const FileSpec *containingModule)
|
|
{
|
|
SearchFilterSP filter_sp;
|
|
lldb::TargetSP target_sp = this->GetSP();
|
|
if (containingModule != NULL)
|
|
{
|
|
// TODO: We should look into sharing module based search filters
|
|
// across many breakpoints like we do for the simple target based one
|
|
filter_sp.reset (new SearchFilterByModule (target_sp, *containingModule));
|
|
}
|
|
else
|
|
{
|
|
if (m_search_filter_sp.get() == NULL)
|
|
m_search_filter_sp.reset (new SearchFilter (target_sp));
|
|
filter_sp = m_search_filter_sp;
|
|
}
|
|
return filter_sp;
|
|
}
|
|
|
|
BreakpointSP
|
|
Target::CreateBreakpoint (FileSpec *containingModule, RegularExpression &func_regex, bool internal)
|
|
{
|
|
SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
|
|
BreakpointResolverSP resolver_sp(new BreakpointResolverName (NULL, func_regex));
|
|
|
|
return CreateBreakpoint (filter_sp, resolver_sp, internal);
|
|
}
|
|
|
|
BreakpointSP
|
|
Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal)
|
|
{
|
|
BreakpointSP bp_sp;
|
|
if (filter_sp && resolver_sp)
|
|
{
|
|
bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp));
|
|
resolver_sp->SetBreakpoint (bp_sp.get());
|
|
|
|
if (internal)
|
|
m_internal_breakpoint_list.Add (bp_sp, false);
|
|
else
|
|
m_breakpoint_list.Add (bp_sp, true);
|
|
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
|
|
if (log)
|
|
{
|
|
StreamString s;
|
|
bp_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
|
|
log->Printf ("Target::%s (internal = %s) => break_id = %s\n", __FUNCTION__, internal ? "yes" : "no", s.GetData());
|
|
}
|
|
|
|
bp_sp->ResolveBreakpoint();
|
|
}
|
|
|
|
if (!internal && bp_sp)
|
|
{
|
|
m_last_created_breakpoint = bp_sp;
|
|
}
|
|
|
|
return bp_sp;
|
|
}
|
|
|
|
void
|
|
Target::RemoveAllBreakpoints (bool internal_also)
|
|
{
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
|
|
if (log)
|
|
log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
|
|
|
|
m_breakpoint_list.RemoveAll (true);
|
|
if (internal_also)
|
|
m_internal_breakpoint_list.RemoveAll (false);
|
|
|
|
m_last_created_breakpoint.reset();
|
|
}
|
|
|
|
void
|
|
Target::DisableAllBreakpoints (bool internal_also)
|
|
{
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
|
|
if (log)
|
|
log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
|
|
|
|
m_breakpoint_list.SetEnabledAll (false);
|
|
if (internal_also)
|
|
m_internal_breakpoint_list.SetEnabledAll (false);
|
|
}
|
|
|
|
void
|
|
Target::EnableAllBreakpoints (bool internal_also)
|
|
{
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
|
|
if (log)
|
|
log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
|
|
|
|
m_breakpoint_list.SetEnabledAll (true);
|
|
if (internal_also)
|
|
m_internal_breakpoint_list.SetEnabledAll (true);
|
|
}
|
|
|
|
bool
|
|
Target::RemoveBreakpointByID (break_id_t break_id)
|
|
{
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
|
|
if (log)
|
|
log->Printf ("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
|
|
|
|
if (DisableBreakpointByID (break_id))
|
|
{
|
|
if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
|
|
m_internal_breakpoint_list.Remove(break_id, false);
|
|
else
|
|
{
|
|
if (m_last_created_breakpoint->GetID() == break_id)
|
|
m_last_created_breakpoint.reset();
|
|
m_breakpoint_list.Remove(break_id, true);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
Target::DisableBreakpointByID (break_id_t break_id)
|
|
{
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
|
|
if (log)
|
|
log->Printf ("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
|
|
|
|
BreakpointSP bp_sp;
|
|
|
|
if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
|
|
bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
|
|
else
|
|
bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
|
|
if (bp_sp)
|
|
{
|
|
bp_sp->SetEnabled (false);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
Target::EnableBreakpointByID (break_id_t break_id)
|
|
{
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
|
|
if (log)
|
|
log->Printf ("Target::%s (break_id = %i, internal = %s)\n",
|
|
__FUNCTION__,
|
|
break_id,
|
|
LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
|
|
|
|
BreakpointSP bp_sp;
|
|
|
|
if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
|
|
bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
|
|
else
|
|
bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
|
|
|
|
if (bp_sp)
|
|
{
|
|
bp_sp->SetEnabled (true);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ModuleSP
|
|
Target::GetExecutableModule ()
|
|
{
|
|
ModuleSP executable_sp;
|
|
if (m_images.GetSize() > 0)
|
|
executable_sp = m_images.GetModuleAtIndex(0);
|
|
return executable_sp;
|
|
}
|
|
|
|
void
|
|
Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
|
|
{
|
|
m_images.Clear();
|
|
m_scratch_ast_context_ap.reset();
|
|
|
|
if (executable_sp.get())
|
|
{
|
|
Timer scoped_timer (__PRETTY_FUNCTION__,
|
|
"Target::SetExecutableModule (executable = '%s/%s')",
|
|
executable_sp->GetFileSpec().GetDirectory().AsCString(),
|
|
executable_sp->GetFileSpec().GetFilename().AsCString());
|
|
|
|
m_images.Append(executable_sp); // The first image is our exectuable file
|
|
|
|
ArchSpec exe_arch = executable_sp->GetArchitecture();
|
|
// If we haven't set an architecture yet, reset our architecture based on what we found in the executable module.
|
|
if (!m_arch_spec.IsValid())
|
|
m_arch_spec = exe_arch;
|
|
|
|
FileSpecList dependent_files;
|
|
ObjectFile * executable_objfile = executable_sp->GetObjectFile();
|
|
if (executable_objfile == NULL)
|
|
{
|
|
|
|
FileSpec bundle_executable(executable_sp->GetFileSpec());
|
|
if (Host::ResolveExecutableInBundle (bundle_executable))
|
|
{
|
|
ModuleSP bundle_exe_module_sp(GetSharedModule(bundle_executable,
|
|
exe_arch));
|
|
SetExecutableModule (bundle_exe_module_sp, get_dependent_files);
|
|
if (bundle_exe_module_sp->GetObjectFile() != NULL)
|
|
executable_sp = bundle_exe_module_sp;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (executable_objfile)
|
|
{
|
|
executable_objfile->GetDependentModules(dependent_files);
|
|
for (uint32_t i=0; i<dependent_files.GetSize(); i++)
|
|
{
|
|
ModuleSP image_module_sp(GetSharedModule(dependent_files.GetFileSpecPointerAtIndex(i),
|
|
exe_arch));
|
|
if (image_module_sp.get())
|
|
{
|
|
//image_module_sp->Dump(&s);// REMOVE THIS, DEBUG ONLY
|
|
ObjectFile *objfile = image_module_sp->GetObjectFile();
|
|
if (objfile)
|
|
objfile->GetDependentModules(dependent_files);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now see if we know the target triple, and if so, create our scratch AST context:
|
|
ConstString target_triple;
|
|
if (GetTargetTriple(target_triple))
|
|
{
|
|
m_scratch_ast_context_ap.reset (new ClangASTContext(target_triple.GetCString()));
|
|
}
|
|
}
|
|
|
|
UpdateInstanceName();
|
|
}
|
|
|
|
|
|
ModuleList&
|
|
Target::GetImages ()
|
|
{
|
|
return m_images;
|
|
}
|
|
|
|
ArchSpec
|
|
Target::GetArchitecture () const
|
|
{
|
|
return m_arch_spec;
|
|
}
|
|
|
|
bool
|
|
Target::SetArchitecture (const ArchSpec &arch_spec)
|
|
{
|
|
if (m_arch_spec == arch_spec)
|
|
{
|
|
// If we're setting the architecture to our current architecture, we
|
|
// don't need to do anything.
|
|
return true;
|
|
}
|
|
else if (!m_arch_spec.IsValid())
|
|
{
|
|
// If we haven't got a valid arch spec, then we just need to set it.
|
|
m_arch_spec = arch_spec;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// If we have an executable file, try to reset the executable to the desired architecture
|
|
m_arch_spec = arch_spec;
|
|
ModuleSP executable_sp = GetExecutableModule ();
|
|
m_images.Clear();
|
|
m_scratch_ast_context_ap.reset();
|
|
m_triple.Clear();
|
|
// Need to do something about unsetting breakpoints.
|
|
|
|
if (executable_sp)
|
|
{
|
|
FileSpec exec_file_spec = executable_sp->GetFileSpec();
|
|
Error error = ModuleList::GetSharedModule(exec_file_spec,
|
|
arch_spec,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
executable_sp,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (!error.Fail() && executable_sp)
|
|
{
|
|
SetExecutableModule (executable_sp, true);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
Target::GetTargetTriple(ConstString &triple)
|
|
{
|
|
triple.Clear();
|
|
|
|
if (m_triple)
|
|
{
|
|
triple = m_triple;
|
|
}
|
|
else
|
|
{
|
|
Module *exe_module = GetExecutableModule().get();
|
|
if (exe_module)
|
|
{
|
|
ObjectFile *objfile = exe_module->GetObjectFile();
|
|
if (objfile)
|
|
{
|
|
objfile->GetTargetTriple(m_triple);
|
|
triple = m_triple;
|
|
}
|
|
}
|
|
}
|
|
return !triple.IsEmpty();
|
|
}
|
|
|
|
void
|
|
Target::ModuleAdded (ModuleSP &module_sp)
|
|
{
|
|
// A module is being added to this target for the first time
|
|
ModuleList module_list;
|
|
module_list.Append(module_sp);
|
|
ModulesDidLoad (module_list);
|
|
}
|
|
|
|
void
|
|
Target::ModuleUpdated (ModuleSP &old_module_sp, ModuleSP &new_module_sp)
|
|
{
|
|
// A module is being added to this target for the first time
|
|
ModuleList module_list;
|
|
module_list.Append (old_module_sp);
|
|
ModulesDidUnload (module_list);
|
|
module_list.Clear ();
|
|
module_list.Append (new_module_sp);
|
|
ModulesDidLoad (module_list);
|
|
}
|
|
|
|
void
|
|
Target::ModulesDidLoad (ModuleList &module_list)
|
|
{
|
|
m_breakpoint_list.UpdateBreakpoints (module_list, true);
|
|
// TODO: make event data that packages up the module_list
|
|
BroadcastEvent (eBroadcastBitModulesLoaded, NULL);
|
|
}
|
|
|
|
void
|
|
Target::ModulesDidUnload (ModuleList &module_list)
|
|
{
|
|
m_breakpoint_list.UpdateBreakpoints (module_list, false);
|
|
// TODO: make event data that packages up the module_list
|
|
BroadcastEvent (eBroadcastBitModulesUnloaded, NULL);
|
|
}
|
|
|
|
size_t
|
|
Target::ReadMemory (const Address& addr, void *dst, size_t dst_len, Error &error)
|
|
{
|
|
error.Clear();
|
|
|
|
bool process_is_valid = m_process_sp && m_process_sp->IsAlive();
|
|
|
|
Address resolved_addr(addr);
|
|
if (!resolved_addr.IsSectionOffset())
|
|
{
|
|
if (process_is_valid)
|
|
{
|
|
m_section_load_list.ResolveLoadAddress (addr.GetOffset(), resolved_addr);
|
|
}
|
|
else
|
|
{
|
|
m_images.ResolveFileAddress(addr.GetOffset(), resolved_addr);
|
|
}
|
|
}
|
|
|
|
|
|
if (process_is_valid)
|
|
{
|
|
lldb::addr_t load_addr = resolved_addr.GetLoadAddress (this);
|
|
if (load_addr == LLDB_INVALID_ADDRESS)
|
|
{
|
|
if (resolved_addr.GetModule() && resolved_addr.GetModule()->GetFileSpec())
|
|
error.SetErrorStringWithFormat("%s[0x%llx] can't be resolved, %s in not currently loaded.\n",
|
|
resolved_addr.GetModule()->GetFileSpec().GetFilename().AsCString(),
|
|
resolved_addr.GetFileAddress());
|
|
else
|
|
error.SetErrorStringWithFormat("0x%llx can't be resolved.\n", resolved_addr.GetFileAddress());
|
|
}
|
|
else
|
|
{
|
|
size_t bytes_read = m_process_sp->ReadMemory(load_addr, dst, dst_len, error);
|
|
if (bytes_read != dst_len)
|
|
{
|
|
if (error.Success())
|
|
{
|
|
if (bytes_read == 0)
|
|
error.SetErrorStringWithFormat("Read memory from 0x%llx failed.\n", load_addr);
|
|
else
|
|
error.SetErrorStringWithFormat("Only %zu of %zu bytes were read from memory at 0x%llx.\n", bytes_read, dst_len, load_addr);
|
|
}
|
|
}
|
|
if (bytes_read)
|
|
return bytes_read;
|
|
// If the address is not section offset we have an address that
|
|
// doesn't resolve to any address in any currently loaded shared
|
|
// libaries and we failed to read memory so there isn't anything
|
|
// more we can do. If it is section offset, we might be able to
|
|
// read cached memory from the object file.
|
|
if (!resolved_addr.IsSectionOffset())
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
const Section *section = resolved_addr.GetSection();
|
|
if (section && section->GetModule())
|
|
{
|
|
ObjectFile *objfile = section->GetModule()->GetObjectFile();
|
|
return section->ReadSectionDataFromObjectFile (objfile,
|
|
resolved_addr.GetOffset(),
|
|
dst,
|
|
dst_len);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
ModuleSP
|
|
Target::GetSharedModule
|
|
(
|
|
const FileSpec& file_spec,
|
|
const ArchSpec& arch,
|
|
const UUID *uuid_ptr,
|
|
const ConstString *object_name,
|
|
off_t object_offset,
|
|
Error *error_ptr
|
|
)
|
|
{
|
|
// Don't pass in the UUID so we can tell if we have a stale value in our list
|
|
ModuleSP old_module_sp; // This will get filled in if we have a new version of the library
|
|
bool did_create_module = false;
|
|
ModuleSP module_sp;
|
|
|
|
// If there are image search path entries, try to use them first to acquire a suitable image.
|
|
|
|
Error error;
|
|
|
|
if (m_image_search_paths.GetSize())
|
|
{
|
|
FileSpec transformed_spec;
|
|
if (m_image_search_paths.RemapPath (file_spec.GetDirectory(), transformed_spec.GetDirectory()))
|
|
{
|
|
transformed_spec.GetFilename() = file_spec.GetFilename();
|
|
error = ModuleList::GetSharedModule (transformed_spec, arch, uuid_ptr, object_name, object_offset, module_sp, &old_module_sp, &did_create_module);
|
|
}
|
|
}
|
|
|
|
// If a module hasn't been found yet, use the unmodified path.
|
|
|
|
if (!module_sp)
|
|
{
|
|
error = (ModuleList::GetSharedModule (file_spec, arch, uuid_ptr, object_name, object_offset, module_sp, &old_module_sp, &did_create_module));
|
|
}
|
|
|
|
if (module_sp)
|
|
{
|
|
m_images.Append (module_sp);
|
|
if (did_create_module)
|
|
{
|
|
if (old_module_sp && m_images.GetIndexForModule (old_module_sp.get()) != LLDB_INVALID_INDEX32)
|
|
ModuleUpdated(old_module_sp, module_sp);
|
|
else
|
|
ModuleAdded(module_sp);
|
|
}
|
|
}
|
|
if (error_ptr)
|
|
*error_ptr = error;
|
|
return module_sp;
|
|
}
|
|
|
|
|
|
Target *
|
|
Target::CalculateTarget ()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
Process *
|
|
Target::CalculateProcess ()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
Thread *
|
|
Target::CalculateThread ()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
StackFrame *
|
|
Target::CalculateStackFrame ()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
Target::CalculateExecutionContext (ExecutionContext &exe_ctx)
|
|
{
|
|
exe_ctx.target = this;
|
|
exe_ctx.process = NULL; // Do NOT fill in process...
|
|
exe_ctx.thread = NULL;
|
|
exe_ctx.frame = NULL;
|
|
}
|
|
|
|
PathMappingList &
|
|
Target::GetImageSearchPathList ()
|
|
{
|
|
return m_image_search_paths;
|
|
}
|
|
|
|
void
|
|
Target::ImageSearchPathsChanged
|
|
(
|
|
const PathMappingList &path_list,
|
|
void *baton
|
|
)
|
|
{
|
|
Target *target = (Target *)baton;
|
|
if (target->m_images.GetSize() > 1)
|
|
{
|
|
ModuleSP exe_module_sp (target->GetExecutableModule());
|
|
if (exe_module_sp)
|
|
{
|
|
target->m_images.Clear();
|
|
target->SetExecutableModule (exe_module_sp, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
ClangASTContext *
|
|
Target::GetScratchClangASTContext()
|
|
{
|
|
return m_scratch_ast_context_ap.get();
|
|
}
|
|
|
|
lldb::UserSettingsControllerSP
|
|
Target::GetSettingsController (bool finish)
|
|
{
|
|
static lldb::UserSettingsControllerSP g_settings_controller (new SettingsController);
|
|
static bool initialized = false;
|
|
|
|
if (!initialized)
|
|
{
|
|
initialized = UserSettingsController::InitializeSettingsController (g_settings_controller,
|
|
Target::SettingsController::global_settings_table,
|
|
Target::SettingsController::instance_settings_table);
|
|
}
|
|
|
|
if (finish)
|
|
{
|
|
UserSettingsController::FinalizeSettingsController (g_settings_controller);
|
|
g_settings_controller.reset();
|
|
initialized = false;
|
|
}
|
|
|
|
return g_settings_controller;
|
|
}
|
|
|
|
ArchSpec
|
|
Target::GetDefaultArchitecture ()
|
|
{
|
|
lldb::UserSettingsControllerSP settings_controller = Target::GetSettingsController();
|
|
lldb::SettableVariableType var_type;
|
|
Error err;
|
|
StringList result = settings_controller->GetVariable ("target.default-arch", var_type, "[]", err);
|
|
|
|
const char *default_name = "";
|
|
if (result.GetSize() == 1 && err.Success())
|
|
default_name = result.GetStringAtIndex (0);
|
|
|
|
ArchSpec default_arch (default_name);
|
|
return default_arch;
|
|
}
|
|
|
|
void
|
|
Target::SetDefaultArchitecture (ArchSpec new_arch)
|
|
{
|
|
if (new_arch.IsValid())
|
|
Target::GetSettingsController ()->SetVariable ("target.default-arch", new_arch.AsCString(),
|
|
lldb::eVarSetOperationAssign, false, "[]");
|
|
}
|
|
|
|
Target *
|
|
Target::GetTargetFromContexts (const ExecutionContext *exe_ctx_ptr, const SymbolContext *sc_ptr)
|
|
{
|
|
// The target can either exist in the "process" of ExecutionContext, or in
|
|
// the "target_sp" member of SymbolContext. This accessor helper function
|
|
// will get the target from one of these locations.
|
|
|
|
Target *target = NULL;
|
|
if (sc_ptr != NULL)
|
|
target = sc_ptr->target_sp.get();
|
|
if (target == NULL)
|
|
{
|
|
if (exe_ctx_ptr != NULL && exe_ctx_ptr->process != NULL)
|
|
target = &exe_ctx_ptr->process->GetTarget();
|
|
}
|
|
return target;
|
|
}
|
|
|
|
|
|
void
|
|
Target::UpdateInstanceName ()
|
|
{
|
|
StreamString sstr;
|
|
|
|
ModuleSP module_sp = GetExecutableModule();
|
|
if (module_sp)
|
|
{
|
|
sstr.Printf ("%s_%s",
|
|
module_sp->GetFileSpec().GetFilename().AsCString(),
|
|
module_sp->GetArchitecture().AsCString());
|
|
Target::GetSettingsController()->RenameInstanceSettings (GetInstanceName().AsCString(),
|
|
sstr.GetData());
|
|
}
|
|
}
|
|
|
|
const char *
|
|
Target::GetExpressionPrefixContentsAsCString ()
|
|
{
|
|
return m_expr_prefix_contents.c_str();
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
// class Target::SettingsController
|
|
//--------------------------------------------------------------
|
|
|
|
Target::SettingsController::SettingsController () :
|
|
UserSettingsController ("target", Debugger::GetSettingsController()),
|
|
m_default_architecture ()
|
|
{
|
|
m_default_settings.reset (new TargetInstanceSettings (*this, false,
|
|
InstanceSettings::GetDefaultName().AsCString()));
|
|
}
|
|
|
|
Target::SettingsController::~SettingsController ()
|
|
{
|
|
}
|
|
|
|
lldb::InstanceSettingsSP
|
|
Target::SettingsController::CreateInstanceSettings (const char *instance_name)
|
|
{
|
|
TargetInstanceSettings *new_settings = new TargetInstanceSettings (*(Target::GetSettingsController().get()),
|
|
false, instance_name);
|
|
lldb::InstanceSettingsSP new_settings_sp (new_settings);
|
|
return new_settings_sp;
|
|
}
|
|
|
|
const ConstString &
|
|
Target::SettingsController::DefArchVarName ()
|
|
{
|
|
static ConstString def_arch_var_name ("default-arch");
|
|
|
|
return def_arch_var_name;
|
|
}
|
|
|
|
bool
|
|
Target::SettingsController::SetGlobalVariable (const ConstString &var_name,
|
|
const char *index_value,
|
|
const char *value,
|
|
const SettingEntry &entry,
|
|
const lldb::VarSetOperationType op,
|
|
Error&err)
|
|
{
|
|
if (var_name == DefArchVarName())
|
|
{
|
|
ArchSpec tmp_spec (value);
|
|
if (tmp_spec.IsValid())
|
|
m_default_architecture = tmp_spec;
|
|
else
|
|
err.SetErrorStringWithFormat ("'%s' is not a valid architecture.", value);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool
|
|
Target::SettingsController::GetGlobalVariable (const ConstString &var_name,
|
|
StringList &value,
|
|
Error &err)
|
|
{
|
|
if (var_name == DefArchVarName())
|
|
{
|
|
// If the arch is invalid (the default), don't show a string for it
|
|
if (m_default_architecture.IsValid())
|
|
value.AppendString (m_default_architecture.AsCString());
|
|
return true;
|
|
}
|
|
else
|
|
err.SetErrorStringWithFormat ("unrecognized variable name '%s'", var_name.AsCString());
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
// class TargetInstanceSettings
|
|
//--------------------------------------------------------------
|
|
|
|
TargetInstanceSettings::TargetInstanceSettings (UserSettingsController &owner, bool live_instance,
|
|
const char *name) :
|
|
InstanceSettings (owner, (name == NULL ? InstanceSettings::InvalidName().AsCString() : name), live_instance)
|
|
{
|
|
// CopyInstanceSettings is a pure virtual function in InstanceSettings; it therefore cannot be called
|
|
// until the vtables for TargetInstanceSettings are properly set up, i.e. AFTER all the initializers.
|
|
// For this reason it has to be called here, rather than in the initializer or in the parent constructor.
|
|
// This is true for CreateInstanceName() too.
|
|
|
|
if (GetInstanceName () == InstanceSettings::InvalidName())
|
|
{
|
|
ChangeInstanceName (std::string (CreateInstanceName().AsCString()));
|
|
m_owner.RegisterInstanceSettings (this);
|
|
}
|
|
|
|
if (live_instance)
|
|
{
|
|
const lldb::InstanceSettingsSP &pending_settings = m_owner.FindPendingSettings (m_instance_name);
|
|
CopyInstanceSettings (pending_settings,false);
|
|
//m_owner.RemovePendingSettings (m_instance_name);
|
|
}
|
|
}
|
|
|
|
TargetInstanceSettings::TargetInstanceSettings (const TargetInstanceSettings &rhs) :
|
|
InstanceSettings (*(Target::GetSettingsController().get()), CreateInstanceName().AsCString())
|
|
{
|
|
if (m_instance_name != InstanceSettings::GetDefaultName())
|
|
{
|
|
const lldb::InstanceSettingsSP &pending_settings = m_owner.FindPendingSettings (m_instance_name);
|
|
CopyInstanceSettings (pending_settings,false);
|
|
//m_owner.RemovePendingSettings (m_instance_name);
|
|
}
|
|
}
|
|
|
|
TargetInstanceSettings::~TargetInstanceSettings ()
|
|
{
|
|
}
|
|
|
|
TargetInstanceSettings&
|
|
TargetInstanceSettings::operator= (const TargetInstanceSettings &rhs)
|
|
{
|
|
if (this != &rhs)
|
|
{
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
#define EXPR_PREFIX_STRING "expr-prefix"
|
|
|
|
void
|
|
TargetInstanceSettings::UpdateInstanceSettingsVariable (const ConstString &var_name,
|
|
const char *index_value,
|
|
const char *value,
|
|
const ConstString &instance_name,
|
|
const SettingEntry &entry,
|
|
lldb::VarSetOperationType op,
|
|
Error &err,
|
|
bool pending)
|
|
{
|
|
static ConstString expr_prefix_str (EXPR_PREFIX_STRING);
|
|
|
|
if (var_name == expr_prefix_str)
|
|
{
|
|
switch (op)
|
|
{
|
|
default:
|
|
err.SetErrorToGenericError ();
|
|
err.SetErrorString ("Unrecognized operation. Cannot update value.\n");
|
|
return;
|
|
case lldb::eVarSetOperationAssign:
|
|
{
|
|
FileSpec file_spec(value, true);
|
|
|
|
if (!file_spec.Exists())
|
|
{
|
|
err.SetErrorToGenericError ();
|
|
err.SetErrorStringWithFormat ("%s does not exist.\n", value);
|
|
return;
|
|
}
|
|
|
|
DataBufferMemoryMap buf;
|
|
|
|
if (!buf.MemoryMapFromFileSpec(&file_spec) &&
|
|
buf.GetError().Fail())
|
|
{
|
|
err.SetErrorToGenericError ();
|
|
err.SetErrorStringWithFormat ("Couldn't read from %s: %s\n", value, buf.GetError().AsCString());
|
|
return;
|
|
}
|
|
|
|
m_expr_prefix_path = value;
|
|
m_expr_prefix_contents.assign(reinterpret_cast<const char *>(buf.GetBytes()), buf.GetByteSize());
|
|
}
|
|
return;
|
|
case lldb::eVarSetOperationAppend:
|
|
err.SetErrorToGenericError ();
|
|
err.SetErrorString ("Cannot append to a path.\n");
|
|
return;
|
|
case lldb::eVarSetOperationClear:
|
|
m_expr_prefix_path.clear ();
|
|
m_expr_prefix_contents.clear ();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
TargetInstanceSettings::CopyInstanceSettings (const lldb::InstanceSettingsSP &new_settings,
|
|
bool pending)
|
|
{
|
|
TargetInstanceSettings *new_settings_ptr = static_cast <TargetInstanceSettings *> (new_settings.get());
|
|
|
|
if (!new_settings_ptr)
|
|
return;
|
|
|
|
m_expr_prefix_path = new_settings_ptr->m_expr_prefix_path;
|
|
m_expr_prefix_contents = new_settings_ptr->m_expr_prefix_contents;
|
|
}
|
|
|
|
bool
|
|
TargetInstanceSettings::GetInstanceSettingsValue (const SettingEntry &entry,
|
|
const ConstString &var_name,
|
|
StringList &value,
|
|
Error *err)
|
|
{
|
|
static ConstString expr_prefix_str (EXPR_PREFIX_STRING);
|
|
|
|
if (var_name == expr_prefix_str)
|
|
{
|
|
value.AppendString (m_expr_prefix_path.c_str(), m_expr_prefix_path.size());
|
|
}
|
|
else
|
|
{
|
|
if (err)
|
|
err->SetErrorStringWithFormat ("unrecognized variable name '%s'", var_name.AsCString());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const ConstString
|
|
TargetInstanceSettings::CreateInstanceName ()
|
|
{
|
|
StreamString sstr;
|
|
static int instance_count = 1;
|
|
|
|
sstr.Printf ("target_%d", instance_count);
|
|
++instance_count;
|
|
|
|
const ConstString ret_val (sstr.GetData());
|
|
return ret_val;
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// Target::SettingsController Variable Tables
|
|
//--------------------------------------------------
|
|
|
|
SettingEntry
|
|
Target::SettingsController::global_settings_table[] =
|
|
{
|
|
//{ "var-name", var-type, "default", enum-table, init'd, hidden, "help-text"},
|
|
{ "default-arch", eSetVarTypeString, NULL, NULL, false, false, "Default architecture to choose, when there's a choice." },
|
|
{ NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL }
|
|
};
|
|
|
|
SettingEntry
|
|
Target::SettingsController::instance_settings_table[] =
|
|
{
|
|
//{ "var-name", var-type, "default", enum-table, init'd, hidden, "help-text"},
|
|
{ EXPR_PREFIX_STRING, eSetVarTypeString, NULL, NULL, false, false, "Path to a file containing expressions to be prepended to all expressions." },
|
|
{ NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL }
|
|
};
|