JITed functions can now have debug info and be debugged with debug and source info:

(lldb) b puts
(lldb) expr -g -i0 -- (int)puts("hello")

First we will stop at the entry point of the expression before it runs, then we can step over a few times and hit the breakpoint in "puts", then we can continue and finishing stepping and fininsh the expression.

Main features:
- New ObjectFileJIT class that can be easily created for JIT functions
- debug info can now be enabled when parsing expressions
- source for any function that is run throught the JIT is now saved in LLDB process specific temp directory and cleaned up on exit
- "expr -g --" allows you to single step through your expression function with source code

<rdar://problem/16382881>

llvm-svn: 204682
This commit is contained in:
Greg Clayton 2014-03-24 23:10:19 +00:00
parent 2256d0dced
commit 23f8c95a44
34 changed files with 1367 additions and 166 deletions

View File

@ -92,6 +92,10 @@ public:
const TimeValue *object_mod_time_ptr = NULL);
Module (const ModuleSpec &module_spec);
static lldb::ModuleSP
CreateJITModule (const lldb::ObjectFileJITDelegateSP &delegate_sp);
//------------------------------------------------------------------
/// Destructor.
//------------------------------------------------------------------
@ -1170,7 +1174,9 @@ protected:
friend class SymbolFile;
private:
Module (); // Only used internally by CreateJITModule ()
size_t
FindTypes_Impl (const SymbolContext& sc,
const ConstString &name,

View File

@ -51,7 +51,8 @@ public:
/// The expression to be parsed.
//------------------------------------------------------------------
ClangExpressionParser (ExecutionContextScope *exe_scope,
ClangExpression &expr);
ClangExpression &expr,
bool generate_debug_info);
//------------------------------------------------------------------
/// Destructor
@ -84,9 +85,9 @@ public:
/// and func_end do not delimit an allocated region; the allocated
/// region may begin before func_addr.)
///
/// @param[in] execution_unit_ap
/// @param[in] execution_unit_sp
/// After parsing, ownership of the execution unit for
/// for the expression is handed to this unique pointer.
/// for the expression is handed to this shared pointer.
///
/// @param[in] exe_ctx
/// The execution context to write the function into.
@ -112,7 +113,7 @@ public:
Error
PrepareForExecution (lldb::addr_t &func_addr,
lldb::addr_t &func_end,
std::unique_ptr<IRExecutionUnit> &execution_unit_ap,
std::shared_ptr<IRExecutionUnit> &execution_unit_sp,
ExecutionContext &exe_ctx,
bool &can_interpret,
lldb_private::ExecutionPolicy execution_policy);
@ -134,6 +135,9 @@ public:
DisassembleFunction (Stream &stream,
ExecutionContext &exe_ctx);
bool
GetGenerateDebugInfo () const;
private:
ClangExpression & m_expr; ///< The expression to be parsed
std::unique_ptr<llvm::LLVMContext> m_llvm_context; ///< The LLVM context to generate IR into
@ -143,7 +147,6 @@ private:
std::unique_ptr<clang::SelectorTable> m_selector_table; ///< Selector table for Objective-C methods
std::unique_ptr<clang::ASTContext> m_ast_context; ///< The AST context used to hold types and names for the parser
std::unique_ptr<clang::CodeGenerator> m_code_generator; ///< The Clang object that generates IR
std::unique_ptr<IRExecutionUnit> m_execution_unit; ///< The container for the finished Module
};
}

View File

@ -410,7 +410,8 @@ private:
//------------------------------------------------------------------
std::unique_ptr<ClangExpressionParser> m_parser; ///< The parser responsible for compiling the function.
std::unique_ptr<IRExecutionUnit> m_execution_unit_ap;
std::shared_ptr<IRExecutionUnit> m_execution_unit_sp;
lldb::ModuleWP m_jit_module_wp;
Function *m_function_ptr; ///< The function we're going to call. May be NULL if we don't have debug info for the function.
Address m_function_addr; ///< If we don't have the FunctionSP, we at least need the address & return type.

View File

@ -105,7 +105,8 @@ public:
Parse (Stream &error_stream,
ExecutionContext &exe_ctx,
lldb_private::ExecutionPolicy execution_policy,
bool keep_result_in_memory);
bool keep_result_in_memory,
bool generate_debug_info);
bool
CanInterpret ()
@ -344,11 +345,11 @@ private:
std::string m_transformed_text; ///< The text of the expression, as send to the parser
ResultType m_desired_type; ///< The type to coerce the expression's result to. If eResultTypeAny, inferred from the expression.
std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing the expression.
std::unique_ptr<IRExecutionUnit> m_execution_unit_ap; ///< The execution unit the expression is stored in.
std::unique_ptr<Materializer> m_materializer_ap; ///< The materializer to use when running the expression.
std::unique_ptr<ASTResultSynthesizer> m_result_synthesizer; ///< The result synthesizer, if one is needed.
std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing the expression.
std::shared_ptr<IRExecutionUnit> m_execution_unit_sp; ///< The execution unit the expression is stored in.
std::unique_ptr<Materializer> m_materializer_ap; ///< The materializer to use when running the expression.
std::unique_ptr<ASTResultSynthesizer> m_result_synthesizer; ///< The result synthesizer, if one is needed.
lldb::ModuleWP m_jit_module_wp;
bool m_enforce_valid_object; ///< True if the expression parser should enforce the presence of a valid class pointer in order to generate the expression as a method.
bool m_cplusplus; ///< True if the expression is compiled as a C++ member function (true if it was parsed when exe_ctx was in a C++ method).
bool m_objectivec; ///< True if the expression is compiled as an Objective-C method (true if it was parsed when exe_ctx was in an Objective-C method).

View File

@ -168,10 +168,10 @@ public:
private:
std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression.
std::unique_ptr<IRExecutionUnit> m_execution_unit_ap;
std::string m_function_text; ///< The text of the function. Must be a well-formed translation unit.
std::string m_function_name; ///< The name of the function.
std::shared_ptr<IRExecutionUnit> m_execution_unit_sp;
lldb::ModuleWP m_jit_module_wp;
std::string m_function_text; ///< The text of the function. Must be a well-formed translation unit.
std::string m_function_name; ///< The name of the function.
};
} // namespace lldb_private

View File

