From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18726 invoked by alias); 7 Jul 2008 21:17:47 -0000 Received: (qmail 18717 invoked by uid 22791); 7 Jul 2008 21:17:46 -0000 X-Spam-Check-By: sourceware.org Received: from snape.ecoscentric.com (HELO snape.ecoscentric.com) (212.13.207.199) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 07 Jul 2008 21:17:20 +0000 Received: from localhost (snape.ecoscentric.com [127.0.0.1]) by snape.ecoscentric.com (Postfix) with ESMTP id 1F068DC8DD5 for ; Mon, 7 Jul 2008 22:17:16 +0100 (BST) Received: from snape.ecoscentric.com ([127.0.0.1]) by localhost (snape.ecoscentric.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id A-hs+W3gKGoj; Mon, 7 Jul 2008 22:17:14 +0100 (BST) Received: from delenn.bartv.net (unknown [212.13.207.199]) by snape.ecoscentric.com (Postfix) with ESMTP id DCF37DC8317 for ; Mon, 7 Jul 2008 22:17:13 +0100 (BST) Date: Mon, 07 Jul 2008 21:17:00 -0000 Message-Id: From: Bart Veer To: gdb@sourceware.org Subject: proposed extension for jtag debugging X-IsSubscribed: yes Mailing-List: contact gdb-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sourceware.org X-SW-Source: 2008-07/txt/msg00045.txt.bz2 These days gdb can interact with many hardware debug solutions based on jtag or BDM. Most solutions involve the remote protocol and a gdb server of some sort, including: OpenOCD, m68k-elf-sprite, nios2-gdb-server, and Abatron BDI units. There are exceptions, for example http://sourceforge.net/projects/bdm/ which adds a "target bdm" instead. Some solutions are open source, others are proprietary. Unfortunately these solutions typically do not provide any console output, the equivalent of 'O' packets. Instead a variety of workarounds are used. Often the output is sent out of a uart, but that only works when (a) the processor has at least one uart and that uart is accessible on the target hardware, and (b) the application does not need all available uarts. Some processors come with special jtag uarts, but those cause portability issues on both host and target. The occasional printf() can be an invaluable debug tool, and it would be useful to have a reasonably portable way of achieving console output when debugging over jtag or BDM. Recently I have been doing some experimenting along these lines. Now, in addition to 'O' packets gdb supports console I/O via the remote file I/O extension - as well as file I/O if desired. Hence one approach is to tweak remote-fileio.c so that it can be invoked even when the remote gdb server is not sending 'F' packets. The target-side code looks something like this: ---------------------------------------------------------------------------- static int _gdb_fileio_disabled = 1; static char _gdb_fileio_pkt[GDB_FILEIO_MAX_PKTLEN]; static int _gdb_fileio_call(void) { if (_gdb_fileio_disabled) { return 0; } // On M68K the reported PC is immediately after the halt instruction. __asm__ volatile ( " halt\n" " .globl _gdb_hwdebug_breakpoint\n" " .type _gdb_hwdebug_breakpoint, function\n" "_gdb_hwdebug_breakpoint:\n" : : : "memory" ); return 1; } ---------------------------------------------------------------------------- I/O code will fill in _gdb_fileio_pkt[] with the contents of an 'F' packet and then invoke _gdb_fileio_call(). This checks whether or not file I/O is currently enabled. The flag _gdb_fileio_disabled is cleared only when gdb is connected, allowing a single application to work either stand-alone or inside a debug session. Next the code triggers a breakpoint. The exact details of this are obviously architecture-specific. Embedding the breakpoint instruction directly in the code means that it will function even when debugging an application programmed into flash, with no need to use up one of the few available hardware breakpoints. The corresponding gdb code lives in a new module hwdebug-fileio.c. The code is disabled by default, things only start happening following a "set hwdebug on" command. Amongst other things that pushes a new set of target_ops, the most interesting of which is hwdebug_wait(): ---------------------------------------------------------------------------- static CORE_ADDR target__gdb_hwdebug_breakpoint; static CORE_ADDR target__gdb_fileio_pkt; static char gdb_fileio_pkt[GDB_FILEIO_MAX_PKTLEN + 1]; ... static ptid_t hwdebug_wait(ptid_t ptid, struct target_waitstatus* status) { ptid_t result; struct target_ops* orig_ops = find_target_beneath (&hwdebug_ops); CORE_ADDR pc; while (1 ) { result = (*orig_ops->to_wait) (ptid, status); pc = read_pc(); if (pc != target__gdb_hwdebug_breakpoint) { break; } gdb_fileio_pkt[0] = 'F'; target_read_memory(target__gdb_fileio_pkt, &(gdb_fileio_pkt[1]), GDB_FILEIO_MAX_PKTLEN); remote_fileio_request(gdb_fileio_pkt, &hwdebug_putpkt); // As per wait_for_inferior() overlay_cache_invalid = 1; registers_changed (); // Automatically resume the target. hwdebug_resume(ptid, hwdebug_resume__last_step, hwdebug_resume__last_sig); } // The target has halted for reasons other than h/w debug file I/O, // e.g. an ordinary breakpoint. Return to higher-level gdb code. return result; } ---------------------------------------------------------------------------- So basically this code chains to the underlying wait() function, e.g. remote_wait(). When the target halts the PC is compared with &_gdb_hwdebug_breakpoint. If there is a match then the 'F' packet is fetched from the target and processed via remote_fileio_request(), and then the target automatically resumes. Otherwise the event is passed back up to higher-level code. For this to work remote-fileio.c needs some tweaking so that it is independent from remote.c - not all hardware debug solutions involve the remote protocol and a gdb server. Calls to remote_read_bytes() need to be replaced with target_read_memory(), and similar for writes to target memory. The response to the file I/O request needs to go via a putpkt() variant supplied as argument to remote_fileio_request(), not the standard remote.c putpkt(). In addition it may be necessary to have a new target ops stratum, e.g. process_override_stratum, sitting between process_stratum and thread_stratum. Obviously a full implementation will be somewhat more complicated than the above. For example it will be necessary to cope with ctrl-C. Generating the 'F' packet on the target is not necessarily the most efficient approach. A binary structure on the target plus code in hwdebug-fileio.c to generate the 'F' packet based on that structure would save some target-side code and data, possibly significant on the smaller targets. On the other hand it would add a lot of complexity to the host-side code and make it more difficult to extend the protocol in future - although I believe that has not happened since the functionality was added in 2003. There is no guarantee that the approach described here will work on all hardware, since some gdb servers may get rather upset if the target hits a breakpoint instruction that was not set by gdb. However I think it should work with most systems. At this stage I would like to invite some comments: 1) is there any interest in adding functionality along these lines, i.e. mostly portable console and host file I/O for jtag and BDM debug solutions, to mainstream gdb? 2) is the basic approach of reusing remote-fileio.c the right one? Bart -- Bart Veer eCos Configuration Architect eCosCentric Limited The eCos experts http://www.ecoscentric.com/ Barnwell House, Barnwell Drive, Cambridge, UK. Tel: +44 1223 245571 Registered in England and Wales: Reg No 4422071.