rizin/subprojects/rzqnx/src/core.c
Riccardo Schirone 6f40dfe493
Move remaining things from shlr/ to meson subprojects (#2126)
* Move binrz meson directives to binrz/ dir

* Move rizin-shell-parser to a subproject

* Move bochs to a meson subproject

* Move rzqnx to meson subproject

* Move winkd to a meson subproject

* Move rzar to a meson subproject

* Move rzw32dbg_wrap to a meson subproject

* Move ptrace-wrap to a meson subproject

* Move rzgdb to a meson subproject

* Rename w32dbg_wrap to rzw32dbg_wrap

* Update CODEOWNERS

* Remove old references to shlr

* Move shlr/heap stuff in core and remove shlr/arm

* Move spp to a meson subproject

* Remove last references to shlr

* Remove use_webui option

* Move include files directives to librz/include/meson.build

* Move librz meson directives into librz/meson.build

* Handle d/ directories inside the specific module meson.build

* Move plugins listing to specific module meson.build

* Move rzheap to its own subproject

* Fix js linter and licenses

* Use meson.override_dependency for all rz_ modules
2021-12-22 09:20:39 +08:00

830 lines
20 KiB
C

// SPDX-FileCopyrightText: 2016 defragger
// SPDX-FileCopyrightText: 2016 madprogrammer
// SPDX-FileCopyrightText: 2016 FSF Inc
// SPDX-License-Identifier: GPL-2.0-only
#include <errno.h>
#include <rz_debug.h>
#include "libqnxr.h"
#include "core.h"
#include "signal.h"
#include "sigutil.h"
#include "packet.h"
#define MAX_TRAN_TRIES 3
#define HOST_QNX_PROTOVER_MAJOR 0
#define HOST_QNX_PROTOVER_MINOR 3
ptid_t null_ptid = { 0, 0 };
void nto_send_init(libqnxr_t *g, ut32 cmd, ut32 subcmd, ut32 chan);
ptid_t nto_parse_notify(libqnxr_t *g);
int nto_send_env(libqnxr_t *g, const char *env);
int nto_send_arg(libqnxr_t *g, const char *arg);
int nto_send(libqnxr_t *g, ut32 len, int report_errors);
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 },
#if 0
{"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},
#endif
{ "", 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 }
};
int qnxr_init(libqnxr_t *g) {
if (!g)
return -1;
memset(g, 0, sizeof(libqnxr_t));
g->send_len = 0;
g->send_buff = (char *)calloc(DS_DATA_MAX_SIZE * 2, 1);
if (!g->send_buff)
return -1;
g->read_buff = (char *)calloc(DS_DATA_MAX_SIZE * 2, 1);
if (!g->read_buff) {
RZ_FREE(g->send_buff);
return -1;
}
g->registers = x86_32;
return 0;
}
int qnxr_set_architecture(libqnxr_t *g, ut8 architecture) {
if (!g)
return -1;
g->architecture = architecture;
switch (architecture) {
case ARCH_X86_32:
g->registers = x86_32;
break;
case ARCH_ARM_32:
g->registers = arm32;
break;
default:
eprintf("Error unknown architecture set\n");
}
return 0;
}
int qnxr_cleanup(libqnxr_t *g) {
if (!g)
return -1;
free(g->send_buff);
g->send_len = 0;
free(g->read_buff);
return 0;
}
int qnxr_connect(libqnxr_t *g, const char *host, int port) {
char tmp[255];
int ret;
if (!g || !host || g->connected)
return -1;
g->data_len = 0;
g->read_len = 0;
g->read_ptr = 0;
g->sock = rz_socket_new(0);
g->connected = 0;
g->mid = 0;
memmove(g->host, host, strlen(host) + 1);
g->port = port;
ret = snprintf(tmp, sizeof(tmp) - 1, "%d", port);
if (!ret)
return -1;
ret = rz_socket_connect_tcp(g->sock, host, tmp, 200);
if (!ret)
return -1;
g->connected = 1;
qnxr_send_ch_reset(g);
nto_send_init(g, DStMsg_connect, 0, SET_CHANNEL_DEBUG);
g->tran.pkt.connect.major = HOST_QNX_PROTOVER_MAJOR;
g->tran.pkt.connect.minor = HOST_QNX_PROTOVER_MINOR;
nto_send(g, sizeof(g->tran.pkt.connect), 0);
if (g->recv.pkt.hdr.cmd == DSrMsg_err) {
eprintf("%s: connection failed: %lld\n", __func__,
EXTRACT_SIGNED_INTEGER(&g->recv.pkt.err.err, 4));
return -1;
}
/* Try to query pdebug for their version of the protocol */
nto_send_init(g, DStMsg_protover, 0, SET_CHANNEL_DEBUG);
g->tran.pkt.protover.major = HOST_QNX_PROTOVER_MAJOR;
g->tran.pkt.protover.minor = HOST_QNX_PROTOVER_MINOR;
nto_send(g, sizeof(g->tran.pkt.protover), 0);
if ((g->recv.pkt.hdr.cmd == DSrMsg_err) && (EXTRACT_SIGNED_INTEGER(&g->recv.pkt.err.err, 4) == EINVAL)) {
g->target_proto_major = 0;
g->target_proto_minor = 0;
} else if (g->recv.pkt.hdr.cmd == DSrMsg_okstatus) {
g->target_proto_major = EXTRACT_SIGNED_INTEGER(&g->recv.pkt.okstatus.status, 4);
g->target_proto_minor = EXTRACT_SIGNED_INTEGER(&g->recv.pkt.okstatus.status, 4);
g->target_proto_major = (g->target_proto_major >> 8) & DSMSG_PROTOVER_MAJOR;
g->target_proto_minor = g->target_proto_minor & DSMSG_PROTOVER_MINOR;
} else {
eprintf("Connection failed (Protocol Version Query): %lld\n",
EXTRACT_SIGNED_INTEGER(&g->recv.pkt.err.err, 4));
return -1;
}
return 0;
}
int qnxr_disconnect(libqnxr_t *g) {
if (!g)
return -1;
if (g->connected) {
nto_send_init(g, DStMsg_disconnect, 0, SET_CHANNEL_DEBUG);
nto_send(g, sizeof(g->tran.pkt.disconnect), 0);
g->connected = 0;
g->inferior_ptid = null_ptid;
if (!rz_socket_close(g->sock))
return -1;
}
return 0;
}
ptid_t qnxr_attach(libqnxr_t *g, pid_t pid) {
if (g->inferior_ptid.pid != pid) {
qnxr_disconnect(g);
rz_sys_sleep(1);
qnxr_connect(g, g->host, g->port);
}
nto_send_init(g, DStMsg_attach, 0, SET_CHANNEL_DEBUG);
g->tran.pkt.attach.pid = pid;
g->tran.pkt.attach.pid = EXTRACT_SIGNED_INTEGER(&g->tran.pkt.attach.pid, 4);
nto_send(g, sizeof(g->tran.pkt.attach), 0);
if (g->recv.pkt.hdr.cmd != DSrMsg_okdata) {
eprintf("%s: failed to attach to %d\n", __func__, pid);
return null_ptid;
}
g->inferior_ptid = ptid_build(
EXTRACT_SIGNED_INTEGER(&g->recv.pkt.notify.pid, 4),
EXTRACT_SIGNED_INTEGER(&g->recv.pkt.notify.tid, 4));
return g->inferior_ptid;
}
ptid_t qnxr_run(libqnxr_t *g, const char *file, char **args, char **env) {
ut32 argc = 0;
ut32 envc = 0;
char **argv, *p;
int errors = 0;
if (!g)
return null_ptid;
nto_send_init(g, DStMsg_env, DSMSG_ENV_CLEARENV, SET_CHANNEL_DEBUG);
nto_send(g, sizeof(DStMsg_env_t), 1);
for (envc = 0; *env; env++, envc++)
errors += !nto_send_env(g, *env);
if (errors) {
eprintf("%s: error(s) occurred while sending environment\n", __func__);
}
nto_send_init(g, DStMsg_env, DSMSG_ENV_CLEARARGV, SET_CHANNEL_DEBUG);
nto_send(g, sizeof(DStMsg_env_t), 1);
if (file != NULL) {
errors = !nto_send_arg(g, file);
if (!errors)
errors = !nto_send_arg(g, file);
if (errors) {
eprintf("%s: failed to send executable file name\n", __func__);
return null_ptid;
}
errors = 0;
for (argv = args; *argv && **argv; argv++, argc++)
errors |= !nto_send_arg(g, *argv);
if (errors) {
eprintf("%s: error(s) occurred while sending args\n", __func__);
}
}
if (errors) {
return null_ptid;
}
nto_send_init(g, DStMsg_load, DSMSG_LOAD_DEBUG, SET_CHANNEL_DEBUG);
p = g->tran.pkt.load.cmdline;
g->tran.pkt.load.envc = 0;
g->tran.pkt.load.argc = 0;
if (file) {
strncpy(p, file, sizeof(g->tran.pkt.load.cmdline) - 8);
p += strlen(p);
}
*p++ = '\0';
*p++ = '\0'; // stdin
*p++ = '\0'; // stdout
*p++ = '\0'; // stderr
nto_send(g, offsetof(DStMsg_load_t, cmdline) + p - g->tran.pkt.load.cmdline + 1, 1);
if (g->recv.pkt.hdr.cmd == DSrMsg_okdata) {
ptid_t ptid = nto_parse_notify(g);
eprintf("%s: inferior pid: %d\n", __func__, ptid.pid);
g->inferior_ptid = ptid;
return ptid;
}
return null_ptid;
}
int qnxr_read_registers(libqnxr_t *g) {
int i = 0;
int len, rlen, regset;
int n = 0;
ut32 off;
char buf[DS_DATA_MAX_SIZE];
if (!g)
return -1;
while (g->registers[i].size > 0) {
regset = i386nto_regset_id(i);
len = i386nto_register_area(i, regset, &off);
if (len < 1) {
eprintf("%s: unknown register %d\n", __func__, i);
len = g->registers[i].size;
}
nto_send_init(g, DStMsg_regrd, regset, SET_CHANNEL_DEBUG);
g->tran.pkt.regrd.offset = EXTRACT_SIGNED_INTEGER(&off, 2);
g->tran.pkt.regrd.size = EXTRACT_SIGNED_INTEGER(&len, 2);
rlen = nto_send(g, sizeof(g->tran.pkt.regrd), 1);
if (rlen > 0) {
if (g->recv.pkt.hdr.cmd == DSrMsg_okdata) {
memcpy(buf + g->registers[i].offset,
g->recv.pkt.okdata.data, len);
n += len;
} else {
memset(buf + g->registers[i].offset,
0, len);
}
} else {
eprintf("%s: couldn't read register %d\n", __func__, i);
return -1;
}
i++;
}
memcpy(g->recv.data, buf, n);
return n;
}
int qnxr_read_memory(libqnxr_t *g, ut64 address, ut8 *data, ut64 len) {
int rcv_len, tot_len, ask_len;
ut64 addr;
if (!g || !data)
return -1;
tot_len = ask_len = 0;
do {
nto_send_init(g, DStMsg_memrd, 0, SET_CHANNEL_DEBUG);
addr = address + tot_len;
g->tran.pkt.memrd.addr = EXTRACT_UNSIGNED_INTEGER(&addr, 8);
ask_len = ((len - tot_len) > DS_DATA_MAX_SIZE) ? DS_DATA_MAX_SIZE : (len - tot_len);
g->tran.pkt.memrd.size = EXTRACT_SIGNED_INTEGER(&ask_len, 2);
rcv_len = nto_send(g, sizeof(g->tran.pkt.memrd), 0) -
sizeof(g->recv.pkt.hdr);
if (rcv_len <= 0)
break;
if (g->recv.pkt.hdr.cmd == DSrMsg_okdata) {
memcpy(data + tot_len, g->recv.pkt.okdata.data, rcv_len);
tot_len += rcv_len;
} else
break;
} while (tot_len != len);
return tot_len;
}
int qnxr_write_memory(libqnxr_t *g, ut64 address, const ut8 *data, ut64 len) {
ut64 addr;
if (!g || !data)
return -1;
nto_send_init(g, DStMsg_memwr, 0, SET_CHANNEL_DEBUG);
addr = address;
g->tran.pkt.memwr.addr = EXTRACT_UNSIGNED_INTEGER(&addr, 8);
memcpy(g->tran.pkt.memwr.data, data, len);
nto_send(g, offsetof(DStMsg_memwr_t, data) + len, 0);
switch (g->recv.pkt.hdr.cmd) {
case DSrMsg_ok:
return len;
case DSrMsg_okstatus:
return EXTRACT_SIGNED_INTEGER(&g->recv.pkt.okstatus.status, 4);
}
return 0;
}
void qnxr_pidlist(libqnxr_t *g, void *ctx, pidlist_cb_t *cb) {
struct dspidlist *pidlist = (void *)g->recv.pkt.okdata.data;
pid_t pid, start_tid;
char subcmd;
if (!g)
return;
start_tid = 1;
pid = 1;
subcmd = DSMSG_PIDLIST_BEGIN;
while (1) {
nto_send_init(g, DStMsg_pidlist, subcmd, SET_CHANNEL_DEBUG);
g->tran.pkt.pidlist.pid = EXTRACT_SIGNED_INTEGER(&pid, 4);
g->tran.pkt.pidlist.tid = EXTRACT_SIGNED_INTEGER(&start_tid, 4);
nto_send(g, sizeof(g->tran.pkt.pidlist), 0);
if (g->recv.pkt.hdr.cmd == DSrMsg_err || g->recv.pkt.hdr.cmd != DSrMsg_okdata)
return;
pid = EXTRACT_SIGNED_INTEGER(&pidlist->pid, 4);
if (cb != NULL)
cb(ctx, pid, pidlist->name);
subcmd = DSMSG_PIDLIST_NEXT;
}
}
int qnxr_select(libqnxr_t *g, pid_t pid, int tid) {
if (!g)
return 0;
/* TODO */
tid = 1;
nto_send_init(g, DStMsg_select, DSMSG_SELECT_SET, SET_CHANNEL_DEBUG);
g->tran.pkt.select.pid = pid;
g->tran.pkt.select.pid = EXTRACT_SIGNED_INTEGER(&g->tran.pkt.select.pid, 4);
g->tran.pkt.select.tid = EXTRACT_SIGNED_INTEGER(&tid, 4);
nto_send(g, sizeof(g->tran.pkt.select), 1);
if (g->recv.pkt.hdr.cmd == DSrMsg_err) {
eprintf("%s: failed to select %d\n", __func__, pid);
return 0;
}
return 1;
}
int qnxr_step(libqnxr_t *g, int thread_id) {
return qnxr_send_vcont(g, 1, thread_id);
}
int qnxr_continue(libqnxr_t *g, int thread_id) {
return qnxr_send_vcont(g, 0, thread_id);
}
int qnxr_write_register(libqnxr_t *g, int index, char *value, int len) {
int tdep_len, regset;
ut32 off;
if (!g)
return -1;
regset = i386nto_regset_id(index);
tdep_len = i386nto_register_area(index, regset, &off);
if (len < 0 || tdep_len != len) {
eprintf("%s: invalid length\n", __func__);
return -1;
}
nto_send_init(g, DStMsg_regwr, regset, SET_CHANNEL_DEBUG);
g->tran.pkt.regwr.offset = EXTRACT_SIGNED_INTEGER(&off, 2);
memcpy(g->tran.pkt.regwr.data, value, len);
nto_send(g, offsetof(DStMsg_regwr_t, data) + len, 1);
return 0;
}
int qnxr_write_reg(libqnxr_t *g, const char *name, char *value, int len) {
int i = 0;
if (!g)
return -1;
while (g->registers[i].size > 0) {
if (!strcmp(g->registers[i].name, name)) {
break;
}
i++;
}
if (g->registers[i].size == 0) {
eprintf("Error registername <%s> not found in profile\n", name);
return -1;
}
qnxr_write_register(g, i, value, len);
return 0;
}
int qnxr_send_vcont(libqnxr_t *g, int step, int thread_id) {
if (!g)
return -1;
nto_send_init(g, DStMsg_run, step ? DSMSG_RUN_COUNT : DSMSG_RUN,
SET_CHANNEL_DEBUG);
g->tran.pkt.run.step.count = 1;
nto_send(g, sizeof(g->tran.pkt.run), 1);
return 0;
}
int qnxr_stop(libqnxr_t *g) {
if (!g)
return 0;
eprintf("%s: waiting for stop\n", __func__);
g->waiting_for_stop = 1;
nto_send_init(g, DStMsg_stop, DSMSG_STOP_PIDS, SET_CHANNEL_DEBUG);
g->send_len = sizeof(g->tran.pkt.stop);
qnxr_send_packet(g);
return 1;
}
ptid_t qnxr_wait(libqnxr_t *g, pid_t pid) {
if (!g || pid < 0) {
return null_ptid;
}
ptid_t returned_ptid = g->inferior_ptid;
if (g->inferior_ptid.pid != pid) {
return null_ptid;
}
if (g->recv.pkt.hdr.cmd != DShMsg_notify) {
int rlen;
char waiting_for_notify = 1;
eprintf("%s: waiting for inferior\n", __func__);
while (1) {
rlen = qnxr_read_packet(g);
if (rlen == -1) {
if (g->waiting_for_stop) {
eprintf("%s: read eror while waiting for stop\n",
__func__);
continue;
} else {
eprintf("%s: read packet error or NAK\n", __func__);
return null_ptid;
}
}
if (g->channelrd == SET_CHANNEL_TEXT) {
// TODO nto_incoming_text
} else {
g->recv.pkt.hdr.cmd &= ~DSHDR_MSG_BIG_ENDIAN;
if (g->waiting_for_stop && g->recv.pkt.hdr.cmd == DSrMsg_ok) {
g->waiting_for_stop = 0;
eprintf("%s: got stop response\n", __func__);
if (!waiting_for_notify)
break;
} else if (g->recv.pkt.hdr.cmd == DShMsg_notify) {
// acknowledge the notify
g->tran.pkt.hdr.cmd = DSrMsg_ok;
g->tran.pkt.hdr.channel = SET_CHANNEL_DEBUG;
g->tran.pkt.hdr.mid = g->recv.pkt.hdr.mid;
qnxr_send_ch_debug(g);
g->send_len = sizeof(g->tran.pkt.ok);
qnxr_send_packet(g);
returned_ptid = nto_parse_notify(g);
break;
}
}
}
}
/* to make us wait the next time */
g->recv.pkt.hdr.cmd = DSrMsg_ok;
return returned_ptid;
}
int qnxr_set_bp(libqnxr_t *g, ut64 address, const char *conditions) {
return _qnxr_set_bp(g, address, conditions, BREAKPOINT);
}
int qnxr_set_hwbp(libqnxr_t *g, ut64 address, const char *conditions) {
return _qnxr_set_bp(g, address, conditions, HARDWARE_BREAKPOINT);
}
int qnxr_remove_bp(libqnxr_t *g, ut64 address) {
return _qnxr_remove_bp(g, address, BREAKPOINT);
}
int qnxr_remove_hwbp(libqnxr_t *g, ut64 address) {
return _qnxr_remove_bp(g, address, HARDWARE_BREAKPOINT);
}
int _qnxr_set_bp(libqnxr_t *g, ut64 address, const char *conditions, enum Breakpoint type) {
if (!g)
return -1;
nto_send_init(g, DStMsg_brk, DSMSG_BRK_EXEC, SET_CHANNEL_DEBUG);
g->tran.pkt.brk.addr = EXTRACT_UNSIGNED_INTEGER(&address, 4);
g->tran.pkt.brk.size = 0;
nto_send(g, sizeof(g->tran.pkt.brk), 0);
if (g->recv.pkt.hdr.cmd == DSrMsg_err)
return -1;
return 0;
}
int _qnxr_remove_bp(libqnxr_t *g, ut64 address, enum Breakpoint type) {
if (!g)
return -1;
nto_send_init(g, DStMsg_brk, DSMSG_BRK_EXEC, SET_CHANNEL_DEBUG);
g->tran.pkt.brk.addr = EXTRACT_UNSIGNED_INTEGER(&address, 4);
g->tran.pkt.brk.size = -1;
nto_send(g, sizeof(g->tran.pkt.brk), 0);
if (g->recv.pkt.hdr.cmd == DSrMsg_err)
return -1;
return 0;
}
void nto_send_init(libqnxr_t *g, ut32 cmd, ut32 subcmd, ut32 chan) {
g->tran.pkt.hdr.cmd = cmd;
g->tran.pkt.hdr.subcmd = subcmd;
g->tran.pkt.hdr.mid = ((chan == SET_CHANNEL_DEBUG) ? g->mid++ : 0);
g->tran.pkt.hdr.channel = chan;
}
ptid_t nto_parse_notify(libqnxr_t *g) {
pid_t pid, tid;
pid = EXTRACT_SIGNED_INTEGER(&g->recv.pkt.notify.pid, 4);
tid = EXTRACT_SIGNED_INTEGER(&g->recv.pkt.notify.tid, 4);
if (tid == 0)
tid = 1;
eprintf("%s: parse notify %d\n", __func__, g->recv.pkt.hdr.subcmd);
switch (g->recv.pkt.hdr.subcmd) {
case DSMSG_NOTIFY_PIDUNLOAD:
g->notify_type = RZ_DEBUG_REASON_DEAD;
break;
case DSMSG_NOTIFY_BRK:
g->stop_flags = EXTRACT_UNSIGNED_INTEGER(&g->recv.pkt.notify.un.brk.flags, 4);
g->stop_pc = EXTRACT_UNSIGNED_INTEGER(&g->recv.pkt.notify.un.brk.ip, 4);
g->notify_type = RZ_DEBUG_REASON_BREAKPOINT;
break;
case DSMSG_NOTIFY_STEP:
g->notify_type = RZ_DEBUG_REASON_STEP;
break;
case DSMSG_NOTIFY_SIGEV:
g->notify_type = RZ_DEBUG_REASON_SIGNAL;
g->signal = host_signal_from_nto(EXTRACT_SIGNED_INTEGER(&g->recv.pkt.notify.un.sigev.signo, 4));
break;
case DSMSG_NOTIFY_PIDLOAD:
eprintf("%s: notify type DSMSG_NOTIFY_PIDLOAD\n", __func__);
g->notify_type = RZ_DEBUG_REASON_UNKNOWN;
break;
case DSMSG_NOTIFY_DLLLOAD:
case DSMSG_NOTIFY_TIDLOAD:
case DSMSG_NOTIFY_TIDUNLOAD:
case DSMSG_NOTIFY_DLLUNLOAD:
eprintf("%s: notify type DSMSG_NOTIFY_DLLTID\n", __func__);
g->notify_type = RZ_DEBUG_REASON_UNKNOWN;
break;
case DSMSG_NOTIFY_STOPPED:
g->notify_type = RZ_DEBUG_REASON_SWI;
break;
default:
eprintf("%s: Unexpected notify type %d\n", __func__,
g->recv.pkt.hdr.subcmd);
g->notify_type = RZ_DEBUG_REASON_UNKNOWN;
}
return ptid_build(pid, tid);
}
int nto_send_env(libqnxr_t *g, const char *env) {
int len; /* Length including zero terminating char. */
int totlen = 0;
if (!g)
return 0;
len = strlen(env) + 1;
if (g->target_proto_minor >= 2) {
while (len > DS_DATA_MAX_SIZE) {
nto_send_init(g, DStMsg_env, DSMSG_ENV_SETENV_MORE,
SET_CHANNEL_DEBUG);
memcpy(g->tran.pkt.env.data, env + totlen,
DS_DATA_MAX_SIZE);
if (!nto_send(g, offsetof(DStMsg_env_t, data) + DS_DATA_MAX_SIZE,
1)) {
/* An error occurred. */
return 0;
}
len -= DS_DATA_MAX_SIZE;
totlen += DS_DATA_MAX_SIZE;
}
} else if (len > DS_DATA_MAX_SIZE) {
/* Not supported by this protocol version. */
eprintf("Protovers < 0.2 do not handle env vars longer than %d\n",
DS_DATA_MAX_SIZE - 1);
return 0;
}
nto_send_init(g, DStMsg_env, DSMSG_ENV_SETENV, SET_CHANNEL_DEBUG);
memcpy(g->tran.pkt.env.data, env + totlen, len);
return nto_send(g, offsetof(DStMsg_env_t, data) + len, 1);
}
int nto_send_arg(libqnxr_t *g, const char *arg) {
int len;
if (!g)
return 0;
len = strlen(arg) + 1;
if (len > DS_DATA_MAX_SIZE - 4) {
eprintf("Argument too long: %.40s...\n", arg);
return 0;
}
nto_send_init(g, DStMsg_env, DSMSG_ENV_ADDARG, SET_CHANNEL_DEBUG);
memcpy(g->tran.pkt.env.data, arg, len);
return nto_send(g, offsetof(DStMsg_env_t, data) + len, 1);
}
int nto_send(libqnxr_t *g, ut32 len, st32 report_errors) {
int rlen;
ut8 tries = 0;
if (!g || g->connected == 0) {
return -1;
}
g->send_len = len;
for (tries = 0;; tries++) {
if (tries >= MAX_TRAN_TRIES) {
eprintf("%s: Remote exhausted %d retries.\n", __func__, tries);
return -1;
}
qnxr_send_packet(g);
for (;;) {
rlen = qnxr_read_packet(g);
if ((g->channelrd != SET_CHANNEL_TEXT) || (rlen == -1))
break;
// nto_incoming_text (rlen); TODO
}
if (rlen == -1) {
eprintf("%s: NAK received - resending\n", __func__);
continue;
}
if ((rlen >= 0) && (g->recv.pkt.hdr.mid == g->tran.pkt.hdr.mid))
break;
eprintf("%s: mid mismatch: %d/%d\n", __func__, g->recv.pkt.hdr.mid,
g->tran.pkt.hdr.mid);
}
switch (g->channelrd) {
case SET_CHANNEL_DEBUG:
g->recv.pkt.hdr.cmd &= ~DSHDR_MSG_BIG_ENDIAN;
if (g->recv.pkt.hdr.cmd == DSrMsg_err) {
if (report_errors) {
int nerrno = errnoconvert(
EXTRACT_SIGNED_INTEGER(&g->recv.pkt.err.err, 4));
switch (g->recv.pkt.hdr.subcmd) {
case PDEBUG_ENOERR:
eprintf("remote: error packet with errno %d\n", nerrno);
break;
case PDEBUG_ENOPTY:
eprintf("remote: no ptys available\n");
break;
case PDEBUG_ETHREAD:
eprintf("remote: thread start error\n");
break;
case PDEBUG_ECONINV:
eprintf("remote: invalid console number\n");
break;
case PDEBUG_ESPAWN:
eprintf("Remote (spawn error)\n");
break;
case PDEBUG_EPROCFS:
eprintf("Remote (procfs [/proc] error)\n");
break;
case PDEBUG_EPROCSTOP:
eprintf("Remote (devctl PROC_STOP error)\n");
break;
case PDEBUG_EQPSINFO:
eprintf("Remote (psinfo error)\n");
break;
case PDEBUG_EQMEMMODEL:
eprintf("Remote (invalid memory model [not flat])\n");
break;
case PDEBUG_EQPROXY:
eprintf("Remote (proxy error)\n");
break;
case PDEBUG_EQDBG:
eprintf("Remote (__nto_debug_* error)\n");
break;
default:
eprintf("Remote error\n");
}
}
}
break;
case SET_CHANNEL_TEXT:
case SET_CHANNEL_RESET:
break;
}
return rlen;
}