From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8714 invoked by alias); 2 Mar 2006 01:29:49 -0000 Received: (qmail 8706 invoked by uid 22791); 2 Mar 2006 01:29:48 -0000 X-Spam-Check-By: sourceware.org Received: from nile.gnat.com (HELO nile.gnat.com) (205.232.38.5) by sourceware.org (qpsmtpd/0.31) with ESMTP; Thu, 02 Mar 2006 01:29:46 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-nile.gnat.com (Postfix) with ESMTP id 0C11748CC05 for ; Wed, 1 Mar 2006 20:29:45 -0500 (EST) Received: from nile.gnat.com ([127.0.0.1]) by localhost (nile.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 18347-01-10 for ; Wed, 1 Mar 2006 20:29:44 -0500 (EST) Received: from takamaka.act-europe.fr (s142-179-108-108.bc.hsia.telus.net [142.179.108.108]) by nile.gnat.com (Postfix) with ESMTP id 8BC9C48CBD9 for ; Wed, 1 Mar 2006 20:29:44 -0500 (EST) Received: by takamaka.act-europe.fr (Postfix, from userid 507) id EA92747E7F; Wed, 1 Mar 2006 17:29:43 -0800 (PST) Date: Thu, 02 Mar 2006 01:29:00 -0000 From: Joel Brobecker To: gdb-patches@sources.redhat.com Subject: Suggestion: backtrace stop guard for threads callstacks Message-ID: <20060302012943.GK1579@adacore.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4i Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2006-03/txt/msg00032.txt.bz2 Hello, We have recently implemented a small feature in our version of the debugger. While the implementation itself is not ready for inclusion here, and not directly interesting in any case (lacking support for Ada tasks for now, see below), I thought the general idea might be interesting to the group. And I think it's not going to be too time consuming, so could probably produce a patch. One of our customers reported that he saw a warning from the debugger saying that a frame was identical to the previous frame. Here is the kind of output he would see: > #3 0x000370d4 in system.tasking.stages.task_wrapper () > #4 0xff34b124 in _thread_start () from /usr/lib/libthread.so.1 > #5 0xff34b124 in _thread_start () from /usr/lib/libthread.so.1 > warning: Previous frame identical to this frame (corrupt stack?) In this case, the user tried to print a backtrace from inside an Ada task, which is mapped over a thread, and that the unwinder didn't (couldn't?) know that it was time to stop at frame #4. The same sort of situation happens with the main process, outside of a thread context, where we sometimes cannot know that we reached the top of the callstack. For the main process, we have a guard put in place that will stop it when reaching the "main program". See main_name(), inside_main_func(), and get_prev_frame(). What we've done for Ada tasks, is to take advantage of the fact that we know that tasks are run from a known routine in the GNAT runtime, called System.Tasking.[...].Task_Wrapper. So we added a small piece of code to detect Ada frames corresponding to this routine (we actually have two, but the principle is the same), and declare that we're inside the main func if the task_wrapper is detected. The complete backtrace can be obtained using the already implemented (gdb) set backtrace past-main It's a little bit less simple for the general case for C, C++ and other languages, but I suggest we implement something similar. How about we add some code that recognizes some of the thread entry-points? For the GNU/Linux NPTL for instance, we could recognize clone() or perhaps _start_thread? We could make the check as stringent as we like, for instance not only check the funtion name, but also the object name, to make sure we're inside the pthread library. Just throwing some ideas. My overall idea is to implement a mechanism where various modules in GDB could register their own routine that would be able to tell whether they recognize the given function as a main or not. For instance, sol-thread.c could implement its routine, and register it during the init phase... inside_main_func() would then go through this list, and call each one of them until one recognizes it or until it reaches its end. Even grander, have a language-specific-hook, followed by list of registered sniffers. So inside_main_func() would look like this: msymbol = lookup_minimal_symbol (main_name (), NULL, symfile_objfile); [check this symbol to see if it's the main] /* Check this frame using the language-specific sniffer */ symtab = find_pc_symtab (pc); if (symtab != NULL) if (language_main_name_sniffer[language] (this_frame)) return 1; /* Check using the other sniffers */ FOR_ALL_MAIN_FUNC_SNIFFERS (sniffer) if (sniffer (this_frame)) return 1; return 0; Thoughts? -- Joel