mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-26 17:15:38 +00:00
added libgdbr sources to shlr folder
Signed-off-by: defragger <rlaemmert@gmail.com>
This commit is contained in:
parent
0e010573c6
commit
0404623595
@ -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
|
@ -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
|
@ -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);
|
||||
}
|
@ -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 <netdb.h>
|
||||
#endif
|
||||
|
||||
#if __WINDOWS__
|
||||
#include <windows.h>
|
||||
#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 <number>*<char> where * and
|
||||
<char> are filled with the value of <number> (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<signum>[:process_pid]#<checksum>
|
||||
*
|
||||
* 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;
|
||||
}
|
@ -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
|
@ -1 +0,0 @@
|
||||
/* This file has to be merged with eresi */
|
@ -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 <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#if __WINDOWS__
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#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
|
@ -1 +0,0 @@
|
||||
#include "revm.h"
|
@ -1 +0,0 @@
|
||||
#include "revm.h"
|
@ -1,36 +0,0 @@
|
||||
#ifndef _INCLUDE_ERESI_H_
|
||||
#define _INCLUDE_ERESI_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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
|
@ -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);
|
||||
}
|
68
shlr/gdb/Makefile
Normal file
68
shlr/gdb/Makefile
Normal file
@ -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"
|
128
shlr/gdb/include/arch.h
Normal file
128
shlr/gdb/include/arch.h
Normal file
@ -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
|
54
shlr/gdb/include/core.h
Normal file
54
shlr/gdb/include/core.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*! \file */
|
||||
#ifndef CORE_H
|
||||
#define CORE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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
|
122
shlr/gdb/include/libgdbr.h
Normal file
122
shlr/gdb/include/libgdbr.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*! \file */
|
||||
#ifndef LIBGDBR_H
|
||||
#define LIBGDBR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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 <regname>=value,<regname>=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
|
24
shlr/gdb/include/messages.h
Normal file
24
shlr/gdb/include/messages.h
Normal file
@ -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
|
||||
* $<command>#<checksum>
|
||||
*/
|
||||
|
||||
#ifndef MESSAGES_H
|
||||
#define MESSAGES_H
|
||||
|
||||
#include <string.h>
|
||||
#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
|
45
shlr/gdb/include/packet.h
Normal file
45
shlr/gdb/include/packet.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*! \file */
|
||||
#ifndef PACKET_H
|
||||
#define PACKET_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include "libgdbr.h"
|
||||
#include <stdio.h>
|
||||
|
||||
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
|
18
shlr/gdb/include/utils.h
Normal file
18
shlr/gdb/include/utils.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*! \file */
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
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
|
319
shlr/gdb/src/core.c
Normal file
319
shlr/gdb/src/core.c
Normal file
@ -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);
|
||||
}
|
||||
|
5
shlr/gdb/src/libgdbr.c
Normal file
5
shlr/gdb/src/libgdbr.c
Normal file
@ -0,0 +1,5 @@
|
||||
#include "libgdbr.h"
|
||||
#include "core.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
61
shlr/gdb/src/messages.c
Normal file
61
shlr/gdb/src/messages.c
Normal file
@ -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;
|
||||
}
|
||||
|
146
shlr/gdb/src/packet.c
Normal file
146
shlr/gdb/src/packet.c
Normal file
@ -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;
|
||||
}
|
127
shlr/gdb/src/utils.c
Normal file
127
shlr/gdb/src/utils.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user