Try to handle signed and unsigned 16-bit accessors.

Not sure whether it makes much sense, seeing as some
accessors (e.g. wear) actually return 32-bit values,
assuming that the caller would correctly sign-extend
the lower half and discard the upper.
develop
Alexander Gavrilov 2011-04-10 22:44:01 +04:00
parent f6ae41fe49
commit fbf76440b5
1 changed files with 30 additions and 32 deletions

@ -51,13 +51,19 @@ enum accessor_type {ACCESSOR_CONSTANT, ACCESSOR_INDIRECT, ACCESSOR_DOUBLE_INDIRE
/* this is used to store data about the way accessors work */ /* this is used to store data about the way accessors work */
class DFHACK_EXPORT Accessor class DFHACK_EXPORT Accessor
{ {
public:
enum DataWidth {
Data32 = 0,
DataSigned16,
DataUnsigned16
};
private: private:
accessor_type type; accessor_type type;
int32_t constant; int32_t constant;
int32_t offset1; int32_t offset1;
int32_t offset2; int32_t offset2;
Process * p; Process * p;
uint32_t dataWidth; DataWidth dataWidth;
public: public:
Accessor(uint32_t function, Process * p); Accessor(uint32_t function, Process * p);
Accessor(accessor_type type, int32_t constant, uint32_t offset1, uint32_t offset2, uint32_t dataWidth, Process * p); Accessor(accessor_type type, int32_t constant, uint32_t offset1, uint32_t offset2, uint32_t dataWidth, Process * p);
@ -134,10 +140,10 @@ static bool match_MEM_ACCESS(uint32_t &ptr, uint64_t v, int isize, int in_reg, i
} }
} }
static bool match_MOV_MEM(uint32_t &ptr, uint64_t v, int in_reg, int &out_reg, int &offset, bool &size16) static bool match_MOV_MEM(uint32_t &ptr, uint64_t v, int in_reg, int &out_reg, int &offset, Accessor::DataWidth &size)
{ {
int prefix = 0; int prefix = 0;
size16 = false; size = Accessor::Data32;
if ((v & 0xFF) == 0x8B) { // MOV if ((v & 0xFF) == 0x8B) { // MOV
v >>= 8; v >>= 8;
prefix = 1; prefix = 1;
@ -145,17 +151,17 @@ static bool match_MOV_MEM(uint32_t &ptr, uint64_t v, int in_reg, int &out_reg, i
else if ((v & 0xFFFF) == 0x8B66) { // MOV 16-bit else if ((v & 0xFFFF) == 0x8B66) { // MOV 16-bit
v >>= 16; v >>= 16;
prefix = 2; prefix = 2;
size16 = true; size = Accessor::DataUnsigned16;
} }
else if ((v & 0xFFFF) == 0xBF0F) { // MOVSX else if ((v & 0xFFFF) == 0xBF0F) { // MOVSX
v >>= 16; v >>= 16;
prefix = 2; prefix = 2;
size16 = true; size = Accessor::DataSigned16;
} }
else if ((v & 0xFFFF) == 0xB70F) { // MOVZ else if ((v & 0xFFFF) == 0xB70F) { // MOVZ
v >>= 16; v >>= 16;
prefix = 2; prefix = 2;
size16 = true; size = Accessor::DataUnsigned16;
} }
else else
return false; return false;
@ -190,7 +196,7 @@ Accessor::Accessor(uint32_t function, Process *p)
} }
else else
{ {
bool size16; DataWidth xsize;
int ptr_reg = 1, tmp; // ECX int ptr_reg = 1, tmp; // ECX
// MOV REG,[ESP+4] // MOV REG,[ESP+4]
@ -200,24 +206,19 @@ Accessor::Accessor(uint32_t function, Process *p)
v = p->readQuad(ptr); v = p->readQuad(ptr);
} }
this->dataWidth = 4; if (match_MOV_MEM(ptr, v, ptr_reg, tmp, this->offset1, xsize)) {
if (match_MOV_MEM(ptr, v, ptr_reg, tmp, this->offset1, size16)) {
data_reg = tmp; data_reg = tmp;
this->type = ACCESSOR_INDIRECT; this->type = ACCESSOR_INDIRECT;
this->dataWidth = xsize;
if (size16) if (xsize == Data32)
this->dataWidth = 2;
else
{ {
v = p->readQuad(ptr); v = p->readQuad(ptr);
if (match_MOV_MEM(ptr, v, data_reg, tmp, this->offset2, size16)) { if (match_MOV_MEM(ptr, v, data_reg, tmp, this->offset2, xsize)) {
data_reg = tmp; data_reg = tmp;
this->type = ACCESSOR_DOUBLE_INDIRECT; this->type = ACCESSOR_DOUBLE_INDIRECT;
this->dataWidth = xsize;
if (size16)
this->dataWidth = 2;
} }
} }
} }
@ -245,29 +246,26 @@ bool Accessor::isConstant()
int32_t Accessor::getValue(uint32_t objectPtr) int32_t Accessor::getValue(uint32_t objectPtr)
{ {
int32_t offset = this->offset1;
switch(this->type) switch(this->type)
{ {
case ACCESSOR_CONSTANT: case ACCESSOR_CONSTANT:
return this->constant; return this->constant;
break; break;
case ACCESSOR_INDIRECT:
switch(this->dataWidth)
{
case 2:
return (int16_t) p->readWord(objectPtr + this->offset1);
case 4:
return p->readDWord(objectPtr + this->offset1);
default:
return -1;
}
break;
case ACCESSOR_DOUBLE_INDIRECT: case ACCESSOR_DOUBLE_INDIRECT:
objectPtr = p->readDWord(objectPtr + this->offset1);
offset = this->offset2;
// fallthrough
case ACCESSOR_INDIRECT:
switch(this->dataWidth) switch(this->dataWidth)
{ {
case 2: case Data32:
return (int16_t) p->readWord(p->readDWord(objectPtr + this->offset1) + this->offset2); return p->readDWord(objectPtr + offset);
case 4: case DataSigned16:
return p->readDWord(p->readDWord(objectPtr + this->offset1) + this->offset2); return (int16_t) p->readWord(objectPtr + offset);
case DataUnsigned16:
return (uint16_t) p->readWord(objectPtr + offset);
default: default:
return -1; return -1;
} }