@ -30,6 +30,7 @@
#include "lldb/Expression/ClangExpressionParser.h"
#include "lldb/Expression/IRMemoryMap.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Symbol/ObjectFile.h"
namespace llvm {
@ -60,7 +61,10 @@ class Error;
/// into the target process, the IRExecutionUnit knows how to copy the
/// emitted code into the target process.
//----------------------------------------------------------------------
class IRExecutionUnit : public IRMemoryMap
class IRExecutionUnit :
public std::enable_shared_from_this<IRExecutionUnit>,
public IRMemoryMap,
public ObjectFileJITDelegate
{
public:
//------------------------------------------------------------------
@ -77,12 +81,14 @@ public:
//------------------------------------------------------------------
~IRExecutionUnit();
llvm::Module *GetModule()
llvm::Module *
GetModule()
{
return m_module;
}
llvm::Function *GetFunction()
llvm::Function *
GetFunction()
{
if (m_module)
return m_module->getFunction (m_name.AsCString());
@ -90,9 +96,10 @@ public:
return NULL;
}
void GetRunnableInfo(Error &error,
lldb::addr_t &func_addr,
lldb::addr_t &func_end);
void
GetRunnableInfo (Error &error,
lldb::addr_t &func_addr,
lldb::addr_t &func_end);
//------------------------------------------------------------------
/// Accessors for IRForTarget and other clients that may want binary
@ -100,11 +107,36 @@ public:
/// IRExecutionUnit unless the client explicitly chooses to free it.
//------------------------------------------------------------------
lldb::addr_t WriteNow(const uint8_t *bytes,
size_t size,
Error &error);
lldb::addr_t
WriteNow (const uint8_t *bytes,
size_t size,
Error &error);
void FreeNow(lldb::addr_t allocation);
void
FreeNow (lldb::addr_t allocation);
//------------------------------------------------------------------
/// ObjectFileJITDelegate overrides
//------------------------------------------------------------------
virtual lldb::ByteOrder
GetByteOrder () const;
virtual uint32_t
GetAddressByteSize () const;
virtual void
PopulateSymtab (lldb_private::ObjectFile *obj_file,
lldb_private::Symtab &symtab);
virtual void
PopulateSectionList (lldb_private::ObjectFile *obj_file,
lldb_private::SectionList &section_list);
virtual bool
GetArchitecture (lldb_private::ArchSpec &arch);
lldb::ModuleSP
GetJITModule ();
private:
//------------------------------------------------------------------
@ -180,6 +212,7 @@ private:
public:
MemoryManager (IRExecutionUnit &parent);
virtual ~MemoryManager();
//------------------------------------------------------------------
/// Passthrough interface stub
//------------------------------------------------------------------
@ -455,26 +488,42 @@ private:
/// Allocations made by the JIT are first queued up and then applied in
/// bulk to the underlying process.
//----------------------------------------------------------------------
enum class AllocationKind {
Stub, Code, Data, Global, Bytes
};
static lldb::SectionType
GetSectionTypeFromSectionName (const llvm::StringRef &name,
AllocationKind alloc_kind);
struct AllocationRecord {
lldb::addr_t m_process_address;
uintptr_t m_host_address;
uint32_t m_permissions;
size_t m_size;
unsigned m_alignment;
unsigned m_section_id;
std::string m_name;
lldb::addr_t m_process_address;
uintptr_t m_host_address;
uint32_t m_permissions;
lldb::SectionType m_sect_type;
size_t m_size;
unsigned m_alignment;
unsigned m_section_id;
AllocationRecord (uintptr_t host_address,
uint32_t permissions,
lldb::SectionType sect_type,
size_t size,
unsigned alignment,
unsigned section_id = eSectionIDInvalid) :
unsigned section_id,
const char *name) :
m_name (),
m_process_address(LLDB_INVALID_ADDRESS),
m_host_address(host_address),
m_permissions(permissions),
m_sect_type (sect_type),
m_size(size),
m_alignment(alignment),
m_section_id(section_id)
{
if (name && name[0])
m_name = name;
}
void dump (Log *log);

View File

@ -61,6 +61,12 @@ namespace lldb_private {
class IRForTarget : public llvm::ModulePass
{
public:
enum class LookupResult {
Success,
Fail,
Ignore
};
//------------------------------------------------------------------
/// Constructor
///
@ -201,7 +207,7 @@ private:
/// @return
/// The pointer.
//------------------------------------------------------------------
bool
LookupResult
GetFunctionAddress (llvm::Function *function,
uint64_t &ptr,
lldb_private::ConstString &name,

View File

@ -66,7 +66,7 @@ public:
uint32_t GetAddressByteSize();
// This function can return NULL.
ExecutionContextScope *GetBestExecutionContextScope();
ExecutionContextScope *GetBestExecutionContextScope() const;
protected:
// This function should only be used if you know you are using the JIT.

View File

@ -538,6 +538,9 @@ public:
static Error
MakeDirectory (const char* path, uint32_t mode);
static Error
RemoveDirectory (const char* path, bool recurse);
static Error
GetFilePermissions (const char* path, uint32_t &file_permissions);

View File

@ -21,6 +21,36 @@
#include "lldb/Symbol/UnwindTable.h"
namespace lldb_private {
class ObjectFileJITDelegate
{
public:
ObjectFileJITDelegate ()
{
}
virtual
~ObjectFileJITDelegate()
{
}
virtual lldb::ByteOrder
GetByteOrder () const = 0;
virtual uint32_t
GetAddressByteSize () const = 0;
virtual void
PopulateSymtab (lldb_private::ObjectFile *obj_file,
lldb_private::Symtab &symtab) = 0;
virtual void
PopulateSectionList (lldb_private::ObjectFile *obj_file,
lldb_private::SectionList &section_list) = 0;
virtual bool
GetArchitecture (lldb_private::ArchSpec &arch) = 0;
};
//----------------------------------------------------------------------
/// @class ObjectFile ObjectFile.h "lldb/Symbol/ObjectFile.h"
@ -68,6 +98,7 @@ public:
eTypeObjectFile, /// An intermediate object file
eTypeSharedLibrary, /// A shared library that can be used during execution
eTypeStubLibrary, /// A library that can be linked against but not used for execution
eTypeJIT, /// JIT code that has symbols, sections and possibly debug info
eTypeUnknown
} Type;
@ -77,7 +108,8 @@ public:
eStrataUnknown,
eStrataUser,
eStrataKernel,
eStrataRawImage
eStrataRawImage,
eStrataJIT
} Strata;
//------------------------------------------------------------------
@ -91,7 +123,7 @@ public:
const FileSpec *file_spec_ptr,
lldb::offset_t file_offset,
lldb::offset_t length,
lldb::DataBufferSP& data_sp,
const lldb::DataBufferSP& data_sp,
lldb::offset_t data_offset);
ObjectFile (const lldb::ModuleSP &module_sp,
@ -756,12 +788,12 @@ public:
size_t
CopyData (off_t offset, size_t length, void *dst) const;
size_t
virtual size_t
ReadSectionData (const Section *section,
off_t section_offset,
void *dst,
size_t dst_len) const;
size_t
virtual size_t
ReadSectionData (const Section *section,
DataExtractor& section_data) const;

View File

@ -201,6 +201,7 @@ public:
m_stop_others(true),
m_debug(false),
m_trap_exceptions(true),
m_generate_debug_info(false),
m_use_dynamic(lldb::eNoDynamicValues),
m_timeout_usec(default_timeout)
{}
@ -335,6 +336,20 @@ public:
SetDebug(bool b)
{
m_debug = b;
if (m_debug)
m_generate_debug_info = true;
}
bool
GetGenerateDebugInfo() const
{
return m_generate_debug_info;
}
void
SetGenerateDebugInfo(bool b)
{
m_generate_debug_info = b;
}
bool
@ -360,6 +375,7 @@ private:
bool m_stop_others;
bool m_debug;
bool m_trap_exceptions;
bool m_generate_debug_info;
lldb::DynamicValueType m_use_dynamic;
uint32_t m_timeout_usec;
};

View File

@ -128,6 +128,7 @@ class OptionGroup;
class OptionGroupOptions;
class OptionGroupPlatform;
class ObjectFile;
class ObjectFileJITDelegate;
class OperatingSystem;
class Options;
class OptionValue;
@ -316,6 +317,8 @@ namespace lldb {
typedef std::weak_ptr<lldb_private::Module> ModuleWP;
typedef std::shared_ptr<lldb_private::ObjectFile> ObjectFileSP;
typedef std::weak_ptr<lldb_private::ObjectFile> ObjectFileWP;
typedef std::shared_ptr<lldb_private::ObjectFileJITDelegate> ObjectFileJITDelegateSP;
typedef std::weak_ptr<lldb_private::ObjectFileJITDelegate> ObjectFileJITDelegateWP;
typedef std::shared_ptr<lldb_private::OptionValue> OptionValueSP;
typedef std::weak_ptr<lldb_private::OptionValue> OptionValueWP;
typedef std::shared_ptr<lldb_private::OptionValueArch> OptionValueArchSP;

View File

@ -118,7 +118,7 @@ typedef enum PathType
ePathTypePythonDir, // Find Python modules (PYTHONPATH) directory
ePathTypeLLDBSystemPlugins, // System plug-ins directory
ePathTypeLLDBUserPlugins, // User plug-ins directory
ePathTypeLLDBTempSystemDir // The LLDB temp directory for this system
ePathTypeLLDBTempSystemDir // The LLDB temp directory for this system that will be cleaned up on exit
} PathType;

View File

@ -542,6 +542,8 @@
26E152261419CAD4007967D0 /* ObjectFilePECOFF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26E152231419CACA007967D0 /* ObjectFilePECOFF.cpp */; };
26ECA04313665FED008D1F18 /* ARM_DWARF_Registers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26ECA04213665FED008D1F18 /* ARM_DWARF_Registers.cpp */; };
26ED3D6D13C563810017D45E /* OptionGroupVariable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26ED3D6C13C563810017D45E /* OptionGroupVariable.cpp */; };
26EFC4CD18CFAF0D00865D87 /* ObjectFileJIT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26EFC4CA18CFAF0D00865D87 /* ObjectFileJIT.cpp */; };
26EFC4CE18CFAF0D00865D87 /* ObjectFileJIT.h in Headers */ = {isa = PBXBuildFile; fileRef = 26EFC4CB18CFAF0D00865D87 /* ObjectFileJIT.h */; };
26F4A21C13FBA31A0064B613 /* ThreadMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F4A21A13FBA31A0064B613 /* ThreadMemory.cpp */; };
26F5C27710F3D9E4009D5894 /* Driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F5C27310F3D9E4009D5894 /* Driver.cpp */; };
26F5C32D10F3DFDD009D5894 /* libtermcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C32B10F3DFDD009D5894 /* libtermcap.dylib */; };
@ -1593,6 +1595,8 @@
26ECA04213665FED008D1F18 /* ARM_DWARF_Registers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ARM_DWARF_Registers.cpp; path = source/Utility/ARM_DWARF_Registers.cpp; sourceTree = "<group>"; };
26ED3D6C13C563810017D45E /* OptionGroupVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OptionGroupVariable.cpp; path = source/Interpreter/OptionGroupVariable.cpp; sourceTree = "<group>"; };
26ED3D6F13C5638A0017D45E /* OptionGroupVariable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OptionGroupVariable.h; path = include/lldb/Interpreter/OptionGroupVariable.h; sourceTree = "<group>"; };
26EFC4CA18CFAF0D00865D87 /* ObjectFileJIT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectFileJIT.cpp; sourceTree = "<group>"; };
26EFC4CB18CFAF0D00865D87 /* ObjectFileJIT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectFileJIT.h; sourceTree = "<group>"; };
26F4A21A13FBA31A0064B613 /* ThreadMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadMemory.cpp; path = Utility/ThreadMemory.cpp; sourceTree = "<group>"; };
26F4A21B13FBA31A0064B613 /* ThreadMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadMemory.h; path = Utility/ThreadMemory.h; sourceTree = "<group>"; };
26F5C26A10F3D9A4009D5894 /* lldb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lldb; sourceTree = BUILT_PRODUCTS_DIR; };
@ -2184,6 +2188,7 @@
isa = PBXGroup;
children = (
260C898310F57C5600BB2B04 /* ELF */,
26EFC4C718CFAF0D00865D87 /* JIT */,
260C898710F57C5600BB2B04 /* Mach-O */,
26E152221419CACA007967D0 /* PECOFF */,
);
@ -3582,6 +3587,15 @@
path = PECOFF;
sourceTree = "<group>";
};
26EFC4C718CFAF0D00865D87 /* JIT */ = {
isa = PBXGroup;
children = (
26EFC4CA18CFAF0D00865D87 /* ObjectFileJIT.cpp */,
26EFC4CB18CFAF0D00865D87 /* ObjectFileJIT.h */,
);
path = JIT;
sourceTree = "<group>";
};
26F5C22410F3D950009D5894 /* Tools */ = {
isa = PBXGroup;
children = (
@ -3973,6 +3987,7 @@
26474CCE18D0CB5B0073DEBA /* RegisterContextPOSIX_x86.h in Headers */,
26474CAD18D0CB070073DEBA /* RegisterContextFreeBSD_x86_64.h in Headers */,
490A36C2180F0E9300BA31F8 /* PlatformWindows.h in Headers */,
26EFC4CE18CFAF0D00865D87 /* ObjectFileJIT.h in Headers */,
260CC63615D04377002BF2E0 /* OptionValueFormat.h in Headers */,
26D1804516CEE12500EDFB5B /* KQueue.h in Headers */,
260CC63715D04377002BF2E0 /* OptionValueSInt64.h in Headers */,
@ -4759,6 +4774,7 @@
49A71FE7141FFA5C00D59478 /* IRInterpreter.cpp in Sources */,
49A71FE8141FFACF00D59478 /* DataEncoder.cpp in Sources */,
B207C4931429607D00F36E4E /* CommandObjectWatchpoint.cpp in Sources */,
26EFC4CD18CFAF0D00865D87 /* ObjectFileJIT.cpp in Sources */,
49A1CAC51430E8DE00306AC9 /* ExpressionSourceCode.cpp in Sources */,
494260DA14579144003C1C78 /* VerifyDecl.cpp in Sources */,
49DA65031485C92A005FF180 /* AppleObjCTypeVendor.cpp in Sources */,

View File

@ -289,7 +289,8 @@ BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error)
if (!m_user_expression_sp->Parse(errors,
exe_ctx,
eExecutionPolicyOnlyWhenNeeded,
true))
true,
false))
{
error.SetErrorStringWithFormat("Couldn't parse conditional expression:\n%s",
errors.GetData());

View File

@ -288,6 +288,12 @@ CommandObjectExpression::EvaluateExpression
options.SetTryAllThreads(m_command_options.try_all_threads);
options.SetDebug(m_command_options.debug);
// If there is any chance we are going to stop and want to see
// what went wrong with our expression, we should generate debug info
if (!m_command_options.ignore_breakpoints ||
!m_command_options.unwind_on_error)
options.SetGenerateDebugInfo(true);
if (m_command_options.timeout > 0)
options.SetTimeoutUsec(m_command_options.timeout);
else

View File

@ -37,6 +37,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Symbol/SymbolFile.h"
#include "Plugins/ObjectFile/JIT/ObjectFileJIT.h"
using namespace lldb;
using namespace lldb_private;
@ -145,6 +147,7 @@ Module::Module (const ModuleSpec &module_spec) :
m_symfile_ap (),
m_ast (),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
m_did_load_symbol_vendor (false),
m_did_parse_uuid (false),
@ -219,6 +222,7 @@ Module::Module(const FileSpec& file_spec,
m_symfile_ap (),
m_ast (),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
m_did_load_symbol_vendor (false),
m_did_parse_uuid (false),
@ -250,6 +254,35 @@ Module::Module(const FileSpec& file_spec,
m_object_name.IsEmpty() ? "" : ")");
}
Module::Module () :
m_mutex (Mutex::eMutexTypeRecursive),
m_mod_time (),
m_arch (),
m_uuid (),
m_file (),
m_platform_file(),
m_remote_install_file (),
m_symfile_spec (),
m_object_name (),
m_object_offset (0),
m_object_mod_time (),
m_objfile_sp (),
m_symfile_ap (),
m_ast (),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
m_did_load_symbol_vendor (false),
m_did_parse_uuid (false),
m_did_init_ast (false),
m_is_dynamic_loader_module (false),
m_file_has_changed (false),
m_first_file_changed_log (false)
{
Mutex::Locker locker (GetAllocationModuleCollectionMutex());
GetModuleCollection().push_back(this);
}
Module::~Module()
{
// Lock our module down while we tear everything down to make sure
@ -1722,3 +1755,27 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
match_name_after_lookup = false;
}
}
ModuleSP
Module::CreateJITModule (const lldb::ObjectFileJITDelegateSP &delegate_sp)
{
if (delegate_sp)
{
// Must create a module and place it into a shared pointer before
// we can create an object file since it has a std::weak_ptr back
// to the module, so we need to control the creation carefully in
// this static function
ModuleSP module_sp(new Module());
module_sp->m_objfile_sp.reset (new ObjectFileJIT (module_sp, delegate_sp));
if (module_sp->m_objfile_sp)
{
// Once we get the object file, update our module with the object file's
// architecture since it might differ in vendor/os if some parts were
// unknown.
module_sp->m_objfile_sp->GetArchitecture (module_sp->m_arch);
}
return module_sp;
}
return ModuleSP();
}

