diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 23ce811..d6cf240 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -13,6 +13,7 @@ add_library(idasql STATIC src/disassembly.cpp src/search_bytes.cpp src/idapython_exec.cpp + src/ida90_compat.cpp src/metadata.cpp src/metadata_welcome.cpp src/ui_context_provider.cpp diff --git a/src/lib/src/decompiler.cpp b/src/lib/src/decompiler.cpp index 3e62892..283e930 100644 --- a/src/lib/src/decompiler.cpp +++ b/src/lib/src/decompiler.cpp @@ -584,6 +584,17 @@ void collect_all_lvars(std::vector& vars) { // Ctree Collector // ============================================================================ +static citem_t* current_parent_item(ctree_parentee_t* visitor) { + if (visitor == nullptr) { + return nullptr; + } +#if IDA_SDK_VERSION >= 920 + return visitor->parent_item(); +#else + return visitor->parents.empty() ? nullptr : visitor->parents.back(); +#endif +} + ctree_collector_t::ctree_collector_t(std::vector& items_, cfunc_t* cfunc_, ea_t func_addr_) : ctree_parentee_t(false), items(items_), cfunc(cfunc_), func_addr(func_addr_), next_id(0) {} @@ -604,7 +615,7 @@ int idaapi ctree_collector_t::visit_insn(cinsn_t* insn) { ci.goto_label_num = insn->cgoto->label_num; } - citem_t* p = parent_item(); + citem_t* p = current_parent_item(this); if (p) { auto it = item_ids.find(p); if (it != item_ids.end()) ci.parent_id = it->second; @@ -628,7 +639,7 @@ int idaapi ctree_collector_t::visit_expr(cexpr_t* expr) { ci.label_num = expr->label_num; ci.depth = static_cast(parents.size()); - citem_t* p = parent_item(); + citem_t* p = current_parent_item(this); if (p) { auto it = item_ids.find(p); if (it != item_ids.end()) ci.parent_id = it->second; diff --git a/src/lib/src/entities.cpp b/src/lib/src/entities.cpp index b696ace..6afee08 100644 --- a/src/lib/src/entities.cpp +++ b/src/lib/src/entities.cpp @@ -2387,13 +2387,33 @@ bool operand_numeric_value(ea_t ea, int opnum, uint64 &out_value, } } +ssize_t find_enum_member_by_name(const tinfo_t &enum_tif, edm_t *out, + const char *name) { +#if IDA_SDK_VERSION >= 920 + return enum_tif.get_edm(out, name); +#else + return enum_tif.find_edm(out, name); +#endif +} + +ssize_t find_enum_member_by_value(const tinfo_t &enum_tif, edm_t *out, + uint64 value, bmask64_t bmask, + uchar serial) { +#if IDA_SDK_VERSION >= 920 + return enum_tif.get_edm_by_value(out, value, bmask, serial); +#else + return enum_tif.find_edm(out, value, bmask, serial); +#endif +} + bool resolve_enum_member_serial(const tinfo_t &enum_tif, const std::string &member_name, uchar &out_serial, std::string *out_error) { if (out_error) out_error->clear(); edm_t target; - const ssize_t idx = enum_tif.get_edm(&target, member_name.c_str()); + const ssize_t idx = + find_enum_member_by_name(enum_tif, &target, member_name.c_str()); if (idx < 0) { if (out_error) *out_error = "enum member not found"; @@ -2402,8 +2422,8 @@ bool resolve_enum_member_serial(const tinfo_t &enum_tif, for (int s = 0; s <= 255; ++s) { edm_t candidate; - const ssize_t by_val = enum_tif.get_edm_by_value( - &candidate, target.value, DEFMASK64, static_cast(s)); + const ssize_t by_val = find_enum_member_by_value( + enum_tif, &candidate, target.value, DEFMASK64, static_cast(s)); if (by_val < 0) break; if (candidate.name == target.name) { @@ -2483,7 +2503,8 @@ bool apply_operand_representation(ea_t ea, int opnum, } edm_t member; - if (enum_tif.get_edm(&member, req.enum_member_name.c_str()) < 0) { + if (find_enum_member_by_name(enum_tif, &member, + req.enum_member_name.c_str()) < 0) { if (out_error) *out_error = "enum member not found"; auto_wait(); diff --git a/src/lib/src/ida90_compat.cpp b/src/lib/src/ida90_compat.cpp new file mode 100644 index 0000000..41b8941 --- /dev/null +++ b/src/lib/src/ida90_compat.cpp @@ -0,0 +1,38 @@ +// Copyright (c) 2026 Oxygen1a1 +// SPDX-License-Identifier: MPL-2.0 +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +/** + * ida90_compat.cpp - compatibility shims for plugins built with newer SDKs. + * + * IDA SDK 9.2 added place_t::equals() and the idaplace_t__equals export. + * Binaries built with 9.2+ headers import that symbol even when they only use + * idaplace_t indirectly. IDA 9.0 does not export it, so loading fails before + * plugin initialization. Provide the default implementation locally. + */ + +struct place_t; +struct idaplace_t; + +#if defined(_WIN32) +#define IDASQL_IDAAPI __stdcall +#else +#define IDASQL_IDAAPI +#endif + +extern "C" int IDASQL_IDAAPI idaplace_t__compare2( + const idaplace_t* ths, + const place_t* t2, + void* ud); + +extern "C" bool IDASQL_IDAAPI idaplace_t__equals( + const idaplace_t* ths, + const place_t* t2, + void* ud) { + return idaplace_t__compare2(ths, t2, ud) == 0; +} + +#undef IDASQL_IDAAPI diff --git a/src/lib/src/ida_headers.hpp b/src/lib/src/ida_headers.hpp index 09c8d47..569935e 100644 --- a/src/lib/src/ida_headers.hpp +++ b/src/lib/src/ida_headers.hpp @@ -85,3 +85,13 @@ #ifdef _MSC_VER #undef strtoull #endif + +#if IDA_SDK_VERSION < 920 +using callcnv_t = cm_t; +#ifndef HTI_SEMICOLON +#define HTI_SEMICOLON 0 +#endif +#ifndef GENDSM_UNHIDE +#define GENDSM_UNHIDE 0 +#endif +#endif diff --git a/src/lib/src/session.cpp b/src/lib/src/session.cpp index 49ff0db..5af755d 100644 --- a/src/lib/src/session.cpp +++ b/src/lib/src/session.cpp @@ -24,7 +24,11 @@ bool Session::open(const char* idb_path) { error_.clear(); // Open the database +#if IDA_SDK_VERSION >= 920 int rc = open_database(idb_path, true, nullptr); +#else + int rc = open_database(idb_path, true); +#endif if (rc != 0) { error_ = "Failed to open database: " + std::string(idb_path); return false; diff --git a/src/lib/src/ui_context_provider.cpp b/src/lib/src/ui_context_provider.cpp index 3acdf15..fc529e2 100644 --- a/src/lib/src/ui_context_provider.cpp +++ b/src/lib/src/ui_context_provider.cpp @@ -242,12 +242,15 @@ static bool is_address_widget_type(twidget_type_t widget_type) { } static bool is_chooser_like_widget_type(twidget_type_t widget_type) { - return is_chooser_widget(widget_type) || - widget_type == BWN_FUNCS || - widget_type == BWN_NAMES || - widget_type == BWN_IMPORTS || - widget_type == BWN_BPTS || - widget_type == BWN_TITREE; + bool is_chooser_like = is_chooser_widget(widget_type) || + widget_type == BWN_FUNCS || + widget_type == BWN_NAMES || + widget_type == BWN_IMPORTS || + widget_type == BWN_BPTS; +#ifdef BWN_TITREE + is_chooser_like = is_chooser_like || widget_type == BWN_TITREE; +#endif + return is_chooser_like; } static const char* widget_type_name(twidget_type_t widget_type) { @@ -262,7 +265,9 @@ static const char* widget_type_name(twidget_type_t widget_type) { case BWN_NAMES: return "BWN_NAMES"; case BWN_IMPORTS: return "BWN_IMPORTS"; case BWN_BPTS: return "BWN_BPTS"; +#ifdef BWN_TITREE case BWN_TITREE: return "BWN_TITREE"; +#endif default: break; } return nullptr; diff --git a/src/plugin/main.cpp b/src/plugin/main.cpp index ecad63e..6e7da59 100644 --- a/src/plugin/main.cpp +++ b/src/plugin/main.cpp @@ -392,7 +392,11 @@ struct idasql_plugmod_t : public plugmod_t static plugmod_t* idaapi init() { // Skip loading when running under idalib (e.g., idasql CLI) +#if IDA_SDK_VERSION >= 920 if (is_ida_library()) { +#else + if (is_ida_library(nullptr, 0, nullptr)) { +#endif msg("IDASQL: Running under idalib, plugin skipped\n"); return nullptr; }