"info threads" changes the default source for "break" and "list", to
whatever the location of the first/bottom thread in the thread list
is...
 (gdb) b start
 (gdb) c
 ...
 (gdb) list
 *lists "start"*
 (gdb) b 23
 Breakpoint 3 at 0x400614: file test.c, line 23.
 (gdb) info threads
   Id   Target Id         Frame
 * 2    Thread 0x7ffff7fcb700 (LWP 1760) "test" start (arg=0x0) at test.c:23
   1    Thread 0x7ffff7fcc740 (LWP 1748) "test" 0x000000323dc08e60 in pthread_join (threadid=
140737353922304, thread_return=0x0) at pthread_join.c:93
 (gdb) b 23
 Breakpoint 4 at 0x323dc08d90: file pthread_join.c, line 23.
                                    ^^^^^^^^^^^^^^^
 (gdb) list
 93          lll_wait_tid (pd->tid);
 94
 95
 96        /* Restore cancellation mode.  */
 97        CANCEL_RESET (oldtype);
 98
 99        /* Remove the handler.  */
 100       pthread_cleanup_pop (0);
 101
 102
The issue is that print_stack_frame always sets the current sal to the
frame's sal.  print_frame_info (which print_stack_frame calls to do
most of the work) also sets the last displayed sal, but only if
print_what isn't LOCATION.  Now the call in question, from within
thread.c:print_thread_info, does pass in LOCATION as print_what, but
print_stack_frame doesn't have the same check print_frame_info has.
We could consider adding it, but setting these globals depending on
print_what isn't very clean, IMO.  What we have is two logically
distinct operations mixed in the same function(s):
  #1 - print frame, in the format specified by {print_what,
    print_level and print_args}.
  #2 - We're displaying a frame to the user, and I want the default
    sal to point here, because the program stopped here, or the user
    did some context-changing command (up, down, etc.).
So I added a new parameter to print_stack_frame & friends for point
#2, and went through all calls in the tree adjusting as necessary.
Tested on x86_64 Fedora 17.
gdb/
2013-09-17  Pedro Alves  <palves@redhat.com>
	PR gdb/15911
	* ada-tasks.c (task_command_1): Adjust call to print_stack_frame.
	* bsd-kvm.c (bsd_kvm_open, bsd_kvm_proc_cmd, bsd_kvm_pcb_cmd):
	* corelow.c (core_open):
	* frame.h (print_stack_frame, print_frame_info): New
	'set_current_sal' parameter.
	* infcmd.c (finish_command, kill_command): Adjust call to
	print_stack_frame.
	* inferior.c (inferior_command): Likewise.
	* infrun.c (normal_stop): Likewise.
	* linux-fork.c (linux_fork_context): Likewise.
	* record-full.c (record_full_goto_entry, record_full_restore):
	Likewise.
	* remote-mips.c (common_open): Likewise.
	* stack.c (print_stack_frame): New 'set_current_sal' parameter.
	Use it.
	(print_frame_info): New 'set_current_sal' parameter.  Set the last
	displayed sal depending on the new paremeter instead of looking at
	print_what.
	(backtrace_command_1, select_and_print_frame, frame_command)
	(current_frame_command, up_command, down_command): Adjust call to
	print_stack_frame.
	* thread.c (print_thread_info, restore_selected_frame)
	(do_captured_thread_select): Adjust call to print_stack_frame.
	* tracepoint.c (tfind_1): Likewise.
	* mi/mi-cmd-stack.c (mi_cmd_stack_list_frames)
	(mi_cmd_stack_info_frame): Likewise.
	* mi/mi-interp.c (mi_on_normal_stop): Likewise.
	* mi/mi-main.c (mi_cmd_exec_return, mi_cmd_trace_find): Likewise.
	gdb/testsuite/
	* gdb.threads/info-threads-cur-sal-2.c: New file.
	* gdb.threads/info-threads-cur-sal.c: New file.
	* gdb.threads/info-threads-cur-sal.exp: New file.
 
