Skip to content

Commit d4a5ad8

Browse files
committed
Parameter location display and parsing
1 parent 540b413 commit d4a5ad8

8 files changed

Lines changed: 149 additions & 8 deletions

File tree

binaryninjaapi.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10572,6 +10572,8 @@ namespace BinaryNinja {
1057210572

1057310573
static ValueLocationComponent FromAPIObject(const BNValueLocationComponent* loc);
1057410574
BNValueLocationComponent ToAPIObject() const;
10575+
10576+
std::string ToString(Architecture* arch) const;
1057510577
};
1057610578

1057710579
struct ValueLocation
@@ -10601,6 +10603,9 @@ namespace BinaryNinja {
1060110603
static ValueLocation FromAPIObject(const BNValueLocation* loc);
1060210604
BNValueLocation ToAPIObject() const;
1060310605
static void FreeAPIObject(BNValueLocation* loc);
10606+
10607+
static std::optional<ValueLocation> Parse(const std::string& str, Architecture* arch, std::string& error);
10608+
std::string ToString(Architecture* arch) const;
1060410609
};
1060510610

1060610611
struct FunctionParameter

binaryninjacore.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,7 @@ extern "C"
478478
BaseStructureNameToken = 37,
479479
BaseStructureSeparatorToken = 38,
480480
BraceToken = 39,
481+
ValueLocationToken = 40,
481482
// The following are output by the analysis system automatically, these should
482483
// not be used directly by the architecture plugins
483484
CodeSymbolToken = 64,
@@ -7177,6 +7178,10 @@ extern "C"
71777178
BINARYNINJACOREAPI BNReturnValue BNGetTypeReturnValue(BNType* type);
71787179
BINARYNINJACOREAPI bool BNIsTypeReturnValueDefaultLocation(BNType* type);
71797180
BINARYNINJACOREAPI BNValueLocationWithConfidence BNGetTypeReturnValueLocation(BNType* type);
7181+
BINARYNINJACOREAPI bool BNParseValueLocation(
7182+
const char* str, BNArchitecture* arch, BNValueLocation* location, char** error);
7183+
BINARYNINJACOREAPI char* BNValueLocationToString(BNValueLocation* location, BNArchitecture* arch);
7184+
BINARYNINJACOREAPI char* BNValueLocationComponentToString(BNValueLocationComponent* component, BNArchitecture* arch);
71807185
BINARYNINJACOREAPI void BNFreeValueLocation(BNValueLocation* location);
71817186
BINARYNINJACOREAPI BNCallingConventionWithConfidence BNGetTypeCallingConvention(BNType* type);
71827187
BINARYNINJACOREAPI BNCallingConventionName BNGetTypeCallingConventionName(BNType* type);

lang/rust/rusttypes.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,6 @@ vector<InstructionTextToken> RustTypePrinter::GetTypeTokensAfterNameInternal(
177177

178178
if (!params[i].defaultLocation && platform && var.has_value())
179179
{
180-
// TODO: Emit a syntax for parameters spanning multiple storage locations
181180
switch (var->type)
182181
{
183182
case RegisterVariableSourceType:
@@ -202,10 +201,14 @@ vector<InstructionTextToken> RustTypePrinter::GetTypeTokensAfterNameInternal(
202201
tokens.emplace_back(IntegerToken, storageStr, var->storage);
203202
break;
204203
}
205-
case CompositeReturnValueSourceType:
206-
case CompositeParameterSourceType:
204+
default:
205+
{
206+
string locationStr = params[i].location.ToString(platform->GetArchitecture());
207+
tokens.emplace_back(TextToken, " @ ");
208+
tokens.emplace_back(ValueLocationToken, locationStr);
207209
break;
208210
}
211+
}
209212
}
210213
}
211214

@@ -235,6 +238,13 @@ vector<InstructionTextToken> RustTypePrinter::GetTypeTokensAfterNameInternal(
235238
i.context = FunctionReturnTokenContext;
236239
}
237240
tokens.insert(tokens.end(), retn.begin(), retn.end());
241+
if (!type->GetReturnValue().defaultLocation)
242+
{
243+
auto location = type->GetReturnValue().location;
244+
string locationStr = location->ToString(platform->GetArchitecture());
245+
tokens.emplace_back(TextToken, " @ ");
246+
tokens.emplace_back(location.GetCombinedConfidence(baseConfidence), ValueLocationToken, locationStr);
247+
}
238248
}
239249
break;
240250
}

