Skip to content

Commit 3f406b6

Browse files
committed
Add support to assign a register to a function parameter
1 parent 7f4fe59 commit 3f406b6

File tree

15 files changed

+282
-4
lines changed

15 files changed

+282
-4
lines changed

api/python/lief/dwarf/__init__.pyi

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,28 @@ class Function:
187187
def instructions(self) -> Iterator[Optional[lief.assembly.Instruction]]: ...
188188

189189
class Parameter:
190+
class Location:
191+
class Type(enum.Enum):
192+
UNKNOWN = 0
193+
194+
REGISTER = 1
195+
196+
@property
197+
def type(self) -> Parameter.Location.Type: ...
198+
199+
class RegisterLoc(Parameter.Location):
200+
@property
201+
def id(self) -> int: ...
202+
190203
@property
191204
def name(self) -> str: ...
192205

193206
@property
194207
def type(self) -> Optional[Type]: ...
195208

209+
@property
210+
def location(self) -> Optional[Parameter.Location]: ...
211+
196212
class CompilationUnit:
197213
class Language:
198214
class LANG(enum.Enum):

api/python/lief/dwarf/editor/__init__.pyi

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,11 @@ class Function:
7777
end: int
7878

7979
class Parameter:
80-
pass
80+
@overload
81+
def assign_register(self, arg: str, /) -> Function.Parameter: ...
82+
83+
@overload
84+
def assign_register(self, arg: int, /) -> Function.Parameter: ...
8185

8286
class LexicalBlock:
8387
pass

