C++: Use parameterized modules instead of abstract classes and predicates to handle debug printing.

This commit is contained in:
Mathias Vorreiter Pedersen
2023-12-19 11:08:41 +01:00
parent 501645920f
commit 9b25834771
4 changed files with 78 additions and 75 deletions

View File

@@ -1,9 +1,21 @@
/**
* This file activates debugging mode for dataflow node printing.
* This file contains module that implements the _debug_ version of
* `toString` for `Instruction` and `Operand` dataflow nodes.
*/
private import Node0ToString
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import Node0ToStringSig
private import DataFlowUtil
private class DebugNode0ToString extends Node0ToString {
final override predicate isDebugMode() { any() }
private module DebugNode0ToString implements Node0ToStringSig {
string instructionToString(Instruction i) { result = i.getDumpString() }
string operandToString(Operand op) {
result = op.getDumpString() + " @ " + op.getUse().getResultId()
}
string toExprString(Node n) { none() }
}
import DebugNode0ToString

View File

@@ -1,75 +1,8 @@
/**
* This file contains the abstract class that serves as the base class for
* dataflow node printing.
* This file imports the module that is used to construct the strings used by `Node.ToString`.
*
* By default, a non-debug string is produced. However, a debug-friendly
* string can be produced by importing `DebugPrinting.qll`.
* Normally, this file should just import `NormalNode0ToString` to compute the efficient `toString`, but for debugging purposes
* one can import `DebugPrinting.qll` to better correlate the dataflow nodes with their underlying instructions and operands.
*/
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
/**
* A class to control whether a debugging version of instructions and operands
* should be printed as part of the `toString` output of dataflow nodes.
*
* To enable debug printing import the `DebugPrinting.ql` file. By default,
* non-debug output will be used.
*/
class Node0ToString extends Unit {
abstract predicate isDebugMode();
private string normalInstructionToString(Instruction i) {
not this.isDebugMode() and
if i.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = i.getAst().toString()
}
private string normalOperandToString(Operand op) {
not this.isDebugMode() and
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = op.getDef().getAst().toString()
}
/**
* Gets the string that should be used by `InstructionNode.toString`
*/
string instructionToString(Instruction i) {
if this.isDebugMode()
then result = i.getDumpString()
else result = this.normalInstructionToString(i)
}
/**
* Gets the string that should be used by `OperandNode.toString`.
*/
string operandToString(Operand op) {
if this.isDebugMode()
then result = op.getDumpString() + " @ " + op.getUse().getResultId()
else result = this.normalOperandToString(op)
}
}
private class NoDebugNode0ToString extends Node0ToString {
final override predicate isDebugMode() { none() }
}
/**
* Gets the string that should be used by `OperandNode.toString`.
*/
string operandToString(Operand op) { result = any(Node0ToString nts).operandToString(op) }
/**
* Gets the string that should be used by `InstructionNode.toString`
*/
string instructionToString(Instruction i) { result = any(Node0ToString nts).instructionToString(i) }
/**
* Holds if debugging mode is enabled.
*
* In debug mode the `toString` on dataflow nodes is more expensive to compute,
* but gives more precise information about the different dataflow nodes.
*/
predicate isDebugMode() { any(Node0ToString nts).isDebugMode() }
import NormalNode0ToString

View File

@@ -0,0 +1,25 @@
/**
* This file contains the signature module for controlling the behavior of `Node.toString`.
*/
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import DataFlowUtil
/** A signature for a module to control the behavior of `Node.toString`. */
signature module Node0ToStringSig {
/**
* Gets the string that should be used by `OperandNode.toString`.
*/
string operandToString(Operand op);
/**
* Gets the string that should be used by `InstructionNode.toString`.
*/
string instructionToString(Instruction i);
/**
* Gets the string representation of the `Expr` associated with `n`, if any.
*/
string toExprString(Node n);
}

View File

@@ -0,0 +1,33 @@
/**
* This file contains module that implements the non-debug version of
* `toString` for `Instruction` and `Operand` dataflow nodes.
*/
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import Node0ToStringSig
private import DataFlowUtil
private import DataFlowPrivate
private module NormalNode0ToStringImpl implements Node0ToStringSig {
string instructionToString(Instruction i) {
if i.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = i.getAst().toString()
}
string operandToString(Operand op) {
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = op.getDef().getAst().toString()
}
string toExprString(Node n) {
result = n.asExpr(0).toString()
or
not exists(n.asExpr()) and
result = stars(n) + n.asIndirectExpr(0, 1).toString()
}
}
import NormalNode0ToStringImpl