Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

gdbremote.cpp

00001 /*
00002  * This file is part of Jelie,
00003  * (c) 2002 Julien Pilet <julien.pilet@epfl.ch> and
00004  * Stephane Magnenat <stephane.magnenat@epfl.ch>
00005  *
00006  * Jelie is free software; you can redistribute it
00007  * and/or modify it under the terms of the GNU General Public License as
00008  * published by the Free Software Foundation; either version 2 of the License,
00009  * or (at your option) any later version.
00010  *
00011  * Jelie is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with Foobar; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /* \file
00022  * \brief gdb protocol talking
00023  *
00024  * This file contains the glue between gdb and jelie.
00025  */
00026 
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <assert.h>
00030 #include "jtagpxa250.h"
00031 #include "gdbremote.h"
00032 #include "debug.h"
00033 #include "step.h"
00034 
00035 GdbRemote::GdbRemote(JTAGpxa250 *pxa) : pxa(pxa), clientSocket(-1), running(false) {
00036         sSocket = -1;
00037         pxa->registerTargetReadyCallback(callback, this);
00038 }
00039 
00040 GdbRemote::~GdbRemote() {
00041         //if (sSocket != -1)
00042         //      close_socket(sSocket);
00043         if (clientSocket != -1)
00044                 close_socket(clientSocket);
00045 }
00046 
00047 bool GdbRemote::openPort(int port) {
00048         return tcpstartsrv(port, 1) == 0;
00049 }
00050 
00051 int GdbRemote::prepareFD_SET(fd_set *set) {
00052         int max = 0;
00053 
00054         if (sSocket > 0) {
00055                 FD_SET(sSocket, set);
00056                 max = sSocket;
00057         }
00058 
00059         if (clientSocket > 0) {
00060                 FD_SET(clientSocket, set);
00061                 if (clientSocket > max) max = clientSocket;
00062         }
00063         return max;
00064 }
00065 
00066 void GdbRemote::processFD_SET(fd_set *set) {
00067 
00068         if (sSocket != -1 && FD_ISSET(sSocket, set)) {
00069                 struct  sockaddr_in addr;
00070                 socklen_t addrLen = sizeof(addr);
00071                 int sock = accept(sSocket, (struct sockaddr *) &addr, &addrLen);
00072                 if (sock == -1) {
00073                         perror("accept()");
00074                         fprintf(stderr, "TCP connection failed.\n");
00075                 } else {
00076                         if (clientSocket == -1) {
00077                                 // good. We can accept the connection.
00078                                 printf("TCP connection accepted from %s\n", inet_ntoa(addr.sin_addr) );
00079                                 clientSocket = sock;
00080                         } else {
00081                                 printf("TCP connection rejected from %s: already connected.\n", 
00082                                                 inet_ntoa(addr.sin_addr) );
00083                                 close_socket(sock);
00084                         }
00085                 }
00086         }
00087 
00088         if (clientSocket != -1 && FD_ISSET(clientSocket, set)) {
00089                 bufferLength = read(clientSocket, buffer, sizeof(buffer) - 1);
00090 
00091                 if ( bufferLength <= 0 ) {
00092                         printf("Read error from TCP client. Closing connection.\n");
00093                         close_socket(clientSocket);
00094                         clientSocket = -1;
00095                 } else {
00096                         buffer[bufferLength] = 0;
00097                         debugMessage(GDB_REMOTE_DEBUG, "<- \"%s\"\n", buffer);
00098                         parse();
00099                 }
00100         }
00101 }
00102 
00103 void GdbRemote::printError() {
00104         geterror();
00105 }
00106 
00107 void GdbRemote::parse() {
00108 
00109         reset();
00110 
00111         // check if the target is ready
00112         pxa->pollForTX();
00113 
00114         do {
00115 
00116                 switch (current()) {
00117                 case '+': break;
00118                 case '-': printf("TCP: warning: GDB refused last packet\n"); break;
00119                 case '$': parsePacket(); break;
00120                 case 3: pxa->extBreak(); break;
00121                 default:
00122                         printf("TCP: parse error (%c %d)\n", current(), current());
00123                 }
00124 
00125         } while(next());
00126 }
00127 
00128 void GdbRemote::parsePacket() {
00129 
00130         assert( current() == '$' );
00131 
00132         unsigned char sum = 0;
00133 
00134         unsigned char * packet = buffer + ptr;
00135         unsigned char * eopacket = (unsigned char *) index((char *)packet, '#');
00136 
00137         if (!eopacket) {
00138                 fprintf(stderr, "TCP error: end of packet not found.\n");
00139                 ptr = bufferLength;
00140                 return;
00141         }
00142 
00143         int len = eopacket - packet - 1;
00144 
00145         for (int i=1; i <= len; ++i) {
00146                 sum += packet[i];
00147         }
00148         
00149         unsigned char packetSum = strtol((char *)packet + len + 2, 0, 16);
00150 
00151         if (packetSum != sum) {
00152                 printf("gdb protocol checksum error (%02X, %02X)\n", sum, packetSum);
00153                 message[0] = '-';
00154                 write(clientSocket, message, 1);
00155                 debugMessage(GDB_REMOTE_DEBUG,"-> '-'\n");
00156 
00157                 // eat the invalid packet
00158                 while(current() != '#') next();
00159                 ptr += 2;
00160         } else {
00161                 // tell gdb we got the packet
00162                 message[0] = '+';
00163                 write(clientSocket, message, 1);
00164                 debugMessage(GDB_REMOTE_DEBUG,"-> '+'\n");
00165 
00166                 next(); // eat the '$'
00167                 parseValidPacket();
00168         }
00169 }
00170 
00171 unsigned char GdbRemote::toAsciiHex(unsigned int v) {
00172         unsigned char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
00173         return hexChars[v&0x0F];
00174 }
00175 
00176 void GdbRemote::sendPacket() {
00177         unsigned char sum = 0;
00178         int len = strlen(message) + 4;
00179         unsigned char *sendBuff = (unsigned char *) alloca(len + 1);
00180         unsigned char *p = sendBuff;
00181 
00182         *(p++) = '$';
00183 
00184         for (int i=0; message[i]; ++i) {
00185                 *(p++) = message[i];
00186                 sum += message[i];
00187         }
00188         *(p++) = '#';
00189         *(p++) = toAsciiHex(sum >> 4);
00190         *(p++) = toAsciiHex(sum & 0x0F);
00191         *p = 0;
00192         write(clientSocket, sendBuff, len);
00193         debugMessage(GDB_REMOTE_DEBUG,"-> '%s'\n", sendBuff);
00194 }
00195 
00196 void GdbRemote::hexPrintWord(unsigned char *str, unsigned int val) {
00197 
00198         for (int i=0; i<4; ++i) {
00199                 str[i*2] = toAsciiHex(val >> ((i*8)+4));
00200                 str[i*2+1] = toAsciiHex(val>>(i*8));
00201         }
00202 }
00203 
00204 unsigned char GdbRemote::asciiToHex(unsigned char c) {
00205         if (c >= 'a' && c <= 'f')
00206                 return c - 'a' + 0xA;
00207         if (c >= '0' && c <= '9')
00208                 return c - '0';
00209         if (c >= 'A' && c <= 'F')
00210                 return c - 'A' + 0xA;
00211         return 0;
00212 }
00213 
00214 unsigned int GdbRemote::parseHexByte() {
00215         unsigned char h, l, c;
00216 
00217         h = asciiToHex(c=current());
00218 
00219         if (c!='#') 
00220                 next();
00221 
00222         l = asciiToHex(c=current());
00223 
00224         if (c!='#') 
00225                 next();
00226 
00227         return (h << 4) + l;
00228 }
00229         
00231 unsigned int GdbRemote::parseHexWord() {
00232         unsigned int r=0;
00233 
00234         for (int i=0; i < 4; ++i) {
00235                 r += parseHexByte() << (i*8);
00236         }
00237         return r;
00238 }
00239 
00240 void GdbRemote::callback(void *p) {
00241         GdbRemote *t = (GdbRemote *) p;
00242 
00243         if (t->running) {
00244                 jelie_cancel_bpt(); /* delete any "step" breakpoints */
00245                 t->lastSignal();
00246         }
00247 
00248         t->running = false;
00249 }
00250 
00251 void GdbRemote::query() {
00252         next();
00253 
00254         if (memcmp(buffer + ptr, "Offsets", 7) == 0) {
00255                 sprintf(message, "Text=%x;Data=%x;Bss=%x", 0,0,0);
00256                 sendPacket();
00257                 return;
00258         }
00259 
00260         // query not understood
00261         message[0] = 0;
00262         sendPacket();
00263 }       
00264 
00265 void GdbRemote::lastSignal() {
00266         sprintf(message, "T05");
00267         sendPacket();
00268 }
00269 
00270 void GdbRemote::setThread() {
00271         sprintf(message, "OK");
00272         sendPacket();
00273 }
00274 
00275 void GdbRemote::getRegisters() {
00276         message[0] = 0;
00277         char *p = message;
00278         unsigned int i;
00279         for (i =0; i<16; ++i) {
00280                 hexPrintWord((unsigned char *)p, pxa->getSavePlace(i));
00281                 p += 8;
00282         }
00283         for (i=0; i< ((96 * 8 + 32) / 8); ++i) {
00284                 sprintf(p, "00");
00285                 p+=2;
00286         }
00287         hexPrintWord((unsigned char *)p, pxa->getSavePlace(16));
00288         p[8]=0;
00289         sendPacket();
00290 }
00291 
00292 void GdbRemote::setRegisters() {
00293         unsigned i;
00294 
00295         // eat the 'G'
00296         next(); 
00297 
00298         for (i=0; i<16; ++i) {
00299                 pxa->setSavePlace(i, parseHexWord());
00300         }
00301 
00302         // skip FPU regs
00303         for (i=0; i< ((96 * 8 + 32)/8); ++i)
00304                 next();
00305 
00306         pxa->setSavePlace(16, parseHexWord());
00307 
00308         sprintf(message, "OK");
00309         sendPacket();
00310 }
00311 
00312 void GdbRemote::readMem() {
00313 
00314         // eat the 'm'
00315         next(); 
00316 
00317         unsigned char *nextStr;
00318         unsigned int addr, len, unaligned;
00319 
00320         addr = strtoul((char *)buffer + ptr, (char **) &nextStr, 16);
00321         unaligned = addr & 0x3;
00322         addr = addr & (~0x3);
00323         len = unaligned + strtoul((char *)nextStr + 1, 0, 16);
00324 
00325         if ((len) & 0x3) len = (len & ~0x3) + 4;
00326         
00327         if (2*len >= GDB_REMOTE_BUFFER_SIZE) {
00328                 fprintf(stderr, "gdb remote: send buffer size too small to send %d bytes of memory !\n",
00329                                 len);
00330         }
00331 
00332         unsigned int *data = (unsigned int *) alloca(len);
00333         pxa->getData(addr, len / 4, data);
00334         nextStr = (unsigned char *)message;
00335 
00336         // do this mess if GDB tries to read an unaligned address
00337         for (unsigned int j= unaligned; j<4; j++) {
00338                 unsigned int byte = data[0] >> (j*8);   // little endian
00339                 nextStr[0] = toAsciiHex(byte >> 4);
00340                 nextStr[1] = toAsciiHex(byte);
00341                 nextStr+=2;
00342         }
00343 
00344         // now it's aligned. Much easier.
00345         for (unsigned int i=1; i < len/4; ++i) {
00346                 hexPrintWord(nextStr, data[i]);
00347                 nextStr+=8;
00348         }
00349 
00350         // terminate the string
00351         nextStr[0] = 0;
00352 
00353         sendPacket();
00354 }
00355 
00356 void GdbRemote::writeMem() {
00357 
00358         // eat the 'M'
00359         next();
00360 
00361         unsigned char *nextStr;
00362         unsigned int addr, len;
00363 
00364         // get the address
00365         addr = strtoul((char *)buffer + ptr, (char **)&nextStr, 16);
00366 
00367         // we want to deal with 32 bits aligned address. 
00368         unsigned int unaligned = addr & 0x3;
00369         addr = addr & (~0x3);
00370         len = unaligned + strtoul((char *)nextStr+1, (char **)&nextStr, 16);
00371 
00372         ptr = nextStr - buffer;
00373         next(); // skip the ':' or whatever separates length from data
00374         
00375         unsigned int *data = (unsigned int *) alloca(len + 4);
00376 
00377         // to write a partial word, we have to fetch the word, modify
00378         // the byte(s), and write it back. Fetch the begining word.
00379         if (unaligned) {
00380                 pxa->getData(addr, 1, data);
00381                 pxa->pollForTX();
00382         }
00383 
00384         // same problem at the end of the transmission
00385         if ((len & 0x3) && len > 4) {
00386                 pxa->getData(addr + (len/4), 1, data + (len/4));
00387                 pxa->pollForTX();
00388         }
00389 
00390         // now read bytes from the gdb packet
00391         for (unsigned int i=unaligned; i<len; i++) {
00392                 unsigned int w =  i/4;
00393                 unsigned int b =  i & 0x3;
00394 
00395                 // replace the 8 concerned bits
00396                 data[w] = (data[w] & ~(0xFF<<(b*8))) | (parseHexByte() << (b*8));
00397         }
00398         
00399         // HACK: replace undefined instruction by 'bkpt #0'
00400         if (len == 4 && data[0] == 0xe7ffdefe)
00401                 data[0] = BKPT_0_INSTR;
00402 
00403         pxa->putData(addr, (len / 4) + (len&0x3 ? 1 : 0), data);
00404 
00405         sprintf(message, "OK");
00406         sendPacket();
00407 }
00408 
00409 void GdbRemote::resumeExec() {
00410 
00411         // if we're trying to exec a breakpoint, skip it.
00412         unsigned int instr;
00413         pxa->getData(pxa->getSavePlace(15), 1, &instr);
00414         pxa->pollForTX();
00415 
00416         if ((instr & 0xFFF000F0) == BKPT_0_INSTR)
00417                 pxa->setSavePlace(15, pxa->getSavePlace(15) + 4);
00418 
00419         // now continue execution
00420         running= true;
00421         pxa->continueCmd();
00422 }
00423 
00424 void GdbRemote::cont() {
00425 
00426         next();
00427 
00428         if (current() != '#') {
00429                 unsigned int addr; 
00430 
00431                 // get the address
00432                 addr = strtoul((char *)buffer + ptr, 0, 16);
00433                 pxa->setSavePlace(15, addr);
00434         }
00435 
00436         // disable the hard break point #1, used for step by step.
00437         pxa->setCp15DebugRegister(0, JTAGpxa250::IBCR1);
00438         pxa->pollForTX();
00439 
00440         resumeExec();
00441 }
00442 
00443 void GdbRemote::step() {
00444         next();
00445 
00446         if (current() != '#') {
00447                 unsigned int addr;
00448 
00449                 // get the address
00450                 addr = strtoul((char *)buffer + ptr, 0, 16);
00451                 pxa->setSavePlace(15, addr);
00452         }
00453         pxa->setCp15DebugRegister(0, JTAGpxa250::IBCR1);
00454         pxa->pollForTX();
00455 
00456         jelie_set_bpt();
00457         resumeExec();
00458 }
00459         
00460 
00461 void GdbRemote::insertBreakWatch() {
00462 
00463         // eat the 'Z'
00464         next();
00465         if (current() == '1') {  // insert hardware breakpoint
00466                 next(); // the '1'
00467                 next(); // the ','
00468                 unsigned int addr = strtoul((char *)buffer + ptr, 0, 16);
00469                 for (int hb=0; hb<2; hb++) {
00470                         if (hardBreak[hb] == 0) {
00471                                 pxa->setCp15DebugRegister(addr | 1, 
00472                                                 hb==0 ? JTAGpxa250::IBCR0 : JTAGpxa250::IBCR1);
00473                                 hardBreak[hb] = addr;
00474                                 sprintf(message, "OK");
00475                                 sendPacket();
00476                                 return;
00477                         }
00478                 }
00479                 // every hard break is taken :/
00480                 sprintf(message, "E01");
00481                 sendPacket();
00482                 return;
00483         }
00484 
00485         // reply nothing if unsupported
00486         message[0] = 0;
00487         sendPacket();
00488 }
00489 
00490 void GdbRemote::removeBreakWatch() {
00491         next();
00492 
00493         if (current() == '1') {
00494                 // remove hard break
00495                 next(); // the '1'
00496                 next(); // the ','
00497                 unsigned int addr = strtoul((char *)buffer + ptr, 0, 16);
00498                 for (int hb=0; hb<2; hb++) {
00499                         if (hardBreak[hb] == addr) {
00500                                 hardBreak[hb] = 0;
00501                                 pxa->setCp15DebugRegister(0, 
00502                                         hb==0 ? JTAGpxa250::IBCR0 : JTAGpxa250::IBCR1);
00503                                 sprintf(message, "OK");
00504                                 sendPacket();
00505                                 return;
00506                         }
00507                         // hum.. trying to remove a non-existent breakpoint ?
00508                         sprintf(message, "E02");
00509                         sendPacket();
00510                         return;
00511                 }
00512         }
00513         // reply nothing if unsupported
00514         message[0] = 0;
00515         sendPacket();
00516 }
00517 
00518 void GdbRemote::parseValidPacket() {
00519         int startOfPacket = ptr;
00520 
00521         switch (current()) {
00522         case 'H': setThread(); break;
00523         case 'q': query(); break;
00524         case '?': lastSignal(); break;
00525         case 'g': getRegisters(); break;
00526         case 'G': setRegisters(); break;
00527         case 'm': readMem(); break;
00528         case 'M': writeMem(); break;
00529         case 'c': cont(); break;
00530         case 'Z': insertBreakWatch(); break;
00531         case 'z': removeBreakWatch(); break;
00532         case 's': step();break;
00533         default:
00534                 printf("gdb command %c not understood.\n", current());
00535                 message[0] = 0;
00536                 sendPacket();
00537         }
00538 
00539         // eat the end of the packet
00540         ptr = startOfPacket;
00541         while(current() != '#') next();
00542         next();
00543         next();
00544 }

Generated on Fri May 16 13:01:45 2003 for Jelie by doxygen1.2.15