api/python/src/DWARF/editor/pyFunction.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,23 @@ void create<dw::editor::Function>(nb::module_& m) {
2323
.def_rw("start", &dw::editor::Function::range_t::start)
2424
.def_rw("end", &dw::editor::Function::range_t::end);
2525

26-
nb::class_<dw::editor::Function::Parameter> FP(F, "Parameter",
26+
using Parameter = dw::editor::Function::Parameter;
27+
nb::class_<Parameter> FP(F, "Parameter",
2728
R"doc(
2829
This class represents a parameter of the current function (``DW_TAG_formal_parameter``)
2930
)doc"_doc
3031
);
3132

33+
FP
34+
.def("assign_register", nb::overload_cast<const std::string&>(&Parameter::assign_register),
35+
"Assign this parameter to a specific named register."_doc,
36+
nb::rv_policy::reference_internal
37+
)
38+
.def("assign_register", nb::overload_cast<uint64_t>(&Parameter::assign_register),
39+
R"doc(Assign this parameter to the given DWARF register id (e.g. ``DW_OP_reg0``))doc"_doc,
40+
nb::rv_policy::reference_internal
41+
);
42+
3243
nb::class_<dw::editor::Function::LexicalBlock> FLB(F, "LexicalBlock",
3344
"This class mirrors the `DW_TAG_lexical_block` DWARF tag"_doc
3445
);

api/python/src/DWARF/pyParameter.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,20 @@
66
#include <nanobind/stl/unique_ptr.h>
77
#include <nanobind/stl/string.h>
88

9+
namespace nanobind::detail {
10+
template<> struct type_hook<LIEF::dwarf::Parameter::Location> {
11+
static const std::type_info* get(const LIEF::dwarf::Parameter::Location *src) {
12+
using Parameter = LIEF::dwarf::Parameter;
13+
if (src) {
14+
if (Parameter::RegisterLoc::classof(src)) {
15+
return &typeid(Parameter::RegisterLoc);
16+
}
17+
}
18+
return &typeid(Parameter::Location);
19+
}
20+
};
21+
}
22+
923
namespace LIEF::dwarf::py {
1024
template<>
1125
void create<dw::Parameter>(nb::module_& m) {
@@ -18,6 +32,28 @@ void create<dw::Parameter>(nb::module_& m) {
1832
)doc"_doc
1933
);
2034

35+
using Location = dw::Parameter::Location;
36+
using RegisterLoc = dw::Parameter::RegisterLoc;
37+
38+
nb::class_<Location> loc(param, "Location",
39+
R"doc(
40+
This class exposes information about the location of a parameter
41+
)doc"_doc);
42+
43+
nb::enum_<dw::Parameter::Location::Type>(loc, "Type")
44+
.value("UNKNOWN", Location::Type::UNKNOWN)
45+
.value("REGISTER", Location::Type::REG);
46+
47+
loc
48+
.def_ro("type", &Location::type);
49+
50+
nb::class_<RegisterLoc, Location>(param, "RegisterLoc",
51+
R"doc(
52+
This class represents a register location
53+
)doc"_doc)
54+
55+
.def_ro("id", &RegisterLoc::id, "DWARF id of the register"_doc);
56+
2157
param
2258
.def_prop_ro("name", &dw::Parameter::name,
2359
R"doc(
@@ -30,6 +66,13 @@ void create<dw::Parameter>(nb::module_& m) {
3066
Type of this parameter
3167
)doc"_doc
3268
)
69+
70+
.def_prop_ro("location", &dw::Parameter::location,
71+
R"doc(
72+
Location of this parameter. For instance it can be a specific register
73+
that is not following the calling convention.
74+
)doc"_doc
75+
)
3376
;
3477

3578
nb::module_ m_params = m.def_submodule("parameters");

api/rust/autocxx_ffi.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,10 @@ include_cpp! {
819819
block_constructors!("DWARF_Function")
820820
generate!("DWARF_Parameter")
821821
block_constructors!("DWARF_Parameter")
822+
generate!("DWARF_Parameter_Location")
823+
block_constructors!("DWARF_Parameter_Location")
824+
generate!("DWARF_Parameter_RegisterLocation")
825+
block_constructors!("DWARF_Parameter_RegisterLocation")
822826
generate!("DWARF_parameters_Formal")
823827
block_constructors!("DWARF_parameters_Formal")
824828
generate!("DWARF_parameters_TemplateValue")

api/rust/cargo/lief/src/dwarf/editor/function.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,24 @@ pub struct Range {
2626

2727

2828
/// This structure represents a parameter of the current function (`DW_TAG_formal_parameter`)
29-
#[allow(dead_code)]
3029
pub struct Parameter {
3130
ptr: cxx::UniquePtr<ffi::DWARF_editor_Function_Parameter>,
3231
}
3332

33+
impl Parameter {
34+
/// Assign this parameter to a specific named register.
35+
pub fn assign_register_by_name(&mut self, name: &str) -> &mut Self {
36+
self.ptr.pin_mut().assign_register_by_name(name);
37+
self
38+
}
39+
40+
/// Assign this parameter to the given DWARF register id (e.g. `DW_OP_reg0`).
41+
pub fn assign_register_by_id(&mut self, id: u64) -> &mut Self {
42+
self.ptr.pin_mut().assign_register_by_id(id);
43+
self
44+
}
45+
}
46+
3447
impl FromFFI<ffi::DWARF_editor_Function_Parameter> for Parameter {
3548
fn from_ffi(ptr: cxx::UniquePtr<ffi::DWARF_editor_Function_Parameter>) -> Self {
3649
Self {

api/rust/cargo/lief/src/dwarf/parameters.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ pub trait Parameter {
1919
fn get_type(&self) -> Option<Type> {
2020
into_optional(self.get_base().get_type())
2121
}
22+
23+
/// Location of this parameter. For instance it can be a specific register
24+
/// that is not following the calling convention.
25+
fn location(&self) -> Option<Location> {
26+
into_optional(self.get_base().location())
27+
}
2228
}
2329

2430
pub enum Parameters<'a> {
@@ -136,3 +142,50 @@ impl Parameter for TemplateType<'_> {
136142
self.ptr.as_ref().unwrap().as_ref()
137143
}
138144
}
145+
146+
/// Enum that represents the different type of locations for a parameters
147+
pub enum Location<'a> {
148+
/// Register location (e.g. `r8, x13`)
149+
Register(RegisterLocation<'a>)
150+
}
151+
152+
impl FromFFI<ffi::DWARF_Parameter_Location> for Location<'_> {
153+
fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::DWARF_Parameter_Location>) -> Self {
154+
unsafe {
155+
let loc_ref = ffi_entry.as_ref().unwrap();
156+
157+
if ffi::DWARF_Parameter_RegisterLocation::classof(loc_ref) {
158+
let raw = {
159+
type From = cxx::UniquePtr<ffi::DWARF_Parameter_Location>;
160+
type To = cxx::UniquePtr<ffi::DWARF_Parameter_RegisterLocation>;
161+
std::mem::transmute::<From, To>(ffi_entry)
162+
};
163+
Location::Register(RegisterLocation::from_ffi(raw))
164+
} else {
165+
panic!("Unknown Parameter");
166+
}
167+
}
168+
}
169+
}
170+
171+
/// Location as a register
172+
pub struct RegisterLocation<'a> {
173+
ptr: cxx::UniquePtr<ffi::DWARF_Parameter_RegisterLocation>,
174+
_owner: PhantomData<&'a ()>,
175+
}
176+
177+
impl FromFFI<ffi::DWARF_Parameter_RegisterLocation> for RegisterLocation<'_> {
178+
fn from_ffi(ptr: cxx::UniquePtr<ffi::DWARF_Parameter_RegisterLocation>) -> Self {
179+
Self {
180+
ptr,
181+
_owner: PhantomData,
182+
}
183+
}
184+
}
185+
186+
impl RegisterLocation<'_> {
187+
/// DWARF id of the register (e.g. `DW_OP_reg0`)
188+
pub fn id(&self) -> u64 {
189+
self.ptr.id()
190+
}
191+
}