View File

@ -15,6 +15,7 @@
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
@ -24,6 +25,8 @@
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Expression/IRInterpreter.h"
#include "lldb/Host/File.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
@ -93,7 +96,8 @@ std::string GetBuiltinIncludePath(const char *Argv0) {
//===----------------------------------------------------------------------===//
ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
ClangExpression &expr) :
ClangExpression &expr,
bool generate_debug_info) :
m_expr (expr),
m_compiler (),
m_code_generator ()
@ -228,6 +232,10 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
m_compiler->getCodeGenOpts().InstrumentFunctions = false;
m_compiler->getCodeGenOpts().DisableFPElim = true;
m_compiler->getCodeGenOpts().OmitLeafFramePointer = false;
if (generate_debug_info)
m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::FullDebugInfo);
else
m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::NoDebugInfo);
// Disable some warnings.
m_compiler->getDiagnostics().setDiagnosticGroupMapping("unused-value", clang::diag::MAP_IGNORE, SourceLocation());
@ -299,8 +307,48 @@ ClangExpressionParser::Parse (Stream &stream)
diag_buf->FlushDiagnostics (m_compiler->getDiagnostics());
MemoryBuffer *memory_buffer = MemoryBuffer::getMemBufferCopy(m_expr.Text(), __FUNCTION__);
m_compiler->getSourceManager().createMainFileIDForMemBuffer (memory_buffer);
const char *expr_text = m_expr.Text();
bool created_main_file = false;
if (m_compiler->getCodeGenOpts().getDebugInfo() == CodeGenOptions::FullDebugInfo)
{
std::string temp_source_path;
FileSpec tmpdir_file_spec;
if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
{
tmpdir_file_spec.GetFilename().SetCString("expr.XXXXXX");
temp_source_path = std::move(tmpdir_file_spec.GetPath());
}
else
{
temp_source_path = "/tmp/expr.XXXXXX";
}
if (mktemp(&temp_source_path[0]))
{
lldb_private::File file (temp_source_path.c_str(),
File::eOpenOptionWrite | File::eOpenOptionCanCreateNewOnly,
lldb::eFilePermissionsFileDefault);
const size_t expr_text_len = strlen(expr_text);
size_t bytes_written = expr_text_len;
if (file.Write(expr_text, bytes_written).Success())
{
if (bytes_written == expr_text_len)
{
file.Close();
m_compiler->getSourceManager().createMainFileID(m_file_manager->getFile(temp_source_path));
created_main_file = true;
}
}
}
}
if (!created_main_file)
{
MemoryBuffer *memory_buffer = MemoryBuffer::getMemBufferCopy(expr_text, __FUNCTION__);
m_compiler->getSourceManager().createMainFileIDForMemBuffer (memory_buffer);
}
diag_buf->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor());
@ -370,7 +418,7 @@ static bool FindFunctionInModule (ConstString &mangled_name,
Error
ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
lldb::addr_t &func_end,
std::unique_ptr<IRExecutionUnit> &execution_unit_ap,
std::shared_ptr<IRExecutionUnit> &execution_unit_sp,
ExecutionContext &exe_ctx,
bool &can_interpret,
ExecutionPolicy execution_policy)
@ -379,13 +427,11 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
func_end = LLDB_INVALID_ADDRESS;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
std::unique_ptr<llvm::ExecutionEngine> execution_engine_ap;
Error err;
std::unique_ptr<llvm::Module> module_ap (m_code_generator->ReleaseModule());
std::unique_ptr<llvm::Module> llvm_module_ap (m_code_generator->ReleaseModule());
if (!module_ap.get())
if (!llvm_module_ap.get())
{
err.SetErrorToGenericError();
err.SetErrorString("IR doesn't contain a module");
@ -396,7 +442,7 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
ConstString function_name;
if (!FindFunctionInModule(function_name, module_ap.get(), m_expr.FunctionName()))
if (!FindFunctionInModule(function_name, llvm_module_ap.get(), m_expr.FunctionName()))
{
err.SetErrorToGenericError();
err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName());
@ -408,12 +454,12 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
log->Printf("Found function %s for %s", function_name.AsCString(), m_expr.FunctionName());
}
m_execution_unit.reset(new IRExecutionUnit(m_llvm_context, // handed off here
module_ap, // handed off here
function_name,
exe_ctx.GetTargetSP(),
m_compiler->getTargetOpts().Features));
execution_unit_sp.reset(new IRExecutionUnit (m_llvm_context, // handed off here
llvm_module_ap, // handed off here
function_name,
exe_ctx.GetTargetSP(),
m_compiler->getTargetOpts().Features));
ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); // result can be NULL
if (decl_map)
@ -425,15 +471,15 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
IRForTarget ir_for_target(decl_map,
m_expr.NeedsVariableResolution(),
*m_execution_unit,
*execution_unit_sp,
error_stream,
function_name.AsCString());
bool ir_can_run = ir_for_target.runOnModule(*m_execution_unit->GetModule());
bool ir_can_run = ir_for_target.runOnModule(*execution_unit_sp->GetModule());
Error interpret_error;
can_interpret = IRInterpreter::CanInterpret(*m_execution_unit->GetModule(), *m_execution_unit->GetFunction(), interpret_error);
can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error);
Process *process = exe_ctx.GetProcessPtr();
@ -483,7 +529,7 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString());
if (!ir_dynamic_checks.runOnModule(*m_execution_unit->GetModule()))
if (!ir_dynamic_checks.runOnModule(*execution_unit_sp->GetModule()))
{
err.SetErrorToGenericError();
err.SetErrorString("Couldn't add dynamic checks to the expression");
@ -491,15 +537,21 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
}
}
m_execution_unit->GetRunnableInfo(err, func_addr, func_end);
execution_unit_sp->GetRunnableInfo(err, func_addr, func_end);
}
}
else
{
m_execution_unit->GetRunnableInfo(err, func_addr, func_end);
execution_unit_sp->GetRunnableInfo(err, func_addr, func_end);
}
execution_unit_ap.reset (m_execution_unit.release());
return err;
}
bool
ClangExpressionParser::GetGenerateDebugInfo () const
{
if (m_compiler)
return m_compiler->getCodeGenOpts().getDebugInfo() == CodeGenOptions::FullDebugInfo;
return false;
}

