summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrandon Miller <brandon@vector35.com>2026-06-02 09:00:15 -0400
committerBrandon Miller <brandon@vector35.com>2026-06-02 09:00:15 -0400
commit5953d087a9a104e7abb63c5739091214edf2faca (patch)
treeabd95a2698f32b8e1f6ae7feaa9647cff8d218ae
parent68215ea14cfbaa4966f830d85d98f7f49b416455 (diff)
Add support for multiple global pointer registers
-rw-r--r--binaryninjaapi.h22
-rw-r--r--binaryninjacore.h27
-rw-r--r--binaryview.cpp92
-rw-r--r--callingconvention.cpp37
-rw-r--r--examples/triage/analysisinfo.cpp41
-rw-r--r--examples/triage/analysisinfo.h2
-rw-r--r--function.cpp20
-rw-r--r--python/binaryview.py83
-rw-r--r--python/callingconvention.py44
-rw-r--r--python/function.py23
-rw-r--r--rust/src/calling_convention.rs81
-rw-r--r--rust/src/function.rs38
12 files changed, 431 insertions, 79 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index d81ddb11..c42a25ba 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -8249,10 +8249,20 @@ namespace BinaryNinja {
Ref<ExternalLocation> GetExternalLocation(Ref<Symbol> sourceSymbol);
std::vector<Ref<ExternalLocation>> GetExternalLocations();
+ /*! \deprecated Use GetGlobalPointerValues instead. */
Confidence<RegisterValue> GetGlobalPointerValue() const;
+ std::vector<std::pair<uint32_t, Confidence<RegisterValue>>> GetGlobalPointerValues() const;
+ std::vector<std::pair<uint32_t, Confidence<RegisterValue>>> GetDefaultGlobalPointerValues() const;
+ std::vector<std::pair<uint32_t, Confidence<RegisterValue>>> GetUserGlobalPointerValues() const;
+ /*! \deprecated Use UserGlobalPointerValuesSet instead. */
bool UserGlobalPointerValueSet() const;
+ bool UserGlobalPointerValuesSet() const;
+ /*! \deprecated Use ClearUserGlobalPointerValues instead. */
void ClearUserGlobalPointerValue();
+ void ClearUserGlobalPointerValues();
+ /*! \deprecated Use SetUserGlobalPointerValues instead. */
void SetUserGlobalPointerValue(const Confidence<RegisterValue>& value);
+ void SetUserGlobalPointerValues(const std::vector<std::pair<uint32_t, Confidence<RegisterValue>>>& values);
std::optional<std::pair<std::string, BNStringType>> StringifyUnicodeData(Architecture* arch, const DataBuffer& buffer, bool nullTerminates = true, bool allowShortStrings = false);
@@ -13650,7 +13660,9 @@ namespace BinaryNinja {
std::vector<DisassemblyTextLine> GetTypeTokens(DisassemblySettings* settings = nullptr);
+ /*! \deprecated Use GetGlobalPointerValues instead. */
Confidence<RegisterValue> GetGlobalPointerValue() const;
+ std::vector<std::pair<uint32_t, Confidence<RegisterValue>>> GetGlobalPointerValues() const;
bool UsesIncomingGlobalPointer() const;
Confidence<RegisterValue> GetRegisterValueAtExit(uint32_t reg) const;
@@ -17972,7 +17984,7 @@ namespace BinaryNinja {
static uint32_t GetIntegerReturnValueRegisterCallback(void* ctxt);
static uint32_t GetHighIntegerReturnValueRegisterCallback(void* ctxt);
static uint32_t GetFloatReturnValueRegisterCallback(void* ctxt);
- static uint32_t GetGlobalPointerRegisterCallback(void* ctxt);
+ static uint32_t* GetGlobalPointerRegistersCallback(void* ctxt, size_t* count);
static uint32_t* GetImplicitlyDefinedRegistersCallback(void* ctxt, size_t* count);
static void GetIncomingRegisterValueCallback(
@@ -18124,11 +18136,13 @@ namespace BinaryNinja {
*/
virtual uint32_t GetFloatReturnValueRegister();
- /*! Gets the register that holds the global pointer, if the calling convention defines one.
+ /*! \deprecated Use GetGlobalPointerRegisters instead. New calling convention implementations
+ should override GetGlobalPointerRegisters.
\return The global pointer register index, or BN_INVALID_REGISTER if there is none
*/
virtual uint32_t GetGlobalPointerRegister();
+ virtual std::vector<uint32_t> GetGlobalPointerRegisters();
/*! Gets the registers that are implicitly given a known value on function entry by this
calling convention.
@@ -18455,7 +18469,11 @@ namespace BinaryNinja {
virtual uint32_t GetIntegerReturnValueRegister() override;
virtual uint32_t GetHighIntegerReturnValueRegister() override;
virtual uint32_t GetFloatReturnValueRegister() override;
+ /*! \deprecated Use GetGlobalPointerRegisters instead. New calling convention implementations
+ should override GetGlobalPointerRegisters.
+ */
virtual uint32_t GetGlobalPointerRegister() override;
+ virtual std::vector<uint32_t> GetGlobalPointerRegisters() override;
virtual std::vector<uint32_t> GetImplicitlyDefinedRegisters() override;
virtual RegisterValue GetIncomingRegisterValue(uint32_t reg, Function* func) override;
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 176d866e..d09690e5 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -37,14 +37,14 @@
// Current ABI version for linking to the core. This is incremented any time
// there are changes to the API that affect linking, including new functions,
// new types, or modifications to existing functions or types.
-#define BN_CURRENT_CORE_ABI_VERSION 171
+#define BN_CURRENT_CORE_ABI_VERSION 172
// Minimum ABI version that is supported for loading of plugins. Plugins that
// are linked to an ABI version less than this will not be able to load and
// will require rebuilding. The minimum version is increased when there are
// incompatible changes that break binary compatibility, such as changes to
// existing types or functions.
-#define BN_MINIMUM_CORE_ABI_VERSION 171
+#define BN_MINIMUM_CORE_ABI_VERSION 172
#ifdef __GNUC__
#ifdef BINARYNINJACORE_LIBRARY
@@ -1323,6 +1323,12 @@ extern "C"
uint8_t confidence;
} BNRegisterValueWithConfidence;
+ typedef struct BNRegisterValueWithConfidenceAndRegister
+ {
+ uint32_t reg;
+ BNRegisterValueWithConfidence value;
+ } BNRegisterValueWithConfidenceAndRegister;
+
typedef struct BNValueRange
{
uint64_t start, end, step;
@@ -2956,7 +2962,7 @@ extern "C"
uint32_t (*getIntegerReturnValueRegister)(void* ctxt);
uint32_t (*getHighIntegerReturnValueRegister)(void* ctxt);
uint32_t (*getFloatReturnValueRegister)(void* ctxt);
- uint32_t (*getGlobalPointerRegister)(void* ctxt);
+ uint32_t* (*getGlobalPointerRegisters)(void* ctxt, size_t* count);
uint32_t* (*getImplicitlyDefinedRegisters)(void* ctxt, size_t* count);
void (*getIncomingRegisterValue)(void* ctxt, uint32_t reg, BNFunction* func, BNRegisterValue* result);
@@ -4889,10 +4895,13 @@ extern "C"
BINARYNINJACOREAPI BNNameSpace BNGetInternalNameSpace(void);
BINARYNINJACOREAPI void BNFreeNameSpace(BNNameSpace* name);
- BINARYNINJACOREAPI BNRegisterValueWithConfidence BNGetGlobalPointerValue(BNBinaryView* view);
- BINARYNINJACOREAPI bool BNUserGlobalPointerValueSet(BNBinaryView* view);
- BINARYNINJACOREAPI void BNClearUserGlobalPointerValue(BNBinaryView* view);
- BINARYNINJACOREAPI void BNSetUserGlobalPointerValue(BNBinaryView* view, BNRegisterValueWithConfidence value);
+ BINARYNINJACOREAPI BNRegisterValueWithConfidenceAndRegister* BNGetGlobalPointerValues(BNBinaryView* view, size_t* count);
+ BINARYNINJACOREAPI BNRegisterValueWithConfidenceAndRegister* BNGetDefaultGlobalPointerValues(BNBinaryView* view, size_t* count);
+ BINARYNINJACOREAPI BNRegisterValueWithConfidenceAndRegister* BNGetUserGlobalPointerValues(BNBinaryView* view, size_t* count);
+ BINARYNINJACOREAPI void BNFreeRegisterValueWithConfidenceAndRegisterList(BNRegisterValueWithConfidenceAndRegister* values);
+ BINARYNINJACOREAPI bool BNUserGlobalPointerValuesSet(BNBinaryView* view);
+ BINARYNINJACOREAPI void BNClearUserGlobalPointerValues(BNBinaryView* view);
+ BINARYNINJACOREAPI void BNSetUserGlobalPointerValues(BNBinaryView* view, const BNRegisterValueWithConfidenceAndRegister* values, size_t count);
BINARYNINJACOREAPI bool BNStringifyUnicodeData(BNBinaryView* data, BNArchitecture* arch, const BNDataBuffer* buffer, bool nullTerminates, bool allowShortStrings, char** string, BNStringType* type);
@@ -5446,7 +5455,7 @@ extern "C"
BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetFunctionTypeTokens(
BNFunction* func, BNDisassemblySettings* settings, size_t* count);
- BINARYNINJACOREAPI BNRegisterValueWithConfidence BNGetFunctionGlobalPointerValue(BNFunction* func);
+ BINARYNINJACOREAPI BNRegisterValueWithConfidenceAndRegister* BNGetFunctionGlobalPointerValues(BNFunction* func, size_t* count);
BINARYNINJACOREAPI bool BNFunctionUsesIncomingGlobalPointer(BNFunction* func);
BINARYNINJACOREAPI BNRegisterValueWithConfidence BNGetFunctionRegisterValueAtExit(BNFunction* func, uint32_t reg);
@@ -7764,7 +7773,7 @@ extern "C"
BINARYNINJACOREAPI uint32_t BNGetIntegerReturnValueRegister(BNCallingConvention* cc);
BINARYNINJACOREAPI uint32_t BNGetHighIntegerReturnValueRegister(BNCallingConvention* cc);
BINARYNINJACOREAPI uint32_t BNGetFloatReturnValueRegister(BNCallingConvention* cc);
- BINARYNINJACOREAPI uint32_t BNGetGlobalPointerRegister(BNCallingConvention* cc);
+ BINARYNINJACOREAPI uint32_t* BNGetGlobalPointerRegisters(BNCallingConvention* cc, size_t* count);
BINARYNINJACOREAPI uint32_t* BNGetImplicitlyDefinedRegisters(BNCallingConvention* cc, size_t* count);
BINARYNINJACOREAPI BNRegisterValue BNGetIncomingRegisterValue(
diff --git a/binaryview.cpp b/binaryview.cpp
index da6f5b0f..36761bff 100644
--- a/binaryview.cpp
+++ b/binaryview.cpp
@@ -5795,32 +5795,102 @@ std::vector<Ref<ExternalLocation>> BinaryView::GetExternalLocations()
Confidence<RegisterValue> BinaryView::GetGlobalPointerValue() const
{
- BNRegisterValueWithConfidence value = BNGetGlobalPointerValue(m_object);
- return Confidence<RegisterValue>(RegisterValue::FromAPIObject(value.value), value.confidence);
+ auto values = GetGlobalPointerValues();
+ if (values.empty())
+ return Confidence<RegisterValue>();
+ return values[0].second;
+}
+
+
+static vector<pair<uint32_t, Confidence<RegisterValue>>> ConvertGlobalPointerValues(
+ BNRegisterValueWithConfidenceAndRegister* values, size_t count)
+{
+ vector<pair<uint32_t, Confidence<RegisterValue>>> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ result.emplace_back(values[i].reg,
+ Confidence<RegisterValue>(RegisterValue::FromAPIObject(values[i].value.value), values[i].value.confidence));
+ BNFreeRegisterValueWithConfidenceAndRegisterList(values);
+ return result;
+}
+
+
+vector<pair<uint32_t, Confidence<RegisterValue>>> BinaryView::GetGlobalPointerValues() const
+{
+ size_t count;
+ BNRegisterValueWithConfidenceAndRegister* values = BNGetGlobalPointerValues(m_object, &count);
+ return ConvertGlobalPointerValues(values, count);
+}
+
+
+vector<pair<uint32_t, Confidence<RegisterValue>>> BinaryView::GetDefaultGlobalPointerValues() const
+{
+ size_t count;
+ BNRegisterValueWithConfidenceAndRegister* values = BNGetDefaultGlobalPointerValues(m_object, &count);
+ return ConvertGlobalPointerValues(values, count);
+}
+
+
+vector<pair<uint32_t, Confidence<RegisterValue>>> BinaryView::GetUserGlobalPointerValues() const
+{
+ size_t count;
+ BNRegisterValueWithConfidenceAndRegister* values = BNGetUserGlobalPointerValues(m_object, &count);
+ return ConvertGlobalPointerValues(values, count);
}
bool BinaryView::UserGlobalPointerValueSet() const
{
- return BNUserGlobalPointerValueSet(m_object);
+ return UserGlobalPointerValuesSet();
+}
+
+
+bool BinaryView::UserGlobalPointerValuesSet() const
+{
+ return BNUserGlobalPointerValuesSet(m_object);
}
void BinaryView::ClearUserGlobalPointerValue()
{
- return BNClearUserGlobalPointerValue(m_object);
+ ClearUserGlobalPointerValues();
+}
+
+
+void BinaryView::ClearUserGlobalPointerValues()
+{
+ return BNClearUserGlobalPointerValues(m_object);
}
void BinaryView::SetUserGlobalPointerValue(const Confidence<RegisterValue>& value)
{
- BNRegisterValueWithConfidence v;
- v.confidence = value.GetConfidence();
- v.value.value = value.GetValue().value;
- v.value.state = value.GetValue().state;
- v.value.size = value.GetValue().size;
- v.value.offset = value.GetValue().offset;
- BNSetUserGlobalPointerValue(m_object, v);
+ vector<pair<uint32_t, Confidence<RegisterValue>>> values;
+ for (auto& [reg, _] : GetGlobalPointerValues())
+ if (reg != BN_INVALID_REGISTER)
+ values.emplace_back(reg, value);
+ if (values.empty())
+ values.emplace_back(BN_INVALID_REGISTER, value);
+ SetUserGlobalPointerValues(values);
+}
+
+
+void BinaryView::SetUserGlobalPointerValues(const vector<pair<uint32_t, Confidence<RegisterValue>>>& values)
+{
+ vector<BNRegisterValueWithConfidenceAndRegister> apiValues;
+ apiValues.reserve(values.size());
+ for (auto& [reg, value] : values)
+ {
+ BNRegisterValueWithConfidenceAndRegister v;
+ v.reg = reg;
+ v.value.confidence = value.GetConfidence();
+ v.value.value.value = value.GetValue().value;
+ v.value.value.state = value.GetValue().state;
+ v.value.value.size = value.GetValue().size;
+ v.value.value.offset = value.GetValue().offset;
+ apiValues.push_back(v);
+ }
+ BNSetUserGlobalPointerValues(m_object, apiValues.data(), apiValues.size());
}
diff --git a/callingconvention.cpp b/callingconvention.cpp
index ec32a5b1..c16521d5 100644
--- a/callingconvention.cpp
+++ b/callingconvention.cpp
@@ -105,7 +105,7 @@ CallingConvention::CallingConvention(Architecture* arch, const string& name)
cc.getIntegerReturnValueRegister = GetIntegerReturnValueRegisterCallback;
cc.getHighIntegerReturnValueRegister = GetHighIntegerReturnValueRegisterCallback;
cc.getFloatReturnValueRegister = GetFloatReturnValueRegisterCallback;
- cc.getGlobalPointerRegister = GetGlobalPointerRegisterCallback;
+ cc.getGlobalPointerRegisters = GetGlobalPointerRegistersCallback;
cc.getImplicitlyDefinedRegisters = GetImplicitlyDefinedRegistersCallback;
cc.getIncomingRegisterValue = GetIncomingRegisterValueCallback;
cc.getIncomingFlagValue = GetIncomingFlagValueCallback;
@@ -282,10 +282,16 @@ uint32_t CallingConvention::GetFloatReturnValueRegisterCallback(void* ctxt)
}
-uint32_t CallingConvention::GetGlobalPointerRegisterCallback(void* ctxt)
+uint32_t* CallingConvention::GetGlobalPointerRegistersCallback(void* ctxt, size_t* count)
{
CallbackRef<CallingConvention> cc(ctxt);
- return cc->GetGlobalPointerRegister();
+ vector<uint32_t> regs = cc->GetGlobalPointerRegisters();
+ *count = regs.size();
+
+ uint32_t* result = new uint32_t[regs.size()];
+ for (size_t i = 0; i < regs.size(); i++)
+ result[i] = regs[i];
+ return result;
}
@@ -695,6 +701,15 @@ uint32_t CallingConvention::GetGlobalPointerRegister()
}
+vector<uint32_t> CallingConvention::GetGlobalPointerRegisters()
+{
+ uint32_t reg = GetGlobalPointerRegister();
+ if (reg == BN_INVALID_REGISTER)
+ return vector<uint32_t>();
+ return vector<uint32_t> { reg };
+}
+
+
vector<uint32_t> CallingConvention::GetImplicitlyDefinedRegisters()
{
return vector<uint32_t>();
@@ -1141,7 +1156,21 @@ uint32_t CoreCallingConvention::GetFloatReturnValueRegister()
uint32_t CoreCallingConvention::GetGlobalPointerRegister()
{
- return BNGetGlobalPointerRegister(m_object);
+ vector<uint32_t> regs = GetGlobalPointerRegisters();
+ if (regs.empty())
+ return BN_INVALID_REGISTER;
+ return regs[0];
+}
+
+
+vector<uint32_t> CoreCallingConvention::GetGlobalPointerRegisters()
+{
+ size_t count;
+ uint32_t* regs = BNGetGlobalPointerRegisters(m_object, &count);
+ vector<uint32_t> result;
+ result.insert(result.end(), regs, &regs[count]);
+ BNFreeRegisterList(regs);
+ return result;
}
diff --git a/examples/triage/analysisinfo.cpp b/examples/triage/analysisinfo.cpp
index cd18e242..7e04a0b7 100644
--- a/examples/triage/analysisinfo.cpp
+++ b/examples/triage/analysisinfo.cpp
@@ -44,11 +44,11 @@ AnalysisInfoWidget::~AnalysisInfoWidget()
void AnalysisInfoWidget::timerExpired()
{
- auto gpValue = m_data->GetGlobalPointerValue();
- if (gpValue == m_lastGPValue)
+ auto gpValues = m_data->GetGlobalPointerValues();
+ if (gpValues == m_lastGPValues)
return;
- m_lastGPValue = gpValue;
+ m_lastGPValues = gpValues;
updateDisplay();
}
@@ -61,14 +61,36 @@ void AnalysisInfoWidget::updateDisplay()
auto callingConvention = defaultPlatform->GetDefaultCallingConvention();
if (callingConvention)
{
- auto gpRegister = callingConvention->GetGlobalPointerRegister();
- if (gpRegister != BN_INVALID_REGISTER)
+ auto gpValues = m_data->GetGlobalPointerValues();
+ if (!gpValues.empty())
{
- auto gpValue = m_data->GetGlobalPointerValue();
- std::string gpString = getStringForRegisterValue(m_data->GetDefaultArchitecture(), gpValue);
- std::string gpExtraString = std::string(" @ ") + m_data->GetDefaultArchitecture()->GetRegisterName(gpRegister);
+ std::vector<std::string> gpStrings;
+ auto arch = m_data->GetDefaultArchitecture();
+ for (auto& [reg, value] : gpValues)
+ {
+ if (reg == BN_INVALID_REGISTER)
+ continue;
+ gpStrings.push_back(arch->GetRegisterName(reg) + "=" + getStringForRegisterValue(arch, value));
+ }
+
+ if (gpStrings.empty())
+ {
+ m_gpLabel->setText("N/A");
+ m_gpExtraLabel->setText("");
+ return;
+ }
+
+ std::string gpString;
+ for (size_t i = 0; i < gpStrings.size(); i++)
+ {
+ if (i != 0)
+ gpString += ", ";
+ gpString += gpStrings[i];
+ }
+
+ std::string gpExtraString;
if (m_data->UserGlobalPointerValueSet())
- gpExtraString += " (*)";
+ gpExtraString = " (*)";
m_gpLabel->setText(QString::fromStdString(gpString));
m_gpExtraLabel->setText(QString::fromStdString(gpExtraString));
@@ -78,4 +100,5 @@ void AnalysisInfoWidget::updateDisplay()
}
m_gpLabel->setText("N/A");
+ m_gpExtraLabel->setText("");
}
diff --git a/examples/triage/analysisinfo.h b/examples/triage/analysisinfo.h
index 4e6e6df3..658d3702 100644
--- a/examples/triage/analysisinfo.h
+++ b/examples/triage/analysisinfo.h
@@ -16,7 +16,7 @@ class AnalysisInfoWidget : public QWidget
NavigationAddressLabel* m_gpLabel;
QLabel* m_gpExtraLabel;
- BinaryNinja::Confidence<BinaryNinja::RegisterValue> m_lastGPValue;
+ std::vector<std::pair<uint32_t, BinaryNinja::Confidence<BinaryNinja::RegisterValue>>> m_lastGPValues;
void updateDisplay();
diff --git a/function.cpp b/function.cpp
index bd7003e0..d81394f8 100644
--- a/function.cpp
+++ b/function.cpp
@@ -2428,8 +2428,24 @@ Ref<Tag> Function::CreateUserFunctionTag(Ref<TagType> tagType, const std::string
Confidence<RegisterValue> Function::GetGlobalPointerValue() const
{
- BNRegisterValueWithConfidence value = BNGetFunctionGlobalPointerValue(m_object);
- return Confidence<RegisterValue>(RegisterValue::FromAPIObject(value.value), value.confidence);
+ auto values = GetGlobalPointerValues();
+ if (values.empty())
+ return Confidence<RegisterValue>();
+ return values[0].second;
+}
+
+
+vector<pair<uint32_t, Confidence<RegisterValue>>> Function::GetGlobalPointerValues() const
+{
+ size_t count;
+ BNRegisterValueWithConfidenceAndRegister* values = BNGetFunctionGlobalPointerValues(m_object, &count);
+ vector<pair<uint32_t, Confidence<RegisterValue>>> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ result.emplace_back(values[i].reg,
+ Confidence<RegisterValue>(RegisterValue::FromAPIObject(values[i].value.value), values[i].value.confidence));
+ BNFreeRegisterValueWithConfidenceAndRegisterList(values);
+ return result;
}
diff --git a/python/binaryview.py b/python/binaryview.py
index d97e9f4d..b1fbde79 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -4204,21 +4204,65 @@ class BinaryView:
@property
def global_pointer_value(self) -> 'variable.RegisterValue':
- """Discovered value of the global pointer register, if the binary uses one (read-only)"""
- result = core.BNGetGlobalPointerValue(self.handle)
- return variable.RegisterValue.from_BNRegisterValue(result, self.arch)
+ """Deprecated. Use :py:attr:`global_pointer_values` instead."""
+ values = self.global_pointer_values
+ if not values:
+ return variable.Undetermined()
+ return values[0][1]
@property
+ def global_pointer_values(self) -> List[Tuple['architecture.RegisterName', 'variable.RegisterValue']]:
+ """Discovered values of the global pointer registers, if the binary uses any (read-only)"""
+ return self._get_global_pointer_values(core.BNGetGlobalPointerValues)
+
+ @property
+ def default_global_pointer_values(self) -> List[Tuple['architecture.RegisterName', 'variable.RegisterValue']]:
+ """Auto-discovered values of the global pointer registers before user overrides are applied (read-only)"""
+ return self._get_global_pointer_values(core.BNGetDefaultGlobalPointerValues)
+
+ @property
+ def user_global_pointer_values(self) -> List[Tuple['architecture.RegisterName', 'variable.RegisterValue']]:
+ """User overrides for global pointer register values (read-only)"""
+ return self._get_global_pointer_values(core.BNGetUserGlobalPointerValues)
+
+ def _get_global_pointer_values(self, getter) -> List[Tuple['architecture.RegisterName', 'variable.RegisterValue']]:
+ count = ctypes.c_ulonglong()
+ values = getter(self.handle, count)
+ if values is None:
+ return []
+ try:
+ return [
+ (self.arch.get_reg_name(values[i].reg), variable.RegisterValue.from_BNRegisterValue(values[i].value, self.arch))
+ for i in range(count.value)
+ ]
+ finally:
+ core.BNFreeRegisterValueWithConfidenceAndRegisterList(values)
+
+ @property
+ @deprecation.deprecated(deprecated_in="5.4", details="Use `BinaryView.user_global_pointer_values_set` instead.")
def user_global_pointer_value_set(self) -> bool:
- """Check whether a user global pointer value has been set"""
- return core.BNUserGlobalPointerValueSet(self.handle)
+ """Deprecated. Use :py:attr:`user_global_pointer_values_set` instead."""
+ return self.user_global_pointer_values_set
+
+ @property
+ def user_global_pointer_values_set(self) -> bool:
+ """Check whether user global pointer values have been set"""
+ return core.BNUserGlobalPointerValuesSet(self.handle)
+ @deprecation.deprecated(deprecated_in="5.4", details="Use `BinaryView.clear_user_global_pointer_values` instead.")
def clear_user_global_pointer_value(self):
- """Clear a previously set user global pointer value, so the auto-analysis can calculate a new value"""
- core.BNClearUserGlobalPointerValue(self.handle)
+ """Deprecated. Use :py:meth:`clear_user_global_pointer_values` instead."""
+ self.clear_user_global_pointer_values()
+ def clear_user_global_pointer_values(self):
+ """Clear previously set user global pointer values, so the auto-analysis can calculate new values"""
+ core.BNClearUserGlobalPointerValues(self.handle)
+
+ @deprecation.deprecated(deprecated_in="5.4", details="Use `BinaryView.set_user_global_pointer_values` instead.")
def set_user_global_pointer_value(self, value: variable.RegisterValue, confidence = 255):
"""
+ Deprecated. Use :py:meth:`set_user_global_pointer_values` instead.
+
Set a user global pointer value. This is useful when the auto analysis fails to find out the value of the global
pointer, or the value is wrong. In this case, we can call ``set_user_global_pointer_value`` with a
``ConstantRegisterValue`` or ``ConstantPointerRegisterValue`` to provide a user global pointer value to assist the
@@ -4258,10 +4302,27 @@ class BinaryView:
>>> bv.global_pointer_value
<undetermined>
"""
- val = core.BNRegisterValueWithConfidence()
- val.value = value._to_core_struct()
- val.confidence = confidence
- core.BNSetUserGlobalPointerValue(self.handle, val)
+ values = [(reg, value, confidence) for reg, _ in self.global_pointer_values]
+ if not values:
+ values = [(0xffffffff, value, confidence)]
+ self.set_user_global_pointer_values(values)
+
+ def set_user_global_pointer_values(self, values):
+ """
+ Set user global pointer values for multiple registers.
+
+ :param list[tuple[str, variable.RegisterValue]] values: register name/value pairs
+ :return: None
+ :rtype: None
+ """
+ api_values = (core.BNRegisterValueWithConfidenceAndRegister * len(values))()
+ for i, value in enumerate(values):
+ reg, reg_value = value[:2]
+ confidence = value[2] if len(value) > 2 else 255
+ api_values[i].reg = reg if isinstance(reg, int) else self.arch.get_reg_index(reg)
+ api_values[i].value.value = reg_value._to_core_struct()
+ api_values[i].value.confidence = confidence
+ core.BNSetUserGlobalPointerValues(self.handle, api_values, len(values))
@property
def parameters_for_analysis(self):
diff --git a/python/callingconvention.py b/python/callingconvention.py
index a76f59f0..6c6e1409 100644
--- a/python/callingconvention.py
+++ b/python/callingconvention.py
@@ -122,8 +122,11 @@ class CallingConvention:
that is too large to fit in a single register, or ``None`` if there is none.
:cvar float_return_reg: The register that holds the floating point return value, or ``None``
if there is none.
- :cvar global_pointer_reg: The register that holds the global pointer, if the calling
- convention defines one, or ``None`` if there is none.
+ :cvar global_pointer_reg: Deprecated. Use ``global_pointer_regs`` instead. The register
+ that holds the global pointer, if the calling convention defines one, or ``None`` if
+ there is none.
+ :cvar global_pointer_regs: The registers that hold global pointers, if the calling
+ convention defines any.
:cvar implicitly_defined_regs: The registers that are implicitly given a known value on
function entry by this calling convention.
:cvar stack_args_naturally_aligned: Whether arguments passed on the stack are aligned to their
@@ -147,6 +150,7 @@ class CallingConvention:
high_int_return_reg = None
float_return_reg = None
global_pointer_reg = None
+ global_pointer_regs = []
implicitly_defined_regs = []
stack_args_naturally_aligned = False
stack_args_pushed_left_to_right = False
@@ -204,8 +208,8 @@ class CallingConvention:
self._cb.getFloatReturnValueRegister = self._cb.getFloatReturnValueRegister.__class__(
self._get_float_return_reg
)
- self._cb.getGlobalPointerRegister = self._cb.getGlobalPointerRegister.__class__(
- self._get_global_pointer_reg
+ self._cb.getGlobalPointerRegisters = self._cb.getGlobalPointerRegisters.__class__(
+ self._get_global_pointer_regs
)
self._cb.getImplicitlyDefinedRegisters = self._cb.getImplicitlyDefinedRegisters.__class__(
self._get_implicitly_defined_regs
@@ -463,6 +467,23 @@ class CallingConvention:
log_error_for_exception("Unhandled Python exception in CallingConvention._get_global_pointer_reg")
return False
+ def _get_global_pointer_regs(self, ctxt, count):
+ try:
+ regs = self.__class__.global_pointer_regs
+ if not regs and self.__class__.global_pointer_reg is not None:
+ regs = [self.__class__.global_pointer_reg]
+ count[0] = len(regs)
+ reg_buf = (ctypes.c_uint * len(regs))()
+ for i in range(0, len(regs)):
+ reg_buf[i] = self.arch.regs[regs[i]].index
+ result = ctypes.cast(reg_buf, ctypes.c_void_p)
+ self._pending_reg_lists[result.value] = (result, reg_buf)
+ return result.value
+ except Exception:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._get_global_pointer_regs")
+ count[0] = 0
+ return None
+
def _get_implicitly_defined_regs(self, ctxt, count):
try:
regs = self.__class__.implicitly_defined_regs
@@ -1509,11 +1530,16 @@ class CoreCallingConvention(CallingConvention):
else:
self.__dict__["float_return_reg"] = self.arch.get_reg_name(reg)
- reg = core.BNGetGlobalPointerRegister(handle)
- if reg == 0xffffffff:
- self.__dict__["global_pointer_reg"] = None
- else:
- self.__dict__["global_pointer_reg"] = self.arch.get_reg_name(reg)
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetGlobalPointerRegisters(handle, count)
+ result = []
+ arch = self.arch
+ if regs is not None:
+ for i in range(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs)
+ self.__dict__["global_pointer_regs"] = result
+ self.__dict__["global_pointer_reg"] = result[0] if result else None
count = ctypes.c_ulonglong()
regs = core.BNGetImplicitlyDefinedRegisters(handle, count)
diff --git a/python/function.py b/python/function.py
index 900aa0de..5e7541f6 100644
--- a/python/function.py
+++ b/python/function.py
@@ -1605,9 +1605,26 @@ class Function:
@property
def global_pointer_value(self) -> variable.RegisterValue:
- """Discovered value of the global pointer register, if the function uses one (read-only)"""
- result = core.BNGetFunctionGlobalPointerValue(self.handle)
- return variable.RegisterValue.from_BNRegisterValue(result, self.arch)
+ """Deprecated. Use :py:attr:`global_pointer_values` instead."""
+ values = self.global_pointer_values
+ if not values:
+ return variable.Undetermined()
+ return values[0][1]
+
+ @property
+ def global_pointer_values(self) -> List[Tuple['architecture.RegisterName', 'variable.RegisterValue']]:
+ """Discovered values of the global pointer registers, if the function uses any (read-only)"""
+ count = ctypes.c_ulonglong()
+ values = core.BNGetFunctionGlobalPointerValues(self.handle, count)
+ if values is None:
+ return []
+ try:
+ return [
+ (self.arch.get_reg_name(values[i].reg), variable.RegisterValue.from_BNRegisterValue(values[i].value, self.arch))
+ for i in range(count.value)
+ ]
+ finally:
+ core.BNFreeRegisterValueWithConfidenceAndRegisterList(values)
@property
def uses_incoming_global_pointer(self) -> bool:
diff --git a/rust/src/calling_convention.rs b/rust/src/calling_convention.rs
index c0d349a8..04ff3452 100644
--- a/rust/src/calling_convention.rs
+++ b/rust/src/calling_convention.rs
@@ -102,8 +102,13 @@ pub trait CallingConvention: 'static + Sync + Sized + AsRef<CoreCallingConventio
/// Gets the register that holds the floating point return value.
fn return_float_reg(&self) -> Option<RegisterId>;
+ /// Deprecated. Use [`CallingConvention::global_pointer_regs`] instead.
+ ///
/// Gets the register that holds the global pointer, if the calling convention defines one.
fn global_pointer_reg(&self) -> Option<RegisterId>;
+ fn global_pointer_regs(&self) -> Vec<RegisterId> {
+ self.global_pointer_reg().into_iter().collect()
+ }
/// Gets the registers that are implicitly given a known value on function entry by this
/// calling convention.
@@ -515,15 +520,12 @@ where
})
}
- extern "C" fn cb_global_pointer_reg<C>(ctxt: *mut c_void) -> u32
+ extern "C" fn cb_global_pointer_regs<C>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
where
C: CallingConvention,
{
- ffi_wrap!("CallingConvention::global_pointer_reg", unsafe {
- from_ctxt::<C>(ctxt)
- .global_pointer_reg()
- .map(|r| r.0)
- .unwrap_or(INVALID_REGISTER)
+ ffi_wrap!("CallingConvention::global_pointer_regs", unsafe {
+ register_list(from_ctxt::<C>(ctxt).global_pointer_regs(), count)
})
}
@@ -1030,7 +1032,7 @@ where
getIntegerReturnValueRegister: Some(cb_return_int_reg::<C>),
getHighIntegerReturnValueRegister: Some(cb_return_hi_int_reg::<C>),
getFloatReturnValueRegister: Some(cb_return_float_reg::<C>),
- getGlobalPointerRegister: Some(cb_global_pointer_reg::<C>),
+ getGlobalPointerRegisters: Some(cb_global_pointer_regs::<C>),
getImplicitlyDefinedRegisters: Some(cb_implicitly_defined_registers::<C>),
getIncomingRegisterValue: Some(cb_incoming_reg_value::<C>),
@@ -1427,6 +1429,7 @@ impl Debug for CoreCallingConvention {
.field("return_hi_int_reg", &self.return_hi_int_reg())
.field("return_float_reg", &self.return_float_reg())
.field("global_pointer_reg", &self.global_pointer_reg())
+ .field("global_pointer_regs", &self.global_pointer_regs())
.field(
"implicitly_defined_registers",
&self.implicitly_defined_registers(),
@@ -1579,14 +1582,22 @@ impl CallingConvention for CoreCallingConvention {
}
}
+ /// Deprecated. Use [`CallingConvention::global_pointer_regs`] instead.
fn global_pointer_reg(&self) -> Option<RegisterId> {
- match unsafe { BNGetGlobalPointerRegister(self.handle) } {
- id if id < 0x8000_0000 => self
- .arch_handle
- .borrow()
- .register_from_id(RegisterId(id))
- .map(|r| r.id()),
- _ => None,
+ self.global_pointer_regs().first().copied()
+ }
+
+ fn global_pointer_regs(&self) -> Vec<RegisterId> {
+ unsafe {
+ let mut count = 0;
+ let regs_ptr = BNGetGlobalPointerRegisters(self.handle, &mut count);
+ let regs: Vec<RegisterId> = std::slice::from_raw_parts(regs_ptr, count)
+ .iter()
+ .copied()
+ .map(RegisterId::from)
+ .collect();
+ BNFreeRegisterList(regs_ptr);
+ regs
}
}
@@ -2009,6 +2020,7 @@ struct ConventionConfig {
return_float_reg: Option<RegisterId>,
global_pointer_reg: Option<RegisterId>,
+ global_pointer_regs: Vec<RegisterId>,
implicitly_defined_registers: Vec<RegisterId>,
@@ -2085,6 +2097,7 @@ impl<A: Architecture> ConventionBuilder<A> {
return_float_reg: None,
global_pointer_reg: None,
+ global_pointer_regs: Vec::new(),
implicitly_defined_registers: Vec::new(),
@@ -2118,7 +2131,33 @@ impl<A: Architecture> ConventionBuilder<A> {
reg!(return_hi_int_reg);
reg!(return_float_reg);
- reg!(global_pointer_reg);
+ /// Deprecated. Use [`Self::global_pointer_regs`] instead.
+ pub fn global_pointer_reg(mut self, reg: &str) -> Self {
+ {
+ // FIXME NLL
+ let arch = self.arch_handle.borrow();
+ self.config.global_pointer_reg = arch.register_by_name(reg).map(|r| r.id());
+ self.config.global_pointer_regs = self.config.global_pointer_reg.into_iter().collect();
+ }
+
+ self
+ }
+
+ pub fn global_pointer_regs(mut self, regs: &[&str]) -> Self {
+ {
+ // FIXME NLL
+ let arch = self.arch_handle.borrow();
+ let arch_regs = regs
+ .iter()
+ .filter_map(|&r| arch.register_by_name(r))
+ .map(|r| r.id());
+
+ self.config.global_pointer_regs = arch_regs.collect();
+ self.config.global_pointer_reg = self.config.global_pointer_regs.first().copied();
+ }
+
+ self
+ }
reg_list!(implicitly_defined_registers);
@@ -2216,7 +2255,17 @@ impl CallingConvention for RegisteredConvention {
}
fn global_pointer_reg(&self) -> Option<RegisterId> {
- self.config.global_pointer_reg
+ self.config
+ .global_pointer_reg
+ .or_else(|| self.config.global_pointer_regs.first().copied())
+ }
+
+ fn global_pointer_regs(&self) -> Vec<RegisterId> {
+ if self.config.global_pointer_regs.is_empty() {
+ self.config.global_pointer_reg.into_iter().collect()
+ } else {
+ self.config.global_pointer_regs.clone()
+ }
}
fn implicitly_defined_registers(&self) -> Vec<RegisterId> {
diff --git a/rust/src/function.rs b/rust/src/function.rs
index 9806a5ca..f9b63524 100644
--- a/rust/src/function.rs
+++ b/rust/src/function.rs
@@ -2230,10 +2230,44 @@ impl Function {
unsafe { Array::new(refs, count, ()) }
}
+ /// Deprecated. Use [`Function::global_pointer_values`] instead.
+ ///
/// Discovered value of the global pointer register, if the function uses one
pub fn global_pointer_value(&self) -> Conf<RegisterValue> {
- let result = unsafe { BNGetFunctionGlobalPointerValue(self.handle) };
- Conf::new(result.value.into(), result.confidence)
+ self.global_pointer_values()
+ .into_iter()
+ .next()
+ .map(|(_, value)| value)
+ .unwrap_or_else(|| {
+ Conf::new(
+ RegisterValue::new(RegisterValueType::UndeterminedValue, 0, 0, 0),
+ 255,
+ )
+ })
+ }
+
+ /// Discovered values of the global pointer registers, if the function uses any
+ pub fn global_pointer_values(&self) -> Vec<(RegisterId, Conf<RegisterValue>)> {
+ unsafe {
+ let mut count = 0;
+ let values_ptr = BNGetFunctionGlobalPointerValues(self.handle, &mut count);
+ if values_ptr.is_null() {
+ return Vec::new();
+ }
+
+ let values = std::slice::from_raw_parts(values_ptr, count);
+ let result = values
+ .iter()
+ .map(|value| {
+ (
+ RegisterId::from(value.reg),
+ Conf::new(value.value.value.into(), value.value.confidence),
+ )
+ })
+ .collect();
+ BNFreeRegisterValueWithConfidenceAndRegisterList(values_ptr);
+ result
+ }
}
pub fn type_tokens(