//------------------------------------------------------------------------------ // Name: resolve_function_call // Desc: //------------------------------------------------------------------------------ Result<QString> CommentServer::resolve_function_call(QHexView::address_t address) const { // ok, we now want to locate the instruction before this one // so we need to look back a few bytes quint8 buffer[edb::Instruction::MAX_SIZE]; // TODO(eteran): portability warning, makes assumptions on the size of a call if(IProcess *process = edb::v1::debugger_core->process()) { if(process->read_bytes(address - CALL_MAX_SIZE, buffer, sizeof(buffer))) { for(int i = (CALL_MAX_SIZE - CALL_MIN_SIZE); i >= 0; --i) { edb::Instruction inst(buffer + i, buffer + sizeof(buffer), 0); if(is_call(inst)) { const QString symname = edb::v1::find_function_symbol(address); if(!symname.isEmpty()) { return edb::v1::make_result(tr("return to %1 <%2>").arg(edb::v1::format_pointer(address)).arg(symname)); } else { return edb::v1::make_result(tr("return to %1").arg(edb::v1::format_pointer(address))); } } } } } return Result<QString>(tr("Failed to resolve function call"), tr("")); }
//------------------------------------------------------------------------------ // Name: get_call_stack // Desc: Gets the state of the call stack at the time the object is created. //------------------------------------------------------------------------------ void CallStack::get_call_stack() { /* * Is rbp a pointer somewhere in the stack? * Is the value below rbp a ret addr? * Are we still scanning within the stack region? */ //Get the frame & stack pointers. State state; edb::v1::debugger_core->get_state(&state); edb::address_t rbp = state.frame_pointer(); edb::address_t rsp = state.stack_pointer(); //Check the alignment. rbp and rsp should be aligned to the stack. if (rbp % edb::v1::pointer_size() != 0 || rsp % edb::v1::pointer_size() != 0) { return; } //Make sure frame pointer is pointing in the same region as stack pointer. //If not, then it's being used as a GPR, and we don't have enough info. //This assumes the stack pointer is always pointing somewhere in the stack. IRegion::pointer region_rsp, region_rbp; edb::v1::memory_regions().sync(); region_rsp = edb::v1::memory_regions().find_region(rsp); region_rbp = edb::v1::memory_regions().find_region(rbp); if (!region_rsp || !region_rbp || (region_rbp != region_rsp) ) { return; } //But if we're good, then scan from rbp downward and look for return addresses. //Code is largely from CommentServer.cpp. Makes assumption of size of call. const quint8 CALL_MIN_SIZE = 2, CALL_MAX_SIZE = 7; quint8 buffer[edb::Instruction::MAX_SIZE]; for (edb::address_t addr = rbp; region_rbp->contains(addr); addr += edb::v1::pointer_size()) { //Get the stack value so that we can see if it's a pointer bool ok; ExpressionError err; edb::address_t possible_ret = edb::v1::get_value(addr, &ok, &err); if(IProcess *process = edb::v1::debugger_core->process()) { if(process->read_bytes(possible_ret - CALL_MAX_SIZE, buffer, sizeof(buffer))) { //0xfffff... if not a ptr. for(int i = (CALL_MAX_SIZE - CALL_MIN_SIZE); i >= 0; --i) { edb::Instruction inst(buffer + i, buffer + sizeof(buffer), 0); //If it's a call, then make a frame if(is_call(inst)) { stack_frame frame; frame.ret = possible_ret; frame.caller = possible_ret - CALL_MAX_SIZE + i; stack_frames_.append(frame); break; } } } } } }
void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { address trampoline = nativeCall_at(addr())->get_trampoline(); if (trampoline) { nativeCall_at(addr())->set_destination_mt_safe(x, /* assert_lock */false); return; } } MacroAssembler::pd_patch_instruction(addr(), x); assert(pd_call_destination(addr()) == x, "fail in reloc"); }
address Relocation::pd_call_destination(address orig_addr) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { address trampoline = nativeCall_at(addr())->get_trampoline(); if (trampoline) { return nativeCallTrampolineStub_at(trampoline)->destination(); } } if (orig_addr != NULL) { address new_addr = MacroAssembler::pd_call_destination(orig_addr); // If call is branch to self, don't try to relocate it, just leave it // as branch to self. This happens during code generation if the code // buffer expands. It will be relocated to the trampoline above once // code generation is complete. new_addr = (new_addr == orig_addr) ? addr() : new_addr; return new_addr; } return MacroAssembler::pd_call_destination(addr()); }
static ssize_t tnt_rpc_base(struct tnt_stream *s, const char *proc, size_t proc_len, struct tnt_stream *args, enum tnt_request_t op) { if (!proc || proc_len == 0) return -1; if (tnt_object_verify(args, MP_ARRAY)) return -1; uint32_t fld = (is_call(op) ? TNT_FUNCTION : TNT_EXPRESSION); struct tnt_iheader hdr; struct iovec v[6]; int v_sz = 6; char *data = NULL, *body_start = NULL; encode_header(&hdr, op, s->reqid++); v[1].iov_base = (void *)hdr.header; v[1].iov_len = hdr.end - hdr.header; char body[64]; body_start = body; data = body; data = mp_encode_map(data, 2); data = mp_encode_uint(data, fld); data = mp_encode_strl(data, proc_len); v[2].iov_base = body_start; v[2].iov_len = data - body_start; v[3].iov_base = (void *)proc; v[3].iov_len = proc_len; body_start = data; data = mp_encode_uint(data, TNT_TUPLE); v[4].iov_base = body_start; v[4].iov_len = data - body_start; v[5].iov_base = TNT_SBUF_DATA(args); v[5].iov_len = TNT_SBUF_SIZE(args); size_t package_len = 0; for (int i = 1; i < v_sz; ++i) package_len += v[i].iov_len; char len_prefix[9]; char *len_end = mp_encode_luint32(len_prefix, package_len); v[0].iov_base = len_prefix; v[0].iov_len = len_end - len_prefix; return s->writev(s, v, v_sz); }
vector<PointerAccess> get_pointer_accesses(const Instruction *ins) { vector<PointerAccess> result; if (const StoreInst *si = dyn_cast<StoreInst>(ins)) { result.push_back(PointerAccess(si, si->getPointerOperand(), true)); } else if (const LoadInst *li = dyn_cast<LoadInst>(ins)) { result.push_back(PointerAccess(li, li->getPointerOperand(), false)); } else if (is_call(ins)) { CallSite cs(const_cast<Instruction *>(ins)); Function *callee = cs.getCalledFunction(); if (callee) { if (callee->getName() == "read") { result.push_back(PointerAccess(ins, cs.getArgument(1), true)); } if (callee->getName() == "write") { result.push_back(PointerAccess(ins, cs.getArgument(1), false)); } if (callee->getName() == "BZ2_bzBuffToBuffDecompress") { result.push_back(PointerAccess(ins, cs.getArgument(0), true)); } } } return result; }
//------------------------------------------------------------------------------ // Name: do_find // Desc: //------------------------------------------------------------------------------ void DialogReferences::do_find() { bool ok = false; edb::address_t address; const edb::address_t page_size = edb::v1::debugger_core->page_size(); const QString text = ui->txtAddress->text(); if(!text.isEmpty()) { ok = edb::v1::eval_expression(text, &address); } if(ok) { edb::v1::memory_regions().sync(); const QList<IRegion::pointer> regions = edb::v1::memory_regions().regions(); int i = 0; for(const IRegion::pointer ®ion: regions) { // a short circut for speading things up if(region->accessible() || !ui->chkSkipNoAccess->isChecked()) { const edb::address_t page_count = region->size() / page_size; const QVector<quint8> pages = edb::v1::read_pages(region->start(), page_count); if(!pages.isEmpty()) { const quint8 *p = &pages[0]; const quint8 *const pages_end = &pages[0] + region->size(); while(p != pages_end) { if(pages_end - p < edb::v1::pointer_size()) { break; } const edb::address_t addr = p - &pages[0] + region->start(); edb::address_t test_address(0); memcpy(&test_address, p, edb::v1::pointer_size()); if(test_address == address) { auto item = new QListWidgetItem(edb::v1::format_pointer(addr)); item->setData(TypeRole, 'D'); item->setData(AddressRole, addr); ui->listWidget->addItem(item); } edb::Instruction inst(p, pages_end, addr); if(inst) { switch(inst.operation()) { case edb::Instruction::Operation::X86_INS_MOV: // instructions of the form: mov [ADDR], 0xNNNNNNNN Q_ASSERT(inst.operand_count() == 2); if(inst.operands()[0].general_type() == edb::Operand::TYPE_EXPRESSION) { if(inst.operands()[1].general_type() == edb::Operand::TYPE_IMMEDIATE && static_cast<edb::address_t>(inst.operands()[1].immediate()) == address) { auto item = new QListWidgetItem(edb::v1::format_pointer(addr)); item->setData(TypeRole, 'C'); item->setData(AddressRole, addr); ui->listWidget->addItem(item); } } break; case edb::Instruction::Operation::X86_INS_PUSH: // instructions of the form: push 0xNNNNNNNN Q_ASSERT(inst.operand_count() == 1); if(inst.operands()[0].general_type() == edb::Operand::TYPE_IMMEDIATE && static_cast<edb::address_t>(inst.operands()[0].immediate()) == address) { auto item = new QListWidgetItem(edb::v1::format_pointer(addr)); item->setData(TypeRole, 'C'); item->setData(AddressRole, addr); ui->listWidget->addItem(item); } break; default: if(is_jump(inst) || is_call(inst)) { if(inst.operands()[0].general_type() == edb::Operand::TYPE_REL) { if(inst.operands()[0].relative_target() == address) { auto item = new QListWidgetItem(edb::v1::format_pointer(addr)); item->setData(TypeRole, 'C'); item->setData(AddressRole, addr); ui->listWidget->addItem(item); } } } break; } } Q_EMIT updateProgress(util::percentage(i, regions.size(), p - &pages[0], region->size())); ++p; } } } else { Q_EMIT updateProgress(util::percentage(i, regions.size())); } ++i; } } }