View File

@ -22,18 +22,20 @@
#include "llvm/IR/Module.h"
// Project includes
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/State.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectList.h"
#include "lldb/Expression/ASTStructExtractor.h"
#include "lldb/Expression/ClangExpressionParser.h"
#include "lldb/Expression/ClangFunction.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/State.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectList.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@ -41,7 +43,6 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Core/Log.h"
using namespace lldb_private;
@ -55,6 +56,9 @@ ClangFunction::ClangFunction
const Address& functionAddress,
const ValueList &arg_value_list
) :
m_parser(),
m_execution_unit_sp(),
m_jit_module_wp(),
m_function_ptr (NULL),
m_function_addr (functionAddress),
m_function_return_type(return_type),
@ -87,7 +91,7 @@ ClangFunction::ClangFunction
m_compiled (false),
m_JITted (false)
{
m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess());
m_jit_process_wp = exe_scope.CalculateProcess();
// Can't make a ClangFunction without a process.
assert (m_jit_process_wp.lock());
@ -100,6 +104,13 @@ ClangFunction::ClangFunction
//----------------------------------------------------------------------
ClangFunction::~ClangFunction()
{
lldb::ProcessSP process_sp (m_jit_process_wp.lock());
if (process_sp)
{
lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock());
if (jit_module_sp)
process_sp->GetTarget().GetImages().Remove(jit_module_sp);
}
}
unsigned
@ -222,7 +233,8 @@ ClangFunction::CompileFunction (Stream &errors)
lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
if (jit_process_sp)
{
m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this));
const bool generate_debug_info = true;
m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this, generate_debug_info));
num_errors = m_parser->Parse (errors);
}
@ -263,7 +275,7 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
Error jit_error (m_parser->PrepareForExecution (m_jit_start_addr,
m_jit_end_addr,
m_execution_unit_ap,
m_execution_unit_sp,
exe_ctx,
can_interpret,
eExecutionPolicyAlways));
@ -271,8 +283,22 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
if (!jit_error.Success())
return false;
if (m_parser->GetGenerateDebugInfo())
{
lldb::ModuleSP jit_module_sp ( m_execution_unit_sp->GetJITModule());
if (jit_module_sp)
{
ConstString const_func_name(FunctionName());
FileSpec jit_file;
jit_file.GetFilename() = const_func_name;
jit_module_sp->SetFileSpecAndObjectName (jit_file, ConstString());
m_jit_module_wp = jit_module_sp;
process->GetTarget().GetImages().Append(jit_module_sp);
}
}
if (process && m_jit_start_addr)
m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
m_jit_process_wp = process->shared_from_this();
m_JITted = true;

View File

