diff --git a/Include/Reai/Api.h b/Include/Reai/Api.h index 2d4d272..f166dc9 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,99 @@ 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 Function + GetFunctionType (Connection* conn, AnalysisId analysis_id, 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, + Function function_type + ); + /// Retrieves log data for a specific analysis job. /// /// This function fetches diagnostic logs generated during @@ -381,8 +463,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 +478,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 +494,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 +509,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 +524,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 +535,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 +551,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 +576,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/ControlFlowGraph.h b/Include/Reai/Api/Types/ControlFlowGraph.h index eeb13a8..690fc48 100644 --- a/Include/Reai/Api/Types/ControlFlowGraph.h +++ b/Include/Reai/Api/Types/ControlFlowGraph.h @@ -32,20 +32,23 @@ typedef struct Block { typedef Vec (Block) Blocks; -typedef struct LocalVariable { +// XXX: conflicts with definition in DataType.h +// Both are mergeable! Defining a separate one creates confusion +// and type-redundancy +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 @@ -96,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` @@ -107,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. @@ -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 new file mode 100644 index 0000000..f8f4b6e --- /dev/null +++ b/Include/Reai/Api/Types/DataType.h @@ -0,0 +1,390 @@ +/** + * @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 + +#include +#include +#include + +typedef struct Typedef { + Str name; + Str type; +} Typedef; + +typedef Vec (Typedef) Typedefs; + +typedef struct NameValue { + Str name; + i64 value; +} NameValue; + +typedef Vec (NameValue) NameValues; + +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 { + u64 offset; + u64 size; + Str name; + Str 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 struct Function { + 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 NameValue object clone. This won't free provided pointer. + /// That must be done by owner. + /// + /// nv[in] : NameValue object. + /// + /// RETURN : Does not return on failure + /// + REAI_API void NameValueDeinit (NameValue* nv); + + /// + /// Create clone of given `src` object into `dst` object + /// + /// dst[out] : Destination NameValue object. + /// src[in] : Source NameValue object. + /// + /// SUCCESS : true + /// FAILURE : Does not return on failure + /// + REAI_API bool NameValueInitClone (NameValue* dst, NameValue* src); + + /// + /// Deinit Enum object clone. This won't free provided pointer. + /// That must be done by owner. + /// + /// e[in] : Enum object. + /// + /// RETURN : Does not return on failure + /// + REAI_API void EnumDeinit (Enum* e); + + /// + /// Create clone of given `src` object into `dst` object + /// + /// dst[out] : Destination Enum object. + /// src[in] : Source Enum object. + /// + /// SUCCESS : true + /// FAILURE : Does not return on failure + /// + 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/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/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/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..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."); @@ -124,40 +126,51 @@ 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); 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_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, "status", status); + if (status) { + 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 +179,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 +285,8 @@ AnalysisInfos GetRecentAnalysis (Connection* conn, RecentAnalysisRequest* reques return infos; } else { + StrDeinit (&url); + StrDeinit (&gj); return (AnalysisInfos) {0}; } } @@ -340,6 +355,8 @@ BinaryInfos SearchBinary (Connection* conn, SearchBinaryRequest* request) { return infos; } else { + StrDeinit (&url); + StrDeinit (&gj); return (BinaryInfos) {0}; } } @@ -447,6 +464,8 @@ CollectionInfos SearchCollection (Connection* conn, SearchCollectionRequest* req return infos; } else { + StrDeinit (&url); + StrDeinit (&gj); return (CollectionInfos) {0}; } } @@ -486,6 +505,9 @@ bool BatchRenameFunctions (Connection* conn, FunctionInfos functions) { return status; } else { + StrDeinit (&url); + StrDeinit (&sj); + StrDeinit (&gj); return false; } } @@ -527,6 +549,9 @@ bool RenameFunction (Connection* conn, FunctionId fn_id, Str new_name) { return status; } else { + StrDeinit (&url); + StrDeinit (&sj); + StrDeinit (&gj); return false; } } @@ -624,6 +649,9 @@ AnnSymbols GetBatchAnnSymbols (Connection* conn, BatchAnnSymbolRequest* request) return syms; } else { + StrDeinit (&url); + StrDeinit (&sj); + StrDeinit (&gj); return (AnnSymbols) {0}; } } @@ -660,11 +688,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 +731,8 @@ ModelInfos GetAiModelInfos (Connection* conn) { return models; } else { + StrDeinit (&url); + StrDeinit (&gj); return (ModelInfos) {0}; } } @@ -735,6 +766,8 @@ bool BeginAiDecompilation (Connection* conn, FunctionId function_id) { return status; } else { + StrDeinit (&url); + StrDeinit (&gj); return false; } } @@ -775,6 +808,8 @@ Status GetAiDecompilationStatus (Connection* conn, FunctionId function_id) { StrDeinit (&status_str); return decomp_status; } else { + StrDeinit (&url); + StrDeinit (&gj); return STATUS_INVALID; } } @@ -962,6 +997,8 @@ AiDecompilation GetAiDecompilation (Connection* conn, FunctionId function_id, bo StrDeinit (&gj); return decomp; } else { + StrDeinit (&url); + StrDeinit (&gj); return (AiDecompilation) {0}; } } @@ -991,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, { @@ -1036,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); @@ -1060,6 +1097,8 @@ ControlFlowGraph GetFunctionControlFlowGraph (Connection* conn, FunctionId funct StrDeinit (&gj); return cfg; } else { + StrDeinit (&url); + StrDeinit (&gj); return (ControlFlowGraph) {0}; } } @@ -1154,10 +1193,533 @@ 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", { + *json = j; + DataType* dtm = JrDataType (json); + j = *json; + 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/data_types", 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); + LOG_INFO ( + "Function type generation complete for function with ID = %llu", + function_id + ); + return true; + } + }); + }); + }); + } + }); + + LOG_INFO ("Function type generation incomplete for function with ID = %llu", function_id); + + 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; + } + + 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); + + 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", { + 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; + } + + StrDeinit (&url); + StrDeinit (&gj); + StrDeinit (&sj); + return false; +} + +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 (Function) {0}; + } + + if (!function_id) { + LOG_ERROR ("Invalid function id."); + return (Function) {0}; + } + + Str url = StrInit(); + Str gj = StrInit(); + + 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; + bool completed = false; + Function ft = FunctionTypeInit(); + + JR_OBJ (j, { + JR_BOOL_KV (j, "status", status); + if (status) { + JR_OBJ_KV (j, "data", { + 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, "type", ft.return_type); + JR_OBJ_KV (j, "args", { + 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", { + 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", { + 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 { + 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); + return ft; + } else { + StrDeinit (&url); + StrDeinit (&gj); + return (Function) {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, + Function 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 +1749,8 @@ AnalysisId AnalysisIdFromBinaryId (Connection* conn, BinaryId binary_id) { return id; } else { + StrDeinit (&url); + StrDeinit (&gj); return 0; } } @@ -1225,6 +1789,8 @@ Str GetAnalysisLogs (Connection* conn, AnalysisId analysis_id) { return logs; } else { + StrDeinit (&url); + StrDeinit (&gj); return (Str) {0}; } } @@ -1269,6 +1835,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/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 +} diff --git a/Source/Reai/Api/Types/DataType.c b/Source/Reai/Api/Types/DataType.c new file mode 100644 index 0000000..7257956 --- /dev/null +++ b/Source/Reai/Api/Types/DataType.c @@ -0,0 +1,212 @@ +/** + * @file DataType.c + * @date 9th July 2025 + * @author Siddharth Mishra (admin@brightprogrammer.in) + * @copyright Copyright (c) RevEngAI. All Rights Reserved. + * */ + +#include +#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; + + return true; +} + +void EnumDeinit (Enum* e) { + if (!e) { + LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); + } + + StrDeinit (&e->name); + VecDeinit (&e->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..."); + } + + StrInitCopy (&dst->name, &src->name); + VecInitClone (&dst->members, &src->members); + + return true; +} + +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..."); + } + + 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); + + memset (s, 0, sizeof (*s)); +} + +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 LocalVariableDeinit (LocalVariable* lv) { + if (!lv) { + LOG_FATAL ("Invalid object provided. Cannot deinit. Aborting..."); + } + + StrDeinit (&lv->name); + StrDeinit (&lv->type); + + memset (lv, 0, sizeof (*lv)); +} + +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..."); + } + + 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.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; +} 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; } 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.");