[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