From 040462359543433d000052ed605f6ebd8b6ab633 Mon Sep 17 00:00:00 2001 From: defragger Date: Fri, 21 Feb 2014 15:19:50 +0100 Subject: [PATCH] added libgdbr sources to shlr folder Signed-off-by: defragger --- libr/debug/p/libgdbwrap/Makefile | 22 - libr/debug/p/libgdbwrap/README | 8 - libr/debug/p/libgdbwrap/client.c | 162 --- libr/debug/p/libgdbwrap/gdbwrapper.c | 973 ------------------ .../libgdbwrap/include/gdbwrapper-internals.h | 71 -- .../p/libgdbwrap/include/gdbwrapper-stddef.h | 1 - libr/debug/p/libgdbwrap/include/gdbwrapper.h | 115 --- libr/debug/p/libgdbwrap/include/libaspect.h | 1 - libr/debug/p/libgdbwrap/include/libe2dbg.h | 1 - libr/debug/p/libgdbwrap/include/revm.h | 36 - libr/debug/p/libgdbwrap/interface.c | 43 - shlr/gdb/Makefile | 68 ++ shlr/gdb/include/arch.h | 128 +++ shlr/gdb/include/core.h | 54 + shlr/gdb/include/libgdbr.h | 122 +++ shlr/gdb/include/messages.h | 24 + shlr/gdb/include/packet.h | 45 + shlr/gdb/include/utils.h | 18 + shlr/gdb/src/core.c | 319 ++++++ shlr/gdb/src/libgdbr.c | 5 + shlr/gdb/src/messages.c | 61 ++ shlr/gdb/src/packet.c | 146 +++ shlr/gdb/src/utils.c | 127 +++ 23 files changed, 1117 insertions(+), 1433 deletions(-) delete mode 100644 libr/debug/p/libgdbwrap/Makefile delete mode 100644 libr/debug/p/libgdbwrap/README delete mode 100644 libr/debug/p/libgdbwrap/client.c delete mode 100644 libr/debug/p/libgdbwrap/gdbwrapper.c delete mode 100644 libr/debug/p/libgdbwrap/include/gdbwrapper-internals.h delete mode 100644 libr/debug/p/libgdbwrap/include/gdbwrapper-stddef.h delete mode 100644 libr/debug/p/libgdbwrap/include/gdbwrapper.h delete mode 100644 libr/debug/p/libgdbwrap/include/libaspect.h delete mode 100644 libr/debug/p/libgdbwrap/include/libe2dbg.h delete mode 100644 libr/debug/p/libgdbwrap/include/revm.h delete mode 100644 libr/debug/p/libgdbwrap/interface.c create mode 100644 shlr/gdb/Makefile create mode 100644 shlr/gdb/include/arch.h create mode 100644 shlr/gdb/include/core.h create mode 100644 shlr/gdb/include/libgdbr.h create mode 100644 shlr/gdb/include/messages.h create mode 100644 shlr/gdb/include/packet.h create mode 100644 shlr/gdb/include/utils.h create mode 100644 shlr/gdb/src/core.c create mode 100644 shlr/gdb/src/libgdbr.c create mode 100644 shlr/gdb/src/messages.c create mode 100644 shlr/gdb/src/packet.c create mode 100644 shlr/gdb/src/utils.c diff --git a/libr/debug/p/libgdbwrap/Makefile b/libr/debug/p/libgdbwrap/Makefile deleted file mode 100644 index 97b26e167f..0000000000 --- a/libr/debug/p/libgdbwrap/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -include ../../../config.mk -OBJ=interface.o gdbwrapper.o client.o -CFLAGS=-Iinclude -I../../../include -ERESIPATH=${HOME}/prg/eresi -BIN=client - -all: ${BIN} - -${BIN}: ${OBJ} - ${CC} ${OBJ} -o ${BIN} - -sync: - @if [ -d ${ERESIPATH} ]; then \ - cp -v ${ERESIPATH}/libgdbwrap/*.c . ; \ - cp -v ${ERESIPATH}/libgdbwrap/include/*.h include ; \ - echo Sync done ; \ - else \ - echo Give me ERESIPATH ; \ - fi - -clean: - -rm -f client ${OBJ} *.o a.out diff --git a/libr/debug/p/libgdbwrap/README b/libr/debug/p/libgdbwrap/README deleted file mode 100644 index 69e4fadd0d..0000000000 --- a/libr/debug/p/libgdbwrap/README +++ /dev/null @@ -1,8 +0,0 @@ -/* This code has been leeched from the ERESI project */ - -This is a hacked/stripped-down version of the original libgdbwrap from eresi. - -gdbserver 0.0.0.0:9999 /bin/ls -./client 127.0.0.1 9999 - -type make sync to keep in sync with eresi diff --git a/libr/debug/p/libgdbwrap/client.c b/libr/debug/p/libgdbwrap/client.c deleted file mode 100644 index dcb928fa4c..0000000000 --- a/libr/debug/p/libgdbwrap/client.c +++ /dev/null @@ -1,162 +0,0 @@ -/* Basic TCP client aimed to develop of fully modular gdb wrapper. Not - part of eresi project. Took code from: - http://neworder.box.sk/newsread.php?newsid=2844. -*/ - - -#include "revm.h" -#include "gdbwrapper.h" - - -extern int errno; -extern int h_errno; - -static void dumpreg(gdbwrap_t *desc) -{ - unsigned i; - - for (i = 0; i < desc->num_registers; i++){ - ut32 v = gdbwrap_getreg(desc,i) & 0xFFFFFFFF; - printf("Reg %d - %#x\n", i, v); - } -} - -int main( int argc, char **argv ) -{ - char buffer[4096]; - int port; - int rval; - int sd; - struct sockaddr_in socketaddr; - struct hostent *hostaddr; - struct protoent *protocol; - gdbwrap_t *desc = NULL; - - if ( argc < 3 ) - { - printf( "usage: client server port \n" ); - return (EINVAL); /* Invalid argument */ - } - - /* quick sanity check */ - - port = atoi( argv[2] ); - - if ( port < 1 || port > 65535 ) - { - printf( "client: invalid port number\n" ); - return (EINVAL); - } - - /* - * Build our socket - */ - - protocol = getprotobyname( "tcp" ); - if ( !protocol ) - { - perror( "getprotobyname()" ); - return (errno); - } - - sd = socket( PF_INET, SOCK_STREAM, protocol->p_proto ); - if ( sd == -1 ) - { - perror( "socket()" ); - return (errno); - } - /* - * Setup info about the remote host - */ - - memset( &socketaddr, 0, sizeof(socketaddr) ); - - socketaddr.sin_family = AF_INET; - socketaddr.sin_port = htons( port ); - - hostaddr = gethostbyname( argv[1] ); - if ( !hostaddr ) - { - fprintf( stderr, "gethostbyname(): %s\n", hstrerror(h_errno) ); - return (h_errno); - } - - /* copy address from hostaddr to socketaddr */ - - memcpy( &socketaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length ); - - /* - * Connect to the host - */ - - rval = connect( sd, (struct sockaddr *) &socketaddr, sizeof(socketaddr) ); - if ( rval == -1 ) - { - perror( "connect()" ); - return (errno); - } - - /* Now that we're connected, we can send and receive all we want. - * I've decided to use this example as a means of simply grabbing - * whatever banner the server sends us and sending it to stdout. - */ - - // 28 registers of 4 bytes for sh4 - desc = gdbwrap_init(sd,28,4); - do - { - char * ret; - - ret = fgets(buffer, sizeof(buffer) - 1, stdin); - assert(ret != NULL); - - if(!strncmp("hello", buffer, 5)) - gdbwrap_hello(desc); - else if(!strncmp("disconnect", buffer, 5)) - { - gdbwrap_bye(desc); - exit(0); - } - else if(!strncmp("why", buffer, 3)) - gdbwrap_reason_halted(desc); -/* else if(!strncmp("test", buffer, 4)) */ -/* gdbwrap_test(desc); */ - else if(!strncmp("gpr", buffer, 3)) - gdbwrap_readgenreg(desc); - else if(!strncmp("cont", buffer, 4)) - gdbwrap_continue(desc); - else if(!strncmp("dump", buffer, 4)) - dumpreg(desc); - else if(!strncmp("stepi", buffer, 5)) - gdbwrap_stepi(desc); - else if(!strncmp("signal", buffer, 5)) - gdbwrap_signal(desc, 0x1); - else if(!strncmp("ship", buffer, 4)) - gdbwrap_shipallreg(desc); - else if(!strncmp("cr0", buffer, 4)) - printf("Value: %s\n", gdbwrap_remotecmd(desc, "r cr0")); - else if(!strncmp("mem", buffer, 3)) - { - char *c; - char u = 0xff; - // c = gdbwrap_writemem(desc, 0xb7fe49a0, &u, 0x1); - printf("Returned from memorycontent: %s\n", c); - fflush(stdout); - } -/* else if(!strncmp("own", buffer, 3)) */ -/* { */ -/* while (strncmp("quitown", buffer, 7)) */ -/* { */ -/* printf("\nCommand: "); */ -/* ret = gdbwrap_own_command(fgets(buffer, sizeof(buffer) - 1, stdin), */ -/* desc); */ -/* printf("\n%s - size: %d", ret, strlen(ret)); */ -/* } */ -/* } */ - else printf("not supported yet\n"); - - } while (strncmp("bye", buffer, 3)); - - close(sd); - return (0); -} diff --git a/libr/debug/p/libgdbwrap/gdbwrapper.c b/libr/debug/p/libgdbwrap/gdbwrapper.c deleted file mode 100644 index e01fe16e71..0000000000 --- a/libr/debug/p/libgdbwrap/gdbwrapper.c +++ /dev/null @@ -1,973 +0,0 @@ -/* - * See gdb documentation, section D for more information on the - * remote serial protocol. To make it short, a packet looks like the following: - * - * $packet-data#checksum or $sequence-id:packet-data#checksum. - * - * where the checksum is the sum of all the characters modulo 256. - */ - -#if __UNIX__ -#include -#endif - -#if __WINDOWS__ -#include -#endif - -#include "libaspect.h" -#include "gdbwrapper-internals.h" -#include "gdbwrapper.h" - -/* wtf global stuff */ -static gdbwrapworld_t gdbwrapworld; - -/******************** Internal functions ********************/ - -IRAPI void gdbwrap_setreg(gdbwrap_t *desc, ut32 idx, ut64 value){ - if (idx >= desc->num_registers) { - fprintf (stderr, "Wrong register index %d\n", idx); - return; - } - switch (desc->reg_size) { - case 1: *(desc->regs+idx) = value & 0xFF; - break; - case 2: *(ut16 *)(desc->regs+idx*2) = value & 0xFFFF; - break; - case 4: *(ut32 *)(desc->regs + idx*4) = value &0xFFFFFFFF; - break; - case 8: *(ut64 *)(desc->regs + idx*8) = value; - break; - default: - fprintf (stderr,"Unsupported register size!"); - } -} - -IRAPI void gdbwrap_getreg_buffer(gdbwrap_t *desc, unsigned char *buf, ut32 size) { - if (desc->reg_size*desc->num_registers > size) - size = desc->reg_size*desc->num_registers; - //Just copy the output buffer - memcpy (buf,desc->regs,size); -} - -IRAPI void gdbwrap_setreg_buffer(gdbwrap_t *desc, const unsigned char *buf, ut32 size) { - if (desc->reg_size*desc->num_registers > size) - size = desc->reg_size*desc->num_registers; - memcpy (desc->regs, buf, size); -} - -IRAPI ut64 gdbwrap_getreg(gdbwrap_t *desc, ut32 idx) { - ut64 ret = -1; - if (idx >= desc->num_registers) { - fprintf (stderr, "Wrong register index %d\n",idx); - } else - switch (desc->reg_size) { - case 1: ret = *(desc->regs+idx); - break; - case 2: ret = *(ut16 *)(desc->regs+idx*2); - break; - case 4: ret = *(ut32 *)(desc->regs + idx*4 ); - break; - case 8: ret = *(ut64 *)(desc->regs + idx*8 ); - break; - default: - fprintf (stderr, "Unsupported register size!"); - } - return ret; -} - -static char *gdbwrap_lastmsg(gdbwrap_t *desc) { - return desc->packet; -} - -static Bool gdbwrap_errorhandler(gdbwrap_t *desc, const char *error) { - /* errorhandler ignored */ - return 0; -#if 0 - ASSERT(desc != NULL && error != NULL); - - DEBUGMSG(printf("Treating error (encoded): %s\n", error)); - - if (!strncmp(GDBWRAP_REPLAY_OK, error, strlen(GDBWRAP_REPLAY_OK))) - { - desc->erroroccured = FALSE; - return FALSE; - } - - if (!strncmp(GDBWRAP_NO_SPACE, error, strlen(GDBWRAP_NO_SPACE))) - fprintf(stderr, "space was not updated.\n"); - - if (!strncmp(GDBWRAP_NO_TABLE, error, strlen(GDBWRAP_NO_TABLE))) - fprintf(stdout, "Not populating the table\n"); - - if (!strncmp(GDBWRAP_DEAD, error, strlen(GDBWRAP_DEAD))) - fprintf(stdout, "The server seems to be dead. Message not sent.\n"); - -#if 0 - /* noisy error */ - if (error[0] == GDBWRAP_REPLAY_ERROR) - fprintf(stdout, "Error received from the server: %s\n", error); -#endif - - if (error[0] == GDBWRAP_EXIT_W_STATUS) - { - fprintf(stdout, "Exit with status: %s\n", error); - desc->is_active = FALSE; - } - - if (error[0] == GDBWRAP_EXIT_W_SIGNAL) - { - fprintf(stdout, "Exit with signal: %s\n", error); - desc->is_active = FALSE; - } - - desc->erroroccured = TRUE; - fflush (stdout); - return TRUE; -#endif -} - -static Bool gdbwrap_is_interrupted(gdbwrap_t *desc) { - return desc->interrupted; -} - -/** - * This function parses a string *strtoparse* starting at character - * *begin* and ending at character *end*. The new parsed string is - * saved in *strret*. If *begin* is not found in *strtoparse* then the - * function returns NULL. If *end* is not found in *strtoparse*, then - * the function returns NULL.. - * - * @param strtoparse: String to parse. - * @param strret : String to return without *begin* and *end*. - * @param begin : String where to start parsing. If NULL, - * we start from the beginning. - * @param end : String where to end parsing. If NULL, - * we copy the string from *begin* to then - * end of *strtoparse* (ie a NULL char is found). - * @param maxsize : The maximum size to extract. - * @return : Returns a pointer on the beginning of the new string. - */ -static char *gdbwrap_extract_from_packet(const char *strtoparse, - char *strret, const char *begin, const char *end, int maxsize) -{ - const char *charbegin, *charend; - unsigned int strtorem; - ptrdiff_t strsize; - - if (strtoparse == NULL) - return NULL; - - if (begin == NULL) { - charbegin = strtoparse; - strtorem = 0; - } else { - charbegin = strstr (strtoparse, begin); - strtorem = strlen (begin); - if (charbegin == NULL) - return NULL; - } - - if (end != NULL) { - charend = strstr (charbegin, end); - if (charend == NULL) - return NULL; - } else charend = charbegin + strlen (charbegin); - - strsize = charend - charbegin - strtorem; - if (strsize > maxsize) - strsize = maxsize; - - //strncpy (strret, charbegin + strtorem, strsize); - { - const char *p = charbegin+strtorem; - memmove (strret, p, R_MIN (strlen (p), strsize)+1); - strret[strsize] = GDBWRAP_NULL_CHAR; - } - - return strret; -} - -static la32 gdbwrap_little_endian(la32 addr) { - la32 addrlittle = 0; - int i; - - for (i = 0; addr > 0; i++) { - addrlittle += (LOBYTE (addr) << (BYTE_IN_BIT * (sizeof (addr) - 1 - i))); - addr >>= BYTE_IN_BIT; - } - return addrlittle; -} - -static uint8_t gdbwrap_calc_checksum(gdbwrap_t *desc, const char *str) { - int i, len; - uint8_t sum; - char *result = gdbwrap_extract_from_packet(str, desc->packet, GDBWRAP_BEGIN_PACKET, - GDBWRAP_END_PACKET, desc->max_packet_size); - /* If result == NULL, it's not a packet. */ - if (result == NULL) - result = gdbwrap_extract_from_packet(str, desc->packet, NULL, NULL, - desc->max_packet_size); - len = strlen (result); - for (i = 0, sum = 0; i < len; i++) - sum += result[i]; - return sum; -} - -static char *gdbwrap_make_message(gdbwrap_t *desc, const char *query) { - uint8_t checksum = gdbwrap_calc_checksum(desc, query); - unsigned max_query_size = (desc->max_packet_size - strlen(GDBWRAP_BEGIN_PACKET) - - strlen(GDBWRAP_END_PACKET) - sizeof(checksum)); - - /* Sometimes C sucks... Basic source and destination checking. We do - not check the overlapping tho.*/ - if (strlen(query) < max_query_size && query != desc->packet) { - int ret = snprintf(desc->packet, desc->max_packet_size, "%s%s%s%.2x", - GDBWRAP_BEGIN_PACKET, query, GDBWRAP_END_PACKET, checksum); - if (ret <1) { - fprintf (stderr, "snprintf failed\n"); - return NULL; - } - return desc->packet; - } - return NULL; -} - -/** - * This function performes a run-length decoding and writes back to - * *dstpacket*, but no more than *maxsize* bytes. - * - * @param srcpacket: the encoded packet. - * @param maxsize: the maximal size of the decoded packet. - */ -static char *gdbwrap_run_length_decode(char *dstpacket, const char *srcpacket, unsigned maxsize) { - /* Protocol specifies to take the following value and substract 29 - and repeat by this number the previous character. Note that the - compression may be used multiple times in a packet. */ - uint8_t numberoftimes; - char *encodestr, valuetocopy; - unsigned int i, strlenc, check; - - if (dstpacket == NULL || srcpacket == NULL || - srcpacket[0] == GDBWRAP_START_ENCODC) - return NULL; - if (srcpacket != dstpacket) - strncpy (dstpacket, srcpacket, maxsize); - encodestr = strstr (dstpacket, GDBWRAP_START_ENCOD); - check = strlen (dstpacket); - while (encodestr != NULL) { - /* This is OK to take encodestr[-1], since we - assert(srcpacket[0] != GDBWRAP_START_ENCODC). */ - valuetocopy = encodestr[-1]; // WTF - numberoftimes = encodestr[1] - 29; - check += numberoftimes; - if (check>=maxsize) - return NULL; - strlenc = strlen (encodestr); - /* We move the string to the right, then set the bytes. We - substract 2, because we have * where * and - are filled with the value of (ie 2 chars). */ - for (i = 0; i < strlenc; i++) - encodestr[strlenc + numberoftimes - i - 2] = encodestr[strlenc - i]; - memset (encodestr, valuetocopy, numberoftimes); - encodestr = strstr (NEXT_CHAR (encodestr), GDBWRAP_START_ENCOD); - } - return dstpacket; -} - -/** - * Populate the gdb registers with the values received in the - * packet. A packet has the following form: - * - * $n:r;[n:r;]#checksum - * - * where n can be a number (the register), or "thread" and r is the - * value of the thread/register. - * - * @param packet: the packet to parse. - * @param reg : the structure in which we want to write the registers. - */ -static void gdbwrap_populate_reg(gdbwrap_t *desc, char *packet) { - const char *nextpacket; - char *nextupacket; - char packetsemicolon[MSG_BUF]; - char packetcolon[MSG_BUF]; - unsigned int packetoffset = 0; - - /* If a signal is received, we populate the registers, starting - after the signal number (ie after Tnn, where nn is the - number). */ - if (packet[0] == GDBWRAP_SIGNAL_RECV) - packetoffset = 3; - - while ((nextpacket = gdbwrap_extract_from_packet(packet + packetoffset, - packetsemicolon, NULL, GDBWRAP_SEP_SEMICOLON, sizeof(packetsemicolon))) != NULL) - { - nextupacket = gdbwrap_extract_from_packet(nextpacket, packetcolon, NULL, - GDBWRAP_SEP_COLON, sizeof(packetcolon)); - if (nextpacket == NULL || !nextupacket) return; - if (strlen (nextupacket) == 2) { - ureg32 regvalue; - uint8_t regnumber = gdbwrap_atoh(nextupacket, strlen(nextupacket)); - - nextupacket = gdbwrap_extract_from_packet (nextpacket, packetcolon, - GDBWRAP_SEP_COLON, NULL, - sizeof (packetcolon)); - if (!nextupacket) break; - //TODO Size-dependent atoh - regvalue = gdbwrap_atoh (nextupacket, strlen (nextupacket)); - regvalue = gdbwrap_little_endian (regvalue); - gdbwrap_setreg (desc,regnumber, regvalue); - //*(ut32 *)(desc->regs + desc->reg_size*regnumber) = regvalue; - } - /* We add 1 in order not to take the right limit. In the worst - case, we should get the NULL char. */ - packetoffset += strlen(nextpacket) + 1; - } -} - -static void gdbwrap_send_ack(gdbwrap_t *desc) { - send (desc->fd, GDBWRAP_COR_CHECKSUM, strlen (GDBWRAP_COR_CHECKSUM), 0x0); -} - -static Bool gdbwrap_check_ack(gdbwrap_t *desc) { - int rval = recv (desc->fd, desc->packet, 1, 0); - /* The result of the previous recv must be a "+". */ - if (!rval) - desc->is_active = FALSE; - if (desc->packet[0] == GDBWRAP_COR_CHECKSUMC && rval != -1) - return TRUE; - if (desc->packet[0] != GDBWRAP_BAD_CHECKSUM) - return FALSE; - fprintf(stderr, "The server has NOT sent any ACK." - "It probably does not follow exactly the gdb protocol (%s - %d).\n", - desc->packet, rval); - return FALSE; -} - -static char *gdbwrap_get_packet(gdbwrap_t *desc) { - int rval, sumrval; - char checksum[3]; - - if (desc == NULL) - return NULL; - desc->packet[0] = GDBWRAP_NULL_CHAR; - rval = -1; - sumrval = 0; - do { - /* In case the packet is splitted into many others. */ - rval = recv (desc->fd, desc->packet + sumrval, desc->max_packet_size, 0); - if (rval>0) sumrval += rval; - if (errno == EINTR) // WTF. if recv is -1 ? - break; - } while (sumrval >= 3 && - desc->packet[sumrval - 3] != GDBWRAP_END_PACKETC && rval); - - /* if rval == 0, it means the host is disconnected/dead. */ - if (rval) { - desc->packet[sumrval] = GDBWRAP_NULL_CHAR; - gdbwrap_extract_from_packet (desc->packet, checksum, GDBWRAP_END_PACKET, - NULL, sizeof (checksum)); - - /* If no error, we ack the packet. */ - if (rval != -1 && gdbwrap_atoh (checksum, strlen (checksum)) == - gdbwrap_calc_checksum (desc, desc->packet)) - { - gdbwrap_send_ack(desc); - gdbwrap_errorhandler(desc, desc->packet); - return gdbwrap_run_length_decode(desc->packet, - desc->packet, desc->max_packet_size); - } else { - if (gdbwrap_is_interrupted (desc)) { - desc->interrupted = FALSE; - gdbwrap_errorhandler (desc, desc->packet); - return gdbwrap_run_length_decode ( - desc->packet, desc->packet, - desc->max_packet_size); - } else { - fprintf (stderr, "Muh ?\n"); - return NULL; - } - } - } else desc->is_active = FALSE; - - return NULL; -} - -static char *gdbwrap_send_data(gdbwrap_t *desc, const char *query) { - int rval = 0; - char *mes = NULL; - if (desc == NULL || query == NULL) - return NULL; - - if (gdbwrap_is_active (desc)) { - do { - mes = gdbwrap_make_message (desc, query); - if (!mes) break; - rval = send (desc->fd, mes, strlen (mes), 0); - if (rval<1) break; - } while (gdbwrap_check_ack (desc) != TRUE); - if (rval == -1) - return NULL; - mes = gdbwrap_get_packet (desc); - } else { - gdbwrap_errorhandler (desc, GDBWRAP_DEAD); - mes = NULL; - } - return mes; -} - -/******************** External functions ********************/ - -/** - * Returns the last signal. We return the signal number or 0 if no - * signal was returned. - **/ -IRAPI unsigned int gdbwrap_lastsignal(gdbwrap_t *desc) { - unsigned int ret = 0; - char *lastmsg = gdbwrap_lastmsg(desc); - - /* When we receive a packet starting with GDBWRAP_SIGNAL_RECV, the - next 2 characters reprensent the signal number. */ - if (lastmsg && (lastmsg[0] == GDBWRAP_SIGNAL_RECV || - lastmsg[0] == GDBWRAP_SIGNAL_RECV2)) - ret = gdbwrap_atoh(lastmsg + 1, BYTE_IN_CHAR * sizeof(char)); - return ret; -} - -IRAPI u_char gdbwrap_lasterror(gdbwrap_t *desc) { - u_char ret = 0; - char *lastmsg = gdbwrap_lastmsg (desc); - /* When we receive a packet starting with GDBWRAP_SIGNAL_RECV, the - next 2 characters reprensent the signal number. */ - if (lastmsg && lastmsg[0] == GDBWRAP_REPLAY_ERROR) - ret = gdbwrap_atoh (lastmsg + 1, BYTE_IN_CHAR * sizeof (char)); - return ret; -} - -IRAPI Bool gdbwrap_is_active(gdbwrap_t *desc) { - return (desc && desc->is_active) ? TRUE: FALSE; -} - -/* If the last command is not supported, we return TRUE. */ -IRAPI Bool gdbwrap_cmdnotsup(gdbwrap_t *desc) { - char *lastmsg = gdbwrap_lastmsg(desc); - if (lastmsg && lastmsg[0] == GDBWRAP_NULL_CHAR) - return TRUE; - return FALSE; -} - -IRAPI Bool gdbwrap_erroroccured(gdbwrap_t *desc) { - return desc->erroroccured; -} - -IRAPI unsigned int gdbwrap_atoh(const char * str, unsigned size) { - unsigned int i, hex; - for (i = 0, hex = 0; i < size; i++) { - if (str != NULL && str[i] >= 'a' && str[i] <= 'f') - hex += (str[i] - 0x57) << 4 * (size - i - 1); - else if (str != NULL && str[i] >= '0' && str[i] <= '9') - hex += (str[i] - 0x30) << 4 * (size - i - 1); - else return 0; - } - return hex; -} - -/** - * Set/Get the gdbwrapworld variable. It's not mandatory to use the - * other functions, but sometimes a global variable is required. - */ -IRAPI gdbwrapworld_t gdbwrap_current_set(gdbwrap_t *world) { - gdbwrapworld.gdbwrapptr = world; - return gdbwrapworld; -} - -IRAPI gdbwrap_t *gdbwrap_current_get(void) { - return gdbwrapworld.gdbwrapptr; -} - -/** - * Initialize the descriptor. We provide a default value of 1000B for - * the string that get the replies from server. - * - */ -IRAPI gdbwrap_t *gdbwrap_init(int fd, ut32 num_regs, ut32 reg_size) { - gdbwrap_t *desc; - if (fd == -1) { -eprintf ("fd is minus wan\n"); - return NULL; -} - desc = malloc (sizeof (gdbwrap_t)); - if (!desc) return NULL; - desc->reg_size = reg_size; - desc->num_registers = num_regs; - desc->regs = malloc(4*desc->reg_size*desc->num_registers); - if (!desc->regs) { - free (desc); - return NULL; - } - ASSERT(fd && desc != NULL && desc->regs !=NULL); // assert fd ?!? wtf?? - desc->max_packet_size = 2500; - desc->packet = malloc((desc->max_packet_size + 1) * sizeof (char)); - if (desc->packet == NULL) { -eprintf ("cant apack\n"); - free (desc->regs); - free (desc); - return NULL; - } - desc->fd = fd; - desc->is_active = TRUE; - desc->interrupted = FALSE; - - return desc; -} - -IRAPI void gdbwrap_close(gdbwrap_t *desc) { - if (desc == NULL) { - free (desc->packet); - free (desc->regs); - free (desc); - } -} - -/** - * Initialize a connection with the gdb server and allocate more - * memory for packets if necessary. - * - */ -IRAPI void gdbwrap_hello(gdbwrap_t *desc) { - char *received = NULL; - char *result = NULL; - unsigned int previousmax = 0; - - received = gdbwrap_send_data(desc, GDBWRAP_QSUPPORTED); - if (!received) - return; - - result = gdbwrap_extract_from_packet(received, desc->packet, - GDBWRAP_PACKETSIZE, GDBWRAP_SEP_SEMICOLON, desc->max_packet_size); - - /* If we receive the info, we update gdbwrap_max_packet_size. */ - if (result != NULL) { - char *reallocptr; - - previousmax = desc->max_packet_size; - desc->max_packet_size = gdbwrap_atoh(desc->packet, strlen(desc->packet)); - reallocptr = realloc(desc->packet, desc->max_packet_size + 1); - if (reallocptr == NULL) { - gdbwrap_errorhandler(desc, GDBWRAP_NO_SPACE); - desc->max_packet_size = previousmax; - } else desc->packet = reallocptr; - } - /* We set the last bit to a NULL char to avoid getting out of the - weeds with a (unlikely) bad strlen. */ - desc->packet[desc->max_packet_size] = GDBWRAP_NULL_CHAR; -} - -/** - * Send a "disconnect" command to the server and free the packet. - */ -IRAPI void gdbwrap_bye(gdbwrap_t *desc) { - if (desc) - gdbwrap_send_data(desc, GDBWRAP_DISCONNECT); - printf("\nThx for using gdbwrap :)\n"); -} - -IRAPI void gdbwrap_reason_halted(gdbwrap_t *desc) { - char *r = gdbwrap_send_data(desc, GDBWRAP_WHY_HALTED); - if (gdbwrap_is_active (desc)) - gdbwrap_populate_reg (desc, r); - else gdbwrap_errorhandler (desc, GDBWRAP_NO_TABLE); -} - -/** - * Great, the gdb protocol has absolutely no consistency, thus we - * cannot reuse the gdbwrap_populate_reg. We receive a poorly - * documented bulk message when sending the "g" query. - */ -IRAPI ut8 *gdbwrap_readgenreg(gdbwrap_t *desc) { - int i; - ureg32 regvalue; - char *rec = gdbwrap_send_data (desc, GDBWRAP_GENPURPREG); - if (rec && gdbwrap_is_active (desc)) { - for (i = 0; i < desc->num_registers; i++) { - /* 1B = 2 characters */ - regvalue = gdbwrap_atoh (rec, 2 * DWORD_IN_BYTE); - regvalue = gdbwrap_little_endian (regvalue); - gdbwrap_setreg (desc,i,regvalue); - //*(ut32 *)(desc->regs + desc->reg_size*i) = regvalue; - rec += 2 * DWORD_IN_BYTE; - } - return desc->regs; - } - return NULL; -} - - -IRAPI void gdbwrap_continue(gdbwrap_t *desc) { - if (gdbwrap_is_active (desc)) { - char *rec = gdbwrap_send_data (desc, GDBWRAP_CONTINUE); - if (rec != NULL && gdbwrap_is_active (desc)) - gdbwrap_populate_reg (desc, rec); - } -} - -/** - * Set a breakpoint. We read the value in memory, save it and write a - * 0xcc in replacement. The usual command to set a bp is not supported - * by the gdbserver. - */ -IRAPI void gdbwrap_setbp(gdbwrap_t *desc, la32 linaddr, void *datasaved) { - unsigned int atohresult; - u_char bp = 0xcc; - char *ret; - - if (desc == NULL || desc == datasaved) { - fprintf (stderr, "gdbwrap_setbp: preconditions assert\n"); - return; - } - ret = gdbwrap_readmem(desc, linaddr, 1); - /* Fix: not clean. ATOH is not clean when returning an unsigned. */ - atohresult = gdbwrap_atoh(ret, 2 * 1); - memcpy(datasaved, &atohresult, 1); - gdbwrap_writemem(desc, linaddr, &bp, sizeof(u_char)); -} - -/** - * this should be preferred over gdbwrap_setbp as it's arch independent. - * It is possible that some gdb servers do not implement it, and we could - * fall back to arch-specific methods then. - */ -int gdbwrap_simplesetbp(gdbwrap_t *desc, la32 linaddr) { - char *ret, packet[MSG_BUF]; - snprintf (packet, sizeof (packet), "%s%s%x%s%x", GDBWRAP_INSERTBP, - GDBWRAP_SEP_COMMA, linaddr, GDBWRAP_SEP_COMMA, 0x1); - ret = gdbwrap_send_data (desc, packet); - return (ret && ret[0])?1:0; -} - -IRAPI int gdbwrap_simplesethwbp(gdbwrap_t *desc, la32 linaddr) { - char *ret, packet[MSG_BUF]; - snprintf (packet, sizeof (packet), "%s%s%x%s%x", GDBWRAP_INSERTHWBP, - GDBWRAP_SEP_COMMA, linaddr, GDBWRAP_SEP_COMMA, 0x1); - ret = gdbwrap_send_data (desc, packet); - return (ret && ret[0])?1:0; -} - -IRAPI void gdbwrap_delbp(gdbwrap_t *desc, la32 linaddr, void *datasaved) { - gdbwrap_writemem(desc, linaddr, datasaved, sizeof(u_char)); -} - -IRAPI int gdbwrap_simpledelbp(gdbwrap_t *desc, la32 linaddr) { - char *ret, packet[MSG_BUF]; - snprintf (packet, sizeof(packet), "%s%s%x%s%x", GDBWRAP_REMOVEBP, - GDBWRAP_SEP_COMMA, linaddr, GDBWRAP_SEP_COMMA, 0x1); - ret = gdbwrap_send_data (desc, packet); - if(ret != NULL && ret[0] == '\0') - return 0; - return 1; -} - -IRAPI void gdbwrap_simpledelhwbp(gdbwrap_t *desc, la32 linaddr) { - char packet[MSG_BUF]; - snprintf (packet, sizeof (packet), "%s%s%x%s%x", GDBWRAP_REMOVEHWBP, - GDBWRAP_SEP_COMMA, linaddr, GDBWRAP_SEP_COMMA, 0x1); - gdbwrap_send_data (desc, packet); -} - -IRAPI char *gdbwrap_readmem(gdbwrap_t *desc, la32 linaddr, unsigned bytes) { - char packet[MSG_BUF]; - snprintf (packet, sizeof (packet), "%s%x%s%x", GDBWRAP_MEMCONTENT, - linaddr, GDBWRAP_SEP_COMMA, bytes); - return gdbwrap_send_data(desc, packet); -} - -static void *gdbwrap_writememory(gdbwrap_t *desc, la32 linaddr, void *value, unsigned bytes) { - uint8_t packetsize; - char *rec, *packet = malloc(bytes + MSG_BUF); - - if (!desc || !value) { - free (packet); - return NULL; - } - snprintf(packet, MSG_BUF, "%s%x%s%x%s", GDBWRAP_MEMWRITE, - linaddr, GDBWRAP_SEP_COMMA, bytes, GDBWRAP_SEP_COLON); - packetsize = strlen(packet); - if (packetsize>=MSG_BUF) { - fprintf (stderr, "Too big packet\n"); - free (packet); - return NULL; - } - /* GDB protocol expects the value we send to be a "Binary value", ie - not converted to a char. */ - memcpy (packet + packetsize, value, bytes); - packet[packetsize + bytes] = GDBWRAP_NULL_CHAR; - rec = gdbwrap_send_data (desc, packet); - free (packet); - - return rec; -} - -static void *gdbwrap_writememory2(gdbwrap_t *desc, la32 linaddr, void *value, unsigned bytes) { - char *rec, *packet; - u_char *val = value; - u_short i; - u_int len; - - packet = malloc (2*bytes+MSG_BUF); - if (packet == NULL) { - fprintf (stderr, "Cannot allocate %d bytes\n", 2*bytes+MSG_BUF); - return NULL; - } - - snprintf(packet, MSG_BUF, "%s%x%s%x%s", GDBWRAP_MEMWRITE2, - linaddr, GDBWRAP_SEP_COMMA, bytes, GDBWRAP_SEP_COLON); - - for (i = 0; i < bytes; i++) - { - len = strlen(packet); - ASSERT(len + 1 < 2 * bytes + MSG_BUF); - snprintf(packet + len, BYTE_IN_CHAR + 1, "%02x", (unsigned)val[i]); - } - rec = gdbwrap_send_data(desc, packet); - - free (packet); - - return rec; -} - - -IRAPI void gdbwrap_writemem(gdbwrap_t *desc, la32 linaddr, void *value, unsigned bytes) { - static u_char choice = 0; - - if (bytes) - { - do { - switch (choice) { - case 0: - gdbwrap_writememory(desc, linaddr, value, bytes); - if (gdbwrap_cmdnotsup(desc)) - choice++; - break; - - case 1: - gdbwrap_writememory2(desc, linaddr, value, bytes); - if (gdbwrap_cmdnotsup(desc)) - choice++; - break; - - default: - fprintf (stderr, "[W] Write to memory not supported.\n"); - break; - } - } while (gdbwrap_cmdnotsup (desc) && choice < 2); - } -} - -/** - * Write a specific register. This command seems not to be supported - * by the gdbserver. See gdbwrap_writereg2. - */ -static void gdbwrap_writeregister(gdbwrap_t *desc, ureg32 regNum, la32 val) { - char regpacket[MSG_BUF]; - if (desc) { - snprintf (regpacket, sizeof (regpacket), "%s%x=%x", - GDBWRAP_WRITEREG, regNum, val); - gdbwrap_send_data (desc, regpacket); - } -} - -static void gdbwrap_writeregister2(gdbwrap_t *desc, ureg32 regNum, la32 val) { - unsigned int offset; // XXX 32 bit only? wtf - char *ret, locreg[700]; - ut8 *reg; - - offset = 2 * regNum * sizeof (ureg32); - - // XXX: this assert looks broken - ASSERT (desc != NULL && (regNum < sizeof(gdbwrap_gdbreg32) / sizeof(ureg32)) && - offset + 2 * sizeof(ureg32) < desc->max_packet_size); - reg = gdbwrap_readgenreg (desc); - ret = gdbwrap_lastmsg (desc); - ASSERT (reg != NULL && ret != NULL); - if (reg == NULL) { - fprintf (stderr, "gdbwrap_writeregister: Fail\n"); - } - - snprintf (locreg, sizeof(locreg), "%08x", gdbwrap_little_endian(val)); - memcpy (ret + offset, locreg, 2 * sizeof (ureg32)); - snprintf (locreg, sizeof(locreg), "%s%s", GDBWRAP_WGENPURPREG, ret); - gdbwrap_send_data(desc, locreg); -} - -IRAPI void gdbwrap_writereg(gdbwrap_t *desc, ureg32 regnum, la32 val) { - static u_char choice = 0; - - do { - switch (choice) { - case 0: - gdbwrap_writeregister(desc, regnum, val); - if (gdbwrap_cmdnotsup(desc)) - choice++; - break; - case 1: - gdbwrap_writeregister2 (desc, regnum, val); - if (gdbwrap_cmdnotsup (desc)) - choice++; - break; - default: - fprintf (stderr, "[W] Write to registers not supported.\n"); - break; - } - } while (gdbwrap_cmdnotsup (desc) && choice < 2); - - if (choice < 2) - gdbwrap_setreg(desc,regnum,val); - // *(ut32 *)(desc->regs + desc->reg_size*regnum) = val; -} - -//This is ugly... -static char *getfmt(ut32 size){ - switch (size){ - case 1: return "%02x"; - case 2: return "%04x"; - case 4: return "%08x"; - case 8: return "%16x"; - } - return NULL; -} - -/** - * Ship all the registers to the server in only 1 query. This is used - * when modifying multiple registers at once for example. - */ -IRAPI char *gdbwrap_shipallreg(gdbwrap_t *desc) { - ut8 *savedregs; - char *ret, *fmt, locreg[700]; - int i; - - if (desc == NULL) - return NULL; - savedregs = (ut8 *)malloc (desc->num_registers*desc->reg_size); - if (savedregs==NULL) - return NULL; - memcpy (savedregs, desc->regs, desc->num_registers*desc->reg_size); - - fmt = getfmt(desc->reg_size); - - gdbwrap_readgenreg (desc); - ret = gdbwrap_lastmsg (desc); - - /* We modify the 9 GPR only and we copy the rest from the gpr - request. */ - for (i = 0; i < desc->num_registers; i++) - snprintf(locreg + i * 2 * desc->reg_size, 2 * desc->reg_size + 1, - fmt, gdbwrap_little_endian(*(ut32 *)(savedregs + desc->reg_size*i))); - if (strlen (locreg)>= desc->max_packet_size) { - fprintf (stderr, "register too far\n"); - free (savedregs); - return NULL; - } - memcpy (ret, locreg, strlen (locreg)); - snprintf (locreg, sizeof (locreg), "%s%s", GDBWRAP_WGENPURPREG, ret); - free (savedregs); - - return gdbwrap_send_data (desc, locreg); -} - -IRAPI void gdbwrap_ctrl_c(gdbwrap_t *desc) { - u_char sended = CTRL_C; - int rval; - if (desc == NULL) - return; - desc->interrupted = TRUE; - send (desc->fd, (void*)&sended, sizeof(u_char), 0); - rval = recv(desc->fd, desc->packet, desc->max_packet_size, 0); - if (rval != desc->max_packet_size) - return; - gdbwrap_populate_reg(desc, desc->packet); - (void)send(desc->fd, GDBWRAP_COR_CHECKSUM, strlen(GDBWRAP_COR_CHECKSUM), 0x0); -} - -/** - * Here's the format of a signal: - * - * $vCont;C[:process_pid]# - * - * Note that que process pid can be retrieved with a "X" command. If - * process_pid is omited, then we apply to the current process - * (default behavior). - */ -IRAPI void gdbwrap_signal(gdbwrap_t *desc, int signal) { - char *rec, signalpacket[MSG_BUF]; - if (desc == NULL) - return; - snprintf (signalpacket, sizeof (signalpacket), "%s;C%.2x", - GDBWRAP_CONTINUEWITH, signal); - rec = gdbwrap_send_data (desc, signalpacket); - if (rec == NULL) { - fprintf (stderr, "gdbwrap_signal: error sending data\n"); - } -} - -IRAPI void gdbwrap_stepi(gdbwrap_t *desc) { - char *rec; - if (desc != NULL) return; - rec = gdbwrap_send_data (desc, GDBWRAP_STEPI); - if (gdbwrap_is_active (desc)) - gdbwrap_populate_reg (desc, rec); - else gdbwrap_errorhandler (desc, GDBWRAP_DEAD); -} - - -/** - * Sends a custom remote command. This heavily depends on the - * server. We "transform" the char into its corresponding ASCII code - * (in char). - * @param: cmd the command to send, in clear text. - **/ -IRAPI char *gdbwrap_remotecmd(gdbwrap_t *desc, char *cmd) { - char signalpacket[MSG_BUF], cmdcpy[MSG_BUF], *ret; - uint8_t i, rval; - if (desc == NULL || cmd == NULL) - return NULL; - - /* We jump 2 in 2 chars, since 1B = 2chars. */ - for (i = 0; i < sizeof(cmdcpy) && cmd[i] != GDBWRAP_NULL_CHAR; i++) - snprintf(cmdcpy + BYTE_IN_CHAR * i, BYTE_IN_CHAR + sizeof(GDBWRAP_NULL_CHAR), - "%02x", cmd[i]); - - snprintf (signalpacket, sizeof (signalpacket), "%s%s%s", - GDBWRAP_RCMD, GDBWRAP_SEP_COMMA, cmdcpy); - ret = gdbwrap_send_data (desc, signalpacket); - /* If we have a new line, it meens the packet is not finished (to - prove...), we listen to the next incoming packet, which is an - OK. */ - if (ret != NULL && gdbwrap_atoh (ret + strlen(ret) - 2, BYTE_IN_CHAR) == 0xa) { - gdbwrap_send_ack (desc); - rval = recv (desc->fd, cmdcpy, sizeof (cmdcpy), 0); - if (rval <1) { - fprintf (stderr, "read error\n"); - return NULL; - } - } - - return ret; -} - -/** - * Get a memory map from the gdb server and - * and return the information parsed on a gdbmemap_t. - * - */ -IRAPI gdbmemap_t gdbwrap_memorymap_get(gdbwrap_t *desc) { - char qXfer_msg[30], *received = NULL; - gdbmemap_t result; - snprintf (qXfer_msg, sizeof (qXfer_msg), "%s::%d,%d", - GDBWRAP_MEMORYMAP_READ, 0, 0xfff); - received = gdbwrap_send_data (desc, qXfer_msg); - if (received != NULL) { - //XXX: parse it and return gdbmemap_t - } - return result; -} diff --git a/libr/debug/p/libgdbwrap/include/gdbwrapper-internals.h b/libr/debug/p/libgdbwrap/include/gdbwrapper-internals.h deleted file mode 100644 index 911e30ebe6..0000000000 --- a/libr/debug/p/libgdbwrap/include/gdbwrapper-internals.h +++ /dev/null @@ -1,71 +0,0 @@ - -/* This file is for the gdb wrapper internals. It is not meant to be - included. */ - -#define GDBWRAP_PACKET_NO_BEGIN(_tocmp, _ptr) \ - assert(_tocmp); \ - _ptr = (strstr(_tocmp, GDBWRAP_BEGIN_PACKET) + 1) - -#define __DEBUG_GDBWRAP__ FALSE -#define MSG_BUF 80 - -#if __DEBUG_GDBWRAP__ -#define DEBUGMSG(_command) \ - do \ - { \ - _command; \ - } while(0) -#else -#define DEBUGMSG(_command) -#endif - -#define CONSTSTRDEC(_name, _value) static const char * const _name = _value -#define CONSTCHRDEC(_name, _value) static const char _name = _value -#define CTRL_C 0x3 -CONSTSTRDEC(GDBWRAP_BEGIN_PACKET, "$"); -CONSTSTRDEC(GDBWRAP_END_PACKET, "#"); -CONSTSTRDEC(GDBWRAP_QSUPPORTED, "qSupported"); -CONSTSTRDEC(GDBWRAP_DISCONNECT, "k"); -CONSTSTRDEC(GDBWRAP_CONTINUEWITH, "vCont"); -CONSTSTRDEC(GDBWRAP_CONTINUE, "c"); //"vCont;c"); -CONSTSTRDEC(GDBWRAP_SIGNAL, "C"); -CONSTSTRDEC(GDBWRAP_GENPURPREG, "g"); -CONSTSTRDEC(GDBWRAP_WGENPURPREG, "G"); -CONSTSTRDEC(GDBWRAP_MEMCONTENT, "m"); -CONSTSTRDEC(GDBWRAP_MEMWRITE, "X"); -CONSTSTRDEC(GDBWRAP_MEMWRITE2, "M"); -CONSTSTRDEC(GDBWRAP_INSERTBP, "Z0"); -CONSTSTRDEC(GDBWRAP_REMOVEBP, "z0"); -CONSTSTRDEC(GDBWRAP_INSERTHWBP, "Z1"); -CONSTSTRDEC(GDBWRAP_REMOVEHWBP, "z1"); -CONSTSTRDEC(GDBWRAP_STEPI, "s"); -CONSTSTRDEC(GDBWRAP_WRITEREG, "P"); -CONSTSTRDEC(GDBWRAP_ERROR, "E"); -CONSTSTRDEC(GDBWRAP_COR_CHECKSUM, "+"); -CONSTSTRDEC(GDBWRAP_WHY_HALTED, "?"); -CONSTSTRDEC(GDBWRAP_START_ENCOD, "*"); -CONSTSTRDEC(GDBWRAP_SEP_COLON, ":"); -CONSTSTRDEC(GDBWRAP_SEP_SEMICOLON, ";"); -CONSTSTRDEC(GDBWRAP_SEP_COMMA, ","); -CONSTSTRDEC(GDBWRAP_RCMD, "qRcmd"); -CONSTSTRDEC(GDBWRAP_PACKETSIZE, "PacketSize="); -CONSTSTRDEC(GDBWRAP_REPLAY_OK, "OK"); -CONSTSTRDEC(GDBWRAP_NO_SPACE, "nospace"); -CONSTSTRDEC(GDBWRAP_NO_TABLE, "notable"); -CONSTSTRDEC(GDBWRAP_DEAD, "dead"); -CONSTSTRDEC(GDBWRAP_MEMORYMAP_READ, "qXfer:memory-map:read"); - -CONSTCHRDEC(GDBWRAP_NULL_CHAR, '\0'); -CONSTCHRDEC(GDBWRAP_REPLAY_ERROR, 'E'); -CONSTCHRDEC(GDBWRAP_SIGNAL_RECV, 'T'); -CONSTCHRDEC(GDBWRAP_SIGNAL_RECV2, 'S'); -CONSTCHRDEC(GDBWRAP_EXIT_W_STATUS, 'W'); -CONSTCHRDEC(GDBWRAP_EXIT_W_SIGNAL, 'X'); -CONSTCHRDEC(GDBWRAP_END_PACKETC, '#'); -CONSTCHRDEC(GDBWRAP_START_ENCODC, '*'); -CONSTCHRDEC(GDBWRAP_COR_CHECKSUMC, '+'); -CONSTCHRDEC(GDBWRAP_BAD_CHECKSUM, '-'); - -#ifndef __ANDROID__ -extern int errno; -#endif diff --git a/libr/debug/p/libgdbwrap/include/gdbwrapper-stddef.h b/libr/debug/p/libgdbwrap/include/gdbwrapper-stddef.h deleted file mode 100644 index aecaa58091..0000000000 --- a/libr/debug/p/libgdbwrap/include/gdbwrapper-stddef.h +++ /dev/null @@ -1 +0,0 @@ -/* This file has to be merged with eresi */ diff --git a/libr/debug/p/libgdbwrap/include/gdbwrapper.h b/libr/debug/p/libgdbwrap/include/gdbwrapper.h deleted file mode 100644 index 9e2adbe903..0000000000 --- a/libr/debug/p/libgdbwrap/include/gdbwrapper.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef _INCLUDE_GDBWRAPPER_H_ -#define _INCLUDE_GDBWRAPPER_H_ - -/* File to include to use the wrapper. */ - -#ifndef IRAPI -#define IRAPI -#endif - -#include "r_types.h" -#if __UNIX__ -#include -#include -#include -#endif -#if __WINDOWS__ -#include -#endif -#include -#include "libaspect.h" - -#if __WINDOWS__ -typedef unsigned char uint8_t; -#endif - -typedef struct gdbwrap_gdbreg32 -{ - ureg32 eax; - ureg32 ecx; - ureg32 edx; - ureg32 ebx; - ureg32 esp; - ureg32 ebp; - ureg32 esi; - ureg32 edi; - ureg32 eip; - ureg32 eflags; - ureg32 cs; - ureg32 ss; - ureg32 ds; - ureg32 es; - ureg32 fs; - ureg32 gs; -} gdbwrap_gdbreg32; - - -typedef struct gdbwrap_t -{ - char *packet; - int fd; - unsigned max_packet_size; - ut8 *regs; - unsigned num_registers; - unsigned reg_size; - Bool is_active; - Bool erroroccured; - Bool interrupted; - Bool pmode; -} gdbwrap_t; - -typedef struct meminfo_t -{ - char *type; - u_int start; - u_int length; - u_int blocksize; -} meminfo_t; - -typedef struct gdbmemap_t -{ - meminfo_t ram; - meminfo_t rom; - meminfo_t flash; -} gdbmemap_t; - - -typedef struct -{ - gdbwrap_t *gdbwrapptr; -} gdbwrapworld_t; - -IRAPI Bool gdbwrap_erroroccured(gdbwrap_t *desc); -IRAPI Bool gdbwrap_cmdnotsup(gdbwrap_t *desc); -IRAPI unsigned gdbwrap_atoh(const char * str, unsigned size); -IRAPI unsigned gdbwrap_lastsignal(gdbwrap_t *desc); -IRAPI Bool gdbwrap_is_active(gdbwrap_t *desc); -IRAPI gdbwrapworld_t gdbwrap_current_set(gdbwrap_t *world); -IRAPI gdbwrap_t *gdbwrap_current_get(void); -IRAPI gdbwrap_t *gdbwrap_init(int fd, ut32 num, ut32 size); -IRAPI void gdbwrap_close(gdbwrap_t *desc); -IRAPI void gdbwrap_hello(gdbwrap_t *desc); -IRAPI void gdbwrap_bye(gdbwrap_t *desc); -IRAPI void gdbwrap_reason_halted(gdbwrap_t *desc); -IRAPI char *gdbwrap_own_command(gdbwrap_t *desc, char *command); -IRAPI ut8 *gdbwrap_readgenreg(gdbwrap_t *desc); -IRAPI void gdbwrap_continue(gdbwrap_t *desc); -IRAPI void gdbwrap_setbp(gdbwrap_t *desc, la32 linaddr, void *datasaved); -IRAPI int gdbwrap_simplesetbp(gdbwrap_t *desc, la32 linaddr); -IRAPI void gdbwrap_delbp(gdbwrap_t *desc, la32 linaddr, void *datasaved); -IRAPI int gdbwrap_simpledelbp(gdbwrap_t *desc, la32 linaddr); -IRAPI char *gdbwrap_readmem(gdbwrap_t *desc, la32 linaddr, unsigned bytes); -IRAPI void gdbwrap_writemem(gdbwrap_t *desc, la32 linaddr, void *value, unsigned bytes); -IRAPI void gdbwrap_writereg(gdbwrap_t *desc, ureg32 regnum, la32 val); -IRAPI char *gdbwrap_shipallreg(gdbwrap_t *desc); -IRAPI void gdbwrap_ctrl_c(gdbwrap_t *desc); -IRAPI void gdbwrap_signal(gdbwrap_t *desc, int signal); -IRAPI void gdbwrap_stepi(gdbwrap_t *desc); -IRAPI char *gdbwrap_remotecmd(gdbwrap_t *desc, char *cmd); -IRAPI u_char gdbwrap_lasterror(gdbwrap_t *desc); -IRAPI gdbmemap_t gdbwrap_memorymap_get(); -IRAPI ut64 gdbwrap_getreg(gdbwrap_t *desc, ut32 idx); -IRAPI void gdbwrap_getreg_buffer(gdbwrap_t *desc, unsigned char *buf, ut32 size); -IRAPI void gdbwrap_setreg(gdbwrap_t *desc, ut32 idx, ut64 value); -IRAPI void gdbwrap_setreg_buffer(gdbwrap_t *desc, const unsigned char *buf, ut32 size); -#endif diff --git a/libr/debug/p/libgdbwrap/include/libaspect.h b/libr/debug/p/libgdbwrap/include/libaspect.h deleted file mode 100644 index e556321a8d..0000000000 --- a/libr/debug/p/libgdbwrap/include/libaspect.h +++ /dev/null @@ -1 +0,0 @@ -#include "revm.h" diff --git a/libr/debug/p/libgdbwrap/include/libe2dbg.h b/libr/debug/p/libgdbwrap/include/libe2dbg.h deleted file mode 100644 index e556321a8d..0000000000 --- a/libr/debug/p/libgdbwrap/include/libe2dbg.h +++ /dev/null @@ -1 +0,0 @@ -#include "revm.h" diff --git a/libr/debug/p/libgdbwrap/include/revm.h b/libr/debug/p/libgdbwrap/include/revm.h deleted file mode 100644 index d8b4f5db11..0000000000 --- a/libr/debug/p/libgdbwrap/include/revm.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _INCLUDE_ERESI_H_ -#define _INCLUDE_ERESI_H_ - -#include -#include -#include -#include - -#if 0 -#define u_short unsigned short -#define u_char unsigned char -#define u_int unsigned int -#define uint8_t unsigned char -#endif - -#define la32 unsigned int -#define ptrdiff_t int -#define ureg32 unsigned int -#define Bool int -#define QWORD_IN_BYTE 8 -#define DWORD_IN_BYTE 4 -#define BYTE_IN_BIT 8 -#define BYTE_IN_CHAR 2 -#define TRUE 1 -#define FALSE 0 -#define ASSERT(x) // -#define assert(x) // -#undef LOBYTE -#define LOBYTE(_w) ((_w) & 0xff) -#define NEXT_CHAR(_x) (_x+1) -#define PROFILER_IN(fd,fun,line) // -#define PROFILER_OUT(fd,fun,line,str,ret) // -#define PROFILER_ROUT(fd,fun,line,ret) return ret -#define PROFILER_ERR(fd,fun,line,str,ret) { fprintf(stderr, str"\n"); return ret; } - -#endif diff --git a/libr/debug/p/libgdbwrap/interface.c b/libr/debug/p/libgdbwrap/interface.c deleted file mode 100644 index ae158c4e20..0000000000 --- a/libr/debug/p/libgdbwrap/interface.c +++ /dev/null @@ -1,43 +0,0 @@ -#include "gdbwrapper.h" - -int gdbwrap_simpleconnect(char *host, int port) -{ - int rval; - int sd; - struct sockaddr_in socketaddr; - struct hostent *hostaddr; - struct protoent *protocol; - - PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); - - hostaddr = gethostbyname(host); - protocol = getprotobyname("tcp"); - - if (!hostaddr) - PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "invalid gethostbyname", -1); - - if (!port) - PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "invalid port", -1); - - if (!protocol) - PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "invalid getprotobyname()", - -1); - - sd = socket(PF_INET, SOCK_STREAM, protocol->p_proto); - - if (sd == -1) - PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "invalid socket", -1); - - memset(&socketaddr, 0, sizeof(socketaddr)); - socketaddr.sin_family = AF_INET; - socketaddr.sin_port = htons(port); - - memcpy(&socketaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length); - rval = connect(sd, (struct sockaddr *)&socketaddr, sizeof(socketaddr)); - - if (rval == -1) - PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Problem when connecting", - -1); - - PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, sd); -} diff --git a/shlr/gdb/Makefile b/shlr/gdb/Makefile new file mode 100644 index 0000000000..38eaf0d9c8 --- /dev/null +++ b/shlr/gdb/Makefile @@ -0,0 +1,68 @@ +CC = gcc +LIBNAME = libgdbr +MAJOR = 0 +MINOR = 1 +CFLAGS = -Wall -g -O0 -ggdb # -std=gnu11 +LD = gcc +LDFLAGS = -L /usr/lib -L /usr/local/lib + +# Test variables +TEST_D = $(PWD)/test +BIN = $(PWD)/bin +UNIT_TEST = $(TEST_D)/unit.c +CLIENT = $(TEST_D)/client.c + +PWD = . +TEST = $(PWD)/test +LIB = $(PWD)/lib +INCLUDES = -I $(PWD)/include + +TEST_INCLUDES += $(INCLUDES) -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include + +SRC_D = $(PWD)/src +SRC_C = $(wildcard $(SRC_D)/*.c) +SRC_O = $(SRC_C:.c=.o) + +TEST_C = $(wildcard $(TEST_D)/*.c) +TEST_O = $(TEST_C:.c=.o) + + +$(SRC_O): %.o : %.c + $(CC) $(CFLAGS) $(INCLUDES) -c -fPIC $< -o $@ + +all: make +default: make + +prepare: + mkdir -p $(LIB) + +lib: prepare $(SRC_O) + $(LD) -shared -Wl,-soname,$(LIBNAME).so -o $(LIB)/$(LIBNAME).so $(SRC_O) + ar rvs $(LIB)/$(LIBNAME).a $(SRC_O) + +clean: + -rm $(SRC_O) + -rm $(LIB)/* + +unit: lib + $(CC) $(CFLAGS) $(TEST_INCLUDES) -c $(UNIT_TEST) -o $(TEST_D)/unit.o + $(LD) $(TEST_D)/unit.o -o $(TEST_D)/unit -L$(LIB) -lgdbr -lglib-2.0 + +run_unit: unit + LD_LIBRARY_PATH=./lib ./test/unit + +client: lib + $(CC) $(CFLAGS) $(INCLUDES) -c $(CLIENT) -o $(TEST_D)/client.o + $(LD) $(TEST_D)/client.o -o $(TEST_D)/client -L$(LIB) -lgdbr + +run_test: client + LD_LIBRARY_PATH=./lib ./test/client + +gdb_test: client + LD_LIBRARY_PATH=./lib gdb ./test/client + +valgrind_test: client + LD_LIBRARY_PATH=./lib valgrind --track-origins=yes -v --leak-check=full ./test/client + +edit: + vim -c "args **/*.h **/*.c" diff --git a/shlr/gdb/include/arch.h b/shlr/gdb/include/arch.h new file mode 100644 index 0000000000..74d8813dd3 --- /dev/null +++ b/shlr/gdb/include/arch.h @@ -0,0 +1,128 @@ +/*! \file */ +#ifndef ARCH_H +#define ARCH_H + +#define ARCH_X86_64 0 +#define ARCH_X86_32 1 + +/*! + * This struct defines a generic + * register view + */ +typedef struct registers_t { + char name[32]; /*! The Name of the current register */ + uint64_t offset; /*! Offset in the data block */ + uint64_t size; /*! Size of the register */ + uint64_t value; /*! Saves the value of the register */ +} registers_t; + + +static registers_t x86_64[] = { + {"rax", 0, 8, 0}, + {"rbx", 8, 8, 0}, + {"rcx", 16, 8, 0}, + {"rdx", 24, 8, 0}, + {"rsi", 32, 8, 0}, + {"rdi", 40, 8, 0}, + {"rbp", 48, 8, 0}, + {"rsp", 56, 8, 0}, + {"r8", 64, 8, 0}, + {"r9", 72, 8, 0}, + {"r10", 80, 8, 0}, + {"r11", 88, 8, 0}, + {"r12", 96, 8, 0}, + {"r13", 104, 8, 0}, + {"r14", 112, 8, 0}, + {"r15", 120, 8, 0}, + {"rip", 128, 8, 0}, + {"eflags",136, 4, 0}, + {"cs", 140, 4, 0}, + {"ss", 144, 4, 0}, + {"ds", 148, 4, 0}, + {"es", 152, 4, 0}, + {"fs", 156, 4, 0}, + {"gs", 160, 4, 0}, + {"st0", 164, 10, 0}, + {"st1", 174, 10, 0}, + {"st2", 184, 10, 0}, + {"st3", 194, 10, 0}, + {"st4", 204, 10, 0}, + {"st5", 214, 10, 0}, + {"st6", 224, 10, 0}, + {"st7", 234, 10, 0}, + {"fctrl", 244, 4, 0}, + {"fstat", 248, 4, 0}, + {"ftag", 252, 4, 0}, + {"fiseg", 256, 4, 0}, + {"fioff", 260, 4, 0}, + {"foseg", 264, 4, 0}, + {"fooff", 268, 4, 0}, + {"fop", 272, 4, 0}, + {"xmm0", 276, 16, 0}, + {"xmm1", 292, 16, 0}, + {"xmm2", 308, 16, 0}, + {"xmm3", 324, 16, 0}, + {"xmm4", 340, 16, 0}, + {"xmm5", 356, 16, 0}, + {"xmm6", 372, 16, 0}, + {"xmm7", 388, 16, 0}, + {"xmm8", 404, 16, 0}, + {"xmm9", 420, 16, 0}, + {"xmm10", 436, 16, 0}, + {"xmm11", 452, 16, 0}, + {"xmm12", 468, 16, 0}, + {"xmm13", 484, 16, 0}, + {"xmm14", 500, 16, 0}, + {"xmm15", 516, 16, 0}, + {"mxcsr", 532, 4, 0}, + {"", 0, 0, 0} +}; + + +static registers_t x86_32[] = { + {"eax", 0, 4, 0}, + {"ecx", 4, 4, 0}, + {"edx", 8, 4, 0}, + {"ebx", 12, 4, 0}, + {"esp", 16, 4, 0}, + {"ebp", 20, 4, 0}, + {"esi", 24, 4, 0}, + {"edi", 28, 4, 0}, + {"eip", 32, 4, 0}, + {"eflags", 36, 4, 0}, + {"cs", 40, 4, 0}, + {"ss", 44, 4, 0}, + {"ds", 48, 4, 0}, + {"es", 52, 4, 0}, + {"fs", 56, 4, 0}, + {"gs", 60, 4, 0}, + {"st0", 64, 10, 0}, + {"st1", 74, 10, 0}, + {"st2", 84, 10, 0}, + {"st3", 94, 10, 0}, + {"st4", 104, 10, 0}, + {"st5", 114, 10, 0}, + {"st6", 124, 10, 0}, + {"st7", 134, 10, 0}, + {"fctrl", 144, 4, 0}, + {"fstat", 148, 4, 0}, + {"ftag", 152, 4, 0}, + {"fiseg", 156, 4, 0}, + {"fioff", 160, 4, 0}, + {"foseg", 164, 4, 0}, + {"fooff", 168, 4, 0}, + {"fop", 172, 4, 0}, + {"xmm0", 176, 16, 0}, + {"xmm1", 192, 16, 0}, + {"xmm2", 208, 16, 0}, + {"xmm3", 224, 16, 0}, + {"xmm4", 240, 16, 0}, + {"xmm5", 256, 16, 0}, + {"xmm6", 272, 16, 0}, + {"xmm7", 288, 16, 0}, + {"mxcsr", 304, 4, 0}, + {"", 0, 0, 0} +}; + + +#endif diff --git a/shlr/gdb/include/core.h b/shlr/gdb/include/core.h new file mode 100644 index 0000000000..6eb6062845 --- /dev/null +++ b/shlr/gdb/include/core.h @@ -0,0 +1,54 @@ +/*! \file */ +#ifndef CORE_H +#define CORE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libgdbr.h" +#include "utils.h" +#include "arch.h" + +#define CMD_READREGS "g" +#define CMD_WRITEREGS "G" +#define CMD_WRITEMEM "M" +#define CMD_READMEM "m" + +#define CMD_BP "Z0" +#define CMD_RBP "z0" +#define CMD_QRCMD "qRcmd," +#define CMD_C "vCont" +#define CMD_C_CONT "c" +#define CMD_C_STEP "s" + + +/*! + * \brief Function sends a command to the gdbserver + * \param instance the "instance" of the current libgdbr session + * \param command the command that will be sent + * \returns a failure code (currently -1) or 0 if call successfully + */ +int send_command(libgdbr_t* instance, char* command); + +/*! + * \brief Function sends a vCont command to the gdbserver + * \param instance thre "instance" of the current libgdbr session + * \param command the command that will be sent (i.e. 's,S,c,C...') + * \returns -1 if something went wrong + */ +int send_vcont(libgdbr_t* instance, char* command, int thread_id); + +/*! + * \brief Functions sends a single ack ('+') + * \param instance thre "instance" of the current libgdbr session + * \returns -1 if something went wrong + */ +int send_ack(libgdbr_t* instance); + +#endif diff --git a/shlr/gdb/include/libgdbr.h b/shlr/gdb/include/libgdbr.h new file mode 100644 index 0000000000..5a115774c5 --- /dev/null +++ b/shlr/gdb/include/libgdbr.h @@ -0,0 +1,122 @@ +/*! \file */ +#ifndef LIBGDBR_H +#define LIBGDBR_H + +#include +#include + +#include "arch.h" + +static int X86_64 = ARCH_X86_64; +static int X86_32 = ARCH_X86_32; + + + +/*! + * Structure that saves a gdb message + */ +typedef struct libgdbr_message_t +{ + ssize_t len; /*! Len of the message */ + char* msg; /*! Pointer to the buffer that contains the message */ + uint8_t chk; /*! Cheksum of the current message read from the packet */ +} libgdbr_message_t; + + +/*! + * Message stack + */ +typedef struct libgdbr_message_stack_t +{ + int count; +} libgdbr_message_stack_t; + + +/*! + * Core "object" that saves + * the instance of the lib + */ +typedef struct libgdbr_t +{ + char* send_buff; // defines a buffer for reading and sending stuff + ssize_t send_len; // definses the maximal len for the given buffer + ssize_t send_max; // definses the maximal len for the given buffer + char* read_buff; + ssize_t read_len; + ssize_t read_max; + + // is already handled (i.e. already send or ...) + int fd; // Filedescriptor // TODO add r_socket stuff from radare + int connected; + int acks; + char* data; + ssize_t data_len; + ssize_t data_max; + uint8_t architecture; + registers_t* registers; +} libgdbr_t; + +/*! + * \brief Function initializes the libgdbr lib + * \returns a failure code (currently -1) or 0 if call successfully + */ +int gdbr_init(libgdbr_t* instance); + +/*! + * \brief Function initializes the architecture of the gdbsession + * \param architecture defines the architecure used (registersize, and such) + * \returns a failure code + */ +int gdbr_set_architecture(libgdbr_t* instance, uint8_t architecture); + +/*! + * \brief frees all buffers and cleans the libgdbr instance stuff + * \returns a failure code (currently -1) or 0 if call successfully + */ +int gdbr_cleanup(libgdbr_t* instance); + +/*! + * \brief Function connects to a gdbserver instance + * \param server string that represents the host + * \param number that represents the port + * \returns a failure code (currently -1) or 0 if call successfully + */ +int gdbr_connect(libgdbr_t* instance, const char* server, int port); + +/*! + * \brief disconnects the lib + * \returns a failure code (currently -1) or 0 if call successfully + */ +int gdbr_disconnect(libgdbr_t* instance); + +// Commands +int gdbr_continue(libgdbr_t* instance, int thread_id); +int gdbr_step(libgdbr_t* instance, int thread_id); +int gdbr_read_registers(libgdbr_t* instance); + +/*! + * \brief Function writes general purpose registers + * \param gdbr instance that contains the current context + * \param reg contains the registers that should be written + * reg contains a comma separated string that uses =value,=value + * i.e. eax=0x123,ebx=0x234 + * \returns a failurre code (currently -1) or 0 if call successfully + */ +int gdbr_write_bin_registers(libgdbr_t* instance, char* registers); +int gdbr_write_registers(libgdbr_t* instance, char* registers); +int gdbr_read_memory(libgdbr_t* instance, uint64_t address, uint64_t len); +int gdbr_write_memory(libgdbr_t* instance, uint64_t address, char* data, uint64_t len); +int gdbr_send_command(libgdbr_t* instance, char* command); +int test_command(libgdbr_t* instance, char* command); + +/*! + * \brief Function sets normal breakpoint (0xcc, int3) + * \param gdbr instance that contains the current context + * \param addrress at this position the breakpoint will be added + * \param conditions TODO: examine how this condition string should look like + * \returns a failure code (currently -1) or 0 if call successfully + */ +int gdbr_set_breakpoint(libgdbr_t* instance, uint64_t address, char* conditions); +int gdbr_unset_breakpoint(libgdbr_t* instance, uint64_t address); + +#endif diff --git a/shlr/gdb/include/messages.h b/shlr/gdb/include/messages.h new file mode 100644 index 0000000000..6dc7827d04 --- /dev/null +++ b/shlr/gdb/include/messages.h @@ -0,0 +1,24 @@ +/*! \file */ +/** + * See Appendix E in the gdb manual (GDB Remote Serial Protocol) + * Packets look following: $ starts a command/packet, the end is indicated + * with # and a final checksum + * $# + */ + +#ifndef MESSAGES_H +#define MESSAGES_H + +#include +#include "libgdbr.h" +#include "utils.h" + +int handle_g(libgdbr_t* instance); +int handle_m(libgdbr_t* instance); +int handle_cmd(libgdbr_t* instance); +int handle_cont(libgdbr_t* instance); +int handle_connect(libgdbr_t* instance); +int handle_setbp(libgdbr_t* instance); +int handle_unsetbp(libgdbr_t* instance); + +#endif diff --git a/shlr/gdb/include/packet.h b/shlr/gdb/include/packet.h new file mode 100644 index 0000000000..33adba7eeb --- /dev/null +++ b/shlr/gdb/include/packet.h @@ -0,0 +1,45 @@ +/*! \file */ +#ifndef PACKET_H +#define PACKET_H + +#include +#include +#include +#include +#include +#include "libgdbr.h" +#include + +typedef struct parsing_object_t +{ + char* buffer; + ssize_t length; + int start; + int end; + int position; + uint8_t checksum; + int acks; +} parsing_object_t; + + +int parse_packet(libgdbr_t* instance, int data_offset); +/*! + * \brief sends a packet sends a packet to the established connection + * \param instance the "instance" of the current libgdbr session + * \returns a failure code (currently -1) or 0 if call successfully + */ +int send_packet(libgdbr_t* instance); + +/*! + * \brief Function reads data from the established connection + * \param instance the "instance" of the current libgdbr session + * \returns a failure code (currently -1) or 0 if call successfully + */ +int read_packet(libgdbr_t* instance); +void handle_data(parsing_object_t* current); +void handle_chk(parsing_object_t* current); +void handle_packet(parsing_object_t* current); +void handle_escape(parsing_object_t* current); +char get_next_token(parsing_object_t* current); + +#endif diff --git a/shlr/gdb/include/utils.h b/shlr/gdb/include/utils.h new file mode 100644 index 0000000000..38ce6186c9 --- /dev/null +++ b/shlr/gdb/include/utils.h @@ -0,0 +1,18 @@ +/*! \file */ +#ifndef UTILS_H +#define UTILS_H + +#include +#include + + +uint8_t cmd_checksum(const char* command); +uint64_t unpack_uint64(char *buff, int len); +uint64_t unpack_uint64_co(char* buff, int len); +int unpack_hex(char* src, uint64_t len, char* dst); +int pack_hex(char* src, uint64_t len, char* dst); +int hex2int(int ch); +int int2hex(int i); +void hexdump(void* ptr, uint64_t len, uint64_t offset); + +#endif diff --git a/shlr/gdb/src/core.c b/shlr/gdb/src/core.c new file mode 100644 index 0000000000..721be3bfb0 --- /dev/null +++ b/shlr/gdb/src/core.c @@ -0,0 +1,319 @@ +#include "libgdbr.h" +#include "core.h" +#include "packet.h" +#include "messages.h" + + +int gdbr_init(libgdbr_t* instance) { + memset(instance,0, sizeof(libgdbr_t)); + instance->send_buff = (char*) calloc(2500, sizeof(char)); + instance->send_len = 0; + instance->send_max = 2500; + instance->read_buff = (char*) calloc(4096, sizeof(char)); + instance->read_len = 0; + instance->read_max = 4096; + instance->connected = 0; + instance->data_len = 0; + instance->data = calloc(4096, sizeof(char)); + instance->data_max = 4096; + return 0; +} + + +int gdbr_set_architecture(libgdbr_t* instance, uint8_t architecture) { + instance->architecture = architecture; + switch (architecture) { + case ARCH_X86_32: + instance->registers = x86_32; + break; + case ARCH_X86_64: + instance->registers = x86_64; + break; + default: + printf("Error unknown architecture set\n"); + } + return 0; +} + + +int gdbr_cleanup(libgdbr_t* instance) { + free(instance->data); + free(instance->send_buff); + instance->send_len = 0; + free(instance->read_buff); + instance->read_len = 0; + return 0; +} + + +int gdbr_connect(libgdbr_t* instance, const char* host, int port) { + int fd; + int connected; + struct protoent *protocol; + struct hostent *hostaddr; + struct sockaddr_in socketaddr; + + protocol = getprotobyname("tcp"); + if (!protocol) { + printf("Error prot\n"); + //TODO Error here + return -1; + } + + fd = socket( PF_INET, SOCK_STREAM, protocol->p_proto); + if (fd == -1) { + printf("Error sock\n"); + //TODO Error here + return -1; + } + memset(&socketaddr, 0, sizeof(socketaddr)); + socketaddr.sin_family = AF_INET; + socketaddr.sin_port = htons(port); + hostaddr = (struct hostent *)gethostbyname(host); + + if (!hostaddr) { + printf("Error host\n"); + //TODO Error here + return -1; + } + + connected = connect(fd, (struct sockaddr *) &socketaddr, sizeof(socketaddr)); + if (connected == -1) { + printf("error conn\n"); + //TODO Error here + return -1; + } + instance->fd = fd; + instance->connected = 1; + // TODO add config possibility here + char* message = "qSupported:multiprocess+;qRelocInsn+"; + send_command(instance, message); + read_packet(instance); + return handle_connect(instance); +} + + +int gdbr_disconnect(libgdbr_t* instance) { + // TODO Disconnect maybe send something to gdbserver + close(instance->fd); + instance->connected = 0; + return 0; +} + + +int gdbr_read_registers(libgdbr_t* instance) { + send_command(instance, CMD_READREGS); + int read_len = read_packet(instance); + if ( read_len > 0) { + parse_packet(instance, 0); + return handle_g(instance); + } + return -1; +} + + +int gdbr_read_memory(libgdbr_t* instance, uint64_t address, uint64_t len) { + char command[255] = {}; + int ret = snprintf(command, 255, "%s%016lx,%ld", CMD_READMEM, address, len); + if (ret < 0) return ret; + send_command(instance, command); + + int read_len = read_packet(instance); + if (read_len > 0) { + parse_packet(instance, 0); + return handle_m(instance); + } + return -1; +} + + +int gdbr_write_memory(libgdbr_t* instance, uint64_t address, char* data, uint64_t len) { + char command[255] = {}; + int command_len = snprintf(command, 255, "%s%016lx,%ld:", CMD_WRITEMEM, address, len); + char* tmp = calloc(command_len + (len * 2), sizeof(char)); + memcpy(tmp, command, command_len); + pack_hex(data, len, (tmp + command_len)); + send_command(instance, tmp); + free(tmp); + + int read_len = read_packet(instance); + if (read_len > 0) { + parse_packet(instance, 0); + return 0; + } + return -1; +} + + +int gdbr_step(libgdbr_t* instance, int thread_id) { + return send_vcont(instance, CMD_C_STEP, thread_id); +} + + +int gdbr_continue(libgdbr_t* instance, int thread_id) { + return send_vcont(instance, CMD_C_CONT, thread_id); +} + + +int gdbr_send_command(libgdbr_t* instance, char* command) { + char* cmd = calloc((strlen(command) * 2 + strlen(CMD_QRCMD) + 2), sizeof(char)); + strcpy(cmd, CMD_QRCMD); + pack_hex(command, strlen(command), (cmd + strlen(CMD_QRCMD))); + int ret = send_command(instance, cmd); + free(cmd); + if (ret < 0) return ret; + + int read_len = read_packet(instance); + if (read_len > 0) { + parse_packet(instance, 1); + return handle_cmd(instance); + } + return -1; +} + + +int gdbr_write_bin_registers(libgdbr_t* instance, char* registers) { + gdbr_read_registers(instance); + + uint64_t buffer_size = instance->data_len * 2 + 8; + char* command = calloc(buffer_size, sizeof(char)); + snprintf(command, buffer_size, "%s", CMD_WRITEREGS); + pack_hex(instance->data, instance->data_len, command+1); + send_command(instance, command); + free(command); + return 0; +} + + +int gdbr_write_registers(libgdbr_t* instance, char* registers) { + int ret = 0; + // read current register set + gdbr_read_registers(instance); + + int len = strlen(registers); + char* buff = calloc(len, sizeof(char)); + memcpy(buff, registers, len); + char* reg = strtok(buff, ","); + while ( reg != NULL ) { + char* name_end = strchr(reg, '='); + if (name_end == NULL) { + printf("Malformed argument: %s\n", reg); + free(buff); + return -1; + } + *name_end = '\0'; // change '=' to '\0' + + // time to find the current register + int i = 0; + while ( instance->registers[i].size > 0) { + if (strcmp(instance->registers[i].name, reg) == 0) { + + uint64_t register_size = instance->registers[i].size; + uint64_t offset = instance->registers[i].offset; + + char* value = calloc(register_size * 2, sizeof(char)); + + memset(value, '0', register_size * 2); + + name_end++; + // be able to take hex with and without 0x + if (name_end[1] == 'x' || name_end[1] == 'X') name_end += 2; + int val_len = strlen(name_end); // size of the rest + strcpy(value+(register_size * 2 - val_len), name_end); + + int x = 0; + while (x < register_size) { + instance->data[offset + register_size - x - 1] = hex2char(&value[x * 2]); + x++; + } + free(value); + } + i++; + } + reg = strtok(NULL, " ,"); + } + + free(buff); + + uint64_t buffer_size = instance->data_len * 2 + 8; + char* command = calloc(buffer_size, sizeof(char)); + snprintf(command, buffer_size, "%s", CMD_WRITEREGS); + pack_hex(instance->data, instance->data_len, command+1); + send_command(instance, command); + read_packet(instance); + free(command); + handle_G(instance); + return 0; +} + + +int test_command(libgdbr_t* instance, char* command) { + send_command(instance, command); + read_packet(instance); + hexdump(instance->read_buff, instance->data_len, 0); + return 0; +} + + +int send_vcont(libgdbr_t* instance, char* command, int thread_id) { + char tmp[255] = {}; + int ret = snprintf(tmp, 255, "%s;%s:%x", CMD_C, command, thread_id); + if (ret < 0) return ret; + send_command(instance, tmp); + + int read_len = read_packet(instance); + if (read_len > 0) { + parse_packet(instance, 0); + return handle_cont(instance); + } + return 0; +} + + +int gdbr_set_breakpoint(libgdbr_t* instance, uint64_t address, char* conditions) { + char tmp[255] = {}; + int ret = snprintf(tmp, 255, "%s,%llx,1", CMD_BP, address); + if (ret < 0) return ret; + send_command(instance, tmp); + + int read_len = read_packet(instance); + if (read_len > 0) { + parse_packet(instance, 0); + return handle_setbp(instance); + } + return 0; +} + + +int gdbr_unset_breakpoint(libgdbr_t* instance, uint64_t address) { + char tmp[255] = {}; + int ret = snprintf(tmp, 255, "%s,%llx,1", CMD_RBP, address); + if (ret < 0) return ret; + send_command(instance, tmp); + + int read_len = read_packet(instance); + if (read_len > 0) { + parse_packet(instance, 0); + return handle_unsetbp(instance); + } + return 0; +} + + +int send_ack(libgdbr_t* instance) { + instance->send_buff[0] = '+'; + instance->send_len = 1; + send_packet(instance); + return 0; +} + +int send_command(libgdbr_t* instance, char* command) { + uint8_t checksum = cmd_checksum(command); + int ret = snprintf(instance->send_buff, instance->send_max, "$%s#%.2x", command, checksum); + if (ret < 0) { + return ret; + } + instance->send_len = ret; + return send_packet(instance); +} + diff --git a/shlr/gdb/src/libgdbr.c b/shlr/gdb/src/libgdbr.c new file mode 100644 index 0000000000..bfbf355f15 --- /dev/null +++ b/shlr/gdb/src/libgdbr.c @@ -0,0 +1,5 @@ +#include "libgdbr.h" +#include "core.h" + +#include + diff --git a/shlr/gdb/src/messages.c b/shlr/gdb/src/messages.c new file mode 100644 index 0000000000..5f0c218c2b --- /dev/null +++ b/shlr/gdb/src/messages.c @@ -0,0 +1,61 @@ +#include "messages.h" +#include "arch.h" +#include "core.h" +#include "utils.h" + + +int handle_g(libgdbr_t* instance) { + unpack_hex(instance->data, instance->data_len, instance->data); + instance->data_len = instance->data_len / 2; + send_ack(instance); + return 0; +} + + +int handle_G(libgdbr_t* instance) { + send_ack(instance); + return 0; +} + + +int handle_m(libgdbr_t* instance) { + int len = strlen(instance->data); + instance->data_len = strlen(instance->data) / 2; + unpack_hex(instance->data, len, instance->data); + send_ack(instance); + return 0; +} + + +int handle_cmd(libgdbr_t* instance) { + unpack_hex(instance->data, strlen(instance->data), instance->data); + instance->data_len = strlen(instance->data) / 2; + send_ack(instance); + return 0; +} + + +int handle_connect(libgdbr_t* instance) { + // TODO handle the message correct and set all infos like packetsize, thread stuff and features + send_ack(instance); + return 0; +} + + +int handle_cont(libgdbr_t* instance) { + send_ack(instance); + return 0; +} + + +int handle_setbp(libgdbr_t* instance) { + send_ack(instance); + return 0; +} + + +int handle_unsetbp(libgdbr_t* instance) { + send_ack(instance); + return 0; +} + diff --git a/shlr/gdb/src/packet.c b/shlr/gdb/src/packet.c new file mode 100644 index 0000000000..74543dec84 --- /dev/null +++ b/shlr/gdb/src/packet.c @@ -0,0 +1,146 @@ +#include "packet.h" + + +char get_next_token(parsing_object_t* current) { + return current->buffer[current->position++]; +} + + +void handle_escape(parsing_object_t* current) { + if (current->position >= current->length) return; + char token = get_next_token(current); + if (token == '}') handle_data(current); + else handle_escape(current); +} + + +void handle_chk(parsing_object_t* current) { + if (current->position >= current->length) return; + char checksum[2]; + checksum[0] = get_next_token(current); + checksum[1] = get_next_token(current); + checksum[2] = '\0'; + current->checksum = (uint8_t) strtol(checksum, NULL, 16); +} + + +void handle_data(parsing_object_t* current) { + if (current->position >= current->length) return; + char token = get_next_token(current); + if (token == '#') { + current->end = current->position - 1; // subtract 2 cause of # itself and the incremented position after getNextToken + handle_chk(current); + } + else if (token == '{') handle_escape(current); + else handle_data(current); +} + + +void handle_packet(parsing_object_t* current) { + if(current->position >= current->length) return; + + char token = get_next_token(current); + if (token == '$') { + current->start = current->position; + handle_data(current); + } + else if (token == '+') { + current->acks++; + handle_packet(current); + } +} + +/** + * helper function that should unpack + * run-length encoded streams of data + */ +int unpack_data(char* dst, char* src, uint64_t len) { + int i = 0; + char last; + int ret_len = 0; + char* p_dst = dst; + while ( i < len) { + if (src[i] == '*') { + if (++i >= len ) printf("Error\n"); + char size = src[i++]; + uint8_t runlength = size - 29; + ret_len += runlength - 2; + while ( i < len && runlength-- > 0) { + *(p_dst++) = last; + } + continue; + } + last = src[i++]; + *(p_dst++) = last; + } + return ret_len; +} + + +int parse_packet(libgdbr_t* instance, int data_offset) { + parsing_object_t new; + memset(&new, 0, sizeof(parsing_object_t)); + new.length = instance->read_len; + new.buffer = instance->read_buff; + uint64_t target_pos = 0; + while(new.position < new.length) { + handle_packet(&new); + new.start += data_offset; + uint64_t current_size = new.end - new.start; + //if ( instance->data_max <= (instance->data_len + current_size)) { + // instance->data = realloc(instance->data, instance->data_len + current_size + 1); + // instance->data_len += current_size; + // instance->data_max += current_size; + //} + int runlength = unpack_data(instance->data + target_pos, new.buffer + new.start, current_size); + //memcpy(instance->data + target_pos , new.buffer + new.start, current_size); + target_pos += current_size + runlength; + } + instance->data_len = target_pos; // setting the resulting length + instance->read_len = 0; // reset the read_buf len + return 0; +} + + +int send_packet(libgdbr_t* instance) { + if (!instance) { + // TODO corect error handling here + printf("Initialize libgdbr_t first\n"); + return -1; + } + int ret = send(instance->fd, instance->send_buff, instance->send_len, 0); + return ret; +} + + +int read_packet(libgdbr_t* instance) { + if (!instance) { + // TODO correct error handling here + printf("Initialize libgdbr_t first\n"); + return -1; + } + int ret = 0; + int current_size = 0; + fd_set readset; + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100*1000; + int result = 1; + while (result > 0) { + FD_ZERO(&readset); + FD_SET(instance->fd, &readset); + result = select(instance->fd + 1, &readset, NULL, NULL, &tv); + if (result > 0) { + if (FD_ISSET(instance->fd, &readset)) { + //if ( instance->read_len <= (current_size + instance->max_read_size)) { + // instance->read_buff = realloc(instance->read_buff, instance->read_len + instance->read_size); + // instance->read_max += instance->read_max; + //} + ret = recv(instance->fd, (instance->read_buff + current_size), (instance->read_max - current_size), 0); + current_size += ret; + } + } + } + instance->read_len = current_size; + return current_size; +} diff --git a/shlr/gdb/src/utils.c b/shlr/gdb/src/utils.c new file mode 100644 index 0000000000..953d564aa7 --- /dev/null +++ b/shlr/gdb/src/utils.c @@ -0,0 +1,127 @@ +#include "utils.h" + + +/** + * Function creates the checksum + * for the given command + * - command : is used to calculate the checksum needs to be null terminated + * @returns : calculated checksum + */ +uint8_t cmd_checksum(const char* command) { + uint8_t sum = 0; + while(*command != '\0') { + sum += *command++; + } + return sum; +} + + +/** + * Converts str to uint64_t + */ +uint64_t unpack_uint64(char *buff, int len) { + int nibble; + uint64_t retval = 0; + while (len) { + nibble = hex2int(*buff++); + retval |= nibble; + len--; + if (len) retval = retval << 4; + } + return retval; +} + + +/** + * Changed byte order and + * converts the value into uint64_t + */ +uint64_t unpack_uint64_co(char* buff, int len) { + uint64_t result = 0; + int i; + for (i = len - 2; i >= 0; i-=2) { + result |= unpack_uint64(&buff[i], 2); + if (i) result <<= 8; + } + return result; +} + + +/** + * Converts a given hex character into its int value + * @returns value of hex or -1 on error + */ +int hex2int(int ch) { + if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; + if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; + if (ch >= '0' && ch <= '9') return ch - '0'; + return -1; +} + + +/** + * Converts a given nibble (4bit) into its hex representation + * @returns hex char or -1 on error + */ +int int2hex(int i) { + if (i >= 0 && i <= 9) return i + 48; + if (i >= 10 && i <= 15) return i + 55; + return -1; +} + + +char hex2char(char* hex) { + uint8_t result = hex2int((int)hex[0]); + result <<= 4; + result |= hex2int(hex[1]); + return (char) result; +} + + +int unpack_hex(char* src, uint64_t len, char* dst) { + int i = 0; + while (i < (len / 2)) { + int val = hex2int(src[(i*2)]); + val <<= 4; + val |= hex2int(src[(i*2)+1]); + dst[i++] = val; + } + dst[i] = '\0'; + return len; +} + + +int pack_hex(char* src, uint64_t len, char* dst) { + int i = 0; + int x = 0; + while (i < (len*2)) { + int val = (src[x] & 0xf0) >> 4; + dst[i++] = int2hex(val); + dst[i++] = int2hex(src[x++] & 0x0f); + } + dst[i] = '\0'; + return (len/2); +} + + +void hexdump(void* ptr, uint64_t len, uint64_t offset) { + unsigned char* data = (unsigned char*)ptr; + int x = 0; + char hex[49], *p; + char txt[17], *c; + uint64_t curr_offset; + while (x < len) { + p = hex; + c = txt; + curr_offset = x+offset; + + do { + p += sprintf(p, "%02hhx ", data[x]); + *c++ = (data[x] >= 32 && data[x] <= 127) ? data[x] : '.'; + }while (++x % 16 && x < len); + + *c = '\0'; + printf("0x%016lx: %-48s- %s\n", (curr_offset), hex, txt); + } +} +