+2013-09-17  Pedro Alves  <palves@redhat.com>
+
+       PR gdb/15911
+       * ada-tasks.c (task_command_1): Adjust call to print_stack_frame.
+       * bsd-kvm.c (bsd_kvm_open, bsd_kvm_proc_cmd, bsd_kvm_pcb_cmd):
+       * corelow.c (core_open):
+       * frame.h (print_stack_frame, print_frame_info): New
+       'set_current_sal' parameter.
+       * infcmd.c (finish_command, kill_command): Adjust call to
+       print_stack_frame.
+       * inferior.c (inferior_command): Likewise.
+       * infrun.c (normal_stop): Likewise.
+       * linux-fork.c (linux_fork_context): Likewise.
+       * record-full.c (record_full_goto_entry, record_full_restore):
+       Likewise.
+       * remote-mips.c (common_open): Likewise.
+       * stack.c (print_stack_frame): New 'set_current_sal' parameter.
+       Use it.
+       (print_frame_info): New 'set_current_sal' parameter.  Set the last
+       displayed sal depending on the new paremeter instead of looking at
+       print_what.
+       (backtrace_command_1, select_and_print_frame, frame_command)
+       (current_frame_command, up_command, down_command): Adjust call to
+       print_stack_frame.
+       * thread.c (print_thread_info, restore_selected_frame)
+       (do_captured_thread_select): Adjust call to print_stack_frame.
+       * tracepoint.c (tfind_1): Likewise.
+       * mi/mi-cmd-stack.c (mi_cmd_stack_list_frames)
+       (mi_cmd_stack_info_frame): Likewise.
+       * mi/mi-interp.c (mi_on_normal_stop): Likewise.
+       * mi/mi-main.c (mi_cmd_exec_return, mi_cmd_trace_find): Likewise.
+
 2013-09-16  Sergio Durigan Junior  <sergiodj@redhat.com>
 
        * value.c (isvoid_internal_fn): Replace "parameter" with
 
   printf_filtered (_("[Switching to task %d]\n"), taskno);
   print_stack_frame (get_selected_frame (NULL),
                      frame_relative_level (get_selected_frame (NULL)),
-                    SRC_AND_LOC);
+                    SRC_AND_LOC, 1);
 }
 
 
 
   target_fetch_registers (get_current_regcache (), -1);
 
   reinit_frame_cache ();
-  print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC, 1);
 }
 
 static void
   target_fetch_registers (get_current_regcache (), -1);
 
   reinit_frame_cache ();
-  print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC, 1);
 }
 
 #endif
   target_fetch_registers (get_current_regcache (), -1);
 
   reinit_frame_cache ();
-  print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC, 1);
 }
 
 static int
 
 
   /* Now, set up the frame cache, and print the top of stack.  */
   reinit_frame_cache ();
-  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
 
 static void
 
 extern struct frame_info *find_relative_frame (struct frame_info *, int *);
 
 extern void print_stack_frame (struct frame_info *, int print_level,
-                              enum print_what print_what);
+                              enum print_what print_what,
+                              int set_current_sal);
 
 extern void print_frame_info (struct frame_info *, int print_level,
-                             enum print_what print_what, int args);
+                             enum print_what print_what, int args,
+                             int set_current_sal);
 
 extern struct frame_info *block_innermost_frame (const struct block *);
 
 
       if (from_tty)
        {
          printf_filtered (_("Run till exit from "));
-         print_stack_frame (get_selected_frame (NULL), 1, LOCATION);
+         print_stack_frame (get_selected_frame (NULL), 1, LOCATION, 0);
        }
 
       proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 1);
       else
        printf_filtered (_("Run till exit from "));
 
-      print_stack_frame (get_selected_frame (NULL), 1, LOCATION);
+      print_stack_frame (get_selected_frame (NULL), 1, LOCATION, 0);
     }
 
   if (execution_direction == EXEC_REVERSE)
       if (target_has_stack)
        {
          printf_filtered (_("In %s,\n"), target_longname);
-         print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+         print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
        }
     }
   bfd_cache_close_all ();
 
   else if (inf->pid != 0)
     {
       ui_out_text (current_uiout, "\n");
-      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
     }
 }
 
 
             LOCATION: Print only location
             SRC_AND_LOC: Print location and source line.  */
          if (do_frame_printing)
-           print_stack_frame (get_selected_frame (NULL), 0, source_flag);
+           print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
 
          /* Display the auto-display expressions.  */
          do_displays ();
 
   printf_filtered (_("Switching to %s\n"),
                   target_pid_to_str (inferior_ptid));
 