@ -20,6 +20,7 @@
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectConstResult.h"
@ -36,6 +37,8 @@
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
#include "lldb/Symbol/VariableList.h"
@ -63,6 +66,11 @@ ClangUserExpression::ClangUserExpression (const char *expr,
m_language (language),
m_transformed_text (),
m_desired_type (desired_type),
m_expr_decl_map(),
m_execution_unit_sp(),
m_materializer_ap(),
m_result_synthesizer(),
m_jit_module_wp(),
m_enforce_valid_object (true),
m_cplusplus (false),
m_objectivec (false),
@ -91,6 +99,12 @@ ClangUserExpression::ClangUserExpression (const char *expr,
ClangUserExpression::~ClangUserExpression ()
{
if (m_target)
{
lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock());
if (jit_module_sp)
m_target->GetImages().Remove(jit_module_sp);
}
}
clang::ASTConsumer *
@ -415,7 +429,8 @@ bool
ClangUserExpression::Parse (Stream &error_stream,
ExecutionContext &exe_ctx,
lldb_private::ExecutionPolicy execution_policy,
bool keep_result_in_memory)
bool keep_result_in_memory,
bool generate_debug_info)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -514,7 +529,7 @@ ClangUserExpression::Parse (Stream &error_stream,
if (!exe_scope)
exe_scope = exe_ctx.GetTargetPtr();
ClangExpressionParser parser(exe_scope, *this);
ClangExpressionParser parser(exe_scope, *this, generate_debug_info);
unsigned num_errors = parser.Parse (error_stream);
@ -533,11 +548,42 @@ ClangUserExpression::Parse (Stream &error_stream,
Error jit_error = parser.PrepareForExecution (m_jit_start_addr,
m_jit_end_addr,
m_execution_unit_ap,
m_execution_unit_sp,
exe_ctx,
m_can_interpret,
execution_policy);
if (generate_debug_info)
{
lldb::ModuleSP jit_module_sp ( m_execution_unit_sp->GetJITModule());
if (jit_module_sp)
{
ConstString const_func_name(FunctionName());
FileSpec jit_file;
jit_file.GetFilename() = const_func_name;
jit_module_sp->SetFileSpecAndObjectName (jit_file, ConstString());
m_jit_module_wp = jit_module_sp;
target->GetImages().Append(jit_module_sp);
}
// lldb_private::ObjectFile *jit_obj_file = jit_module_sp->GetObjectFile();
// StreamFile strm (stdout, false);
// if (jit_obj_file)
// {
// jit_obj_file->GetSectionList();
// jit_obj_file->GetSymtab();
// jit_obj_file->Dump(&strm);
// }
// lldb_private::SymbolVendor *jit_sym_vendor = jit_module_sp->GetSymbolVendor();
// if (jit_sym_vendor)
// {
// lldb_private::SymbolContextList sc_list;
// jit_sym_vendor->FindFunctions(const_func_name, NULL, lldb::eFunctionNameTypeFull, true, false, sc_list);
// sc_list.Dump(&strm, target);
// jit_sym_vendor->Dump(&strm);
// }
}
m_expr_decl_map.reset(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any ClangASTImporter::Minions.
if (jit_error.Success())
@ -667,7 +713,7 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
IRMemoryMap::AllocationPolicy policy = m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror;
m_materialized_address = m_execution_unit_ap->Malloc(m_materializer_ap->GetStructByteSize(),
m_materialized_address = m_execution_unit_sp->Malloc(m_materializer_ap->GetStructByteSize(),
m_materializer_ap->GetStructAlignment(),
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
policy,
@ -688,7 +734,7 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
const size_t stack_frame_size = 512 * 1024;
m_stack_frame_bottom = m_execution_unit_ap->Malloc(stack_frame_size,
m_stack_frame_bottom = m_execution_unit_sp->Malloc(stack_frame_size,
8,
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
IRMemoryMap::eAllocationPolicyHostOnly,
@ -705,7 +751,7 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
Error materialize_error;
m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_ap, struct_address, materialize_error);
m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_sp, struct_address, materialize_error);
if (!materialize_error.Success())
{
@ -781,8 +827,8 @@ ClangUserExpression::Execute (Stream &error_stream,
if (m_can_interpret)
{
llvm::Module *module = m_execution_unit_ap->GetModule();
llvm::Function *function = m_execution_unit_ap->GetFunction();
llvm::Module *module = m_execution_unit_sp->GetModule();
llvm::Function *function = m_execution_unit_sp->GetFunction();
if (!module || !function)
{
@ -810,7 +856,7 @@ ClangUserExpression::Execute (Stream &error_stream,
IRInterpreter::Interpret (*module,
*function,
args,
*m_execution_unit_ap.get(),
*m_execution_unit_sp.get(),
interpreter_error,
function_stack_bottom,
function_stack_top);
@ -965,8 +1011,13 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
log->Printf("== [ClangUserExpression::Evaluate] Parsing expression %s ==", expr_cstr);
const bool keep_expression_in_memory = true;
const bool generate_debug_info = options.GetGenerateDebugInfo();
if (!user_expression_sp->Parse (error_stream, exe_ctx, execution_policy, keep_expression_in_memory))
if (!user_expression_sp->Parse (error_stream,
exe_ctx,
execution_policy,
keep_expression_in_memory,
generate_debug_info))
{
if (error_stream.GetString().empty())
error.SetErrorString ("expression failed to parse, unknown error");

View File

@ -17,6 +17,7 @@
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Expression/ClangExpressionDeclMap.h"
@ -42,6 +43,9 @@ using namespace lldb_private;
ClangUtilityFunction::ClangUtilityFunction (const char *text,
const char *name) :
ClangExpression (),
m_expr_decl_map (),
m_execution_unit_sp (),
m_jit_module_wp (),
m_function_text (ExpressionSourceCode::g_expression_prefix),
m_function_name (name)
{
@ -51,6 +55,14 @@ ClangUtilityFunction::ClangUtilityFunction (const char *text,
ClangUtilityFunction::~ClangUtilityFunction ()
{
lldb::ProcessSP process_sp (m_jit_process_wp.lock());
if (process_sp)
{
lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock());
if (jit_module_sp)
process_sp->GetTarget().GetImages().Remove(jit_module_sp);
}
}
//------------------------------------------------------------------
@ -108,8 +120,9 @@ ClangUtilityFunction::Install (Stream &error_stream,
error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n");
return false;
}
ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this);
const bool generate_debug_info = true;
ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this, generate_debug_info);
unsigned num_errors = parser.Parse (error_stream);
@ -130,13 +143,29 @@ ClangUtilityFunction::Install (Stream &error_stream,
Error jit_error = parser.PrepareForExecution (m_jit_start_addr,
m_jit_end_addr,
m_execution_unit_ap,
m_execution_unit_sp,
exe_ctx,
can_interpret,
eExecutionPolicyAlways);
if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
{
m_jit_process_wp = process->shared_from_this();
if (parser.GetGenerateDebugInfo())
{
lldb::ModuleSP jit_module_sp ( m_execution_unit_sp->GetJITModule());
if (jit_module_sp)
{
ConstString const_func_name(FunctionName());
FileSpec jit_file;
jit_file.GetFilename() = const_func_name;
jit_module_sp->SetFileSpecAndObjectName (jit_file, ConstString());
m_jit_module_wp = jit_module_sp;
target->GetImages().Append(jit_module_sp);
}
}
}
#if 0
// jingham: look here

View File

@ -19,6 +19,8 @@
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
@ -333,6 +335,9 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
m_module_ap.release(); // ownership was transferred
}
// Make sure we see all sections, including ones that don't have relocations...
m_execution_engine_ap->setProcessAllSections(true);
m_execution_engine_ap->DisableLazyCompilation();
// We don't actually need the function pointer here, this just forces it to get resolved.
@ -433,6 +438,9 @@ IRExecutionUnit::MemoryManager::MemoryManager (IRExecutionUnit &parent) :
{
}
IRExecutionUnit::MemoryManager::~MemoryManager ()
{
}
void
IRExecutionUnit::MemoryManager::setMemoryWritable ()
{
@ -464,8 +472,11 @@ IRExecutionUnit::MemoryManager::allocateStub(const llvm::GlobalValue* F,
m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
GetSectionTypeFromSectionName (llvm::StringRef(), AllocationKind::Stub),
StubSize,
Alignment));
Alignment,
eSectionIDInvalid,
NULL));
if (log)
{
@ -484,6 +495,115 @@ IRExecutionUnit::MemoryManager::endFunctionBody(const llvm::Function *F,
m_default_mm_ap->endFunctionBody(F, FunctionStart, FunctionEnd);
}
lldb::SectionType
IRExecutionUnit::GetSectionTypeFromSectionName (const llvm::StringRef &name, IRExecutionUnit::AllocationKind alloc_kind)
{
lldb::SectionType sect_type = lldb::eSectionTypeCode;
switch (alloc_kind)
{
case AllocationKind::Stub: sect_type = lldb::eSectionTypeCode; break;
case AllocationKind::Code: sect_type = lldb::eSectionTypeCode; break;
case AllocationKind::Data: sect_type = lldb::eSectionTypeData; break;
case AllocationKind::Global:sect_type = lldb::eSectionTypeData; break;
case AllocationKind::Bytes: sect_type = lldb::eSectionTypeOther; break;
}
if (!name.empty())
{
if (name.equals("__text") || name.equals(".text"))
sect_type = lldb::eSectionTypeCode;
else if (name.equals("__data") || name.equals(".data"))
sect_type = lldb::eSectionTypeCode;
else if (name.startswith("__debug_") || name.startswith(".debug_"))
{
const uint32_t name_idx = name[0] == '_' ? 8 : 7;
llvm::StringRef dwarf_name(name.substr(name_idx));
switch (dwarf_name[0])
{
case 'a':
if (dwarf_name.equals("abbrev"))
sect_type = lldb::eSectionTypeDWARFDebugAbbrev;
else if (dwarf_name.equals("aranges"))
sect_type = lldb::eSectionTypeDWARFDebugAranges;
break;
case 'f':
if (dwarf_name.equals("frame"))
sect_type = lldb::eSectionTypeDWARFDebugFrame;
break;
case 'i':
if (dwarf_name.equals("info"))
sect_type = lldb::eSectionTypeDWARFDebugInfo;
break;
case 'l':
if (dwarf_name.equals("line"))
sect_type = lldb::eSectionTypeDWARFDebugLine;
else if (dwarf_name.equals("loc"))
sect_type = lldb::eSectionTypeDWARFDebugLoc;
break;
case 'm':
if (dwarf_name.equals("macinfo"))
sect_type = lldb::eSectionTypeDWARFDebugMacInfo;
break;
case 'p':
if (dwarf_name.equals("pubnames"))
sect_type = lldb::eSectionTypeDWARFDebugPubNames;
else if (dwarf_name.equals("pubtypes"))
sect_type = lldb::eSectionTypeDWARFDebugPubTypes;
break;
case 's':
if (dwarf_name.equals("str"))
sect_type = lldb::eSectionTypeDWARFDebugStr;
break;
case 'r':
if (dwarf_name.equals("ranges"))
sect_type = lldb::eSectionTypeDWARFDebugRanges;
break;
default:
break;
}
}
else if (name.startswith("__apple_") || name.startswith(".apple_"))
{
#if 0
const uint32_t name_idx = name[0] == '_' ? 8 : 7;
llvm::StringRef apple_name(name.substr(name_idx));
switch (apple_name[0])
{
case 'n':
if (apple_name.equals("names"))
sect_type = lldb::eSectionTypeDWARFAppleNames;
else if (apple_name.equals("namespac") || apple_name.equals("namespaces"))
sect_type = lldb::eSectionTypeDWARFAppleNamespaces;
break;
case 't':
if (apple_name.equals("types"))
sect_type = lldb::eSectionTypeDWARFAppleTypes;
break;
case 'o':
if (apple_name.equals("objc"))
sect_type = lldb::eSectionTypeDWARFAppleObjC;
break;
default:
break;
}
#else
sect_type = lldb::eSectionTypeInvalid;
#endif
}
else if (name.equals("__objc_imageinfo"))
sect_type = lldb::eSectionTypeOther;
}
return sect_type;
}
uint8_t *
IRExecutionUnit::MemoryManager::allocateSpace(intptr_t Size, unsigned Alignment)
{
@ -493,8 +613,11 @@ IRExecutionUnit::MemoryManager::allocateSpace(intptr_t Size, unsigned Alignment)
m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
GetSectionTypeFromSectionName (llvm::StringRef(), AllocationKind::Bytes),
Size,
Alignment));
Alignment,
eSectionIDInvalid,
NULL));
if (log)
{
@ -517,9 +640,11 @@ IRExecutionUnit::MemoryManager::allocateCodeSection(uintptr_t Size,
m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
lldb::ePermissionsReadable | lldb::ePermissionsExecutable,
GetSectionTypeFromSectionName (SectionName, AllocationKind::Code),
Size,
Alignment,
SectionID));
SectionID,
SectionName.str().c_str()));
if (log)
{
@ -542,10 +667,12 @@ IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size,
uint8_t *return_value = m_default_mm_ap->allocateDataSection(Size, Alignment, SectionID, SectionName, IsReadOnly);
m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
lldb::ePermissionsReadable | (IsReadOnly ? 0 : lldb::ePermissionsWritable),
GetSectionTypeFromSectionName (SectionName, AllocationKind::Data),
Size,
Alignment,
SectionID));
SectionID,
SectionName.str().c_str()));
if (log)
{
log->Printf("IRExecutionUnit::allocateDataSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p",
@ -565,8 +692,11 @@ IRExecutionUnit::MemoryManager::allocateGlobal(uintptr_t Size,
m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
GetSectionTypeFromSectionName (llvm::StringRef(), AllocationKind::Global),
Size,
Alignment));
Alignment,
eSectionIDInvalid,
NULL));
if (log)
{
@ -646,12 +776,34 @@ IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp)
if (record.m_process_address != LLDB_INVALID_ADDRESS)
continue;
record.m_process_address = Malloc(record.m_size,
record.m_alignment,
record.m_permissions,
eAllocationPolicyProcessOnly,
err);
switch (record.m_sect_type)
{
case lldb::eSectionTypeInvalid:
case lldb::eSectionTypeDWARFDebugAbbrev:
case lldb::eSectionTypeDWARFDebugAranges:
case lldb::eSectionTypeDWARFDebugFrame:
case lldb::eSectionTypeDWARFDebugInfo:
case lldb::eSectionTypeDWARFDebugLine:
case lldb::eSectionTypeDWARFDebugLoc:
case lldb::eSectionTypeDWARFDebugMacInfo:
case lldb::eSectionTypeDWARFDebugPubNames:
case lldb::eSectionTypeDWARFDebugPubTypes:
case lldb::eSectionTypeDWARFDebugRanges:
case lldb::eSectionTypeDWARFDebugStr:
case lldb::eSectionTypeDWARFAppleNames:
case lldb::eSectionTypeDWARFAppleTypes:
case lldb::eSectionTypeDWARFAppleNamespaces:
case lldb::eSectionTypeDWARFAppleObjC:
err.Clear();
break;
default:
record.m_process_address = Malloc (record.m_size,
record.m_alignment,
record.m_permissions,
eAllocationPolicyProcessOnly,
err);
break;
}
if (!err.Success())
{
@ -696,17 +848,18 @@ IRExecutionUnit::ReportAllocations (llvm::ExecutionEngine &engine)
bool
IRExecutionUnit::WriteData (lldb::ProcessSP &process_sp)
{
bool wrote_something = false;
for (AllocationRecord &record : m_records)
{
if (record.m_process_address == LLDB_INVALID_ADDRESS)
return false;
lldb_private::Error err;
WriteMemory (record.m_process_address, (uint8_t*)record.m_host_address, record.m_size, err);
if (record.m_process_address != LLDB_INVALID_ADDRESS)
{
lldb_private::Error err;
WriteMemory (record.m_process_address, (uint8_t*)record.m_host_address, record.m_size, err);
if (err.Success())
wrote_something = true;
}
}
return true;
return wrote_something;
}
void
@ -722,3 +875,79 @@ IRExecutionUnit::AllocationRecord::dump (Log *log)
(unsigned)m_alignment,
(unsigned)m_section_id);
}
lldb::ByteOrder
IRExecutionUnit::GetByteOrder () const
{
ExecutionContext exe_ctx (GetBestExecutionContextScope());
return exe_ctx.GetByteOrder();
}
uint32_t
IRExecutionUnit::GetAddressByteSize () const
{
ExecutionContext exe_ctx (GetBestExecutionContextScope());
return exe_ctx.GetAddressByteSize();
}
void
IRExecutionUnit::PopulateSymtab (lldb_private::ObjectFile *obj_file,
lldb_private::Symtab &symtab)
{
// No symbols yet...
}
void
IRExecutionUnit::PopulateSectionList (lldb_private::ObjectFile *obj_file,
lldb_private::SectionList &section_list)
{
for (AllocationRecord &record : m_records)
{
if (record.m_size > 0)
{
lldb::SectionSP section_sp (new lldb_private::Section (obj_file->GetModule(),
obj_file,
record.m_section_id,
ConstString(record.m_name),
record.m_sect_type,
record.m_process_address,
record.m_size,
record.m_host_address, // file_offset (which is the host address for the data)
record.m_size, // file_size
record.m_permissions)); // flags
section_list.AddSection (section_sp);
}
}
}
bool
IRExecutionUnit::GetArchitecture (lldb_private::ArchSpec &arch)
{
ExecutionContext exe_ctx (GetBestExecutionContextScope());
Target *target = exe_ctx.GetTargetPtr();
if (target)
arch = target->GetArchitecture();
else
arch.Clear();
return arch.IsValid();
}
lldb::ModuleSP
IRExecutionUnit::GetJITModule ()
{
ExecutionContext exe_ctx (GetBestExecutionContextScope());
Target *target = exe_ctx.GetTargetPtr();
if (target)
{
lldb::ModuleSP jit_module_sp = lldb_private::Module::CreateJITModule (std::static_pointer_cast<lldb_private::ObjectFileJITDelegate>(shared_from_this()));
if (jit_module_sp)
{
bool changed = false;
jit_module_sp->SetLoadAddress(*target, 0, true, changed);
}
return jit_module_sp;
}
return lldb::ModuleSP();
}

