char *resize(char *inout_begin, size_t count) { intptr_t size_bytes = count * data_size; // cout << "resizing memory " << (void *)*inout_begin << " / " << (void *)*inout_end << " from size " << // (*inout_end - *inout_begin) << " to " << size_bytes << endl; // cout << "memory state before " << (void *)emb->m_memory_begin << " / " << (void *)emb->m_memory_current << " // / // " << (void *)emb->m_memory_end << endl; char **inout_end = &m_memory_current; char *end = inout_begin + size_bytes; if (end <= m_memory_end) { // If it fits, just adjust the current allocation point m_memory_current = end; *inout_end = end; } else { // If it doesn't fit, need to copy to newly malloc'd memory char *old_current = inout_begin, *old_end = *inout_end; // Allocate memory to double the amount used so far, or the requested size, whichever is larger // NOTE: We're assuming malloc produces memory which has good enough alignment for anything append_memory(std::max(m_total_allocated_capacity, size_bytes)); memcpy(m_memory_begin, inout_begin, *inout_end - inout_begin); end = m_memory_begin + size_bytes; m_memory_current = end; inout_begin = m_memory_begin; *inout_end = end; m_total_allocated_capacity -= old_end - old_current; } // cout << "memory state after " << (void *)emb->m_memory_begin << " / " << (void *)emb->m_memory_current << " // / // " << (void *)emb->m_memory_end << endl; return inout_begin; }
//-------------------------------------------------------------------------- ssize_t idaapi rpc_debmod_t::dbg_write_memory(ea_t ea, const void *buffer, size_t size) { bytevec_t req = prepare_rpc_packet(RPC_WRITE_MEMORY); append_ea64(req, ea); append_dd(req, (uint32)size); append_memory(req, buffer, size); return process_long(req); }
//-------------------------------------------------------------------------- ssize_t rpc_debmod_t::dbg_write_memory(ea_t ea, const void *buffer, size_t size) { qstring cmd = prepare_rpc_packet(RPC_WRITE_MEMORY); append_ea(cmd, ea); append_long(cmd, (uint32)size); append_memory(cmd, buffer, size); return process_long(cmd); }
//-------------------------------------------------------------------------- int rpc_debmod_t::dbg_del_bpt(ea_t ea, const uchar *orig_bytes, int len) { qstring cmd = prepare_rpc_packet(RPC_DEL_BPT); append_ea(cmd, ea); append_long(cmd, len); append_memory(cmd, orig_bytes, len); return process_long(cmd); }
objectarray_memory_block(const ndt::type &dt, size_t arrmeta_size, const char *arrmeta, intptr_t stride, intptr_t initial_count) : m_dt(dt), arrmeta_size(arrmeta_size), m_arrmeta(arrmeta), m_stride(stride), m_total_allocated_count(0), m_finalized(false), m_memory_handles() { if ((dt.get_flags() & type_flag_destructor) == 0) { std::stringstream ss; ss << "Cannot create objectarray memory block with dynd type " << dt; ss << " because it does not have a destructor, use a POD memory block instead"; throw std::runtime_error(ss.str()); } append_memory(initial_count); }
char *resize(char *previous_allocated, size_t count) { memory_chunk *mc = &m_memory_handles.back(); size_t previous_index = (previous_allocated - mc->memory) / m_stride; size_t previous_count = mc->used_count - previous_index; char *result = previous_allocated; if (mc->capacity_count - previous_index < count) { append_memory(std::max(m_total_allocated_count, count)); memory_chunk *new_mc = &m_memory_handles.back(); // Move the old memory to the newly allocated block if (previous_count > 0) { // Subtract the previously used memory from the old chunk's count mc->used_count -= previous_count; memcpy(new_mc->memory, previous_allocated, previous_count); // If the old memory only had the memory being resized, // free it completely. if (previous_allocated == mc->memory) { free(mc->memory); // Remove the second-last element of the vector m_memory_handles.erase(m_memory_handles.begin() + m_memory_handles.size() - 2); } } mc = &m_memory_handles.back(); result = mc->memory; mc->used_count = count; } else { // Adjust the used count (this may mean to grow it or shrink it) if (count >= previous_count) { mc->used_count += (count - previous_count); } else { // Call the destructor on the elements no longer used m_dt.extended()->data_destruct_strided(m_arrmeta + arrmeta_size, previous_allocated + m_stride * count, m_stride, previous_count - count); mc->used_count -= (previous_count - count); } } if ((m_dt.get_flags() & type_flag_zeroinit) != 0) { // Zero-init the new memory intptr_t new_count = count - (intptr_t)previous_count; if (new_count > 0) { memset(mc->memory + m_stride * previous_count, 0, m_stride * new_count); } } else { // TODO: Add a default data constructor to base_type // as well, with a flag for it std::stringstream ss; ss << "Expected objectarray data to be zeroinit, but is not with dynd type " << m_dt; throw std::runtime_error(ss.str()); } return result; }
//-------------------------------------------------------------------------- int idaapi rpc_debmod_t::dbg_update_lowcnds(const lowcnd_t *lowcnds, int nlowcnds) { ea_t ea = 0; bytevec_t req = prepare_rpc_packet(RPC_UPDATE_LOWCNDS); append_dd(req, nlowcnds); const lowcnd_t *lc = lowcnds; for ( int i=0; i < nlowcnds; i++, lc++ ) { append_ea64(req, lc->ea-ea); ea = lc->ea; append_str(req, lc->cndbody); if ( !lc->cndbody.empty() ) { append_dd(req, lc->type); if ( lc->type != BPT_SOFT ) append_dd(req, lc->size); append_db(req, lc->orgbytes.size()); append_memory(req, lc->orgbytes.begin(), lc->orgbytes.size()); append_ea64(req, lc->cmd.ea); if ( lc->cmd.ea != BADADDR ) append_memory(req, &lc->cmd, sizeof(lc->cmd)); } } return process_long(req); }
char *alloc(size_t count) { // cout << "allocating " << size_bytes << " of memory with alignment " << alignment << endl; // Allocate new POD memory of the requested size and alignment memory_chunk *mc = &m_memory_handles.back(); if (mc->capacity_count - mc->used_count < count) { append_memory(std::max(m_total_allocated_count, count)); mc = &m_memory_handles.back(); } char *result = mc->memory + m_stride * mc->used_count; mc->used_count += count; if ((m_dt.get_flags() & type_flag_zeroinit) != 0) { memset(result, 0, m_stride * count); } else { // TODO: Add a default data constructor to base_type // as well, with a flag for it std::stringstream ss; ss << "Expected objectarray data to be zeroinit, but is not with dynd type " << m_dt; throw std::runtime_error(ss.str()); } return result; }
//-------------------------------------------------------------------------- ssize_t idaapi rpc_debmod_t::dbg_write_file(int fn, uint32 off, const void *buf, size_t size) { bytevec_t req = prepare_rpc_packet(RPC_WRITE_FILE); append_dd(req, fn); append_dd(req, off); append_dd(req, (uint32)size); append_memory(req, buf, size); rpc_packet_t *rp = process_request(req); if ( rp == NULL ) return -1; const uchar *answer = (uchar *)(rp+1); const uchar *end = answer + rp->length; int32 rsize = extract_long(&answer, end); if ( size != rsize ) qerrcode(extract_long(&answer, end)); qfree(rp); return rsize; }
//-------------------------------------------------------------------------- int rpc_debmod_t::dbg_read_registers(thid_t tid, int clsmask, regval_t *values) { qstring cmd = prepare_rpc_packet(RPC_READ_REGS); append_long(cmd, tid); append_long(cmd, clsmask); // append additional information about the class structure bytevec_t regmap; int nregs = calc_regmap(®map, clsmask); append_long(cmd, nregs); append_memory(cmd, regmap.begin(), regmap.size()); rpc_packet_t *rp = process_request(cmd); if ( rp == NULL ) return -1; const uchar *answer = (uchar *)(rp+1); const uchar *end = answer + rp->length; int result = extract_long(&answer, end); if ( result ) extract_regvals(&answer, end, values, nregs, regmap.begin()); qfree(rp); return result; }
char *alloc(size_t count) { intptr_t size_bytes = count * data_size; // cout << "allocating " << size_bytes << " of memory with alignment " << alignment << endl; // Allocate new POD memory of the requested size and alignment char *begin = reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(m_memory_current) + data_alignment - 1) & ~(data_alignment - 1)); char *end = begin + size_bytes; if (end > m_memory_end) { m_total_allocated_capacity -= m_memory_end - m_memory_current; // Allocate memory to double the amount used so far, or the requested size, whichever is larger // NOTE: We're assuming malloc produces memory which has good enough alignment for anything append_memory(std::max(m_total_allocated_capacity, size_bytes)); begin = m_memory_begin; end = begin + size_bytes; } // Indicate where to allocate the next memory m_memory_current = end; // Return the allocated memory return begin; // cout << "allocated at address " << (void *)begin << endl; }
//-------------------------------------------------------------------------- int idaapi rpc_debmod_t::dbg_update_bpts(update_bpt_info_t *ubpts, int nadd, int ndel) { int skipped = 0; update_bpt_info_t *b; update_bpt_info_t *bend = ubpts + nadd; for ( b=ubpts; b != bend; b++ ) if ( b->code != BPT_OK ) skipped++; if ( skipped == nadd && ndel == 0 ) return 0; // no bpts to update bytevec_t req = prepare_rpc_packet(RPC_UPDATE_BPTS); append_dd(req, nadd-skipped); append_dd(req, ndel); ea_t ea = 0; for ( b=ubpts; b != bend; b++ ) { if ( b->code == BPT_OK ) { append_ea64(req, b->ea-ea); ea = b->ea; append_dd(req, b->size); append_dd(req, b->type); } } ea = 0; bend += ndel; for ( ; b != bend; b++ ) { append_ea64(req, b->ea-ea); ea = b->ea; append_db(req, b->orgbytes.size()); append_memory(req, b->orgbytes.begin(), b->orgbytes.size()); append_dd(req, b->type); } rpc_packet_t *rp = process_request(req); if ( rp == NULL ) return -1; const uchar *ptr = (uchar *)(rp+1); const uchar *end = ptr + rp->length; int ret = extract_long(&ptr, end); bend = ubpts + nadd; for ( b=ubpts; b != bend; b++ ) { if ( b->code == BPT_OK ) { b->code = extract_byte(&ptr, end); if ( b->code == BPT_OK && b->type == BPT_SOFT ) { uchar len = extract_byte(&ptr, end); b->orgbytes.resize(len); extract_memory(&ptr, end, b->orgbytes.begin(), len); } } } bend += ndel; for ( ; b != bend; b++ ) b->code = extract_byte(&ptr, end); return ret; }
//------------------------------------------------------------------------- bool varser_t::serialize(bytevec_t &out, const VARIANT &var) { append_dw(out, var.vt); if ( (var.vt & VT_BYREF) == VT_BYREF || (var.vt & VT_ARRAY) == VT_ARRAY ) { return false; } const size_t sz_before = out.size(); switch ( var.vt ) { case VT_EMPTY: // = 0x0000, case VT_NULL: // = 0x0001, break; case VT_I2: // = 0x0002, case VT_UI2: // = 0x0012, append_dw(out, var.uiVal); break; case VT_I4: // = 0x0003, case VT_UI4: // = 0x0013, append_dd(out, var.ulVal); break; case VT_R4: // = 0x0004, append_dd(out, *(uint32*)&var.fltVal); break; case VT_R8: // = 0x0005, append_dq(out, *(uint64*)&var.dblVal); break; case VT_CY: // = 0x0006, case VT_DATE: // = 0x0007, break; case VT_BSTR: // = 0x0008, { uint8 *ptr = (uint8*) var.bstrVal; ptr -= 4; uint32 bcnt = * (uint32*) ptr; append_dd(out, bcnt); append_memory(out, ptr + 4, bcnt); } break; case VT_DISPATCH: // = 0x0009, case VT_ERROR: // = 0x000A, case VT_BOOL: // = 0x000B, case VT_VARIANT: // = 0x000C, case VT_UNKNOWN: // = 0x000D, case VT_DECIMAL: // = 0x000E, case VT_I1: // = 0x0010, case VT_UI1: // = 0x0011, append_db(out, var.bVal); break; case VT_I8: // = 0x0014, case VT_UI8: // = 0x0015, append_dq(out, var.ullVal); break; case VT_INT: // = 0x0016, case VT_UINT: // = 0x0017, case VT_HRESULT: // = 0x0019, append_dd(out, var.uintVal); break; case VT_VOID: // = 0x0018, case VT_PTR: // = 0x001A, case VT_SAFEARRAY: // = 0x001B, case VT_CARRAY: // = 0x001C, case VT_USERDEFINED: // = 0x001D, case VT_LPSTR: // = 0x001E, case VT_LPWSTR: // = 0x001F, case VT_RECORD: // = 0x0024, case VT_INT_PTR: // = 0x0025, case VT_UINT_PTR: // = 0x0026, break; default: break; } return out.size() > sz_before; }
//-------------------------------------------------------------------------- // requests received from the server. // here the client handles certain server -> client requests qstring rpc_client_t::perform_request(const rpc_packet_t *rp) { const uchar *ptr = (const uchar *)(rp + 1); const uchar *end = ptr + rp->length; qstring cmd = prepare_rpc_packet(RPC_OK); switch ( rp->code ) { case RPC_SET_DEBUG_NAMES: { int qty = extract_long(&ptr, end); ea_t *addrs = new ea_t[qty]; if ( addrs == NULL ) goto nomem; char **names = new char *[qty]; if ( names == NULL ) { delete [] addrs; goto nomem; } char name[MAXSTR]; ea_t old = 0; name[0] = '\0'; for ( int i=0; i < qty; i++ ) { adiff_t o2 = extract_ea(&ptr, end); if ( extract_long(&ptr, end) ) o2 = -o2; old += o2; addrs[i] = old; int oldlen = extract_long(&ptr, end); qstrncpy(&name[oldlen], extract_str(&ptr, end), sizeof(name)-oldlen); names[i] = qstrdup(name); } int result = set_debug_names(addrs, names, qty); verb(("set_debug_name(qty=%d) => %d\n", qty, result)); append_long(cmd, result); for ( int i=0; i < qty; i++ ) qfree(names[i]); delete [] addrs; delete [] names; } break; case RPC_HANDLE_DEBUG_EVENT: { debug_event_t ev; extract_debug_event(&ptr, end, &ev); int rqflags = extract_long(&ptr, end); int code = send_debug_event_to_ida(&ev, rqflags); append_long(cmd, code); } break; case RPC_SYNC_STUB: { char *fname = extract_str(&ptr, end); uint32 crc = extract_long(&ptr, end); size_t size = 0; uchar *contents = sync_stub(fname, crc, &size); append_long(cmd, (uint32)size); if ( contents != NULL ) { append_memory(cmd, contents, size); qfree(contents); } } break; case RPC_ERROR: case RPC_MSG: case RPC_WARNING: { char *str = extract_str(&ptr, end); if ( rp->code == RPC_MSG) msg("%s", str); else if ( rp->code == RPC_ERROR ) error("%s", str); else warning("%s", str); } break; case RPC_EVENT: { extract_debug_event(&ptr, end, &pending_event); has_pending_event = true; cmd = prepare_rpc_packet(RPC_EVOK); verbev(("got event, storing it and sending RPC_EVOK\n")); } break; case RPC_IOCTL: { int code = handle_ioctl_packet(cmd, ptr, end); if ( code != RPC_OK ) return prepare_rpc_packet((uchar)code); } break; default: return prepare_rpc_packet(RPC_UNK); nomem: return prepare_rpc_packet(RPC_MEM); } return cmd; }
pod_memory_block(size_t data_size, intptr_t data_alignment, intptr_t initial_capacity_bytes = 2048) : data_size(data_size), data_alignment(data_alignment), m_total_allocated_capacity(0), m_memory_handles() { append_memory(initial_capacity_bytes); }
zeroinit_memory_block(size_t data_size, intptr_t data_alignment, intptr_t initial_capacity_bytes) : memory_block_data(1, zeroinit_memory_block_type), data_size(data_size), data_alignment(data_alignment), m_total_allocated_capacity(0), m_memory_handles() { append_memory(initial_capacity_bytes); }