python/examples/pseudo_python.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,23 +1136,33 @@ def function_type_tokens(self, func: Function, settings: DisassemblySettings) ->
11361136
tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "def "))
11371137
tokens.append(InstructionTextToken(InstructionTextTokenType.CodeSymbolToken, func.name, value=func.start))
11381138
tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, "("))
1139+
params = func.type.parameters
11391140
for (i, param) in enumerate(func.type.parameters_with_all_locations):
11401141
if i > 0:
11411142
tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
1143+
var = param.location.variable_for_parameter(i)
11421144
tokens.append(InstructionTextToken(InstructionTextTokenType.ArgumentNameToken, param.name,
11431145
context=InstructionTextTokenContext.LocalVariableTokenContext,
1144-
address=param.location.identifier))
1146+
address=var.identifier))
11451147
tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ": "))
11461148
for token in param.type.get_tokens():
11471149
token.context = InstructionTextTokenContext.LocalVariableTokenContext
1148-
token.address = param.location.identifier
1150+
token.address = var.identifier
11491151
tokens.append(token)
1152+
if i < len(params) and params[i].location is not None:
1153+
tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " @ "))
1154+
tokens.append(InstructionTextToken(InstructionTextTokenType.ValueLocationToken,
1155+
params[i].location.to_string(func.arch)))
11501156
tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, ")"))
11511157
if func.can_return.value and func.type.return_value is not None and not isinstance(func.type.return_value, VoidType):
11521158
tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " -> "))
11531159
for token in func.type.return_value.get_tokens():
11541160
token.context = InstructionTextTokenContext.FunctionReturnTokenContext
11551161
tokens.append(token)
1162+
if func.type.return_value_location is not None:
1163+
tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " @ "))
1164+
tokens.append(InstructionTextToken(InstructionTextTokenType.ValueLocationToken,
1165+
func.type.return_value_location.location.to_string(func.arch)))
11561166
tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
11571167
return [DisassemblyTextLine(tokens, func.start)]
11581168

python/types.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,31 @@ def _to_core_struct(self) -> core.BNValueLocationComponent:
479479
struct.returnedPointer = self.returned_pointer.to_BNVariable()
480480
return struct
481481

482+
def to_string(self, arch: Optional['architecture.Architecture']):
483+
if arch is None:
484+
if isinstance(self.var, variable.ArchitectureVariable):
485+
arch = self.var.arch
486+
elif isinstance(self.var, variable.Variable):
487+
arch = self.var.function.arch
488+
if arch is None:
489+
if self.indirect:
490+
indirect = " indirect"
491+
else:
492+
indirect = ""
493+
if self.returned_pointer is None:
494+
ret_ptr = ""
495+
else:
496+
ret_ptr = f" returned ptr {repr(self.returned_pointer)}"
497+
return f"{repr(self.var)} offset {hex(self.offset)} size {repr(self.size)}{indirect}{ret_ptr}"
498+
struct = self._to_core_struct()
499+
return core.BNValueLocationComponentToString(struct, arch.handle)
500+
501+
def __str__(self):
502+
return self.to_string(None)
503+
504+
def __repr__(self):
505+
return f"<component {self.to_string(None)}>"
506+
482507

483508
@dataclass
484509
class ValueLocation:
@@ -503,6 +528,46 @@ def _to_core_struct(self) -> core.BNValueLocation:
503528
def with_confidence(self, confidence: int) -> 'ValueLocationWithConfidence':
504529
return ValueLocationWithConfidence(self, confidence)
505530

531+
def variable_for_parameter(self, idx: int) -> Optional['variable.CoreVariable']:
532+
struct = self._to_core_struct()
533+
var = core.BNVariable()
534+
if core.BNGetValueLocationVariableForParameter(struct, var, idx):
535+
return variable.CoreVariable.from_BNVariable(var)
536+
return None
537+
538+
@staticmethod
539+
def parse(string: str, arch: 'architecture.Architecture') -> 'ValueLocation':
540+
struct = core.BNValueLocation()
541+
error = ctypes.c_char_p()
542+
if not core.BNParseValueLocation(string, arch.handle, struct, error):
543+
assert error.value is not None, "core.BNParseValueLocation returned 'error' set to None"
544+
error_str = error.value.decode("utf-8")
545+
core.free_string(error)
546+
raise SyntaxError(error_str)
547+
result = ValueLocation._from_core_struct(struct, arch)
548+
core.BNFreeValueLocation(struct)
549+
return result
550+
551+
def to_string(self, arch: Optional['architecture.Architecture']):
552+
if arch is None:
553+
for component in self.components:
554+
if isinstance(component.var, variable.ArchitectureVariable):
555+
arch = component.var.arch
556+
break
557+
if isinstance(component.var, variable.Variable):
558+
arch = component.var.function.arch
559+
break
560+
if arch is None:
561+
return repr(self.components)
562+
struct = self._to_core_struct()
563+
return core.BNValueLocationToString(struct, arch.handle)
564+
565+
def __str__(self):
566+
return self.to_string(None)
567+
568+
def __repr__(self):
569+
return f"<value location {self.to_string(None)}>"
570+
506571

