#include #include #include #include #include #include #include "kdp-udp.h" #include "defs.h" #define assert CHECK_FATAL static inline unsigned short read16u (const unsigned char *s, int bigendian) { if (bigendian) { return (s[1] << 8) + s[0]; } else { return (s[0] << 8) + s[1]; } } static inline unsigned long read32u (const unsigned char *s, int bigendian) { if (bigendian) { return (s[3] << 24) + (s[2] << 16) + (s[1] << 8) + s[0]; } else { return (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3]; } } static inline void write16u (unsigned char *s, unsigned short i, int bigendian) { if (bigendian) { s[1] = (i >> 8) & 0xff; s[0] = (i >> 0) & 0xff; } else { s[0] = (i >> 8) & 0xff; s[1] = (i >> 0) & 0xff; } } static inline void write32u (unsigned char *s, unsigned long i, int bigendian) { if (bigendian) { s[3] = (i >> 24) & 0xff; s[2] = (i >> 16) & 0xff; s[1] = (i >> 8) & 0xff; s[0] = (i >> 0) & 0xff; } else { s[0] = (i >> 24) & 0xff; s[1] = (i >> 16) & 0xff; s[2] = (i >> 8) & 0xff; s[3] = (i >> 0) & 0xff; } } const char *kdp_req_string (kdp_req_t req) { switch (req) { case KDP_CONNECT: return "CONNECT"; case KDP_DISCONNECT: return "DISCONNECT"; case KDP_HOSTINFO: return "HOSTINFO"; case KDP_REGIONS: return "REGIONS"; case KDP_MAXBYTES: return "MAXBYTES"; case KDP_READMEM: return "READMEM"; case KDP_WRITEMEM: return "WRITEMEM"; case KDP_READREGS: return "READREGS"; case KDP_WRITEREGS: return "WRITEREGS"; case KDP_LOAD: return "LOAD"; case KDP_IMAGEPATH: return "IMAGEPATH"; case KDP_SUSPEND: return "SUSPEND"; case KDP_RESUMECPUS: return "RESUMECPUS"; case KDP_EXCEPTION: return "EXCEPTION"; case KDP_TERMINATION: return "TERMINATION"; default: return "[UNKNOWN]"; } } const char *kdp_error_string (kdp_error_t error) { switch (error) { case KDP_PROTERR_SUCCESS: return "no error detected"; case KDP_PROTERR_ALREADY_CONNECTED: return "target already connected"; case KDP_PROTERR_BAD_NBYTES: return "invalid memory access"; case KDP_PROTERR_BADFLAVOR: return "bad thread state flavor"; default: return "unknown error"; } } const char *kdp_return_string (kdp_return_t error) { switch (error) { case RR_SUCCESS: return "no error detected"; case RR_ALREADY_CONNECTED: return "target already connected"; case RR_BAD_NBYTES: return "illegal address or byte count"; case RR_BADFLAVOR: return "bad thread state flavor"; case RR_SEND_TIMEOUT: return "send timeout exceeded"; case RR_RECV_TIMEOUT: return "receive timeout exceeded"; case RR_IP_ERROR: return "RR_IP_ERROR"; case RR_BAD_ACK: return "RR_BAD_ACK"; case RR_BYTE_COUNT: return "RR_BYTE_COUNT"; case RR_BAD_SEQ: return "RR_BAD_SEQ"; case RR_RESOURCE: return "RR_RESOURCE"; case RR_LOOKUP: return "RR_LOOKUP"; case RR_INTERNAL: return "RR_INTERNAL"; case RR_CONNECT: return "RR_CONNECT"; case RR_INVALID_ADDRESS: return "RR_INVALID_ADDRESS"; case RR_EXCEPTION: return "RR_EXCEPTION"; case RR_RECV_INTR: return "RR_RECV_INTR"; default: return "[UNKNOWN]"; } } void kdp_log_data (kdp_log_function *f, kdp_log_level l, const unsigned char *data, unsigned int nbytes) { unsigned int i; for (i = 0; i < (nbytes / 4); i++) { const unsigned char *s = data + (i * 4); if (i == 0) { f (l, " %8s:", "data"); } f (l, " 0x%02x%02x%02x%02x", s[0], s[1], s[2], s[3]); if ((i % 6) == 5) { f (l, "\n "); } } if (i == 0) { f (l, " %8s:", "data"); } for (i = i * 4; i < nbytes; i++) { f (l, " 0x%02x", data[i]); } f (l, "\n"); } void kdp_log_packet (kdp_log_function *f, kdp_log_level l, const kdp_pkt_t *p) { const kdp_hdr_t *h = &p->hdr; unsigned int i; f (l, "{\n" " %8s: %s\n" " %8s: %d\n" " %8s: %d\n" " %8s: %d\n", "request", kdp_req_string (h->request), "is_reply", h->is_reply, "seq", h->seq, "key", h->key); if (h->is_reply) { switch (h->request) { case KDP_CONNECT: f (l, " %8s: \"%s\" (%d)\n", "error", kdp_error_string (p->connect_reply.error), p->connect_reply.error); break; case KDP_DISCONNECT: break; case KDP_HOSTINFO: f (l, " %8s: %d\n" " %8s: %d\n" " %8s: %d\n", "cpu_mask", p->hostinfo_reply.cpu_mask, "type", p->hostinfo_reply.cpu_type, "subtype", p->hostinfo_reply.cpu_subtype); break; case KDP_REGIONS: f (l, " %8s: %d\n", "nregions", p->regions_reply.nregions); for (i = 0; i < p->regions_reply.nregions; i++) { f (l, " r[%d].addr: %d\n" " r[%d].nbytes: %d\n" " r[%d].prot: %d\n", i, p->regions_reply.regions[i].address, i, p->regions_reply.regions[i].nbytes, i, p->regions_reply.regions[i].protection); } break; case KDP_MAXBYTES: f (l, " %8s: %d\n", "maxbytes", p->maxbytes_reply.max_bytes); break; case KDP_READMEM: f (l, " %8s: \"%s\" (%d)\n" " %8s: %d\n", "error", kdp_error_string (p->readmem_reply.error), p->readmem_reply.error, "nbytes", p->readmem_reply.nbytes); kdp_log_data (f, l, p->readmem_reply.data, p->readmem_reply.nbytes); break; case KDP_WRITEMEM: f (l, " %8s: \"%s\" (%d)\n", "error", kdp_error_string (p->writemem_reply.error), p->writemem_reply.error); break; case KDP_READREGS: f (l, " %8s: \"%s\" (%d)\n" " %8s: %d\n", "error", kdp_error_string (p->readregs_reply.error), p->readregs_reply.error, "nbytes", p->readregs_reply.nbytes); kdp_log_data (f, l, p->readregs_reply.data, p->readregs_reply.nbytes); break; case KDP_WRITEREGS: f (l, " %8s: \"%s\" (%d)\n", "error", kdp_error_string (p->writeregs_reply.error), p->writeregs_reply.error); break; case KDP_LOAD: f (l, " %8s: \"%s\" (%d)\n", "error", kdp_error_string (p->load_reply.error), p->load_reply.error); break; case KDP_IMAGEPATH: f (l, " %8s: \"%s\"\n", "path", p->imagepath_reply.path); break; case KDP_SUSPEND: case KDP_RESUMECPUS: break; case KDP_EXCEPTION: break; case KDP_TERMINATION: break; } } else { switch (h->request) { case KDP_CONNECT: f (l, " %8s: %d\n" " %8s: %d\n" " %8s: \"%s\"\n", "req_port", p->connect_req.req_reply_port, "exc_port", p->connect_req.exc_note_port, "greeting", p->connect_req.greeting); break; case KDP_DISCONNECT: break; case KDP_HOSTINFO: break; case KDP_REGIONS: break; case KDP_MAXBYTES: break; case KDP_READMEM: f (l, " %8s: 0x%lx\n" " %8s: %d\n", "addr", (unsigned long) p->readmem_req.address, "nbytes", (unsigned long) p->readmem_req.nbytes); break; case KDP_WRITEMEM: f (l, " %8s: 0x%lx\n" " %8s: %d\n", "addr", (unsigned long) p->writemem_req.address, "nbytes", (unsigned long) p->writemem_req.nbytes); kdp_log_data (f, l, p->writemem_req.data, p->writemem_req.nbytes); break; case KDP_READREGS: f (l, " %8s: 0x%lx\n" " %8s: 0x%lx\n", "cpu", (unsigned long) p->readregs_req.cpu, "flavor", (unsigned long) p->readregs_req.flavor); break; case KDP_WRITEREGS: f (l, " %8s: 0x%lx\n" " %8s: 0x%lx\n" " %8s: 0x%lx\n", "cpu", (unsigned long) p->writeregs_req.cpu, "flavor", (unsigned long) p->writeregs_req.flavor, "nbytes", (unsigned long) p->writeregs_req.nbytes); kdp_log_data (f, l, p->writeregs_req.data, p->writeregs_req.nbytes); break; case KDP_LOAD: f (l, " %8s: \"%s\"\n", "file", p->load_req.file_args); break; case KDP_IMAGEPATH: break; case KDP_SUSPEND: break; case KDP_RESUMECPUS: f (l, " %8s: 0x%lx\n", "mask", p->resumecpus_req.cpu_mask); break; case KDP_EXCEPTION: break; case KDP_TERMINATION: break; } } f (l, "}\n"); } kdp_return_t kdp_marshal (kdp_connection *c, kdp_pkt_t *p, unsigned char *s, size_t maxlen, size_t *plen) { #define CHECK_LEN_MAX(len, maxlen) \ if (len > maxlen) { \ c->logger (KDP_LOG_ERROR, \ "kdp_marshal: length required for packet (%lu) is greater than length provided (%lu)\n", \ (unsigned long) len, (unsigned long) maxlen); \ return RR_RESOURCE; \ } size_t len = 0; *plen = 0; CHECK_FATAL (c->logger != NULL); if (maxlen < 32) { c->logger (KDP_LOG_ERROR, "kdp_marshal: maximum length must be at least 32\n"); return RR_RESOURCE; } if (p->hdr.is_reply) { switch (p->hdr.request) { case KDP_CONNECT: len = 12; write32u (s + 8, p->connect_reply.error, c->bigendian); break; case KDP_DISCONNECT: len = 8; break; case KDP_HOSTINFO: len = 20; write32u (s + 8, p->hostinfo_reply.cpu_mask, c->bigendian); write32u (s + 12, p->hostinfo_reply.cpu_type, c->bigendian); write32u (s + 16, p->hostinfo_reply.cpu_subtype, c->bigendian); break; case KDP_REGIONS: { const unsigned int REGION_SIZE = 12; unsigned int i = 0; len = 12 + (p->regions_reply.nregions * REGION_SIZE); CHECK_LEN_MAX (len, maxlen); for (i = 0; i < p->regions_reply.nregions; i++) { unsigned int offset = 12 + (i * REGION_SIZE); write32u (s + offset, p->regions_reply.regions[i].address, c->bigendian); write32u (s + offset + 4, p->regions_reply.regions[i].nbytes, c->bigendian); write32u (s + offset + 8, p->regions_reply.regions[i].protection, c->bigendian); } break; } case KDP_MAXBYTES: len = 12; write32u (s + 8, p->maxbytes_reply.max_bytes, c->bigendian); break; case KDP_READMEM: len = 12 + p->readmem_reply.nbytes; CHECK_LEN_MAX (len, maxlen); memcpy (s + 12, p->readmem_reply.data, len - 12); break; case KDP_WRITEMEM: len = 12; write32u (s + 8, p->writemem_reply.error, c->bigendian); break; case KDP_READREGS: { const unsigned int KDP_REGISTER_SIZE = 4; unsigned int i; unsigned int reglen = p->readregs_reply.nbytes; len = reglen + 12; CHECK_LEN_MAX (len, maxlen); if ((reglen % KDP_REGISTER_SIZE) != 0) { return RR_IP_ERROR; } write32u (s + 8, p->readregs_reply.error, c->bigendian); for (i = 0; i < (reglen / KDP_REGISTER_SIZE); i++) { write32u (s + 12 + (i * KDP_REGISTER_SIZE), ((unsigned long *) p->readregs_reply.data)[i], c->bigendian); } break; } case KDP_WRITEREGS: len = 12; write32u (s + 8, p->writeregs_reply.error, c->bigendian); break; case KDP_LOAD: len = 12; write32u (s + 8, p->load_reply.error, c->bigendian); break; case KDP_IMAGEPATH: len = 8 + strlen (p->imagepath_reply.path) + 1; CHECK_LEN_MAX (len, maxlen); memcpy (s + 8, p->imagepath_reply.path, len - 8); break; case KDP_SUSPEND: case KDP_RESUMECPUS: case KDP_EXCEPTION: case KDP_TERMINATION: len = 8; break; default: c->logger (KDP_LOG_ERROR, "kdp_marshal: unknown packet type for reply 0x%x\n", p->hdr.request); return RR_IP_ERROR; } } else { switch (p->hdr.request) { case KDP_CONNECT: len = 12 + strlen (p->connect_req.greeting) + 1; CHECK_LEN_MAX (len, maxlen); /* port numbers are always sent little-endian */ write16u (s + 8, p->connect_req.req_reply_port, 0); write16u (s + 10, p->connect_req.exc_note_port, 0); memcpy (s + 12, p->connect_req.greeting, len - 12); break; case KDP_DISCONNECT: case KDP_HOSTINFO: case KDP_REGIONS: case KDP_MAXBYTES: len = 8; break; case KDP_READMEM: len = 16; write32u (s + 8, p->readmem_req.address, c->bigendian); write32u (s + 12, p->readmem_req.nbytes, c->bigendian); break; case KDP_WRITEMEM: len = 16 + p->writemem_req.nbytes; CHECK_LEN_MAX (len, maxlen); write32u (s + 8, p->writemem_req.address, c->bigendian); write32u (s + 12, p->writemem_req.nbytes, c->bigendian); memcpy (s + 16, p->writemem_req.data, p->writemem_req.nbytes); break; case KDP_READREGS: len = 16; write32u (s + 8, p->readregs_req.cpu, c->bigendian); write32u (s + 12, p->readregs_req.flavor, c->bigendian); break; case KDP_WRITEREGS: { const unsigned int KDP_REGISTER_SIZE = 4; unsigned int i; unsigned int reglen = p->writeregs_req.nbytes; if ((reglen % KDP_REGISTER_SIZE) != 0) { c->logger (KDP_LOG_ERROR, "kdp_marshal: length of register data (%u bytes) " "is not a multiple of register size (%u bytes)\n", p->writeregs_req.nbytes, KDP_REGISTER_SIZE); return RR_IP_ERROR; } len = reglen + 16; CHECK_LEN_MAX (len, maxlen); write32u (s + 8, p->writeregs_req.cpu, c->bigendian); write32u (s + 12, p->writeregs_req.flavor, c->bigendian); for (i = 0; i < (reglen / KDP_REGISTER_SIZE); i++) { write32u (s + 16 + (i * KDP_REGISTER_SIZE), ((unsigned long *) p->writeregs_req.data)[i], c->bigendian); } break; } case KDP_LOAD: len = 8 + strlen (p->load_req.file_args) + 1; CHECK_LEN_MAX (len, maxlen); memcpy (s + 8, p->connect_req.greeting, len - 8); break; case KDP_IMAGEPATH: case KDP_SUSPEND: len = 8; break; case KDP_RESUMECPUS: len = 12; write32u (s + 8, p->resumecpus_req.cpu_mask, c->bigendian); break; case KDP_EXCEPTION: { const unsigned int EXCEPTION_SIZE = 16; unsigned int i; len = 12 + (p->exception.n_exc_info * EXCEPTION_SIZE); CHECK_LEN_MAX (len, maxlen); write32u (s + 8, p->exception.n_exc_info, c->bigendian); for (i = 0; i < p->exception.n_exc_info; i++) { kdp_exc_info_t *e = &p->exception.exc_info[i]; write32u (s + 12 + (i * EXCEPTION_SIZE), e->cpu, c->bigendian); write32u (s + 12 + (i * EXCEPTION_SIZE) + 4, e->exception, c->bigendian); write32u (s + 12 + (i * EXCEPTION_SIZE) + 8, e->code, c->bigendian); write32u (s + 12 + (i * EXCEPTION_SIZE) + 12, e->subcode, c->bigendian); } break; } case KDP_TERMINATION: len = 16; write32u (s + 8, p->termination.term_code, c->bigendian); write32u (s + 12, p->termination.exit_code, c->bigendian); break; default: c->logger (KDP_LOG_ERROR, "kdp_marshal: unknown packet type for request 0x%x\n", p->hdr.request); return RR_IP_ERROR; } } CHECK_LEN_MAX (len, maxlen); if (len < 8) { c->logger (KDP_LOG_ERROR, "kdp_marshal: length of packet (%lu) is less than 8 " "(an error must have occurred)\n"); return RR_RESOURCE; } if (c->bigendian) { s[0] = (p->hdr.request & 0x7f) | (p->hdr.is_reply << 7); } else { s[0] = ((p->hdr.request & 0x7f) << 1) | (p->hdr.is_reply & 0x1); } s[1] = p->hdr.seq; write16u (s + 2, len, c->bigendian); write32u (s + 4, p->hdr.key, c->bigendian); *plen = len; return RR_SUCCESS; } kdp_return_t kdp_unmarshal (kdp_connection *c, kdp_pkt_t *p, const unsigned char *s, size_t rlen) { #define CHECK_PLEN_RLEN(plen, rlen) \ if (plen != rlen) { \ c->logger (KDP_LOG_ERROR, \ "kdp_unmarshal: length contained in packet (%lu) " \ "does not match length read from socket (%lu)\n", \ (unsigned long) plen, (unsigned long) rlen); \ return RR_IP_ERROR; \ } #define CHECK_PLEN_LEN(plen, len) \ if (plen != len) { \ c->logger (KDP_LOG_ERROR, \ "kdp_unmarshal: length contained in packet (%lu) " \ "does not match expected length of packet (%lu)\n", \ (unsigned long) plen, (unsigned long) len); \ return RR_IP_ERROR; \ } #define CHECK_PLEN_MINLEN(plen, len) \ if (plen < len) { \ c->logger (KDP_LOG_ERROR, \ "kdp_unmarshal: length contained in packet (%lu) " \ "is smaller than expected minimum packet length (%lu)\n", \ (unsigned long) plen, (unsigned long) len); \ return RR_IP_ERROR; \ } size_t plen = 0; CHECK_FATAL (c->logger != NULL); if (rlen < 8) { c->logger (KDP_LOG_ERROR, "data length (%lu) is too small (less than %d)\n", rlen, 8); return RR_IP_ERROR; } if (rlen > KDP_MAX_PACKET_SIZE) { c->logger (KDP_LOG_ERROR, "data length (%lu) is too large (greater than %d)\n", rlen, KDP_MAX_PACKET_SIZE); return RR_IP_ERROR; } if (c->bigendian) { p->hdr.is_reply = s[0] >> 7; p->hdr.request = s[0] & 0x7f; } else { p->hdr.request = s[0] >> 1; p->hdr.is_reply = s[0] & 0x1; } p->hdr.seq = s[1]; plen = read16u (s + 2, c->bigendian); p->hdr.key = read32u (s + 4, c->bigendian); if (p->hdr.is_reply) { switch (p->hdr.request) { case KDP_CONNECT: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 12); p->connect_reply.error = read32u (s + 8, c->bigendian); break; case KDP_DISCONNECT: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 8); break; case KDP_HOSTINFO: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 20); p->hostinfo_reply.cpu_mask = read32u (s + 8, c->bigendian); p->hostinfo_reply.cpu_type = read32u (s + 12, c->bigendian); p->hostinfo_reply.cpu_subtype = read32u (s + 16, c->bigendian); break; case KDP_REGIONS: { const unsigned int REGION_SIZE = 12; unsigned int i; CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 12); p->regions_reply.nregions = read32u (s + 8, c->bigendian); CHECK_PLEN_LEN (plen, ((p->regions_reply.nregions * REGION_SIZE) + 12)); for (i = 0; i < p->regions_reply.nregions; i++) { unsigned int offset = 12 + (i * REGION_SIZE); p->regions_reply.regions[i].address = read32u (s + offset, c->bigendian); p->regions_reply.regions[i].nbytes = read32u (s + offset + 4, c->bigendian); p->regions_reply.regions[i].protection = read32u (s + offset + 8, c->bigendian); } break; } case KDP_MAXBYTES: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 12); p->maxbytes_reply.max_bytes = read32u (s + 8, c->bigendian); break; case KDP_READMEM: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 12); p->readmem_reply.error = read32u (s + 8, c->bigendian); p->readmem_reply.nbytes = plen - 12; memcpy (p->readmem_reply.data, s + 12, plen - 12); break; case KDP_WRITEMEM: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 12); p->writemem_reply.error = read32u (s + 8, c->bigendian); break; case KDP_READREGS: { const unsigned int KDP_REGISTER_SIZE = 4; unsigned int i; unsigned int reglen = plen - 12; CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 12); p->readregs_reply.error = read32u (s + 8, c->bigendian); if ((reglen % KDP_REGISTER_SIZE) != 0) { c->logger (KDP_LOG_ERROR, "length of register data (%u) is not an integer multiple of KDP_REGISTER_SIZE (%u)\n", reglen, KDP_REGISTER_SIZE); return RR_IP_ERROR; } p->readregs_reply.nbytes = reglen; for (i = 0; i < (reglen / KDP_REGISTER_SIZE); i++) { ((unsigned long *) p->readregs_reply.data)[i] = read32u (s + 12 + (i * KDP_REGISTER_SIZE), c->bigendian); } break; } case KDP_WRITEREGS: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 12); p->writeregs_reply.error = read32u (s + 8, c->bigendian); break; case KDP_LOAD: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 12); p->load_reply.error = read32u (s + 8, c->bigendian); break; case KDP_IMAGEPATH: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 8); memcpy (p->imagepath_reply.path, s + 8, plen - 8); break; case KDP_SUSPEND: case KDP_RESUMECPUS: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 8); break; case KDP_EXCEPTION: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 8); break; case KDP_TERMINATION: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 8); break; default: c->logger (KDP_LOG_ERROR, "kdp_unmarshal: unknown packet type 0x%x\n", p->hdr.request); return RR_IP_ERROR; } } else { switch (p->hdr.request) { case KDP_CONNECT: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 12 + 1); /* port numbers are always sent little-endian */ p->connect_req.req_reply_port = read16u (s + 8, 0); p->connect_req.exc_note_port = read16u (s + 10, 0); memcpy (p->connect_req.greeting, s + 12, plen - 12); break; case KDP_DISCONNECT: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 8); break; case KDP_HOSTINFO: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 8); break; case KDP_REGIONS: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 8); break; case KDP_MAXBYTES: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 8); break; case KDP_READMEM: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 16); p->readmem_req.address = read32u (s + 8, c->bigendian); p->readmem_req.nbytes = read32u (s + 12, c->bigendian); break; case KDP_WRITEMEM: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 16); p->writemem_req.address = read32u (s + 8, c->bigendian); p->writemem_req.nbytes = read32u (s + 12, c->bigendian); CHECK_PLEN_LEN (plen, p->writemem_req.nbytes + 16); memcpy (p->writemem_req.data, s + 16, plen - 16); break; case KDP_READREGS: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 16); p->readregs_req.cpu = read32u (s + 8, c->bigendian); p->readregs_req.flavor = read32u (s + 12, c->bigendian); break; case KDP_WRITEREGS: { const unsigned int KDP_REGISTER_SIZE = 4; unsigned int i; unsigned int reglen = plen - 16; CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 16); p->writeregs_req.cpu = read32u (s + 8, c->bigendian); p->writeregs_req.flavor = read32u (s + 12, c->bigendian); if ((reglen % KDP_REGISTER_SIZE) != 0) { c->logger (KDP_LOG_ERROR, "length of register data (%u) is not an integer multiple of KDP_REGISTER_SIZE (%u)\n", reglen, KDP_REGISTER_SIZE); return RR_IP_ERROR; } p->writeregs_req.nbytes = reglen; for (i = 0; i < (reglen / KDP_REGISTER_SIZE); i++) { ((unsigned long *) p->writeregs_req.data)[i] = read32u (s + 16 + (i * KDP_REGISTER_SIZE), c->bigendian); } break; } case KDP_LOAD: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 8 + 1); memcpy (p->load_req.file_args, c + 8, plen - 8); break; case KDP_IMAGEPATH: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 8); break; case KDP_SUSPEND: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 8); break; case KDP_RESUMECPUS: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 12); p->resumecpus_req.cpu_mask = read32u (s + 8, c->bigendian); break; case KDP_EXCEPTION: { const unsigned int EXCEPTION_SIZE = 16; unsigned int i; CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_MINLEN (plen, 12); p->exception.n_exc_info = read32u (s + 8, c->bigendian); /* bug in KDP on NextStep <= 4.2, Rhapsody Developer */ if ((plen == 44) && (p->exception.n_exc_info == 1)) { plen = 28; } CHECK_PLEN_LEN (plen, ((p->exception.n_exc_info * EXCEPTION_SIZE) + 12)); for (i = 0; i < p->exception.n_exc_info; i++) { unsigned int offset = 12 + (i * EXCEPTION_SIZE); p->exception.exc_info[i].cpu = read32u (s + offset, c->bigendian); p->exception.exc_info[i].exception = read32u (s + offset + 4, c->bigendian); p->exception.exc_info[i].code = read32u (s + offset + 8, c->bigendian); p->exception.exc_info[i].subcode = read32u (s + offset + 12, c->bigendian); } break; } case KDP_TERMINATION: CHECK_PLEN_RLEN (plen, rlen); CHECK_PLEN_LEN (plen, 16); p->termination.term_code = read32u (s + 8, c->bigendian); p->termination.exit_code = read32u (s + 12, c->bigendian); break; default: c->logger (KDP_LOG_ERROR, "kdp_unmarshal: unknown packet type 0x%x\n", p->hdr.request); return RR_IP_ERROR; } } return RR_SUCCESS; }