ExprEngine: Print some 'debug' output

This commit is contained in:
Daniel Marjamäki 2019-09-19 20:18:39 +02:00
parent bf55e835aa
commit 5f0f8afc27
1 changed files with 113 additions and 26 deletions

View File

@ -17,6 +17,7 @@
*/ */
#include "exprengine.h" #include "exprengine.h"
#include "astutils.h"
#include "settings.h" #include "settings.h"
#include "symboldatabase.h" #include "symboldatabase.h"
#include "tokenize.h" #include "tokenize.h"
@ -51,29 +52,71 @@ std::string ExprEngine::str(int128_t value)
static ExprEngine::ValuePtr getValueRangeFromValueType(const std::string &name, const ValueType *vt, const cppcheck::Platform &platform); static ExprEngine::ValuePtr getValueRangeFromValueType(const std::string &name, const ValueType *vt, const cppcheck::Platform &platform);
namespace { namespace {
class TrackExecution {
public:
TrackExecution() : dataIndex(0) {}
std::map<const Token *, std::vector<std::string>> map;
int getNewDataIndex() {
return dataIndex++;
}
void newValue(const Token *tok, ExprEngine::ValuePtr value) {
if (!tok)
return;
if (!value)
map[tok].push_back(tok->expressionString() + "=TODO_NO_VALUE");
/*
else if (value->name[0] == '$')
map[tok].push_back(tok->expressionString() + "=(" + value->name + "," + value->getRange() + ")");
else
map[tok].push_back(tok->expressionString() + "=" + value->name);
*/
}
void state(const Token *tok, const std::string &s) {
map[tok].push_back(s);
}
void print() {
std::set<std::pair<int,int>> locations;
for (auto it : map) {
locations.emplace(it.first->linenr(), it.first->column());
}
for (const std::pair<int,int> &loc : locations) {
int lineNumber = loc.first;
int column = loc.second;
for (auto &it : map) {
const Token *tok = it.first;
if (lineNumber != tok->linenr())
continue;
const std::vector<std::string> &dumps = it.second;
for (const std::string &dump : dumps)
std::cout << lineNumber << ":" << column << ": " << dump << "\n";
}
}
}
private:
int dataIndex;
};
class Data { class Data {
public: public:
Data(int *symbolValueIndex, const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks) Data(int *symbolValueIndex, const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, TrackExecution *trackExecution)
: symbolValueIndex(symbolValueIndex) : symbolValueIndex(symbolValueIndex)
, tokenizer(tokenizer) , tokenizer(tokenizer)
, settings(settings) , settings(settings)
, callbacks(callbacks) {} , callbacks(callbacks)
, mTrackExecution(trackExecution)
, dataIndex(trackExecution->getNewDataIndex()) {}
typedef std::map<nonneg int, std::shared_ptr<ExprEngine::Value>> Memory; typedef std::map<nonneg int, std::shared_ptr<ExprEngine::Value>> Memory;
Memory memory; Memory memory;
int *symbolValueIndex; int * const symbolValueIndex;
const Tokenizer *tokenizer; const Tokenizer * const tokenizer;
const Settings *settings; const Settings * const settings;
const std::vector<ExprEngine::Callback> &callbacks; const std::vector<ExprEngine::Callback> &callbacks;
void printMemory() const {
const SymbolDatabase *symbolDatabase = tokenizer->getSymbolDatabase();
for (Memory::const_iterator mem = memory.cbegin(); mem != memory.cend(); ++mem) {
std::cout << symbolDatabase->getVariableFromVarId(mem->first)->name() << " name:" << mem->second->name << " range:" << mem->second->getRange() << "\n";
}
}
Data getData(const Token *cond, bool trueData) { Data getData(const Token *cond, bool trueData) {
Data ret(symbolValueIndex, tokenizer, settings, callbacks); Data ret(symbolValueIndex, tokenizer, settings, callbacks, mTrackExecution);
for (Memory::const_iterator mem = memory.cbegin(); mem != memory.cend(); ++mem) { for (Memory::const_iterator mem = memory.cbegin(); mem != memory.cend(); ++mem) {
ret.memory[mem->first] = mem->second; ret.memory[mem->first] = mem->second;
@ -81,10 +124,15 @@ namespace {
const int128_t rhsValue = MathLib::toLongNumber(cond->astOperand2()->str()); const int128_t rhsValue = MathLib::toLongNumber(cond->astOperand2()->str());
if (auto intRange = std::dynamic_pointer_cast<ExprEngine::IntRange>(mem->second)) { if (auto intRange = std::dynamic_pointer_cast<ExprEngine::IntRange>(mem->second)) {
if (cond->str() == ">") { if (cond->str() == ">") {
if (trueData && intRange->minValue <= rhsValue) if (trueData && intRange->minValue <= rhsValue) {
ret.memory[mem->first] = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), rhsValue + 1, intRange->maxValue); auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), rhsValue + 1, intRange->maxValue);
else if (!trueData && intRange->maxValue > rhsValue) ret.trackAssignment(cond, val);
ret.memory[mem->first] = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), intRange->minValue, rhsValue); ret.memory[mem->first] = val;
} else if (!trueData && intRange->maxValue > rhsValue) {
auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), intRange->minValue, rhsValue);
ret.trackAssignment(cond, val);
ret.memory[mem->first] = val;
}
} }
} }
} }
@ -103,17 +151,45 @@ namespace {
return std::shared_ptr<ExprEngine::ArrayValue>(); return std::shared_ptr<ExprEngine::ArrayValue>();
} }
ExprEngine::ValuePtr getValue(unsigned int varId, const ValueType *valueType) { ExprEngine::ValuePtr getValue(unsigned int varId, const ValueType *valueType, const Token *tok) {
const Memory::const_iterator it = memory.find(varId); const Memory::const_iterator it = memory.find(varId);
if (it != memory.end()) if (it != memory.end())
return it->second; return it->second;
if (!valueType) if (!valueType)
return ExprEngine::ValuePtr(); return ExprEngine::ValuePtr();
ExprEngine::ValuePtr value = getValueRangeFromValueType(getNewSymbolName(), valueType, *settings); ExprEngine::ValuePtr value = getValueRangeFromValueType(getNewSymbolName(), valueType, *settings);
if (value) if (value) {
if (tok)
trackAssignment(tok, value);
memory[varId] = value; memory[varId] = value;
}
return value; return value;
} }
void trackAssignment(const Token *tok, ExprEngine::ValuePtr value) {
return mTrackExecution->newValue(tok, value);
}
void trackProgramState(const Token *tok) {
if (memory.empty())
return;
const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase();
std::ostringstream s;
s << "{"; // << dataIndex << ":";
for (auto mem : memory) {
ExprEngine::ValuePtr value = mem.second;
s << " " << symbolDatabase->getVariableFromVarId(mem.first)->name() << "=";
if (value->name[0] == '$')
s << "(" << value->name << "," << value->getRange() << ")";
else
s << value->name;
}
s << "}";
mTrackExecution->state(tok, s.str());
}
private:
TrackExecution * const mTrackExecution;
const int dataIndex;
}; };
} }
@ -290,6 +366,7 @@ static ExprEngine::ValuePtr executeAssign(const Token *tok, Data &data)
call(data.callbacks, tok, rhsValue); call(data.callbacks, tok, rhsValue);
const Token *lhsToken = tok->astOperand1(); const Token *lhsToken = tok->astOperand1();
data.trackAssignment(lhsToken, rhsValue);
if (lhsToken->varId() > 0) { if (lhsToken->varId() > 0) {
data.memory[lhsToken->varId()] = rhsValue; data.memory[lhsToken->varId()] = rhsValue;
} else if (lhsToken->str() == "[") { } else if (lhsToken->str() == "[") {
@ -311,7 +388,8 @@ static ExprEngine::ValuePtr executeAssign(const Token *tok, Data &data)
static ExprEngine::ValuePtr executeFunctionCall(const Token *tok, Data &data) static ExprEngine::ValuePtr executeFunctionCall(const Token *tok, Data &data)
{ {
(void)executeExpression(tok->astOperand2(), data); for (const Token *argtok : getArguments(tok))
(void)executeExpression(argtok, data);
auto val = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings); auto val = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings);
call(data.callbacks, tok, val); call(data.callbacks, tok, val);
return val; return val;
@ -333,7 +411,7 @@ static ExprEngine::ValuePtr executeDot(const Token *tok, Data &data)
{ {
if (!tok->astOperand1() || !tok->astOperand1()->varId()) if (!tok->astOperand1() || !tok->astOperand1()->varId())
return ExprEngine::ValuePtr(); return ExprEngine::ValuePtr();
std::shared_ptr<ExprEngine::StructValue> structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(data.getValue(tok->astOperand1()->varId(), nullptr)); std::shared_ptr<ExprEngine::StructValue> structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr));
if (!structValue) if (!structValue)
return ExprEngine::ValuePtr(); return ExprEngine::ValuePtr();
return structValue->getValueOfMember(tok->astOperand2()->str()); return structValue->getValueOfMember(tok->astOperand2()->str());
@ -364,7 +442,7 @@ static ExprEngine::ValuePtr executeDeref(const Token *tok, Data &data)
if (pval) { if (pval) {
auto addressOf = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(pval); auto addressOf = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(pval);
if (addressOf) { if (addressOf) {
auto val = data.getValue(addressOf->varId, tok->valueType()); auto val = data.getValue(addressOf->varId, tok->valueType(), tok);
call(data.callbacks, tok, val); call(data.callbacks, tok, val);
return val; return val;
} }
@ -380,7 +458,7 @@ static ExprEngine::ValuePtr executeDeref(const Token *tok, Data &data)
static ExprEngine::ValuePtr executeVariable(const Token *tok, Data &data) static ExprEngine::ValuePtr executeVariable(const Token *tok, Data &data)
{ {
auto val = data.getValue(tok->varId(), tok->valueType()); auto val = data.getValue(tok->varId(), tok->valueType(), tok);
call(data.callbacks, tok, val); call(data.callbacks, tok, val);
return val; return val;
} }
@ -429,6 +507,8 @@ static ExprEngine::ValuePtr executeExpression(const Token *tok, Data &data)
static void execute(const Token *start, const Token *end, Data &data) static void execute(const Token *start, const Token *end, Data &data)
{ {
for (const Token *tok = start; tok != end; tok = tok->next()) { for (const Token *tok = start; tok != end; tok = tok->next()) {
if (tok->str() == ";")
data.trackProgramState(tok);
if (tok->variable() && tok->variable()->nameToken() == tok) { if (tok->variable() && tok->variable()->nameToken() == tok) {
if (tok->variable()->isArray() && tok->variable()->dimensions().size() == 1 && tok->variable()->dimensions()[0].known) { if (tok->variable()->isArray() && tok->variable()->dimensions().size() == 1 && tok->variable()->dimensions()[0].known) {
data.memory[tok->varId()] = std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), tok->variable()->dimension(0)); data.memory[tok->varId()] = std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), tok->variable()->dimension(0));
@ -504,16 +584,23 @@ void ExprEngine::executeFunction(const Scope *functionScope, const Tokenizer *to
return; return;
int symbolValueIndex = 0; int symbolValueIndex = 0;
Data data(&symbolValueIndex, tokenizer, settings, callbacks); TrackExecution trackExecution;
data.printMemory(); Data data(&symbolValueIndex, tokenizer, settings, callbacks, &trackExecution);
for (const Variable &arg : function->argumentList) { for (const Variable &arg : function->argumentList) {
ValuePtr val = createVariableValue(arg, data); ValuePtr val = createVariableValue(arg, data);
if (val) if (val) {
data.trackAssignment(arg.nameToken(), val);
data.memory[arg.declarationId()] = val; data.memory[arg.declarationId()] = val;
}
} }
execute(functionScope->bodyStart, functionScope->bodyEnd, data); execute(functionScope->bodyStart, functionScope->bodyEnd, data);
if (settings->verification) {
// TODO generate better output!!
trackExecution.print();
}
} }
void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings) void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings)