From 5ef0a7f77428e39e79ce83157702d51e71a057e5 Mon Sep 17 00:00:00 2001 From: Siddharth Mishra Date: Sat, 5 Jul 2025 22:12:12 +0530 Subject: [PATCH 1/5] Data Types Sync (Begin,IsCompleted,Set,Get) API Endpoints --- Include/Reai/Api.h | 198 +++++++---- Include/Reai/Api/Types.h | 1 + Include/Reai/Api/Types/DataType.h | 130 +++++++ Include/Reai/Api/Types/FunctionInfo.h | 1 + Include/Reai/Util/Str.h | 25 ++ Source/Reai/Api.c | 467 +++++++++++++++++++++++++- Source/Reai/Api/Types/DataType.c | 85 +++++ Source/Reai/Api/Types/FunctionInfo.c | 1 + 8 files changed, 834 insertions(+), 74 deletions(-) create mode 100644 Include/Reai/Api/Types/DataType.h create mode 100644 Source/Reai/Api/Types/DataType.c diff --git a/Include/Reai/Api.h b/Include/Reai/Api.h index 2d4d272..63a284a 100644 --- a/Include/Reai/Api.h +++ b/Include/Reai/Api.h @@ -153,8 +153,8 @@ extern "C" { /// /// conn[in] : Connection information /// - /// SUCCESS : true - /// FAILURE : false, error messages are logged. + /// SUCCESS: true + /// FAILURE: false, error messages are logged. /// REAI_API bool Authenticate (Connection* conn); @@ -168,8 +168,8 @@ extern "C" { /// conn[in] : A valid connection object with host and API key set. /// request[in] : The request object to serialize and send to the server. /// - /// SUCCESS : A non-zero binary ID corresponding to newly created analysis. - /// FAILURE : 0, error messages logged. + /// SUCCESS: A non-zero binary ID corresponding to newly created analysis. + /// FAILURE: 0, error messages logged. /// REAI_API BinaryId CreateNewAnalysis (Connection* conn, NewAnalysisRequest* request); @@ -180,13 +180,13 @@ extern "C" { /// a response containing basic function information. The response is parsed into a `BasicFunctionInfoResponse` /// structure, which includes the success flag and a list of functions associated with the binary ID. /// - /// conn[in] : A valid connection object with host and API key set for making the request. - /// binary_id[in] : The binary ID used to identify the binary for which function information is to be fetched. + /// conn[in] : A valid connection object with host and API key set for making the request. + /// analysis_id[in] : The analysis ID used to identify the analysis for which function information is to be fetched. /// - /// SUCCESS : FunctionInfos vector filled with function symbol information retrieved from analysis. - /// FAILURE : Empty FunctionInfos vector. + /// SUCCESS: FunctionInfos vector filled with function symbol information retrieved from analysis. + /// FAILURE: Empty FunctionInfos vector. /// - REAI_API FunctionInfos GetBasicFunctionInfoUsingBinaryId (Connection* conn, BinaryId binary_id); + REAI_API FunctionInfos GetFunctionsList (Connection* conn, AnalysisId analysis_id); /// /// Sends a request to retrieve recent analysis data based on the provided parameters. @@ -197,8 +197,8 @@ extern "C" { /// conn[in] : A valid connection object with host and API key set. /// request[in] : The request object that contains the filters and parameters for retrieving recent analysis data. /// - /// SUCCESS : A populated `AnalysisInfos` struct on success. - /// FAILURE : An empty struct (all fields set to 0) on failure. + /// SUCCESS: A populated `AnalysisInfos` struct on success. + /// FAILURE: An empty struct (all fields set to 0) on failure. /// REAI_API AnalysisInfos GetRecentAnalysis (Connection* conn, RecentAnalysisRequest* request); @@ -208,8 +208,8 @@ extern "C" { /// conn[in] : Connection information. /// request[in] : Request info. /// - /// SUCCESS : BinaryInfos struct filled with valid data on success. - /// FAILURE : Empty struct otherwise. + /// SUCCESS: BinaryInfos struct filled with valid data on success. + /// FAILURE: Empty struct otherwise. /// REAI_API BinaryInfos SearchBinary (Connection* conn, SearchBinaryRequest* request); @@ -219,8 +219,8 @@ extern "C" { /// conn[in] : Connection info. /// request[in] : Request info. /// - /// SUCCESS : CollectionInfos struct filled with valid data on success. - /// FAILURE : Empty struct otherwise. + /// SUCCESS: CollectionInfos struct filled with valid data on success. + /// FAILURE: Empty struct otherwise. /// REAI_API CollectionInfos SearchCollection (Connection* conn, SearchCollectionRequest* request); @@ -230,8 +230,8 @@ extern "C" { /// conn[in] : Connection /// functions[in] : Functions to be renamed. Only `id` and `symbol.name` field will be used. /// - /// SUCCESS : true - /// FAILURE : false + /// SUCCESS: true + /// FAILURE: false /// REAI_API bool BatchRenameFunctions (Connection* conn, FunctionInfos functions); @@ -242,8 +242,8 @@ extern "C" { /// fn_id[in] : Functions to be renamed. Only `id` and `symbol.name` field will be used. /// new_name[in] : Name of function after rename /// - /// SUCCESS : true - /// FAILURE : false + /// SUCCESS: true + /// FAILURE: false /// REAI_API bool RenameFunction (Connection* conn, FunctionId fn_id, Str new_name); @@ -267,9 +267,8 @@ extern "C" { /// conn[in] : Valid connection object with host and API key configured /// binary_id[in] : Unique identifier for the binary being analyzed /// - /// RETURNS: - /// - Status code indicating current analysis state (STATUS_SUCCESS, STATUS_PENDING, etc.) - /// - STATUS_INVALID if connection parameters are invalid or request fails + /// SUCCESS: Status code indicating current analysis state (STATUS_SUCCESS, STATUS_PENDING, etc.) + /// FAILURE: STATUS_INVALID /// REAI_API Status GetAnalysisStatus (Connection* conn, BinaryId binary_id); @@ -280,9 +279,8 @@ extern "C" { /// /// conn[in] : Valid connection object with host and API key configured /// - /// RETURNS: - /// - Vector of ModelInfo structures containing model IDs and names - /// - Empty vector if connection fails or no models available + /// SUCCESS: ModelInfos vector filled with model information + /// FAILURE: Empty ModelInfos vector /// REAI_API ModelInfos GetAiModelInfos (Connection* conn); @@ -294,9 +292,8 @@ extern "C" { /// conn[in] : Valid connection object /// function_id[in] : ID of the function to decompile /// - /// RETURNS: - /// - true if decompilation job started successfully - /// - false if invalid parameters or connection failure + /// SUCCESS: true + /// FAILURE: false /// REAI_API bool BeginAiDecompilation (Connection* conn, FunctionId function_id); @@ -308,9 +305,8 @@ extern "C" { /// conn[in] : Valid connection object /// function_id[in] : ID of the function being decompiled /// - /// RETURNS: - /// - Status code (STATUS_PENDING, STATUS_SUCCESS, etc.) - /// - STATUS_INVALID if invalid parameters or connection failure + /// SUCCESS: Status code (STATUS_PENDING, STATUS_SUCCESS, etc.) + /// FAILURE: STATUS_INVALID /// REAI_API Status GetAiDecompilationStatus (Connection* conn, FunctionId function_id); @@ -323,9 +319,8 @@ extern "C" { /// function_id[in] : ID of the decompiled function /// get_ai_summary[in]: Whether to include AI-generated summary /// - /// RETURNS: - /// - AiDecompilation structure containing decompilation results - /// - Empty structure if job failed or results unavailable + /// SUCCESS: AiDecompilation structure containing decompilation results + /// FAILURE: Empty AiDecompilation structure /// REAI_API AiDecompilation GetAiDecompilation (Connection* conn, FunctionId function_id, bool get_ai_summary); @@ -339,8 +334,8 @@ extern "C" { /// conn[in] : A valid connection object with host and API key set. /// function_id[in]: The function ID for which to retrieve the CFG. /// - /// SUCCESS : ControlFlowGraph structure populated with CFG data - /// FAILURE : Empty ControlFlowGraph structure + /// SUCCESS: ControlFlowGraph structure populated with CFG data + /// FAILURE: Empty ControlFlowGraph structure /// REAI_API ControlFlowGraph GetFunctionControlFlowGraph (Connection* conn, FunctionId function_id); @@ -353,9 +348,8 @@ extern "C" { /// conn[in] : Valid connection object /// request[in] : Parameters controlling search criteria and filters /// - /// RETURNS: - /// - Vector of SimilarFunction structures containing match details - /// - Empty vector if no matches found or connection failure + /// SUCCESS: Vector of SimilarFunction structures containing match details + /// FAILURE: Empty vector /// REAI_API SimilarFunctions GetSimilarFunctions (Connection* conn, SimilarFunctionsRequest* request); @@ -368,11 +362,98 @@ extern "C" { /// conn[in] : Valid connection object /// binary_id[in] : ID of the binary file to look up /// - /// SUCCESS : Non-zero analysis ID if found - /// FAILURE : 0 if invalid input or no matching analysis found. + /// SUCCESS: Non-zero analysis ID if found + /// FAILURE: 0 if invalid input or no matching analysis found. /// REAI_API AnalysisId AnalysisIdFromBinaryId (Connection* conn, BinaryId binary_id); + /// + /// Start generating function type for a specific function. + /// + /// conn[in] : Valid connection object + /// analysis_id[in] : ID of the analysis to generate function type for + /// function_ids[in] : IDs of the functions to generate function type for + /// + /// SUCCESS: true + /// FAILURE: false + /// + REAI_API bool BeginFunctionTypeGeneration ( + Connection* conn, + AnalysisId analysis_id, + FunctionIds function_ids + ); + + /// + /// Start generating function type for all functions in an analysis. + /// + /// conn[in] : Valid connection object + /// analysis_id[in] : ID of the analysis to generate function type for + /// + /// SUCCESS: true + /// FAILURE: false + /// + REAI_API bool + BeginFunctionTypeGenerationForAllFunctions (Connection* conn, AnalysisId analysis_id); + + /// + /// Check if function type generation is completed for a specific function. + /// + /// conn[in] : Valid connection object + /// function_id[in] : ID of the function to check + /// + /// SUCCESS: true + /// FAILURE: false + /// + REAI_API bool IsFunctionTypeGenerationCompleted ( + Connection* conn, + AnalysisId analysis_id, + FunctionId function_id + ); + + /// + /// Check if function type generation is completed for all functions in an analysis. + /// + /// conn[in] : Valid connection object + /// analysis_id[in] : ID of the analysis to check + /// + /// SUCCESS: true + /// FAILURE: false + /// + REAI_API bool + IsFunctionTypeGenerationCompletedForAllFunctions (Connection* conn, AnalysisId analysis_id); + + /// + /// Retrieves function type information for a specific function. + /// + /// This function queries the server for detailed data type information + /// including function signatures, dependencies, and variable information. + /// + /// conn[in] : Valid connection object + /// function_id[in] : ID of the function to query + /// + /// SUCCESS: FunctionType object + /// FAILURE: Empty FunctionType object + /// + REAI_API FunctionType GetFunctionType (Connection* conn, FunctionId function_id); + + /// + /// Set function type for a specific function. + /// + /// conn[in] : Valid connection object + /// analysis_id[in] : ID of the analysis to set function type for + /// function_id[in] : ID of the function to set + /// function_type[in] : Function type to set + /// + /// SUCCESS: true + /// FAILURE: false + /// + REAI_API bool SetFunctionType ( + Connection* conn, + AnalysisId analysis_id, + FunctionId function_id, + FunctionType function_type + ); + /// Retrieves log data for a specific analysis job. /// /// This function fetches diagnostic logs generated during @@ -381,8 +462,8 @@ extern "C" { /// conn[in] : Valid connection object /// analysis_id[in] : ID of the analysis job to query /// - /// SUCCESS : String containing log text - /// FAILURE : Empty string. + /// SUCCESS: String containing log text + /// FAILURE: Empty string. /// REAI_API Str GetAnalysisLogs (Connection* conn, AnalysisId analysis_id); @@ -396,8 +477,8 @@ extern "C" { /// conn[in] : Connection information including host and API key. /// file_path[in] : File path of to-be-uploaded file /// - /// SUCCESS : Str object containing SHA-256 Hash of uploaded file. - /// FAILURE : Empty Str object. + /// SUCCESS: Str object containing SHA-256 Hash of uploaded file. + /// FAILURE: Empty Str object. /// REAI_API Str UploadFile (Connection* conn, Str file_path); @@ -412,8 +493,8 @@ extern "C" { /// of whether this is first query param. If not provided /// it'll be treated as first query param. /// - /// SUCCESS : Updated `url` string on success. - /// FAILURE : `NULL` otherwise. + /// SUCCESS: Updated `url` string on success. + /// FAILURE: `NULL` otherwise. /// REAI_API Str* UrlAddQueryStr (Str* url, const char* key, const char* value, bool* is_first); @@ -427,8 +508,8 @@ extern "C" { /// of whether this is first query param. If not provided /// it'll be treated as first query param. /// - /// SUCCESS : Updated `url` string on success. - /// FAILURE : `NULL` otherwise. + /// SUCCESS: Updated `url` string on success. + /// FAILURE: `NULL` otherwise. /// REAI_API Str* UrlAddQueryInt (Str* url, const char* key, i64 value, bool* is_first); @@ -442,8 +523,8 @@ extern "C" { /// of whether this is first query param. If not provided /// it'll be treated as first query param. /// - /// SUCCESS : Updated `url` string on success. - /// FAILURE : `NULL` otherwise. + /// SUCCESS: Updated `url` string on success. + /// FAILURE: `NULL` otherwise. /// REAI_API Str* UrlAddQueryFloat (Str* url, const char* key, f64 value, bool* is_first); @@ -453,9 +534,8 @@ extern "C" { /// key[in] : Name of query parameter /// value[in] : Value of query parameter. /// - /// RETURNS: - /// - Updated `url` string on success. - /// - `NULL` otherwise. + /// SUCCESS: Updated `url` string on success. + /// FAILURE: `NULL` otherwise. /// REAI_API Str* UrlAddQueryBool (Str* url, const char* key, bool value, bool* is_first); @@ -470,9 +550,8 @@ extern "C" { /// response_json[out] : String object to store the response data in JSON format. Can be NULL if response is not required. /// request_method[in] : The HTTP method to use for the request (e.g., "POST", "GET"). /// - /// RETURNS: - /// On success - true - /// On failure - false, with log messages printed to log file or stderr. + /// SUCCESS: true + /// FAILURE: false /// REAI_API bool MakeRequest ( Str* user_agent, @@ -496,9 +575,8 @@ extern "C" { /// request_method[in] : The HTTP method to use for the request (e.g., "POST", "GET"). /// file_path[in] : File to be uploaded. /// - /// RETURNS: - /// On success - true - /// On failure - false, with log messages printed to log file or stderr. + /// SUCCESS: true + /// FAILURE: false /// REAI_API bool MakeUploadRequest ( Str* user_agent, diff --git a/Include/Reai/Api/Types.h b/Include/Reai/Api/Types.h index cfdc797..6bcae00 100644 --- a/Include/Reai/Api/Types.h +++ b/Include/Reai/Api/Types.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/Include/Reai/Api/Types/DataType.h b/Include/Reai/Api/Types/DataType.h new file mode 100644 index 0000000..a72e426 --- /dev/null +++ b/Include/Reai/Api/Types/DataType.h @@ -0,0 +1,130 @@ +#ifndef REAI_DATA_TYPE_H +#define REAI_DATA_TYPE_H + +#include +#include +#include + +typedef struct DataType DataType; +typedef Vec (DataType*) DataTypes; + +struct DataType { + Str last_change; + u64 offset; + u64 size; + Str name; + Str type; + Str artifact_type; + DataTypes members; +}; + +#ifdef __cplusplus +# define DataTypeInit() \ + (DataType { \ + .last_change = StrInit(), \ + .offset = 0, \ + .size = 0, \ + .name = StrInit(), \ + .type = StrInit(), \ + .artifact_type = StrInit(), \ + .members = VecInitWithDeepCopy (NULL, DataTypeDeinit) \ + }) +#else +# define DataTypeInit() \ + ((DataType) {.last_change = StrInit(), \ + .offset = 0, \ + .size = 0, \ + .name = StrInit(), \ + .type = StrInit(), \ + .artifact_type = StrInit(), \ + .members = VecInitWithDeepCopy (NULL, DataTypeDeinit)}) +#endif + +typedef struct FunctionType { + Str last_change; + u64 addr; + u64 size; + Str name; + Str return_type; + DataTypes args; + DataTypes stack_vars; + DataTypes deps; +} FunctionType; + +#ifdef __cplusplus +# define FunctionTypeInit() \ + (FunctionType { \ + .last_change = StrInit(), \ + .addr = 0, \ + .size = 0, \ + .name = StrInit(), \ + .return_type = StrInit(), \ + .args = VecInitWithDeepCopy (NULL, DataTypeDeinit), \ + .stack_vars = VecInitWithDeepCopy (NULL, DataTypeDeinit), \ + .deps = VecInitWithDeepCopy (NULL, DataTypeDeinit) \ + }) +#else +# define FunctionTypeInit() \ + ((FunctionType) {.last_change = StrInit(), \ + .addr = 0, \ + .size = 0, \ + .name = StrInit(), \ + .return_type = StrInit(), \ + .args = VecInitWithDeepCopy (NULL, DataTypeDeinit), \ + .stack_vars = VecInitWithDeepCopy (NULL, DataTypeDeinit), \ + .deps = VecInitWithDeepCopy (NULL, DataTypeDeinit)}) +#endif + +typedef Vec (FunctionType) FunctionTypes; + +#ifdef __cplusplus +extern "C" { +#endif + + /// + /// Deinit DataType object clone. This won't free provided pointer. + /// That must be done by owner. + /// + /// dt[in] : DataType object. + /// + /// RETURN : Does not return on failure + /// + REAI_API void DataTypeDeinit (DataType** dt); + + /// + /// Create clone of given `src` object into `dst` object + /// + /// dst[out] : Destination DataType object. + /// src[in] : Source DataType object. + /// + /// SUCCESS : true + /// FAILURE : Does not return on failure + /// + REAI_API bool DataTypeInitClone (DataType** dst, DataType** src); + + /// + /// Deinit FunctionType object clone. This won't free provided pointer. + /// That must be done by owner. + /// + /// ft[in] : FunctionType object. + /// + /// RETURN : Does not return on failure + /// + REAI_API void FunctionTypeDeinit (FunctionType* ft); + + /// + /// Create clone of given `src` object into `dst` object + /// + /// dst[out] : Destination FunctionType object. + /// src[in] : Source FunctionType object. + /// + /// SUCCESS : true + /// FAILURE : Does not return on failure + /// + REAI_API bool FunctionTypeInitClone (FunctionType* dst, FunctionType* src); + +#ifdef __cplusplus +} +#endif + +#endif // REAI_DATA_TYPE_H diff --git a/Include/Reai/Api/Types/FunctionInfo.h b/Include/Reai/Api/Types/FunctionInfo.h index 342ab9e..a3e7601 100644 --- a/Include/Reai/Api/Types/FunctionInfo.h +++ b/Include/Reai/Api/Types/FunctionInfo.h @@ -20,6 +20,7 @@ typedef struct FunctionInfo { FunctionId id; u64 size; SymbolInfo symbol; + bool debug; } FunctionInfo; typedef Vec (FunctionInfo) FunctionInfos; diff --git a/Include/Reai/Util/Str.h b/Include/Reai/Util/Str.h index 508ce01..1001795 100644 --- a/Include/Reai/Util/Str.h +++ b/Include/Reai/Util/Str.h @@ -56,6 +56,31 @@ extern "C" { .alignment = 1}) #endif +#ifdef __cplusplus +# define StrOwnZstr(zstr) \ + (zstr ? (Str { \ + .length = strlen (zstr), \ + .capacity = strlen (zstr), \ + .data = zstr, \ + .alignment = 1 \ + }) : \ + (Str)VecInit()) +#else +/// Initialize a Str object using a zero-terminated string and take ownership of the string. +/// +/// zstr[in] : Zero-terminated string to be initialized. +/// +/// SUCCESS : `str` +/// FAILURE : Empty Str object +/// +# define StrOwnZstr(zstr) \ + (zstr ? ((Str) {.length = strlen (zstr), \ + .capacity = strlen (zstr), \ + .data = zstr, \ + .alignment = 1}) : \ + (Str)VecInit()) +#endif + /// /// Initialize a Str object using a zero-terminated string /// diff --git a/Source/Reai/Api.c b/Source/Reai/Api.c index 136755e..a41840f 100644 --- a/Source/Reai/Api.c +++ b/Source/Reai/Api.c @@ -124,20 +124,28 @@ BinaryId CreateNewAnalysis (Connection* conn, NewAnalysisRequest* request) { return binary_id; } else { + StrDeinit (&url); + StrDeinit (&sj); + StrDeinit (&gj); return 0; } } -FunctionInfos GetBasicFunctionInfoUsingBinaryId (Connection* conn, BinaryId binary_id) { +FunctionInfos GetFunctionsList (Connection* conn, AnalysisId analysis_id) { if (!conn->api_key.length || !conn->host.length) { LOG_ERROR ("Missing API key or host to connect to."); return (FunctionInfos) {0}; } + if (!analysis_id) { + LOG_ERROR ("Invalid analysis id."); + return (FunctionInfos) {0}; + } + Str url = StrInit(); Str gj = StrInit(); - StrPrintf (&url, "%s/v1/analyse/functions/%llu", conn->host.data, binary_id); + StrPrintf (&url, "%s/v2/analyses/%llu/functions/list", conn->host.data, analysis_id); if (MakeRequest (&conn->user_agent, &conn->api_key, &url, NULL, &gj, "GET")) { StrDeinit (&url); @@ -148,16 +156,19 @@ FunctionInfos GetBasicFunctionInfoUsingBinaryId (Connection* conn, BinaryId bina JR_OBJ (j, { JR_BOOL_KV (j, "success", success); if (success) { - JR_ARR_KV (j, "functions", { - FunctionInfo function = {0}; - function.symbol.is_addr = true; - JR_OBJ (j, { - JR_INT_KV (j, "function_id", function.id); - JR_STR_KV (j, "function_name", function.symbol.name); - JR_INT_KV (j, "function_size", function.size); - JR_INT_KV (j, "function_vaddr", function.symbol.value.addr); + JR_OBJ_KV (j, "data", { + JR_ARR_KV (j, "functions", { + FunctionInfo function = {0}; + function.symbol.is_addr = true; + JR_OBJ (j, { + JR_INT_KV (j, "function_id", function.id); + JR_STR_KV (j, "function_name", function.symbol.name); + JR_INT_KV (j, "function_size", function.size); + JR_INT_KV (j, "function_vaddr", function.symbol.value.addr); + JR_BOOL_KV (j, "debug", function.debug); + }); + VecPushBack (&functions, function); }); - VecPushBack (&functions, function); }); } }); @@ -166,12 +177,12 @@ FunctionInfos GetBasicFunctionInfoUsingBinaryId (Connection* conn, BinaryId bina return functions; } else { + StrDeinit (&url); + StrDeinit (&gj); return (FunctionInfos) {0}; } } -// TODO: GetBasicFunctionInfoUsingAnalysisId - AnalysisInfos GetRecentAnalysis (Connection* conn, RecentAnalysisRequest* request) { if (!conn->api_key.length || !conn->host.length) { LOG_ERROR ("Missing API key or host to connect to."); @@ -272,6 +283,8 @@ AnalysisInfos GetRecentAnalysis (Connection* conn, RecentAnalysisRequest* reques return infos; } else { + StrDeinit (&url); + StrDeinit (&gj); return (AnalysisInfos) {0}; } } @@ -340,6 +353,8 @@ BinaryInfos SearchBinary (Connection* conn, SearchBinaryRequest* request) { return infos; } else { + StrDeinit (&url); + StrDeinit (&gj); return (BinaryInfos) {0}; } } @@ -447,6 +462,8 @@ CollectionInfos SearchCollection (Connection* conn, SearchCollectionRequest* req return infos; } else { + StrDeinit (&url); + StrDeinit (&gj); return (CollectionInfos) {0}; } } @@ -486,6 +503,9 @@ bool BatchRenameFunctions (Connection* conn, FunctionInfos functions) { return status; } else { + StrDeinit (&url); + StrDeinit (&sj); + StrDeinit (&gj); return false; } } @@ -527,6 +547,9 @@ bool RenameFunction (Connection* conn, FunctionId fn_id, Str new_name) { return status; } else { + StrDeinit (&url); + StrDeinit (&sj); + StrDeinit (&gj); return false; } } @@ -624,6 +647,9 @@ AnnSymbols GetBatchAnnSymbols (Connection* conn, BatchAnnSymbolRequest* request) return syms; } else { + StrDeinit (&url); + StrDeinit (&sj); + StrDeinit (&gj); return (AnnSymbols) {0}; } } @@ -660,11 +686,12 @@ Status GetAnalysisStatus (Connection* conn, BinaryId binary_id) { StrDeinit (&status); return analysis_status; } else { + StrDeinit (&url); + StrDeinit (&gj); return STATUS_INVALID; } } - ModelInfos GetAiModelInfos (Connection* conn) { if (!conn->api_key.length || !conn->host.length) { LOG_ERROR ("Missing API key or host to connect to."); @@ -702,6 +729,8 @@ ModelInfos GetAiModelInfos (Connection* conn) { return models; } else { + StrDeinit (&url); + StrDeinit (&gj); return (ModelInfos) {0}; } } @@ -735,6 +764,8 @@ bool BeginAiDecompilation (Connection* conn, FunctionId function_id) { return status; } else { + StrDeinit (&url); + StrDeinit (&gj); return false; } } @@ -775,6 +806,8 @@ Status GetAiDecompilationStatus (Connection* conn, FunctionId function_id) { StrDeinit (&status_str); return decomp_status; } else { + StrDeinit (&url); + StrDeinit (&gj); return STATUS_INVALID; } } @@ -962,6 +995,8 @@ AiDecompilation GetAiDecompilation (Connection* conn, FunctionId function_id, bo StrDeinit (&gj); return decomp; } else { + StrDeinit (&url); + StrDeinit (&gj); return (AiDecompilation) {0}; } } @@ -1060,6 +1095,8 @@ ControlFlowGraph GetFunctionControlFlowGraph (Connection* conn, FunctionId funct StrDeinit (&gj); return cfg; } else { + StrDeinit (&url); + StrDeinit (&gj); return (ControlFlowGraph) {0}; } } @@ -1154,10 +1191,406 @@ SimilarFunctions GetSimilarFunctions (Connection* conn, SimilarFunctionsRequest* StrDeinit (&gj); return functions; } else { + StrDeinit (&url); + StrDeinit (&gj); return (SimilarFunctions) {0}; } } +bool BeginFunctionTypeGeneration ( + Connection* conn, + AnalysisId analysis_id, + FunctionIds function_ids +) { + if (!conn->api_key.length || !conn->host.length) { + LOG_ERROR ("Missing API key or host to connect to."); + return false; + } + + if (!analysis_id) { + LOG_ERROR ("Invalid analysis id."); + return false; + } + + Str url = StrInit(); + Str gj = StrInit(); + Str sj = StrInit(); + + JW_OBJ (sj, { + JW_ARR_KV (sj, "function_ids", function_ids, function_id, { JW_INT (sj, function_id); }); + }); + + StrPrintf (&url, "%s/v2/analyses/%llu/functions/data_types", conn->host.data, analysis_id); + + if (MakeRequest (&conn->user_agent, &conn->api_key, &url, &sj, &gj, "POST")) { + StrDeinit (&url); + StrDeinit (&gj); + StrDeinit (&sj); + return true; + } + + StrDeinit (&url); + StrDeinit (&gj); + StrDeinit (&sj); + return false; +} + +bool BeginFunctionTypeGenerationForAllFunctions (Connection* conn, AnalysisId analysis_id) { + if (!conn->api_key.length || !conn->host.length) { + LOG_ERROR ("Missing API key or host to connect to."); + return false; + } + + if (!analysis_id) { + LOG_ERROR ("Invalid analysis id."); + return false; + } + + Str url = StrInit(); + Str gj = StrInit(); + Str sj = StrInit(); + + FunctionInfos functions = GetFunctionsList (conn, analysis_id); + JW_OBJ (sj, { + JW_ARR_KV (sj, "function_ids", functions, function, { JW_INT (sj, function.id); }); + }); + VecDeinit (&functions); + + StrPrintf (&url, "%s/v2/analyses/%llu/functions/data_types", conn->host.data, analysis_id); + + if (MakeRequest (&conn->user_agent, &conn->api_key, &url, &sj, &gj, "POST")) { + StrDeinit (&url); + StrDeinit (&gj); + StrDeinit (&sj); + return true; + } + + StrDeinit (&url); + StrDeinit (&gj); + StrDeinit (&sj); + return false; +} + +/// +/// Helper function to parse data type from JSON. +/// +/// json[in] : JSON iterator +/// +/// SUCCESS : DataType object +/// FAILURE : NULL +/// +DataType* JrDataType (StrIter* json) { + DataType* dt = NEW (DataType); + *dt = DataTypeInit(); + StrIter j = *json; + JR_OBJ (j, { + JR_STR_KV (j, "last_change", dt->last_change); + JR_INT_KV (j, "offset", dt->offset); + JR_INT_KV (j, "size", dt->size); + JR_STR_KV (j, "name", dt->name); + JR_STR_KV (j, "type", dt->type); + JR_STR_KV (j, "artifact_type", dt->artifact_type); + JR_OBJ_KV (j, "members", { + DataType* dtm = JrDataType (&j); + VecPushBack (&dt->members, dtm); + }); + }); + *json = j; + return dt; +} + +bool IsFunctionTypeGenerationCompleted ( + Connection* conn, + AnalysisId analysis_id, + FunctionId function_id +) { + if (!conn->api_key.length || !conn->host.length) { + LOG_ERROR ("Missing API key or host to connect to."); + return false; + } + + if (!function_id) { + LOG_ERROR ("Invalid function id."); + return false; + } + + Str url = StrInit(); + Str gj = StrInit(); + + StrPrintf (&url, "%s/v2/analyses/%llu/functions", conn->host.data, analysis_id); + + Str sj = StrInit(); + StrPrintf (&sj, "{\"function_ids\":[%llu]}", function_id); + + if (MakeRequest (&conn->user_agent, &conn->api_key, &url, &sj, &gj, "POST")) { + StrDeinit (&url); + StrDeinit (&sj); + + StrIter j = StrIterInitFromStr (&gj); + + JR_OBJ (j, { + bool status = false; + JR_BOOL_KV (j, "status", status); + if (status) { + JR_OBJ_KV (j, "data", { + JR_OBJ_KV (j, "data_types_list", { + JR_ARR_KV (j, "items", { + FunctionId fn_id = 0; + bool completed = false; + + JR_OBJ (j, { + JR_INT_KV (j, "function_id", fn_id); + JR_BOOL_KV (j, "completed", completed); + }); + + if ((fn_id == function_id) && completed) { + StrDeinit (&gj); + return true; + } + }); + }); + }); + } + }); + + StrDeinit (&gj); + return false; + } + + StrDeinit (&url); + StrDeinit (&gj); + StrDeinit (&sj); + return false; +} + +bool IsFunctionTypeGenerationCompletedForAllFunctions (Connection* conn, AnalysisId analysis_id) { + if (!conn->api_key.length || !conn->host.length) { + LOG_ERROR ("Missing API key or host to connect to."); + return false; + } + + if (!analysis_id) { + LOG_ERROR ("Invalid analysis id."); + return false; + } + + FunctionInfos functions = GetFunctionsList (conn, analysis_id); + VecForeach (&functions, function, { + if (!IsFunctionTypeGenerationCompleted (conn, analysis_id, function.id)) { + VecDeinit (&functions); + return false; + } + }); + VecDeinit (&functions); + + Str sj = StrInit(); + JW_OBJ (sj, { + JW_ARR_KV (sj, "function_ids", functions, function, { JW_INT (sj, function.id); }); + }); + + Str url = StrInit(); + StrPrintf (&url, "%s/v2/analyses/%llu/functions/data_types", conn->host.data, analysis_id); + Str gj = StrInit(); + + if (MakeRequest (&conn->user_agent, &conn->api_key, &url, &sj, &gj, "POST")) { + StrDeinit (&url); + StrDeinit (&sj); + + StrIter j = StrIterInitFromStr (&gj); + bool status = false; + JR_OBJ (j, { + JR_BOOL_KV (j, "status", status); + if (status) { + JR_OBJ_KV (j, "data", { + JR_OBJ_KV (j, "data_types_list", { + JR_ARR_KV (j, "items", { + JR_OBJ (j, { + bool completed = false; + JR_BOOL_KV (j, "completed", completed); + if (!completed) { + StrDeinit (&gj); + return false; + } + }); + }); + }); + }); + } + }); + + StrDeinit (&gj); + return status; + } + + StrDeinit (&url); + StrDeinit (&gj); + StrDeinit (&sj); + return false; +} + +FunctionType GetFunctionType (Connection* conn, FunctionId function_id) { + if (!conn->api_key.length || !conn->host.length) { + LOG_ERROR ("Missing API key or host to connect to."); + return (FunctionType) {0}; + } + + if (!function_id) { + LOG_ERROR ("Invalid function id."); + return (FunctionType) {0}; + } + + Str url = StrInit(); + Str gj = StrInit(); + + StrPrintf (&url, "%s/v2/functions/%llu/data_types", conn->host.data, function_id); + + if (MakeRequest (&conn->user_agent, &conn->api_key, &url, NULL, &gj, "GET")) { + StrDeinit (&url); + + StrIter j = StrIterInitFromStr (&gj); + + bool status = false; + FunctionType ft = FunctionTypeInit(); + + JR_OBJ (j, { + JR_BOOL_KV (j, "status", status); + if (status) { + JR_OBJ_KV (j, "data", { + bool completed = false; + JR_BOOL_KV (j, "completed", completed); + if (completed) { + JR_OBJ_KV (j, "data_types", { + JR_OBJ_KV (j, "func_types", { + JR_INT_KV (j, "size", ft.size); + JR_OBJ_KV (j, "header", { + JR_STR_KV (j, "last_change", ft.last_change); + JR_STR_KV (j, "name", ft.name); + JR_INT_KV (j, "addr", ft.addr); + JR_STR_KV (j, "return_type", ft.return_type); + JR_OBJ_KV (j, "args", { + DataType* dt = JrDataType (&j); + VecPushBack (&ft.args, dt); + }); + }); + JR_OBJ_KV (j, "stack_vars", { + DataType* dt = JrDataType (&j); + VecPushBack (&ft.stack_vars, dt); + }); + }); + JR_OBJ_KV (j, "func_deps", { + DataType* dt = JrDataType (&j); + VecPushBack (&ft.deps, dt); + }); + }); + } else { + LOG_INFO ("Function type is not completed"); + } + }); + } else { + LOG_INFO ("Status is false"); + } + }); + + StrDeinit (&gj); + return ft; + } else { + StrDeinit (&url); + StrDeinit (&gj); + return (FunctionType) {0}; + } +} + +Str* JwDataType (Str* sjson, DataType* dt) { + if (!dt || !sjson) { + LOG_FATAL ("Invalid data type or string json."); + } + + Str sj = *sjson; + JW_OBJ (sj, { + JW_STR_KV (sj, "type", dt->type); + JW_STR_KV (sj, "name", dt->name); + JW_INT_KV (sj, "size", dt->size); + JW_STR_KV (sj, "last_change", dt->last_change); + JW_STR_KV (sj, "artifact_type", dt->artifact_type); + JW_ARR_KV (sj, "members", dt->members, member, { + *sjson = sj; + JwDataType (sjson, member); + }); + }); + *sjson = sj; + + return sjson; +} + +bool SetFunctionType ( + Connection* conn, + AnalysisId analysis_id, + FunctionId function_id, + FunctionType function_type +) { + if (!conn->api_key.length || !conn->host.length) { + LOG_ERROR ("Missing API key or host to connect to."); + return false; + } + + if (!function_id) { + LOG_ERROR ("Invalid function id."); + return false; + } + + Str url = StrInit(); + Str gj = StrInit(); + Str sj = StrInit(); + + StrPrintf ( + &url, + "%s/v2/analyses/%llu/functions/%llu/data_types", + conn->host.data, + analysis_id, + function_id + ); + + JW_OBJ (sj, { + JW_INT_KV (sj, "data_types_version", 0); + JW_OBJ_KV (sj, "data_types", { + JW_OBJ_KV (sj, "func_types", { + JW_STR_KV (sj, "last_change", function_type.last_change); + JW_INT_KV (sj, "addr", function_type.addr); + JW_INT_KV (sj, "size", function_type.size); + JW_OBJ_KV (sj, "header", { + JW_STR_KV (sj, "last_change", function_type.last_change); + JW_STR_KV (sj, "name", function_type.name); + JW_INT_KV (sj, "addr", function_type.addr); + JW_STR_KV (sj, "type", function_type.return_type); + JW_ARR_KV (sj, "args", function_type.args, arg, { JwDataType (&sj, arg); }); + }); + JW_ARR_KV (sj, "stack_vars", function_type.stack_vars, var, { + JwDataType (&sj, var); + }); + JW_STR_KV (sj, "name", function_type.name); + JW_STR_KV (sj, "type", function_type.return_type); + JW_ZSTR_KV (sj, "artifact_type", "Function"); + }); + }); + JW_OBJ_KV (sj, "func_deps", { + JW_ARR_KV (sj, "items", function_type.deps, dep, { JwDataType (&sj, dep); }); + }); + }); + + if (MakeRequest (&conn->user_agent, &conn->api_key, &url, &sj, &gj, "PUT")) { + StrDeinit (&url); + StrDeinit (&sj); + StrDeinit (&gj); + return true; + } + + StrDeinit (&url); + StrDeinit (&sj); + StrDeinit (&gj); + + return false; +} + AnalysisId AnalysisIdFromBinaryId (Connection* conn, BinaryId binary_id) { if (!conn->api_key.length || !conn->host.length) { LOG_ERROR ("Missing API key or host to connect to."); @@ -1187,6 +1620,8 @@ AnalysisId AnalysisIdFromBinaryId (Connection* conn, BinaryId binary_id) { return id; } else { + StrDeinit (&url); + StrDeinit (&gj); return 0; } } @@ -1225,6 +1660,8 @@ Str GetAnalysisLogs (Connection* conn, AnalysisId analysis_id) { return logs; } else { + StrDeinit (&url); + StrDeinit (&gj); return (Str) {0}; } } @@ -1269,6 +1706,8 @@ Str UploadFile (Connection* conn, Str file_path) { return sha256; } else { + StrDeinit (&url); + StrDeinit (&gj); return (Str) {0}; } } diff --git a/Source/Reai/Api/Types/DataType.c b/Source/Reai/Api/Types/DataType.c new file mode 100644 index 0000000..0c3fd95 --- /dev/null +++ b/Source/Reai/Api/Types/DataType.c @@ -0,0 +1,85 @@ +/** + * @file DataType.c + * @date 1st April 2025 + * @author Siddharth Mishra (admin@brightprogrammer.in) + * @copyright Copyright (c) RevEngAI. All Rights Reserved. + * */ + +#include +#include + +/* libc */ +#include + +#include "Reai/Util/Vec.h" + +void DataTypeDeinit (DataType** dt) { + if (!dt || !*dt) { + LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); + } + + DataType* d = *dt; + + StrDeinit (&d->last_change); + StrDeinit (&d->name); + StrDeinit (&d->type); + StrDeinit (&d->artifact_type); + VecDeinit (&d->members); + + memset (d, 0, sizeof (*d)); + *dt = NULL; +} + +bool DataTypeInitClone (DataType** dst, DataType** src) { + if (!dst || !src) { + LOG_FATAL ("Invalid objects provided for cloning. Cannot clone. Aborting..."); + } + + DataType* d = *dst; + DataType* s = *src; + + StrInitCopy (&d->last_change, &s->last_change); + d->offset = s->offset; + d->size = s->size; + StrInitCopy (&d->name, &s->name); + StrInitCopy (&d->type, &s->type); + StrInitCopy (&d->artifact_type, &s->artifact_type); + + d->members = VecInitWithDeepCopy_T (&d->members, DataTypeInitClone, DataTypeDeinit); + VecInitClone (&d->members, &s->members); + d->members.copy_init = NULL; + + return true; +} + +void FunctionTypeDeinit (FunctionType* ft) { + if (!ft) { + LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); + } + + StrDeinit (&ft->last_change); + StrDeinit (&ft->name); + StrDeinit (&ft->return_type); + VecDeinit (&ft->args); + VecDeinit (&ft->stack_vars); + VecDeinit (&ft->deps); + + memset (ft, 0, sizeof (*ft)); +} + +bool FunctionTypeInitClone (FunctionType* dst, FunctionType* src) { + if (!dst || !src) { + LOG_FATAL ("Invalid objects provided for cloning. Cannot clone. Aborting..."); + } + + StrInitCopy (&dst->last_change, &src->last_change); + dst->addr = src->addr; + dst->size = src->size; + StrInitCopy (&dst->name, &src->name); + StrInitCopy (&dst->return_type, &src->return_type); + VecInitClone (&dst->args, &src->args); + VecInitClone (&dst->stack_vars, &src->stack_vars); + VecInitClone (&dst->deps, &src->deps); + + return true; +} diff --git a/Source/Reai/Api/Types/FunctionInfo.c b/Source/Reai/Api/Types/FunctionInfo.c index bc0ff73..ef7ffd5 100644 --- a/Source/Reai/Api/Types/FunctionInfo.c +++ b/Source/Reai/Api/Types/FunctionInfo.c @@ -29,6 +29,7 @@ bool FunctionInfoInitClone (FunctionInfo* dst, FunctionInfo* src) { dst->id = src->id; dst->size = src->size; SymbolInfoInitClone (&dst->symbol, &src->symbol); + dst->debug = src->debug; return true; } From a84b9343e66647ece64500e77e9d4c49e0b232fa Mon Sep 17 00:00:00 2001 From: Siddharth Mishra Date: Sat, 5 Jul 2025 22:39:33 +0530 Subject: [PATCH 2/5] GetFunctionsList JSON Parsing Fix (success->status) --- Source/Reai/Api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Reai/Api.c b/Source/Reai/Api.c index a41840f..e697a8e 100644 --- a/Source/Reai/Api.c +++ b/Source/Reai/Api.c @@ -151,11 +151,11 @@ FunctionInfos GetFunctionsList (Connection* conn, AnalysisId analysis_id) { StrIter j = StrIterInitFromStr (&gj); - bool success = false; + bool status = false; FunctionInfos functions = VecInitWithDeepCopy (NULL, FunctionInfoDeinit); JR_OBJ (j, { - JR_BOOL_KV (j, "success", success); - if (success) { + JR_BOOL_KV (j, "status", status); + if (status) { JR_OBJ_KV (j, "data", { JR_ARR_KV (j, "functions", { FunctionInfo function = {0}; From 2d8456c60cb597d672c0bcd6a04c63fb3c6207d4 Mon Sep 17 00:00:00 2001 From: Siddharth Mishra Date: Mon, 7 Jul 2025 23:28:04 +0530 Subject: [PATCH 3/5] JI_ Macros, Fixes To Conditional Object Reading --- Include/Reai/Api.h | 3 +- Include/Reai/Util/Json.h | 93 ++++++++++++++++++++++++++++++++++++++-- Source/Reai/Api.c | 73 +++++++++++++++++++------------ Source/Reai/Util/Json.c | 18 ++++---- 4 files changed, 147 insertions(+), 40 deletions(-) diff --git a/Include/Reai/Api.h b/Include/Reai/Api.h index 63a284a..e259858 100644 --- a/Include/Reai/Api.h +++ b/Include/Reai/Api.h @@ -434,7 +434,8 @@ extern "C" { /// SUCCESS: FunctionType object /// FAILURE: Empty FunctionType object /// - REAI_API FunctionType GetFunctionType (Connection* conn, FunctionId function_id); + REAI_API FunctionType + GetFunctionType (Connection* conn, AnalysisId analysis_id, FunctionId function_id); /// /// Set function type for a specific function. diff --git a/Include/Reai/Util/Json.h b/Include/Reai/Util/Json.h index dbcb85d..89be0c2 100644 --- a/Include/Reai/Util/Json.h +++ b/Include/Reai/Util/Json.h @@ -234,14 +234,15 @@ extern "C" { /// /// Skip the current JSON value at reading position. /// - /// si[in] : Current position in string iterator to skip value from + /// si[in] : Current position in string iterator to skip value from + /// enable_logging[in] : Whether to log skipped field names /// /// SUCCESS : Returns updated `StrIter` after value is skipped /// FAILURE : Returns same `StrIter` on error (e.g. invalid type) /// /// TAGS: JSON, Parsing, Utility /// - REAI_API StrIter JSkipValue (StrIter si); + REAI_API StrIter JSkipValue (StrIter si, bool enable_logging); #ifdef __cplusplus } @@ -493,7 +494,7 @@ extern "C" { /* if no advancement in read position */ \ if (si_before_read.pos == si.pos) { \ /* skip the value */ \ - StrIter read_si = JSkipValue (si); \ + StrIter read_si = JSkipValue (si, true); \ \ /* if still no advancement in read position */ \ if (read_si.pos == si.pos) { \ @@ -616,7 +617,7 @@ extern "C" { /* if no advancement in read position */ \ if (si_before_read.pos == si.pos) { \ /* skip the value */ \ - StrIter read_si = JSkipValue (si); \ + StrIter read_si = JSkipValue (si, true); \ \ \ /* if still no advancement in read position */ \ @@ -675,6 +676,90 @@ extern "C" { } \ } while (0) +#define JI_OBJ(si) \ + do { \ + JSkipValue (si, false); \ + } while (0) + +#define JI_OBJ_KV(si, k) \ + do { \ + if (!StrCmpZstr (&key, (k))) { \ + JSkipValue (si, false); \ + } \ + } while (0) + +#define JI_ARR(si) \ + do { \ + JSkipValue (si, false); \ + } while (0) + +#define JI_ARR_KV(si, k) \ + do { \ + if (!StrCmpZstr (&key, (k))) { \ + JSkipValue (si, false); \ + } \ + } while (0) + +#define JI_STR(si) \ + do { \ + JSkipValue (si, false); \ + } while (0) + +#define JI_STR_KV(si, k) \ + do { \ + if (!StrCmpZstr (&key, (k))) { \ + JSkipValue (si, false); \ + } \ + } while (0) + +#define JI_FLT(si) \ + do { \ + JSkipValue (si, false); \ + } while (0) + +#define JI_FLT_KV(si, k) \ + do { \ + if (!StrCmpZstr (&key, (k))) { \ + JSkipValue (si, false); \ + } \ + } while (0) + +#define JI_INT(si) \ + do { \ + JSkipValue (si, false); \ + } while (0) + +#define JI_INT_KV(si, k) \ + do { \ + if (!StrCmpZstr (&key, (k))) { \ + JSkipValue (si, false); \ + } \ + } while (0) + +#define JI_ZSTR(si) \ + do { \ + JSkipValue (si, false); \ + } while (0) + +#define JI_ZSTR_KV(si, k) \ + do { \ + if (!StrCmpZstr (&key, (k))) { \ + JSkipValue (si, false); \ + } \ + } while (0) + +#define JI_BOOL(si) \ + do { \ + JSkipValue (si, false); \ + } while (0) + +#define JI_BOOL_KV(si, k) \ + do { \ + if (!StrCmpZstr (&key, (k))) { \ + JSkipValue (si, false); \ + } \ + } while (0) + /// /// Conditionally parse a JSON array if key matches expected name. /// diff --git a/Source/Reai/Api.c b/Source/Reai/Api.c index e697a8e..2698c8d 100644 --- a/Source/Reai/Api.c +++ b/Source/Reai/Api.c @@ -1291,7 +1291,9 @@ DataType* JrDataType (StrIter* json) { JR_STR_KV (j, "type", dt->type); JR_STR_KV (j, "artifact_type", dt->artifact_type); JR_OBJ_KV (j, "members", { - DataType* dtm = JrDataType (&j); + *json = j; + DataType* dtm = JrDataType (json); + j = *json; VecPushBack (&dt->members, dtm); }); }); @@ -1317,7 +1319,7 @@ bool IsFunctionTypeGenerationCompleted ( Str url = StrInit(); Str gj = StrInit(); - StrPrintf (&url, "%s/v2/analyses/%llu/functions", conn->host.data, analysis_id); + StrPrintf (&url, "%s/v2/analyses/%llu/functions/data_types", conn->host.data, analysis_id); Str sj = StrInit(); StrPrintf (&sj, "{\"function_ids\":[%llu]}", function_id); @@ -1345,6 +1347,10 @@ bool IsFunctionTypeGenerationCompleted ( if ((fn_id == function_id) && completed) { StrDeinit (&gj); + LOG_INFO ( + "Function type generation complete for function with ID = %llu", + function_id + ); return true; } }); @@ -1353,6 +1359,8 @@ bool IsFunctionTypeGenerationCompleted ( } }); + LOG_INFO ("Function type generation incomplete for function with ID = %llu", function_id); + StrDeinit (&gj); return false; } @@ -1374,19 +1382,12 @@ bool IsFunctionTypeGenerationCompletedForAllFunctions (Connection* conn, Analysi return false; } + Str sj = StrInit(); FunctionInfos functions = GetFunctionsList (conn, analysis_id); - VecForeach (&functions, function, { - if (!IsFunctionTypeGenerationCompleted (conn, analysis_id, function.id)) { - VecDeinit (&functions); - return false; - } - }); - VecDeinit (&functions); - - Str sj = StrInit(); JW_OBJ (sj, { JW_ARR_KV (sj, "function_ids", functions, function, { JW_INT (sj, function.id); }); }); + VecDeinit (&functions); Str url = StrInit(); StrPrintf (&url, "%s/v2/analyses/%llu/functions/data_types", conn->host.data, analysis_id); @@ -1404,20 +1405,24 @@ bool IsFunctionTypeGenerationCompletedForAllFunctions (Connection* conn, Analysi JR_OBJ_KV (j, "data", { JR_OBJ_KV (j, "data_types_list", { JR_ARR_KV (j, "items", { - JR_OBJ (j, { - bool completed = false; - JR_BOOL_KV (j, "completed", completed); - if (!completed) { - StrDeinit (&gj); - return false; - } - }); + bool completed = false; + JR_OBJ (j, { JR_BOOL_KV (j, "completed", completed); }); + if (!completed) { + LOG_INFO ( + "Function type generation still incomplete for all " + "functions., Completed = %s", + completed ? "true" : "false" + ); + StrDeinit (&gj); + return false; + } }); }); }); } }); + LOG_INFO ("Function type generation completed for all functions!"); StrDeinit (&gj); return status; } @@ -1428,7 +1433,7 @@ bool IsFunctionTypeGenerationCompletedForAllFunctions (Connection* conn, Analysi return false; } -FunctionType GetFunctionType (Connection* conn, FunctionId function_id) { +FunctionType GetFunctionType (Connection* conn, AnalysisId analysis_id, FunctionId function_id) { if (!conn->api_key.length || !conn->host.length) { LOG_ERROR ("Missing API key or host to connect to."); return (FunctionType) {0}; @@ -1442,31 +1447,41 @@ FunctionType GetFunctionType (Connection* conn, FunctionId function_id) { Str url = StrInit(); Str gj = StrInit(); - StrPrintf (&url, "%s/v2/functions/%llu/data_types", conn->host.data, function_id); + StrPrintf ( + &url, + "%s/v2/analyses/%llu/functions/%llu/data_types", + conn->host.data, + analysis_id, + function_id + ); if (MakeRequest (&conn->user_agent, &conn->api_key, &url, NULL, &gj, "GET")) { StrDeinit (&url); StrIter j = StrIterInitFromStr (&gj); - bool status = false; - FunctionType ft = FunctionTypeInit(); + bool status = false; + bool completed = false; + FunctionType ft = FunctionTypeInit(); JR_OBJ (j, { JR_BOOL_KV (j, "status", status); if (status) { JR_OBJ_KV (j, "data", { - bool completed = false; JR_BOOL_KV (j, "completed", completed); + JI_STR_KV (j, "status"); if (completed) { JR_OBJ_KV (j, "data_types", { JR_OBJ_KV (j, "func_types", { + JI_STR_KV (j, "last_change"); + JI_STR_KV (j, "name"); + JI_INT_KV (j, "addr"); JR_INT_KV (j, "size", ft.size); JR_OBJ_KV (j, "header", { JR_STR_KV (j, "last_change", ft.last_change); JR_STR_KV (j, "name", ft.name); JR_INT_KV (j, "addr", ft.addr); - JR_STR_KV (j, "return_type", ft.return_type); + JR_STR_KV (j, "type", ft.return_type); JR_OBJ_KV (j, "args", { DataType* dt = JrDataType (&j); VecPushBack (&ft.args, dt); @@ -1477,18 +1492,22 @@ FunctionType GetFunctionType (Connection* conn, FunctionId function_id) { VecPushBack (&ft.stack_vars, dt); }); }); - JR_OBJ_KV (j, "func_deps", { + JR_ARR_KV (j, "func_deps", { DataType* dt = JrDataType (&j); VecPushBack (&ft.deps, dt); }); }); } else { - LOG_INFO ("Function type is not completed"); + LOG_INFO ("Function type generation is not completed"); } + JI_INT_KV (j, "data_types_version"); }); } else { LOG_INFO ("Status is false"); } + JI_STR_KV (j, "message"); + JI_OBJ_KV (j, "errors"); + JI_OBJ_KV (j, "meta"); }); StrDeinit (&gj); diff --git a/Source/Reai/Util/Json.c b/Source/Reai/Util/Json.c index b492987..458ccaa 100644 --- a/Source/Reai/Util/Json.c +++ b/Source/Reai/Util/Json.c @@ -1,7 +1,7 @@ #include #include -static StrIter JSkipObject (StrIter si) { +static StrIter JSkipObject (StrIter si, bool enable_logging) { if (!StrIterRemainingLength (&si)) { return si; } @@ -55,7 +55,7 @@ static StrIter JSkipObject (StrIter si) { si = JSkipWhitespace (si); // skip values within object - read_si = JSkipValue (si); + read_si = JSkipValue (si, enable_logging); // if still no advancement in read position if (read_si.pos == si.pos) { @@ -64,7 +64,9 @@ static StrIter JSkipObject (StrIter si) { return saved_si; } - LOG_INFO ("User skipped reading of '%s' field in JSON object.", key.data); + if (enable_logging) { + LOG_INFO ("User skipped reading of '%s' field in JSON object.", key.data); + } StrDeinit (&key); si = read_si; @@ -83,7 +85,7 @@ static StrIter JSkipObject (StrIter si) { return si; } -static StrIter JSkipArray (StrIter si) { +static StrIter JSkipArray (StrIter si, bool enable_logging) { if (!StrIterRemainingLength (&si)) { return si; } @@ -114,7 +116,7 @@ static StrIter JSkipArray (StrIter si) { } // skip values within array - read_si = JSkipValue (si); + read_si = JSkipValue (si, enable_logging); // if no advancement in read position if (read_si.pos == si.pos) { @@ -540,7 +542,7 @@ StrIter JReadNull (StrIter si, bool* is_null) { } } -StrIter JSkipValue (StrIter si) { +StrIter JSkipValue (StrIter si, bool enable_logging) { if (!StrIterRemainingLength (&si)) { return si; } @@ -615,7 +617,7 @@ StrIter JSkipValue (StrIter si) { // looks like starting of an object if (StrIterPeek (&si) == '{') { StrIter before_si = si; - si = JSkipObject (si); + si = JSkipObject (si, enable_logging); if (si.pos == before_si.pos) { LOG_ERROR ("Failed to read object. Expected an object. Invalid JSON."); @@ -628,7 +630,7 @@ StrIter JSkipValue (StrIter si) { // looks like starting of an array if (StrIterPeek (&si) == '[') { StrIter before_si = si; - si = JSkipArray (si); + si = JSkipArray (si, enable_logging); if (si.pos == before_si.pos) { LOG_ERROR ("Failed to read array. Expected an array. Invalid JSON."); From 174af88624f9a660a60a73fdd4df3e9f6a165d31 Mon Sep 17 00:00:00 2001 From: Siddharth Mishra Date: Wed, 9 Jul 2025 20:12:01 +0530 Subject: [PATCH 4/5] Compatibility With LibBS & Type Redundancy In ControlFlowGraph, DataType --- Include/Reai/Api.h | 4 +- Include/Reai/Api/Types/ControlFlowGraph.h | 5 +- Include/Reai/Api/Types/DataType.h | 419 ++++++++++++++++++---- Source/Reai/Api.c | 12 +- Source/Reai/Api/Types/DataType.c | 201 +++++++++-- 5 files changed, 517 insertions(+), 124 deletions(-) diff --git a/Include/Reai/Api.h b/Include/Reai/Api.h index e259858..837b3f6 100644 --- a/Include/Reai/Api.h +++ b/Include/Reai/Api.h @@ -434,7 +434,7 @@ extern "C" { /// SUCCESS: FunctionType object /// FAILURE: Empty FunctionType object /// - REAI_API FunctionType + REAI_API Function GetFunctionType (Connection* conn, AnalysisId analysis_id, FunctionId function_id); /// @@ -452,7 +452,7 @@ extern "C" { Connection* conn, AnalysisId analysis_id, FunctionId function_id, - FunctionType function_type + Function function_type ); /// Retrieves log data for a specific analysis job. diff --git a/Include/Reai/Api/Types/ControlFlowGraph.h b/Include/Reai/Api/Types/ControlFlowGraph.h index eeb13a8..9338140 100644 --- a/Include/Reai/Api/Types/ControlFlowGraph.h +++ b/Include/Reai/Api/Types/ControlFlowGraph.h @@ -32,6 +32,9 @@ typedef struct Block { typedef Vec (Block) Blocks; +// XXX: conflicts with definition in DataType.h +// Both are mergeable! Defining a separate one creates confusion +// and type-redundancy typedef struct LocalVariable { Str address; Str d_type; @@ -132,4 +135,4 @@ extern "C" { } #endif -#endif // REAI_CONTROL_FLOW_GRAPH_H \ No newline at end of file +#endif // REAI_CONTROL_FLOW_GRAPH_H diff --git a/Include/Reai/Api/Types/DataType.h b/Include/Reai/Api/Types/DataType.h index a72e426..9ca4ce0 100644 --- a/Include/Reai/Api/Types/DataType.h +++ b/Include/Reai/Api/Types/DataType.h @@ -1,3 +1,11 @@ +/** + * @file DataType.h + * @date 9th July 2025 + * @author Siddharth Mishra (admin@brightprogrammer.in) + * @copyright Copyright (c) RevEngAI. All Rights Reserved. + * */ + + #ifndef REAI_DATA_TYPE_H #define REAI_DATA_TYPE_H @@ -5,126 +13,381 @@ #include #include -typedef struct DataType DataType; -typedef Vec (DataType*) DataTypes; +typedef struct Typedef { + Str name; + Str type; +} Typedef; -struct DataType { - Str last_change; - u64 offset; - u64 size; - Str name; - Str type; - Str artifact_type; - DataTypes members; -}; +typedef Vec (Typedef) Typedefs; -#ifdef __cplusplus -# define DataTypeInit() \ - (DataType { \ - .last_change = StrInit(), \ - .offset = 0, \ - .size = 0, \ - .name = StrInit(), \ - .type = StrInit(), \ - .artifact_type = StrInit(), \ - .members = VecInitWithDeepCopy (NULL, DataTypeDeinit) \ - }) -#else -# define DataTypeInit() \ - ((DataType) {.last_change = StrInit(), \ - .offset = 0, \ - .size = 0, \ - .name = StrInit(), \ - .type = StrInit(), \ - .artifact_type = StrInit(), \ - .members = VecInitWithDeepCopy (NULL, DataTypeDeinit)}) -#endif +typedef struct NameValue { + Str name; + i64 value; +} NameValue; -typedef struct FunctionType { - Str last_change; - u64 addr; - u64 size; - Str name; - Str return_type; - DataTypes args; - DataTypes stack_vars; - DataTypes deps; -} FunctionType; +typedef Vec (NameValue) NameValues; -#ifdef __cplusplus -# define FunctionTypeInit() \ - (FunctionType { \ - .last_change = StrInit(), \ - .addr = 0, \ - .size = 0, \ - .name = StrInit(), \ - .return_type = StrInit(), \ - .args = VecInitWithDeepCopy (NULL, DataTypeDeinit), \ - .stack_vars = VecInitWithDeepCopy (NULL, DataTypeDeinit), \ - .deps = VecInitWithDeepCopy (NULL, DataTypeDeinit) \ - }) -#else -# define FunctionTypeInit() \ - ((FunctionType) {.last_change = StrInit(), \ - .addr = 0, \ - .size = 0, \ - .name = StrInit(), \ - .return_type = StrInit(), \ - .args = VecInitWithDeepCopy (NULL, DataTypeDeinit), \ - .stack_vars = VecInitWithDeepCopy (NULL, DataTypeDeinit), \ - .deps = VecInitWithDeepCopy (NULL, DataTypeDeinit)}) -#endif +typedef struct Enum { + Str name; + NameValues members; +} Enum; + +typedef Vec (Enum) Enums; + +typedef struct StructMember { + Str name; + Str type; + u64 offset; + u64 size; +} StructMember, FunctionArgument; + +typedef Vec (StructMember) StructMembers; +typedef Vec (FunctionArgument) FunctionArguments; + +typedef struct Struct { + Str last_change; + u64 offset; + u64 size; + Str name; + Str type; + Str artifact_type; + StructMembers members; +} Struct; + +typedef Vec (Struct) Structs; + +/// XXX: Conflicts with definition in ControlFlowGraph.h +/// Both types are mergeable! +/// Same goes with some other types like FunctionArgument +typedef struct LocalVariable { + u64 offset; + u64 size; + Str name; + Str type; + u64 addr; +} LocalVariable; + +typedef Vec (LocalVariable) LocalVariables; + +typedef struct GlobalVariable { + u64 size; + Str name; + Str type; + u64 addr; +} GlobalVariable; + +typedef Vec (GlobalVariable) GlobalVariables; -typedef Vec (FunctionType) FunctionTypes; +typedef struct Function { + Str last_change; + u64 addr; + u64 size; + Str name; + Str return_type; + FunctionArguments args; + LocalVariables stack_vars; + struct { + Enums enums; + Structs structs; + GlobalVariables global_vars; + Typedefs typedefs; + } deps; +} Function; + +typedef Vec (Function) Functions; #ifdef __cplusplus extern "C" { #endif /// - /// Deinit DataType object clone. This won't free provided pointer. + /// Deinit NameValue object clone. This won't free provided pointer. /// That must be done by owner. /// - /// dt[in] : DataType object. + /// nv[in] : NameValue object. /// /// RETURN : Does not return on failure /// - REAI_API void DataTypeDeinit (DataType** dt); + REAI_API void NameValueDeinit (NameValue* nv); /// /// Create clone of given `src` object into `dst` object /// - /// dst[out] : Destination DataType object. - /// src[in] : Source DataType object. + /// dst[out] : Destination NameValue object. + /// src[in] : Source NameValue object. /// /// SUCCESS : true /// FAILURE : Does not return on failure /// - REAI_API bool DataTypeInitClone (DataType** dst, DataType** src); + REAI_API bool NameValueInitClone (NameValue* dst, NameValue* src); /// - /// Deinit FunctionType object clone. This won't free provided pointer. + /// Deinit Enum object clone. This won't free provided pointer. /// That must be done by owner. /// - /// ft[in] : FunctionType object. + /// e[in] : Enum object. /// /// RETURN : Does not return on failure /// - REAI_API void FunctionTypeDeinit (FunctionType* ft); + REAI_API void EnumDeinit (Enum* e); /// /// Create clone of given `src` object into `dst` object /// - /// dst[out] : Destination FunctionType object. - /// src[in] : Source FunctionType object. + /// dst[out] : Destination Enum object. + /// src[in] : Source Enum object. /// /// SUCCESS : true /// FAILURE : Does not return on failure /// - REAI_API bool FunctionTypeInitClone (FunctionType* dst, FunctionType* src); + REAI_API bool EnumInitClone (Enum* dst, Enum* src); + + /// + /// Deinit StructMember object clone. This won't free provided pointer. + /// That must be done by owner. + /// + /// nv[in] : StructMember object. + /// + /// RETURN : Does not return on failure + /// + REAI_API void StructMemberDeinit (StructMember* nv); + + /// + /// Create clone of given `src` object into `dst` object + /// + /// dst[out] : Destination StructMember object. + /// src[in] : Source StructMember object. + /// + /// SUCCESS : true + /// FAILURE : Does not return on failure + /// + REAI_API bool StructMemberInitClone (StructMember* dst, StructMember* src); + + /// + /// Deinit Struct object clone. This won't free provided pointer. + /// That must be done by owner. + /// + /// s[in] : Struct object. + /// + /// RETURN : Does not return on failure + /// + REAI_API void StructDeinit (Struct* s); + + /// + /// Create clone of given `src` object into `dst` object + /// + /// dst[out] : Destination Struct object. + /// src[in] : Source Struct object. + /// + /// SUCCESS : true + /// FAILURE : Does not return on failure + /// + REAI_API bool StructInitClone (Struct* dst, Struct* src); + + /// + /// Deinit LocalVariable object clone. This won't free provided pointer. + /// That must be done by owner. + /// + /// lv[in] : LocalVariable object. + /// + /// RETURN : Does not return on failure + /// + REAI_API void LocalVariableDeinit (LocalVariable* lv); + + /// + /// Create clone of given `src` object into `dst` object + /// + /// dst[out] : Destination LocalVariable object. + /// src[in] : Source LocalVariable object. + /// + /// SUCCESS : true + /// FAILURE : Does not return on failure + /// + REAI_API bool LocalVariableInitClone (LocalVariable* dst, LocalVariable* src); + + /// + /// Deinit GlobalVariable object clone. This won't free provided pointer. + /// That must be done by owner. + /// + /// lv[in] : GlobalVariable object. + /// + /// RETURN : Does not return on failure + /// + REAI_API void GlobalVariableDeinit (GlobalVariable* lv); + + /// + /// Create clone of given `src` object into `dst` object + /// + /// dst[out] : Destination GlobalVariable object. + /// src[in] : Source GlobalVariable object. + /// + /// SUCCESS : true + /// FAILURE : Does not return on failure + /// + REAI_API bool GlobalVariableInitClone (GlobalVariable* dst, GlobalVariable* src); + + /// + /// Deinit Function object clone. This won't free provided pointer. + /// That must be done by owner. + /// + /// ft[in] : Function object. + /// + /// RETURN : Does not return on failure + /// + REAI_API void FunctionDeinit (Function* ft); + + /// + /// Create clone of given `src` object into `dst` object + /// + /// dst[out] : Destination Function object. + /// src[in] : Source Function object. + /// + /// SUCCESS : true + /// FAILURE : Does not return on failure + /// + REAI_API bool FunctionInitClone (Function* dst, Function* src); + + /// + /// Deinit FunctionArgument object clone. This won't free provided pointer. + /// That must be done by owner. + /// + /// fa[in] : FunctionArgument object. + /// + /// RETURN : Does not return on failure + /// + static inline void FunctionArgumentDeinit (FunctionArgument* fa) { + StructMemberDeinit (fa); + } + + /// + /// Create clone of given `src` object into `dst` object + /// + /// dst[out] : Destination FunctionArgument object. + /// src[in] : Source FunctionArgument object. + /// + /// SUCCESS : true + /// FAILURE : Does not return on failure + /// + static inline bool FunctionArgumentInitClone (FunctionArgument* dst, FunctionArgument* src) { + return StructMemberInitClone (dst, src); + } #ifdef __cplusplus } #endif +#ifdef __cplusplus + +# define FunctionInit() \ + (Function { \ + .last_change = StrInit(), \ + .addr = 0, \ + .size = 0, \ + .name = StrInit(), \ + .return_type = StrInit(), \ + .args = VecInitWithDeepCopy (NULL, FunctionArgumentDeinit), \ + .stack_vars = VecInitWithDeepCopy (NULL, LocalVariableDeinit), \ + .deps = { \ + .enums = VecInitWithDeepCopy (NULL, EnumDeinit), \ + .structs = VecInitWithDeepCopy (NULL, StructDeinit), \ + .global_vars = VecInitWithDeepCopy (NULL, GlobalVariableDeinit), \ + .typedefs = VecInitWithDeepCopy (NULL, TypedefDeinit) \ + } \ + }) + +# define LocalVariableInit() \ + (LocalVariable {.offset = 0, .size = 0, .name = StrInit(), .type = StrInit(), .addr = 0}) + +# define GlobalVariableInit() \ + (GlobalVariable {.size = 0, .name = StrInit(), .type = StrInit(), .addr = 0}) + +# define StructInit() \ + (Struct { \ + .last_change = StrInit(), \ + .offset = 0, \ + .size = 0, \ + .name = StrInit(), \ + .type = StrInit(), \ + .artifact_type = StrInit(), \ + .members = VecInitWithDeepCopy (NULL, StructDeinit) \ + }) + +# define StructMemberInit() \ + (StructMember {.name = StrInit(), .type = StrInit(), .offset = 0, .size = 0}) +#else + +/// +/// Initialize a Function object with default values. +/// +/// RETURN : A fully initialized Function object: +/// - last_change, name, return_type: empty strings +/// - addr, size: zero +/// - args, stack_vars: empty vectors with deep copy support +/// - deps.enums, deps.structs, deps.global_vars, deps.typedefs: empty vectors +/// +# define FunctionInit() \ + ((Function) { \ + .last_change = StrInit(), \ + .addr = 0, \ + .size = 0, \ + .name = StrInit(), \ + .return_type = StrInit(), \ + .args = VecInitWithDeepCopy (NULL, FunctionArgumentDeinit), \ + .stack_vars = VecInitWithDeepCopy (NULL, LocalVariableDeinit), \ + .deps = { \ + .enums = VecInitWithDeepCopy (NULL, EnumDeinit), \ + .structs = VecInitWithDeepCopy (NULL, StructDeinit), \ + .global_vars = VecInitWithDeepCopy (NULL, GlobalVariableDeinit), \ + .typedefs = VecInitWithDeepCopy (NULL, TypedefDeinit) \ + } \ + }) + +/// +/// Initialize a LocalVariable object with default values. +/// +/// RETURN : A fully initialized LocalVariable object: +/// - name, type: empty strings +/// - offset, size, addr: zero +/// +# define LocalVariableInit() \ + ((LocalVariable) {.offset = 0, .size = 0, .name = StrInit(), .type = StrInit(), .addr = 0}) + +/// +/// Initialize a GlobalVariable object with default values. +/// +/// RETURN : A fully initialized GlobalVariable object: +/// - name, type: empty strings +/// - size, addr: zero +/// +# define GlobalVariableInit() \ + ((GlobalVariable) {.size = 0, .name = StrInit(), .type = StrInit(), .addr = 0}) + +/// +/// Initialize a Struct object with default values. +/// +/// RETURN : A fully initialized Struct object: +/// - last_change, name, type, artifact_type: empty strings +/// - offset, size: zero +/// - members: empty vector with deep copy support +/// +# define StructInit() \ + ((Struct) {.last_change = StrInit(), \ + .offset = 0, \ + .size = 0, \ + .name = StrInit(), \ + .type = StrInit(), \ + .artifact_type = StrInit(), \ + .members = VecInitWithDeepCopy (NULL, StructDeinit)}) + +/// +/// Initialize a StructMember object with default values. +/// +/// RETURN : A fully initialized StructMember object: +/// - name, type: empty strings +/// - offset, size: zero +/// +# define StructMemberInit() \ + ((StructMember) {.name = StrInit(), .type = StrInit(), .offset = 0, .size = 0}) +#endif // __cplusplus + #endif // REAI_DATA_TYPE_H diff --git a/Source/Reai/Api.c b/Source/Reai/Api.c index 2698c8d..e120f92 100644 --- a/Source/Reai/Api.c +++ b/Source/Reai/Api.c @@ -1433,15 +1433,15 @@ bool IsFunctionTypeGenerationCompletedForAllFunctions (Connection* conn, Analysi return false; } -FunctionType GetFunctionType (Connection* conn, AnalysisId analysis_id, FunctionId function_id) { +Function GetFunctionType (Connection* conn, AnalysisId analysis_id, FunctionId function_id) { if (!conn->api_key.length || !conn->host.length) { LOG_ERROR ("Missing API key or host to connect to."); - return (FunctionType) {0}; + return (Function) {0}; } if (!function_id) { LOG_ERROR ("Invalid function id."); - return (FunctionType) {0}; + return (Function) {0}; } Str url = StrInit(); @@ -1462,7 +1462,7 @@ FunctionType GetFunctionType (Connection* conn, AnalysisId analysis_id, Function bool status = false; bool completed = false; - FunctionType ft = FunctionTypeInit(); + Function ft = FunctionTypeInit(); JR_OBJ (j, { JR_BOOL_KV (j, "status", status); @@ -1515,7 +1515,7 @@ FunctionType GetFunctionType (Connection* conn, AnalysisId analysis_id, Function } else { StrDeinit (&url); StrDeinit (&gj); - return (FunctionType) {0}; + return (Function) {0}; } } @@ -1545,7 +1545,7 @@ bool SetFunctionType ( Connection* conn, AnalysisId analysis_id, FunctionId function_id, - FunctionType function_type + Function function_type ) { if (!conn->api_key.length || !conn->host.length) { LOG_ERROR ("Missing API key or host to connect to."); diff --git a/Source/Reai/Api/Types/DataType.c b/Source/Reai/Api/Types/DataType.c index 0c3fd95..7257956 100644 --- a/Source/Reai/Api/Types/DataType.c +++ b/Source/Reai/Api/Types/DataType.c @@ -1,6 +1,6 @@ /** * @file DataType.c - * @date 1st April 2025 + * @date 9th July 2025 * @author Siddharth Mishra (admin@brightprogrammer.in) * @copyright Copyright (c) RevEngAI. All Rights Reserved. * */ @@ -8,66 +8,169 @@ #include #include -/* libc */ -#include +void NameValueDeinit (NameValue* nv) { + if (!nv) { + LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); + } + + StrDeinit (&nv->name); + memset (nv, 0, sizeof (*nv)); +} + +bool NameValueInitClone (NameValue* dst, NameValue* src) { + if (!dst || !src) { + LOG_FATAL ("Invalid objects provided for cloning. Cannot clone. Aborting..."); + } + + StrInitCopy (&dst->name, &src->name); + dst->value = src->value; -#include "Reai/Util/Vec.h" + return true; +} -void DataTypeDeinit (DataType** dt) { - if (!dt || !*dt) { +void EnumDeinit (Enum* e) { + if (!e) { LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); } - DataType* d = *dt; + StrDeinit (&e->name); + VecDeinit (&e->members); - StrDeinit (&d->last_change); - StrDeinit (&d->name); - StrDeinit (&d->type); - StrDeinit (&d->artifact_type); - VecDeinit (&d->members); + memset (e, 0, sizeof (*e)); +} + +bool EnumInitClone (Enum* dst, Enum* src) { + if (!dst || !src) { + LOG_FATAL ("Invalid objects provided for cloning. Cannot clone. Aborting..."); + } - memset (d, 0, sizeof (*d)); - *dt = NULL; + StrInitCopy (&dst->name, &src->name); + VecInitClone (&dst->members, &src->members); + + return true; } -bool DataTypeInitClone (DataType** dst, DataType** src) { +void StructMemberDeinit (StructMember* sm) { + if (!sm) { + LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); + } + + StrDeinit (&sm->name); + StrDeinit (&sm->type); + + memset (sm, 0, sizeof (*sm)); +} + +bool StructMemberInitClone (StructMember* dst, StructMember* src) { if (!dst || !src) { LOG_FATAL ("Invalid objects provided for cloning. Cannot clone. Aborting..."); } - DataType* d = *dst; - DataType* s = *src; + StrInitCopy (&dst->name, &src->name); + StrInitCopy (&dst->type, &src->type); + dst->offset = src->offset; + dst->size = src->size; + + return true; +} + +void StructDeinit (Struct* s) { + if (!s) { + LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); + } + + StrDeinit (&s->last_change); + StrDeinit (&s->name); + StrDeinit (&s->type); + StrDeinit (&s->artifact_type); + VecDeinit (&s->members); - StrInitCopy (&d->last_change, &s->last_change); - d->offset = s->offset; - d->size = s->size; - StrInitCopy (&d->name, &s->name); - StrInitCopy (&d->type, &s->type); - StrInitCopy (&d->artifact_type, &s->artifact_type); + memset (s, 0, sizeof (*s)); +} - d->members = VecInitWithDeepCopy_T (&d->members, DataTypeInitClone, DataTypeDeinit); - VecInitClone (&d->members, &s->members); - d->members.copy_init = NULL; +bool StructInitClone (Struct* dst, Struct* src) { + if (!dst || !src) { + LOG_FATAL ("Invalid objects provided for cloning. Cannot clone. Aborting..."); + } + + StrInitCopy (&dst->last_change, &src->last_change); + dst->offset = src->offset; + dst->size = src->size; + StrInitCopy (&dst->name, &src->name); + StrInitCopy (&dst->type, &src->type); + StrInitCopy (&dst->artifact_type, &src->artifact_type); + VecInitClone (&dst->members, &src->members); return true; } -void FunctionTypeDeinit (FunctionType* ft) { - if (!ft) { +void LocalVariableDeinit (LocalVariable* lv) { + if (!lv) { LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); } - StrDeinit (&ft->last_change); - StrDeinit (&ft->name); - StrDeinit (&ft->return_type); - VecDeinit (&ft->args); - VecDeinit (&ft->stack_vars); - VecDeinit (&ft->deps); + StrDeinit (&lv->name); + StrDeinit (&lv->type); - memset (ft, 0, sizeof (*ft)); + memset (lv, 0, sizeof (*lv)); } -bool FunctionTypeInitClone (FunctionType* dst, FunctionType* src) { +bool LocalVariableInitClone (LocalVariable* dst, LocalVariable* src) { + if (!dst || !src) { + LOG_FATAL ("Invalid objects provided for cloning. Cannot clone. Aborting..."); + } + + dst->offset = src->offset; + dst->size = src->size; + StrInitCopy (&dst->name, &src->name); + StrInitCopy (&dst->type, &src->type); + dst->addr = src->addr; + + return true; +} + +void GlobalVariableDeinit (GlobalVariable* gv) { + if (!gv) { + LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); + } + + StrDeinit (&gv->name); + StrDeinit (&gv->type); + + memset (gv, 0, sizeof (*gv)); +} + +bool GlobalVariableInitClone (GlobalVariable* dst, GlobalVariable* src) { + if (!dst || !src) { + LOG_FATAL ("Invalid objects provided for cloning. Cannot clone. Aborting..."); + } + + dst->size = src->size; + StrInitCopy (&dst->name, &src->name); + StrInitCopy (&dst->type, &src->type); + dst->addr = src->addr; + + return true; +} + +void FunctionDeinit (Function* f) { + if (!f) { + LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); + } + + StrDeinit (&f->last_change); + StrDeinit (&f->name); + StrDeinit (&f->return_type); + VecDeinit (&f->args); + VecDeinit (&f->stack_vars); + VecDeinit (&f->deps.enums); + VecDeinit (&f->deps.structs); + VecDeinit (&f->deps.global_vars); + + memset (f, 0, sizeof (*f)); +} + +bool FunctionInitClone (Function* dst, Function* src) { if (!dst || !src) { LOG_FATAL ("Invalid objects provided for cloning. Cannot clone. Aborting..."); } @@ -79,7 +182,31 @@ bool FunctionTypeInitClone (FunctionType* dst, FunctionType* src) { StrInitCopy (&dst->return_type, &src->return_type); VecInitClone (&dst->args, &src->args); VecInitClone (&dst->stack_vars, &src->stack_vars); - VecInitClone (&dst->deps, &src->deps); + VecInitClone (&dst->deps.enums, &src->deps.enums); + VecInitClone (&dst->deps.structs, &src->deps.structs); + VecInitClone (&dst->deps.global_vars, &src->deps.global_vars); + + return true; +} + +void TypedefDeinit (Typedef* td) { + if (!td) { + LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); + } + + StrDeinit (&td->name); + StrDeinit (&td->type); + + memset (td, 0, sizeof (*td)); +} + +bool TypedefInitClone (Typedef* dst, Typedef* src) { + if (!dst || !src) { + LOG_FATAL ("Invalid objects provided for cloning. Cannot clone. Aborting..."); + } + + StrInitCopy (&dst->name, &src->name); + StrInitCopy (&dst->type, &src->type); return true; } From 30c5fcf40c05690cbec53d928a1fc6fde7e78cd0 Mon Sep 17 00:00:00 2001 From: Siddharth Mishra Date: Fri, 11 Jul 2025 23:35:20 +0530 Subject: [PATCH 5/5] Parse API Response With New Types --- Include/Reai/Api.h | 8 +- Include/Reai/Api/Types/ControlFlowGraph.h | 16 +-- Include/Reai/Api/Types/DataType.h | 3 - Source/Reai/Api.c | 146 +++++++++++++++++++--- Source/Reai/Api/Types/ControlFlowGraph.c | 8 +- 5 files changed, 144 insertions(+), 37 deletions(-) diff --git a/Include/Reai/Api.h b/Include/Reai/Api.h index 837b3f6..f166dc9 100644 --- a/Include/Reai/Api.h +++ b/Include/Reai/Api.h @@ -449,10 +449,10 @@ extern "C" { /// FAILURE: false /// REAI_API bool SetFunctionType ( - Connection* conn, - AnalysisId analysis_id, - FunctionId function_id, - Function function_type + Connection* conn, + AnalysisId analysis_id, + FunctionId function_id, + Function function_type ); /// Retrieves log data for a specific analysis job. diff --git a/Include/Reai/Api/Types/ControlFlowGraph.h b/Include/Reai/Api/Types/ControlFlowGraph.h index 9338140..690fc48 100644 --- a/Include/Reai/Api/Types/ControlFlowGraph.h +++ b/Include/Reai/Api/Types/ControlFlowGraph.h @@ -35,20 +35,20 @@ typedef Vec (Block) Blocks; // XXX: conflicts with definition in DataType.h // Both are mergeable! Defining a separate one creates confusion // and type-redundancy -typedef struct LocalVariable { +typedef struct CfgLocalVariable { Str address; Str d_type; u64 size; Str loc; Str name; -} LocalVariable; +} CfgLocalVariable; -typedef Vec (LocalVariable) LocalVariables; +typedef Vec (CfgLocalVariable) CfgLocalVariables; typedef struct ControlFlowGraph { - Blocks blocks; - LocalVariables local_variables; - Str overview_comment; + Blocks blocks; + CfgLocalVariables local_variables; + Str overview_comment; } ControlFlowGraph; #ifdef __cplusplus @@ -99,7 +99,7 @@ extern "C" { /// /// var[in,out] : Object to be destroyed. /// - REAI_API void LocalVariableDeinit (LocalVariable* var); + REAI_API void CfgLocalVariableDeinit (CfgLocalVariable* var); /// /// Clone a LocalVariable object from `src` to `dst` @@ -110,7 +110,7 @@ extern "C" { /// SUCCESS : True /// FAILURE : Does not return /// - REAI_API bool LocalVariableInitClone (LocalVariable* dst, LocalVariable* src); + REAI_API bool CfgLocalVariableInitClone (CfgLocalVariable* dst, CfgLocalVariable* src); /// /// Deinit cloned ControlFlowGraph object. Provided pointer is not freed. diff --git a/Include/Reai/Api/Types/DataType.h b/Include/Reai/Api/Types/DataType.h index 9ca4ce0..f8f4b6e 100644 --- a/Include/Reai/Api/Types/DataType.h +++ b/Include/Reai/Api/Types/DataType.h @@ -45,12 +45,10 @@ typedef Vec (StructMember) StructMembers; typedef Vec (FunctionArgument) FunctionArguments; typedef struct Struct { - Str last_change; u64 offset; u64 size; Str name; Str type; - Str artifact_type; StructMembers members; } Struct; @@ -79,7 +77,6 @@ typedef struct GlobalVariable { typedef Vec (GlobalVariable) GlobalVariables; typedef struct Function { - Str last_change; u64 addr; u64 size; Str name; diff --git a/Source/Reai/Api.c b/Source/Reai/Api.c index e120f92..f50d93b 100644 --- a/Source/Reai/Api.c +++ b/Source/Reai/Api.c @@ -9,6 +9,8 @@ #include #include +#include "Reai/Util/Vec.h" + bool Authenticate (Connection* conn) { if (!conn->api_key.length || !conn->host.length) { LOG_ERROR ("Missing API key or host to connect to."); @@ -1026,7 +1028,7 @@ ControlFlowGraph GetFunctionControlFlowGraph (Connection* conn, FunctionId funct ControlFlowGraph cfg = {0}; cfg.blocks = VecInitWithDeepCopy_T (&cfg.blocks, NULL, BlockDeinit); cfg.local_variables = - VecInitWithDeepCopy_T (&cfg.local_variables, NULL, LocalVariableDeinit); + VecInitWithDeepCopy_T (&cfg.local_variables, NULL, CfgLocalVariableDeinit); cfg.overview_comment = StrInit(); JR_OBJ (j, { @@ -1071,11 +1073,11 @@ ControlFlowGraph GetFunctionControlFlowGraph (Connection* conn, FunctionId funct }); JR_ARR_KV (j, "local_variables", { - LocalVariable var = {0}; - var.address = StrInit(); - var.d_type = StrInit(); - var.loc = StrInit(); - var.name = StrInit(); + CfgLocalVariable var = {0}; + var.address = StrInit(); + var.d_type = StrInit(); + var.loc = StrInit(); + var.name = StrInit(); JR_OBJ (j, { JR_STR_KV (j, "address", var.address); @@ -1460,8 +1462,8 @@ Function GetFunctionType (Connection* conn, AnalysisId analysis_id, FunctionId f StrIter j = StrIterInitFromStr (&gj); - bool status = false; - bool completed = false; + bool status = false; + bool completed = false; Function ft = FunctionTypeInit(); JR_OBJ (j, { @@ -1483,18 +1485,126 @@ Function GetFunctionType (Connection* conn, AnalysisId analysis_id, FunctionId f JR_INT_KV (j, "addr", ft.addr); JR_STR_KV (j, "type", ft.return_type); JR_OBJ_KV (j, "args", { - DataType* dt = JrDataType (&j); - VecPushBack (&ft.args, dt); + FunctionArgument fa = FunctionArgumentInit(); + JR_OBJ (j, { + JI_STR_KV (j, "last_change"); + JR_STR_KV (j, "name", fa.name); + JR_STR_KV (j, "type", fa.type); + JR_INT_KV (j, "offset", fa.offset); + JR_INT_KV (j, "size", fa.size); + }); + VecPushBack (&ft.args, fa); }); }); JR_OBJ_KV (j, "stack_vars", { - DataType* dt = JrDataType (&j); - VecPushBack (&ft.stack_vars, dt); + LocalVariable sv = LocalVariableInit(); + JR_OBJ (j, { + JI_STR_KV (j, "last_change"); + JR_STR_KV (j, "name", sv.name); + JR_STR_KV (j, "type", sv.type); + JR_INT_KV (j, "offset", sv.offset); + JR_INT_KV (j, "size", sv.size); + }); + VecPushBack (&ft.stack_vars, sv); }); }); JR_ARR_KV (j, "func_deps", { - DataType* dt = JrDataType (&j); - VecPushBack (&ft.deps, dt); + static const u32 tGlobalVariable = 1; + static const u32 tStruct = 2; + static const u32 tEnum = 3; + static const u32 tTypedef = 4; + u32 t = 0; + + // common across all types + union { + u32 addr; + u32 offset; + } p = {0}; + u64 size = 0; + Str type = StrInit(); + Str name = StrInit(); + StructMembers sm = VecInitWithDeepCopy (NULL, StructMemberDeinit); + + // only for enum + i64 value = -1; + + Str atype = StrInit(); + JR_OBJ (j, { + JI_STR_KV (j, "last_change"); + JR_STR_KV (j, "name", name); + JR_INT_KV (j, "size", size); + JR_INT_KV (j, "addr", p.addr); + JR_INT_KV (j, "offset", p.offset); + JR_STR_KV (j, "type", type); + + JR_OBJ_KV (j, "members", { + // TODO: How to detect enum or struct herer? + // Can detect based on what fields are present but don't have an enum example atm + StructMember m = StructMemberInit(); + JR_OBJ (j, { + JI_STR_KV (j, "last_change"); + JR_STR_KV (j, "name", m.name); + JR_STR_KV (j, "type", m.type); + JR_INT_KV (j, "offset", m.offset); + JR_INT_KV (j, "size", m.size); + }); + VecPushBack (&sm, &m); + }); + + JR_STR_KV (j, "artifact_type", atype); + if (!t && atype.length) { + Str* at = &atype; + if (!StrCmpZstr (at, "Struct")) { + t = tStruct; + } else if (!StrCmpZstr (at, "GlobalVariable")) { + t = tGlobalVariable; + } else if (!StrCmpZstr (at, "Enum")) { + t = tEnum; + } else if (!StrCmpZstr (at, "Typedef")) { + t = tTypedef; + } + } + }); + + switch (t) { + case tGlobalVariable : { + GlobalVariable gv = GlobalVariableInit(); + gv.addr = p.addr; + gv.size = size; + gv.name = name; + gv.type = type; + VecPushBack (&ft.deps.global_vars, gv); + break; + } + case tStruct : { + Struct s = StructInit(); + s.offset = p.offset; + s.type = type; + s.name = name; + s.size = size; + s.members = sm; + break; + } + case tEnum : { + // TODO: + break; + } + case tTypedef : { + // TODO: + break; + } + default : { + StrDeinit (&name); + StrDeinit (&type); + LOG_ERROR ( + "Unsupported type %s provided in function types " + "response : %s", + atype.data + ); + } + } + + StrDeinit (&atype); }); }); } else { @@ -1542,10 +1652,10 @@ Str* JwDataType (Str* sjson, DataType* dt) { } bool SetFunctionType ( - Connection* conn, - AnalysisId analysis_id, - FunctionId function_id, - Function function_type + Connection* conn, + AnalysisId analysis_id, + FunctionId function_id, + Function function_type ) { if (!conn->api_key.length || !conn->host.length) { LOG_ERROR ("Missing API key or host to connect to."); diff --git a/Source/Reai/Api/Types/ControlFlowGraph.c b/Source/Reai/Api/Types/ControlFlowGraph.c index 889d47b..7fff5e2 100644 --- a/Source/Reai/Api/Types/ControlFlowGraph.c +++ b/Source/Reai/Api/Types/ControlFlowGraph.c @@ -61,7 +61,7 @@ bool BlockInitClone (Block* dst, Block* src) { return true; } -void LocalVariableDeinit (LocalVariable* var) { +void CfgLocalVariableDeinit (CfgLocalVariable* var) { if (!var) { LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); } @@ -71,10 +71,10 @@ void LocalVariableDeinit (LocalVariable* var) { StrDeinit (&var->loc); StrDeinit (&var->name); - memset (var, 0, sizeof (LocalVariable)); + memset (var, 0, sizeof (CfgLocalVariable)); } -bool LocalVariableInitClone (LocalVariable* dst, LocalVariable* src) { +bool CfgLocalVariableInitClone (CfgLocalVariable* dst, CfgLocalVariable* src) { if (!dst || !src) { LOG_FATAL ("Invalid objects provided. Cannot init clone. Aborting..."); } @@ -110,4 +110,4 @@ bool ControlFlowGraphInitClone (ControlFlowGraph* dst, ControlFlowGraph* src) { StrInitCopy (&dst->overview_comment, &src->overview_comment); return true; -} \ No newline at end of file +}