Added a user-settable variable, 'target.expr-prefix',

which holds the name of a file whose contents are
prefixed to each expression.  For example, if the file
~/lldb.prefix.header contains:

typedef unsigned short my_type;

then you can do this:

(lldb) settings set target.expr-prefix '~/lldb.prefix.header'
(lldb) expr sizeof(my_type)
(unsigned long) $0 = 2

When the variable is changed, the corresponding file
is loaded and its contents are fetched into a string
that is stored along with the target.  This string
is then passed to each expression and inserted into
it during parsing, like this:

typedef unsigned short my_type;
                             
void                           
$__lldb_expr(void *$__lldb_arg)          
{                              
    sizeof(my_type);                        
}

llvm-svn: 117627
This commit is contained in:
Sean Callanan 2010-10-29 00:29:03 +00:00
parent 5d6f6a061b
commit 322f529b37
7 changed files with 143 additions and 28 deletions

View File

@ -45,8 +45,16 @@ class ClangUserExpression : public ClangExpression
public: public:
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Constructor /// Constructor
///
/// @param[in] expr
/// The expression to parse.
///
/// @param[in] expr_prefix
/// If non-NULL, a C string containing translation-unit level
/// definitions to be included when the expression is parsed.
//------------------------------------------------------------------ //------------------------------------------------------------------
ClangUserExpression (const char *expr); ClangUserExpression (const char *expr,
const char *expr_prefix);
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Destructor /// Destructor
@ -189,9 +197,23 @@ public:
return true; return true;
} }
//------------------------------------------------------------------
/// Evaluate one expression and return its result.
///
/// @param[in] exe_ctx
/// The execution context to use when evaluating the expression.
///
/// @param[in] expr_cstr
/// A C string containing the expression to be evaluated.
///
/// @param[in] expr_prefix
/// If non-NULL, a C string containing translation-unit level
/// definitions to be included when the expression is parsed.
//------------------------------------------------------------------
static lldb::ValueObjectSP static lldb::ValueObjectSP
Evaluate (ExecutionContext &exe_ctx, const char *expr_cstr); Evaluate (ExecutionContext &exe_ctx,
const char *expr_cstr,
const char *expr_prefix);
private: private:
//------------------------------------------------------------------ //------------------------------------------------------------------
@ -202,11 +224,12 @@ private:
bool bool
PrepareToExecuteJITExpression (Stream &error_stream, PrepareToExecuteJITExpression (Stream &error_stream,
ExecutionContext &exe_ctx, ExecutionContext &exe_ctx,
lldb::addr_t &struct_address, lldb::addr_t &struct_address,
lldb::addr_t &object_ptr); lldb::addr_t &object_ptr);
std::string m_expr_text; ///< The text of the expression, as typed by the user std::string m_expr_text; ///< The text of the expression, as typed by the user
std::string m_expr_prefix; ///< The text of the translation-level definitions, as provided by the user
std::string m_transformed_text; ///< The text of the expression, as send to the parser std::string m_transformed_text; ///< The text of the expression, as send to the parser
std::auto_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression. std::auto_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression.

View File

@ -70,9 +70,9 @@ protected:
const ConstString const ConstString
CreateInstanceName (); CreateInstanceName ();
private: std::string m_expr_prefix_path;
std::string m_expr_prefix_contents;
}; };
class Target : class Target :
@ -437,6 +437,9 @@ public:
ClangASTContext * ClangASTContext *
GetScratchClangASTContext(); GetScratchClangASTContext();
const char *
GetExpressionPrefixContentsAsCString ();
protected: protected:
friend class lldb::SBTarget; friend class lldb::SBTarget;

View File

@ -547,7 +547,13 @@ SBFrame::EvaluateExpression (const char *expr)
{ {
ExecutionContext exe_ctx; ExecutionContext exe_ctx;
m_opaque_sp->CalculateExecutionContext (exe_ctx); m_opaque_sp->CalculateExecutionContext (exe_ctx);
*expr_result_value = ClangUserExpression::Evaluate (exe_ctx, expr);
const char *prefix = NULL;
if (exe_ctx.target)
prefix = exe_ctx.target->GetExpressionPrefixContentsAsCString();
*expr_result_value = ClangUserExpression::Evaluate (exe_ctx, expr, prefix);
} }
return expr_result_value; return expr_result_value;
} }

View File