-  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
 
 /* Switch inferior process (checkpoint) context, by checkpoint id.  */
 
          QUIT;
          /* Print the location and the address always, even for level 0.
             If args is 0, don't print the arguments.  */
-         print_frame_info (fi, 1, LOC_AND_ADDRESS, 0 /* args */ );
+         print_frame_info (fi, 1, LOC_AND_ADDRESS, 0 /* args */, 0);
        }
     }
 
   if (argc > 0)
     error (_("-stack-info-frame: No arguments allowed"));
 
-  print_frame_info (get_selected_frame (NULL), 1, LOC_AND_ADDRESS, 0);
+  print_frame_info (get_selected_frame (NULL), 1, LOC_AND_ADDRESS, 0, 1);
 }
 
          get_last_target_status (&last_ptid, &last);
          bpstat_print (bs, last.kind);
 
-         print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC);
+         print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC, 1);
          current_uiout = saved_uiout;
        }
 
 
 
   /* Because we have called return_command with from_tty = 0, we need
      to print the frame here.  */
-  print_stack_frame (get_selected_frame (NULL), 1, LOC_AND_ADDRESS);
+  print_stack_frame (get_selected_frame (NULL), 1, LOC_AND_ADDRESS, 1);
 }
 
 void
     error (_("Invalid mode '%s'"), mode);
 
   if (has_stack_frames () || get_traceframe_number () >= 0)
-    print_stack_frame (get_selected_frame (NULL), 1, LOC_AND_ADDRESS);
+    print_stack_frame (get_selected_frame (NULL), 1, LOC_AND_ADDRESS, 1);
 }
 
 void
 
 
   registers_changed ();
   reinit_frame_cache ();
-  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
 
 /* The "to_goto_record_begin" target method.  */
   printf_filtered (_("Restored records from core file %s.\n"),
                   bfd_get_filename (core_bfd));
 
-  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
 
 /* bfdcore_write -- write bytes into a core file section.  */
 
   reinit_frame_cache ();
   registers_changed ();
   stop_pc = regcache_read_pc (get_current_regcache ());
-  print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC, 1);
   xfree (serial_port_name);
 
   do_cleanups (cleanup);
 
 
 void
 print_stack_frame (struct frame_info *frame, int print_level,
-                  enum print_what print_what)
+                  enum print_what print_what,
+                  int set_current_sal)
 {
   volatile struct gdb_exception e;
 
     {
       int center = (print_what == SRC_LINE || print_what == SRC_AND_LOC);
 
-      print_frame_info (frame, print_level, print_what, 1 /* print_args */);
-      set_current_sal_from_frame (frame, center);
+      print_frame_info (frame, print_level, print_what, 1 /* print_args */,
+                       set_current_sal);
+      if (set_current_sal)
+       set_current_sal_from_frame (frame, center);
     }
 }
 
 
 void
 print_frame_info (struct frame_info *frame, int print_level,
-                 enum print_what print_what, int print_args)
+                 enum print_what print_what, int print_args,
+                 int set_current_sal)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   struct symtab_and_line sal;
        do_gdb_disassembly (get_frame_arch (frame), -1, sal.pc, sal.end);
     }
 
-  if (print_what != LOCATION)
+  if (set_current_sal)
     {
       CORE_ADDR pc;
 
             hand, perhaps the code does or could be fixed to make sure
             the frame->prev field gets set to NULL in that case).  */
 
