[Lldb-commits] [lldb] r109938 - in /lldb/trunk: include/lldb/Expression/ClangExpressionDeclMap.h include/lldb/Expression/IRForTarget.h source/Expression/ClangExpressionDeclMap.cpp source/Expression/IRForTarget.cpp source/Target/ThreadPlanCallFunction.cpp
Sean Callanan
scallanan at apple.com
Fri Jul 30 18:32:05 PDT 2010
Author: spyffe
Date: Fri Jul 30 20:32:05 2010
New Revision: 109938
URL: http://llvm.org/viewvc/llvm-project?rev=109938&view=rev
Log:
Added support for rewriting objc_msgSend so we can
call Objective-C methods from expressions. Also added
some more logging to the function-calling thread plan
so that we can see the registers when a function
finishes.
Also documented things maybe a bit better.
Modified:
lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h
lldb/trunk/include/lldb/Expression/IRForTarget.h
lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp
lldb/trunk/source/Expression/IRForTarget.cpp
lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
Modified: lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h?rev=109938&r1=109937&r2=109938&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h (original)
+++ lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h Fri Jul 30 20:32:05 2010
@@ -29,33 +29,6 @@
namespace lldb_private {
-//----------------------------------------------------------------------
-// For cases in which there are multiple classes of types that are not
-// interchangeable, to allow static type checking.
-//----------------------------------------------------------------------
-template <unsigned int C> class TaggedClangASTType : public ClangASTType
-{
-public:
- TaggedClangASTType (void *type, clang::ASTContext *ast_context) :
- ClangASTType(type, ast_context) { }
-
- TaggedClangASTType (const TaggedClangASTType<C> &tw) :
- ClangASTType(tw) { }
-
- TaggedClangASTType () :
- ClangASTType() { }
-
- ~TaggedClangASTType() { }
-
- const TaggedClangASTType<C> &
- operator= (const TaggedClangASTType<C> &tw)
- {
- ClangASTType::operator= (tw);
- return *this;
- }
-};
-
-
class Error;
class Function;
class NameSearchContext;
@@ -92,6 +65,9 @@
llvm::Value**& value,
uint64_t &ptr);
+ bool GetFunctionAddress (const char *name,
+ uint64_t &ptr);
+
// Interface for DwarfExpression
Value *GetValueForIndex (uint32_t index);
@@ -112,8 +88,8 @@
void GetDecls (NameSearchContext &context,
const char *name);
private:
- typedef TaggedClangASTType<0> TypeFromParser;
- typedef TaggedClangASTType<1> TypeFromUser;
+ typedef TaggedASTType<0> TypeFromParser;
+ typedef TaggedASTType<1> TypeFromUser;
struct Tuple
{
Modified: lldb/trunk/include/lldb/Expression/IRForTarget.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/IRForTarget.h?rev=109938&r1=109937&r2=109938&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Expression/IRForTarget.h (original)
+++ lldb/trunk/include/lldb/Expression/IRForTarget.h Fri Jul 30 20:32:05 2010
@@ -15,7 +15,9 @@
namespace llvm {
class BasicBlock;
class CallInst;
+ class Constant;
class Function;
+ class Instruction;
class Module;
class TargetData;
class Value;
@@ -37,22 +39,36 @@
llvm::PassManagerType T = llvm::PMT_ModulePassManager);
llvm::PassManagerType getPotentialPassManagerType() const;
private:
+ // pass to rewrite Objective-C method calls to use the runtime function
+ // sel_registerName
+ bool RewriteObjCSelector(llvm::Instruction* selector_load,
+ llvm::Module &M);
+ bool rewriteObjCSelectors(llvm::Module &M,
+ llvm::BasicBlock &BB);
+
+ // pass to register referenced variables and redirect functions at their
+ // targets in the debugged process
bool MaybeHandleVariable(llvm::Module &M,
llvm::Value *V,
bool Store);
bool MaybeHandleCall(llvm::Module &M,
llvm::CallInst *C);
- bool runOnBasicBlock(llvm::Module &M,
- llvm::BasicBlock &BB);
+ bool resolveExternals(llvm::Module &M,
+ llvm::BasicBlock &BB);
+
+ // pass to find references to guard variables and excise them
bool removeGuards(llvm::Module &M,
llvm::BasicBlock &BB);
+
+ // pass to replace all identified variables with references to members of
+ // the argument struct
bool replaceVariables(llvm::Module &M,
- llvm::Function *F);
- bool replaceFunctions(llvm::Module &M,
- llvm::Function *F);
+ llvm::Function &F);
lldb_private::ClangExpressionDeclMap *m_decl_map;
const llvm::TargetData *m_target_data;
+
+ llvm::Constant *m_sel_registerName;
};
-#endif
\ No newline at end of file
+#endif
Modified: lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp?rev=109938&r1=109937&r2=109938&view=diff
==============================================================================
--- lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp (original)
+++ lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp Fri Jul 30 20:32:05 2010
@@ -204,6 +204,39 @@
return false;
}
+bool
+ClangExpressionDeclMap::GetFunctionAddress (const char *name,
+ uint64_t &ptr)
+{
+ // Back out in all cases where we're not fully initialized
+ if (!m_exe_ctx || !m_exe_ctx->frame || !m_sym_ctx)
+ return false;
+
+ ConstString name_cs(name);
+ SymbolContextList sym_ctxs;
+
+ m_sym_ctx->FindFunctionsByName(name_cs, false, sym_ctxs);
+
+ if (!sym_ctxs.GetSize())
+ return false;
+
+ SymbolContext sym_ctx;
+ sym_ctxs.GetContextAtIndex(0, sym_ctx);
+
+ const Address *fun_address;
+
+ if (sym_ctx.function)
+ fun_address = &sym_ctx.function->GetAddressRange().GetBaseAddress();
+ else if (sym_ctx.symbol)
+ fun_address = &sym_ctx.symbol->GetAddressRangeRef().GetBaseAddress();
+ else
+ return false;
+
+ ptr = fun_address->GetLoadAddress(m_exe_ctx->process);
+
+ return true;
+}
+
// Interface for DwarfExpression
lldb_private::Value
*ClangExpressionDeclMap::GetValueForIndex (uint32_t index)
@@ -547,7 +580,7 @@
if (type->GetASTContext() == var->GetType()->GetClangAST())
{
- if (!ClangASTContext::AreTypesSame(type->GetASTContext(), type, var->GetType()->GetOpaqueClangQualType()))
+ if (!ClangASTContext::AreTypesSame(type->GetASTContext(), type->GetOpaqueQualType(), var->GetType()->GetOpaqueClangQualType()))
continue;
}
else
@@ -778,7 +811,7 @@
m_tuples.push_back(tuple);
if (log)
- log->PutCString("Found variable");
+ log->Printf("Found variable %s, returned (NamedDecl)%p", context.Name.getAsString().c_str(), var_decl);
}
void
@@ -851,5 +884,5 @@
m_tuples.push_back(tuple);
if (log)
- log->PutCString("Found function");
+ log->Printf("Found function %s, returned (NamedDecl)%p", context.Name.getAsString().c_str(), fun_decl);
}
Modified: lldb/trunk/source/Expression/IRForTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/IRForTarget.cpp?rev=109938&r1=109937&r2=109938&view=diff
==============================================================================
--- lldb/trunk/source/Expression/IRForTarget.cpp (original)
+++ lldb/trunk/source/Expression/IRForTarget.cpp Fri Jul 30 20:32:05 2010
@@ -32,7 +32,8 @@
const TargetData *target_data) :
ModulePass(pid),
m_decl_map(decl_map),
- m_target_data(target_data)
+ m_target_data(target_data),
+ m_sel_registerName(NULL)
{
}
@@ -40,6 +41,165 @@
{
}
+static bool isObjCSelectorRef(Value *V)
+{
+ GlobalVariable *GV = dyn_cast<GlobalVariable>(V);
+
+ if (!GV || !GV->hasName() || !GV->getName().startswith("\01L_OBJC_SELECTOR_REFERENCES_"))
+ return false;
+
+ return true;
+}
+
+bool
+IRForTarget::RewriteObjCSelector(Instruction* selector_load,
+ Module &M)
+{
+ lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
+
+ LoadInst *load = dyn_cast<LoadInst>(selector_load);
+
+ if (!load)
+ return false;
+
+ // Unpack the message name from the selector. In LLVM IR, an objc_msgSend gets represented as
+ //
+ // %tmp = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_" ; <i8*>
+ // %call = call i8* (i8*, i8*, ...)* @objc_msgSend(i8* %obj, i8* %tmp, ...) ; <i8*>
+ //
+ // where %obj is the object pointer and %tmp is the selector.
+ //
+ // @"\01L_OBJC_SELECTOR_REFERENCES_" is a pointer to a character array called @"\01L_OBJC_METH_VAR_NAME_".
+ // @"\01L_OBJC_METH_VAR_NAME_" contains the string.
+
+ // Find the pointer's initializer (a ConstantExpr with opcode GetElementPtr) and get the string from its target
+
+ GlobalVariable *_objc_selector_references_ = dyn_cast<GlobalVariable>(load->getPointerOperand());
+
+ if (!_objc_selector_references_ || !_objc_selector_references_->hasInitializer())
+ return false;
+
+ Constant *osr_initializer = _objc_selector_references_->getInitializer();
+
+ ConstantExpr *osr_initializer_expr = dyn_cast<ConstantExpr>(osr_initializer);
+
+ if (!osr_initializer_expr || osr_initializer_expr->getOpcode() != Instruction::GetElementPtr)
+ return false;
+
+ Value *osr_initializer_base = osr_initializer_expr->getOperand(0);
+
+ if (!osr_initializer_base)
+ return false;
+
+ // Find the string's initializer (a ConstantArray) and get the string from it
+
+ GlobalVariable *_objc_meth_var_name_ = dyn_cast<GlobalVariable>(osr_initializer_base);
+
+ if (!_objc_meth_var_name_ || !_objc_meth_var_name_->hasInitializer())
+ return false;
+
+ Constant *omvn_initializer = _objc_meth_var_name_->getInitializer();
+
+ ConstantArray *omvn_initializer_array = dyn_cast<ConstantArray>(omvn_initializer);
+
+ if (!omvn_initializer_array->isString())
+ return false;
+
+ std::string omvn_initializer_string = omvn_initializer_array->getAsString();
+
+ if (log)
+ log->Printf("Found Objective-C selector reference %s", omvn_initializer_string.c_str());
+
+ // Construct a call to sel_registerName
+
+ if (!m_sel_registerName)
+ {
+ uint64_t srN_addr;
+
+ if (!m_decl_map->GetFunctionAddress("sel_registerName", srN_addr))
+ return false;
+
+ // Build the function type: struct objc_selector *sel_registerName(uint8_t*)
+
+ // The below code would be "more correct," but in actuality what's required is uint8_t*
+ //Type *sel_type = StructType::get(M.getContext());
+ //Type *sel_ptr_type = PointerType::getUnqual(sel_type);
+ const Type *sel_ptr_type = Type::getInt8PtrTy(M.getContext());
+
+ std::vector <const Type *> srN_arg_types;
+ srN_arg_types.push_back(Type::getInt8PtrTy(M.getContext()));
+ llvm::Type *srN_type = FunctionType::get(sel_ptr_type, srN_arg_types, false);
+
+ // Build the constant containing the pointer to the function
+ const IntegerType *intptr_ty = Type::getIntNTy(M.getContext(),
+ (M.getPointerSize() == Module::Pointer64) ? 64 : 32);
+ PointerType *srN_ptr_ty = PointerType::getUnqual(srN_type);
+ Constant *srN_addr_int = ConstantInt::get(intptr_ty, srN_addr, false);
+ m_sel_registerName = ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty);
+ }
+
+ SmallVector <Value*, 1> srN_arguments;
+
+ Constant *omvn_pointer = ConstantExpr::getBitCast(_objc_meth_var_name_, Type::getInt8PtrTy(M.getContext()));
+
+ srN_arguments.push_back(omvn_pointer);
+
+ CallInst *srN_call = CallInst::Create(m_sel_registerName,
+ srN_arguments.begin(),
+ srN_arguments.end(),
+ "srN",
+ selector_load);
+
+ // Replace the load with the call in all users
+
+ selector_load->replaceAllUsesWith(srN_call);
+
+ selector_load->eraseFromParent();
+
+ return true;
+}
+
+bool
+IRForTarget::rewriteObjCSelectors(Module &M,
+ BasicBlock &BB)
+{
+ lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
+
+ BasicBlock::iterator ii;
+
+ typedef SmallVector <Instruction*, 2> InstrList;
+ typedef InstrList::iterator InstrIterator;
+
+ InstrList selector_loads;
+
+ for (ii = BB.begin();
+ ii != BB.end();
+ ++ii)
+ {
+ Instruction &inst = *ii;
+
+ if (LoadInst *load = dyn_cast<LoadInst>(&inst))
+ if (isObjCSelectorRef(load->getPointerOperand()))
+ selector_loads.push_back(&inst);
+ }
+
+ InstrIterator iter;
+
+ for (iter = selector_loads.begin();
+ iter != selector_loads.end();
+ ++iter)
+ {
+ if (!RewriteObjCSelector(*iter, M))
+ {
+ if(log)
+ log->PutCString("Couldn't rewrite a reference to an Objective-C selector");
+ return false;
+ }
+ }
+
+ return true;
+}
+
static clang::NamedDecl *
DeclForGlobalValue(Module &module,
GlobalValue *global_value)
@@ -85,10 +245,22 @@
Value *V,
bool Store)
{
+ lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
+
if (GlobalVariable *global_variable = dyn_cast<GlobalVariable>(V))
- {
+ {
clang::NamedDecl *named_decl = DeclForGlobalValue(M, global_variable);
+ if (!named_decl)
+ {
+ if (isObjCSelectorRef(V))
+ return true;
+
+ if (log)
+ log->Printf("Found global variable %s without metadata", global_variable->getName().str().c_str());
+ return false;
+ }
+
std::string name = named_decl->getName().str();
void *qual_type = NULL;
@@ -134,28 +306,34 @@
return true;
clang::NamedDecl *fun_decl = DeclForGlobalValue(M, fun);
+ uint64_t fun_addr;
+ Value **fun_value_ptr = NULL;
- if (!fun_decl)
+ if (fun_decl)
{
- if (log)
- log->Printf("Function %s wasn't in the metadata", fun->getName().str().c_str());
- return false;
+ if (!m_decl_map->GetFunctionInfo(fun_decl, fun_value_ptr, fun_addr))
+ {
+ if (log)
+ log->Printf("Function %s had no address", fun_decl->getNameAsCString());
+ return false;
+ }
}
-
- uint64_t fun_addr;
- Value **fun_value_ptr;
-
- if (!m_decl_map->GetFunctionInfo(fun_decl, fun_value_ptr, fun_addr))
+ else
{
- if (log)
- log->Printf("Function %s had no address", fun_decl->getNameAsCString());
- return false;
+ if (!m_decl_map->GetFunctionAddress(fun->getName().str().c_str(), fun_addr))
+ {
+ if (log)
+ log->Printf("Metadataless function %s had no address", fun->getName().str().c_str());
+ return false;
+ }
}
if (log)
- log->Printf("Found %s at %llx", fun_decl->getNameAsCString(), fun_addr);
+ log->Printf("Found %s at %llx", fun->getName().str().c_str(), fun_addr);
- if (!*fun_value_ptr)
+ Value *fun_addr_ptr;
+
+ if (!fun_value_ptr || !*fun_value_ptr)
{
std::vector<const Type*> params;
@@ -165,17 +343,22 @@
FunctionType *fun_ty = FunctionType::get(intptr_ty, params, true);
PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
Constant *fun_addr_int = ConstantInt::get(intptr_ty, fun_addr, false);
- Constant *fun_addr_ptr = ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty);
- *fun_value_ptr = fun_addr_ptr;
+ fun_addr_ptr = ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty);
+
+ if (fun_value_ptr)
+ *fun_value_ptr = fun_addr_ptr;
}
+
+ if (fun_value_ptr)
+ fun_addr_ptr = *fun_value_ptr;
- C->setCalledFunction(*fun_value_ptr);
+ C->setCalledFunction(fun_addr_ptr);
return true;
}
bool
-IRForTarget::runOnBasicBlock(Module &M, BasicBlock &BB)
+IRForTarget::resolveExternals(Module &M, BasicBlock &BB)
{
/////////////////////////////////////////////////////////////////////////
// Prepare the current basic block for execution in the remote process
@@ -192,7 +375,7 @@
if (LoadInst *load = dyn_cast<LoadInst>(&inst))
if (!MaybeHandleVariable(M, load->getPointerOperand(), false))
return false;
-
+
if (StoreInst *store = dyn_cast<StoreInst>(&inst))
if (!MaybeHandleVariable(M, store->getPointerOperand(), true))
return false;
@@ -409,7 +592,7 @@
}
bool
-IRForTarget::replaceVariables(Module &M, Function *F)
+IRForTarget::replaceVariables(Module &M, Function &F)
{
lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
@@ -427,9 +610,9 @@
if (!m_decl_map->GetStructInfo (num_elements, size, alignment))
return false;
- Function::arg_iterator iter(F->getArgumentList().begin());
+ Function::arg_iterator iter(F.getArgumentList().begin());
- if (iter == F->getArgumentList().end())
+ if (iter == F.getArgumentList().end())
return false;
Argument *argument = iter;
@@ -440,7 +623,7 @@
if (log)
log->Printf("Arg: %s", PrintValue(argument).c_str());
- BasicBlock &entry_block(F->getEntryBlock());
+ BasicBlock &entry_block(F.getEntryBlock());
Instruction *first_entry_instruction(entry_block.getFirstNonPHIOrDbg());
if (!first_entry_instruction)
@@ -500,21 +683,29 @@
Function::iterator bbi;
+ //////////////////////////////////
+ // Run basic-block level passes
+ //
+
for (bbi = function->begin();
bbi != function->end();
++bbi)
{
- if (!runOnBasicBlock(M, *bbi))
+ if (!rewriteObjCSelectors(M, *bbi))
+ return false;
+
+ if (!resolveExternals(M, *bbi))
return false;
if (!removeGuards(M, *bbi))
return false;
}
- // TEMPORARY FOR DEBUGGING
- M.dump();
+ ///////////////////////////////
+ // Run function-level passes
+ //
- if (!replaceVariables(M, function))
+ if (!replaceVariables(M, *function))
return false;
if (log)
Modified: lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanCallFunction.cpp?rev=109938&r1=109937&r2=109938&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanCallFunction.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanCallFunction.cpp Fri Jul 30 20:32:05 2010
@@ -181,6 +181,25 @@
{
if (PlanExplainsStop())
{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (log)
+ {
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+
+ log->PutCString("Function completed. Register state was:");
+
+ for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
+ register_index < num_registers;
+ ++register_index)
+ {
+ const char *register_name = reg_ctx->GetRegisterName(register_index);
+ uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
+
+ log->Printf(" %s = 0x%llx", register_name, register_value);
+ }
+ }
+
m_thread.RestoreSaveFrameZero(m_register_backup);
m_thread.ClearStackFrames();
SetPlanComplete();
More information about the lldb-commits
mailing list