diff options
Diffstat (limited to 'lldb/source')
-rw-r--r-- | lldb/source/Commands/CommandObjectExpression.cpp | 250 | ||||
-rw-r--r-- | lldb/source/Expression/IRForTarget.cpp | 111 |
2 files changed, 252 insertions, 109 deletions
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 37659f5e697..56f97fb4027 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -270,122 +270,158 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream log->Printf("Code cannot be interpreted and must be run in the target."); success = clang_expr.PrepareIRForTarget (expr_local_vars); } + + if (!success) + { + error_stream.PutCString ("error: expression couldn't be converted to IR\n"); + return false; + } + + if (canInterpret) + { + // TODO interpret IR + return false; + } + else + { + if (!clang_expr.JITFunction (m_exe_ctx, "___clang_expr")) + { + error_stream.PutCString ("error: IR could not be JIT compiled\n"); + return false; + } + + if (!clang_expr.WriteJITCode (m_exe_ctx)) + { + error_stream.PutCString ("error: JIT code could not be written to the target\n"); + return false; + } + + lldb::addr_t function_address(clang_expr.GetFunctionAddress ("___clang_expr")); + + if (function_address == LLDB_INVALID_ADDRESS) + { + error_stream.PutCString ("JIT compiled code's address couldn't be found\n"); + return false; + } + + log->Printf("Function is at 0x%llx", (uint64_t)function_address); + } } else { success = (clang_expr.ConvertExpressionToDWARF (expr_local_vars, dwarf_opcodes) == 0); - } - - if (!success) - { - error_stream.PutCString ("error: expression couldn't be translated to DWARF\n"); - return false; - } - - ////////////////////////////////////////// - // Evaluate the generated DWARF opcodes - // - - DataExtractor dwarf_opcodes_data (dwarf_opcodes.GetData (), dwarf_opcodes.GetSize (), eByteOrderHost, 8); - DWARFExpression dwarf_expr (dwarf_opcodes_data, 0, dwarf_opcodes_data.GetByteSize (), NULL); - - dwarf_expr.SetExpressionLocalVariableList(&expr_local_vars); - - if (log) - { - StreamString stream_string; - log->PutCString ("Expression parsed ok, dwarf opcodes:"); + if (!success) + { + error_stream.PutCString ("error: expression couldn't be translated to DWARF\n"); + return false; + } - stream_string.PutCString ("\n"); - stream_string.IndentMore (); - dwarf_expr.GetDescription (&stream_string, lldb::eDescriptionLevelVerbose); - stream_string.IndentLess (); - stream_string.EOL (); + ////////////////////////////////////////// + // Evaluate the generated DWARF opcodes + // + + DataExtractor dwarf_opcodes_data (dwarf_opcodes.GetData (), dwarf_opcodes.GetSize (), eByteOrderHost, 8); + DWARFExpression dwarf_expr (dwarf_opcodes_data, 0, dwarf_opcodes_data.GetByteSize (), NULL); + + dwarf_expr.SetExpressionLocalVariableList(&expr_local_vars); + + if (log) + { + StreamString stream_string; + + log->PutCString ("Expression parsed ok, dwarf opcodes:"); + + stream_string.PutCString ("\n"); + stream_string.IndentMore (); + dwarf_expr.GetDescription (&stream_string, lldb::eDescriptionLevelVerbose); + stream_string.IndentLess (); + stream_string.EOL (); + + log->PutCString (stream_string.GetString ().c_str ()); + } + + clang::ASTContext *ast_context = clang_expr.GetASTContext (); + Value expr_result; + Error expr_error; + success = dwarf_expr.Evaluate (&m_exe_ctx, ast_context, NULL, expr_result, &expr_error); + + if (!success) + { + error_stream.Printf ("error: couldn't evaluate DWARF expression: %s\n", expr_error.AsCString ()); + return false; + } + + /////////////////////////////////////// + // Interpret the result and print it + // + + lldb::Format format = m_options.format; + + // Resolve any values that are possible + expr_result.ResolveValue (&m_exe_ctx, ast_context); + + if (expr_result.GetContextType () == Value::eContextTypeInvalid && + expr_result.GetValueType () == Value::eValueTypeScalar && + format == eFormatDefault) + { + // The expression result is just a scalar with no special formatting + expr_result.GetScalar ().GetValue (&output_stream, m_options.show_types); + output_stream.EOL (); + return true; + } + + // The expression result is more complext and requires special handling + DataExtractor data; + expr_error = expr_result.GetValueAsData (&m_exe_ctx, ast_context, data, 0); + + if (!expr_error.Success ()) + { + error_stream.Printf ("error: couldn't resolve result value: %s\n", expr_error.AsCString ()); + return false; + } + + if (format == eFormatDefault) + format = expr_result.GetValueDefaultFormat (); + + void *clang_type = expr_result.GetValueOpaqueClangQualType (); + + if (clang_type) + { + if (m_options.show_types) + Type::DumpClangTypeName (&output_stream, clang_type); + + Type::DumpValue (&m_exe_ctx, // The execution context for memory and variable access + ast_context, // The ASTContext that the clang type belongs to + clang_type, // The opaque clang type we want to dump that value of + &output_stream, // Stream to dump to + format, // Format to use when dumping + data, // A buffer containing the bytes for the clang type + 0, // Byte offset within "data" where value is + data.GetByteSize (), // Size in bytes of the value we are dumping + 0, // Bitfield bit size + 0, // Bitfield bit offset + m_options.show_types, // Show types? + m_options.show_summary, // Show summary? + m_options.debug, // Debug logging output? + UINT32_MAX); // Depth to dump in case this is an aggregate type + } + else + { + data.Dump (&output_stream, // Stream to dump to + 0, // Byte offset within "data" + format, // Format to use when dumping + data.GetByteSize (), // Size in bytes of each item we are dumping + 1, // Number of items to dump + UINT32_MAX, // Number of items per line + LLDB_INVALID_ADDRESS, // Invalid address, don't show any offset/address context + 0, // Bitfield bit size + 0); // Bitfield bit offset + } + output_stream.EOL(); - log->PutCString (stream_string.GetString ().c_str ()); - } - - clang::ASTContext *ast_context = clang_expr.GetASTContext (); - Value expr_result; - Error expr_error; - success = dwarf_expr.Evaluate (&m_exe_ctx, ast_context, NULL, expr_result, &expr_error); - - if (!success) - { - error_stream.Printf ("error: couldn't evaluate DWARF expression: %s\n", expr_error.AsCString ()); - return false; - } - - /////////////////////////////////////// - // Interpret the result and print it - // - - lldb::Format format = m_options.format; - - // Resolve any values that are possible - expr_result.ResolveValue (&m_exe_ctx, ast_context); - - if (expr_result.GetContextType () == Value::eContextTypeInvalid && - expr_result.GetValueType () == Value::eValueTypeScalar && - format == eFormatDefault) - { - // The expression result is just a scalar with no special formatting - expr_result.GetScalar ().GetValue (&output_stream, m_options.show_types); - output_stream.EOL (); return true; } - - // The expression result is more complext and requires special handling - DataExtractor data; - expr_error = expr_result.GetValueAsData (&m_exe_ctx, ast_context, data, 0); - - if (!expr_error.Success ()) - { - error_stream.Printf ("error: couldn't resolve result value: %s\n", expr_error.AsCString ()); - return false; - } - - if (format == eFormatDefault) - format = expr_result.GetValueDefaultFormat (); - - void *clang_type = expr_result.GetValueOpaqueClangQualType (); - - if (clang_type) - { - if (m_options.show_types) - Type::DumpClangTypeName (&output_stream, clang_type); - - Type::DumpValue (&m_exe_ctx, // The execution context for memory and variable access - ast_context, // The ASTContext that the clang type belongs to - clang_type, // The opaque clang type we want to dump that value of - &output_stream, // Stream to dump to - format, // Format to use when dumping - data, // A buffer containing the bytes for the clang type - 0, // Byte offset within "data" where value is - data.GetByteSize (), // Size in bytes of the value we are dumping - 0, // Bitfield bit size - 0, // Bitfield bit offset - m_options.show_types, // Show types? - m_options.show_summary, // Show summary? - m_options.debug, // Debug logging output? - UINT32_MAX); // Depth to dump in case this is an aggregate type - } - else - { - data.Dump (&output_stream, // Stream to dump to - 0, // Byte offset within "data" - format, // Format to use when dumping - data.GetByteSize (), // Size in bytes of each item we are dumping - 1, // Number of items to dump - UINT32_MAX, // Number of items per line - LLDB_INVALID_ADDRESS, // Invalid address, don't show any offset/address context - 0, // Bitfield bit size - 0); // Bitfield bit offset - } - output_stream.EOL(); - - return true; } bool diff --git a/lldb/source/Expression/IRForTarget.cpp b/lldb/source/Expression/IRForTarget.cpp index fc8b0393bc2..fd814fcd7b4 100644 --- a/lldb/source/Expression/IRForTarget.cpp +++ b/lldb/source/Expression/IRForTarget.cpp @@ -129,7 +129,8 @@ IRForTarget::runOnBasicBlock(Module &M, BasicBlock &BB) return true; } -static std::string PrintValue(llvm::Value *V, bool truncate = false) +static std::string +PrintValue(llvm::Value *V, bool truncate = false) { std::string s; raw_string_ostream rso(s); @@ -140,6 +141,109 @@ static std::string PrintValue(llvm::Value *V, bool truncate = false) return s; } +// UnfoldConstant operates on a constant [C] which has just been replaced with a value +// [new_value]. We assume that new_value has been properly placed early in the function, +// most likely somewhere in front of the first instruction in the entry basic block +// [first_entry_instruction]. +// +// UnfoldConstant reads through the uses of C and replaces C in those uses with new_value. +// Where those uses are constants, the function generates new instructions to compute the +// result of the new, non-constant expression and places them before first_entry_instruction. +// These instructions replace the constant uses, so UnfoldConstant calls itself recursively +// for those. + +static bool +UnfoldConstant(llvm::Constant *C, llvm::Value *new_value, llvm::Instruction *first_entry_instruction) +{ + lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); + + Value::use_iterator ui; + + for (ui = C->use_begin(); + ui != C->use_end(); + ++ui) + { + User *user = *ui; + + if (Constant *constant = dyn_cast<Constant>(user)) + { + // synthesize a new non-constant equivalent of the constant + + if (ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(constant)) + { + switch (constant_expr->getOpcode()) + { + default: + if (log) + log->Printf("Unhandled constant expression type: %s", PrintValue(constant_expr).c_str()); + return false; + case Instruction::BitCast: + { + // UnaryExpr + // OperandList[0] is value + + Value *s = constant_expr->getOperand(0); + + if (s == C) + s = new_value; + + BitCastInst *bit_cast(new BitCastInst(s, C->getType(), "", first_entry_instruction)); + + UnfoldConstant(constant_expr, bit_cast, first_entry_instruction); + } + break; + case Instruction::GetElementPtr: + { + // GetElementPtrConstantExpr + // OperandList[0] is base + // OperandList[1]... are indices + + Value *ptr = constant_expr->getOperand(0); + + if (ptr == C) + ptr = new_value; + + SmallVector<Value*, 16> indices; + + unsigned operand_index; + unsigned num_operands = constant_expr->getNumOperands(); + + for (operand_index = 1; + operand_index < num_operands; + ++operand_index) + { + Value *operand = constant_expr->getOperand(operand_index); + + if (operand == C) + operand = new_value; + + indices.push_back(operand); + } + + GetElementPtrInst *get_element_ptr(GetElementPtrInst::Create(ptr, indices.begin(), indices.end(), "", first_entry_instruction)); + + UnfoldConstant(constant_expr, get_element_ptr, first_entry_instruction); + } + break; + } + } + else + { + if (log) + log->Printf("Unhandled constant type: %s", PrintValue(constant).c_str()); + return false; + } + } + else + { + // simple fall-through case for non-constants + user->replaceUsesOfWith(C, new_value); + } + } + + return true; +} + bool IRForTarget::replaceVariables(Module &M, Function *F) { @@ -203,7 +307,10 @@ IRForTarget::replaceVariables(Module &M, Function *F) GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create(argument, offset_int, "", first_entry_instruction); BitCastInst *bit_cast = new BitCastInst(get_element_ptr, value->getType(), "", first_entry_instruction); - value->replaceAllUsesWith(bit_cast); + if (Constant *constant = dyn_cast<Constant>(value)) + UnfoldConstant(constant, bit_cast, first_entry_instruction); + else + value->replaceAllUsesWith(bit_cast); } if (log) |