@ -59,7 +59,7 @@ BreakpointOptions::BreakpointOptions(const BreakpointOptions& rhs) :
if (rhs.m_thread_spec_ap.get() != NULL) if (rhs.m_thread_spec_ap.get() != NULL)
m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get())); m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get()));
if (rhs.m_condition_ap.get()) if (rhs.m_condition_ap.get())
m_condition_ap.reset (new ClangUserExpression (rhs.m_condition_ap->GetUserText())); m_condition_ap.reset (new ClangUserExpression (rhs.m_condition_ap->GetUserText(), NULL));
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -76,7 +76,7 @@ BreakpointOptions::operator=(const BreakpointOptions& rhs)
if (rhs.m_thread_spec_ap.get() != NULL) if (rhs.m_thread_spec_ap.get() != NULL)
m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get())); m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
if (rhs.m_condition_ap.get()) if (rhs.m_condition_ap.get())
m_condition_ap.reset (new ClangUserExpression (rhs.m_condition_ap->GetUserText())); m_condition_ap.reset (new ClangUserExpression (rhs.m_condition_ap->GetUserText(), NULL));
return *this; return *this;
} }
@ -165,7 +165,7 @@ BreakpointOptions::SetCondition (const char *condition)
} }
else else
{ {
m_condition_ap.reset(new ClangUserExpression (condition)); m_condition_ap.reset(new ClangUserExpression (condition, NULL));
} }
} }

View File

