Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1112)

Unified Diff: src/processor/disassembler_x86.cc

Issue 1821293002: Replace libdisasm with capstone Base URL: https://chromium.googlesource.com/breakpad/breakpad.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/processor/disassembler_x86.cc
diff --git a/src/processor/disassembler_x86.cc b/src/processor/disassembler_x86.cc
index 559022404f6ee0ac1cac44ab67b4eb5d8c4ffb7b..b5c8838d837880e587fe10211027c1febf959f50 100644
--- a/src/processor/disassembler_x86.cc
+++ b/src/processor/disassembler_x86.cc
@@ -36,132 +36,139 @@ DisassemblerX86::DisassemblerX86(const uint8_t *bytecode,
bytecode_(bytecode),
size_(size),
virtual_address_(virtual_address),
- current_byte_offset_(0),
- current_inst_offset_(0),
+ handle_(0),
instr_valid_(false),
+ current_instr_(nullptr),
register_valid_(false),
+ bad_register_(X86_REG_INVALID),
pushed_bad_value_(false),
end_of_block_(false),
flags_(0) {
- libdis::x86_init(libdis::opt_none, NULL, NULL);
+ //TODO: allow selecting 32 or 64-bit.
+ if (cs_open(CS_ARCH_X86, CS_MODE_32, &handle_) == CS_ERR_OK) {
+ // Enable detailed instruction information.
+ cs_option(handle_, CS_OPT_DETAIL, CS_OPT_ON);
+ current_instr_ = cs_malloc(handle_);
+ }
}
DisassemblerX86::~DisassemblerX86() {
- if (instr_valid_)
- libdis::x86_oplist_free(&current_instr_);
+ if (current_instr_) {
+ cs_free(current_instr_, 1);
+ }
- libdis::x86_cleanup();
+ cs_close(&handle_);
}
-uint32_t DisassemblerX86::NextInstruction() {
- if (instr_valid_)
- libdis::x86_oplist_free(&current_instr_);
-
- if (current_byte_offset_ >= size_) {
- instr_valid_ = false;
- return 0;
+// Return a pointer to the `nth` (zero-based) operand in `detail`, or NULL if
+// no such operand exists.
+static cs_x86_op* get_operand(cs_x86& detail, size_t nth) {
+ if (nth > detail.op_count) {
+ return nullptr;
}
- uint32_t instr_size = 0;
- instr_size = libdis::x86_disasm((unsigned char *)bytecode_, size_,
- virtual_address_, current_byte_offset_,
- &current_instr_);
- if (instr_size == 0) {
- instr_valid_ = false;
+ return &detail.operands[nth];
+}
+
+size_t DisassemblerX86::NextInstruction() {
+ instr_valid_ = false;
+ if (size_ == 0) {
return 0;
}
- current_byte_offset_ += instr_size;
- current_inst_offset_++;
- instr_valid_ = libdis::x86_insn_is_valid(&current_instr_);
- if (!instr_valid_)
+ if (!cs_disasm_iter(handle_, &bytecode_, &size_, &virtual_address_,
+ current_instr_)) {
return 0;
+ }
- if (current_instr_.type == libdis::insn_return)
+ instr_valid_ = true;
+ if (cs_insn_group(handle_, current_instr_, CS_GRP_RET))
end_of_block_ = true;
- libdis::x86_op_t *src = libdis::x86_get_src_operand(&current_instr_);
- libdis::x86_op_t *dest = libdis::x86_get_dest_operand(&current_instr_);
+ cs_x86_op* src = get_operand(current_instr_->detail->x86, 1);
+ cs_x86_op* dest = get_operand(current_instr_->detail->x86, 0);
if (register_valid_) {
- switch (current_instr_.group) {
+ if (cs_insn_group(handle_, current_instr_, CS_GRP_JUMP) ||
+ cs_insn_group(handle_, current_instr_, CS_GRP_CALL)) {
// Flag branches based off of bad registers and calls that occur
// after pushing bad values.
- case libdis::insn_controlflow:
- switch (current_instr_.type) {
- case libdis::insn_jmp:
- case libdis::insn_jcc:
- case libdis::insn_call:
- case libdis::insn_callcc:
- if (dest) {
- switch (dest->type) {
- case libdis::op_expression:
- if (dest->data.expression.base.id == bad_register_.id)
- flags_ |= DISX86_BAD_BRANCH_TARGET;
- break;
- case libdis::op_register:
- if (dest->data.reg.id == bad_register_.id)
- flags_ |= DISX86_BAD_BRANCH_TARGET;
- break;
- default:
- if (pushed_bad_value_ &&
- (current_instr_.type == libdis::insn_call ||
- current_instr_.type == libdis::insn_callcc))
- flags_ |= DISX86_BAD_ARGUMENT_PASSED;
- break;
- }
- }
- break;
- default:
- break;
+ if (dest) {
+ switch (dest->type) {
+ case X86_OP_MEM:
+ if (dest->mem.base == bad_register_)
+ flags_ |= DISX86_BAD_BRANCH_TARGET;
+ break;
+ case X86_OP_REG:
+ if (dest->reg == bad_register_)
+ flags_ |= DISX86_BAD_BRANCH_TARGET;
+ break;
+ default:
+ if (pushed_bad_value_ &&
+ cs_insn_group(handle_, current_instr_, CS_GRP_CALL)) {
+ flags_ |= DISX86_BAD_ARGUMENT_PASSED;
+ }
+ break;
}
- break;
-
- // Flag block data operations that use bad registers for src or dest.
- case libdis::insn_string:
- if (dest && dest->type == libdis::op_expression &&
- dest->data.expression.base.id == bad_register_.id)
+ }
+ } else if(currentInstructionIsBlockData()) {
+ // Flag block data operations that use bad registers for src or dest.
+ if (dest && dest->type == X86_OP_MEM &&
+ dest->mem.base == bad_register_) {
flags_ |= DISX86_BAD_BLOCK_WRITE;
- if (src && src->type == libdis::op_expression &&
- src->data.expression.base.id == bad_register_.id)
+ }
+ if (src && src->type == X86_OP_MEM &&
+ src->mem.base == bad_register_) {
flags_ |= DISX86_BAD_BLOCK_READ;
- break;
-
- // Flag comparisons based on bad data.
- case libdis::insn_comparison:
- if ((dest && dest->type == libdis::op_expression &&
- dest->data.expression.base.id == bad_register_.id) ||
- (src && src->type == libdis::op_expression &&
- src->data.expression.base.id == bad_register_.id) ||
- (dest && dest->type == libdis::op_register &&
- dest->data.reg.id == bad_register_.id) ||
- (src && src->type == libdis::op_register &&
- src->data.reg.id == bad_register_.id))
+ }
+ } else {
+ switch (current_instr_->id) {
+ // Flag comparisons based on bad data.
+ case X86_INS_CMP:
+ case X86_INS_CMPPS:
+ case X86_INS_PCMPEQD:
+ case X86_INS_PCMPEQW:
+ case X86_INS_PFCMPEQ:
+ case X86_INS_PFCMPGE:
+ case X86_INS_PFCMPGT:
+ case X86_INS_TEST:
+ if ((dest && dest->type == X86_OP_MEM &&
+ dest->mem.base == bad_register_) ||
+ (src && src->type == X86_OP_MEM &&
+ src->mem.base == bad_register_) ||
+ (dest && dest->type == X86_OP_REG &&
+ dest->reg == bad_register_) ||
+ (src && src->type == X86_OP_REG &&
+ src->reg == bad_register_)) {
flags_ |= DISX86_BAD_COMPARISON;
+ }
break;
- // Flag any other instruction which derefs a bad register for
- // src or dest.
+ // Flag any other instruction which derefs a bad register for
+ // src or dest.
default:
- if (dest && dest->type == libdis::op_expression &&
- dest->data.expression.base.id == bad_register_.id)
+ if (dest && dest->type == X86_OP_MEM &&
+ dest->mem.base == bad_register_) {
flags_ |= DISX86_BAD_WRITE;
- if (src && src->type == libdis::op_expression &&
- src->data.expression.base.id == bad_register_.id)
+ }
+ if (src && src->type == X86_OP_MEM &&
+ src->mem.base == bad_register_) {
flags_ |= DISX86_BAD_READ;
+ }
break;
+ }
}
}
// When a register is marked as tainted check if it is pushed.
// TODO(cdn): may also want to check for MOVs into EBP offsets.
- if (register_valid_ && dest && current_instr_.type == libdis::insn_push) {
+ if (register_valid_ && dest && current_instr_->id == X86_INS_PUSH) {
switch (dest->type) {
- case libdis::op_expression:
- if (dest->data.expression.base.id == bad_register_.id ||
- dest->data.expression.index.id == bad_register_.id)
+ case X86_OP_MEM:
+ if (dest->mem.base == bad_register_ ||
+ dest->mem.index == bad_register_)
pushed_bad_value_ = true;
break;
- case libdis::op_register:
- if (dest->data.reg.id == bad_register_.id)
+ case X86_OP_REG:
+ if (dest->reg == bad_register_)
pushed_bad_value_ = true;
break;
default:
@@ -173,32 +180,93 @@ uint32_t DisassemblerX86::NextInstruction() {
// For conditional MOVs and XCHGs assume that
// there is a hit.
if (register_valid_) {
- switch (current_instr_.type) {
- case libdis::insn_xor:
- if (src && src->type == libdis::op_register &&
- dest && dest->type == libdis::op_register &&
- src->data.reg.id == bad_register_.id &&
- src->data.reg.id == dest->data.reg.id)
+ switch (current_instr_->id) {
+ case X86_INS_PXOR:
+ case X86_INS_XOR:
+ case X86_INS_XORPD:
+ case X86_INS_XORPS:
+ if (src && src->type == X86_OP_REG &&
+ dest && dest->type == X86_OP_REG &&
+ src->reg == bad_register_ &&
+ src->reg == dest->reg) {
register_valid_ = false;
+ }
break;
- case libdis::insn_pop:
- case libdis::insn_mov:
- case libdis::insn_movcc:
- if (dest && dest->type == libdis::op_register &&
- dest->data.reg.id == bad_register_.id)
+ case X86_INS_POP:
+ case X86_INS_CVTDQ2PS:
+ case X86_INS_CVTPI2PS:
+ case X86_INS_CVTPS2PD:
+ case X86_INS_CVTPS2PI:
+ case X86_INS_CVTTPS2PI:
+ case X86_INS_LAHF:
+ case X86_INS_LDS:
+ case X86_INS_LEA:
+ case X86_INS_LES:
+ case X86_INS_LFS:
+ case X86_INS_LGS:
+ case X86_INS_LSS:
+ case X86_INS_MASKMOVQ:
+ case X86_INS_MOVD:
+ case X86_INS_MOVQ:
+ case X86_INS_MOV:
+ case X86_INS_MOVAPD:
+ case X86_INS_MOVAPS:
+ case X86_INS_MOVHLPS:
+ case X86_INS_MOVHPD:
+ case X86_INS_MOVLHPS:
+ case X86_INS_MOVLPD:
+ case X86_INS_MOVLPS:
+ case X86_INS_MOVMSKPS:
+ case X86_INS_MOVNTI:
+ case X86_INS_MOVNTPS:
+ case X86_INS_MOVNTQ:
+ case X86_INS_MOVSX:
+ case X86_INS_MOVSXD:
+ case X86_INS_MOVUPD:
+ case X86_INS_MOVUPS:
+ case X86_INS_MOVZX:
+ case X86_INS_PSHUFW:
+ case X86_INS_SAHF:
+ case X86_INS_CMOVA:
+ case X86_INS_CMOVBE:
+ case X86_INS_CMOVG:
+ case X86_INS_CMOVGE:
+ case X86_INS_CMOVL:
+ case X86_INS_CMOVLE:
+ case X86_INS_CMOVNO:
+ case X86_INS_CMOVNP:
+ case X86_INS_CMOVNS:
+ case X86_INS_CMOVO:
+ case X86_INS_CMOVP:
+ case X86_INS_CMOVS:
+ case X86_INS_SETA:
+ case X86_INS_SETBE:
+ case X86_INS_SETG:
+ case X86_INS_SETGE:
+ case X86_INS_SETL:
+ case X86_INS_SETLE:
+ case X86_INS_SETNO:
+ case X86_INS_SETNS:
+ case X86_INS_SETO:
+ case X86_INS_SETS:
+ if (dest && dest->type == X86_OP_REG &&
+ dest->reg == bad_register_) {
register_valid_ = false;
+ }
break;
- case libdis::insn_popregs:
+ case X86_INS_POPAW:
register_valid_ = false;
break;
- case libdis::insn_xchg:
- case libdis::insn_xchgcc:
- if (dest && dest->type == libdis::op_register &&
- src && src->type == libdis::op_register) {
- if (dest->data.reg.id == bad_register_.id)
- memcpy(&bad_register_, &src->data.reg, sizeof(libdis::x86_reg_t));
- else if (src->data.reg.id == bad_register_.id)
- memcpy(&bad_register_, &dest->data.reg, sizeof(libdis::x86_reg_t));
+ case X86_INS_BSWAP:
+ case X86_INS_XCHG:
+ case X86_INS_CMPXCHG:
+ case X86_INS_CMPXCHG8B:
+ if (dest && dest->type == X86_OP_REG &&
+ src && src->type == X86_OP_REG) {
+ if (dest->reg == bad_register_)
+ bad_register_ = src->reg;
+ else if (src->reg == bad_register_)
+ bad_register_ = dest->reg;
}
break;
default:
@@ -206,34 +274,67 @@ uint32_t DisassemblerX86::NextInstruction() {
}
}
- return instr_size;
+ return current_instr_->size;
+}
+
+bool DisassemblerX86::currentInstructionIsBlockData() {
+ if (!instr_valid_)
+ return false;
+
+ switch (current_instr_->id) {
+ case X86_INS_CMPSB:
+ case X86_INS_CMPSD:
+ case X86_INS_CMPSQ:
+ case X86_INS_CMPSW:
+ case X86_INS_LODSB:
+ case X86_INS_LODSD:
+ case X86_INS_LODSQ:
+ case X86_INS_LODSW:
+ case X86_INS_MOVSB:
+ case X86_INS_MOVSD:
+ case X86_INS_MOVSQ:
+ case X86_INS_MOVSW:
+ case X86_INS_SCASB:
+ case X86_INS_SCASD:
+ case X86_INS_SCASQ:
+ case X86_INS_SCASW:
+ case X86_INS_STOSB:
+ case X86_INS_STOSD:
+ case X86_INS_STOSQ:
+ case X86_INS_STOSW:
+ case X86_INS_XLATB:
+ return true;
+ default:
+ return false;
+ }
}
bool DisassemblerX86::setBadRead() {
if (!instr_valid_)
return false;
- libdis::x86_op_t *operand = libdis::x86_get_src_operand(&current_instr_);
- if (!operand || operand->type != libdis::op_expression)
+ cs_x86_op* operand = get_operand(current_instr_->detail->x86, 1);
+ if (!operand || operand->type != X86_OP_MEM)
return false;
- memcpy(&bad_register_, &operand->data.expression.base,
- sizeof(libdis::x86_reg_t));
+ bad_register_ = static_cast<x86_reg>(operand->mem.base);
register_valid_ = true;
+
return true;
}
bool DisassemblerX86::setBadWrite() {
+
if (!instr_valid_)
return false;
- libdis::x86_op_t *operand = libdis::x86_get_dest_operand(&current_instr_);
- if (!operand || operand->type != libdis::op_expression)
+ cs_x86_op* operand = get_operand(current_instr_->detail->x86, 0);
+ if (!operand || operand->type != X86_OP_MEM)
return false;
- memcpy(&bad_register_, &operand->data.expression.base,
- sizeof(libdis::x86_reg_t));
+ bad_register_ = static_cast<x86_reg>(operand->mem.base);
register_valid_ = true;
+
return true;
}

Powered by Google App Engine
This is Rietveld 408576698