Add GNU indirect function support in expressions for Linux.
authorMatt Kopec <Matt.Kopec@intel.com>
Wed, 27 Feb 2013 20:13:38 +0000 (20:13 +0000)
committerMatt Kopec <Matt.Kopec@intel.com>
Wed, 27 Feb 2013 20:13:38 +0000 (20:13 +0000)
llvm-svn: 176206

16 files changed:
lldb/include/lldb/Core/Address.h
lldb/include/lldb/Symbol/Symbol.h
lldb/include/lldb/Target/Process.h
lldb/include/lldb/Target/ThreadPlanCallFunction.h
lldb/include/lldb/lldb-enumerations.h
lldb/source/Core/Address.cpp
lldb/source/Core/Module.cpp
lldb/source/Expression/ClangExpressionDeclMap.cpp
lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h
lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h
lldb/source/Symbol/Symbol.cpp
lldb/source/Target/ThreadPlanCallFunction.cpp
lldb/test/lang/c/strings/TestCStrings.py

index 6a97e87b87ca50658862b127c006ad53d9306d20..6bb186b6fb7a7d1d1a93ea4d6c2a84888ec6a3e6 100644 (file)
@@ -302,7 +302,7 @@ public:
     ///     the address is currently not loaded.
     //------------------------------------------------------------------
     lldb::addr_t
-    GetCallableLoadAddress (Target *target) const;
+    GetCallableLoadAddress (Target *target, bool is_indirect = false) const;
 
     //------------------------------------------------------------------
     /// Get the load address as an opcode load address.
index 6cc72afff9f77d2fddbb5df29a5073f4af41da68..8235a8875bee3a7f7ccc5af661c5f6e6f9b8db7f 100644 (file)
@@ -205,6 +205,9 @@ public:
     bool
     IsTrampoline () const;
 
+    bool
+    IsIndirect () const;
+
     lldb::addr_t
     GetByteSize () const;
     
index ea163fb394fbd24894a5e345beed5bf816c5f443..19540ec25b97720bf481b16492cd4a79b89e991a 100644 (file)
@@ -2894,6 +2894,28 @@ public:
     lldb::addr_t
     AllocateMemory (size_t size, uint32_t permissions, Error &error);
 
+
+    //------------------------------------------------------------------
+    /// Resolve dynamically loaded indirect functions.
+    ///
+    /// @param[in] address
+    ///     The load address of the indirect function to resolve.
+    ///
+    /// @param[out] error
+    ///     An error value in case the resolve fails.
+    ///
+    /// @return
+    ///     The address of the resolved function.
+    ///     LLDB_INVALID_ADDRESS if the resolution failed.
+    //------------------------------------------------------------------
+
+    virtual lldb::addr_t
+    ResolveIndirectFunction(const Address *address, Error &error)
+    {
+        error.SetErrorStringWithFormat("error: %s does not support indirect functions in the debug process", GetShortPluginName());
+        return LLDB_INVALID_ADDRESS;
+    }
+
     virtual Error
     GetMemoryRegionInfo (lldb::addr_t load_addr, 
                         MemoryRegionInfo &range_info)
