⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 remote.cc

📁 avrrice软件用于AVR单片机的JTAG调试.
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* *	avarice - The "avarice" program. *	Copyright (C) 2001 Scott Finneran *      Copyright (C) 2002 Intel Corporation * *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License Version 2 *      as published by the Free Software Foundation. * *	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, write to the Free Software *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * * This file contains functions for interfacing with the GDB remote protocol. */#include <stdlib.h>#include <string.h>#include <termios.h>#include <sys/time.h>#include <unistd.h>#include <errno.h>#include <stdio.h>#include <fcntl.h>#include <signal.h>#include "avarice.h"#include "remote.h"#include "jtag.h"enum{    /** BUFMAX defines the maximum number of characters in     * inbound/outbound buffers at least NUMREGBYTES*2 are needed for     * register packets     */    BUFMAX      = 400,    NUMREGS     = 32/* + 1 + 1 + 1*/, /* SREG, FP, PC */    SREG	= 32,    SP		= 33,    PC		= 34,    // Number of bytes of registers.  See GDB gdb/avr-tdep.c    NUMREGBYTES = (NUMREGS + 1 + 2 + 4),};static char remcomInBuffer[BUFMAX];static char remcomOutBuffer[BUFMAX];static void ok();static void error(int n);int gdbFileDescriptor = -1;void gdbCheck(int status){    unixCheck(status, GDB_CAUSE);}void setGdbFile(int fd){    gdbFileDescriptor = fd;    int ret = fcntl(gdbFileDescriptor, F_SETFL, O_NONBLOCK);    gdbCheck(ret);}static void waitForGdbOutput(void){    int numfds;    fd_set writefds;    FD_ZERO (&writefds);    FD_SET (gdbFileDescriptor, &writefds);    numfds = select (gdbFileDescriptor + 1, 0, &writefds, 0, 0);    gdbCheck(numfds);}/** Send single char to gdb. Abort in case of problem. **/static void putDebugChar(char c){    // This loop busy waits when it cannot write to gdb.    // But that shouldn't happen    for (;;)    {	int ret = write(gdbFileDescriptor, &c, 1);	if (ret == 1)	    return;	if (ret == 0) // this shouldn't happen?	    check(false, GDB_CAUSE);	if (errno != EAGAIN)	    gdbCheck(ret);	waitForGdbOutput();    }}static void waitForGdbInput(void){    int numfds;    fd_set readfds;    FD_ZERO (&readfds);    FD_SET (gdbFileDescriptor, &readfds);    numfds = select (gdbFileDescriptor + 1, &readfds, 0, 0, 0);    gdbCheck(numfds);}/** Return single char read from gdb. Abort in case of problem,    exit cleanly if EOF detected on gdbFileDescriptor. **/int getDebugChar(void){    uchar c = 0;    int result;    do    {	waitForGdbInput();	result = read(gdbFileDescriptor, &c, 1);    }    while (result < 0 && errno == EAGAIN);    gdbCheck(result);    if (result == 0) // gdb exited    {	statusOut("gdb exited.\n");	resumeProgram();	exit(0);    }    return (int)c;}int checkForDebugChar(void){    uchar c = 0;    int result;    result = read(gdbFileDescriptor, &c, 1);    if (result < 0 && errno == EAGAIN)	return -1;    gdbCheck(result);    if (result == 0) // gdb exited    {	statusOut("gdb exited.\n");	resumeProgram();	exit(0);    }    return (int)c;}    static const unsigned char hexchars[] = "0123456789abcdef";static char *byteToHex(uchar x, char *buf){    *buf++ = hexchars[x >> 4];    *buf++ = hexchars[x & 0xf];    return buf;}static int hex(unsigned 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);}/** Convert hex string at '*ptr' to an integer.    Advances '*ptr' to 1st non-hex character found.    Returns number of characters used in conversion. **/static int hexToInt(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);}/** Convert the memory pointed to by mem into hex, placing result in buf.    Return a pointer to the last char put in buf (null).**/static char *mem2hex(uchar *mem, char *buf, int count){    for (int i = 0; i < count; i++)	buf = byteToHex(*mem++, buf);    *buf = 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 uchar *hex2mem(char *buf, uchar *mem, int count){    int i;    unsigned char ch;    for(i = 0; i < count; i++)    {	ch = hex(*buf++) << 4;	ch = ch + hex(*buf++);	*mem++ = ch;    }    return (mem);}/** Convert the binary stream in BUF to memory.    Gdb will escape $, #, and the escape char (0x7d).    'count' is the total number of bytes to write into    memory.**/static uchar *bin2mem(char *buf, uchar *mem, int count){    int i;    for(i = 0; i < count; i++)    {	// Check for any escaped characters. Be paranoid and	// only unescape chars that should be escaped.	if(*buf == 0x7d)	{	    switch (*(buf + 1))	    {	    case 0x3:	// #	    case 0x4:	// $	    case 0x5d:	// escape char		buf++;		*buf |= 0x20;		break;	    default:		// nothing		break;	    }	}	*mem++ = *buf++;    }    return mem;}static void putpacket(char *buffer);void vgdbOut(const char *fmt, va_list args){    // We protect against reentry because putpacket could try and report    // an error which would lead to a call back to vgdbOut    static bool reentered = false;    if (gdbFileDescriptor >= 0 && !reentered)    {	char textbuf[BUFMAX], hexbuf[2 * BUFMAX], *textscan, *hexscan;	reentered = true;	vsnprintf(textbuf, BUFMAX, fmt, args);	hexscan = hexbuf;	*hexscan++ = 'O';	for (textscan = textbuf; *textscan; textscan++)	    hexscan = byteToHex(*textscan, hexscan);	*hexscan = '\0';	putpacket(hexbuf);	reentered = false;    }}void gdbOut(const char *fmt, ...){  va_list args;  va_start(args, fmt);  vgdbOut(fmt, args);  va_end(args);}/** Fill 'remcomOutBuffer' with a status report for signal 'sigval'    Reply with a packet of the form:      "Tss20:rr;21:llhh;22:aabbccdd;"    where (all values in hex):      ss       = signal number (usually SIGTRAP)      rr       = SREG value      llhh     = SPL:SPH  (stack pointer)      aabbccdd = PC (program counter)    This actually saves having to read the 32 general registers when stepping    over code since gdb won't send a 'g' packet until the PC it is hunting for    is found.  */static void reportStatusExtended(int sigval){    uchar *jtagBuffer;    unsigned long pc = getProgramCounter();    // Read in SPL SPH SREG    jtagBuffer = jtagRead(0x5D + DATA_SPACE_ADDR_OFFSET, 0x03);    if (jtagBuffer)    {        // We have SPL SPH SREG and need SREG SPL SPH        snprintf (remcomOutBuffer, sizeof(remcomOutBuffer),                  "T%02x" "20:%02x;" "21:%02x%02x;" "22:%02x%02x%02x%02x;",                  sigval & 0xff,                  jtagBuffer[2], // SREG                  jtagBuffer[0], // SPL                  jtagBuffer[1], // SPH                  pc & 0xff, (pc >> 8) & 0xff,                  (pc >> 16) & 0xff, (pc >> 24) & 0xff);        delete [] jtagBuffer;        jtagBuffer = 0;    }    else    {        error(1);        return;    }}/** Fill 'remcomOutBuffer' with a status report for signal 'sigval' **/static void reportStatus(int sigval){    char *ptr = remcomOutBuffer;    // We could use 'T'. But this requires reading SREG, SP, PC at least, so    // won't be significantly faster than the 'g' operation that gdb will    // request if we use 'S' here. [TRoth/2003-06-12: this is not necessarily    // true. See above comment for reportStatusExtended().]    *ptr++ = 'S';	// notify gdb with signo    ptr = byteToHex(sigval, ptr);    *ptr++ = 0;}// little-endian word readunsigned int readLWord(unsigned int address){    unsigned char *mem = jtagRead(DATA_SPACE_ADDR_OFFSET + address, 2);    if (!mem)	return 0;		// hmm    unsigned int val = mem[0] | mem[1] << 8;    delete[] mem;    return val;}// big-endian word readunsigned int readBWord(unsigned int address){    unsigned char *mem = jtagRead(DATA_SPACE_ADDR_OFFSET + address, 2);    if (!mem)	return 0;		// hmm    unsigned int val = mem[0] << 8 | mem[1];    delete[] mem;    return val;}unsigned int readSP(void){    return readLWord(0x5d);}bool handleInterrupt(void){    bool result;    // Set a breakpoint at return address    debugOut("INTERRUPT\n");    unsigned int intrSP = readSP();    unsigned int retPC = readBWord(intrSP + 1) << 1;    debugOut("INT SP = %x, retPC = %x\n", intrSP, retPC);    bool needBP = !codeBreakpointAt(retPC);    for (;;)    {	if (needBP)	{	    // If no breakpoint at return address (normal case),	    // add one.	    // Normally, this breakpoint add should succeed as gdb shouldn't	    // be using a momentary breakpoint when doing a step-through-range,	    // thus leaving is a free hw breakpoint. But if for some reason it	    // the add fails, interrupt the program at the interrupt handler	    // entry point	    if (!addBreakpoint(retPC, CODE, 0))		return false;	}	result = jtagContinue(true);	if (needBP)	    deleteBreakpoint(retPC, CODE, 0);	if (!result || !needBP) // user interrupt or hit user BP at retPC	    break;	// We check that SP is > intrSP. If SP <= intrSP, this is just	// an unrelated excursion to retPC	if (readSP() > intrSP)	    break;    }    return result;}static bool stepThrough(int start, int end){    // Try and use a breakpoint at end and "break on change of flow"    // This doesn't seem to provide much benefit...    bool flowIntr = !codeBreakpointBetween(start, end);    for (;;)     {	if (flowIntr)	{	    setJtagParameter(JTAG_P_BP_FLOW, 1);	    stopAt(end);	    if (!jtagContinue(false))		return false;	}	else	{	    if (!jtagSingleStep())		gdbOut("Failed to single-step");	    int gdbIn = checkForDebugChar();	    if (gdbIn >= 0)		if (gdbIn == 3)		    return false;		else		    debugOut("Unexpected GDB input `%02x'\n", gdbIn);	}	for (;;)	{	    int newPC = getProgramCounter();	    if (codeBreakpointAt(newPC))		return true;	    if (newPC >= start && newPC < end)		break;	    // assume interrupt when PC goes into interrupt table	    if (ignoreInterrupts && newPC < global_p_device_def->vectors_end)	    {		if (!handleInterrupt())		    return false;	    }	    else		return true;	}    }}static bool singleStep(){    if (!jtagSingleStep())	gdbOut("Failed to single-step");    int newPC = getProgramCounter();    if (codeBreakpointAt(newPC))	return true;    // assume interrupt when PC goes into interrupt table    if (ignoreInterrupts && newPC < global_p_device_def->vectors_end) 	return handleInterrupt();    return true;}/** Read packet from gdb into remcomInBuffer, check checksum and confirm    reception to gdb.    Return pointer to null-terminated, actual packet data (without $, #,    the checksum)**/static char *getpacket(void){    char *buffer = &remcomInBuffer[0];    unsigned char checksum;    unsigned char xmitcsum;    int count;    char ch;    // scan for the sequence $<data>#<checksum>    while(1)    {	// wait around for the start character, ignore all other characters	while((ch = getDebugChar()) != '$')	    ;      retry:	checksum = 0;	xmitcsum = 0; // This was -1 but compiler got upset	count = 0;	// now, read until a # or end of buffer is found	while(count < BUFMAX - 1)	{	    ch = getDebugChar();	    if(ch == '$')	    {		goto retry;	    }	    if(ch == '#')	    {		break;	    }	    checksum = checksum + ch;	    buffer[count] = ch;	    count = count + 1;	}	buffer[count] = 0;	if(ch == '#')	{	    ch = getDebugChar();	    xmitcsum = hex(ch) << 4;	    ch = getDebugChar();	    xmitcsum += hex(ch);	    if(checksum != xmitcsum)	    {		char buf[16];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -