When looking for symbols, find load addresses in a more robust way.

IRExecutionUnit previously replicated a bunch of logic that already
existed elsewhere for the purpose of getting a load address for a
symbol.  This approach failed to resolve certain types of symbols.
Instead, we now use functions on SymbolContext to do the address
resolution.

This is a cleanup of IRExecutionUnit::FindInSymbols, and also fixes a
latent bug where we looked at the wrong SymbolContext to determine
whether or not it is external.

<rdar://problem/24770829>

llvm-svn: 261704
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 5d8cc34..a209dd1 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -769,9 +769,62 @@
 lldb::addr_t
 IRExecutionUnit::FindInSymbols(const std::vector<IRExecutionUnit::SearchSpec> &specs, const lldb_private::SymbolContext &sc)
 {
+    Target *target = sc.target_sp.get();
+
+    if (!target)
+    {
+        // we shouldn't be doing any symbol lookup at all without a target
+        return LLDB_INVALID_ADDRESS;
+    }
+
     for (const SearchSpec &spec : specs)
     {
         SymbolContextList sc_list;
+
+        lldb::addr_t best_internal_load_address = LLDB_INVALID_ADDRESS;
+
+        std::function<bool (lldb::addr_t &, SymbolContextList &, const lldb_private::SymbolContext &)> get_external_load_address =
+            [&best_internal_load_address, target](lldb::addr_t &load_address,
+                                                  SymbolContextList &sc_list,
+                                                  const lldb_private::SymbolContext &sc) -> lldb::addr_t
+        {
+            load_address = LLDB_INVALID_ADDRESS;
+
+            for (size_t si = 0, se = sc_list.GetSize(); si < se; ++si)
+            {
+                SymbolContext candidate_sc;
+
+                sc_list.GetContextAtIndex(si, candidate_sc);
+
+                const bool is_external = (candidate_sc.function) ||
+                                         (candidate_sc.symbol && candidate_sc.symbol->IsExternal());
+
+                AddressRange range;
+
+                if (candidate_sc.GetAddressRange(lldb::eSymbolContextFunction | lldb::eSymbolContextSymbol,
+                                                 0,
+                                                 false,
+                                                 range))
+                {
+                    load_address = range.GetBaseAddress().GetCallableLoadAddress(target);
+
+                    if (load_address != LLDB_INVALID_ADDRESS)
+                    {
+                        if (is_external)
+                        {
+                            return true;
+                        }
+                        else if (best_internal_load_address == LLDB_INVALID_ADDRESS)
+                        {
+                            best_internal_load_address = load_address;
+                            load_address = LLDB_INVALID_ADDRESS;
+                        }
+                    }
+                }
+            }
+
+            return false;
+        };
         
         if (sc.module_sp)
         {
@@ -783,6 +836,17 @@
                                         true,  // append
                                         sc_list);
         }
+
+        lldb::addr_t load_address = LLDB_INVALID_ADDRESS;
+
+        if (get_external_load_address(load_address, sc_list, sc))
+        {
+            return load_address;
+        }
+        else
+        {
+            sc_list.Clear();
+        }
     
         if (sc_list.GetSize() == 0 && sc.target_sp)
         {
@@ -794,49 +858,26 @@
                                                     sc_list);
         }
         
+        if (get_external_load_address(load_address, sc_list, sc))
+        {
+            return load_address;
+        }
+        else
+        {
+            sc_list.Clear();
+        }
+
         if (sc_list.GetSize() == 0 && sc.target_sp)
         {
             sc.target_sp->GetImages().FindSymbolsWithNameAndType(spec.name, lldb::eSymbolTypeAny, sc_list);
         }
 
-        lldb::addr_t best_internal_load_address = LLDB_INVALID_ADDRESS;
-        
-        for (size_t si = 0, se = sc_list.GetSize(); si < se; ++si)
+        if (get_external_load_address(load_address, sc_list, sc))
         {
-            bool is_external = false;
-            
-            SymbolContext candidate_sc;
-            
-            sc_list.GetContextAtIndex(si, candidate_sc);
-            if (candidate_sc.function)
-            {
-                is_external = true;
-            }
-            else if (sc.symbol)
-            {
-                if (sc.symbol->IsExternal())
-                {
-                    is_external = true;
-                }
-            }
-            
-            lldb::addr_t load_address = candidate_sc.symbol->ResolveCallableAddress(*sc.target_sp);
-            
-            if (load_address == LLDB_INVALID_ADDRESS)
-                load_address = candidate_sc.symbol->GetAddress().GetLoadAddress(sc.target_sp.get());
-
-            if (load_address != LLDB_INVALID_ADDRESS)
-            {
-                if (is_external)
-                {
-                    return load_address;
-                }
-                else
-                {
-                    best_internal_load_address = load_address;
-                }
-            }
+            return load_address;
         }
+        // if there are any searches we try after this, add an sc_list.Clear() in an "else" clause here
+
         if (best_internal_load_address != LLDB_INVALID_ADDRESS)
         {
             return best_internal_load_address;