[ELF] --gdb-index: use lower_bound to compute relative CU index in the object file

Summary:
This reinstates what I originally intended to do in D54361.
It removes the assumption that .debug_gnu_pubnames has increasing CuOffset.

Now we do better than gold here: when .debug_gnu_pubnames contains
multiple sets, gold would think every set has the same CU index as the
first set (incorrect).

Reviewed By: ruiu

Reviewers: ruiu, dblaikie, espindola

Subscribers: emaste, arichardson, arphaman, llvm-commits

Differential Revision: https://reviews.llvm.org/D54483

git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@347820 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index c2eeaf5..a0dab23 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -2434,16 +2434,17 @@
   std::vector<GdbIndexSection::NameAttrEntry> Ret;
   for (const DWARFSection *Pub : {&PubNames, &PubTypes}) {
     DWARFDebugPubTable Table(Obj, *Pub, Config->IsLE, true);
-    uint32_t I = 0;
     for (const DWARFDebugPubTable::Set &Set : Table.getData()) {
       // The value written into the constant pool is Kind << 24 | CuIndex. As we
       // don't know how many compilation units precede this object to compute
       // CuIndex, we compute (Kind << 24 | CuIndexInThisObject) instead, and add
       // the number of preceding compilation units later.
-      //
-      // We assume both CUs[*].CuOff and Set.Offset are increasing.
-      while (I < CUs.size() && CUs[I].CuOffset < Set.Offset)
-        ++I;
+      uint32_t I =
+          lower_bound(CUs, Set.Offset,
+                      [](GdbIndexSection::CuEntry CU, uint32_t Offset) {
+                        return CU.CuOffset < Offset;
+                      }) -
+          CUs.begin();
       for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
         Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)},
                        (Ent.Descriptor.toBits() << 24) | I});
diff --git a/test/ELF/gdb-index-multiple-cu.s b/test/ELF/gdb-index-multiple-cu.s
index fc1d83e..9a8c2ea 100644
--- a/test/ELF/gdb-index-multiple-cu.s
+++ b/test/ELF/gdb-index-multiple-cu.s
@@ -3,20 +3,27 @@
 # RUN: ld.lld --gdb-index %t.o -o %t
 # RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s
 
-# Attributes << 24 | CuIndex = 48 << 24 | 1 = 0x30000001
-# CHECK: Constant pool
-# CHECK-NEXT: 0(0x0): 0x30000001
+# CuIndexAndAttrs of _start:
+#   Attributes << 24 | CuIndex = 48 << 24 | 0 = 0x30000000
+# CuIndexAndAttrs of foo:
+#   Attributes << 24 | CuIndex = 48 << 24 | 1 = 0x30000001
+# CHECK:      Symbol table
+# CHECK-DAG:      String name: _start, CU vector index: 0
+# CHECK-DAG:      String name: foo, CU vector index: 1
+# CHECK:      Constant pool
+# CHECK-NEXT:   0(0x0): 0x30000000
+# CHECK-NEXT:   1(0x8): 0x30000001
 
-.globl _start
+.globl _start, foo
 _start:
-	ret
+foo:
 
 .section .debug_abbrev,"",@progbits
 	.byte	1              # Abbreviation Code
 	.byte	17             # DW_TAG_compile_unit
 	.byte	1              # DW_CHILDREN_yes
 	.ascii	"\264B"        # DW_AT_GNU_pubnames
-	.byte	12             # DW_FORM_flag
+	.byte	25             # DW_FORM_flag_present
 	.byte	0              # EOM(1)
 	.byte	0              # EOM(2)
 	.byte	2              # Abbreviation Code
@@ -34,8 +41,11 @@
 	.short	4              # DWARF version number
 	.long	0              # Offset Into Abbrev. Section
 	.byte	4              # Address Size
+.Ldie0:
 	.byte	1              # Abbrev [1] DW_TAG_compile_unit
-	.byte	0              # DW_AT_GNU_pubnames
+	.byte	2              # Abbrev [2] DW_TAG_subprogram
+	.asciz	"_start"       # DW_AT_name
+	.byte	0
 	.byte	0
 .Lcu_end0:
 .Lcu_begin1:
@@ -43,23 +53,36 @@
 	.short	4              # DWARF version number
 	.long	0              # Offset Into Abbrev. Section
 	.byte	4              # Address Size
-.Ldie:
+.Ldie1:
 	.byte	1              # Abbrev [1] DW_TAG_compile_unit
-	.byte	1              # DW_AT_GNU_pubnames
 	.byte	2              # Abbrev [2] DW_TAG_subprogram
-	.asciz	"_start"       # DW_AT_name
+	.asciz	"foo"          # DW_AT_name
 	.byte	0
 .Lcu_end1:
 
-# .debug_gnu_pubnames has just one set, associated with .Lcu_begin1 (CuIndex: 1)
+# Swap sets to test the case where pubnames are in a
+# different order than the CUs they refer to.
 .section .debug_gnu_pubnames,"",@progbits
-	.long	.LpubNames_end1-.LpubNames_begin1
+	# CuIndex: 1
+	.long	.LpubNames_end1 - .LpubNames_begin1
 .LpubNames_begin1:
 	.short	2              # Version
 	.long	.Lcu_begin1    # CU Offset
 	.long	.Lcu_end1 - .Lcu_begin1
-	.long	.Ldie - .Lcu_begin1
+	.long	.Ldie1 - .Lcu_begin1
+	.byte	48             # Attributes: FUNCTION, EXTERNAL
+	.asciz	"foo"          # External Name
+	.long	0
+.LpubNames_end1:
+
+	# CuIndex: 0
+	.long	.LpubNames_end0 - .LpubNames_begin0
+.LpubNames_begin0:
+	.short	2              # Version
+	.long	.Lcu_begin0    # CU Offset
+	.long	.Lcu_end0 - .Lcu_begin0
+	.long	.Ldie0 - .Lcu_begin0
 	.byte	48             # Attributes: FUNCTION, EXTERNAL
 	.asciz	"_start"       # External Name
 	.long	0
-.LpubNames_end1:
+.LpubNames_end0: