Skip to content

Commit 7ff2c54

Browse files
committed
CIL: Support calls.
1 parent 0b54394 commit 7ff2c54

11 files changed

Lines changed: 183 additions & 7 deletions

File tree

binary/extractor/cil/Semmle.Extraction.CSharp.IL/ILExtractor.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ private void ExtractMethodBody(MethodDefinition method, int methodId) {
120120
var targetMethodName =
121121
$"{methodRef.DeclaringType.FullName}.{methodRef.Name}";
122122
trap.WriteTuple("il_call_target_unresolved", instrId, targetMethodName);
123+
trap.WriteTuple("il_number_of_arguments", instrId, methodRef.Parameters.Count);
124+
if(methodRef.MethodReturnType.ReturnType.MetadataType is not Mono.Cecil.MetadataType.Void) {
125+
trap.WriteTuple("il_call_has_return_value", instrId);
126+
}
123127
} else if (instruction.Operand is string str) {
124128
trap.WriteTuple("il_operand_string", instrId, str);
125129
} else if (instruction.Operand is sbyte sb) {

binary/ql/lib/semmle/code/binary/ast/internal/CilInstructions.qll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,15 @@ class CilDup extends @il_dup, CilInstruction { }
270270

271271
class CilIl_pop extends @il_il_pop, CilInstruction { }
272272

273-
abstract class CilCall extends CilInstruction { }
273+
abstract class CilCall extends CilInstruction {
274+
final int getNumberOfArguments() { il_number_of_arguments(this, result) }
275+
276+
final predicate hasReturnValue() { il_call_has_return_value(this) }
277+
278+
string getExternalName() {
279+
il_call_target_unresolved(this, result)
280+
}
281+
}
274282

275283
class CilIl_jmp extends @il_il_jmp, CilCall { }
276284

binary/ql/lib/semmle/code/binary/ast/ir/internal/Instruction0/Instruction.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,14 @@ class InstrRefInstruction extends Instruction {
178178
}
179179
}
180180

181+
class ExternalRefInstruction extends Instruction {
182+
override Opcode::ExternalRef opcode;
183+
184+
string getExternalName() { result = te.getExternalName(tag) }
185+
186+
final override string getImmediateValue() { result = this.getExternalName() }
187+
}
188+
181189
class FunEntryInstruction extends Instruction {
182190
override Opcode::FunEntry opcode;
183191
}

binary/ql/lib/semmle/code/binary/ast/ir/internal/Instruction0/InstructionTag.qll

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
private import codeql.util.Boolean
22
private import semmle.code.binary.ast.ir.internal.Opcode
3+
private import semmle.code.binary.ast.internal.CilInstructions
34

45
newtype TInstructionTag =
56
SingleTag() or
@@ -56,7 +57,9 @@ newtype TInstructionTag =
5657
CilBoolBranchConstTag() or
5758
CilBoolBranchCJumpTag() or
5859
CilUnconditionalBranchTag() or
59-
CilUnconditionalBranchRefTag()
60+
CilUnconditionalBranchRefTag() or
61+
CilCallTag() or
62+
CilCallTargetTag()
6063

