Files
fail/src/experiments/l4-sys/aluinstr.cc
2012-10-05 12:02:39 +00:00

157 lines
5.0 KiB
C++

#include "aluinstr.hpp"
#include <iostream>
#include <sstream>
#include <string.h>
#include <time.h>
#include "bochs.h"
#include "cpu/cpu.h"
#include "cpu/fetchdecode.h"
/**
* Forward declaration of the Bochs instruction decode table.
* This is necessary because, inconveniently, it is not declared in a header file.
*/
//extern bxIAOpcodeTable *BxOpcodesTable;
bxIAOpcodeTable MyBxOpcodesTable[] = {
#define bx_define_opcode(a, b, c, d, e) { b, c, e },
#include "cpu/ia_opcodes.h"
};
#undef bx_define_opcode
BochsALUInstructions::BochsALUInstructions(BochsALUInstr const *initial_array, size_t array_size)
{
allInstr = reinterpret_cast<BochsALUInstr*>(malloc(array_size));
memcpy(allInstr, initial_array, array_size);
allInstrSize = array_size / sizeof(BochsALUInstr);
srand(time(NULL));
buildEquivalenceClasses();
}
void BochsALUInstructions::buildEquivalenceClasses() {
for (size_t i = 0; i < allInstrSize; i++) {
InstrList &currVector = equivalenceClasses[allInstr[i].aluClass];
if (allInstr[i].opcodeRegisterOffset <= BochsALUInstr::REG_COUNT) {
// add an entry for each possible opcode
for (int j = 0; j < allInstr[i].opcodeRegisterOffset; j++) {
BochsALUInstr newInstr = { allInstr[i].bochs_operation,
allInstr[i].opcode + j,
allInstr[i].reg,
j,
allInstr[i].aluClass };
currVector.push_back(newInstr);
}
} else {
// normal case -- just add the instruction
currVector.push_back(allInstr[i]);
}
}
}
void BochsALUInstructions::bochsInstrToInstrStruct(bxInstruction_c const &src, BochsALUInstr &dest) const {
//Note: it may be necessary to introduce a solution for two-byte
//opcodes once they overlap with one-byte ones
for (size_t i = 0; i < allInstrSize; i++) {
// first, check the opcode
if (allInstr[i].opcodeRegisterOffset <= BochsALUInstr::REG_COUNT) {
// the opcode listed in allInstr is the starting value for a range
if (src.b1() < allInstr[i].opcode ||
src.b1() > allInstr[i].opcode + BochsALUInstr::REG_COUNT) {
continue;
}
} else if (src.b1() != allInstr[i].opcode) {
// normal case -- just compare the opcode
continue;
}
// second, check the opcode extension
if (allInstr[i].reg < BochsALUInstr::REG_COUNT &&
allInstr[i].reg != src.nnn()) {
continue;
}
// found it - now copy
if (allInstr[i].opcodeRegisterOffset <= BochsALUInstr::REG_COUNT) {
dest.bochs_operation = allInstr[i].bochs_operation;
dest.opcode = src.b1();
dest.reg = allInstr[i].reg;
dest.opcodeRegisterOffset = src.rm();
dest.aluClass = allInstr[i].aluClass;
} else {
dest = allInstr[i];
}
return;
}
// not found - marking it undefined
dest.aluClass = ALU_UNDEF;
}
bool BochsALUInstructions::isALUInstruction(bxInstruction_c const *src) {
memcpy(&lastOrigInstr, src, sizeof(bxInstruction_c));
bochsInstrToInstrStruct(lastOrigInstr, lastInstr);
if (lastInstr.aluClass != ALU_UNDEF) {
return true;
}
return false;
}
void BochsALUInstructions::randomEquivalent(bxInstruction_c &result,
std::string &details) const {
// find a random member of the same equivalence class
X86AluClass equClassID = lastInstr.aluClass;
if (equClassID == ALU_UNDEF) {
// something went wrong - just return the original instruction
result = lastOrigInstr;
return;
}
InstrList const &destList = equivalenceClasses.at(equClassID);
BochsALUInstr dest;
// make sure the two are not equal by chance
do {
int index = rand() % destList.size();
dest = destList[index];
} while (memcmp(&dest, &lastInstr, sizeof(BochsALUInstr)) == 0);
// alternative chosen -- now store the necessary details
std::ostringstream oss;
oss << "Opcode 0x" << std::hex << static_cast<unsigned>(dest.opcode) << std::dec;
if (dest.reg < dest.REG_COUNT) oss << " # " << static_cast<unsigned>(dest.reg);
if (dest.opcodeRegisterOffset <= dest.REG_COUNT)
oss << " # " << static_cast<unsigned>(dest.opcodeRegisterOffset);
details = oss.str();
// first, copy everything
result = lastOrigInstr;
// then change what has to be different
// execute functions
bxIAOpcodeTable entry = MyBxOpcodesTable[dest.bochs_operation];
if (result.execute2 == NULL) {
result.execute = entry.execute2;
} else {
result.execute = entry.execute1;
result.execute2 = entry.execute2;
}
// opcodes
result.metaInfo.ia_opcode = dest.bochs_operation;
result.setB1(dest.opcode);
if (dest.opcodeRegisterOffset < BochsALUInstr::REG_COUNT) {
result.setRm(dest.opcodeRegisterOffset);
}
}
#ifdef DEBUG
void BochsALUInstructions::printNestedMap() {
for (EquivClassMap::iterator it = equivalenceClasses.begin();
it != equivalenceClasses.end(); it++) {
std::cerr << it->first << ":" << std::endl;
for (InstrList::iterator jt = it->second.begin();
jt != it->second.end(); jt++) {
std::cerr << std::hex << " " << jt->bochs_operation
<< "," << (unsigned) jt->opcode << std::dec << "," << (unsigned) jt->reg
<< "," << (unsigned) jt->opcodeRegisterOffset << ","
<< jt->aluClass << std::endl;
}
}
}
#endif