diff options
author | J.T. Conklin <jtc@acorntoolworks.com> | 1994-09-19 23:00:48 +0000 |
---|---|---|
committer | J.T. Conklin <jtc@acorntoolworks.com> | 1994-09-19 23:00:48 +0000 |
commit | d6a62067d982e9757878011925731c098276e31b (patch) | |
tree | 67169f400e005ee4fec3521a14b8c6330e4c9824 /gdb/i386-nlmstub.c | |
parent | 8268e3ec917a06345c2d0802412f9e705a1f0f38 (diff) | |
download | gdb-d6a62067d982e9757878011925731c098276e31b.zip gdb-d6a62067d982e9757878011925731c098276e31b.tar.gz gdb-d6a62067d982e9757878011925731c098276e31b.tar.bz2 |
* Makefile.in: Removed prelude.o, i386-nlmstub.o, nlmstub.o,
nlmstub.nlm, and nlmstub targets. Removed NWSOURCE and
NWINCLUDES definitions.
* i386-nlmstub.c: Removed.
Diffstat (limited to 'gdb/i386-nlmstub.c')
-rw-r--r-- | gdb/i386-nlmstub.c | 1164 |
1 files changed, 0 insertions, 1164 deletions
diff --git a/gdb/i386-nlmstub.c b/gdb/i386-nlmstub.c index 109aa14..e69de29 100644 --- a/gdb/i386-nlmstub.c +++ b/gdb/i386-nlmstub.c @@ -1,1164 +0,0 @@ -/* i386-nlmstub.c -- NLM debugging stub for the i386. - - This is originally based on an m68k software stub written by Glenn - Engel at HP, but has changed quite a bit. It was modified for the - i386 by Jim Kingdon, Cygnus Support. It was modified to run under - NetWare by Ian Lance Taylor, Cygnus Support. - - This code is intended to produce an NLM (a NetWare Loadable Module) - to run under NetWare on an i386 platform. To create the NLM, - compile this code into an object file using the NLM SDK on any i386 - host, and use the nlmconv program (available in the GNU binutils) - to transform the resulting object file into an NLM. */ - -/**************************************************************************** - - THIS SOFTWARE IS NOT COPYRIGHTED - - HP offers the following for use in the public domain. HP makes no - warranty with regard to the software or it's performance and the - user accepts the software "AS IS" with all faults. - - HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD - TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - -****************************************************************************/ - -/**************************************************************************** - * - * The following gdb commands are supported: - * - * command function Return value - * - * g return the value of the CPU registers hex data or ENN - * G set the value of the CPU registers OK or ENN - * - * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN - * - * c Resume at current address SNN ( signal NN) - * cAA..AA Continue at address AA..AA SNN - * - * s Step one instruction SNN - * sAA..AA Step one instruction from AA..AA SNN - * - * k kill - * - * ? What was the last sigval ? SNN (signal NN) - * - * All commands and responses are sent with a packet which includes a - * checksum. A packet consists of - * - * $<packet info>#<checksum>. - * - * where - * <packet info> :: <characters representing the command or response> - * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> - * - * When a packet is received, it is first acknowledged with either '+' or '-'. - * '+' indicates a successful transfer. '-' indicates a failed transfer. - * - * Example: - * - * Host: Reply: - * $m0,10#2a +$00010203040506070809101112131415#42 - * - ****************************************************************************/ - -#include <dfs.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <time.h> -#include <aio.h> -#include <conio.h> -#include <advanced.h> -#include <debugapi.h> -#include <process.h> -#include <errno.h> - -/****************************************************/ -/* This information is from Novell. It is not in any of the standard - NetWare header files. */ - -struct DBG_LoadDefinitionStructure -{ - void *reserved1[4]; - LONG reserved5; - LONG LDCodeImageOffset; - LONG LDCodeImageLength; - LONG LDDataImageOffset; - LONG LDDataImageLength; - LONG LDUninitializedDataLength; - LONG LDCustomDataOffset; - LONG LDCustomDataSize; - LONG reserved6[2]; - LONG (*LDInitializationProcedure)(void); -}; - -#define LO_NORMAL 0x0000 -#define LO_STARTUP 0x0001 -#define LO_PROTECT 0x0002 -#define LO_DEBUG 0x0004 -#define LO_AUTO_LOAD 0x0008 - -/* Loader returned error codes */ -#define LOAD_COULD_NOT_FIND_FILE 1 -#define LOAD_ERROR_READING_FILE 2 -#define LOAD_NOT_NLM_FILE_FORMAT 3 -#define LOAD_WRONG_NLM_FILE_VERSION 4 -#define LOAD_REENTRANT_INITIALIZE_FAILURE 5 -#define LOAD_CAN_NOT_LOAD_MULTIPLE_COPIES 6 -#define LOAD_ALREADY_IN_PROGRESS 7 -#define LOAD_NOT_ENOUGH_MEMORY 8 -#define LOAD_INITIALIZE_FAILURE 9 -#define LOAD_INCONSISTENT_FILE_FORMAT 10 -#define LOAD_CAN_NOT_LOAD_AT_STARTUP 11 -#define LOAD_AUTO_LOAD_MODULES_NOT_LOADED 12 -#define LOAD_UNRESOLVED_EXTERNAL 13 -#define LOAD_PUBLIC_ALREADY_DEFINED 14 -/****************************************************/ - -/* The main thread ID. */ -static int mainthread; - -/* An error message for the main thread to print. */ -static char *error_message; - -/* The AIO port handle. */ -static int AIOhandle; - -/* BUFMAX defines the maximum number of characters in inbound/outbound - buffers. At least NUMREGBYTES*2 are needed for register packets */ -#define BUFMAX (REGISTER_BYTES * 2 + 16) - -/* remote_debug > 0 prints ill-formed commands in valid packets and - checksum errors. */ -static int remote_debug = 1; - -static const char hexchars[] = "0123456789abcdef"; - -/* Register values. All of these values *MUST* agree with tm.h */ -#define SP_REGNUM 4 /* Contains address of top of stack */ -#define PC_REGNUM 8 /* Contains program counter */ -#define FP_REGNUM 5 /* Virtual frame pointer */ -#define NUM_REGS 16 /* Number of machine registers */ -#define REGISTER_BYTES (NUM_REGS * 4) /* Total size of registers array */ - -#define ExceptionPC ExceptionEIP -#define DECR_PC_AFTER_BREAK 1 /* int 3 leaves PC pointing after insn */ -#define BREAKPOINT {0xcc} -#define StackFrame T_TSS_StackFrame - -unsigned char breakpoint_insn[] = BREAKPOINT; -#define BREAKPOINT_SIZE (sizeof breakpoint_insn) - -static void flush_i_cache() {} - -static char *mem2hex (void *mem, char *buf, int count, int may_fault); -static char *hex2mem (char *buf, void *mem, int count, int may_fault); -static void set_step_traps (struct StackFrame *); -static void clear_step_traps (struct StackFrame *); - -#if 0 -__main() {}; -#endif - -/* Read a character from the serial port. This must busy wait, but - that's OK because we will be the only thread running anyhow. */ - -static int -getDebugChar () -{ - int err; - LONG got; - unsigned char ret; - - do - { - err = AIOReadData (AIOhandle, (char *) &ret, 1, &got); - if (err != 0) - { - error_message = "AIOReadData failed"; - ResumeThread (mainthread); - return -1; - } - } - while (got == 0); - - return ret; -} - -/* Write a character to the serial port. Returns 0 on failure, - non-zero on success. */ - -static int -putDebugChar (c) - unsigned char c; -{ - int err; - LONG put; - - put = 0; - while (put < 1) - { - err = AIOWriteData (AIOhandle, (char *) &c, 1, &put); - if (err != 0) - ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err, put); - } - return 1; -} - -/* Get the registers out of the frame information. */ - -static void -frame_to_registers (frame, regs) - struct StackFrame *frame; - char *regs; -{ - /* Copy EAX -> EDI */ - mem2hex (&frame->ExceptionEAX, ®s[0 * 4 * 2], 4 * 8, 0); - - /* Copy EIP & PS */ - mem2hex (&frame->ExceptionPC, ®s[8 * 4 * 2], 4 * 2, 0); - - /* Copy CS, SS, DS */ - mem2hex (&frame->ExceptionCS, ®s[10 * 4 * 2], 4 * 3, 0); - - /* Copy ES */ - mem2hex (&frame->ExceptionES, ®s[13 * 4 * 2], 4 * 1, 0); - - /* Copy FS & GS */ - mem2hex (&frame->ExceptionFS, ®s[14 * 4 * 2], 4 * 2, 0); -} - -/* Put the registers back into the frame information. */ - -static void -registers_to_frame (regs, frame) - char *regs; - struct StackFrame *frame; -{ - /* Copy EAX -> EDI */ - hex2mem (®s[0 * 4 * 2], &frame->ExceptionEAX, 4 * 8, 0); - - /* Copy EIP & PS */ - hex2mem (®s[8 * 4 * 2], &frame->ExceptionPC, 4 * 2, 0); - - /* Copy CS, SS, DS */ - hex2mem (®s[10 * 4 * 2], &frame->ExceptionCS, 4 * 3, 0); - - /* Copy ES */ - hex2mem (®s[13 * 4 * 2], &frame->ExceptionES, 4 * 1, 0); - - /* Copy FS & GS */ - hex2mem (®s[14 * 4 * 2], &frame->ExceptionFS, 4 * 2, 0); -} - -/* Turn a hex character into a number. */ - -static int -hex (ch) - char ch; -{ - if ((ch >= 'a') && (ch <= 'f')) - return (ch-'a'+10); - if ((ch >= '0') && (ch <= '9')) - return (ch-'0'); - if ((ch >= 'A') && (ch <= 'F')) - return (ch-'A'+10); - return (-1); -} - -/* Scan for the sequence $<data>#<checksum>. Returns 0 on failure, - non-zero on success. */ - -static int -getpacket (buffer) - char * buffer; -{ - unsigned char checksum; - unsigned char xmitcsum; - int i; - int count; - int ch; - - do - { - /* wait around for the start character, ignore all other characters */ - while ((ch = getDebugChar()) != '$') - if (ch == -1) - return 0; - checksum = 0; - xmitcsum = -1; - - count = 0; - - /* now, read until a # or end of buffer is found */ - while (count < BUFMAX) - { - ch = getDebugChar(); - if (ch == -1) - return 0; - if (ch == '#') - break; - checksum = checksum + ch; - buffer[count] = ch; - count = count + 1; - } - buffer[count] = 0; - - if (ch == '#') - { - ch = getDebugChar (); - if (ch == -1) - return 0; - xmitcsum = hex(ch) << 4; - ch = getDebugChar (); - if (ch == -1) - return 0; - xmitcsum += hex(ch); - - if (checksum != xmitcsum) - { - if (remote_debug) - ConsolePrintf ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", - checksum,xmitcsum,buffer); - /* failed checksum */ - if (! putDebugChar('-')) - return 0; - return 1; - } - else - { - /* successful transfer */ - if (! putDebugChar('+')) - return 0; - /* if a sequence char is present, reply the sequence ID */ - if (buffer[2] == ':') - { - if (! putDebugChar (buffer[0]) - || ! putDebugChar (buffer[1])) - return 0; - /* remove sequence chars from buffer */ - count = strlen(buffer); - for (i=3; i <= count; i++) - buffer[i-3] = buffer[i]; - } - } - } - } - while (checksum != xmitcsum); - - if (remote_debug) - ConsolePrintf ("Received packet \"%s\"\r\n", buffer); - - return 1; -} - -/* Send the packet in buffer. Returns 0 on failure, non-zero on - success. */ - -static int -putpacket (buffer) - char * buffer; -{ - unsigned char checksum; - int count; - int ch; - - if (remote_debug) - ConsolePrintf ("Sending packet \"%s\"\r\n", buffer); - - /* $<packet info>#<checksum>. */ - do - { - if (! putDebugChar('$')) - return 0; - checksum = 0; - count = 0; - - while (ch=buffer[count]) - { - if (! putDebugChar(ch)) - return 0; - checksum += ch; - count += 1; - } - - if (! putDebugChar('#') - || ! putDebugChar(hexchars[checksum >> 4]) - || ! putDebugChar(hexchars[checksum % 16])) - return 0; - - ch = getDebugChar (); - if (ch == -1) - return 0; - } - while (ch != '+'); - - return 1; -} - -static char remcomInBuffer[BUFMAX]; -static char remcomOutBuffer[BUFMAX]; -static short error; - -static void -debug_error (format, parm) - char *format; - char *parm; -{ - if (remote_debug) - { - ConsolePrintf (format, parm); - ConsolePrintf ("\n"); - } -} - -/* This is set if we could get a memory access fault. */ -static int mem_may_fault; - -/* Indicate to caller of mem2hex or hex2mem that there has been an - error. */ -static volatile int mem_err = 0; - -/* These are separate functions so that they are so short and sweet - that the compiler won't save any registers (if there is a fault - to mem_fault, they won't get restored, so there better not be any - saved). */ - -static int -get_char (addr) - char *addr; -{ - return *addr; -} - -static void -set_char (addr, val) - char *addr; - int val; -{ - *addr = val; -} - -/* This bit of assembly language just returns from a function. If a - memory error occurs within get_char or set_char, the debugger - handler points EIP at these instructions to get out. */ - -extern void just_return (); -asm (".globl just_return"); -asm (".globl _just_return"); -asm ("just_return:"); -asm ("_just_return:"); -asm ("leave"); -asm ("ret"); - -/* convert the memory pointed to by mem into hex, placing result in buf */ -/* return a pointer to the last char put in buf (null) */ -/* If MAY_FAULT is non-zero, then we should set mem_err in response to - a fault; if zero treat a fault like any other fault in the stub. */ - -static char * -mem2hex (mem, buf, count, may_fault) - void *mem; - char *buf; - int count; - int may_fault; -{ - int i; - unsigned char ch; - char *ptr = mem; - - mem_may_fault = may_fault; - for (i = 0; i < count; i++) - { - ch = get_char (ptr++); - if (may_fault && mem_err) - return (buf); - *buf++ = hexchars[ch >> 4]; - *buf++ = hexchars[ch % 16]; - } - *buf = 0; - mem_may_fault = 0; - return(buf); -} - -/* convert the hex array pointed to by buf into binary to be placed in mem */ -/* return a pointer to the character AFTER the last byte written */ - -static char * -hex2mem (buf, mem, count, may_fault) - char *buf; - void *mem; - int count; - int may_fault; -{ - int i; - unsigned char ch; - char *ptr = mem; - - mem_may_fault = may_fault; - for (i=0;i<count;i++) - { - ch = hex(*buf++) << 4; - ch = ch + hex(*buf++); - set_char (ptr++, ch); - if (may_fault && mem_err) - return (ptr); - } - mem_may_fault = 0; - return(mem); -} - -/* This function takes the 386 exception vector and attempts to - translate this number into a unix compatible signal value. */ - -static int -computeSignal (exceptionVector) - int exceptionVector; -{ - int sigval; - switch (exceptionVector) - { - case 0 : sigval = 8; break; /* divide by zero */ - case 1 : sigval = 5; break; /* debug exception */ - case 3 : sigval = 5; break; /* breakpoint */ - case 4 : sigval = 16; break; /* into instruction (overflow) */ - case 5 : sigval = 16; break; /* bound instruction */ - case 6 : sigval = 4; break; /* Invalid opcode */ - case 7 : sigval = 8; break; /* coprocessor not available */ - case 8 : sigval = 7; break; /* double fault */ - case 9 : sigval = 11; break; /* coprocessor segment overrun */ - case 10 : sigval = 11; break; /* Invalid TSS */ - case 11 : sigval = 11; break; /* Segment not present */ - case 12 : sigval = 11; break; /* stack exception */ - case 13 : sigval = 11; break; /* general protection */ - case 14 : sigval = 11; break; /* page fault */ - case 16 : sigval = 7; break; /* coprocessor error */ - default: - sigval = 7; /* "software generated"*/ - } - return (sigval); -} - -/**********************************************/ -/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ -/* RETURN NUMBER OF CHARS PROCESSED */ -/**********************************************/ -static int -hexToInt(ptr, intValue) - char **ptr; - int *intValue; -{ - int numChars = 0; - int hexValue; - - *intValue = 0; - - while (**ptr) - { - hexValue = hex(**ptr); - if (hexValue >=0) - { - *intValue = (*intValue <<4) | hexValue; - numChars ++; - } - else - break; - - (*ptr)++; - } - - return (numChars); -} - -static void -set_step_traps (frame) - struct StackFrame *frame; -{ - frame->ExceptionSystemFlags |= 0x100; -} - -static void -clear_step_traps (frame) - struct StackFrame *frame; -{ - frame->ExceptionSystemFlags &= ~0x100; -} - -static void -do_status (ptr, frame) - char *ptr; - struct StackFrame *frame; -{ - int sigval; - - sigval = computeSignal (frame->ExceptionNumber); - - sprintf (ptr, "T%02x", sigval); - ptr += 3; - - sprintf (ptr, "%02x:", PC_REGNUM); - ptr = mem2hex (&frame->ExceptionPC, ptr + 3, 4, 0); - *ptr++ = ';'; - - sprintf (ptr, "%02x:", SP_REGNUM); - ptr = mem2hex (&frame->ExceptionESP, ptr + 3, 4, 0); - *ptr++ = ';'; - - sprintf (ptr, "%02x:", FP_REGNUM); - ptr = mem2hex (&frame->ExceptionEBP, ptr + 3, 4, 0); - *ptr++ = ';'; - - *ptr = '\000'; -} - -/* This function does all command processing for interfacing to gdb. - It is called whenever an exception occurs in the module being - debugged. */ - -static LONG -handle_exception (frame) - struct StackFrame *frame; -{ - int addr, length; - char *ptr; - static int thread_killed = 0; - static int thread_started = 0; - static struct DBG_LoadDefinitionStructure *ldinfo = 0; - static unsigned char first_insn[BREAKPOINT_SIZE]; /* The first instruction in the program. */ - - /* Apparently the bell can sometimes be ringing at this point, and - should be stopped. */ - StopBell (); - - if (remote_debug) - { - ConsolePrintf ("vector=%d: %s, sr=%08x, pc=%08x, thread=%08x\r\n", - frame->ExceptionNumber, - frame->ExceptionDescription, - frame->ExceptionSystemFlags, - frame->ExceptionPC, - GetThreadID ()); - } - - switch (frame->ExceptionNumber) - { - case START_NLM_EVENT: - /* If the NLM just started, we record the module load information - and the thread ID, and set a breakpoint at the first instruction - in the program. */ - - ldinfo = ((struct DBG_LoadDefinitionStructure *) - frame->ExceptionErrorCode); - memcpy (first_insn, ldinfo->LDInitializationProcedure, - BREAKPOINT_SIZE); - memcpy (ldinfo->LDInitializationProcedure, breakpoint_insn, - BREAKPOINT_SIZE); - flush_i_cache (); - return RETURN_TO_PROGRAM; - - case START_THREAD_EVENT: - thread_started = 1; - return RETURN_TO_PROGRAM; - - case TERMINATE_NLM_EVENT: - if (!thread_killed) - { - /* NetWare processes don't have an exit status so we - generate our own */ - sprintf (remcomOutBuffer, "W%02x", 0); - putpacket(remcomOutBuffer); - } - ResumeThread (mainthread); - return RETURN_TO_PROGRAM; - - case ENTER_DEBUGGER_EVENT: - case KEYBOARD_BREAK_EVENT: - /* Pass some events on to the next debugger, in case it will handle - them. */ - return RETURN_TO_NEXT_DEBUGGER; - - case 3: /* Breakpoint */ - /* After we've reached the initial breakpoint, reset it. */ - if (frame->ExceptionPC - DECR_PC_AFTER_BREAK == (LONG) ldinfo->LDInitializationProcedure - && memcmp (ldinfo->LDInitializationProcedure, breakpoint_insn, - BREAKPOINT_SIZE) == 0) - { - memcpy (ldinfo->LDInitializationProcedure, first_insn, - BREAKPOINT_SIZE); - frame->ExceptionPC -= DECR_PC_AFTER_BREAK; - flush_i_cache (); - } - /* Normal breakpoints end up here */ - do_status (remcomOutBuffer, frame); - break; - - default: - /* At the moment, we don't care about most of the unusual NetWare - exceptions. */ - if (frame->ExceptionNumber > 31) - return RETURN_TO_PROGRAM; - - /* Most machine level exceptions end up here */ - do_status (remcomOutBuffer, frame); - break; - - case 11: /* Segment not present */ - case 13: /* General protection */ - case 14: /* Page fault */ - /* If we get a GP fault, and mem_may_fault is set, and the - instruction pointer is near set_char or get_char, then we caused - the fault ourselves accessing an illegal memory location. */ - if (mem_may_fault - && ((frame->ExceptionPC >= (long) &set_char - && frame->ExceptionPC < (long) &set_char + 50) - || (frame->ExceptionPC >= (long) &get_char - && frame->ExceptionPC < (long) &get_char + 50))) - { - mem_err = 1; - /* Point the instruction pointer at an assembly language stub - which just returns from the function. */ - - frame->ExceptionPC = (long) &just_return; - - /* Keep going. This will act as though it returned from - set_char or get_char. The calling routine will check - mem_err, and do the right thing. */ - return RETURN_TO_PROGRAM; - } - /* Random mem fault, report it */ - do_status (remcomOutBuffer, frame); - break; - } - - /* We point the PC at _exit() and continue to kill the NLM, but that - won't work until it's thread has been started. */ - if (thread_started && thread_killed) - { - frame->ExceptionPC = &_exit; - return RETURN_TO_PROGRAM; - } - - /* FIXME: How do we know that this exception has anything to do with - the program we are debugging? We can check whether the PC is in - the range of the module we are debugging, but that doesn't help - much since an error could occur in a library routine. */ - - clear_step_traps (frame); - - if (! putpacket(remcomOutBuffer)) - return RETURN_TO_NEXT_DEBUGGER; - - while (1) - { - error = 0; - remcomOutBuffer[0] = 0; - if (! getpacket (remcomInBuffer)) - return RETURN_TO_NEXT_DEBUGGER; - switch (remcomInBuffer[0]) - { - case '?': - do_status (remcomOutBuffer, frame); - break; - case 'd': - remote_debug = !(remote_debug); /* toggle debug flag */ - break; - case 'g': - /* return the value of the CPU registers */ - frame_to_registers (frame, remcomOutBuffer); - break; - case 'G': - /* set the value of the CPU registers - return OK */ - registers_to_frame (&remcomInBuffer[1], frame); - strcpy(remcomOutBuffer,"OK"); - break; - - case 'm': - /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ - /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ - ptr = &remcomInBuffer[1]; - if (hexToInt(&ptr,&addr)) - if (*(ptr++) == ',') - if (hexToInt(&ptr,&length)) - { - ptr = 0; - mem_err = 0; - mem2hex((char*) addr, remcomOutBuffer, length, 1); - if (mem_err) - { - strcpy (remcomOutBuffer, "E03"); - debug_error ("memory fault"); - } - } - - if (ptr) - { - strcpy(remcomOutBuffer,"E01"); - debug_error("malformed read memory command: %s",remcomInBuffer); - } - break; - - case 'M': - /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ - /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ - ptr = &remcomInBuffer[1]; - if (hexToInt(&ptr,&addr)) - if (*(ptr++) == ',') - if (hexToInt(&ptr,&length)) - if (*(ptr++) == ':') - { - mem_err = 0; - hex2mem(ptr, (char*) addr, length, 1); - - if (mem_err) - { - strcpy (remcomOutBuffer, "E03"); - debug_error ("memory fault"); - } - else - { - strcpy(remcomOutBuffer,"OK"); - } - - ptr = 0; - } - if (ptr) - { - strcpy(remcomOutBuffer,"E02"); - debug_error("malformed write memory command: %s",remcomInBuffer); - } - break; - - case 'c': - case 's': - /* cAA..AA Continue at address AA..AA(optional) */ - /* sAA..AA Step one instruction from AA..AA(optional) */ - /* try to read optional parameter, pc unchanged if no parm */ - ptr = &remcomInBuffer[1]; - if (hexToInt(&ptr,&addr)) - { -/* registers[PC_REGNUM].lo = addr;*/ - ConsolePrintf("Setting PC to 0x%x\n", addr); - while (1); - } - - if (remcomInBuffer[0] == 's') - set_step_traps (frame); - - flush_i_cache (); - return RETURN_TO_PROGRAM; - - case 'k': - /* The undocumented netware call KillMe() is supposed to - schedule the NLM to be killed when it next blocks. What - really happens is that the server hangs as it tries to - unload the NLM. - - So, since netware won't cooperate, we just point the PC - at the start of _exit() and continue, while noting that - we've killed the process. */ - - thread_killed = 1; - if (thread_started) - frame->ExceptionPC = &_exit; - return RETURN_TO_PROGRAM; - - case 'q': /* Query message */ - if (strcmp (&remcomInBuffer[1], "Offsets") == 0) - { - sprintf (remcomOutBuffer, "Text=%x;Data=%x;Bss=%x", - ldinfo->LDCodeImageOffset, - ldinfo->LDDataImageOffset, - ldinfo->LDDataImageOffset + ldinfo->LDDataImageLength); - } - else - sprintf (remcomOutBuffer, "E04, Unknown query %s", &remcomInBuffer[1]); - break; - } - - /* reply to the request */ - if (! putpacket(remcomOutBuffer)) - return RETURN_TO_NEXT_DEBUGGER; - } -} - - -char *progname; - -struct bitRate { - BYTE bitRate; - const char *bitRateString; -}; - -struct bitRate bitRateTable[] = -{ - { AIO_BAUD_50 , "50" }, - { AIO_BAUD_75 , "75" }, - { AIO_BAUD_110 , "110" }, - { AIO_BAUD_134p5 , "134.5" }, - { AIO_BAUD_150 , "150" }, - { AIO_BAUD_300 , "300" }, - { AIO_BAUD_600 , "600" }, - { AIO_BAUD_1200 , "1200" }, - { AIO_BAUD_1800 , "1800" }, - { AIO_BAUD_2000 , "2000" }, - { AIO_BAUD_2400 , "2400" }, - { AIO_BAUD_3600 , "3600" }, - { AIO_BAUD_4800 , "4800" }, - { AIO_BAUD_7200 , "7200" }, - { AIO_BAUD_9600 , "9600" }, - { AIO_BAUD_19200 , "19200" }, - { AIO_BAUD_38400 , "38400" }, - { AIO_BAUD_57600 , "57600" }, - { AIO_BAUD_115200, "115200" }, - { -1, NULL } -}; - -char dataBitsTable[] = "5678"; - -char *stopBitsTable[] = { "1", "1.5", "2" }; - -char parity[] = "NOEMS"; - -/* Start up. The main thread opens the named serial I/O port, loads - the named NLM module and then goes to sleep. The serial I/O port - is named as a board number and a port number. It would be more DOS - like to provide a menu of available serial ports, but I don't want - to have to figure out how to do that. */ - -int -main (argc, argv) - int argc; - char **argv; -{ - int hardware, board, port; - BYTE bitRate; - BYTE dataBits; - BYTE stopBits; - BYTE parityMode; - LONG err; - struct debuggerStructure s; - int cmdindx; - char *cmdlin; - int i; - - /* set progname */ - progname = "nlmstub"; - - hardware = -1; - board = 0; - port = 0; - - /* set default serial line characteristics */ - bitRate = AIO_BAUD_9600; - dataBits = AIO_DATA_BITS_8; - stopBits = AIO_STOP_BITS_1; - parityMode = AIO_PARITY_NONE; - - cmdindx = 0; - for (argc--, argv++; *argv; argc--, argv++) - { - char *bp; - char *ep; - - if (strnicmp(*argv, "BAUD=", 5) == 0) - { - struct bitRate *brp; - - bp = *argv + 5; - for (brp = bitRateTable; brp->bitRate != (BYTE) -1; brp++) - { - if (strcmp(brp->bitRateString, bp) == 0) - { - bitRate = brp->bitRate; - break; - } - } - - if (brp->bitRateString == NULL) - { - fprintf(stderr, "%s: %s: unknown or unsupported bit rate", - progname, bp); - exit (1); - } - } - else if (strnicmp(*argv, "NODE=", 5) == 0) - { - bp = *argv + 5; - board = strtol (bp, &ep, 0); - if (ep == bp || *ep != '\0') - { - fprintf (stderr, "%s: %s: expected integer argument\n", - progname, bp); - exit(1); - } - } - else if (strnicmp(*argv, "PORT=", 5) == 0) - { - bp = *argv + 5; - port = strtol (bp, &ep, 0); - if (ep == bp || *ep != '\0') - { - fprintf (stderr, "%s: %s: expected integer argument\n", - progname, bp); - exit(1); - } - } - else - { - break; - } - - cmdindx++; - } - - if (argc == 0) - { - fprintf (stderr, - "Usage: load %s [options] program [arguments]\n", progname); - exit (1); - } - - err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle); - if (err != AIO_SUCCESS) - { - switch (err) - { - case AIO_PORT_NOT_AVAILABLE: - fprintf (stderr, "Port not available\n"); - break; - - case AIO_BOARD_NUMBER_INVALID: - case AIO_PORT_NUMBER_INVALID: - fprintf (stderr, "No such port\n"); - break; - - default: - fprintf (stderr, "Could not open port: %d\n", err); - break; - } - - exit (1); - } - - err = AIOConfigurePort (AIOhandle, bitRate, dataBits, stopBits, parityMode, - AIO_HARDWARE_FLOW_CONTROL_OFF); - - if (err == AIO_QUALIFIED_SUCCESS) - { - AIOPORTCONFIG portConfig; - - fprintf (stderr, "Port configuration changed!\n"); - - portConfig.returnLength = sizeof(portConfig); - AIOGetPortConfiguration (AIOhandle, &portConfig, NULL); - - fprintf (stderr, - " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\ - Flow:%s\n", - bitRateTable[portConfig.bitRate].bitRateString, - dataBitsTable[portConfig.dataBits], - stopBitsTable[portConfig.stopBits], - parity[portConfig.parityMode], - portConfig.flowCtrlMode ? "ON" : "OFF"); - } - else if (err != AIO_SUCCESS) - { - fprintf (stderr, "Could not configure port: %d\n", err); - AIOReleasePort (AIOhandle); - exit (1); - } - - if (AIOSetExternalControl(AIOhandle, AIO_EXTERNAL_CONTROL, - (AIO_EXTCTRL_DTR | AIO_EXTCTRL_RTS)) - != AIO_SUCCESS) - { - LONG extStatus, chgdExtStatus; - - fprintf (stderr, "Could not set desired port controls!\n"); - AIOGetExternalStatus (AIOhandle, &extStatus, &chgdExtStatus); - fprintf (stderr, "Port controls now: %d, %d\n", extStatus, - chgdExtStatus); - } - - /* Register ourselves as an alternate debugger. */ - memset (&s, 0, sizeof s); - s.DDSResourceTag = ((struct ResourceTagStructure *) - AllocateResourceTag (GetNLMHandle (), - (BYTE *)"gdbserver", - DebuggerSignature)); - if (s.DDSResourceTag == 0) - { - fprintf (stderr, "AllocateResourceTag failed\n"); - AIOReleasePort (AIOhandle); - exit (1); - } - s.DDSdebuggerEntry = handle_exception; - s.DDSFlags = TSS_FRAME_BIT; - - err = RegisterDebuggerRTag (&s, AT_FIRST); - if (err != 0) - { - fprintf (stderr, "RegisterDebuggerRTag failed\n"); - AIOReleasePort (AIOhandle); - exit (1); - } - - /* Get the command line we were invoked with, and advance it past - our name and command line arguments. */ - cmdlin = getcmd ((char *) NULL); - for (i = 0; i < cmdindx; i++) - { - while (! isspace (*cmdlin)) - cmdlin++; - while (isspace (*cmdlin)) - cmdlin++; - } - - /* In case GDB is started before us, ack any packets (presumably - "$?#xx") sitting there. */ - if (! putDebugChar ('+')) - { - fprintf (stderr, "putDebugChar failed\n"); - UnRegisterDebugger (&s); - AIOReleasePort (AIOhandle); - exit (1); - } - - mainthread = GetThreadID (); - - if (remote_debug > 0) - ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n", - cmdlin, __GetScreenID (GetCurrentScreen())); - - /* Start up the module to be debugged. */ - err = LoadModule ((struct ScreenStruct *) __GetScreenID (GetCurrentScreen()), - (BYTE *)cmdlin, LO_DEBUG); - if (err != 0) - { - fprintf (stderr, "LoadModule failed: %d\n", err); - UnRegisterDebugger (&s); - AIOReleasePort (AIOhandle); - exit (1); - } - - /* Wait for the debugger to wake us up. */ - if (remote_debug > 0) - ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread); - SuspendThread (mainthread); - if (remote_debug > 0) - ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread); - - /* If we are woken up, print an optional error message, deregister - ourselves and exit. */ - if (error_message != NULL) - fprintf (stderr, "%s\n", error_message); - UnRegisterDebugger (&s); - AIOReleasePort (AIOhandle); - exit (0); -} |