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 /lldb/source | |
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
Diffstat (limited to 'lldb/source')
20 files changed, 1192 insertions, 127 deletions
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 |