View File

@ -157,7 +157,7 @@ IRForTarget::FixFunctionLinkage(llvm::Function &llvm_function)
return true;
}
bool
IRForTarget::LookupResult
IRForTarget::GetFunctionAddress (llvm::Function *fun,
uint64_t &fun_addr,
lldb_private::ConstString &name,
@ -182,7 +182,7 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Call to unhandled compiler intrinsic '%s'\n", Intrinsic::getName(intrinsic_id).c_str());
return false;
return LookupResult::Fail;
case Intrinsic::memcpy:
{
static lldb_private::ConstString g_memcpy_str ("memcpy");
@ -195,6 +195,8 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
name = g_memset_str;
}
break;
case Intrinsic::dbg_declare:
return LookupResult::Ignore;
}
if (log && name)
@ -258,7 +260,7 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
m_error_stream->Printf("error: call to a function '%s' that is not present in the target\n",
mangled_name.GetName().GetCString());
}
return false;
return LookupResult::Fail;
}
}
}
@ -272,14 +274,14 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
if (m_error_stream)
m_error_stream->Printf("Error [IRForTarget]: Call to a symbol-only function '%s' that is not present in the target\n", name.GetCString());
return false;
return LookupResult::Fail;
}
}
if (log)
log->Printf("Found \"%s\" at 0x%" PRIx64, name.GetCString(), fun_addr);
return true;
return LookupResult::Success;
}
llvm::Constant *
@ -339,34 +341,46 @@ IRForTarget::ResolveFunctionPointers(llvm::Module &llvm_module)
lldb_private::ConstString name;
Constant **value_ptr = NULL;
if (!GetFunctionAddress(fun,
addr,
name,
value_ptr))
LookupResult result = GetFunctionAddress(fun,
addr,
name,
value_ptr);
switch (result)
{
case LookupResult::Fail:
return false; // GetFunctionAddress reports its own errors
Constant *value = BuildFunctionPointer(fun->getFunctionType(), addr);
RegisterFunctionMetadata (llvm_module.getContext(), fun, name.AsCString());
if (value_ptr)
*value_ptr = value;
case LookupResult::Ignore:
break; // Nothing to do
case LookupResult::Success:
{
Constant *value = BuildFunctionPointer(fun->getFunctionType(), addr);
RegisterFunctionMetadata (llvm_module.getContext(), fun, name.AsCString());
if (value_ptr)
*value_ptr = value;
// If we are replacing a function with the nobuiltin attribute, it may
// be called with the builtin attribute on call sites. Remove any such
// attributes since it's illegal to have a builtin call to something
// other than a nobuiltin function.
if (fun->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
llvm::Attribute builtin = llvm::Attribute::get(fun->getContext(), llvm::Attribute::Builtin);
// If we are replacing a function with the nobuiltin attribute, it may
// be called with the builtin attribute on call sites. Remove any such
// attributes since it's illegal to have a builtin call to something
// other than a nobuiltin function.
if (fun->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
llvm::Attribute builtin = llvm::Attribute::get(fun->getContext(), llvm::Attribute::Builtin);
for (auto u : fun->users()) {
if (auto call = dyn_cast<CallInst>(u)) {
call->removeAttribute(AttributeSet::FunctionIndex, builtin);
for (auto u : fun->users()) {
if (auto call = dyn_cast<CallInst>(u)) {
call->removeAttribute(AttributeSet::FunctionIndex, builtin);
}
}
}
fun->replaceAllUsesWith(value);
}
break;
}
fun->replaceAllUsesWith(value);
}
return true;

View File

@ -185,7 +185,7 @@ IRMemoryMap::GetAddressByteSize()
}
ExecutionContextScope *
IRMemoryMap::GetBestExecutionContextScope()
IRMemoryMap::GetBestExecutionContextScope() const
{
lldb::ProcessSP process_sp = m_process_wp.lock();

View File

@ -12,6 +12,7 @@
// C includes
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#ifdef _WIN32
#include "lldb/Host/windows/windows.h"
@ -1008,6 +1009,20 @@ Host::GetModuleFileSpecForHostAddress (const void *host_addr)
#endif
static void CleanupProcessSpecificLLDBTempDir ()
{
// Get the process specific LLDB temporary directory and delete it.
FileSpec tmpdir_file_spec;
if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
{
// Remove the LLDB temporary directory if we have one. Set "recurse" to
// true to all files that were created for the LLDB process can be cleaned up.
const bool recurse = true;
Host::RemoveDirectory(tmpdir_file_spec.GetDirectory().GetCString(), recurse);
}
}
bool
Host::GetLLDBPath (PathType path_type, FileSpec &file_spec)
{
@ -1279,9 +1294,22 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec)
}
if (tmpdir_cstr)
{
g_lldb_tmp_dir.SetCString(tmpdir_cstr);
if (log)
log->Printf("Host::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_lldb_tmp_dir.GetCString());
StreamString pid_tmpdir;
pid_tmpdir.Printf("%s/lldb", tmpdir_cstr);
if (Host::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success())
{
pid_tmpdir.Printf("/%" PRIu64, Host::GetCurrentProcessID());
if (Host::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success())
{
// Make an atexit handler to clean up the process specify LLDB temp dir
// and all of its contents.
::atexit (CleanupProcessSpecificLLDBTempDir);
g_lldb_tmp_dir.SetCString(pid_tmpdir.GetString().c_str());
if (log)
log->Printf("Host::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_lldb_tmp_dir.GetCString());
}
}
}
}
file_spec.GetDirectory() = g_lldb_tmp_dir;
@ -2141,6 +2169,14 @@ Host::Unlink (const char *path)
return error;
}
Error
Host::RemoveDirectory (const char* path, bool recurse)
{
Error error;
error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
return error;
}
#else
Error
@ -2189,6 +2225,33 @@ Host::MakeDirectory (const char* path, uint32_t file_permissions)
}
return error;
}
Error
Host::RemoveDirectory (const char* path, bool recurse)
{
Error error;
if (path && path[0])
{
if (recurse)
{
StreamString command;
command.Printf("rm -rf \"%s\"", path);
int status = ::system(command.GetString().c_str());
if (status != 0)
error.SetError(status, eErrorTypeGeneric);
}
else
{
if (::rmdir(path) != 0)
error.SetErrorToErrno();
}
}
else
{
error.SetErrorString("empty path");
}
return error;
}
Error
Host::GetFilePermissions (const char* path, uint32_t &file_permissions)