index d3ca83b4710ac3d09592d18ed691c64eba8bf50a..f22f88df9dbd7d4e2818ad7dc9f0d0da6aa92c68 100644 (file)
@@ -27,7 +27,7 @@ class ThreadPlanCallFunction : public ThreadPlan
     // return type, otherwise just pass in an invalid ClangASTType.
 public:
     ThreadPlanCallFunction (Thread &thread,
-                            Address &function,
+                            const Address &function,
                             const ClangASTType &return_type,
                             lldb::addr_t arg,
                             bool stop_other_threads,
@@ -37,7 +37,7 @@ public:
                             lldb::addr_t *cmd_arg = 0);
 
     ThreadPlanCallFunction (Thread &thread,
-                            Address &function,
+                            const Address &function,
                             const ClangASTType &return_type,
                             bool stop_other_threads,
                             bool unwind_on_error,
index b3feb8e65f2d4fcf140f5b17b10a3b377a60e32d..fb246ec29d1e1d46e9a8c21c5c2c3dd9202a9a15 100644 (file)
@@ -455,6 +455,7 @@ namespace lldb {
         eSymbolTypeInvalid = 0,
         eSymbolTypeAbsolute,
         eSymbolTypeCode,
+        eSymbolTypeResolver,
         eSymbolTypeData,
         eSymbolTypeTrampoline,
         eSymbolTypeRuntime,
index 66093bcc2e100587bf627912819eb7ffae6f51f0..abde4ac42c94ebcbeb65ed19e792fcaf4e07ea55 100644 (file)
@@ -311,8 +311,15 @@ Address::GetLoadAddress (Target *target) const
 }
 
 addr_t
-Address::GetCallableLoadAddress (Target *target) const
+Address::GetCallableLoadAddress (Target *target, bool is_indirect) const
 {
+    if (is_indirect && target) {
+        ProcessSP processSP = target->GetProcessSP();
+        Error error;
+        if (processSP.get())
+            return processSP->ResolveIndirectFunction(this, error);
+    }
+
     addr_t code_addr = GetLoadAddress (target);
 
     if (target)
index 953a81bfdbe03b88db823a6f33dfecbb270f3d3d..2341144132b100269bf4f91353cebef2816ea1f9 100644 (file)
@@ -606,7 +606,7 @@ Module::FindFunctions (const ConstString &name,
             if (symtab)
             {
                 std::vector<uint32_t> symbol_indexes;
-                symtab->FindAllSymbolsWithNameAndType (name, eSymbolTypeCode, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
+                symtab->FindAllSymbolsWithNameAndType (name, eSymbolTypeAny, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
                 const size_t num_matches = symbol_indexes.size();
                 if (num_matches)
                 {
@@ -615,7 +615,10 @@ Module::FindFunctions (const ConstString &name,
                     for (size_t i=0; i<num_matches; i++)
                     {
                         sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
-                        sc_list.AppendIfUnique (sc, merge_symbol_into_function);
+                        SymbolType sym_type = sc.symbol->GetType();
+                        if (sc.symbol && (sym_type == eSymbolTypeCode ||
+                                          sym_type == eSymbolTypeResolver))
+                            sc_list.AppendIfUnique (sc, merge_symbol_into_function);
                     }
                 }
             }
@@ -649,7 +652,7 @@ Module::FindFunctions (const RegularExpression& regex,
             if (symtab)
             {
                 std::vector<uint32_t> symbol_indexes;
-                symtab->AppendSymbolIndexesMatchingRegExAndType (regex, eSymbolTypeCode, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
+                symtab->AppendSymbolIndexesMatchingRegExAndType (regex, eSymbolTypeAny, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
                 const size_t num_matches = symbol_indexes.size();
                 if (num_matches)
                 {
@@ -658,7 +661,10 @@ Module::FindFunctions (const RegularExpression& regex,
                     for (size_t i=0; i<num_matches; i++)
                     {
                         sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
-                        sc_list.AppendIfUnique (sc, merge_symbol_into_function);
+                        SymbolType sym_type = sc.symbol->GetType();
+                        if (sc.symbol && (sym_type == eSymbolTypeCode ||
+                                          sym_type == eSymbolTypeResolver))
+                            sc_list.AppendIfUnique (sc, merge_symbol_into_function);
                     }
                 }
             }
index db1ef1684dd4c9e736dd256c75ebcae32c16eb33..6bcab76114394b57fa7e207023209177536be45f 100644 (file)
@@ -696,11 +696,32 @@ FindCodeSymbolInContext
     SymbolContextList &sc_list
 )
 {
+    SymbolContextList temp_sc_list;
     if (sym_ctx.module_sp)
-       sym_ctx.module_sp->FindSymbolsWithNameAndType(name, eSymbolTypeCode, sc_list);
+        sym_ctx.module_sp->FindSymbolsWithNameAndType(name, eSymbolTypeAny, temp_sc_list);
     
-    if (!sc_list.GetSize())
-        sym_ctx.target_sp->GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeCode, sc_list);
+    if (!sc_list.GetSize() && sym_ctx.target_sp)
+        sym_ctx.target_sp->GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny, temp_sc_list);
+
+    unsigned temp_sc_list_size = temp_sc_list.GetSize();
+    for (unsigned i = 0; i < temp_sc_list_size; i++)
+    {
+        SymbolContext sym_ctx;
+        temp_sc_list.GetContextAtIndex(i, sym_ctx);
+        if (sym_ctx.symbol)
+        {
+            switch (sym_ctx.symbol->GetType())
+            {
+                case eSymbolTypeCode:
+                case eSymbolTypeResolver:
+                    sc_list.Append(sym_ctx);
+                    break;
+
+                default:
+                    break;
+            }
+        }
+    }
 }
 
 bool
@@ -724,7 +745,7 @@ ClangExpressionDeclMap::GetFunctionAddress
     SymbolContextList sc_list;
     
     FindCodeSymbolInContext(name, m_parser_vars->m_sym_ctx, sc_list);
-        
+
     if (!sc_list.GetSize())
     {
         // We occasionally get debug information in which a const function is reported 
@@ -746,23 +767,25 @@ ClangExpressionDeclMap::GetFunctionAddress
     
     if (!sc_list.GetSize())
         return false;
-    
+
     SymbolContext sym_ctx;
     sc_list.GetContextAtIndex(0, sym_ctx);
-    
+
     const Address *func_so_addr = NULL;
-    
+    bool is_indirect_function = false;
+
     if (sym_ctx.function)
         func_so_addr = &sym_ctx.function->GetAddressRange().GetBaseAddress();
-    else if (sym_ctx.symbol)
+    else if (sym_ctx.symbol) {
         func_so_addr = &sym_ctx.symbol->GetAddress();
-    else
+        is_indirect_function = sym_ctx.symbol->IsIndirect();
+    } else
         return false;
-    
+
     if (!func_so_addr || !func_so_addr->IsValid())
         return false;
-    
-    func_addr = func_so_addr->GetCallableLoadAddress (target);
+
+    func_addr = func_so_addr->GetCallableLoadAddress (target, is_indirect_function);
 
     return true;
 }
@@ -795,7 +818,11 @@ ClangExpressionDeclMap::GetSymbolAddress (Target &target, Process *process, cons
                 case eSymbolTypeTrampoline:
                     symbol_load_addr = sym_address->GetCallableLoadAddress (&target);
                     break;
-                    
+
+                case eSymbolTypeResolver:
+                    symbol_load_addr = sym_address->GetCallableLoadAddress (&target, true);
+                    break;
+
                 case eSymbolTypeData:
                 case eSymbolTypeRuntime:
                 case eSymbolTypeVariable:
@@ -2467,6 +2494,7 @@ ClangExpressionDeclMap::FindGlobalDataSymbol (Target &target,
                     case eSymbolTypeCompiler:
                     case eSymbolTypeInstrumentation:
                     case eSymbolTypeUndefined:
+                    case eSymbolTypeResolver:
                         break;
                 }
             }
@@ -3540,7 +3568,9 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
     // only valid for Functions, not for Symbols
     void *fun_opaque_type = NULL;
     ASTContext *fun_ast_context = NULL;
-    
+
+    bool is_indirect_function = false;
+
     if (fun)
     {
         Type *fun_type = fun->GetType();
@@ -3586,6 +3616,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
     {
         fun_address = &symbol->GetAddress();
         fun_decl = context.AddGenericFunDecl();
+        is_indirect_function = symbol->IsIndirect();
     }
     else
     {
@@ -3596,7 +3627,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
     
     Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
 
-    lldb::addr_t load_addr = fun_address->GetCallableLoadAddress(target);
+    lldb::addr_t load_addr = fun_address->GetCallableLoadAddress(target, is_indirect_function);
     fun_location->SetValueType(Value::eValueTypeLoadAddress);
     fun_location->GetScalar() = load_addr;
     
index 2cee5c01da987850f3cacc1bd8f97163c15b80e1..42bfefe8d625864de207fa1fbfa9d12b50cdd57c 100644 (file)
@@ -784,6 +784,12 @@ ParseSymbols(Symtab *symtab,
                 // STB_LOCAL symbols for the file, if it is present.
                 symbol_type = eSymbolTypeObjectFile;
                 break;
+
+            case STT_GNU_IFUNC:
+                // The symbol is associated with an indirect function. The actual
+                // function will be resolved if it is referenced.
+                symbol_type = eSymbolTypeResolver;
+                break;
             }
         }
 
index c65f95c883d216248746ab8df5a5d5fc1ebf7ab4..0a741bca1debf5a2c87968bee1cb1d5d9c606993 100644 (file)
@@ -483,6 +483,19 @@ ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr)
     return error;
 }
 
+addr_t
+ProcessPOSIX::ResolveIndirectFunction(const Address *address, Error &error)
+{
+    addr_t function_addr = LLDB_INVALID_ADDRESS;
+    if (address == NULL) {
+        error.SetErrorStringWithFormat("unable to determine direct function call for NULL address");
+    } else if (!InferiorCall(this, address, function_addr)) {
+        function_addr = LLDB_INVALID_ADDRESS;
+        error.SetErrorStringWithFormat("unable to determine direct function call for indirect function with address %x", address);
+    }
+    return function_addr;
+}
+
 size_t
 ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
 {
index d12e063c312f4d0e75a5c843df876c2350a9eb8a..068686df99f31b273d86f59dab51bee9a2488c07 100644 (file)
@@ -96,6 +96,9 @@ public:
     virtual lldb_private::Error
     DoDeallocateMemory(lldb::addr_t ptr);
 
+    virtual lldb::addr_t
+    ResolveIndirectFunction(const lldb_private::Address *address, lldb_private::Error &error);
+
     virtual size_t
     GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site);
 
index 905ab2514467bd29fb7e2de5b3a7b4229b147a34..ba1d3b6eb9500033d50a78c4a5d39845bcc5283a 100644 (file)
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "InferiorCallPOSIX.h"
+#include "lldb/Core/Address.h"
 #include "lldb/Core/StreamFile.h"
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Symbol/ClangASTContext.h"
@@ -119,6 +120,11 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
                                 if (allocated_addr == UINT32_MAX)
                                     return false;
                             }
+                            else if (process->GetAddressByteSize() == 8)
+                            {
+                                if (allocated_addr == UINT64_MAX)
+                                    return false;
+                            }
                             return true;
                         }
                     }
@@ -203,3 +209,66 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
 
    return false;
 }
+
+bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) {
+    Thread *thread = process->GetThreadList().GetSelectedThread().get();
+    if (thread == NULL || address == NULL)
+        return false;
+
+    const bool stop_other_threads = true;
+    const bool unwind_on_error = true;
+    const bool ignore_breakpoints = true;
+    const bool try_all_threads = true;
+    const uint32_t timeout_usec = 500000;
+
+    ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+    lldb::clang_type_t clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false);
+    ThreadPlanCallFunction *call_function_thread_plan
+        = new ThreadPlanCallFunction (*thread,
+                                      *address,
+                                      ClangASTType (clang_ast_context->getASTContext(), clang_void_ptr_type),
+                                      stop_other_threads,
+                                      unwind_on_error,
+                                      ignore_breakpoints);
+    lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+    if (call_plan_sp)
+    {
+        StreamFile error_strm;
+        // This plan is a utility plan, so set it to discard itself when done.
+        call_plan_sp->SetIsMasterPlan (true);
+        call_plan_sp->SetOkayToDiscard(true);
+
+        StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+        if (frame)
+        {
+            ExecutionContext exe_ctx;
+            frame->CalculateExecutionContext (exe_ctx);
+            ExecutionResults result = process->RunThreadPlan (exe_ctx,
+                                                              call_plan_sp,
+                                                              stop_other_threads,
+                                                              try_all_threads,
+                                                              unwind_on_error,
+                                                              ignore_breakpoints,
+                                                              timeout_usec,
+                                                              error_strm);
+            if (result == eExecutionCompleted)
+            {
+                returned_func = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+
+                if (process->GetAddressByteSize() == 4)
+                {
+                    if (returned_func == UINT32_MAX)
+                        return false;
+                }
+                else if (process->GetAddressByteSize() == 8)
+                {
+                    if (returned_func == UINT64_MAX)
+                        return false;
+                }
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
index a85db72ec036719b31114b80d1cee25227e5f96c..d8b6d0ed57fd34d900b55a5d7a2544c85c17d60b 100644 (file)
@@ -36,6 +36,8 @@ bool InferiorCallMmap(Process *proc, lldb::addr_t &allocated_addr,
 
 bool InferiorCallMunmap(Process *proc, lldb::addr_t addr, lldb::addr_t length);
 
+bool InferiorCall(Process *proc, const Address *address, lldb::addr_t &returned_func);
+
 }   // namespace lldb_private
 
 #endif  // lldb_InferiorCallPOSIX_h_
index db4ceb24c805c2f14cb1e1fad15f3bcef99346c8..0fe0ceb57d7c0d28a6726bb596049174e6de2496 100644 (file)
@@ -184,6 +184,12 @@ Symbol::IsTrampoline () const
     return m_type == eSymbolTypeTrampoline;
 }
 
+bool
+Symbol::IsIndirect () const
+{
+    return m_type == eSymbolTypeResolver;
+}
+
 void
 Symbol::GetDescription (Stream *s, lldb::DescriptionLevel level, Target *target) const
 {
@@ -273,7 +279,7 @@ Symbol::Dump(Stream *s, Target *target, uint32_t index) const
 uint32_t
 Symbol::GetPrologueByteSize ()
 {
-    if (m_type == eSymbolTypeCode)
+    if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver)
     {
         if (!m_type_data_resolved)
         {
index c48f4fb7fe926839f8071061b397fdff721691dd..9247bcee6a2ee55da43796bbc3a1bfb675b4fd69 100644 (file)
@@ -119,7 +119,7 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
 }
 
 ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
-                                                Address &function,
+                                                const Address &function,
                                                 const ClangASTType &return_type,
                                                 addr_t arg,
                                                 bool stop_other_threads,
@@ -182,7 +182,7 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
 
 
 ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
-                                                Address &function,
+                                                const Address &function,
                                                 const ClangASTType &return_type,
                                                 bool stop_other_threads,
                                                 bool unwind_on_error,
index 0a1a826674a0580a5db02a534d791779c802a276..481f8b01cfef58b45dfc4e344986c783eed4892a 100644 (file)
@@ -16,7 +16,6 @@ class CStringsTestCase(TestBase):
         self.buildDsym()
         self.static_method_commands()
 
-    @expectedFailureLinux # bugzilla 14437
     @dwarf_test
     def test_with_dwarf_and_run_command(self):
         """Tests that C strings work as expected in expressions"""
@@ -43,6 +42,7 @@ class CStringsTestCase(TestBase):
         self.expect("expression -- z[2]",
                     startstr = "(const char) $1 = 'x'")
 
+        # On Linux, the expression below will test GNU indirect function calls.
         self.expect("expression -- (int)strlen(\"hello\")",
                     startstr = "(int) $2 = 5")