507572
@dataclass
508573
class ValueLocationWithConfidence:
@@ -519,6 +584,9 @@ def from_optional_location(location: OptionalLocation) -> Optional['ValueLocatio
519584
return ValueLocation([ValueLocationComponent(location)]).with_confidence(core.max_confidence)
520585
return None
521586

587+
def __repr__(self):
588+
return f"<value location {self.location.to_string(None)} confidence {self.confidence}>"
589+
522590

523591
@dataclass
524592
class ReturnValue:
@@ -570,7 +638,7 @@ def __init__(self, type: SomeType, name: str = "", location: OptionalLocation =
570638

571639
def __repr__(self):
572640
ic = self.type.immutable_copy()
573-
if self.location is not None:
641+
if (self.location is not None) and (str(self.location) != self.name):
574642
return f"{ic.get_string_before_name()} {self.name}{ic.get_string_after_name()} @ {self.location}"
575643
return f"{ic.get_string_before_name()} {self.name}{ic.get_string_after_name()}"
576644

rust/src/disassembly.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ pub enum InstructionTextTokenKind {
506506
// TODO: Explain what this is
507507
hash: Option<u64>,
508508
},
509+
ValueLocation,
509510
CodeSymbol {
510511
// Target address of the symbol
511512
value: u64,
@@ -700,6 +701,7 @@ impl InstructionTextTokenKind {
700701
hash => Some(hash),
701702
},
702703
},
704+
BNInstructionTextTokenType::ValueLocationToken => Self::ValueLocation,
703705
BNInstructionTextTokenType::CodeSymbolToken => Self::CodeSymbol {
704706
value: value.value,
705707
size: value.size,
@@ -914,6 +916,9 @@ impl From<InstructionTextTokenKind> for BNInstructionTextTokenType {
914916
BNInstructionTextTokenType::BaseStructureSeparatorToken
915917
}
916918
InstructionTextTokenKind::Brace { .. } => BNInstructionTextTokenType::BraceToken,
919+
InstructionTextTokenKind::ValueLocation => {
920+
BNInstructionTextTokenType::ValueLocationToken
921+
}
917922
InstructionTextTokenKind::CodeSymbol { .. } => {
918923
BNInstructionTextTokenType::CodeSymbolToken
919924
}

rust/src/types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,7 +1291,7 @@ impl ValueLocation {
12911291
}
12921292
}
12931293

1294-
pub(crate) fn into_rust_raw(value: &Self) -> BNValueLocation {
1294+
pub fn into_rust_raw(value: &Self) -> BNValueLocation {
12951295
let components: Box<[BNValueLocationComponent]> = value
12961296
.components
12971297
.iter()
@@ -1304,7 +1304,7 @@ impl ValueLocation {
13041304
}
13051305

13061306
/// Free a RUST ALLOCATED possible value set. Do not use this with CORE ALLOCATED values.
1307-
pub(crate) fn free_rust_raw(value: BNValueLocation) {
1307+
pub fn free_rust_raw(value: BNValueLocation) {
13081308
let raw_components =
13091309
unsafe { std::slice::from_raw_parts_mut(value.components, value.count) };
13101310
let _ = unsafe { Box::from_raw(raw_components) };

type.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,16 @@ BNValueLocationComponent ValueLocationComponent::ToAPIObject() const
591591
}
592592

593593

594+
std::string ValueLocationComponent::ToString(Architecture* arch) const
595+
{
596+
auto componentRaw = ToAPIObject();
597+
char* str = BNValueLocationComponentToString(&componentRaw, arch->GetObject());
598+
string result = str;
599+
BNFreeString(str);
600+
return result;
601+
}
602+
603+
594604
std::optional<Variable> ValueLocation::GetVariableForReturnValue() const
595605
{
596606
BNValueLocation loc = ToAPIObject();
@@ -680,6 +690,34 @@ void ValueLocation::FreeAPIObject(BNValueLocation* loc)
680690
}
681691

682692

693+
std::optional<ValueLocation> ValueLocation::Parse(const std::string& str, Architecture* arch, std::string& error)
694+
{
695+
BNValueLocation locationRaw;
696+
char* errorRaw;
697+
if (BNParseValueLocation(str.c_str(), arch->GetObject(), &locationRaw, &errorRaw))
698+
{
699+
auto location = FromAPIObject(&locationRaw);
700+
BNFreeValueLocation(&locationRaw);
701+
return location;
702+
}
703+
704+
error = errorRaw;
705+
BNFreeString(errorRaw);
706+
return std::nullopt;
707+
}
708+
709+
710+
std::string ValueLocation::ToString(Architecture* arch) const
711+
{
712+
auto locationRaw = ToAPIObject();
713+
char* str = BNValueLocationToString(&locationRaw, arch->GetObject());
714+
FreeAPIObject(&locationRaw);
715+
string result = str;
716+
BNFreeString(str);
717+
return result;
718+
}
719+
720+
683721
bool ReturnValue::operator==(const ReturnValue& nt) const
684722
{
685723
if (type != nt.type)

0 commit comments

Comments
 (0)