Add GNU indirect function support in expressions for Linux.

llvm-svn: 176206
diff --git a/lldb/source/Core/Address.cpp b/lldb/source/Core/Address.cpp
index 66093bc..abde4ac 100644
--- a/lldb/source/Core/Address.cpp
+++ b/lldb/source/Core/Address.cpp
@@ -311,8 +311,15 @@
 }
 
 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)
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 953a81b..2341144 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -606,7 +606,7 @@
             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 @@
                     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 @@
             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 @@
                     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);
                     }
                 }
             }
diff --git a/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp
index db1ef16..6bcab76 100644
--- a/lldb/source/Expression/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp
@@ -696,11 +696,32 @@
     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 @@
     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 @@
     
     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 @@
                 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 @@
                     case eSymbolTypeCompiler:
                     case eSymbolTypeInstrumentation:
                     case eSymbolTypeUndefined:
+                    case eSymbolTypeResolver:
                         break;
                 }
             }
@@ -3540,7 +3568,9 @@
     // 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 @@
     {
         fun_address = &symbol->GetAddress();
         fun_decl = context.AddGenericFunDecl();
+        is_indirect_function = symbol->IsIndirect();
     }
     else
     {
@@ -3596,7 +3627,7 @@
     
     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;
     
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 2cee5c0..42bfefe 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -784,6 +784,12 @@
                 // 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;
             }
         }
 
diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
index c65f95c..0a741bc 100644
--- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -483,6 +483,19 @@
     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)
 {
diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h
index d12e063..068686d 100644
--- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h
+++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h
@@ -96,6 +96,9 @@
     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);
 
diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index 905ab25..ba1d3b6 100644
--- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -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 @@
                                 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 @@
 
    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;
+}
diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h
index a85db72..d8b6d0e 100644
--- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h
+++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h
@@ -36,6 +36,8 @@
 
 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_
diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp
index db4ceb2..0fe0ceb 100644
--- a/lldb/source/Symbol/Symbol.cpp
+++ b/lldb/source/Symbol/Symbol.cpp
@@ -184,6 +184,12 @@
     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 @@
 uint32_t
 Symbol::GetPrologueByteSize ()
 {
-    if (m_type == eSymbolTypeCode)
+    if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver)
     {
         if (!m_type_data_resolved)
         {
diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp
index c48f4fb..9247bce 100644
--- a/lldb/source/Target/ThreadPlanCallFunction.cpp
+++ b/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -119,7 +119,7 @@
 }
 
 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,
-                                                Address &function,
+                                                const Address &function,
                                                 const ClangASTType &return_type,
                                                 bool stop_other_threads,
                                                 bool unwind_on_error,