Skip to content

Commit

Permalink
Fix implementations for AMD GPU CFWidget::apply
Browse files Browse the repository at this point in the history
This commit mainly touches logic on determining pc-relative/absolute
branch, patching of existing s_branch/s_cbranch/s_setpc/s_swappc
instructions.
  • Loading branch information
bbiiggppiigg committed Apr 17, 2024
1 parent cf43cca commit 744c5ea
Show file tree
Hide file tree
Showing 4 changed files with 288 additions and 253 deletions.
77 changes: 52 additions & 25 deletions common/src/arch-amdgpu.C
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ namespace NS_amdgpu {
ATOMIC_t ATOMIC;
UNCOND_BR_t UNCOND_BR;
COND_BR_t COND_BR;
ABSOLUTE_BR_t ABSOLUTE_BR;
PC_RELATIVE_BR_t PC_RELATIVE_BR;


unsigned int swapBytesIfNeeded(unsigned int i)
{
Expand Down Expand Up @@ -69,6 +72,7 @@ instruction *instruction::copy() const {
}

unsigned instruction::getTargetReg() const {
assert(0);
if( isBranchReg() ){
// for this instruction, the reg contains the target address directly.
return getBranchTargetReg();
Expand Down Expand Up @@ -107,24 +111,60 @@ void instruction::setInstruction(unsigned char *ptr, Dyninst::Address) {
}

bool instruction::isBranchReg() const{
assert(0);
return CHECK_INST(UNCOND_BR.REG );
}

bool instruction::isUncondBranch() const {
if( CHECK_INST(UNCOND_BR.IMM ) == true
|| CHECK_INST(UNCOND_BR.REG ) == true
)
if( CHECK_INST(UNCOND_BR.S_BRANCH) == true
|| CHECK_INST(UNCOND_BR.S_SETPC_B64) == true
|| CHECK_INST(UNCOND_BR.S_SWAPPC_B64) == true
)
return true;

return false;
}

bool instruction::isCondBranch() const {
if( CHECK_INST(COND_BR.CB) == true ||
CHECK_INST(COND_BR.BR) == true ||
CHECK_INST(COND_BR.TB) == true )
bool instruction::isPCRelativeBranch() const {
if(
CHECK_INST(PC_RELATIVE_BR.S_BRANCH) == true ||
CHECK_INST(PC_RELATIVE_BR.S_CBRANCH_SCC0) == true ||
CHECK_INST(PC_RELATIVE_BR.S_CBRANCH_SCC1) == true ||
CHECK_INST(PC_RELATIVE_BR.S_CBRANCH_VCCZ) == true ||
CHECK_INST(PC_RELATIVE_BR.S_CBRANCH_VCCNZ) == true ||
CHECK_INST(PC_RELATIVE_BR.S_CBRANCH_EXECZ) == true ||
CHECK_INST(PC_RELATIVE_BR.S_CBRANCH_EXECNZ) == true ||
CHECK_INST(PC_RELATIVE_BR.S_CBRANCH_CDBGSYS) == true ||
CHECK_INST(PC_RELATIVE_BR.S_CBRANCH_CDBGUSER) == true ||
CHECK_INST(PC_RELATIVE_BR.S_CBRANCH_CDBGSYS_OR_USER) == true ||
CHECK_INST(PC_RELATIVE_BR.S_CBRANCH_CDBGSYS_AND_USER) == true
)
return true;
return false;
}

bool instruction::isAbsoluteBranch() const {
if(
CHECK_INST(ABSOLUTE_BR.S_SETPC_B64) == true ||
CHECK_INST(ABSOLUTE_BR.S_SWAPPC_B64) == true
)
return true;
return false;
}

bool instruction::isCondBranch() const {
if( CHECK_INST(COND_BR.S_CBRANCH_SCC0) == true ||
CHECK_INST(COND_BR.S_CBRANCH_SCC1) == true ||
CHECK_INST(COND_BR.S_CBRANCH_VCCZ) == true ||
CHECK_INST(COND_BR.S_CBRANCH_VCCNZ) == true ||
CHECK_INST(COND_BR.S_CBRANCH_EXECZ) == true ||
CHECK_INST(COND_BR.S_CBRANCH_EXECNZ) == true ||
CHECK_INST(COND_BR.S_CBRANCH_CDBGSYS) == true ||
CHECK_INST(COND_BR.S_CBRANCH_CDBGUSER) == true ||
CHECK_INST(COND_BR.S_CBRANCH_CDBGSYS_OR_USER) == true ||
CHECK_INST(COND_BR.S_CBRANCH_CDBGSYS_AND_USER) == true
)
return true;
return false;
}

Expand Down Expand Up @@ -180,6 +220,7 @@ bool instruction::isThunk() const {
}

unsigned instruction::getBranchTargetReg() const{
assert(0);
// keep sure this instruction is uncond b reg.
assert( isUncondBranch() );
unsigned regNum;
Expand All @@ -197,25 +238,11 @@ unsigned instruction::getBranchTargetReg() const{
}

Dyninst::Address instruction::getBranchOffset() const {
if (isUncondBranch()) {
if( CHECK_INST(UNCOND_BR.IMM) ){
return signExtend(GET_OFFSET32(UNCOND_BR.IMM), 26+2 );
}
if( CHECK_INST(UNCOND_BR.REG) ){
// branch reg doesn't return offset.
assert(0);
}
if (isAbsoluteBranch()){
assert(0);
}
else if (isCondBranch()) {
if( CHECK_INST(COND_BR.CB) ){
return signExtend(GET_OFFSET32(COND_BR.CB),19+2 );
}
if( CHECK_INST(COND_BR.TB) ){
return signExtend(GET_OFFSET32(COND_BR.TB),14+2 );
}
if( CHECK_INST(COND_BR.BR) ){
return signExtend(GET_OFFSET32(COND_BR.BR),19+2 );
}
else if (isPCRelativeBranch()) {
return signExtend(GET_OFFSET32(PC_RELATIVE_BR.S_BRANCH),16+2);
}
assert(0); //never goes here.
return 0;
Expand Down
125 changes: 125 additions & 0 deletions common/src/arch-amdgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,16 @@ class UNCOND_BR_t {
static insn_mask REG =(0xd6000000);
static insn_mask REG_OFFSET_MASK =(0x000001e0);
static insn_mask REG_OFFSHIFT =5;

static insn_mask S_BRANCH_MASK =(0xffff0000);
static insn_mask S_BRANCH =(0xbf820000);

static insn_mask S_SETPC_B64_MASK =(0xff80ff00);
static insn_mask S_SETPC_B64 =(0xbe801d00);

static insn_mask S_SWAPPC_B64_MASK =(0xff80ff00);
static insn_mask S_SWAPPC_B64 =(0xbe801e00);

};


Expand All @@ -162,6 +172,118 @@ class COND_BR_t {
static insn_mask CB_OFFSHIFT = 4;
static insn_mask TB_OFFSHIFT = 4;
static insn_mask BR_OFFSHIFT = 4;

static insn_mask S_BRANCH_MASK =(0xffff0000);
static insn_mask S_BRANCH =(0xbf820000);


static insn_mask S_CBRANCH_SCC0_MASK =(0xffff0000);
static insn_mask S_CBRANCH_SCC0 =(0xbf840000);
static insn_mask S_CBRANCH_SCC1_MASK =(0xffff0000);
static insn_mask S_CBRANCH_SCC1 =(0xbf850000);
static insn_mask S_CBRANCH_VCCZ_MASK =(0xffff0000);
static insn_mask S_CBRANCH_VCCZ =(0xbf860000);
static insn_mask S_CBRANCH_VCCNZ_MASK =(0xffff0000);
static insn_mask S_CBRANCH_VCCNZ =(0xbf870000);
static insn_mask S_CBRANCH_EXECZ_MASK =(0xffff0000);
static insn_mask S_CBRANCH_EXECZ =(0xbf880000);
static insn_mask S_CBRANCH_EXECNZ_MASK =(0xffff0000);
static insn_mask S_CBRANCH_EXECNZ =(0xbf890000);
static insn_mask S_CBRANCH_CDBGSYS_MASK =(0xffff0000);
static insn_mask S_CBRANCH_CDBGSYS =(0xbf970000);
static insn_mask S_CBRANCH_CDBGUSER_MASK =(0xffff0000);
static insn_mask S_CBRANCH_CDBGUSER =(0xbf980000);
static insn_mask S_CBRANCH_CDBGSYS_OR_USER_MASK =(0xffff0000);
static insn_mask S_CBRANCH_CDBGSYS_OR_USER =(0xbf990000);
static insn_mask S_CBRANCH_CDBGSYS_AND_USER_MASK =(0xffff0000);
static insn_mask S_CBRANCH_CDBGSYS_AND_USER =(0xbf9a0000);

static insn_mask S_CBRANCH_SCC0_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_SCC1_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_VCCZ_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_VCCNZ_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_EXECZ_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_EXECNZ_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_CDBGSYS_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_CDBGUSER_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_CDBGSYS_OR_USER_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_CDBGSYS_AND_USER_OFFSET_MASK =(0x0000ffff);

static insn_mask S_CBRANCH_SCC0_OFFSHIFT =0;
static insn_mask S_CBRANCH_SCC1_OFFSHIFT =0;
static insn_mask S_CBRANCH_VCCZ_OFFSHIFT =0;
static insn_mask S_CBRANCH_VCCNZ_OFFSHIFT =0;
static insn_mask S_CBRANCH_EXECZ_OFFSHIFT =0;
static insn_mask S_CBRANCH_EXECNZ_OFFSHIFT =0;
static insn_mask S_CBRANCH_CDBGSYS_OFFSHIFT =0;
static insn_mask S_CBRANCH_CDBGUSER_OFFSHIFT =0;
static insn_mask S_CBRANCH_CDBGSYS_OR_USER_OFFSHIFT =0;
static insn_mask S_CBRANCH_CDBGSYS_AND_USER_OFFSHIFT =0;
};

class ABSOLUTE_BR_t {
public:
static insn_mask S_SETPC_B64_MASK =(0xff80ff00);
static insn_mask S_SETPC_B64 =(0xbe801d00);

static insn_mask S_SWAPPC_B64_MASK =(0xff80ff00);
static insn_mask S_SWAPPC_B64 =(0xbe801e00);
};



class PC_RELATIVE_BR_t {
public:
static insn_mask S_BRANCH_MASK =(0xffff0000);
static insn_mask S_BRANCH =(0xbf820000);

static insn_mask S_CBRANCH_SCC0_MASK =(0xffff0000);
static insn_mask S_CBRANCH_SCC0 =(0xbf840000);
static insn_mask S_CBRANCH_SCC1_MASK =(0xffff0000);
static insn_mask S_CBRANCH_SCC1 =(0xbf850000);
static insn_mask S_CBRANCH_VCCZ_MASK =(0xffff0000);
static insn_mask S_CBRANCH_VCCZ =(0xbf860000);
static insn_mask S_CBRANCH_VCCNZ_MASK =(0xffff0000);
static insn_mask S_CBRANCH_VCCNZ =(0xbf870000);
static insn_mask S_CBRANCH_EXECZ_MASK =(0xffff0000);
static insn_mask S_CBRANCH_EXECZ =(0xbf880000);
static insn_mask S_CBRANCH_EXECNZ_MASK =(0xffff0000);
static insn_mask S_CBRANCH_EXECNZ =(0xbf890000);
static insn_mask S_CBRANCH_CDBGSYS_MASK =(0xffff0000);
static insn_mask S_CBRANCH_CDBGSYS =(0xbf970000);
static insn_mask S_CBRANCH_CDBGUSER_MASK =(0xffff0000);
static insn_mask S_CBRANCH_CDBGUSER =(0xbf980000);
static insn_mask S_CBRANCH_CDBGSYS_OR_USER_MASK =(0xffff0000);
static insn_mask S_CBRANCH_CDBGSYS_OR_USER =(0xbf990000);
static insn_mask S_CBRANCH_CDBGSYS_AND_USER_MASK =(0xffff0000);
static insn_mask S_CBRANCH_CDBGSYS_AND_USER =(0xbf9a0000);



static insn_mask S_BRANCH_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_SCC0_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_SCC1_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_VCCZ_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_VCCNZ_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_EXECZ_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_EXECNZ_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_CDBGSYS_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_CDBGUSER_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_CDBGSYS_OR_USER_OFFSET_MASK =(0x0000ffff);
static insn_mask S_CBRANCH_CDBGSYS_AND_USER_OFFSET_MASK =(0x0000ffff);


static insn_mask S_BRANCH_OFFSHIFT =0;
static insn_mask S_CBRANCH_SCC0_OFFSHIFT =0;
static insn_mask S_CBRANCH_SCC1_OFFSHIFT =0;
static insn_mask S_CBRANCH_VCCZ_OFFSHIFT =0;
static insn_mask S_CBRANCH_VCCNZ_OFFSHIFT =0;
static insn_mask S_CBRANCH_EXECZ_OFFSHIFT =0;
static insn_mask S_CBRANCH_EXECNZ_OFFSHIFT =0;
static insn_mask S_CBRANCH_CDBGSYS_OFFSHIFT =0;
static insn_mask S_CBRANCH_CDBGUSER_OFFSHIFT =0;
static insn_mask S_CBRANCH_CDBGSYS_OR_USER_OFFSHIFT =0;
static insn_mask S_CBRANCH_CDBGSYS_AND_USER_OFFSHIFT =0;
};

typedef union {
Expand Down Expand Up @@ -280,6 +402,9 @@ class COMMON_EXPORT instruction {
bool isUncondBranch() const;
bool isThunk() const;

bool isPCRelativeBranch() const;
bool isAbsoluteBranch() const;


bool isCleaningRet() const {return false; }

Expand Down
55 changes: 55 additions & 0 deletions dyninstAPI/src/Relocation/Widgets/CFWidget-amdgpu.C
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,61 @@ bool CFWidget::generateIndirectCall(CodeBuffer &buffer,
}

bool CFPatch::apply(codeGen &gen, CodeBuffer *buf) {
// Otherwise this is a classic, and therefore easy.
int targetLabel = target->label(buf);

relocation_cerr << "\t\t CFPatch::apply, type " << type << ", origAddr " << hex << origAddr_
<< ", and label " << dec << targetLabel << endl;
if (orig_insn.isValid()) {
relocation_cerr << "\t\t\t Currently at " << hex << gen.currAddr() << " and targeting predicted " << buf->predictedAddr(targetLabel) << dec << endl;
switch(type) {
case CFPatch::Jump: {
relocation_cerr << "\t\t\t Generating CFPatch::Jump from "
<< hex << gen.currAddr() << " to " << buf->predictedAddr(targetLabel) << dec << endl;
if (!insnCodeGen::modifyJump(buf->predictedAddr(targetLabel), *ugly_insn, gen)) {
cerr << "Failed to modify jump" << endl;
return false;
}
return true;
}
case CFPatch::JCC: {
relocation_cerr << "\t\t\t Generating CFPatch::JCC from "
<< hex << gen.currAddr() << " to " << buf->predictedAddr(targetLabel) << dec << endl;
if (!insnCodeGen::modifyJcc(buf->predictedAddr(targetLabel), *ugly_insn, gen)) {
cerr << "Failed to modify conditional jump" << endl;
return false;
}
return true;
}
case CFPatch::Call: {
if (!insnCodeGen::modifyCall(buf->predictedAddr(targetLabel), *ugly_insn, gen)) {
cerr << "Failed to modify call" << endl;
return false;
}
return true;
}
case CFPatch::Data: {
// According to the comments in the aarch64 implementation
// This is for PC-relative call, and should only be applicable to x86_64,
// Even though it specifies ADR instruction which exists in ARM as well
assert(0 && "Trying to apply patch for PC-relative call for AMD GPU");
}
}
}
else {
switch(type) {
case CFPatch::Jump:
insnCodeGen::generateBranch(gen, gen.currAddr(), buf->predictedAddr(targetLabel));
break;
case CFPatch::Call:
insnCodeGen::generateCall(gen, gen.currAddr(), buf->predictedAddr(targetLabel));
break;
default:
assert(0);
}
}


return true;
}

Expand Down

0 comments on commit 744c5ea

Please sign in to comment.