-         print_frame_info (fi, 1, LOCATION, 1);
+         print_frame_info (fi, 1, LOCATION, 1, 0);
          if (show_locals)
            {
              struct frame_id frame_id = get_frame_id (fi);
 {
   select_frame (frame);
   if (frame)
-    print_stack_frame (frame, 1, SRC_AND_LOC);
+    print_stack_frame (frame, 1, SRC_AND_LOC, 1);
 }
 \f
 /* Return the symbol-block in which the selected frame is executing.
 frame_command (char *level_exp, int from_tty)
 {
   select_frame_command (level_exp, from_tty);
-  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
 
 /* The XDB Compatibility command to print the current frame.  */
 static void
 current_frame_command (char *level_exp, int from_tty)
 {
-  print_stack_frame (get_selected_frame (_("No stack.")), 1, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (_("No stack.")), 1, SRC_AND_LOC, 1);
 }
 
 /* Select the frame up one or COUNT_EXP stack levels from the
 up_command (char *count_exp, int from_tty)
 {
   up_silently_base (count_exp);
-  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
 
 /* Select the frame down one or COUNT_EXP stack levels from the previously
 down_command (char *count_exp, int from_tty)
 {
   down_silently_base (count_exp);
-  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
 \f
 
 
+2013-09-17  Pedro Alves  <palves@redhat.com>
+
+       PR gdb/15911
+       * gdb.threads/info-threads-cur-sal-2.c: New file.
+       * gdb.threads/info-threads-cur-sal.c: New file.
+       * gdb.threads/info-threads-cur-sal.exp: New file.
+
 2013-09-17  Yao Qi  <yao@codesourcery.com>
 
        * gdb.base/catch-load.c: Remove the include of "dlfcn.h".
 
--- /dev/null
+/* Copyright 2013 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 <stddef.h>
+
+void *
+start (void *arg)
+{
+  /* "list" should show this line.  */
+  return NULL;
+}
 
--- /dev/null
+/* Copyright 2007-2013 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 <pthread.h>
+#include <assert.h>
+#include <unistd.h>
+
+extern void *start (void *arg);
+
+int
+main (void)
+{
+  pthread_t thread;
+  int i;
+
+  i = pthread_create (&thread, NULL, start, NULL);
+  assert (i == 0);
+  pthread_join (thread, NULL);
+
+  return 0;
+}
 
--- /dev/null
+# Copyright (C) 2013 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/>.
+
+standard_testfile info-threads-cur-sal.c info-threads-cur-sal-2.c
+
+set executable ${testfile}
+
+if {[gdb_compile_pthreads \
+        "${srcdir}/${subdir}/${srcfile} ${srcdir}/${subdir}/${srcfile2}" \
+        "${binfile}" executable {debug}] != "" } {
+    return -1
+}
+
+clean_restart ${executable}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_breakpoint "start"
+gdb_continue_to_breakpoint "start"
+
+set line [gdb_get_line_number "should show this line" "${srcfile2}"]
+
+gdb_test "list $line" \
+    "\"list\" should show this line.*" \
+    "list before info threads"
+
+# There used to be a bug where "info threads" would set the current
+# SAL to the location of the last thread displayed.
+gdb_test "info threads" \
+    "\r\n\[ \t\]*Id\[ \t\]+Target\[ \t\]+Id\[ \t\]+Frame\[ \t\]*\r\n\\* 2 *Thread \[^\r\n\]* at \[^\r\n\]*\r\n  1 *Thread \[^\r\n\]* .* \[^\r\n\]*" \
+    "info threads before break"
+
+# Check that "break" is still operating on the same file by default.
+gdb_test "break $line" ".*${srcfile2}.*" "break on line"
+
+gdb_test "info threads" \
+    "\r\n\[ \t\]*Id\[ \t\]+Target\[ \t\]+Id\[ \t\]+Frame\[ \t\]*\r\n\\* 2 *Thread \[^\r\n\]* at \[^\r\n\]*\r\n  1 *Thread \[^\r\n\]* .* \[^\r\n\]*" \
+    "info threads before list"
+
+# And that so is "list".
+gdb_test "list $line" \
+    "\"list\" should show this line.*" \
+    "list after info threads"
 
          print_stack_frame (get_selected_frame (NULL),
                             /* For MI output, print frame level.  */
                             ui_out_is_mi_like_p (uiout),
-                            LOCATION);
+                            LOCATION, 0);
        }
 
       if (ui_out_is_mi_like_p (uiout))
       /* For MI, we should probably have a notification about
         current frame change.  But this error is not very
         likely, so don't bother for now.  */
-      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
     }
 }
 
   else
     {
       ui_out_text (uiout, "\n");
-      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
     }
 
   /* Since the current thread may have changed, see if there is any
 
       else
        print_what = SRC_AND_LOC;
 
-      print_stack_frame (get_selected_frame (NULL), 1, print_what);
+      print_stack_frame (get_selected_frame (NULL), 1, print_what, 1);
       do_displays ();
     }
 }