Added a ClangUtilityFunction class that allows the

debugger to insert self-contained functions for use by
expressions (mainly for error-checking).

In order to support detecting whether a crash occurred
in one of these helpers -- currently our preferred way
of reporting that an error-check failed -- added a bit
of support for getting the extent of a JITted function
in addition to just its base.

llvm-svn: 112324
This commit is contained in:
Sean Callanan 2010-08-27 23:31:21 +00:00
parent 38f6b7fe3b
commit e71d553cd4
10 changed files with 341 additions and 8 deletions

View File

@ -41,6 +41,13 @@ class RecordingMemoryManager;
class ClangExpression
{
public:
//------------------------------------------------------------------
/// Destructor
//------------------------------------------------------------------
virtual ~ClangExpression ()
{
}
//------------------------------------------------------------------
/// Return the string that the parser should parse. Must be a full
/// translation unit.

View File

@ -93,7 +93,12 @@ public:
/// @param[out] func_addr
/// The address to which the function has been written.
///
/// @para[in] exe_ctx
/// @param[out] func_end
/// The end of the function's allocated memory region. (func_addr
/// and func_end do not delimit an allocated region; the allocated
/// region may begin before func_addr.)
///
/// @param[in] exe_ctx
/// The execution context to write the function into.
///
/// @return
@ -101,7 +106,8 @@ public:
/// Test with Success().
//------------------------------------------------------------------
Error
MakeJIT (lldb::addr_t &func_addr,
MakeJIT (lldb::addr_t &func_addr,
lldb::addr_t &func_end,
ExecutionContext &exe_ctx);
//------------------------------------------------------------------

View File

@ -47,6 +47,11 @@ public:
//------------------------------------------------------------------
ClangUserExpression (const char *expr);
//------------------------------------------------------------------
/// Destructor
//------------------------------------------------------------------
virtual ~ClangUserExpression ();
//------------------------------------------------------------------
/// Parse the expression
///

View File

@ -0,0 +1,176 @@
//===-- ClangUtilityFunction.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_ClangUtilityFunction_h_
#define liblldb_ClangUtilityFunction_h_
// C Includes
// C++ Includes
#include <string>
#include <map>
#include <memory>
#include <vector>
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private.h"
#include "lldb/Core/ClangForward.h"
#include "lldb/Expression/ClangExpression.h"
namespace lldb_private
{
//----------------------------------------------------------------------
/// @class ClangUtilityFunction ClangUtilityFunction.h "lldb/Expression/ClangUtilityFunction.h"
/// @brief Encapsulates a single expression for use with Clang
///
/// LLDB uses expressions for various purposes, notably to call functions
/// and as a backend for the expr command. ClangUtilityFunction encapsulates
/// a self-contained function meant to be used from other code. Utility
/// functions can perform error-checking for ClangUserExpressions,
//----------------------------------------------------------------------
class ClangUtilityFunction : public ClangExpression
{
public:
//------------------------------------------------------------------
/// Constructor
///
/// @param[in] text
/// The text of the function. Must be a full translation unit.
///
/// @param[in] name
/// The name of the function, as used in the text.
//------------------------------------------------------------------
ClangUtilityFunction (const char *text,
const char *name);
//------------------------------------------------------------------
/// Install the utility function into a process
///
/// @param[in] error_stream
/// A stream to print parse errors and warnings to.
///
/// @param[in] exe_ctx
/// The execution context to install the utility function to.
///
/// @return
/// True on success (no errors); false otherwise.
//------------------------------------------------------------------
bool
Install (Stream &error_stream, ExecutionContext &exe_ctx);
//------------------------------------------------------------------
/// Check whether the given PC is inside the function
///
/// Especially useful if the function dereferences NULL to indicate a failed
/// assert.
///
/// @param[in] pc
/// The program counter to check.
///
/// @return
/// True if the program counter falls within the function's bounds;
/// false if not (or the function is not JIT compiled)
//------------------------------------------------------------------
bool
ContainsAddress (lldb::addr_t address)
{
// nothing is both >= LLDB_INVALID_ADDRESS and < LLDB_INVALID_ADDRESS,
// so this always returns false if the function is not JIT compiled yet
return (address >= m_jit_begin && address < m_jit_end);
}
//------------------------------------------------------------------
/// Return the address of the function's JIT-compiled code, or
/// LLDB_INVALID_ADDRESS if the function is not JIT compiled
//------------------------------------------------------------------
lldb::addr_t
StartAddress ()
{
return m_jit_begin;
}
//------------------------------------------------------------------
/// Return the string that the parser should parse. Must be a full
/// translation unit.
//------------------------------------------------------------------
const char *
Text ()
{
return m_function_text.c_str();
}
//------------------------------------------------------------------
/// Return the function name that should be used for executing the
/// expression. Text() should contain the definition of this
/// function.
//------------------------------------------------------------------
const char *
FunctionName ()
{
return m_function_name.c_str();
}
//------------------------------------------------------------------
/// Return the object that the parser should use when resolving external
/// values. May be NULL if everything should be self-contained.
//------------------------------------------------------------------
ClangExpressionDeclMap *
DeclMap ()
{
return NULL;
}
//------------------------------------------------------------------
/// Return the object that the parser should use when registering
/// local variables. May be NULL if the Expression doesn't care.
//------------------------------------------------------------------
ClangExpressionVariableStore *
LocalVariables ()
{
return NULL;
}
//------------------------------------------------------------------
/// Return the object that the parser should allow to access ASTs.
/// May be NULL if the ASTs do not need to be transformed.
///
/// @param[in] passthrough
/// The ASTConsumer that the returned transformer should send
/// the ASTs to after transformation.
//------------------------------------------------------------------
clang::ASTConsumer *
ASTTransformer (clang::ASTConsumer *passthrough)
{
return NULL;
}
//------------------------------------------------------------------
/// Return the stream that the parser should use to write DWARF
/// opcodes.
//------------------------------------------------------------------
StreamString &
DwarfOpcodeStream ()
{
return *((StreamString*)NULL);
}
private:
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.
lldb::addr_t m_jit_begin; ///< The address of the JITted code. LLDB_INVALID_ADDRESS if invalid.
lldb::addr_t m_jit_end; ///< The end of the JITted code. LLDB_INVALID_ADDRESS if invalid.
};
} // namespace lldb_private
#endif // liblldb_ClangUtilityFunction_h_

View File

@ -52,7 +52,9 @@ namespace lldb_private {
//----------------------------------------------------------------------
class RecordingMemoryManager : public llvm::JITMemoryManager
{
friend Error ClangExpressionParser::MakeJIT (uint64_t &, ExecutionContext &);
friend Error ClangExpressionParser::MakeJIT (uint64_t &,
uint64_t&,
ExecutionContext &);
public:
//------------------------------------------------------------------

View File

@ -336,6 +336,8 @@
49445C2612245E3600C11A81 /* ClangExpressionParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49445C2512245E3600C11A81 /* ClangExpressionParser.cpp */; };
49445C2A12245E5500C11A81 /* ClangExpressionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 49445C2912245E5500C11A81 /* ClangExpressionParser.h */; };
49445E351225AB6A00C11A81 /* ClangUserExpression.h in Headers */ = {isa = PBXBuildFile; fileRef = 49445E341225AB6A00C11A81 /* ClangUserExpression.h */; };
497C86BE122823D800B54702 /* ClangUtilityFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 497C86BD122823D800B54702 /* ClangUtilityFunction.cpp */; };
497C86C2122823F300B54702 /* ClangUtilityFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 497C86C1122823F300B54702 /* ClangUtilityFunction.h */; };
49A8A3A011D568A300AD3B68 /* ASTResultSynthesizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49A8A39F11D568A300AD3B68 /* ASTResultSynthesizer.cpp */; };
49A8A3A411D568BF00AD3B68 /* ASTResultSynthesizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49A8A3A311D568BF00AD3B68 /* ASTResultSynthesizer.h */; };
49BB309611F79450001A4197 /* TaggedASTType.h in Headers */ = {isa = PBXBuildFile; fileRef = 49BB309511F79450001A4197 /* TaggedASTType.h */; };
@ -919,6 +921,8 @@
495BBACF119A0DE700418BEA /* PathMappingList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PathMappingList.h; path = include/lldb/Target/PathMappingList.h; sourceTree = "<group>"; };
497650CE11A21BEE008DDB57 /* ABIMacOSX_i386.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ABIMacOSX_i386.cpp; path = "ABI/MacOSX-i386/ABIMacOSX_i386.cpp"; sourceTree = "<group>"; };
497650CF11A21BEE008DDB57 /* ABIMacOSX_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ABIMacOSX_i386.h; path = "ABI/MacOSX-i386/ABIMacOSX_i386.h"; sourceTree = "<group>"; };
497C86BD122823D800B54702 /* ClangUtilityFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangUtilityFunction.cpp; path = source/Expression/ClangUtilityFunction.cpp; sourceTree = "<group>"; };
497C86C1122823F300B54702 /* ClangUtilityFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangUtilityFunction.h; path = include/lldb/Expression/ClangUtilityFunction.h; sourceTree = "<group>"; };
497E7B331188ED300065CCA1 /* ABI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ABI.h; path = include/lldb/Target/ABI.h; sourceTree = "<group>"; };
497E7B9D1188F6690065CCA1 /* ABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ABI.cpp; path = source/Target/ABI.cpp; sourceTree = "<group>"; };
499F381E11A5B3F300F5CE02 /* CommandObjectArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectArgs.h; path = source/Commands/CommandObjectArgs.h; sourceTree = "<group>"; };
@ -1854,8 +1858,6 @@
49D7072611B5AD03001AD875 /* ClangASTSource.h */,
49D7072811B5AD11001AD875 /* ClangASTSource.cpp */,
26BC7DC010F1B79500F91463 /* ClangExpression.h */,
49445E341225AB6A00C11A81 /* ClangUserExpression.h */,
26BC7ED510F1B86700F91463 /* ClangUserExpression.cpp */,
4C98D3E0118FB98F00E575D0 /* ClangFunction.h */,
4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */,
49F1A74911B338AE003ED505 /* ClangExpressionDeclMap.h */,
@ -1866,6 +1868,10 @@
26BC7ED610F1B86700F91463 /* ClangExpressionVariable.cpp */,
49D4FE821210B5FB00CDB854 /* ClangPersistentVariables.h */,
49D4FE871210B61C00CDB854 /* ClangPersistentVariables.cpp */,
49445E341225AB6A00C11A81 /* ClangUserExpression.h */,
26BC7ED510F1B86700F91463 /* ClangUserExpression.cpp */,
497C86C1122823F300B54702 /* ClangUtilityFunction.h */,
497C86BD122823D800B54702 /* ClangUtilityFunction.cpp */,
26BC7DC310F1B79500F91463 /* DWARFExpression.h */,
26BC7ED810F1B86700F91463 /* DWARFExpression.cpp */,
49A8A3A311D568BF00AD3B68 /* ASTResultSynthesizer.h */,
@ -2243,6 +2249,7 @@
49445C2A12245E5500C11A81 /* ClangExpressionParser.h in Headers */,
49445E351225AB6A00C11A81 /* ClangUserExpression.h in Headers */,
4911934C1226383D00578B7F /* ASTStructExtractor.h in Headers */,
497C86C2122823F300B54702 /* ClangUtilityFunction.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -2700,6 +2707,7 @@
49FB515E121481B000DF8983 /* DWARFExpression.cpp in Sources */,
49445C2612245E3600C11A81 /* ClangExpressionParser.cpp in Sources */,
491193521226386000578B7F /* ASTStructExtractor.cpp in Sources */,
497C86BE122823D800B54702 /* ClangUtilityFunction.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -369,7 +369,9 @@ ClangExpressionParser::MakeDWARF ()
}
Error
ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr, ExecutionContext &exe_ctx)
ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr,
lldb::addr_t &func_end,
ExecutionContext &exe_ctx)
{
Error err;
@ -507,7 +509,10 @@ ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr, ExecutionContext &exe_c
(*pos).m_remote_addr = m_jit_mm->GetRemoteAddressForLocal ((*pos).m_local_addr);
if (!(*pos).m_name.compare(m_expr.FunctionName()))
{
func_end = m_jit_mm->GetRemoteRangeForLocal ((*pos).m_local_addr).second;
func_addr = (*pos).m_remote_addr;
}
}
err.Clear();

View File

@ -227,7 +227,9 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
if (m_JITted)
return true;
Error jit_error = m_parser->MakeJIT(m_wrapper_function_addr, exe_ctx);
lldb::addr_t wrapper_function_end;
Error jit_error = m_parser->MakeJIT(m_wrapper_function_addr, wrapper_function_end, exe_ctx);
if (!jit_error.Success())
return false;

View File

@ -45,6 +45,10 @@ ClangUserExpression::ClangUserExpression (const char *expr) :
m_transformed_text = m_transformed_stream.GetData();
}
ClangUserExpression::~ClangUserExpression ()
{
}
clang::ASTConsumer *
ClangUserExpression::ASTTransformer (clang::ASTConsumer *passthrough)
{
@ -123,7 +127,9 @@ ClangUserExpression::Parse (Stream &error_stream, ExecutionContext &exe_ctx)
m_dwarf_opcodes.reset();
Error jit_error = parser.MakeJIT (m_jit_addr, exe_ctx);
lldb::addr_t jit_end;
Error jit_error = parser.MakeJIT (m_jit_addr, jit_end, exe_ctx);
if (jit_error.Success())
{

View File

@ -0,0 +1,116 @@
//===-- ClangUserExpression.cpp -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
#include <stdio.h>
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
// C++ Includes
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Stream.h"
#include "lldb/Expression/ClangExpressionParser.h"
#include "lldb/Expression/ClangUtilityFunction.h"
#include "lldb/Host/Host.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
using namespace lldb_private;
//------------------------------------------------------------------
/// Constructor
///
/// @param[in] text
/// The text of the function. Must be a full translation unit.
///
/// @param[in] name
/// The name of the function, as used in the text.
//------------------------------------------------------------------
ClangUtilityFunction::ClangUtilityFunction (const char *text,
const char *name) :
m_function_text(text),
m_function_name(name)
{
}
//------------------------------------------------------------------
/// Install the utility function into a process
///
/// @param[in] error_stream
/// A stream to print parse errors and warnings to.
///
/// @param[in] exe_ctx
/// The execution context to install the utility function to.
///
/// @return
/// True on success (no errors); false otherwise.
//------------------------------------------------------------------
bool
ClangUtilityFunction::Install (Stream &error_stream,
ExecutionContext &exe_ctx)
{
////////////////////////////////////
// Set up the target and compiler
//
Target *target = exe_ctx.target;
if (!target)
{
error_stream.PutCString ("error: invalid target\n");
return false;
}
ConstString target_triple;
target->GetTargetTriple (target_triple);
if (!target_triple)
target_triple = Host::GetTargetTriple ();
if (!target_triple)
{
error_stream.PutCString ("error: invalid target triple\n");
return false;
}
//////////////////////////
// Parse the expression
//
ClangExpressionParser parser(target_triple.GetCString(), *this);
unsigned num_errors = parser.Parse (error_stream);
if (num_errors)
{
error_stream.Printf ("error: %d errors parsing expression\n", num_errors);
return false;
}
//////////////////////////////////
// JIT the output of the parser
//
Error jit_error = parser.MakeJIT (m_jit_begin, m_jit_end, exe_ctx);
if (jit_error.Success())
{
return true;
}
else
{
error_stream.Printf ("error: expression can't be interpreted or run\n", num_errors);
return false;
}
}