From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19461 invoked by alias); 10 Feb 2012 13:44:22 -0000 Received: (qmail 19419 invoked by uid 22791); 10 Feb 2012 13:44:14 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL,BAYES_00,TW_HK,TW_NV,T_FRT_STOCK2 X-Spam-Check-By: sourceware.org Received: from mel.act-europe.fr (HELO mel.act-europe.fr) (194.98.77.210) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 10 Feb 2012 13:43:56 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id 2753629000B; Fri, 10 Feb 2012 14:43:54 +0100 (CET) Received: from mel.act-europe.fr ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id LiXE7dk9VqY9; Fri, 10 Feb 2012 14:43:54 +0100 (CET) Received: from ulanbator.act-europe.fr (ulanbator.act-europe.fr [10.10.1.67]) (using TLSv1 with cipher AES128-SHA (128/128 bits)) (No client certificate requested) by mel.act-europe.fr (Postfix) with ESMTP id 0EA92290001; Fri, 10 Feb 2012 14:43:54 +0100 (CET) Subject: RFA: New port: ia64-hp-openvms - the stub Mime-Version: 1.0 (Apple Message framework v1251.1) Content-Type: text/plain; charset=windows-1252 From: Tristan Gingold In-Reply-To: <6AD2487F-8409-4F4E-93A6-9DB7FD195E71@adacore.com> Date: Fri, 10 Feb 2012 13:44:00 -0000 Cc: Rupp Douglas Content-Transfer-Encoding: quoted-printable Message-Id: <35B93121-2F70-4E7C-B415-E691138D6698@adacore.com> References: <6AD2487F-8409-4F4E-93A6-9DB7FD195E71@adacore.com> To: "gdb-patches@sourceware.org ml" 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: 2012-02/txt/msg00186.txt.bz2 Hi, this is the debugger stub for ia64 VMS. Because it is independent of gdb (not unlike gdbserver) and because it isn'= t a one file stub, I think it is worth creating a subdirectory. I think we should also move the existing stubs there. The interesting part is that on OpenVMS, the debugger is a shared library t= hat is loaded with the application when debugging is needed (either from th= e start or during the run - like attach). Just think about catching SIGTRA= P, SIGSEGV, SIGBUS,=85 from a LD_PRELOAD binary. The stub was written from scratch because it is highly OpenVMS dependent an= d in particular the standard C library shouldn't be used. The stub is not complete: some registers are partially or not handled, and = inferior procedure call is not yet implemented (will be the funny part). B= ut it has already be extremely useful to debug some applications. Tristan. gdb/stubs: 2012-02-10 Tristan Gingold * buildvms.com: New file. * ia64vms-stub.c: New file. diff --git a/gdb/stubs/buildvms.com b/gdb/stubs/buildvms.com new file mode 100644 index 0000000..5ac2bf9 --- /dev/null +++ b/gdb/stubs/buildvms.com @@ -0,0 +1,9 @@ +$! Command to build the gdb stub +$cc ia64vms-stub +sys$library:sys$lib_c.tlb/lib +$ link/notraceback/sysexe/map=3Dstub.map/full/share=3Dgdbstub.exe ia64vms-= stub,sys$input/opt +$deck +cluster=3Dgdbzero +collect=3Dgdbzero, XFER_PSECT +$eod +$! Example of use. +$ DEFINE /nolog LIB$DEBUG sys$login:gdbstub.exe diff --git a/gdb/stubs/ia64vms-stub.c b/gdb/stubs/ia64vms-stub.c new file mode 100644 index 0000000..256b95f --- /dev/null +++ b/gdb/stubs/ia64vms-stub.c @@ -0,0 +1,1583 @@ +/* GDB stub for Itanium OpenVMS + Copyright (C) 2012, Free Software Foundation, Inc. + + Contributed by Tristan Gingold, AdaCore. + + 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 . = */ + +/* On VMS, the debugger (in our case the stub) is loaded in the process and + executed (via SYS$IMGSTA) before the main entry point of the executable. + In UNIX parlance, this is like using LD_PRELOAD and debug via installing + SIGTRAP, SIGSEGV... handlers. + + This is currently a partial implementation. In particular, modifying + registers is currently not implemented, as well as inferior procedure + calls. + + This is written in very low-level C, in order not to use the C runtime, + because it may have weird consequences on the program being debugged. +*/ + +#define __NEW_STARLET 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Declared in lib$ots. */ +extern void ots$fill (void *addr, size_t len, unsigned char b); +extern int ots$strcmp_eql (const void *str1, size_t str1len, + const void *str2, size_t str2len); + +/* Stub port number. */ +static unsigned int serv_port =3D 1234; + +/* If true, display packets exchanged with gdb. */ +static int trace_pkt =3D 0; + +/* If true, display info about entry point. */ +static int trace_entry =3D 0; + +/* If true, display all exceptions. */ +static int trace_excp =3D 0; + +/* Connect inet device I/O channel. */ +static unsigned short conn_channel; + +/* Socket characteristics. Apparently, there are no declaration for it in + standard headers. */ +struct sockchar +{ + unsigned short prot; + unsigned char type; + unsigned char af; +}; + +/* IA64 integer register representation. */ +union ia64_ireg +{ + unsigned __int64 v; + unsigned char b[8]; +}; + +/* IA64 register numbers, as defined by ia64-tdep.h. */ +#define IA64_GR0_REGNUM 0 +#define IA64_GR32_REGNUM (IA64_GR0_REGNUM + 32) + +/* Floating point registers; 128 82-bit wide registers. */ +#define IA64_FR0_REGNUM 128 + +/* Predicate registers; There are 64 of these one bit registers. It'd + be more convenient (implementation-wise) to use a single 64 bit + word with all of these register in them. Note that there's also a + IA64_PR_REGNUM below which contains all the bits and is used for + communicating the actual values to the target. */ +#define IA64_PR0_REGNUM 256 + +/* Branch registers: 8 64-bit registers for holding branch targets. */ +#define IA64_BR0_REGNUM 320 + +/* Virtual frame pointer; this matches IA64_FRAME_POINTER_REGNUM in + gcc/config/ia64/ia64.h. */ +#define IA64_VFP_REGNUM 328 + +/* Virtual return address pointer; this matches + IA64_RETURN_ADDRESS_POINTER_REGNUM in gcc/config/ia64/ia64.h. */ +#define IA64_VRAP_REGNUM 329 + +/* Predicate registers: There are 64 of these 1-bit registers. We + define a single register which is used to communicate these values + to/from the target. We will somehow contrive to make it appear + that IA64_PR0_REGNUM thru IA64_PR63_REGNUM hold the actual values. */ +#define IA64_PR_REGNUM 330 + +/* Instruction pointer: 64 bits wide. */ +#define IA64_IP_REGNUM 331 + +/* Process Status Register. */ +#define IA64_PSR_REGNUM 332 + +/* Current Frame Marker (raw form may be the cr.ifs). */ +#define IA64_CFM_REGNUM 333 + +/* Application registers; 128 64-bit wide registers possible, but some + of them are reserved. */ +#define IA64_AR0_REGNUM 334 +#define IA64_KR0_REGNUM (IA64_AR0_REGNUM + 0) +#define IA64_KR7_REGNUM (IA64_KR0_REGNUM + 7) + +#define IA64_RSC_REGNUM (IA64_AR0_REGNUM + 16) +#define IA64_BSP_REGNUM (IA64_AR0_REGNUM + 17) +#define IA64_BSPSTORE_REGNUM (IA64_AR0_REGNUM + 18) +#define IA64_RNAT_REGNUM (IA64_AR0_REGNUM + 19) +#define IA64_FCR_REGNUM (IA64_AR0_REGNUM + 21) +#define IA64_EFLAG_REGNUM (IA64_AR0_REGNUM + 24) +#define IA64_CSD_REGNUM (IA64_AR0_REGNUM + 25) +#define IA64_SSD_REGNUM (IA64_AR0_REGNUM + 26) +#define IA64_CFLG_REGNUM (IA64_AR0_REGNUM + 27) +#define IA64_FSR_REGNUM (IA64_AR0_REGNUM + 28) +#define IA64_FIR_REGNUM (IA64_AR0_REGNUM + 29) +#define IA64_FDR_REGNUM (IA64_AR0_REGNUM + 30) +#define IA64_CCV_REGNUM (IA64_AR0_REGNUM + 32) +#define IA64_UNAT_REGNUM (IA64_AR0_REGNUM + 36) +#define IA64_FPSR_REGNUM (IA64_AR0_REGNUM + 40) +#define IA64_ITC_REGNUM (IA64_AR0_REGNUM + 44) +#define IA64_PFS_REGNUM (IA64_AR0_REGNUM + 64) +#define IA64_LC_REGNUM (IA64_AR0_REGNUM + 65) +#define IA64_EC_REGNUM (IA64_AR0_REGNUM + 66) + +/* NAT (Not A Thing) Bits for the general registers; there are 128 of + these. */ +#define IA64_NAT0_REGNUM 462 + +/* Process registers when a condition is caught. */ +struct ia64_all_regs +{ + union ia64_ireg gr[32]; + union ia64_ireg br[8]; + union ia64_ireg ip; + union ia64_ireg psr; + union ia64_ireg bsp; + union ia64_ireg cfm; + union ia64_ireg pfs; + union ia64_ireg pr; +}; + +static struct ia64_all_regs regs; + +/* IO channel for the terminal. */ +static unsigned short term_chan; + +/* Output buffer and length. */ +static char term_buf[128]; +static int term_buf_len; + +/* Buffer for communication with gdb. */ +static unsigned char gdb_buf[sizeof (regs) * 2 + 64]; +static unsigned int gdb_blen; + +/* Previous primary handler. */ +static void *prevhnd; + +/* Entry point address and bundle. */ +static unsigned __int64 entry_pc; +static unsigned char entry_saved[16]; + +/* Write on the terminal. */ + +static void +term_raw_write (const char *str, unsigned int len) +{ + unsigned short status; + struct _iosb iosb; + + status =3D sys$qiow (EFN$C_ENF, /* Event flag. */ + term_chan, /* I/O channel. */ + IO$_WRITEVBLK, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + (char *)str, /* P1 - buffer address. */ + len, /* P2 - buffer length. */ + 0, 0, 0, 0); + + if (status & STS$M_SUCCESS) + status =3D iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); +} + +/* Flush ther term buffer. */ + +static void +term_flush (void) +{ + if (term_buf_len !=3D 0) + { + term_raw_write (term_buf, term_buf_len); + term_buf_len =3D 0; + } +} + +/* Write a single character, without translation. */ + +static void +term_raw_putchar (char c) +{ + if (term_buf_len =3D=3D sizeof (term_buf)) + term_flush (); + term_buf[term_buf_len++] =3D c; +} + +/* Write character C. Translate '\n' to '\n\r'. */ + +static void +term_putc (char c) +{ + term_raw_putchar (c); + if (c =3D=3D '\n') + { + term_raw_putchar ('\r'); + term_flush (); + } +} + +/* Write a C string. */ + +static void +term_puts (const char *str) +{ + while (*str) + term_putc (*str++); +} + +/* Write LEN bytes from STR. */ + +static void +term_write (const char *str, unsigned int len) +{ + for (; len > 0; len--) + term_putc (*str++); +} + +static const char hex[] =3D "0123456789abcdef"; + +/* Write V as a 16 hexa digits number. */ + +static void +term_puthex8 (unsigned __int64 v) +{ + int i; + + for (i =3D 0; i < 16; i++) + { + term_putc (hex[(v >> 60) & 0x0f]); + v <<=3D 4; + } +} + +/* Write a byte in hexa (two digits). */ + +void +term_puthex1 (unsigned int v) +{ + term_putc (hex[v >> 4]); + term_putc (hex[v & 0x0f]); +} + +/* Write V in decimal. */ + +static void +term_putdec (unsigned __int64 v) +{ + char res[20]; + int i; + + i =3D sizeof (res) - 1; + while (1) + { + res[i] =3D '0' + (v % 10); + v /=3D 10; + if (v =3D=3D 0 || i =3D=3D 0) + break; + i--; + } + term_write (res + i, sizeof (res) - i); +} + +/* Write P in hexa. */ + +static void +term_putp (void *p) +{ + term_puthex8 ((unsigned __int64)p); +} + +/* New line. */ + +static void +term_putnl (void) +{ + term_putc ('\n'); +} + +/* Initialize terminal. */ + +static void +term_init (void) +{ + unsigned int status,i; + unsigned short len; + char resstring[LNM$C_NAMLENGTH]; + static const $DESCRIPTOR (tabdesc, "LNM$FILE_DEV"); + static const $DESCRIPTOR (logdesc, "SYS$OUTPUT"); + $DESCRIPTOR (term_desc, resstring); + ILE3 item_lst[2]; + + item_lst[0].ile3$w_length =3D LNM$C_NAMLENGTH; + item_lst[0].ile3$w_code =3D LNM$_STRING; + item_lst[0].ile3$ps_bufaddr =3D resstring; + item_lst[0].ile3$ps_retlen_addr =3D &len; + item_lst[1].ile3$w_length =3D 0; + item_lst[1].ile3$w_code =3D 0; + + /* Translate the logical name. */ + status =3D SYS$TRNLNM (0, /* Attr of the logical name. */ + (void *) &tabdesc, /* Logical name table. */ + (void *) &logdesc, /* Logical name. */ + 0, /* Access mode. */ + item_lst); /* Item list. */ + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); + + term_desc.dsc$w_length =3D len; + + /* Examine 4-byte header. Skip escape sequence. */ + if (resstring[0] =3D=3D 0x1B) + { + term_desc.dsc$w_length -=3D 4; + term_desc.dsc$a_pointer +=3D 4; + } + + /* Assign a channel. */ + status =3D sys$assign (&term_desc, /* Device name. */ + &term_chan, /* I/O channel. */ + 0, /* Access mode. */ + 0); + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); +} + +/* Convert from native endianness to network endianness (and vice-versa). = */ + +static unsigned int +wordswap (unsigned int v) +{ + return ((v & 0xff) << 8) | ((v >> 8) & 0xff); +} + +/* Initialize the socket connection, and wait for a client. */ + +static void +sock_init (void) +{ + struct _iosb iosb; + unsigned int status; + + /* Listen channel and characteristics. */ + unsigned short listen_channel; + struct sockchar listen_sockchar; + + /* Client address. */ + unsigned short cli_addrlen; + struct sockaddr_in cli_addr; + ILE3 cli_itemlst; + + /* Our address. */ + struct sockaddr_in serv_addr; + ILE2 serv_itemlst; + + /* Reuseaddr option value (on). */ + int optval =3D 1; + ILE2 sockopt_itemlst; + ILE2 reuseaddr_itemlst; + + /* TCP/IP network pseudodevice. */ + static const $DESCRIPTOR (inet_device, "TCPIP$DEVICE:"); + + /* Initialize socket characteristics. */ + listen_sockchar.prot =3D TCPIP$C_TCP; + listen_sockchar.type =3D TCPIP$C_STREAM; + listen_sockchar.af =3D TCPIP$C_AF_INET; + + /* Assign I/O channels to network device. */ + status =3D sys$assign ((void *) &inet_device, &listen_channel, 0, 0); + if (status & STS$M_SUCCESS) + status =3D sys$assign ((void *) &inet_device, &conn_channel, 0, 0); + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to assign I/O channel(s)\n\r"); + LIB$SIGNAL (status); + } + + /* Create a listen socket. */ + status =3D sys$qiow (EFN$C_ENF, /* Event flag. */ + listen_channel, /* I/O channel. */ + IO$_SETMODE, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + &listen_sockchar, /* P1 - socket characteristics. = */ + 0, 0, 0, 0, 0); + if (status & STS$M_SUCCESS) + status =3D iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to create socket\n\r"); + LIB$SIGNAL (status); + } + + /* Set reuse address option. */ + /* Initialize reuseaddr's item-list element. */ + reuseaddr_itemlst.ile2$w_length =3D sizeof (optval); + reuseaddr_itemlst.ile2$w_code =3D TCPIP$C_REUSEADDR; + reuseaddr_itemlst.ile2$ps_bufaddr =3D &optval; + + /* Initialize setsockopt's item-list descriptor. */ + sockopt_itemlst.ile2$w_length =3D sizeof (reuseaddr_itemlst); + sockopt_itemlst.ile2$w_code =3D TCPIP$C_SOCKOPT; + sockopt_itemlst.ile2$ps_bufaddr =3D &reuseaddr_itemlst; + + status =3D sys$qiow (EFN$C_ENF, /* Event flag. */ + listen_channel, /* I/O channel. */ + IO$_SETMODE, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, /* P1. */ + 0, /* P2. */ + 0, /* P3. */ + 0, /* P4. */ + (__int64) &sockopt_itemlst, /* P5 - socket options. = */ + 0); + if (status & STS$M_SUCCESS) + status =3D iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to set socket option\n\r"); + LIB$SIGNAL (status); + } + + /* Bind server's ip address and port number to listen socket. */ + /* Initialize server's socket address structure. */ + ots$fill (&serv_addr, sizeof (serv_addr), 0); + serv_addr.sin_family =3D TCPIP$C_AF_INET; + serv_addr.sin_port =3D wordswap (serv_port); + serv_addr.sin_addr.s_addr =3D TCPIP$C_INADDR_ANY; + + /* Initialize server's item-list descriptor. */ + serv_itemlst.ile2$w_length =3D sizeof (serv_addr); + serv_itemlst.ile2$w_code =3D TCPIP$C_SOCK_NAME; + serv_itemlst.ile2$ps_bufaddr =3D &serv_addr; + + status =3D sys$qiow (EFN$C_ENF, /* Event flag. */ + listen_channel, /* I/O channel. */ + IO$_SETMODE, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, /* P1. */ + 0, /* P2. */ + (__int64) &serv_itemlst, /* P3 - local socket name. = */ + 0, 0, 0); + if (status & STS$M_SUCCESS) + status =3D iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to bind socket\n\r"); + LIB$SIGNAL (status); + } + + /* Set socket as a listen socket. */ + status =3D sys$qiow (EFN$C_ENF, /* Event flag. */ + listen_channel, /* I/O channel. */ + IO$_SETMODE, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, /* P1. */ + 0, /* P2. */ + 0, /* P3. */ + 1, /* P4 - connection backlog. */ + 0, 0); + if (status & STS$M_SUCCESS) + status =3D iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to set socket passive\n\r"); + LIB$SIGNAL (status); + } + + /* Accept connection from a client. */ + term_puts ("Waiting for a client connection on port: "); + term_putdec (wordswap (serv_addr.sin_port)); + term_putnl (); + + status =3D sys$qiow (EFN$C_ENF, /* Event flag. */ + listen_channel, /* I/O channel. */ + IO$_ACCESS|IO$M_ACCEPT, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, /* P1. */ + 0, /* P2. */ + 0, /* P3. */ + (__int64) &conn_channel, /* P4 - I/O channel for conn= . */ + 0, 0); + + if (status & STS$M_SUCCESS) + status =3D iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to accept client connection\n\r"); + LIB$SIGNAL (status); + } + + /* Log client connection request. */ + cli_itemlst.ile3$w_length =3D sizeof (cli_addr); + cli_itemlst.ile3$w_code =3D TCPIP$C_SOCK_NAME; + cli_itemlst.ile3$ps_bufaddr =3D &cli_addr; + cli_itemlst.ile3$ps_retlen_addr =3D &cli_addrlen; + ots$fill (&cli_addr, sizeof(cli_addr), 0); + status =3D sys$qiow (EFN$C_ENF, /* Event flag. */ + conn_channel, /* I/O channel. */ + IO$_SENSEMODE, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, /* P1. */ + 0, /* P2. */ + 0, /* P3. */ + (__int64) &cli_itemlst, /* P4 - peer socket name. */ + 0, 0); + if (status & STS$M_SUCCESS) + status =3D iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to get client name\n\r"); + LIB$SIGNAL (status); + } + + term_puts ("Accepted connection from host: "); + term_putdec ((cli_addr.sin_addr.s_addr >> 0) & 0xff); + term_putc ('.'); + term_putdec ((cli_addr.sin_addr.s_addr >> 8) & 0xff); + term_putc ('.'); + term_putdec ((cli_addr.sin_addr.s_addr >> 16) & 0xff); + term_putc ('.'); + term_putdec ((cli_addr.sin_addr.s_addr >> 24) & 0xff); + term_puts (", port: "); + term_putdec (wordswap (cli_addr.sin_port)); + term_putnl (); +} + +/* Close the socket. */ + +static void +sock_close (void) +{ + struct _iosb iosb; + unsigned int status; + + /* Close socket. */ + status =3D sys$qiow (EFN$C_ENF, /* Event flag. */ + conn_channel, /* I/O channel. */ + IO$_DEACCESS, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, 0, 0, 0, 0, 0); + + if (status & STS$M_SUCCESS) + status =3D iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to close socket\n\r"); + LIB$SIGNAL (status); + } + + /* Deassign I/O channel to network device. */ + status =3D sys$dassgn (conn_channel); + + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to deassign I/O channel\n\r"); + LIB$SIGNAL (status); + } +} + +/* Mark a page as R/W. Return old rights. */ + +static unsigned int +page_set_rw (unsigned __int64 startva, unsigned __int64 len, + unsigned int *oldprot) +{ + unsigned int status; + unsigned __int64 retva; + unsigned __int64 retlen; + + status =3D SYS$SETPRT_64 ((void *)startva, len, PSL$C_USER, PRT$C_UW, + (void *)&retva, &retlen, oldprot); + return status; +} + +/* Restore page rights. */ + +static void +page_restore_rw (unsigned __int64 startva, unsigned __int64 len, + unsigned int prot) +{ + unsigned int status; + unsigned __int64 retva; + unsigned __int64 retlen; + unsigned int oldprot; + + status =3D SYS$SETPRT_64 ((void *)startva, len, PSL$C_USER, prot, + (void *)&retva, &retlen, &oldprot); + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); +} + +/* Convert an hexadecimal character to a nibble. Return -1 in case of + error. */ + +static int +hex2nibble (unsigned char h) +{ + if (h >=3D '0' && h <=3D '9') + return h - '0'; + if (h >=3D 'A' && h <=3D 'F') + return h - 'A' + 10; + if (h >=3D 'a' && h <=3D 'f') + return h - 'a' + 10; + return -1; +} + +/* Convert an hexadecimal 2 character string to a byte. Return -1 in case + of error. */ + +static int +hex2byte (const unsigned char *p) +{ + int h, l; + + h =3D hex2nibble (p[0]); + l =3D hex2nibble (p[1]); + if (h =3D=3D -1 || l =3D=3D -1) + return -1; + return (h << 4) | l; +} + +/* Convert a byte V to a 2 character strings P. */ + +static void +byte2hex (unsigned char *p, unsigned char v) +{ + p[0] =3D hex[v >> 4]; + p[1] =3D hex[v & 0xf]; +} + +/* Convert a quadword V to a 16 character strings P. */ + +static void +quad2hex (unsigned char *p, unsigned __int64 v) +{ + int i; + for (i =3D 0; i < 16; i++) + { + p[i] =3D hex[v >> 60]; + v <<=3D 4; + } +} + +/* Generate an error packet. */ + +static void +packet_error (unsigned int err) +{ + gdb_buf[1] =3D 'E'; + byte2hex (gdb_buf + 2, err); + gdb_blen =3D 4; +} + +/* Generate an OK packet. */ + +static void +packet_ok (void) +{ + gdb_buf[1] =3D 'O'; + gdb_buf[2] =3D 'K'; + gdb_blen =3D 3; +} + +/* Append a register to the packet. */ + +static void +ireg2pkt (const unsigned char *p) +{ + int i; + + for (i =3D 0; i < 8; i++) + { + byte2hex (gdb_buf + gdb_blen, p[i]); + gdb_blen +=3D 2; + } +} + +/* Extract a number fro the packet. */ + +static unsigned __int64 +pkt2val (const unsigned char *pkt, unsigned int *pos) +{ + unsigned __int64 res =3D 0; + unsigned int i; + + while (1) + { + int r =3D hex2nibble (pkt[*pos]); + + if (r < 0) + return res; + res =3D (res << 4) | r; + (*pos)++; + } +} + +/* Append LEN bytes from B to the current gdb packet (encode in binary). = */ + +static void +mem2bin (const unsigned char *b, unsigned int len) +{ + unsigned int i; + for (i =3D 0; i < len; i++) + switch (b[i]) + { + case '#': + case '$': + case '}': + case '*': + case 0: + gdb_buf[gdb_blen++] =3D '}'; + gdb_buf[gdb_blen++] =3D b[i] ^ 0x20; + break; + default: + gdb_buf[gdb_blen++] =3D b[i]; + break; + } +} + +/* Append LEN bytes from B to the current gdb packet (encode in hex). */ + +static void +mem2hex (const unsigned char *b, unsigned int len) +{ + unsigned int i; + for (i =3D 0; i < len; i++) + { + byte2hex (gdb_buf + gdb_blen, b[i]); + gdb_blen +=3D 2; + } +} + +/* Handle the 'q' packet. */ + +static void +handle_q_packet (const unsigned char *pkt, unsigned int pktlen) +{ + static const char xfer_uib[] =3D "qXfer:uib:read:"; +#define XFER_UIB_LEN (sizeof (xfer_uib) - 1) + + if (pktlen > XFER_UIB_LEN + && ots$strcmp_eql (pkt, XFER_UIB_LEN, xfer_uib, XFER_UIB_LEN)) + { + unsigned __int64 pc; + unsigned int pos =3D 24; + unsigned int off; + unsigned int len; + unsigned char blk[32]; + int res; + int i; + + packet_error (0); + + pc =3D pkt2val (pkt, &pos); + if (pkt[pos] !=3D ':') + return; + pos++; + off =3D pkt2val (pkt, &pos); + if (pkt[pos] !=3D ',' || off !=3D 0) + return; + pos++; + len =3D pkt2val (pkt, &pos); + if (pkt[pos] !=3D '#' || len !=3D 0x20) + return; + + res =3D SYS$GET_UNWIND_ENTRY_INFO (pc, blk, 0); + if (res =3D=3D SS$_NODATA || res !=3D SS$_NORMAL) + ots$fill (blk, sizeof (blk), 0); + +#if 0 + term_puts ("Got unwind request for "); + term_puthex8 (pc); + term_puts (", res=3D"); + term_puthex8 (res); + term_putnl (); +#endif + + gdb_buf[0] =3D '$'; + gdb_buf[1] =3D 'l'; + gdb_blen =3D 2; + mem2bin (blk, sizeof (blk)); + } + else + return; +} + +/* Return 1 to continue. */ + +static int +handle_packet (const unsigned char *pkt, unsigned int len) +{ + unsigned int pos; + + /* By default, reply unsupported. */ + gdb_buf[0] =3D '$'; + gdb_blen =3D 1; + + pos =3D 1; + switch (pkt[0]) + { + case '?': + if (len =3D=3D 1) + { + gdb_buf[1] =3D 'S'; + gdb_buf[2] =3D '0'; + gdb_buf[3] =3D '5'; + gdb_blen +=3D 3; + return 0; + } + break; + case 'g': + if (len =3D=3D 1) + { + unsigned int i; + unsigned char *p =3D regs.gr[0].b; + + for (i =3D 0; i < 8 * 32; i++) + byte2hex (gdb_buf + 1 + 2 * i, p[i]); + gdb_blen +=3D 2 * 8 * 32; + return 0; + } + break; + case 'p': + { + unsigned int num =3D 0; + unsigned int i; + + num =3D pkt2val (pkt, &pos); + if (pos !=3D len) + { + packet_error (0); + return 0; + } + + switch (num) + { + case IA64_IP_REGNUM: + ireg2pkt (regs.ip.b); + break; + case IA64_BR0_REGNUM: + ireg2pkt (regs.br[0].b); + break; + case IA64_PSR_REGNUM: + ireg2pkt (regs.psr.b); + break; + case IA64_BSP_REGNUM: + ireg2pkt (regs.bsp.b); + break; + case IA64_CFM_REGNUM: + ireg2pkt (regs.cfm.b); + break; + case IA64_PFS_REGNUM: + ireg2pkt (regs.pfs.b); + break; + case IA64_PR_REGNUM: + ireg2pkt (regs.pr.b); + break; + default: + term_puts ("gdbserv: unhandled reg "); + term_putdec (num); + term_putnl (); + packet_error (0); + return 0; + } + } + break; + case 'q': + handle_q_packet (pkt, len); + break; + case 'k': + SYS$EXIT (SS$_NORMAL); + break; + case 'm': + { + unsigned __int64 addr; + unsigned int l; + unsigned int i; + addr =3D pkt2val (pkt, &pos); + if (pkt[pos] !=3D ',') + { + packet_error (0); + return 0; + } + pos++; + l =3D pkt2val (pkt, &pos); + if (pkt[pos] !=3D '#') + { + packet_error (0); + return 0; + } + for (i =3D 0; i < l; i++) + byte2hex (gdb_buf + 1 + 2 * i, ((unsigned char *)addr)[i]); + gdb_blen +=3D 2 * l; + } + break; + case 'M': + { + unsigned __int64 addr; + unsigned int l; + unsigned int i; + unsigned int oldprot; + + addr =3D pkt2val (pkt, &pos); + if (pkt[pos] !=3D ',') + { + packet_error (0); + return 0; + } + pos++; + l =3D pkt2val (pkt, &pos); + if (pkt[pos] !=3D ':') + { + packet_error (0); + return 0; + } + pos++; + page_set_rw (addr, l, &oldprot); + for (i =3D 0; i < l; i++) + { + int v =3D hex2byte (pkt + pos); + pos +=3D 2; + ((unsigned char *)addr)[i] =3D v; + } + for (i =3D 0; i < l; i +=3D 15) + __fc (addr + i); + __fc (addr + l); + page_restore_rw (addr, l, oldprot); + packet_ok (); + } + break; + case 'c': + if (len =3D=3D 1) + { + /* Clear psr.ss. */ + regs.psr.v &=3D ~(unsigned __int64)PSR$M_SS; + return 1; + } + else + packet_error (0); + break; + case 's': + if (len =3D=3D 1) + { + /* Set psr.ss. */ + regs.psr.v |=3D (unsigned __int64)PSR$M_SS; + return 1; + } + else + packet_error (0); + break; + default: + break; + } + return 0; +} + +/* Raw write to gdb. */ + +static void +sock_write (const unsigned char *buf, int len) +{ + struct _iosb iosb; + unsigned int status; + + /* Write data to connection. */ + status =3D sys$qiow (EFN$C_ENF, /* Event flag. */ + conn_channel, /* I/O channel. */ + IO$_WRITEVBLK, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + (char *)buf, /* P1 - buffer address. */ + len, /* P2 - buffer length. */ + 0, 0, 0, 0); + if (status & STS$M_SUCCESS) + status =3D iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to write data to gdb\n\r"); + LIB$SIGNAL (status); + } +} + +/* Compute the cheksum and send the packet. */ + +static void +send_pkt (void) +{ + unsigned char chksum =3D 0; + unsigned int i; + + for (i =3D 1; i < gdb_blen; i++) + chksum +=3D gdb_buf[i]; + + gdb_buf[gdb_blen] =3D '#'; + byte2hex (gdb_buf + gdb_blen + 1, chksum); + + sock_write (gdb_buf, gdb_blen + 3); + + if (trace_pkt) + { + term_puts (">: "); + term_write ((char *)gdb_buf, gdb_blen + 3); + term_putnl (); + } +} + +/* Read and handle one command. Return 1 is execution must resume. */ + +static int +one_command (void) +{ + struct _iosb iosb; + unsigned int status; + unsigned int off; + unsigned int dollar_off =3D 0; + unsigned int sharp_off =3D 0; + unsigned int cmd_off; + unsigned int cmd_len; + + /* Wait for a packet. */ + while (1) + { + off =3D 0; + while (1) + { + /* Read data from connection. */ + status =3D sys$qiow (EFN$C_ENF, /* Event flag. */ + conn_channel, /* I/O channel. */ + IO$_READVBLK, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. = */ + 0, /* Ast parameter. */ + gdb_buf + off, /* P1 - buffer address. = */ + sizeof (gdb_buf) - off, /* P2 - buffer leng. = */ + 0, 0, 0, 0); + if (status & STS$M_SUCCESS) + status =3D iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to read data from connection\n\r" ); + LIB$SIGNAL (status); + } + +#ifdef RAW_DUMP + term_puts ("{: "); + term_write ((char *)gdb_buf + off, iosb.iosb$w_bcnt); + term_putnl (); +#endif + + gdb_blen =3D off + iosb.iosb$w_bcnt; + + if (off =3D=3D 0) + { + /* Search for '$'. */ + for (dollar_off =3D 0; dollar_off < gdb_blen; dollar_off++) + if (gdb_buf[dollar_off] =3D=3D '$') + break; + if (dollar_off >=3D gdb_blen) + { + /* Not found, discard the data. */ + off =3D 0; + continue; + } + /* Search for '#'. */ + for (sharp_off =3D dollar_off + 1; sharp_off < gdb_blen; sha= rp_off++) + if (gdb_buf[sharp_off] =3D=3D '#') + break; + } + else if (sharp_off >=3D off) + { + /* Search for '#'. */ + for (; sharp_off < gdb_blen; sharp_off++) + if (gdb_buf[sharp_off] =3D=3D '#') + break; + } + + /* Got packet with checksum. */ + if (sharp_off + 2 <=3D gdb_blen) + break; + + off =3D gdb_blen; + if (gdb_blen =3D=3D sizeof (gdb_buf)) + { + /* Packet too large, discard. */ + off =3D 0; + } + } + + /* Validate and acknowledge a packet. */ + { + unsigned char chksum =3D 0; + unsigned int i; + int v; + + for (i =3D dollar_off + 1; i < sharp_off; i++) + chksum +=3D gdb_buf[i]; + v =3D hex2byte (gdb_buf + sharp_off + 1); + if (v !=3D chksum) + { + term_puts ("Discard bad checksum packet\n\r"); + continue; + } + else + { + sock_write ((const unsigned char *)"+", 1); + break; + } + } + } + + if (trace_pkt) + { + term_puts ("<: "); + term_write ((char *)gdb_buf + dollar_off, sharp_off - dollar_off + 1= ); + term_putnl (); + } + + cmd_off =3D dollar_off + 1; + cmd_len =3D sharp_off - dollar_off - 1; + + if (handle_packet (gdb_buf + dollar_off + 1, sharp_off - dollar_off - 1)= =3D=3D 1) + return 1; + + send_pkt (); + return 0; +} + +/* Display the condition given by SIG64. */ + +static void +display_excp (struct chf64$signal_array *sig64) +{ + unsigned int status; + char msg[160]; + unsigned short msglen; + $DESCRIPTOR (msg_desc, msg); + unsigned char outadr[4]; + + status =3D SYS$GETMSG (sig64->chf64$q_sig_name, &msglen, &msg_desc, 0, o= utadr); + if (status & STS$M_SUCCESS) + { + char msg2[160]; + unsigned short msg2len; + struct dsc$descriptor_s msg2_desc =3D + { sizeof (msg2), DSC$K_DTYPE_T, DSC$K_CLASS_S, msg2}; + msg_desc.dsc$w_length =3D msglen; + status =3D SYS$FAOL_64 (&msg_desc, &msg2len, &msg2_desc, + &sig64->chf64$q_sig_arg1); + if (status & STS$M_SUCCESS) + term_write (msg2, msg2len); + } + else + term_puts ("no message"); + term_putnl (); +} + +/* The condition handler. That's the core of the stub. */ + +static int +excp_handler (struct chf$signal_array *sig, + struct chf$mech_array *mech) +{ + unsigned int status; + struct chf64$signal_array *sig64 =3D + (struct chf64$signal_array *)mech->chf$ph_mch_sig64_addr; + struct _intstk *intstk =3D + (struct _intstk *)mech->chf$q_mch_esf_addr; + + unsigned int code =3D sig->chf$l_sig_name & STS$M_COND_ID; + unsigned int cnt =3D sig64->chf64$w_sig_arg_count; + unsigned __int64 pc =3D (&sig64->chf64$q_sig_name)[cnt - 2]; + int i; + int ret =3D SS$_RESIGNAL_64; + + /* Completly ignore some conditions (signaled indirectly by this stub). = */ + switch (code) + { + case LIB$_KEYNOTFOU & STS$M_COND_ID: + return SS$_RESIGNAL_64; + default: + break; + } + + if (trace_excp) + { + term_puts ("excp_handler: "); + term_puthex8 (code); + term_puts (", vec count: "); + term_putdec (cnt); + term_puts (", pc=3D"); + term_puthex8 (pc); + term_putnl (); + } + + /* If break on the entry point, restore the bundle. */ + if (code =3D=3D (SS$_BREAK & STS$M_COND_ID) + && pc =3D=3D entry_pc + && entry_pc !=3D 0) + { + static unsigned int entry_prot; + + if (trace_entry) + term_puts ("initial entry breakpoint\n\r"); + page_set_rw (entry_pc, 16, &entry_prot); + + ots$move3 (16, entry_saved, (void *)entry_pc); + __fc (entry_pc); + page_restore_rw (entry_pc, 16, entry_prot); + + ret =3D SS$_CONTINUE_64; + } + + switch (code) + { + case SS$_ACCVIO & STS$M_COND_ID: + if (trace_excp <=3D 1) + display_excp (sig64); + /* Fall through. */ + case SS$_BREAK & STS$M_COND_ID: + case SS$_OPCDEC & STS$M_COND_ID: + case SS$_TBIT & STS$M_COND_ID: + if (trace_excp > 1) + { + display_excp (sig64); + + term_puts (" intstk: "); + term_putp (intstk); + term_putnl (); + for (i =3D 0; i < cnt + 1; i++) + { + term_puts (" "); + term_puthex8 (((unsigned __int64 *)sig64)[i]); + term_putnl (); + } + } + regs.ip.v =3D pc; + regs.psr.v =3D intstk->intstk$q_ipsr; +#if 1 + /* What a mess. Gdb and linux expects bsp to point after the current + register frame. Adjust. */ + { + unsigned __int64 bsp =3D intstk->intstk$q_bsp; + unsigned int sof =3D intstk->intstk$q_ifs & 0x7f; + unsigned int delta =3D ((bsp >> 3) & 0x3f) + sof; + regs.bsp.v =3D bsp + ((sof + delta / 0x3f) << 3); + } +#else + regs.bsp.v =3D intstk->intstk$q_bsp; +#endif + regs.cfm.v =3D intstk->intstk$q_ifs & 0x3fffffffff; + regs.pfs.v =3D intstk->intstk$q_pfs; + regs.pr.v =3D intstk->intstk$q_preds; + regs.gr[0].v =3D 0; + regs.gr[1].v =3D intstk->intstk$q_gp; + regs.gr[2].v =3D intstk->intstk$q_r2; + regs.gr[3].v =3D intstk->intstk$q_r3; + regs.gr[4].v =3D intstk->intstk$q_r4; + regs.gr[5].v =3D intstk->intstk$q_r5; + regs.gr[6].v =3D intstk->intstk$q_r6; + regs.gr[7].v =3D intstk->intstk$q_r7; + regs.gr[8].v =3D intstk->intstk$q_r8; + regs.gr[9].v =3D intstk->intstk$q_r9; + regs.gr[10].v =3D intstk->intstk$q_r10; + regs.gr[11].v =3D intstk->intstk$q_r11; + regs.gr[12].v =3D (unsigned __int64)intstk + intstk->intstk$l_stkali= gn; + regs.gr[13].v =3D intstk->intstk$q_r13; + regs.gr[14].v =3D intstk->intstk$q_r14; + regs.gr[15].v =3D intstk->intstk$q_r15; + regs.gr[16].v =3D intstk->intstk$q_r16; + regs.gr[17].v =3D intstk->intstk$q_r17; + regs.gr[18].v =3D intstk->intstk$q_r18; + regs.gr[19].v =3D intstk->intstk$q_r19; + regs.gr[20].v =3D intstk->intstk$q_r20; + regs.gr[21].v =3D intstk->intstk$q_r21; + regs.gr[22].v =3D intstk->intstk$q_r22; + regs.gr[23].v =3D intstk->intstk$q_r23; + regs.gr[24].v =3D intstk->intstk$q_r24; + regs.gr[25].v =3D intstk->intstk$q_r25; + regs.gr[26].v =3D intstk->intstk$q_r26; + regs.gr[27].v =3D intstk->intstk$q_r27; + regs.gr[28].v =3D intstk->intstk$q_r28; + regs.gr[29].v =3D intstk->intstk$q_r29; + regs.gr[30].v =3D intstk->intstk$q_r30; + regs.gr[31].v =3D intstk->intstk$q_r31; + regs.br[0].v =3D intstk->intstk$q_b0; + regs.br[1].v =3D intstk->intstk$q_b1; + regs.br[2].v =3D intstk->intstk$q_b2; + regs.br[3].v =3D intstk->intstk$q_b3; + regs.br[4].v =3D intstk->intstk$q_b4; + regs.br[5].v =3D intstk->intstk$q_b5; + regs.br[6].v =3D intstk->intstk$q_b6; + regs.br[7].v =3D intstk->intstk$q_b7; + + /* Send stop reply packet. */ + { + gdb_buf[0] =3D '$'; + gdb_buf[1] =3D 'S'; + gdb_buf[2] =3D '0'; + gdb_buf[3] =3D '5'; + gdb_blen =3D 4; + send_pkt (); + } + while (one_command () =3D=3D 0) + ; + intstk->intstk$q_ipsr =3D regs.psr.v; + ret =3D SS$_CONTINUE_64; + break; + + default: + display_excp (sig64); + break; + } + + return ret; +} + +/* Setup internal trace flags according to GDBSTUB$TRACE logical. */ + +static void +trace_init (void) +{ + unsigned int status, i, start; + unsigned short len; + char resstring[LNM$C_NAMLENGTH]; + static const $DESCRIPTOR (tabdesc, "LNM$DCL_LOGICAL"); + static const $DESCRIPTOR (logdesc, "GDBSTUB$TRACE"); + static const $DESCRIPTOR (pkt_desc, "packets"); + static const $DESCRIPTOR (entry_desc, "entry"); + static const $DESCRIPTOR (except_desc, "except"); + $DESCRIPTOR (sub_desc, resstring); + ILE3 item_lst[2]; + + item_lst[0].ile3$w_length =3D LNM$C_NAMLENGTH; + item_lst[0].ile3$w_code =3D LNM$_STRING; + item_lst[0].ile3$ps_bufaddr =3D resstring; + item_lst[0].ile3$ps_retlen_addr =3D &len; + item_lst[1].ile3$w_length =3D 0; + item_lst[1].ile3$w_code =3D 0; + + /* Translate the logical name. */ + status =3D SYS$TRNLNM (0, /* Attributes of the logical name. */ + (void *)&tabdesc, /* Logical name table. */ + (void *)&logdesc, /* Logical name. */ + 0, /* Access mode. */ + &item_lst); /* Item list. */ + if (status =3D=3D SS$_NOLOGNAM) + return; + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); + + start =3D 0; + for (i =3D 0; i <=3D len; i++) + { + if ((i =3D=3D len || resstring[i] =3D=3D ',') && i !=3D start) + { + sub_desc.dsc$a_pointer =3D resstring + start; + sub_desc.dsc$w_length =3D i - start; + + if (str$case_blind_compare (&sub_desc, (void *)&pkt_desc) =3D=3D= 0) + trace_pkt++; + else if (str$case_blind_compare (&sub_desc, (void *)&entry_desc)= =3D=3D 0) + trace_entry++; + else if (str$case_blind_compare (&sub_desc, (void *)&except_desc= ) =3D=3D 0) + trace_excp++; + else + { + term_puts ("GDBSTUB$TRACE: unknown directive "); + term_write (sub_desc.dsc$a_pointer, sub_desc.dsc$w_length); + term_putnl (); + } + + start =3D i + 1; + } + } +} + +/* Entry point. */ + +static void +stub_start (unsigned __int64 *progxfer, void *cli_util, + void *imghdr, void *imgfile, + unsigned int linkflag, unsigned int cliflag) +{ + int i; + + term_init (); + trace_init (); + + /* Hello banner. */ + term_puts ("Hello gdb stub\n\r"); + if (trace_entry) + { + term_puts ("xfer: "); + term_putp (progxfer); + term_putnl (); + for (i =3D -2; i < 8; i++) + { + term_puthex8 (progxfer[i]); + term_putnl (); + } + } + + /* Search for entry point. */ + entry_pc =3D 0; + for (i =3D 0; progxfer[i]; i++) + entry_pc =3D progxfer[i]; + + if (trace_entry) + { + if (entry_pc =3D=3D 0) + { + term_puts ("No entry point\n\r"); + return; + } + else + { + term_puts ("Entry: "); + term_puthex8 (entry_pc); + term_putnl (); + } + } + + /* Set primary exception vector. */ + { + unsigned int status; + status =3D sys$setexv (0, excp_handler, PSL$C_USER, &prevhnd); + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); + } + + /* Change first instruction to set a breakpoint. */ + { + /* + 01 08 00 40 00 00 [MII] break.m 0x80001 + 00 00 00 02 00 00 nop.i 0x0 + 00 00 04 00 nop.i 0x0;; + */ + static const unsigned char initbp[16] =3D + { 0x01, 0x08, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00 }; + unsigned int entry_prot; + unsigned int status; + + status =3D page_set_rw (entry_pc, 16, &entry_prot); +#if 0 + term_puthex8 (status); + term_putnl (); + term_puthex8 ((status & STS$M_COND_ID)); + term_puthex8 (SS$_NOT_PROCESS_VA); + term_putnl (); +#endif + + if (!(status & STS$M_SUCCESS)) + { + if ((status & STS$M_COND_ID) =3D=3D (SS$_NOT_PROCESS_VA & STS$M_CO= ND_ID)) + { + /* Cannot write here. This can happen when pthreads are used.= */ + entry_pc =3D 0; + term_puts ("gdbstub: cannot set breakpoint on entry\n\r"); + } + else + LIB$SIGNAL (status); + } + + if (entry_pc !=3D 0) + { + ots$move3 (16, (void *)entry_pc, entry_saved); + ots$move3 (16, (void *)initbp, (void *)entry_pc); + __fc (entry_pc); + page_restore_rw (entry_pc, 16, entry_prot); + } + } + +#if 0 + term_puts ("sizeof regs: "); + term_putdec (sizeof (regs)); + term_putnl (); +#endif + + sock_init (); + + /* If it wasn't possible to set a breakpoint on the entry point, + accept gdb commands now. Note that registers are not updated. */ + if (entry_pc =3D=3D 0) + { + while (one_command () =3D=3D 0) + ; + } + + /* We will see! */ + return; +} + +/* Declare the entry point of this relocatable module. */ + +static void stub_start (); + +struct xfer_vector +{ + __int64 impure_start; + __int64 impure_end; + void (*entry) (); +}; + +#pragma __extern_model save +#pragma __extern_model strict_refdef "XFER_PSECT" +struct xfer_vector xfer_vector =3D {0, 0, stub_start}; +#pragma __extern_model restore