diff options
author | Greg Clayton <gclayton@apple.com> | 2014-03-24 23:10:19 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2014-03-24 23:10:19 +0000 |
commit | 23f8c95a4439767cf9c7dc9d7a35eb55dc78b9d0 (patch) | |
tree | 3e56f285be57acf15b3fb73195567727a329aca9 | |
parent | 2256d0dcedf887593ebfb35db860827e8682807e (diff) | |
download | bcm5719-llvm-23f8c95a4439767cf9c7dc9d7a35eb55dc78b9d0.tar.gz bcm5719-llvm-23f8c95a4439767cf9c7dc9d7a35eb55dc78b9d0.zip |
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
34 files changed, 1369 insertions, 168 deletions
diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 42904dd9eac..f6491db72bf 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -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, diff --git a/lldb/include/lldb/Expression/ClangExpressionParser.h b/lldb/include/lldb/Expression/ClangExpressionParser.h index 3247f2094ba..cb7a2c06993 100644 --- a/lldb/include/lldb/Expression/ClangExpressionParser.h +++ b/lldb/include/lldb/Expression/ClangExpressionParser.h @@ -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 }; } diff --git a/lldb/include/lldb/Expression/ClangFunction.h b/lldb/include/lldb/Expression/ClangFunction.h index e150d389b41..23540dd901b 100644 --- a/lldb/include/lldb/Expression/ClangFunction.h +++ b/lldb/include/lldb/Expression/ClangFunction.h @@ -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. diff --git a/lldb/include/lldb/Expression/ClangUserExpression.h b/lldb/include/lldb/Expression/ClangUserExpression.h index 83fdf1c2195..9121d147de4 100644 --- a/lldb/include/lldb/Expression/ClangUserExpression.h +++ b/lldb/include/lldb/Expression/ClangUserExpression.h @@ -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). diff --git a/lldb/include/lldb/Expression/ClangUtilityFunction.h b/lldb/include/lldb/Expression/ClangUtilityFunction.h index 6da8e5ec3a8..bb5601fa291 100644 --- a/lldb/include/lldb/Expression/ClangUtilityFunction.h +++ b/lldb/include/lldb/Expression/ClangUtilityFunction.h @@ -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 diff --git a/lldb/include/lldb/Expression/IRExecutionUnit.h b/lldb/include/lldb/Expression/IRExecutionUnit.h index 2820317e108..32ccfe7ca4a 100644 --- a/lldb/include/lldb/Expression/IRExecutionUnit.h +++ b/lldb/include/lldb/Expression/IRExecutionUnit.h @@ -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); + + //------------------------------------------------------------------ + /// ObjectFileJITDelegate overrides + //------------------------------------------------------------------ + virtual lldb::ByteOrder + GetByteOrder () const; - void FreeNow(lldb::addr_t allocation); + 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 §ion_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); diff --git a/lldb/include/lldb/Expression/IRForTarget.h b/lldb/include/lldb/Expression/IRForTarget.h index 502f796d15a..7eac13dda86 100644 --- a/lldb/include/lldb/Expression/IRForTarget.h +++ b/lldb/include/lldb/Expression/IRForTarget.h @@ -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, diff --git a/lldb/include/lldb/Expression/IRMemoryMap.h b/lldb/include/lldb/Expression/IRMemoryMap.h index affe19350e3..750ff684d78 100644 --- a/lldb/include/lldb/Expression/IRMemoryMap.h +++ b/lldb/include/lldb/Expression/IRMemoryMap.h @@ -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. diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h index 862b1ed7943..61c391b0129 100644 --- a/lldb/include/lldb/Host/Host.h +++ b/lldb/include/lldb/Host/Host.h @@ -539,6 +539,9 @@ public: 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); static Error diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index afa1f9b4090..cf17c3d5b15 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -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 §ion_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; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index e65a511ab77..85d283df391 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -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; }; diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index 6c522c1d9a9..f5539bc3062 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -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; diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h index c2273f5dfe2..d9b06820048 100644 --- a/lldb/include/lldb/lldb-private-enumerations.h +++ b/lldb/include/lldb/lldb-private-enumerations.h @@ -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; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 2a4479715ce..9eaff8b4991 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -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 */, diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp index fac0dcf05f3..f7b9dc6f3e7 100644 --- a/lldb/source/Breakpoint/BreakpointLocation.cpp +++ b/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -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()); diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index df97550c31b..2598f3f9fec 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -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 diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 588c3eacc11..e6f2daa76e7 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -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(); +} + diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp index ea3ff95f578..44f1e535ec7 100644 --- a/lldb/source/Expression/ClangExpressionParser.cpp +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -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; +} diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index f856f726696..a7e7ac01069 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -22,18 +22,20 @@ #include "llvm/IR/Module.h" // Project includes -#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/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/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; diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 2b9bd2cef50..4eefddda41a 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -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"); diff --git a/lldb/source/Expression/ClangUtilityFunction.cpp b/lldb/source/Expression/ClangUtilityFunction.cpp index c911c279993..de5b0c1b03f 100644 --- a/lldb/source/Expression/ClangUtilityFunction.cpp +++ b/lldb/source/Expression/ClangUtilityFunction.cpp @@ -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 diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 17bd03ae6cb..d50802ac956 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -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 §ion_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(); +} diff --git a/lldb/source/Expression/IRForTarget.cpp b/lldb/source/Expression/IRForTarget.cpp index 0ec3525a50e..a1fa6538e04 100644 --- a/lldb/source/Expression/IRForTarget.cpp +++ b/lldb/source/Expression/IRForTarget.cpp @@ -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)) - return false; // GetFunctionAddress reports its own errors + LookupResult result = GetFunctionAddress(fun, + addr, + name, + value_ptr); - 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); - - for (auto u : fun->users()) { - if (auto call = dyn_cast<CallInst>(u)) { - call->removeAttribute(AttributeSet::FunctionIndex, builtin); + switch (result) + { + case LookupResult::Fail: + return false; // GetFunctionAddress reports its own errors + + 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); + + 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; diff --git a/lldb/source/Expression/IRMemoryMap.cpp b/lldb/source/Expression/IRMemoryMap.cpp index f927e8b978b..7bc2ed034de 100644 --- a/lldb/source/Expression/IRMemoryMap.cpp +++ b/lldb/source/Expression/IRMemoryMap.cpp @@ -185,7 +185,7 @@ IRMemoryMap::GetAddressByteSize() } ExecutionContextScope * -IRMemoryMap::GetBestExecutionContextScope() +IRMemoryMap::GetBestExecutionContextScope() const { lldb::ProcessSP process_sp = m_process_wp.lock(); diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index eb45f4a82a5..e5a0f339e9d 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -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) diff --git a/lldb/source/Plugins/ObjectFile/JIT/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/JIT/CMakeLists.txt new file mode 100644 index 00000000000..1e87e1fba64 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/JIT/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_NO_RTTI 1) + +add_lldb_library(lldbPluginObjectFileJIT + ObjectFileJIT.cpp + ) diff --git a/lldb/source/Plugins/ObjectFile/JIT/Makefile b/lldb/source/Plugins/ObjectFile/JIT/Makefile new file mode 100644 index 00000000000..2af3521777a --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/JIT/Makefile @@ -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 diff --git a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp new file mode 100644 index 00000000000..530e11af22c --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp @@ -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; +} + diff --git a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h new file mode 100644 index 00000000000..3a0e2ad679b --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h @@ -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_ diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 2ab13d96707..fd0136d00b4 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -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()); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 4e34a9a09a0..59689860916 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -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: diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index c12dd621402..0cb2143711a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -341,6 +341,7 @@ SymbolFileDWARFDebugMap::InitOSO() case ObjectFile::eTypeObjectFile: case ObjectFile::eTypeStubLibrary: case ObjectFile::eTypeUnknown: + case ObjectFile::eTypeJIT: return; case ObjectFile::eTypeExecutable: diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp index ec69c9dd1e1..931433540c6 100644 --- a/lldb/source/Symbol/ObjectFile.cpp +++ b/lldb/source/Symbol/ObjectFile.cpp @@ -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), diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index d759801ae98..e9a8189814a 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -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 |