Add call_conv to tool
This commit is contained in:
parent
3ad0cb5bd1
commit
15ec7bd1f1
|
@ -78,9 +78,8 @@ bool dumpTreeFile(const std::string &filepath) {
|
|||
void register_cmd_dump(CLI::App &app) {
|
||||
auto cmd =
|
||||
app.add_subcommand("dump-tree", "Dump the tree-sitter AST for a file");
|
||||
cmd->add_option("-f,--filepath", filepath,
|
||||
"File to dump the tree-sitter AST for")
|
||||
->required();
|
||||
cmd->add_option("file", filepath,
|
||||
"Input C++ file to parse")->required();
|
||||
cmd->final_callback([]() {
|
||||
spdlog::info("=== Processing: {} ===", filepath);
|
||||
dumpTreeFile(filepath);
|
||||
|
|
|
@ -24,10 +24,11 @@ bool generateHooksFile(const std::string &output_filepath) {
|
|||
for (const auto &func : fix_functions) {
|
||||
// Extract just the filename from the full path
|
||||
std::string filename = std::filesystem::path(func.filepath).filename().string();
|
||||
std::string conv_str = callingConventionToString(func.calling_convention);
|
||||
|
||||
output_stream << "HOOK(0x" << func.address << ", " << func.name << ") // " << filename << std::endl;
|
||||
output_stream << "HOOK(0x" << func.address << ", " << func.name << ", " << conv_str << ") // " << filename << std::endl;
|
||||
|
||||
spdlog::debug("Added hook: {} {} from {}", func.address, func.name, filename);
|
||||
spdlog::debug("Added hook: {} {} {} from {}", func.address, func.name, conv_str, filename);
|
||||
}
|
||||
|
||||
output_stream.close();
|
||||
|
|
|
@ -27,11 +27,11 @@ public:
|
|||
&delete_imports_stmt,
|
||||
"Failed to prepare delete imports statement");
|
||||
prepareStatement("INSERT OR REPLACE INTO Functions (filepath, name, "
|
||||
"address, type) VALUES (?, ?, ?, ?)",
|
||||
"address, type, calling_convention) VALUES (?, ?, ?, ?, ?)",
|
||||
&insert_functions_stmt,
|
||||
"Failed to prepare insert functions statement");
|
||||
prepareStatement("INSERT OR REPLACE INTO Imports (filepath, name, address, "
|
||||
"type) VALUES (?, ?, ?, ?)",
|
||||
"type, calling_convention) VALUES (?, ?, ?, ?, ?)",
|
||||
&insert_imports_stmt,
|
||||
"Failed to prepare insert imports statement");
|
||||
prepareStatement("DELETE FROM Globals WHERE filepath = ?",
|
||||
|
@ -80,8 +80,8 @@ DatabaseManager::DatabaseManager(const std::string &db_path) : db(nullptr) {
|
|||
}
|
||||
|
||||
const char *create_tables = R"(
|
||||
CREATE TABLE IF NOT EXISTS Functions (filepath TEXT, name TEXT, address TEXT, type INTEGER DEFAULT 0, PRIMARY KEY (name, filepath));
|
||||
CREATE TABLE IF NOT EXISTS Imports (filepath TEXT, name TEXT, address TEXT, type INTEGER DEFAULT 0, PRIMARY KEY (name, filepath));
|
||||
CREATE TABLE IF NOT EXISTS Functions (filepath TEXT, name TEXT, address TEXT, type INTEGER DEFAULT 0, calling_convention INTEGER DEFAULT 0, PRIMARY KEY (name, filepath));
|
||||
CREATE TABLE IF NOT EXISTS Imports (filepath TEXT, name TEXT, address TEXT, type INTEGER DEFAULT 0, calling_convention INTEGER DEFAULT 0, PRIMARY KEY (name, filepath));
|
||||
CREATE TABLE IF NOT EXISTS Globals (filepath TEXT, name TEXT, address TEXT);
|
||||
)";
|
||||
|
||||
|
@ -118,6 +118,7 @@ void DatabaseManager::insertFunction(const FunctionInfo &func) {
|
|||
sqlite3_bind_text(stmt, 2, func.name.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 3, func.address.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int(stmt, 4, static_cast<int>(func.type));
|
||||
sqlite3_bind_int(stmt, 5, static_cast<int>(func.calling_convention));
|
||||
sqlite3_step(stmt);
|
||||
}
|
||||
|
||||
|
@ -240,7 +241,7 @@ std::vector<FunctionInfo> DatabaseManager::getFunctionsByType(FileType type) {
|
|||
std::vector<FunctionInfo> functions;
|
||||
|
||||
const char *sql = R"(
|
||||
SELECT name, address, filepath
|
||||
SELECT name, address, filepath, calling_convention
|
||||
FROM Functions
|
||||
WHERE type = ? AND address != ''
|
||||
ORDER BY address;
|
||||
|
@ -259,6 +260,7 @@ std::vector<FunctionInfo> DatabaseManager::getFunctionsByType(FileType type) {
|
|||
func.name = (const char *)sqlite3_column_text(stmt, 0);
|
||||
func.address = (const char *)sqlite3_column_text(stmt, 1);
|
||||
func.filepath = (const char *)sqlite3_column_text(stmt, 2);
|
||||
func.calling_convention = static_cast<CallingConvention>(sqlite3_column_int(stmt, 3));
|
||||
func.type = type;
|
||||
func.is_import = false; // Functions table contains non-imports
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
tool=build/clang-x86_64-pc-windows-msvc/Release/r3_gh_tool
|
||||
cmake --build build/clang-x86_64-pc-windows-msvc/Release --target r3_gh_tool
|
||||
tool=build/clang-x86_64-pc-windows-msvc/Release/gh_tool
|
||||
cmake --build build/clang-x86_64-pc-windows-msvc/Release --target gh_tool
|
||||
|
||||
types=(auto ref fix stub)
|
||||
for type in "${types[@]}"; do
|
||||
|
@ -12,9 +12,9 @@ for type in "${types[@]}"; do
|
|||
for file in "tmps/gh_${type}"/*.cxx; do
|
||||
echo "$file" >>"$file_list"
|
||||
done
|
||||
$tool "@$file_list" -v --type=$type --log-file=log-functions.txt
|
||||
$tool -v --log-file=log-functions.txt functions "@$file_list" --type=$type
|
||||
fi
|
||||
done
|
||||
|
||||
$tool tmps/gh_global.h -mglobals -v --log-file=log-globals.txt
|
||||
$tool -mduplicates -v --log-file=log-duplicates.txt
|
||||
$tool -v --log-file=log-globals.txt globals tmps/gh_global.h
|
||||
$tool -v --log-file=log-duplicates.txt verify
|
||||
|
|
|
@ -209,6 +209,47 @@ bool hasFunctionBody(TSNode node) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Add this helper function to detect calling convention from a function declaration
|
||||
CallingConvention getCallingConvention(TSNode node, const char *source_code) {
|
||||
uint32_t child_count = ts_node_child_count(node);
|
||||
|
||||
for (uint32_t i = 0; i < child_count; i++) {
|
||||
TSNode child = ts_node_child(node, i);
|
||||
const char *type = ts_node_type(child);
|
||||
|
||||
// Look for identifiers that might be calling conventions
|
||||
if (strcmp(type, "identifier") == 0) {
|
||||
std::string text = extractNodeText(child, source_code);
|
||||
if (text == "__fastcall" || text == "__FASTCALL") {
|
||||
return CallingConvention::Fastcall;
|
||||
} else if (text == "__stdcall" || text == "__STDCALL") {
|
||||
return CallingConvention::Stdcall;
|
||||
} else if (text == "__cdecl" || text == "__CDECL") {
|
||||
return CallingConvention::Cdecl;
|
||||
}
|
||||
}
|
||||
// Also check in type specifiers and declaration specifiers
|
||||
else if (strcmp(type, "type_specifier") == 0 ||
|
||||
strcmp(type, "declaration_specifier") == 0 ||
|
||||
strcmp(type, "specifier_qualifier_list") == 0) {
|
||||
CallingConvention conv = getCallingConvention(child, source_code);
|
||||
if (conv != CallingConvention::Cdecl) {
|
||||
return conv;
|
||||
}
|
||||
}
|
||||
// Check in declarators as well (calling convention can appear in various positions)
|
||||
else if (strcmp(type, "function_declarator") == 0 ||
|
||||
strcmp(type, "pointer_declarator") == 0) {
|
||||
CallingConvention conv = getCallingConvention(child, source_code);
|
||||
if (conv != CallingConvention::Cdecl) {
|
||||
return conv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CallingConvention::Cdecl; // Default
|
||||
}
|
||||
|
||||
void findFunctions(TSNode node, const char *source_code, uint32_t source_length,
|
||||
std::vector<FunctionInfo> &functions, FileType file_type) {
|
||||
const char *type = ts_node_type(node);
|
||||
|
@ -226,11 +267,19 @@ void findFunctions(TSNode node, const char *source_code, uint32_t source_length,
|
|||
}
|
||||
|
||||
if (!address.empty()) {
|
||||
// Detect calling convention
|
||||
CallingConvention calling_conv = getCallingConvention(node, source_code);
|
||||
|
||||
FunctionInfo func{func_name, address, "",
|
||||
strcmp(type, "function_definition") == 0
|
||||
? !hasFunctionBody(node)
|
||||
: true,
|
||||
file_type}; // Add file_type parameter
|
||||
func.calling_convention = calling_conv; // Set the calling convention
|
||||
|
||||
spdlog::debug("Found function: {} at {} with calling convention: {}",
|
||||
func_name, address, callingConventionToString(calling_conv));
|
||||
|
||||
functions.push_back(func);
|
||||
}
|
||||
// We'll never nest function declarations
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "tool.hpp"
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
#include <CLI11.hpp>
|
||||
|
@ -45,3 +46,28 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CallingConvention stringToCallingConvention(const std::string &conv_str) {
|
||||
std::string lower_conv = conv_str;
|
||||
std::transform(lower_conv.begin(), lower_conv.end(), lower_conv.begin(), ::tolower);
|
||||
|
||||
if (lower_conv == "fastcall" || lower_conv == "__fastcall") {
|
||||
return CallingConvention::Fastcall;
|
||||
} else if (lower_conv == "stdcall" || lower_conv == "__stdcall") {
|
||||
return CallingConvention::Stdcall;
|
||||
} else {
|
||||
return CallingConvention::Cdecl; // Default
|
||||
}
|
||||
}
|
||||
|
||||
std::string callingConventionToString(CallingConvention conv) {
|
||||
switch (conv) {
|
||||
case CallingConvention::Fastcall:
|
||||
return "fastcall";
|
||||
case CallingConvention::Stdcall:
|
||||
return "stdcall";
|
||||
case CallingConvention::Cdecl:
|
||||
default:
|
||||
return "cdecl";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@ extern const std::regex ADDRESS_REGEX;
|
|||
// Enums
|
||||
enum class FileType { Auto, Fix, Stub, Ref };
|
||||
|
||||
// Add calling convention enum
|
||||
enum class CallingConvention { Cdecl, Stdcall, Fastcall };
|
||||
|
||||
// Data structures
|
||||
struct FunctionInfo {
|
||||
std::string name;
|
||||
|
@ -21,6 +24,7 @@ struct FunctionInfo {
|
|||
std::string filepath;
|
||||
bool is_import;
|
||||
FileType type;
|
||||
CallingConvention calling_convention = CallingConvention::Cdecl; // Default to cdecl
|
||||
};
|
||||
|
||||
struct GlobalInfo {
|
||||
|
@ -35,6 +39,10 @@ std::string fileTypeToString(FileType type);
|
|||
bool hasAddressPattern(const std::string &comment);
|
||||
std::string extractAddress(const std::string &comment);
|
||||
|
||||
// Add utility functions for calling convention
|
||||
CallingConvention stringToCallingConvention(const std::string &conv_str);
|
||||
std::string callingConventionToString(CallingConvention conv);
|
||||
|
||||
// Tree-sitter parsing functions
|
||||
std::string extractNodeText(TSNode node, const char *source_code);
|
||||
std::string findIdentifierInNode(TSNode node, const char *source_code);
|
||||
|
|
Loading…
Reference in New Issue