Fix CID 1171365 Fix CID 1211169 Fix CID 1230038 Fix CID 1295063, 1295062, 1295061 Fix CID 1295070 Fix CID 1295068 Fix CID 12950067
741 lines
15 KiB
C
741 lines
15 KiB
C
/* libgdbr - LGPL - Copyright 2014 - defragger */
|
|
|
|
#include "libgdbr.h"
|
|
#include "core.h"
|
|
#include "packet.h"
|
|
#include "messages.h"
|
|
|
|
extern char hex2char(char* hex);
|
|
|
|
static registers_t x86_64[] = {
|
|
{"rax", 0, 8},
|
|
{"rbx", 8, 8},
|
|
{"rcx", 16, 8},
|
|
{"rdx", 24, 8},
|
|
{"rsi", 32, 8},
|
|
{"rdi", 40, 8},
|
|
{"rbp", 48, 8},
|
|
{"rsp", 56, 8},
|
|
{"r8", 64, 8},
|
|
{"r9", 72, 8},
|
|
{"r10", 80, 8},
|
|
{"r11", 88, 8},
|
|
{"r12", 96, 8},
|
|
{"r13", 104, 8},
|
|
{"r14", 112, 8},
|
|
{"r15", 120, 8},
|
|
{"rip", 128, 8},
|
|
{"eflags",136, 4},
|
|
{"cs", 140, 4},
|
|
{"ss", 144, 4},
|
|
{"ds", 148, 4},
|
|
{"es", 152, 4},
|
|
{"fs", 156, 4},
|
|
{"gs", 160, 4},
|
|
{"st0", 164, 10},
|
|
{"st1", 174, 10},
|
|
{"st2", 184, 10},
|
|
{"st3", 194, 10},
|
|
{"st4", 204, 10},
|
|
{"st5", 214, 10},
|
|
{"st6", 224, 10},
|
|
{"st7", 234, 10},
|
|
{"fctrl", 244, 4},
|
|
{"fstat", 248, 4},
|
|
{"ftag", 252, 4},
|
|
{"fiseg", 256, 4},
|
|
{"fioff", 260, 4},
|
|
{"foseg", 264, 4},
|
|
{"fooff", 268, 4},
|
|
{"fop", 272, 4},
|
|
{"xmm0", 276, 16},
|
|
{"xmm1", 292, 16},
|
|
{"xmm2", 308, 16},
|
|
{"xmm3", 324, 16},
|
|
{"xmm4", 340, 16},
|
|
{"xmm5", 356, 16},
|
|
{"xmm6", 372, 16},
|
|
{"xmm7", 388, 16},
|
|
{"xmm8", 404, 16},
|
|
{"xmm9", 420, 16},
|
|
{"xmm10", 436, 16},
|
|
{"xmm11", 452, 16},
|
|
{"xmm12", 468, 16},
|
|
{"xmm13", 484, 16},
|
|
{"xmm14", 500, 16},
|
|
{"xmm15", 516, 16},
|
|
{"mxcsr", 532, 4},
|
|
{"", 0, 0}
|
|
};
|
|
|
|
|
|
static registers_t x86_32[] = {
|
|
{"eax", 0, 4},
|
|
{"ecx", 4, 4},
|
|
{"edx", 8, 4},
|
|
{"ebx", 12, 4},
|
|
{"esp", 16, 4},
|
|
{"ebp", 20, 4},
|
|
{"esi", 24, 4},
|
|
{"edi", 28, 4},
|
|
{"eip", 32, 4},
|
|
{"eflags", 36, 4},
|
|
{"cs", 40, 4},
|
|
{"ss", 44, 4},
|
|
{"ds", 48, 4},
|
|
{"es", 52, 4},
|
|
{"fs", 56, 4},
|
|
{"gs", 60, 4},
|
|
{"st0", 64, 10},
|
|
{"st1", 74, 10},
|
|
{"st2", 84, 10},
|
|
{"st3", 94, 10},
|
|
{"st4", 104, 10},
|
|
{"st5", 114, 10},
|
|
{"st6", 124, 10},
|
|
{"st7", 134, 10},
|
|
{"fctrl", 144, 4},
|
|
{"fstat", 148, 4},
|
|
{"ftag", 152, 4},
|
|
{"fiseg", 156, 4},
|
|
{"fioff", 160, 4},
|
|
{"foseg", 164, 4},
|
|
{"fooff", 168, 4},
|
|
{"fop", 172, 4},
|
|
{"xmm0", 176, 16},
|
|
{"xmm1", 192, 16},
|
|
{"xmm2", 208, 16},
|
|
{"xmm3", 224, 16},
|
|
{"xmm4", 240, 16},
|
|
{"xmm5", 256, 16},
|
|
{"xmm6", 272, 16},
|
|
{"xmm7", 288, 16},
|
|
{"mxcsr", 304, 4},
|
|
{"", 0, 0}
|
|
};
|
|
|
|
static registers_t arm32[] = {
|
|
{"r0", 0, 4},
|
|
{"r1", 4, 4},
|
|
{"r2", 8, 4},
|
|
{"r3", 12, 4},
|
|
{"r4", 16, 4},
|
|
{"r5", 20, 4},
|
|
{"r6", 24, 4},
|
|
{"r7", 28, 4},
|
|
{"r8", 32, 4},
|
|
{"r9", 36, 4},
|
|
{"r10", 40, 4},
|
|
{"r11", 44, 4},
|
|
{"r12", 48, 4},
|
|
{"sp", 52, 4},
|
|
{"lr", 56, 4},
|
|
{"pc", 60, 4},
|
|
{"f0", 64, 12},
|
|
{"f1", 76, 12},
|
|
{"f2", 88, 12},
|
|
{"f3", 100, 12},
|
|
{"f4", 112, 12},
|
|
{"f5", 124, 12},
|
|
{"f6", 136, 12},
|
|
{"f7", 148, 12},
|
|
{"fps", 160, 12},
|
|
{"cpsr", 172,4},
|
|
{"", 0, 0}
|
|
};
|
|
|
|
|
|
static registers_t aarch64[] = {
|
|
{"x0", 0, 8},
|
|
{"x1", 8, 8},
|
|
{"x2", 16, 8},
|
|
{"x3", 24, 8},
|
|
{"x4", 32, 8},
|
|
{"x5", 40, 8},
|
|
{"x6", 48, 8},
|
|
{"x7", 56, 8},
|
|
{"x8", 64, 8},
|
|
{"x9", 72, 8},
|
|
{"x10", 80, 8},
|
|
{"x11", 88, 8},
|
|
{"x12", 96, 8},
|
|
{"x13", 104, 8},
|
|
{"x14", 112, 8},
|
|
{"x15", 120, 8},
|
|
{"x16", 128, 8},
|
|
{"x17", 136, 8},
|
|
{"x18", 144, 8},
|
|
{"x19", 152, 8},
|
|
{"x20", 160, 8},
|
|
{"x21", 168, 8},
|
|
{"x22", 176, 8},
|
|
{"x23", 184, 8},
|
|
{"x24", 192, 8},
|
|
{"x25", 200, 8},
|
|
{"x26", 208, 8},
|
|
{"x27", 216, 8},
|
|
{"x28", 224, 8},
|
|
{"x29", 232, 8},
|
|
{"x30", 240, 8},
|
|
{"sp", 248, 8},
|
|
{"pc", 256, 8},
|
|
{"cpsr", 264, 4},
|
|
{"v0", 268, 16},
|
|
{"v1", 284, 16},
|
|
{"v2", 300, 16},
|
|
{"v3", 316, 16},
|
|
{"v4", 332, 16},
|
|
{"v5", 348, 16},
|
|
{"v6", 364, 16},
|
|
{"v7", 380, 16},
|
|
{"v8", 396, 16},
|
|
{"v9", 412, 16},
|
|
{"v10", 428, 16},
|
|
{"v11", 444, 16},
|
|
{"v12", 460, 16},
|
|
{"v13", 476, 16},
|
|
{"v14", 492, 16},
|
|
{"v15", 508, 16},
|
|
{"v16", 524, 16},
|
|
{"v17", 540, 16},
|
|
{"v18", 556, 16},
|
|
{"v19", 572, 16},
|
|
{"v20", 588, 16},
|
|
{"v21", 604, 16},
|
|
{"v22", 620, 16},
|
|
{"v23", 636, 16},
|
|
{"v24", 652, 16},
|
|
{"v25", 668, 16},
|
|
{"v26", 684, 16},
|
|
{"v27", 700, 16},
|
|
{"v28", 716, 16},
|
|
{"v29", 732, 16},
|
|
{"v30", 748, 16},
|
|
{"v31", 764, 16},
|
|
{"fpsr", 780, 4},
|
|
{"fpcr", 784, 4},
|
|
{"", 0, 0}
|
|
};
|
|
static registers_t mips[] = {
|
|
{"zero", 0, 0},
|
|
{"at", 4, 0},
|
|
{"v0", 8, 0},
|
|
{"v1", 12, 8},
|
|
{"a0", 16, 8},
|
|
{"a1", 20, 8},
|
|
{"a2", 24, 8},
|
|
{"a3", 28, 8},
|
|
{"t0", 32, 8},
|
|
{"t1", 36, 8},
|
|
{"t2", 40, 8},
|
|
{"t3", 44, 8},
|
|
{"t4", 48, 8},
|
|
{"t5", 52, 8},
|
|
{"t6", 56, 8},
|
|
{"t7", 60, 8},
|
|
{"s0", 64, 8},
|
|
{"s1", 68, 8},
|
|
{"s2", 72, 8},
|
|
{"s3", 76, 8},
|
|
{"s4", 80, 8},
|
|
{"s5", 84, 8},
|
|
{"s6", 88, 8},
|
|
{"s7", 92, 8},
|
|
{"t8", 96, 8},
|
|
{"t9", 100, 8},
|
|
{"k0", 104, 8},
|
|
{"k1", 108, 8},
|
|
{"gp", 112, 8},
|
|
{"sp", 116, 8},
|
|
{"s8", 120, 8},
|
|
{"ra", 124, 8},
|
|
{"sr", 128, 8},
|
|
{"lo", 132, 8},
|
|
{"hi", 134, 8},
|
|
{"bad", 140, 8},
|
|
{"cause", 144, 8},
|
|
{"pc", 148, 8},
|
|
{"f0", 152, 8},
|
|
{"f1", 156, 8},
|
|
{"f2", 160, 8},
|
|
{"f3", 164, 8},
|
|
{"f4", 168, 8},
|
|
{"f5", 172, 8},
|
|
{"f6", 176, 8},
|
|
{"f7", 180, 8},
|
|
{"f8", 184, 8},
|
|
{"f9", 188, 8},
|
|
{"f10", 192, 8},
|
|
{"f11", 196, 8},
|
|
{"f12", 200, 8},
|
|
{"f13", 204, 8},
|
|
{"f14", 208, 8},
|
|
{"f15", 212, 8},
|
|
{"f16", 216, 8},
|
|
{"f17", 220, 8},
|
|
{"f18", 224, 8},
|
|
{"f19", 228, 8},
|
|
{"f20", 232, 8},
|
|
{"f21", 236, 8},
|
|
{"f22", 240, 8},
|
|
{"f23", 244, 8},
|
|
{"f24", 248, 8},
|
|
{"f25", 252, 8},
|
|
{"f26", 256, 8},
|
|
{"f27", 260, 8},
|
|
{"f28", 264, 8},
|
|
{"f29", 268, 8},
|
|
{"f30", 272, 8},
|
|
{"f31", 276, 8},
|
|
{"fsr", 280, 8},
|
|
{"fir", 284, 8},
|
|
{"unknw", 288, 8},
|
|
{"", 0, 0}
|
|
};
|
|
|
|
int gdbr_init(libgdbr_t* g) {
|
|
if (!g) return -1;
|
|
memset (g ,0 , sizeof (libgdbr_t));
|
|
g->send_buff = (char*) calloc (2500, sizeof (char));
|
|
if (!g->send_buff) return -1;
|
|
g->send_len = 0;
|
|
g->send_max = 2500;
|
|
g->read_buff = (char*) calloc (4096, sizeof (char));
|
|
if (!g->read_buff) {
|
|
free (g->send_buff);
|
|
return -1;
|
|
}
|
|
g->read_len = 0;
|
|
g->sock = r_socket_new (0);
|
|
g->last_code = MSG_OK;
|
|
g->read_max = 4096;
|
|
g->connected = 0;
|
|
g->data_len = 0;
|
|
g->data = calloc (4096, sizeof (char));
|
|
if (!g->data) {
|
|
free (g->send_buff);
|
|
free (g->read_buff);
|
|
return -1;
|
|
}
|
|
g->data_max = 4096;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int gdbr_set_architecture(libgdbr_t* g, uint8_t architecture) {
|
|
if (!g) return -1;
|
|
g->architecture = architecture;
|
|
switch (architecture) {
|
|
case ARCH_X86_32:
|
|
g->registers = x86_32;
|
|
break;
|
|
case ARCH_X86_64:
|
|
g->registers = x86_64;
|
|
break;
|
|
case ARCH_ARM_32:
|
|
g->registers = arm32;
|
|
break;
|
|
case ARCH_ARM_64:
|
|
g->registers = aarch64;
|
|
break;
|
|
case ARCH_MIPS:
|
|
g->registers = mips;
|
|
break;
|
|
default:
|
|
fprintf (stderr, "Error unknown architecture set\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int gdbr_cleanup(libgdbr_t* g) {
|
|
if (!g) return -1;
|
|
free (g->data);
|
|
free (g->send_buff);
|
|
g->send_len = 0;
|
|
free (g->read_buff);
|
|
g->read_len = 0;
|
|
return 0;
|
|
}
|
|
|
|
int gdbr_connect(libgdbr_t* g, const char* host, int port) {
|
|
int ret;
|
|
const char *message = "qSupported:multiprocess+;qRelocInsn+";
|
|
char tmp[255];
|
|
if (!g || !host) return -1;
|
|
ret = snprintf (tmp, sizeof(tmp)-1, "%d", port);
|
|
if (!ret) return -1;
|
|
ret = r_socket_connect_tcp (g->sock, host, tmp, 200);
|
|
if (!ret) return -1;
|
|
g->connected = 1;
|
|
// TODO add config possibility here
|
|
ret = send_command(g, message);
|
|
if (ret < 0)
|
|
return ret;
|
|
read_packet(g);
|
|
return handle_connect(g);
|
|
}
|
|
|
|
int gdbr_disconnect(libgdbr_t* g) {
|
|
// TODO Disconnect maybe send something to gdbserver
|
|
if (!g || !r_socket_close (g->sock)) return -1;
|
|
g->connected = 0;
|
|
return 0;
|
|
}
|
|
|
|
int gdbr_read_registers(libgdbr_t* g) {
|
|
int ret = -1;
|
|
if (!g) return -1;
|
|
ret = send_command (g, CMD_READREGS);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (read_packet (g) > 0) {
|
|
parse_packet (g, 0);
|
|
return handle_g (g);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int gdbr_read_memory(libgdbr_t* g, ut64 address, ut64 len) {
|
|
char command[255] = {};
|
|
int ret;
|
|
if (!g) return -1;
|
|
ret = snprintf (command, sizeof (command),
|
|
"%s%016"PFMT64x",%"PFMT64d, CMD_READMEM, address, len);
|
|
if (ret < 0)
|
|
return ret;
|
|
ret = send_command(g, command);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (read_packet (g) > 0) {
|
|
parse_packet (g, 0);
|
|
return handle_m (g);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int gdbr_write_memory(libgdbr_t* g, ut64 address, const uint8_t* data, ut64 len) {
|
|
char command[255] = {};
|
|
int ret = 0;
|
|
int command_len;
|
|
char* tmp;
|
|
if (!g || !data) return -1;
|
|
command_len = snprintf(command, 255,
|
|
"%s%016"PFMT64x",%"PFMT64d":",
|
|
CMD_WRITEMEM, address, len);
|
|
tmp = calloc (command_len + (len * 2), sizeof(ut8));
|
|
if (!tmp)
|
|
return -1;
|
|
memcpy (tmp, command, command_len);
|
|
pack_hex ((char*)data, len, (tmp + command_len));
|
|
ret = send_command (g, tmp);
|
|
free (tmp);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (read_packet (g) > 0) {
|
|
parse_packet (g, 0);
|
|
return handle_M (g);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int gdbr_step(libgdbr_t* g, int thread_id) {
|
|
return send_vcont (g, CMD_C_STEP, thread_id);
|
|
}
|
|
|
|
|
|
int gdbr_continue(libgdbr_t* g, int thread_id) {
|
|
return send_vcont (g, CMD_C_CONT, thread_id);
|
|
}
|
|
|
|
int gdbr_send_command(libgdbr_t* g, char* command) {
|
|
int ret;
|
|
char* cmd;
|
|
if (!g || !command) return -1;
|
|
cmd = calloc ((strlen (command) * 2 + strlen (CMD_QRCMD) + 2), sizeof (char));
|
|
if (!cmd) return -1;
|
|
strcpy (cmd, CMD_QRCMD);
|
|
pack_hex (command, strlen (command), (cmd + strlen (CMD_QRCMD)));
|
|
ret = send_command (g, cmd);
|
|
free (cmd);
|
|
if (ret < 0) return ret;
|
|
|
|
if (read_packet (g) > 0) {
|
|
parse_packet (g, 1);
|
|
return handle_cmd (g);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int gdbr_write_bin_registers(libgdbr_t* g){
|
|
uint64_t buffer_size;
|
|
char* command;
|
|
if (!g) return -1;
|
|
buffer_size = g->data_len * 2 + 8;
|
|
command = calloc (buffer_size, sizeof (char));
|
|
if (!command) return -1;
|
|
snprintf (command, buffer_size, "%s", CMD_WRITEREGS);
|
|
pack_hex (g->data, g->data_len, command+1);
|
|
if (send_command (g, command) < 0) {
|
|
free (command);
|
|
return -1;
|
|
}
|
|
read_packet (g);
|
|
free (command);
|
|
handle_G (g);
|
|
return 0;
|
|
}
|
|
|
|
int gdbr_write_register(libgdbr_t* g, int index, char* value, int len) {
|
|
int ret;
|
|
char command[255] = {};
|
|
if (!g) return -1;
|
|
ret = snprintf (command, 255, "%s%d=", CMD_WRITEREG, index);
|
|
memcpy (command + ret, value, len);
|
|
pack_hex (value, len, (command + ret));
|
|
if (send_command (g, command) < 0)
|
|
return -1;
|
|
if (read_packet (g) > 0) {
|
|
parse_packet (g, 0);
|
|
handle_P (g);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int gdbr_write_reg(libgdbr_t* g, const char* name, char* value, int len) {
|
|
// static variable that keeps the information if writing
|
|
// register through packet <P> was possible
|
|
static int P = 1;
|
|
int i = 0;
|
|
if (!g) return -1;
|
|
while (g->registers[i].size > 0) {
|
|
if (strcmp (g->registers[i].name, name) == 0) {
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (g->registers[i].size == 0) {
|
|
fprintf(stderr, "Error registername <%s> not found in profile\n", name);
|
|
return -1;
|
|
}
|
|
if (P) {
|
|
gdbr_write_register (g, i, value, len);
|
|
if (g->last_code == MSG_OK) {
|
|
return 0;
|
|
}
|
|
P = 0;
|
|
}
|
|
gdbr_read_registers (g);
|
|
memcpy (g->data + g->registers[i].offset, value, len);
|
|
gdbr_write_bin_registers (g);
|
|
return 0;
|
|
}
|
|
|
|
int gdbr_write_registers(libgdbr_t* g, char* registers) {
|
|
uint64_t buffer_size;
|
|
int ret, i = 0;
|
|
unsigned int x, len;
|
|
char* command, *reg, *buff;
|
|
// read current register set
|
|
|
|
if (!g) return -1;
|
|
gdbr_read_registers (g);
|
|
len = strlen (registers);
|
|
buff = calloc (len, sizeof(char));
|
|
if (!buff)
|
|
return -1;
|
|
memcpy (buff, registers, len);
|
|
reg = strtok(buff, ",");
|
|
while ( reg != NULL ) {
|
|
char* name_end = strchr (reg, '=');
|
|
if (name_end == NULL) {
|
|
fprintf (stderr, "Malformed argument: %s\n", reg);
|
|
free (buff);
|
|
return -1;
|
|
}
|
|
*name_end = '\0'; // change '=' to '\0'
|
|
|
|
// time to find the current register
|
|
while ( g->registers[i].size > 0) {
|
|
if (strcmp(g->registers[i].name, reg) == 0) {
|
|
const uint64_t register_size = g->registers[i].size;
|
|
const uint64_t offset = g->registers[i].offset;
|
|
char* value = malloc ((register_size * 2)+1);
|
|
if (!value) {
|
|
free (buff);
|
|
return -1;
|
|
}
|
|
|
|
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;
|
|
const int val_len = strlen (name_end); // size of the rest
|
|
strcpy (value+(register_size * 2 - val_len), name_end);
|
|
|
|
for (x=0; x < register_size; x++) {
|
|
g->data[offset + register_size - x - 1] = hex2char (&value[x * 2]);
|
|
}
|
|
free(value);
|
|
}
|
|
i++;
|
|
}
|
|
reg = strtok (NULL, " ,");
|
|
}
|
|
|
|
free (buff);
|
|
|
|
buffer_size = g->data_len * 2 + 8;
|
|
command = calloc(buffer_size, sizeof(char));
|
|
if (!command)
|
|
return -1;
|
|
snprintf (command, buffer_size, "%s", CMD_WRITEREGS);
|
|
pack_hex (g->data, g->data_len, command+1);
|
|
ret = send_command (g, command);
|
|
if (ret < 0) {
|
|
free (command);
|
|
return ret;
|
|
}
|
|
read_packet (g);
|
|
free (command);
|
|
handle_G (g);
|
|
return 0;
|
|
}
|
|
|
|
int test_command(libgdbr_t* g, const char* command) {
|
|
int ret = send_command (g, command);
|
|
if (ret < 0)
|
|
return ret;
|
|
read_packet (g);
|
|
hexdump (g->read_buff, g->data_len, 0);
|
|
return 0;
|
|
}
|
|
|
|
int send_vcont(libgdbr_t* g, const char* command, int thread_id) {
|
|
char tmp[255] = {};
|
|
int ret;
|
|
if (!g) return -1;
|
|
if (thread_id < 0) {
|
|
ret = snprintf (tmp, 255, "%s;%s", CMD_C, command);
|
|
} else {
|
|
ret = snprintf (tmp, 255, "%s;%s:%x", CMD_C, command, thread_id);
|
|
}
|
|
if (ret < 0) return ret;
|
|
ret = send_command (g, tmp);
|
|
if (ret < 0) return ret;
|
|
if (read_packet (g) > 0) {
|
|
parse_packet (g, 0);
|
|
return handle_cont (g);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int set_bp(libgdbr_t* g, ut64 address, const char* conditions, enum Breakpoint type) {
|
|
char tmp[255] = {};
|
|
int ret = 0;
|
|
if (!g) return -1;
|
|
switch (type) {
|
|
case BREAKPOINT:
|
|
ret = snprintf (tmp, sizeof (tmp)-1,
|
|
"%s,%"PFMT64x",1", CMD_BP, address);
|
|
break;
|
|
case HARDWARE_BREAKPOINT:
|
|
ret = snprintf (tmp, sizeof (tmp)-1,
|
|
"%s,%"PFMT64x",1", CMD_HBP, address);
|
|
break;
|
|
case WRITE_WATCHPOINT:
|
|
break;
|
|
case READ_WATCHPOINT:
|
|
break;
|
|
case ACCESS_WATCHPOINT:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (ret < 0) return ret;
|
|
ret = send_command (g, tmp);
|
|
if (ret < 0) return ret;
|
|
|
|
if (read_packet (g) > 0) {
|
|
parse_packet (g, 0);
|
|
return handle_setbp (g);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int gdbr_set_bp(libgdbr_t* g, ut64 address, const char* conditions) {
|
|
return set_bp (g, address, conditions, BREAKPOINT);
|
|
}
|
|
|
|
int gdbr_set_hwbp(libgdbr_t* g, ut64 address, const char* conditions) {
|
|
return set_bp (g, address, conditions, HARDWARE_BREAKPOINT);
|
|
}
|
|
|
|
int gdbr_remove_bp(libgdbr_t* g, ut64 address) {
|
|
return remove_bp (g, address, BREAKPOINT);
|
|
}
|
|
|
|
int gdbr_remove_hwbp(libgdbr_t* g, ut64 address) {
|
|
return remove_bp (g, address, HARDWARE_BREAKPOINT);
|
|
}
|
|
|
|
int remove_bp(libgdbr_t* g, ut64 address, enum Breakpoint type) {
|
|
char tmp[255] = {};
|
|
int ret = 0;
|
|
if (!g) return -1;
|
|
switch (type) {
|
|
case BREAKPOINT:
|
|
ret = snprintf (tmp, sizeof (tmp)-1, "%s,%"PFMT64x",1", CMD_RBP, address);
|
|
break;
|
|
case HARDWARE_BREAKPOINT:
|
|
ret = snprintf (tmp, sizeof (tmp)-1, "%s,%"PFMT64x",1", CMD_RHBP, address);
|
|
break;
|
|
case WRITE_WATCHPOINT:
|
|
break;
|
|
case READ_WATCHPOINT:
|
|
break;
|
|
case ACCESS_WATCHPOINT:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (ret < 0) return ret;
|
|
ret = send_command (g, tmp);
|
|
if (ret < 0) return ret;
|
|
|
|
if (read_packet (g) > 0) {
|
|
parse_packet (g, 0);
|
|
return handle_removebp (g);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int send_ack(libgdbr_t* g) {
|
|
if (!g) return -1;
|
|
g->send_buff[0] = '+';
|
|
g->send_len = 1;
|
|
send_packet (g);
|
|
return 0;
|
|
}
|
|
|
|
int send_command(libgdbr_t* g, const char* command) {
|
|
uint8_t checksum;
|
|
int ret;
|
|
|
|
if (!g || !command)
|
|
return -1;
|
|
|
|
checksum = cmd_checksum (command);
|
|
ret = snprintf(g->send_buff, g->send_max,
|
|
"$%s#%.2x", command, checksum);
|
|
if (ret >= 0) {
|
|
g->send_len = ret;
|
|
ret = send_packet (g);
|
|
g->send_len = ret;
|
|
return ret;
|
|
}
|
|
return -1;
|
|
}
|
|
|