@ -233,7 +233,12 @@ CommandObjectExpression::EvaluateExpression
m_exe_ctx.process->SetDynamicCheckers(dynamic_checkers); m_exe_ctx.process->SetDynamicCheckers(dynamic_checkers);
} }
lldb::ValueObjectSP result_valobj_sp (ClangUserExpression::Evaluate (m_exe_ctx, expr)); const char *prefix = NULL;
if (m_exe_ctx.target)
prefix = m_exe_ctx.target->GetExpressionPrefixContentsAsCString();
lldb::ValueObjectSP result_valobj_sp (ClangUserExpression::Evaluate (m_exe_ctx, expr, prefix));
assert (result_valobj_sp.get()); assert (result_valobj_sp.get());
if (result_valobj_sp->GetError().Success()) if (result_valobj_sp->GetError().Success())
{ {

View File

@ -35,8 +35,10 @@
using namespace lldb_private; using namespace lldb_private;
ClangUserExpression::ClangUserExpression (const char *expr) : ClangUserExpression::ClangUserExpression (const char *expr,
const char *expr_prefix) :
m_expr_text(expr), m_expr_text(expr),
m_expr_prefix(expr_prefix),
m_transformed_text(), m_transformed_text(),
m_jit_addr(LLDB_INVALID_ADDRESS), m_jit_addr(LLDB_INVALID_ADDRESS),
m_cplusplus(false), m_cplusplus(false),
@ -129,12 +131,14 @@ ClangUserExpression::Parse (Stream &error_stream, ExecutionContext &exe_ctx)
if (m_cplusplus) if (m_cplusplus)
{ {
m_transformed_stream.Printf("typedef unsigned short unichar; \n" m_transformed_stream.Printf("%s \n"
"typedef unsigned short unichar; \n"
"void \n" "void \n"
"$__lldb_class::%s(void *$__lldb_arg) \n" "$__lldb_class::%s(void *$__lldb_arg) \n"
"{ \n" "{ \n"
" %s; \n" " %s; \n"
"} \n", "} \n",
m_expr_prefix.c_str(),
FunctionName(), FunctionName(),
m_expr_text.c_str()); m_expr_text.c_str());
@ -142,12 +146,14 @@ ClangUserExpression::Parse (Stream &error_stream, ExecutionContext &exe_ctx)
} }
else else
{ {
m_transformed_stream.Printf("typedef unsigned short unichar;\n" m_transformed_stream.Printf("%s \n"
"typedef unsigned short unichar;\n"
"void \n" "void \n"
"%s(void *$__lldb_arg) \n" "%s(void *$__lldb_arg) \n"
"{ \n" "{ \n"
" %s; \n" " %s; \n"
"} \n", "} \n",
m_expr_prefix.c_str(),
FunctionName(), FunctionName(),
m_expr_text.c_str()); m_expr_text.c_str());
} }
@ -425,11 +431,13 @@ ClangUserExpression::DwarfOpcodeStream ()
lldb::ValueObjectSP lldb::ValueObjectSP
ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, const char *expr_cstr) ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
const char *expr_cstr,
const char *expr_prefix)
{ {
Error error; Error error;
lldb::ValueObjectSP result_valobj_sp; lldb::ValueObjectSP result_valobj_sp;
ClangUserExpression user_expression (expr_cstr); ClangUserExpression user_expression (expr_cstr, expr_prefix);
StreamString error_stream; StreamString error_stream;

View File

@ -17,6 +17,7 @@
#include "lldb/Breakpoint/BreakpointResolverAddress.h" #include "lldb/Breakpoint/BreakpointResolverAddress.h"
#include "lldb/Breakpoint/BreakpointResolverFileLine.h" #include "lldb/Breakpoint/BreakpointResolverFileLine.h"
#include "lldb/Breakpoint/BreakpointResolverName.h" #include "lldb/Breakpoint/BreakpointResolverName.h"
#include "lldb/Core/DataBufferMemoryMap.h"
#include "lldb/Core/Event.h" #include "lldb/Core/Event.h"
#include "lldb/Core/Log.h" #include "lldb/Core/Log.h"
#include "lldb/Core/Timer.h" #include "lldb/Core/Timer.h"
@ -853,6 +854,12 @@ Target::UpdateInstanceName ()
} }
} }
const char *
Target::GetExpressionPrefixContentsAsCString ()
{
return m_expr_prefix_contents.c_str();
}
//-------------------------------------------------------------- //--------------------------------------------------------------
// class Target::SettingsController // class Target::SettingsController
//-------------------------------------------------------------- //--------------------------------------------------------------
@ -976,6 +983,7 @@ TargetInstanceSettings::operator= (const TargetInstanceSettings &rhs)
return *this; return *this;
} }
#define EXPR_PREFIX_STRING "expr-prefix"
void void
TargetInstanceSettings::UpdateInstanceSettingsVariable (const ConstString &var_name, TargetInstanceSettings::UpdateInstanceSettingsVariable (const ConstString &var_name,
@ -987,14 +995,64 @@ TargetInstanceSettings::UpdateInstanceSettingsVariable (const ConstString &var_n
Error &err, Error &err,
bool pending) bool pending)
{ {
// Currently 'target' does not have any instance settings. static ConstString expr_prefix_str (EXPR_PREFIX_STRING);
if (var_name == expr_prefix_str)
{
switch (op)
{
default:
err.SetErrorToGenericError ();
err.SetErrorString ("Unrecognized operation. Cannot update value.\n");
return;
case lldb::eVarSetOperationAssign:
{
FileSpec file_spec(value, true);
if (!file_spec.Exists())
{
err.SetErrorToGenericError ();
err.SetErrorStringWithFormat ("%s does not exist.\n", value);
return;
}
DataBufferMemoryMap buf;
if (!buf.MemoryMapFromFileSpec(&file_spec) &&
buf.GetError().Fail())
{
err.SetErrorToGenericError ();
err.SetErrorStringWithFormat ("Couldn't read from %s: %s\n", value, buf.GetError().AsCString());
return;
}
m_expr_prefix_path = value;
m_expr_prefix_contents.assign(reinterpret_cast<const char *>(buf.GetBytes()), buf.GetByteSize());
}
return;
case lldb::eVarSetOperationAppend:
err.SetErrorToGenericError ();
err.SetErrorString ("Cannot append to a path.\n");
return;
case lldb::eVarSetOperationClear:
m_expr_prefix_path.clear ();
m_expr_prefix_contents.clear ();
return;
}
}
} }
void void
TargetInstanceSettings::CopyInstanceSettings (const lldb::InstanceSettingsSP &new_settings, TargetInstanceSettings::CopyInstanceSettings (const lldb::InstanceSettingsSP &new_settings,
bool pending) bool pending)
{ {
// Currently 'target' does not have any instance settings. TargetInstanceSettings *new_settings_ptr = static_cast <TargetInstanceSettings *> (new_settings.get());
if (!new_settings_ptr)
return;
m_expr_prefix_path = new_settings_ptr->m_expr_prefix_path;
m_expr_prefix_contents = new_settings_ptr->m_expr_prefix_contents;
} }
bool bool
@ -1003,9 +1061,20 @@ TargetInstanceSettings::GetInstanceSettingsValue (const SettingEntry &entry,
StringList &value, StringList &value,
Error *err) Error *err)
{ {
if (err) static ConstString expr_prefix_str (EXPR_PREFIX_STRING);
err->SetErrorString ("'target' does not have any instance settings");
return false; if (var_name == expr_prefix_str)
{
value.AppendString (m_expr_prefix_path.c_str(), m_expr_prefix_path.size());
}
else
{
if (err)
err->SetErrorStringWithFormat ("unrecognized variable name '%s'", var_name.AsCString());
return false;
}
return true;
} }
const ConstString const ConstString
@ -1028,14 +1097,15 @@ TargetInstanceSettings::CreateInstanceName ()
SettingEntry SettingEntry
Target::SettingsController::global_settings_table[] = Target::SettingsController::global_settings_table[] =
{ {
//{ "var-name", var-type , "default", enum-table, init'd, hidden, "help-text"}, //{ "var-name", var-type, "default", enum-table, init'd, hidden, "help-text"},
{ "default-arch", eSetVarTypeString, NULL, NULL, false, false, "Default architecture to choose, when there's a choice." }, { "default-arch", eSetVarTypeString, NULL, NULL, false, false, "Default architecture to choose, when there's a choice." },
{ NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL } { NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL }
}; };
SettingEntry SettingEntry
Target::SettingsController::instance_settings_table[] = Target::SettingsController::instance_settings_table[] =
{ {
//{ "var-name", var-type, "default", enum-table, init'd, hidden, "help-text"}, //{ "var-name", var-type, "default", enum-table, init'd, hidden, "help-text"},
{ EXPR_PREFIX_STRING, eSetVarTypeString, NULL, NULL, false, false, "Path to a file containing expressions to be prepended to all expressions." },
{ NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL } { NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL }
}; };