6164
class InstructionTag extends TInstructionTag {
6265
final string toString() {
@@ -211,6 +214,12 @@ class InstructionTag extends TInstructionTag {
211214
or
212215
this = CilUnconditionalBranchRefTag() and
213216
result = "CilUnconditionalBranchRef"
217+
or
218+
this = CilCallTag() and
219+
result = "CilCall"
220+
or
221+
this = CilCallTargetTag() and
222+
result = "CilCallTarget"
214223
}
215224
}
216225

@@ -224,7 +233,10 @@ private newtype TOperandTag =
224233
TCallTargetTag() or
225234
TCondTag() or
226235
TCondJumpTargetTag() or
227-
TJumpTargetTag()
236+
TJumpTargetTag() or
237+
TCilOperandTag(int i) {
238+
i = [0 .. max(CilCall call, int k | k = call.getNumberOfArguments() - 1 | k)]
239+
}
228240

229241
abstract class OperandTag extends TOperandTag {
230242
abstract int getIndex();
@@ -287,7 +299,10 @@ class StoreAddressTag extends OperandTag, TStoreAddressTag {
287299
class CallTargetTag extends OperandTag, TCallTargetTag {
288300
final override int getIndex() { result = 0 }
289301

290-
final override OperandTag getSuccessorTag() { none() }
302+
final override OperandTag getSuccessorTag() {
303+
// Note: This will be `none` on x86 DBs.
304+
result.(CilOperandTag).getCilIndex() = 0
305+
}
291306

292307
final override string toString() { result = "CallTarget" }
293308
}
@@ -315,3 +330,18 @@ class JumpTargetTag extends OperandTag, TJumpTargetTag {
315330

316331
final override string toString() { result = "JumpTarget" }
317332
}
333+
334+
class CilOperandTag extends OperandTag, TCilOperandTag {
335+
final override int getIndex() { result = this.getCilIndex() }
336+
337+
final int getCilIndex() { this = TCilOperandTag(result) }
338+
339+
final override OperandTag getSuccessorTag() {
340+
exists(int i |
341+
this = TCilOperandTag(i) and
342+
result = TCilOperandTag(i + 1)
343+
)
344+
}
345+
346+
final override string toString() { result = "CilOperand(" + this.getIndex().toString() + ")" }
347+
}

binary/ql/lib/semmle/code/binary/ast/ir/internal/Instruction0/TempVariableTag.qll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ newtype TTempVariableTag =
2828
CilBoolBranchConstVarTag() or
2929
CilBoolBranchSubVarTag() or
3030
CilBoolBranchRefVarTag() or
31-
CilUnconditionalBranchRefVarTag()
31+
CilUnconditionalBranchRefVarTag() or
32+
CallReturnValueTag() or
33+
CilCallTargetVarTag()
3234

3335
class TempVariableTag extends TTempVariableTag {
3436
string toString() {
@@ -121,5 +123,11 @@ class TempVariableTag extends TTempVariableTag {
121123
or
122124
this = CilBoolBranchRefVarTag() and
123125
result = "cbb_ir"
126+
or
127+
this = CallReturnValueTag() and
128+
result = "call_ret"
129+
or
130+
this = CilCallTargetVarTag() and
131+
result = "call_target"
124132
}
125133
}

binary/ql/lib/semmle/code/binary/ast/ir/internal/Instruction0/TranslatedElement.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ newtype TTranslatedElement =
8989
TTranslatedCilBooleanBranchInstruction(Raw::CilBooleanBranchInstruction cbr) {
9090
shouldTranslateCilInstr(cbr)
9191
} or
92-
TTranslatedCilRet(Raw::CilIl_ret ret) { shouldTranslateCilInstr(ret) }
92+
TTranslatedCilRet(Raw::CilIl_ret ret) { shouldTranslateCilInstr(ret) } or
93+
TTranslatedCilCall(Raw::CilCall call) { shouldTranslateCilInstr(call) }
9394

9495
TranslatedElement getTranslatedElement(Raw::Element raw) {
9596
result.getRawElement() = raw and
@@ -125,6 +126,8 @@ abstract class TranslatedElement extends TTranslatedElement {
125126

126127
int getConstantValue(InstructionTag tag) { none() }
127128

129+
string getExternalName(InstructionTag tag) { none() }
130+
128131
Instruction getReferencedInstruction(InstructionTag tag) { none() }
129132

130133
abstract Raw::Element getRawElement();

binary/ql/lib/semmle/code/binary/ast/ir/internal/Instruction0/TranslatedInstruction.qll

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,3 +2198,88 @@ class TranslatedCilRet extends TranslatedCilInstruction, TTranslatedCilRet {
21982198
)
21992199
}
22002200
}
2201+
2202+
class TranslatedCilCall extends TranslatedCilInstruction, TTranslatedCilCall {
2203+
override Raw::CilCall instr;
2204+
2205+
TranslatedCilCall() { this = TTranslatedCilCall(instr) }
2206+
2207+
final override predicate hasInstruction(
2208+
Opcode opcode, InstructionTag tag, Option<Variable>::Option v
2209+
) {
2210+
opcode instanceof Opcode::Call and
2211+
tag = CilCallTag() and
2212+
if instr.hasReturnValue()
2213+
then v.asSome() = this.getVariable(CallReturnValueTag())
2214+
else v.isNone()
2215+
or
2216+
opcode instanceof Opcode::ExternalRef and
2217+
tag = CilCallTargetTag() and
2218+
v.asSome() = this.getVariable(CilCallTargetVarTag())
2219+
}
2220+
2221+
override predicate hasTempVariable(TempVariableTag tag) {
2222+
instr.hasReturnValue() and
2223+
tag = CallReturnValueTag()
2224+
or
2225+
tag = CilCallTargetVarTag()
2226+
}
2227+
2228+
override predicate producesResult() { any() }
2229+
2230+
override Variable getVariableOperand(InstructionTag tag, OperandTag operandTag) {
2231+
tag = CilCallTag() and
2232+
(
2233+
exists(int index |
2234+
operandTag.(CilOperandTag).getIndex() = index and
2235+
getTranslatedCilInstruction(instr.getABackwardPredecessor()).getStackElement(index) = result
2236+
)
2237+
or
2238+
operandTag instanceof CallTargetTag and
2239+
result = this.getInstruction(CilCallTargetTag()).getResultVariable()
2240+
)
2241+
}
2242+
2243+
override string getExternalName(InstructionTag tag) {
2244+
tag = CilCallTargetTag() and
2245+
result = instr.getExternalName()
2246+
}
2247+
2248+
override Instruction getChildSuccessor(TranslatedElement child, SuccessorType succType) { none() }
2249+
2250+
override Instruction getSuccessor(InstructionTag tag, SuccessorType succType) {
2251+
tag = CilCallTargetTag() and
2252+
succType instanceof DirectSuccessor and
2253+
result = this.getInstruction(CilCallTag())
2254+
or
2255+
tag = CilCallTag() and
2256+
succType instanceof DirectSuccessor and
2257+
result = getTranslatedInstruction(instr.getASuccessor()).getEntry()
2258+
}
2259+
2260+
override Instruction getEntry() { result = this.getInstruction(CilCallTargetTag()) }
2261+
2262+
override Variable getResultVariable() {
2263+
instr.hasReturnValue() and
2264+
result = this.getVariable(CallReturnValueTag())
2265+
}
2266+
2267+
final override Variable getStackElement(int i) {
2268+
if instr.hasReturnValue()
2269+
then
2270+
// If the call has a return value, it will be on top of the stack
2271+
if i = 0
2272+
then result = this.getInstruction(CilCallTag()).getResultVariable()
2273+
else
2274+
// Otherwise, get the stack element from the predecessor. However, the call also popped the arguments
2275+
// off the stack, so we need to adjust the index accordingly.
2276+
result =
2277+
getTranslatedCilInstruction(instr.getABackwardPredecessor())
2278+
.getStackElement(i + instr.getNumberOfArguments() - 1)
2279+
else
2280+
// If the call has no return value, just get the stack element from the predecessor, adjusting for the popped arguments.
2281+
result =
2282+
getTranslatedCilInstruction(instr.getABackwardPredecessor())
2283+
.getStackElement(i + instr.getNumberOfArguments())
2284+
}
2285+
}

binary/ql/lib/semmle/code/binary/ast/ir/internal/InstructionSig.qll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ signature module InstructionSig {
9393

9494
Operand getAnAccess();
9595
}
96-
96+
9797
predicate variableHasOrdering(Variable v, int ordering);
9898

9999
class TempVariable extends Variable;
@@ -176,6 +176,10 @@ signature module InstructionSig {
176176

177177
class InitInstruction extends Instruction;
178178

179+
class ExternalRefInstruction extends Instruction {
180+
string getExternalName();
181+
}
182+
179183
class SubInstruction extends BinaryInstruction;
180184

181185
class AddInstruction extends BinaryInstruction;

binary/ql/lib/semmle/code/binary/ast/ir/internal/Opcode.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ private newtype TOpcode =
2525
TNot() or
2626
TInit() or
2727
TInstrRef() or
28+
// TODO: Ideally, this should either be removed when we handle unresolved CIL calls better.
29+
TExternalRef() or
2830
TFunEntry()
2931

3032
class Opcode extends TOpcode {
@@ -139,6 +141,10 @@ class InstrRef extends Opcode, TInstrRef {
139141
override string toString() { result = "InstrRef" }
140142
}
141143

144+
class ExternalRef extends Opcode, TExternalRef {
145+
override string toString() { result = "ExternalRef" }
146+
}
147+
142148
class Init extends Opcode, TInit {
143149
override string toString() { result = "Init" }
144150
}

binary/ql/lib/semmle/code/binary/ast/ir/internal/TransformInstruction/TransformInstruction.qll

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,17 @@ module Transform<InstructionSig Input> {
719719
}
720720
}
721721

722+
class ExternalRefInstruction extends Instruction {
723+
ExternalRefInstruction() { this.getOpcode() instanceof Opcode::ExternalRef }
724+
725+
string getExternalName() {
726+
exists(Input::ExternalRefInstruction extRef |
727+
this = TOldInstruction(extRef) and
728+
result = extRef.getExternalName()
729+
)
730+
}
731+
}
732+
722733
private class NewInstruction extends MkInstruction, Instruction {
723734
Opcode opcode;
724735
TranslatedElement te;

0 commit comments

Comments
 (0)