api/rust/include/LIEF/rust/DWARF/Parameter.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,29 @@
1717
#include "LIEF/rust/Mirror.hpp"
1818
#include "LIEF/rust/DWARF/Type.hpp"
1919

20+
class DWARF_Parameter_Location : public Mirror<LIEF::dwarf::Parameter::Location> {
21+
public:
22+
using Mirror::Mirror;
23+
using lief_t = LIEF::dwarf::Parameter::Location;
24+
25+
auto get_type() const { return to_int(get().type); }
26+
};
27+
28+
class DWARF_Parameter_RegisterLocation : public Mirror<LIEF::dwarf::Parameter::RegisterLoc> {
29+
public:
30+
using Mirror::Mirror;
31+
using lief_t = LIEF::dwarf::Parameter::RegisterLoc;
32+
33+
auto id() const { return impl().id; }
34+
35+
static bool classof(const DWARF_Parameter_Location& loc) {
36+
return lief_t::classof(&loc.get());
37+
}
38+
39+
private:
40+
const lief_t& impl() const { return as<lief_t>(this); }
41+
};
42+
2043
class DWARF_Parameter : public Mirror<LIEF::dwarf::Parameter> {
2144
public:
2245
using Mirror::Mirror;
@@ -27,6 +50,10 @@ class DWARF_Parameter : public Mirror<LIEF::dwarf::Parameter> {
2750
auto get_type() const {
2851
return details::try_unique<DWARF_Type>(get().type()); // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
2952
}
53+
54+
auto location() const {
55+
return details::try_unique<DWARF_Parameter_Location>(get().location());
56+
}
3057
};
3158

3259
class DWARF_parameters_Formal : public DWARF_Parameter {

api/rust/include/LIEF/rust/DWARF/editor/Function.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ class DWARF_editor_Function_Parameter : public Mirror<LIEF::dwarf::editor::Funct
3030
public:
3131
using Mirror::Mirror;
3232
using lief_t = LIEF::dwarf::editor::Function::Parameter;
33+
34+
void assign_register_by_name(std::string name) {
35+
get().assign_register(name);
36+
}
37+
38+
void assign_register_by_id(uint64_t id) {
39+
get().assign_register(id);
40+
}
3341
};
3442

3543
class DWARF_editor_Function_LexicalBlock : public Mirror<LIEF::dwarf::editor::Function::LexicalBlock> {

doc/sphinx/changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
* Add :ref:`Android JNI Analyzer <plugins-binaryninja-analyzers-android-jni>`
1212

13+
:DWARF:
14+
15+
* Add support to read or assign a register to a function's parameter
16+
1317
0.17.0 - September 14th, 2025
1418
-----------------------------
1519

0 commit comments

Comments
 (0)