View File

@ -0,0 +1,5 @@
set(LLVM_NO_RTTI 1)
add_lldb_library(lldbPluginObjectFileJIT
ObjectFileJIT.cpp
)

View File

@ -0,0 +1,14 @@
##===- source/Plugins/ObjectFile/JIT/Makefile --------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LLDB_LEVEL := ../../../..
LIBRARYNAME := lldbPluginObjectFileJIT
BUILD_ARCHIVE = 1
include $(LLDB_LEVEL)/Makefile

View File

@ -0,0 +1,364 @@
//===-- ObjectFileJIT.cpp ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringRef.h"
#include "ObjectFileJIT.h"
#include "lldb/lldb-private-log.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/DataBuffer.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/FileSpecList.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RangeMap.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
#include "lldb/Core/UUID.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#ifndef __APPLE__
#include "Utility/UuidCompatibility.h"
#endif
using namespace lldb;
using namespace lldb_private;
void
ObjectFileJIT::Initialize()
{
PluginManager::RegisterPlugin (GetPluginNameStatic(),
GetPluginDescriptionStatic(),
CreateInstance,
CreateMemoryInstance,
GetModuleSpecifications);
}
void
ObjectFileJIT::Terminate()
{
PluginManager::UnregisterPlugin (CreateInstance);
}
lldb_private::ConstString
ObjectFileJIT::GetPluginNameStatic()
{
static ConstString g_name("jit");
return g_name;
}
const char *
ObjectFileJIT::GetPluginDescriptionStatic()
{
return "JIT code object file";
}
ObjectFile *
ObjectFileJIT::CreateInstance (const lldb::ModuleSP &module_sp,
DataBufferSP& data_sp,
lldb::offset_t data_offset,
const FileSpec* file,
lldb::offset_t file_offset,
lldb::offset_t length)
{
// JIT'ed object file is backed by the ObjectFileJITDelegate, never
// read from a file
return NULL;
}
ObjectFile *
ObjectFileJIT::CreateMemoryInstance (const lldb::ModuleSP &module_sp,
DataBufferSP& data_sp,
const ProcessSP &process_sp,
lldb::addr_t header_addr)
{
// JIT'ed object file is backed by the ObjectFileJITDelegate, never
// read from memory
return NULL;
}
size_t
ObjectFileJIT::GetModuleSpecifications (const lldb_private::FileSpec& file,
lldb::DataBufferSP& data_sp,
lldb::offset_t data_offset,
lldb::offset_t file_offset,
lldb::offset_t length,
lldb_private::ModuleSpecList &specs)
{
// JIT'ed object file can't be read from a file on disk
return 0;
}
ObjectFileJIT::ObjectFileJIT (const lldb::ModuleSP &module_sp,
const ObjectFileJITDelegateSP &delegate_sp) :
ObjectFile(module_sp, NULL, 0, 0, DataBufferSP(), 0),
m_delegate_wp ()
{
if (delegate_sp)
{
m_delegate_wp = delegate_sp;
m_data.SetByteOrder(delegate_sp->GetByteOrder());
m_data.SetAddressByteSize(delegate_sp->GetAddressByteSize());
}
}
ObjectFileJIT::~ObjectFileJIT()
{
}
bool
ObjectFileJIT::ParseHeader ()
{
// JIT code is never in a file, nor is it required to have any header
return false;
}
ByteOrder
ObjectFileJIT::GetByteOrder () const
{
return m_data.GetByteOrder();
}
bool
ObjectFileJIT::IsExecutable() const
{
return false;
}
uint32_t
ObjectFileJIT::GetAddressByteSize () const
{
return m_data.GetAddressByteSize();
}
Symtab *
ObjectFileJIT::GetSymtab()
{
ModuleSP module_sp(GetModule());
if (module_sp)
{
lldb_private::Mutex::Locker locker(module_sp->GetMutex());
if (m_symtab_ap.get() == NULL)
{
m_symtab_ap.reset(new Symtab(this));
Mutex::Locker symtab_locker (m_symtab_ap->GetMutex());
ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock());
if (delegate_sp)
delegate_sp->PopulateSymtab(this, *m_symtab_ap);
// TODO: get symbols from delegate
m_symtab_ap->Finalize ();
}
}
return m_symtab_ap.get();
}
bool
ObjectFileJIT::IsStripped ()
{
return false; // JIT code that is in a module is never stripped
}
void
ObjectFileJIT::CreateSections (SectionList &unified_section_list)
{
if (!m_sections_ap.get())
{
m_sections_ap.reset(new SectionList());
ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock());
if (delegate_sp)
{
delegate_sp->PopulateSectionList(this, *m_sections_ap);
unified_section_list = *m_sections_ap;
}
}
}
void
ObjectFileJIT::Dump (Stream *s)
{
ModuleSP module_sp(GetModule());
if (module_sp)
{
lldb_private::Mutex::Locker locker(module_sp->GetMutex());
s->Printf("%p: ", this);
s->Indent();
s->PutCString("ObjectFileJIT");
ArchSpec arch;
if (GetArchitecture(arch))
*s << ", arch = " << arch.GetArchitectureName();
s->EOL();
SectionList *sections = GetSectionList();
if (sections)
sections->Dump(s, NULL, true, UINT32_MAX);
if (m_symtab_ap.get())
m_symtab_ap->Dump(s, NULL, eSortOrderNone);
}
}
bool
ObjectFileJIT::GetUUID (lldb_private::UUID* uuid)
{
// TODO: maybe get from delegate, not needed for first pass
return false;
}
uint32_t
ObjectFileJIT::GetDependentModules (FileSpecList& files)
{
// JIT modules don't have dependencies, but they could
// if external functions are called and we know where they are
files.Clear();
return 0;
}
lldb_private::Address
ObjectFileJIT::GetEntryPointAddress ()
{
return Address();
}
lldb_private::Address
ObjectFileJIT::GetHeaderAddress ()
{
return Address();
}
ObjectFile::Type
ObjectFileJIT::CalculateType()
{
return eTypeJIT;
}
ObjectFile::Strata
ObjectFileJIT::CalculateStrata()
{
return eStrataJIT;
}
bool
ObjectFileJIT::GetArchitecture (ArchSpec &arch)
{
ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock());
if (delegate_sp)
return delegate_sp->GetArchitecture(arch);
return false;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
lldb_private::ConstString
ObjectFileJIT::GetPluginName()
{
return GetPluginNameStatic();
}
uint32_t
ObjectFileJIT::GetPluginVersion()
{
return 1;
}
bool
ObjectFileJIT::SetLoadAddress (Target &target,
lldb::addr_t value,
bool value_is_offset)
{
bool changed = false;
size_t num_loaded_sections = 0;
SectionList *section_list = GetSectionList ();
if (section_list)
{
const size_t num_sections = section_list->GetSize();
// "value" is an offset to apply to each top level segment
for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx)
{
// Iterate through the object file sections to find all
// of the sections that size on disk (to avoid __PAGEZERO)
// and load them
SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
if (section_sp &&
section_sp->GetFileSize() > 0 &&
section_sp->IsThreadSpecific() == false)
{
if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value))
++num_loaded_sections;
}
}
}
changed = num_loaded_sections > 0;
return num_loaded_sections > 0;
}
size_t
ObjectFileJIT::ReadSectionData (const lldb_private::Section *section,
off_t section_offset,
void *dst,
size_t dst_len) const
{
lldb::offset_t file_size = section->GetFileSize();
if (section_offset < file_size)
{
uint64_t src_len = file_size - section_offset;
if (src_len > dst_len)
src_len = dst_len;
const uint8_t *src = ((uint8_t *)(uintptr_t)section->GetFileOffset()) + section_offset;
memcpy (dst, src, src_len);
return src_len;
}
return 0;
}
size_t
ObjectFileJIT::ReadSectionData (const lldb_private::Section *section,
lldb_private::DataExtractor& section_data) const
{
if (section->GetFileSize())
{
const void *src = (void *)(uintptr_t)section->GetFileOffset();
DataBufferSP data_sp (new lldb_private::DataBufferHeap(src, section->GetFileSize()));
if (data_sp)
{
section_data.SetData (data_sp, 0, data_sp->GetByteSize());
section_data.SetByteOrder (GetByteOrder());
section_data.SetAddressByteSize (GetAddressByteSize());
return section_data.GetByteSize();
}
}
section_data.Clear();
return 0;
}

