llvm-project/lldb/source/Target/Target.cpp

1201 lines
37 KiB
C++
Raw Normal View History

//===-- 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"
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/StreamString.h"
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Host/Host.h"
#include "lldb/lldb-private-log.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Process.h"
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
#include "lldb/Target/StackFrame.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// Target constructor
//----------------------------------------------------------------------
Target::Target(Debugger &debugger) :
Broadcaster("lldb.target"),
TargetInstanceSettings (*GetSettingsController()),
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),
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
m_scratch_ast_context_ap (NULL),
m_persistent_variables ()
{
SetEventName (eBroadcastBitBreakpointChanged, "breakpoint-changed");
SetEventName (eBroadcastBitModulesLoaded, "modules-loaded");
SetEventName (eBroadcastBitModulesUnloaded, "modules-unloaded");
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
log->Printf ("%p Target::Target()", this);
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
Target::~Target()
{
LogSP 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
{
2010-10-30 12:51:46 +08:00
s->PutCString (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
Added support for inlined stack frames being represented as real stack frames which is now on by default. Frames are gotten from the unwinder as concrete frames, then if inline frames are to be shown, extra information to track and reconstruct these frames is cached with each Thread and exanded as needed. I added an inline height as part of the lldb_private::StackID class, the class that helps us uniquely identify stack frames. This allows for two frames to shared the same call frame address, yet differ only in inline height. Fixed setting breakpoint by address to not require addresses to resolve. A quick example: % cat main.cpp % ./build/Debug/lldb test/stl/a.out Current executable set to 'test/stl/a.out' (x86_64). (lldb) breakpoint set --address 0x0000000100000d31 Breakpoint created: 1: address = 0x0000000100000d31, locations = 1 (lldb) r Launching 'a.out' (x86_64) (lldb) Process 38031 Stopped * thread #1: tid = 0x2e03, pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::_M_data() const at /usr/include/c++/4.2.1/bits/basic_string.h:280, stop reason = breakpoint 1.1, queue = com.apple.main-thread 277 278 _CharT* 279 _M_data() const 280 -> { return _M_dataplus._M_p; } 281 282 _CharT* 283 _M_data(_CharT* __p) (lldb) bt thread #1: tid = 0x2e03, stop reason = breakpoint 1.1, queue = com.apple.main-thread frame #0: pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::_M_data() const at /usr/include/c++/4.2.1/bits/basic_string.h:280 frame #1: pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::_M_rep() const at /usr/include/c++/4.2.1/bits/basic_string.h:288 frame #2: pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::size() const at /usr/include/c++/4.2.1/bits/basic_string.h:606 frame #3: pc = 0x0000000100000d31, where = a.out`main [inlined] operator<< <char, std::char_traits<char>, std::allocator<char> > at /usr/include/c++/4.2.1/bits/basic_string.h:2414 frame #4: pc = 0x0000000100000d31, where = a.out`main + 33 at /Volumes/work/gclayton/Documents/src/lldb/test/stl/main.cpp:14 frame #5: pc = 0x0000000100000d08, where = a.out`start + 52 Each inline frame contains only the variables that they contain and each inlined stack frame is treated as a single entity. llvm-svn: 111877
2010-08-24 08:45:41 +08:00
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.
Added support for inlined stack frames being represented as real stack frames which is now on by default. Frames are gotten from the unwinder as concrete frames, then if inline frames are to be shown, extra information to track and reconstruct these frames is cached with each Thread and exanded as needed. I added an inline height as part of the lldb_private::StackID class, the class that helps us uniquely identify stack frames. This allows for two frames to shared the same call frame address, yet differ only in inline height. Fixed setting breakpoint by address to not require addresses to resolve. A quick example: % cat main.cpp % ./build/Debug/lldb test/stl/a.out Current executable set to 'test/stl/a.out' (x86_64). (lldb) breakpoint set --address 0x0000000100000d31 Breakpoint created: 1: address = 0x0000000100000d31, locations = 1 (lldb) r Launching 'a.out' (x86_64) (lldb) Process 38031 Stopped * thread #1: tid = 0x2e03, pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::_M_data() const at /usr/include/c++/4.2.1/bits/basic_string.h:280, stop reason = breakpoint 1.1, queue = com.apple.main-thread 277 278 _CharT* 279 _M_data() const 280 -> { return _M_dataplus._M_p; } 281 282 _CharT* 283 _M_data(_CharT* __p) (lldb) bt thread #1: tid = 0x2e03, stop reason = breakpoint 1.1, queue = com.apple.main-thread frame #0: pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::_M_data() const at /usr/include/c++/4.2.1/bits/basic_string.h:280 frame #1: pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::_M_rep() const at /usr/include/c++/4.2.1/bits/basic_string.h:288 frame #2: pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::size() const at /usr/include/c++/4.2.1/bits/basic_string.h:606 frame #3: pc = 0x0000000100000d31, where = a.out`main [inlined] operator<< <char, std::char_traits<char>, std::allocator<char> > at /usr/include/c++/4.2.1/bits/basic_string.h:2414 frame #4: pc = 0x0000000100000d31, where = a.out`main + 33 at /Volumes/work/gclayton/Documents/src/lldb/test/stl/main.cpp:14 frame #5: pc = 0x0000000100000d08, where = a.out`start + 52 Each inline frame contains only the variables that they contain and each inlined stack frame is treated as a single entity. llvm-svn: 111877
2010-08-24 08:45:41 +08:00
// Try and resolve as a load address if possible
m_section_load_list.ResolveLoadAddress(addr, so_addr);
Added support for inlined stack frames being represented as real stack frames which is now on by default. Frames are gotten from the unwinder as concrete frames, then if inline frames are to be shown, extra information to track and reconstruct these frames is cached with each Thread and exanded as needed. I added an inline height as part of the lldb_private::StackID class, the class that helps us uniquely identify stack frames. This allows for two frames to shared the same call frame address, yet differ only in inline height. Fixed setting breakpoint by address to not require addresses to resolve. A quick example: % cat main.cpp % ./build/Debug/lldb test/stl/a.out Current executable set to 'test/stl/a.out' (x86_64). (lldb) breakpoint set --address 0x0000000100000d31 Breakpoint created: 1: address = 0x0000000100000d31, locations = 1 (lldb) r Launching 'a.out' (x86_64) (lldb) Process 38031 Stopped * thread #1: tid = 0x2e03, pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::_M_data() const at /usr/include/c++/4.2.1/bits/basic_string.h:280, stop reason = breakpoint 1.1, queue = com.apple.main-thread 277 278 _CharT* 279 _M_data() const 280 -> { return _M_dataplus._M_p; } 281 282 _CharT* 283 _M_data(_CharT* __p) (lldb) bt thread #1: tid = 0x2e03, stop reason = breakpoint 1.1, queue = com.apple.main-thread frame #0: pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::_M_data() const at /usr/include/c++/4.2.1/bits/basic_string.h:280 frame #1: pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::_M_rep() const at /usr/include/c++/4.2.1/bits/basic_string.h:288 frame #2: pc = 0x0000000100000d31, where = a.out`main [inlined] std::string::size() const at /usr/include/c++/4.2.1/bits/basic_string.h:606 frame #3: pc = 0x0000000100000d31, where = a.out`main [inlined] operator<< <char, std::char_traits<char>, std::allocator<char> > at /usr/include/c++/4.2.1/bits/basic_string.h:2414 frame #4: pc = 0x0000000100000d31, where = a.out`main + 33 at /Volumes/work/gclayton/Documents/src/lldb/test/stl/main.cpp:14 frame #5: pc = 0x0000000100000d08, where = a.out`start + 52 Each inline frame contains only the variables that they contain and each inlined stack frame is treated as a single entity. llvm-svn: 111877
2010-08-24 08:45:41 +08:00
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
Added function name types to allow us to set breakpoints by name more intelligently. The four name types we currently have are: eFunctionNameTypeFull = (1 << 1), // The function name. // For C this is the same as just the name of the function // For C++ this is the demangled version of the mangled name. // For ObjC this is the full function signature with the + or // - and the square brackets and the class and selector eFunctionNameTypeBase = (1 << 2), // The function name only, no namespaces or arguments and no class // methods or selectors will be searched. eFunctionNameTypeMethod = (1 << 3), // Find function by method name (C++) with no namespace or arguments eFunctionNameTypeSelector = (1 << 4) // Find function by selector name (ObjC) names this allows much more flexibility when setting breakoints: (lldb) breakpoint set --name main --basename (lldb) breakpoint set --name main --fullname (lldb) breakpoint set --name main --method (lldb) breakpoint set --name main --selector The default: (lldb) breakpoint set --name main will inspect the name "main" and look for any parens, or if the name starts with "-[" or "+[" and if any are found then a full name search will happen. Else a basename search will be the default. Fixed some command option structures so not all options are required when they shouldn't be. Cleaned up the breakpoint output summary. Made the "image lookup --address <addr>" output much more verbose so it shows all the important symbol context results. Added a GetDescription method to many of the SymbolContext objects for the more verbose output. llvm-svn: 107075
2010-06-29 05:30:43 +08:00
Target::CreateBreakpoint (FileSpec *containingModule, const char *func_name, uint32_t func_name_type_mask, bool internal)
{
Added function name types to allow us to set breakpoints by name more intelligently. The four name types we currently have are: eFunctionNameTypeFull = (1 << 1), // The function name. // For C this is the same as just the name of the function // For C++ this is the demangled version of the mangled name. // For ObjC this is the full function signature with the + or // - and the square brackets and the class and selector eFunctionNameTypeBase = (1 << 2), // The function name only, no namespaces or arguments and no class // methods or selectors will be searched. eFunctionNameTypeMethod = (1 << 3), // Find function by method name (C++) with no namespace or arguments eFunctionNameTypeSelector = (1 << 4) // Find function by selector name (ObjC) names this allows much more flexibility when setting breakoints: (lldb) breakpoint set --name main --basename (lldb) breakpoint set --name main --fullname (lldb) breakpoint set --name main --method (lldb) breakpoint set --name main --selector The default: (lldb) breakpoint set --name main will inspect the name "main" and look for any parens, or if the name starts with "-[" or "+[" and if any are found then a full name search will happen. Else a basename search will be the default. Fixed some command option structures so not all options are required when they shouldn't be. Cleaned up the breakpoint output summary. Made the "image lookup --address <addr>" output much more verbose so it shows all the important symbol context results. Added a GetDescription method to many of the SymbolContext objects for the more verbose output. llvm-svn: 107075
2010-06-29 05:30:43 +08:00
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);
LogSP 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)
{
LogSP 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)
{
LogSP 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)
{
LogSP 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)
{
LogSP 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)
{
LogSP 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)
{
LogSP 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());
Added a new Host call to find LLDB related paths: static bool Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec); This will fill in "file_spec" with an appropriate path that is appropriate for the current Host OS. MacOSX will return paths within the LLDB.framework, and other unixes will return the paths they want. The current PathType enums are: typedef enum PathType { ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc) ePathTypeHeaderDir, // Find LLDB header file directory ePathTypePythonDir // Find Python modules (PYTHONPATH) directory } PathType; All places that were finding executables are and python paths are now updated to use this Host call. Added another new host call to launch the inferior in a terminal. This ability will be very host specific and doesn't need to be supported on all systems. MacOSX currently will create a new .command file and tell Terminal.app to open the .command file. It also uses the new "darwin-debug" app which is a small app that uses posix to exec (no fork) and stop at the entry point of the program. The GDB remote plug-in is almost able launch a process and attach to it, it currently will spawn the process, but it won't attach to it just yet. This will let LLDB not have to share the terminal with another process and a new terminal window will pop up when you launch. This won't get hooked up until we work out all of the kinks. The new Host function is: static lldb::pid_t Host::LaunchInNewTerminal ( const char **argv, // argv[0] is executable const char **envp, const ArchSpec *arch_spec, bool stop_at_entry, bool disable_aslr); Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero filling the entire path buffer. Fixed an issue with the dynamic checker function where I missed a '$' prefix that should have been added. llvm-svn: 116690
2010-10-18 06:03:32 +08:00
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);
// Remove the images from the target image list
m_images.Remove(module_list);
// 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
There are now to new "settings set" variables that live in each debugger instance: settings set frame-format <string> settings set thread-format <string> This allows users to control the information that is seen when dumping threads and frames. The default values are set such that they do what they used to do prior to changing over the the user defined formats. This allows users with terminals that can display color to make different items different colors using the escape control codes. A few alias examples that will colorize your thread and frame prompts are: settings set frame-format 'frame #${frame.index}: \033[0;33m${frame.pc}\033[0m{ \033[1;4;36m${module.file.basename}\033[0;36m ${function.name}{${function.pc-offset}}\033[0m}{ \033[0;35mat \033[1;35m${line.file.basename}:${line.number}}\033[0m\n' settings set thread-format 'thread #${thread.index}: \033[1;33mtid\033[0;33m = ${thread.id}\033[0m{, \033[0;33m${frame.pc}\033[0m}{ \033[1;4;36m${module.file.basename}\033[0;36m ${function.name}{${function.pc-offset}}\033[0m}{, \033[1;35mstop reason\033[0;35m = ${thread.stop-reason}\033[0m}{, \033[1;36mname = \033[0;36m${thread.name}\033[0m}{, \033[1;32mqueue = \033[0;32m${thread.queue}}\033[0m\n' A quick web search for "colorize terminal output" should allow you to see what you can do to make your output look like you want it. The "settings set" commands above can of course be added to your ~/.lldbinit file for permanent use. Changed the pure virtual void ExecutionContextScope::Calculate (ExecutionContext&); To: void ExecutionContextScope::CalculateExecutionContext (ExecutionContext&); I did this because this is a class that anything in the execution context heirarchy inherits from and "target->Calculate (exe_ctx)" didn't always tell you what it was really trying to do unless you look at the parameter. llvm-svn: 115485
2010-10-04 09:05:56 +08:00
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();
}
void
Target::Initialize ()
{
UserSettingsControllerSP &usc = GetSettingsController();
usc.reset (new SettingsController);
UserSettingsController::InitializeSettingsController (usc,
SettingsController::global_settings_table,
SettingsController::instance_settings_table);
}
void
Target::Terminate ()
{
UserSettingsControllerSP &usc = GetSettingsController();
UserSettingsController::FinalizeSettingsController (usc);
usc.reset();
}
UserSettingsControllerSP &
Target::GetSettingsController ()
{
static UserSettingsControllerSP g_settings_controller;
return g_settings_controller;
}
ArchSpec
Target::GetDefaultArchitecture ()
{
lldb::UserSettingsControllerSP &settings_controller = 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())
GetSettingsController ()->SetVariable ("target.default-arch",
new_arch.AsCString(),
lldb::eVarSetOperationAssign,
false,
"[]");
}
There are now to new "settings set" variables that live in each debugger instance: settings set frame-format <string> settings set thread-format <string> This allows users to control the information that is seen when dumping threads and frames. The default values are set such that they do what they used to do prior to changing over the the user defined formats. This allows users with terminals that can display color to make different items different colors using the escape control codes. A few alias examples that will colorize your thread and frame prompts are: settings set frame-format 'frame #${frame.index}: \033[0;33m${frame.pc}\033[0m{ \033[1;4;36m${module.file.basename}\033[0;36m ${function.name}{${function.pc-offset}}\033[0m}{ \033[0;35mat \033[1;35m${line.file.basename}:${line.number}}\033[0m\n' settings set thread-format 'thread #${thread.index}: \033[1;33mtid\033[0;33m = ${thread.id}\033[0m{, \033[0;33m${frame.pc}\033[0m}{ \033[1;4;36m${module.file.basename}\033[0;36m ${function.name}{${function.pc-offset}}\033[0m}{, \033[1;35mstop reason\033[0;35m = ${thread.stop-reason}\033[0m}{, \033[1;36mname = \033[0;36m${thread.name}\033[0m}{, \033[1;32mqueue = \033[0;32m${thread.queue}}\033[0m\n' A quick web search for "colorize terminal output" should allow you to see what you can do to make your output look like you want it. The "settings set" commands above can of course be added to your ~/.lldbinit file for permanent use. Changed the pure virtual void ExecutionContextScope::Calculate (ExecutionContext&); To: void ExecutionContextScope::CalculateExecutionContext (ExecutionContext&); I did this because this is a class that anything in the execution context heirarchy inherits from and "target->Calculate (exe_ctx)" didn't always tell you what it was really trying to do unless you look at the parameter. llvm-svn: 115485
2010-10-04 09:05:56 +08:00
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());
GetSettingsController()->RenameInstanceSettings (GetInstanceName().AsCString(),
sstr.GetData());
}
}
const char *
Target::GetExpressionPrefixContentsAsCString ()
{
return m_expr_prefix_contents.c_str();
}
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
ExecutionResults
Target::EvaluateExpression
(
const char *expr_cstr,
StackFrame *frame,
bool unwind_on_error,
lldb::ValueObjectSP &result_valobj_sp
)
{
ExecutionResults execution_results = eExecutionSetupError;
result_valobj_sp.reset();
ExecutionContext exe_ctx;
if (frame)
{
frame->CalculateExecutionContext(exe_ctx);
result_valobj_sp = frame->GetValueForVariableExpressionPath (expr_cstr);
}
else if (m_process_sp)
{
m_process_sp->CalculateExecutionContext(exe_ctx);
}
else
{
CalculateExecutionContext(exe_ctx);
}
if (result_valobj_sp)
{
execution_results = eExecutionCompleted;
// We got a result from the frame variable expression path above...
ConstString persistent_variable_name (m_persistent_variables.GetNextPersistentVariableName());
lldb::ValueObjectSP const_valobj_sp;
// Check in case our value is already a constant value
if (result_valobj_sp->GetIsConstant())
{
const_valobj_sp = result_valobj_sp;
const_valobj_sp->SetName (persistent_variable_name);
}
else
const_valobj_sp = result_valobj_sp->CreateConstantValue (exe_ctx.GetBestExecutionContextScope(),
persistent_variable_name);
result_valobj_sp = const_valobj_sp;
ClangExpressionVariableSP clang_expr_variable_sp(m_persistent_variables.CreatePersistentVariable(result_valobj_sp));
assert (clang_expr_variable_sp.get());
}
else
{
// Make sure we aren't just trying to see the value of a persistent
// variable (something like "$0")
lldb::ClangExpressionVariableSP persistent_var_sp (m_persistent_variables.GetVariable (expr_cstr));
if (persistent_var_sp)
{
result_valobj_sp = persistent_var_sp->GetValueObject ();
execution_results = eExecutionCompleted;
}
else
{
const char *prefix = GetExpressionPrefixContentsAsCString();
execution_results = ClangUserExpression::Evaluate (exe_ctx,
unwind_on_error,
expr_cstr,
prefix,
result_valobj_sp);
}
}
return execution_results;
}
//--------------------------------------------------------------
// 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 (*GetSettingsController(),
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 ? name : InstanceSettings::InvalidName().AsCString(), 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(), 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 }
};