From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11379 invoked by alias); 4 Jun 2009 16:43:28 -0000 Received: (qmail 11366 invoked by uid 22791); 4 Jun 2009 16:43:26 -0000 X-SWARE-Spam-Status: No, hits=-0.9 required=5.0 tests=AWL,BAYES_00,SPF_NEUTRAL X-Spam-Check-By: sourceware.org Received: from honeysuckle.london.02.net (HELO honeysuckle.london.02.net) (87.194.255.144) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 04 Jun 2009 16:43:17 +0000 Received: from elm.config (87.194.37.195) by honeysuckle.london.02.net (8.5.016.1) id 4A23EDE6002C8A6A; Thu, 4 Jun 2009 17:43:14 +0100 Date: Thu, 04 Jun 2009 16:43:00 -0000 From: Karen Osmond Reply-To: karen.osmond@gmail.com To: gdb-patches@sourceware.org Subject: [rfc][patch] Allow GDB to display user-defined thread names Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-06/txt/msg00073.txt.bz2 Hello! When debugging programs with posix threads, it often makes me sad that the threads don't have any meaningful name associated with them. I use a workaround involving a new gdb command for setting a thread name together with a script for use with the "-x" option. The workaround should be generic enough to be useful to other people too, so I'm hoping the patch might be considered for inclusion. The new gdb command takes the form "thread name NAME" and associates NAME with the current thread, so you can issue something like: (gdb) thread 3 (gdb) thread name "producer" etc Then anytime gdb needs to identify the thread to the user, it can be supplemented with the name, e.g. on a thread info: 3 Thread ["producer"] 0xb678cb90 (LWP 10286) 0x00a46416 in __kernel_vsyscall () 2 Thread ["consumer"] 0xb718db90 (LWP 10285) 0x00a46416 in __kernel_vsyscall () * 1 Thread ["main"] 0x7f2b9d0 (LWP 10282) 0x00a46416 in __kernel_vsyscall () It's not much fun to name the threads by hand, but it can be automated with a script, so long as you know a place to set a breakpoint that is unique to the thread. For example, to name "main": tbreak main commands silent thread name "main" c end In the codebase I debug most often, thread creation is wrapped for portability, and the thread name is available in the code itself at a thread's entrypoint, for use with Windows threads. So my script looks a bit like the following: break Thread::ThreadProc commands silent thread name ((ThreadProcData*)pParam)->name c end I attach a patch for the "thread name" command functionality. Despite its small size, I know it will need improvement - at very least I doubt it is good style to expose language / valprint stuff in thread.c. There are also a few caveats / potential improvements: - Thread names aren't known at the point gdb issues a "New thread..." notification, and initial "Switching to...". - There is a slight problem with pagination on, since the prompt_for_continue prompt will appear after several threads are created. I think this happens without my patch, and is caused by the "Switching..." messages that happen on the automated "continue". - It would be good to get this working with MI. - Maybe the script could be done better with python - I haven't yet tried the python stuff in gdb. So, if this is of interest, I'd like to spend the time to improve it but if anybody has time, it would be of great help if a gdb bod could volunteer to mentor me a bit... please? :) cheers, -karen Index: gdb/gdbthread.h =================================================================== RCS file: /cvs/src/src/gdb/gdbthread.h,v retrieving revision 1.49 diff -c -p -r1.49 gdbthread.h *** gdb/gdbthread.h 24 May 2009 21:06:53 -0000 1.49 --- gdb/gdbthread.h 4 Jun 2009 16:32:14 -0000 *************** struct thread_info *** 180,185 **** --- 180,188 ---- /* True if this thread has been explicitly requested to stop. */ int stop_requested; + /* Thread name as optionally set by user command. */ + char *name; + /* Private data used by the target vector implementation. */ struct private_thread_info *private; }; Index: gdb/linux-thread-db.c =================================================================== RCS file: /cvs/src/src/gdb/linux-thread-db.c,v retrieving revision 1.60 diff -c -p -r1.60 linux-thread-db.c *** gdb/linux-thread-db.c 24 May 2009 21:06:53 -0000 1.60 --- gdb/linux-thread-db.c 4 Jun 2009 16:32:17 -0000 *************** thread_db_pid_to_str (struct target_ops *** 1373,1380 **** thread_t tid; tid = thread_info->private->tid; ! snprintf (buf, sizeof (buf), "Thread 0x%lx (LWP %ld)", ! tid, GET_LWP (ptid)); return buf; } --- 1373,1384 ---- thread_t tid; tid = thread_info->private->tid; ! if (thread_info->name == NULL) ! snprintf (buf, sizeof (buf), "Thread 0x%lx (LWP %ld)", ! tid, GET_LWP (ptid)); ! else ! snprintf (buf, sizeof (buf), "Thread [%s] 0x%lx (LWP %ld)", ! thread_info->name, tid, GET_LWP (ptid)); return buf; } Index: gdb/thread.c =================================================================== RCS file: /cvs/src/src/gdb/thread.c,v retrieving revision 1.113 diff -c -p -r1.113 thread.c *** gdb/thread.c 24 May 2009 21:06:53 -0000 1.113 --- gdb/thread.c 4 Jun 2009 16:32:17 -0000 *************** *** 35,40 **** --- 35,42 ---- #include "regcache.h" #include "gdb.h" #include "gdb_string.h" + #include "language.h" + #include "valprint.h" #include #include *************** static int highest_thread_num; *** 57,62 **** --- 59,65 ---- static void thread_command (char *tidstr, int from_tty); static void thread_apply_all_command (char *, int); + static void thread_name_command (char *, int); static int thread_alive (struct thread_info *); static void info_threads_command (char *, int); static void thread_apply_command (char *, int); *************** free_thread (struct thread_info *tp) *** 114,119 **** --- 117,124 ---- { clear_thread_inferior_resources (tp); + xfree (tp->name); + /* FIXME: do I ever need to call the back-end to give it a chance at this private data before deleting the thread? */ if (tp->private) *************** thread_apply_all_command (char *cmd, int *** 1059,1064 **** --- 1064,1095 ---- } static void + thread_name_command (char *arg, int from_tty) + { + struct value *val; + struct ui_file *mem_file; + char *str; + long len; + struct thread_info *tp; + struct value_print_options opts; + + tp = find_thread_ptid (inferior_ptid); + + get_raw_print_options (&opts); + opts.addressprint = 0; + + val = parse_and_eval (arg); + + mem_file = mem_fileopen (); + LA_VALUE_PRINT (val, mem_file, &opts); + str = ui_file_xstrdup (mem_file, &len); + ui_file_delete (mem_file); + + xfree (tp->name); + tp->name = str; + } + + static void thread_apply_command (char *tidlist, int from_tty) { char *cmd; *************** The new thread ID must be currently know *** 1242,1247 **** --- 1273,1282 ---- _("Apply a command to a list of threads."), &thread_apply_list, "thread apply ", 1, &thread_cmd_list); + add_cmd ("name", class_run, thread_name_command, + _("Name current thread."), + &thread_cmd_list); + add_cmd ("all", class_run, thread_apply_all_command, _("Apply a command to all threads."), &thread_apply_list);