diff --git a/gdb/symtab.c b/gdb/symtab.c
index 5671953..063c59f 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3046,8 +3046,6 @@ find_symbol_at_address (CORE_ADDR address)
    find the one whose first PC is closer than that of the next line in this
    symtab.  */
 
-/* If it's worth the effort, we could be using a binary search.  */
-
 struct symtab_and_line
 find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
 {
@@ -3206,23 +3204,25 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
 	  continue;
 	}
 
-      prev = NULL;
-      item = l->item;		/* Get first line info.  */
+	prev = NULL;
+	item = l->item;		/* Get first line info.  */
 
-      /* Is this file's first line closer than the first lines of other files?
-         If so, record this file, and its first line, as best alternate.  */
-      if (item->pc > pc && (!alt || item->pc < alt->pc))
-	alt = item;
+	/* Is this file's first line closer than the first lines of other files?
+	   If so, record this file, and its first line, as best alternate.  */
+	if (item->pc > pc && (!alt || item->pc < alt->pc))
+		alt = item;
 
-      for (i = 0; i < len; i++, item++)
+	auto PCCompare = [](const CORE_ADDR &pc,
+			    const struct linetable_entry &lhs) -> bool
 	{
-	  /* Leave prev pointing to the linetable entry for the last line
-	     that started at or before PC.  */
-	  if (item->pc > pc)
-	    break;
+		return pc < lhs.pc;
+	};
 
-	  prev = item;
-	}
+	struct linetable_entry *first = item;
+	struct linetable_entry *last = item + len;
+	item = std::upper_bound (first, last, pc, PCCompare);
+	if (item != first)
+	prev = item - 1; /* Found a matching item.  */
 
       /* At this point, prev points at the line whose start addr is <= pc, and
          item points at the next line.  If we ran off the end of the linetable
@@ -3247,7 +3247,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
       /* If another line (denoted by ITEM) is in the linetable and its
          PC is after BEST's PC, but before the current BEST_END, then
 	 use ITEM's PC as the new best_end.  */
-      if (best && i < len && item->pc > best->pc
+      if (best && item < last && item->pc > best->pc
           && (best_end == 0 || best_end > item->pc))
 	best_end = item->pc;
     }
diff --git a/gdb/testsuite/gdb.perf/template-breakpoints.cc b/gdb/testsuite/gdb.perf/template-breakpoints.cc
new file mode 100644
index 0000000..164c31e
--- /dev/null
+++ b/gdb/testsuite/gdb.perf/template-breakpoints.cc
@@ -0,0 +1,97 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright (C) 2016-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <iostream>
+
+template <int I, int J, int K, int VAL>
+struct ThirdDimension
+{
+  int
+  value () const
+  {
+    ThirdDimension<I, J, K - 1, VAL> d3;
+    return d3.value();
+  }
+};
+
+template <int I, int J, int VAL>
+struct ThirdDimension<I, J, 0, VAL>
+{
+  int
+  value () const
+  {
+    // Please note - this testcase sets a breakpoint on the following line.
+    // It is therefore sensitive to line numbers. If any changes are made to
+    // this file, please ensure that the testcase is updated to reflect this.
+    std::cout << "Value: " << VAL << std::endl;
+    return VAL;
+  }
+};
+
+template <int I, int J, int K, int VAL>
+struct SecondDimension
+{
+  int
+  value () const
+  {
+    SecondDimension<I, J - 1, K, VAL> d1;
+    ThirdDimension<I, J, K, VAL> d2;
+    return d1.value() + d2.value();
+  }
+};
+
+template <int I, int K, int VAL>
+struct SecondDimension<I, 0, K, VAL>
+{
+  int
+  value () const
+  {
+    ThirdDimension<I, 0, K, VAL> d2;
+    return d2.value();
+  }
+};
+
+template <int I, int J, int K, int VAL>
+struct FirstDimension
+{
+  int
+  value () const
+  {
+    FirstDimension<I - 1, J, K, VAL> d1;
+    SecondDimension<I, J, K, VAL> d2;
+    return d1.value() + d2.value();
+  }
+};
+
+template <int J, int K, int VAL>
+struct FirstDimension<0, J, K, VAL>
+{
+  int
+  value () const
+  {
+    SecondDimension<0, J, K, VAL> d2;
+    return d2.value();
+  }
+};
+
+int
+main (int argc, char *argv[])
+{
+  FirstDimension<EXPANSION_DEPTH, EXPANSION_DEPTH, EXPANSION_DEPTH, 1> product;
+  std::cout << product.value() << std::endl;
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.perf/template-breakpoints.exp b/gdb/testsuite/gdb.perf/template-breakpoints.exp
new file mode 100644
index 0000000..e9fb669
--- /dev/null
+++ b/gdb/testsuite/gdb.perf/template-breakpoints.exp
@@ -0,0 +1,65 @@
+# Copyright (C) 2016-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This test case is to test the performance of GDB when setting breakpoints
+# on heavily temlatized C++ code.
+
+# Parameters:
+# EXPANSION_DEPTH: knob to control how many times template expansions occur
+
+load_lib perftest.exp
+
+if [skip_perf_tests] {
+	return 0
+}
+
+standard_testfile .cc
+set executable $testfile
+set expfile $testfile.exp
+
+# make check-perf RUNTESTFLAGS='template-breakpoints.exp EXPANSION_DEPTH=40'
+if ![info exists EXPANSION_DEPTH] {
+	set EXPANSION_DEPTH 40
+}
+
+PerfTest::assemble {
+	global EXPANSION_DEPTH
+	global srcdir subdir srcfile
+
+	set compile_flags {c++ debug}
+	lappend compile_flags "additional_flags=-DEXPANSION_DEPTH=${EXPANSION_DEPTH}"
+
+	if { [gdb_compile "$srcdir/$subdir/$srcfile" ${binfile} executable $compile_flags] != ""} {
+		return -1
+	}
+
+	return 0
+} {
+	global binfile
+
+	clean_restart $binfile
+
+	if ![runto_main] {
+		fail "can't run to main"
+		return -1
+	}
+
+	return 0
+} {
+
+	gdb_test "python TemplateBreakpoints().run()"
+
+	return 0
+}
diff --git a/gdb/testsuite/gdb.perf/template-breakpoints.py b/gdb/testsuite/gdb.perf/template-breakpoints.py
new file mode 100644
index 0000000..27f74ce
--- /dev/null
+++ b/gdb/testsuite/gdb.perf/template-breakpoints.py
@@ -0,0 +1,33 @@
+# Copyright (C) 2016-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from perftest import perftest
+
+class TemplateBreakpoints (perftest.TestCaseWithBasicMeasurements):
+    def __init__(self):
+        super (TemplateBreakpoints, self).__init__ ("template-breakpoints")
+
+    def warm_up(self):
+        for _ in range(0, 2):
+            gdb.Breakpoint("template-breakpoints.cc:38").delete()
+
+    def _do_test(self, bpcount):
+        for _ in range(1, bpcount):
+            gdb.Breakpoint("template-breakpoints.cc:38").delete()
+
+    def execute_test(self):
+        for bpcount in range(1, 10):
+            tfunc = lambda bound_bpcount=bpcount: self._do_test(bound_bpcount)
+            self.measure.measure(tfunc, bpcount)