View File

@ -0,0 +1,142 @@
//===-- ObjectFileJIT.h -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ObjectFileJIT_h_
#define liblldb_ObjectFileJIT_h_
#include "lldb/Core/Address.h"
#include "lldb/Symbol/ObjectFile.h"
//----------------------------------------------------------------------
// This class needs to be hidden as eventually belongs in a plugin that
// will export the ObjectFile protocol
//----------------------------------------------------------------------
class ObjectFileJIT :
public lldb_private::ObjectFile
{
public:
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
static void
Initialize();
static void
Terminate();
static lldb_private::ConstString
GetPluginNameStatic();
static const char *
GetPluginDescriptionStatic();
static lldb_private::ObjectFile *
CreateInstance (const lldb::ModuleSP &module_sp,
lldb::DataBufferSP& data_sp,
lldb::offset_t data_offset,
const lldb_private::FileSpec* file,
lldb::offset_t file_offset,
lldb::offset_t length);
static lldb_private::ObjectFile *
CreateMemoryInstance (const lldb::ModuleSP &module_sp,
lldb::DataBufferSP& data_sp,
const lldb::ProcessSP &process_sp,
lldb::addr_t header_addr);
static size_t
GetModuleSpecifications (const lldb_private::FileSpec& file,
lldb::DataBufferSP& data_sp,
lldb::offset_t data_offset,
lldb::offset_t file_offset,
lldb::offset_t length,
lldb_private::ModuleSpecList &specs);
//------------------------------------------------------------------
// Member Functions
//------------------------------------------------------------------
ObjectFileJIT (const lldb::ModuleSP &module_sp,
const lldb::ObjectFileJITDelegateSP &delegate_sp);
virtual
~ObjectFileJIT();
virtual bool
ParseHeader ();
virtual bool
SetLoadAddress(lldb_private::Target &target,
lldb::addr_t value,
bool value_is_offset);
virtual lldb::ByteOrder
GetByteOrder () const;
virtual bool
IsExecutable () const;
virtual uint32_t
GetAddressByteSize () const;
virtual lldb_private::Symtab *
GetSymtab();
virtual bool
IsStripped ();
virtual void
CreateSections (lldb_private::SectionList &unified_section_list);
virtual void
Dump (lldb_private::Stream *s);
virtual bool
GetArchitecture (lldb_private::ArchSpec &arch);
virtual bool
GetUUID (lldb_private::UUID* uuid);
virtual uint32_t
GetDependentModules (lldb_private::FileSpecList& files);
virtual size_t
ReadSectionData (const lldb_private::Section *section,
off_t section_offset,
void *dst,
size_t dst_len) const;
virtual size_t
ReadSectionData (const lldb_private::Section *section,
lldb_private::DataExtractor& section_data) const;
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
virtual lldb_private::ConstString
GetPluginName();
virtual uint32_t
GetPluginVersion();
virtual lldb_private::Address
GetEntryPointAddress ();
virtual lldb_private::Address
GetHeaderAddress ();
virtual ObjectFile::Type
CalculateType();
virtual ObjectFile::Strata
CalculateStrata();
protected:
lldb::ObjectFileJITDelegateWP m_delegate_wp;
};
#endif // liblldb_ObjectFileJIT_h_

View File

@ -163,15 +163,17 @@ RegisterContextLLDB::InitializeZerothFrame()
UnwindLogMsg ("using architectural default unwind method");
}
// We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
// We require either a symbol or function in the symbols context to be successfully
// filled in or this context is of no use to us.
const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
if (pc_module_sp.get()
&& (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
&& (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, resolve_scope, m_sym_ctx) & resolve_scope))
{
m_sym_ctx_valid = true;
}
AddressRange addr_range;
m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range);
m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range);
if (IsTrapHandlerSymbol (process, m_sym_ctx))
{
@ -417,18 +419,20 @@ RegisterContextLLDB::InitializeNonZerothFrame()
// a function/symbol because it is beyond the bounds of the correct
// function and there's no symbol there. ResolveSymbolContextForAddress
// will fail to find a symbol, back up the pc by 1 and re-search.
const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc,
eSymbolContextFunction | eSymbolContextSymbol,
resolve_scope,
m_sym_ctx, resolve_tail_call_address);
// We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
if ((resolved_scope & eSymbolContextSymbol) == eSymbolContextSymbol)
// We require either a symbol or function in the symbols context to be successfully
// filled in or this context is of no use to us.
if (resolve_scope & resolved_scope)
{
m_sym_ctx_valid = true;
}
AddressRange addr_range;
if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
if (!m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range))
{
m_sym_ctx_valid = false;
}
@ -461,13 +465,12 @@ RegisterContextLLDB::InitializeNonZerothFrame()
temporary_pc.SetOffset(m_current_pc.GetOffset() - 1);
m_sym_ctx.Clear(false);
m_sym_ctx_valid = false;
if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
if (pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope)
{
m_sym_ctx_valid = true;
}
if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
{
m_sym_ctx_valid = false;
if (m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range))
m_sym_ctx_valid = true;
}
}
@ -707,7 +710,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// Note, if we have a symbol context & a symbol, we don't want to follow this code path. This is
// for jumping to memory regions without any information available.
if ((!m_sym_ctx_valid || m_sym_ctx.symbol == NULL) && behaves_like_zeroth_frame && m_current_pc.IsValid())
if ((!m_sym_ctx_valid || (m_sym_ctx.function == NULL && m_sym_ctx.symbol == NULL)) && behaves_like_zeroth_frame && m_current_pc.IsValid())
{
uint32_t permissions;
addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr());

View File

@ -244,6 +244,7 @@ ProcessGDBRemote::CanDebug (Target &target, bool plugin_specified_by_name)
case ObjectFile::eTypeObjectFile:
case ObjectFile::eTypeSharedLibrary:
case ObjectFile::eTypeStubLibrary:
case ObjectFile::eTypeJIT:
return false;
case ObjectFile::eTypeExecutable:
case ObjectFile::eTypeDynamicLinker:

View File

@ -341,6 +341,7 @@ SymbolFileDWARFDebugMap::InitOSO()
case ObjectFile::eTypeObjectFile:
case ObjectFile::eTypeStubLibrary:
case ObjectFile::eTypeUnknown:
case ObjectFile::eTypeJIT:
return;
case ObjectFile::eTypeExecutable:

View File

@ -239,7 +239,7 @@ ObjectFile::ObjectFile (const lldb::ModuleSP &module_sp,
const FileSpec *file_spec_ptr,
lldb::offset_t file_offset,
lldb::offset_t length,
lldb::DataBufferSP& data_sp,
const lldb::DataBufferSP& data_sp,
lldb::offset_t data_offset
) :
ModuleChild (module_sp),

View File

@ -1142,32 +1142,39 @@ void
Target::ModuleAdded (const ModuleList& module_list, const ModuleSP &module_sp)
{
// A module is being added to this target for the first time
ModuleList my_module_list;
my_module_list.Append(module_sp);
LoadScriptingResourceForModule(module_sp, this);
ModulesDidLoad (my_module_list);
if (m_valid)
{
ModuleList my_module_list;
my_module_list.Append(module_sp);
LoadScriptingResourceForModule(module_sp, this);
ModulesDidLoad (my_module_list);
}
}
void
Target::ModuleRemoved (const ModuleList& module_list, const ModuleSP &module_sp)
{
// A module is being added to this target for the first time
ModuleList my_module_list;
my_module_list.Append(module_sp);
ModulesDidUnload (my_module_list, false);
if (m_valid)
{
ModuleList my_module_list;
my_module_list.Append(module_sp);
ModulesDidUnload (my_module_list, false);
}
}
void
Target::ModuleUpdated (const ModuleList& module_list, const ModuleSP &old_module_sp, const ModuleSP &new_module_sp)
{
// A module is replacing an already added module
m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp);
if (m_valid)
m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp);
}
void
Target::ModulesDidLoad (ModuleList &module_list)
{
if (module_list.GetSize())
if (m_valid && module_list.GetSize())
{
m_breakpoint_list.UpdateBreakpoints (module_list, true, false);
if (m_process_sp)
@ -1182,7 +1189,7 @@ Target::ModulesDidLoad (ModuleList &module_list)
void
Target::SymbolsDidLoad (ModuleList &module_list)
{
if (module_list.GetSize())
if (m_valid && module_list.GetSize())
{
if (m_process_sp)
{
@ -1202,7 +1209,7 @@ Target::SymbolsDidLoad (ModuleList &module_list)
void
Target::ModulesDidUnload (ModuleList &module_list, bool delete_locations)
{
if (module_list.GetSize())
if (m_valid && module_list.GetSize())
{
m_breakpoint_list.UpdateBreakpoints (module_list, false, delete_locations);
// TODO: make event data that packages up the module_list