HAL  v4.5.0-124-g47ab54673
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
python_bindings.cpp
Go to the documentation of this file.
1 // MIT License
2 //
3 // Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved.
4 // Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved.
5 // Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved.
6 // Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved.
7 // Copyright (c) 2025-2026 Sascha Tommasone. All rights reserved.
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in all
17 // copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 // SOFTWARE.
26 
28 
31 #include "pybind11/pybind11.h"
32 
33 #include <igraph/igraph.h>
34 #include <pybind11/detail/descr.h>
35 #include <pybind11/pytypes.h>
36 #include <set>
37 #include <string>
38 #include <vector>
39 
40 namespace hal
41 {
42  class BasePluginInterface;
43 }
44 namespace hal
45 {
46  class Netlist;
47 }
48 
49 namespace py = pybind11;
50 
51 namespace hal
52 {
53 
54  // the name in PYBIND11_MODULE/PYBIND11_PLUGIN *MUST* match the filename of the output library (without extension),
55  // otherwise you will get "ImportError: dynamic module does not define module export function" when importing the
56  // module
57 
58 #ifdef PYBIND11_MODULE
59  PYBIND11_MODULE( clock_tree_extractor, m )
60  {
61  m.doc() = "";
62 #else
63  PYBIND11_PLUGIN( clock_tree_extractor )
64  {
65  py::module m( "clock_tree_extractor", "" );
66 #endif // ifdef PYBIND11_MODULE
67 
68  py::class_<ClockTreeExtractorPlugin, RawPtrWrapper<ClockTreeExtractorPlugin>, BasePluginInterface>
69  py_clock_tree_extractor_plugin( m, "ClockTreeExtractorPlugin", "" );
70 
71  py_clock_tree_extractor_plugin.def_property_readonly( "name", &ClockTreeExtractorPlugin::get_name, R"(
72  The name of the plugin.
73 
74  :type: str
75  )" );
76 
77  py_clock_tree_extractor_plugin.def( "get_name", &ClockTreeExtractorPlugin::get_name, R"(
78  Get the name of the plugin.
79 
80  :returns: The name of the plugin.
81  :rtype: str
82  )" );
83 
84  py_clock_tree_extractor_plugin.def_property_readonly( "version", &ClockTreeExtractorPlugin::get_version, R"(
85  The version of the plugin.
86 
87  :type: str
88  )" );
89 
90  py_clock_tree_extractor_plugin.def( "get_version", &ClockTreeExtractorPlugin::get_version, R"(
91  Get the version of the plugin.
92 
93  :returns: The version of the plugin.
94  :rtype: str
95  )" );
96 
97  py_clock_tree_extractor_plugin.def_property_readonly(
99  The description of the plugin.
100 
101  :type: str
102  )" );
103 
104  py_clock_tree_extractor_plugin.def( "get_description", &ClockTreeExtractorPlugin::get_description, R"(
105  Get the description of the plugin.
106 
107  :returns: The description of the plugin.
108  :rtype: str
109  )" );
110 
111  py_clock_tree_extractor_plugin.def_property_readonly(
112  "dependencies", &ClockTreeExtractorPlugin::get_dependencies, R"(
113  A set of plugin names that this plugin depends on.
114 
115  :type: set[str]
116  )" );
117 
118  py_clock_tree_extractor_plugin.def( "get_dependencies", &ClockTreeExtractorPlugin::get_dependencies, R"(
119  Get a set of plugin names that this plugin depends on.
120 
121  :returns: A set of plugin names that this plugin depends on.
122  :rtype: set[str]
123  )" );
124 
125  py::class_<cte::ClockTree>( m, "ClockTree", R"()" )
126  .def_static(
127  "from_netlist",
128  []( const Netlist *netlist ) -> std::unique_ptr<cte::ClockTree> {
129  auto result = cte::ClockTree::from_netlist( netlist );
130  if( result.is_ok() )
131  {
132  return result.get();
133  }
134 
135  log_error( "clock_tree_extractor", "{}", result.get_error().get() );
136  return nullptr;
137  },
138  py::arg( "netlist" ),
139  py::return_value_policy::move,
140  R"()" )
141  .def(
142  "export",
143  []( const cte::ClockTree &self, const std::string &pathname ) -> bool {
144  auto result = self.export_dot( pathname );
145  if( result.is_ok() )
146  {
147  return true;
148  }
149 
150  log_error( "clock_tree_extractor", "{}", result.get_error().get() );
151  return false;
152  },
153  py::arg( "pathname" ),
154  R"()" )
155  .def(
156  "get_subtree",
157  []( const cte::ClockTree &self,
158  const void *ptr,
159  const bool parent ) -> std::unique_ptr<cte::ClockTree> {
160  auto result = self.get_subtree( ptr, parent );
161  if( result.is_ok() )
162  {
163  return result.get();
164  }
165 
166  log_error( "clock_tree_extractor", "{}", result.get_error().get() );
167  return nullptr;
168  },
169  py::arg( "ptr" ),
170  py::arg( "parent" ) = false,
171  py::return_value_policy::move,
172  R"()" )
173  .def(
174  "get_all",
175  []( const cte::ClockTree &self ) -> py::list {
176  py::list result;
177  const auto &map = self.get_all();
178  for( auto &[ptr, type] : map )
179  {
180  if( type == cte::PtrType::GATE )
181  {
182  result.append( py::cast( (const Gate *) ptr ) );
183  }
184  else if( type == cte::PtrType::NET )
185  {
186  result.append( py::cast( (const Net *) ptr ) );
187  }
188  }
189  return result;
190  },
191  borrowed(),
192  R"()" )
193  .def(
194  "get_vertex_from_ptr",
195  []( const cte::ClockTree &self, const void *ptr ) -> py::object {
196  auto result = self.get_vertex_from_ptr( ptr );
197  if( result.is_ok() )
198  {
199  return py::int_( result.get() );
200  }
201  log_error( "clock_tree_extractor", "{}", result.get_error().get() );
202  return py::none();
203  },
204  py::arg( "ptr" ),
205  R"()" )
206  .def(
207  "get_ptr_from_vertex",
208  []( const cte::ClockTree &self, const igraph_integer_t vertex ) -> py::object {
209  auto result = self.get_ptr_from_vertex( vertex );
210  if( result.is_ok() )
211  {
212  auto [ptr, type] = result.get();
213  if( type == cte::PtrType::GATE )
214  {
215  return py::cast( (const Gate *) ptr );
216  }
217  else if( type == cte::PtrType::NET )
218  {
219  return py::cast( (const Net *) ptr );
220  }
221  return py::none();
222  }
223  log_error( "clock_tree_extractor", "{}", result.get_error().get() );
224  return py::none();
225  },
226  py::arg( "vertex" ),
227  borrowed(),
228  R"()" )
229  .def(
230  "get_vertices_from_ptrs",
231  []( const cte::ClockTree &self, const std::vector<const void *> &ptrs ) -> py::list {
232  auto result = self.get_vertices_from_ptrs( ptrs );
233  if( result.is_ok() )
234  {
235  return py::cast( result.get() );
236  }
237  log_error( "clock_tree_extractor", "{}", result.get_error().get() );
238  return py::none();
239  },
240  py::arg( "ptrs" ),
241  R"()" )
242  .def(
243  "get_ptrs_from_vertices",
244  []( const cte::ClockTree &self, const std::vector<igraph_integer_t> &vertices ) -> py::list {
245  auto res = self.get_ptrs_from_vertices( vertices );
246  if( res.is_ok() )
247  {
248  py::list result;
249  for( const auto &[ptr, type] : res.get() )
250  {
251  if( type == cte::PtrType::GATE )
252  {
253  result.append( py::cast( (const Gate *) ptr ) );
254  }
255  else if( type == cte::PtrType::NET )
256  {
257  result.append( py::cast( (const Net *) ptr ) );
258  }
259  else
260  {
261  log_error( "clock_tree_extractor", "unknown ptr type" );
262  return py::none();
263  }
264  }
265  return result;
266  }
267  log_error( "clock_tree_extractor", "{}", res.get_error().get() );
268  return py::none();
269  },
270  py::arg( "vertices" ),
271  R"()" )
272  .def(
273  "get_parents",
274  []( const cte::ClockTree &self, const void *ptr ) -> py::list {
275  auto res = self.get_neighbors( ptr, IGRAPH_IN );
276  if( res.is_ok() )
277  {
278  py::list result;
279  for( const auto &[ptr, type] : res.get() )
280  {
281  if( type == cte::PtrType::GATE )
282  {
283  result.append( py::cast( (const Gate *) ptr ) );
284  }
285  else if( type == cte::PtrType::NET )
286  {
287  result.append( py::cast( (const Net *) ptr ) );
288  }
289  else
290  {
291  log_error( "clock_tree_extractor", "unknown ptr type" );
292  return py::none();
293  }
294  }
295  return result;
296  }
297  log_error( "clock_tree_extractor", "{}", res.get_error().get() );
298  return py::none();
299  },
300  py::arg( "ptr" ),
301  borrowed(),
302  R"()" )
303  .def(
304  "get_childs",
305  []( const cte::ClockTree &self, const void *ptr ) -> py::list {
306  auto res = self.get_neighbors( ptr, IGRAPH_OUT );
307  if( res.is_ok() )
308  {
309  py::list result;
310  for( const auto &[ptr, type] : res.get() )
311  {
312  if( type == cte::PtrType::GATE )
313  {
314  result.append( py::cast( (const Gate *) ptr ) );
315  }
316  else if( type == cte::PtrType::NET )
317  {
318  result.append( py::cast( (const Net *) ptr ) );
319  }
320  else
321  {
322  log_error( "clock_tree_extractor", "unknown ptr type" );
323  return py::none();
324  }
325  }
326  return result;
327  }
328  log_error( "clock_tree_extractor", "{}", res.get_error().get() );
329  return py::none();
330  },
331  py::arg( "ptr" ),
332  borrowed(),
333  R"()" )
334  .def( "get_gates", &cte::ClockTree::get_gates, borrowed(), R"()" )
335  .def( "get_nets", &cte::ClockTree::get_nets, borrowed(), R"()" )
336  .def( "get_netlist", &cte::ClockTree::get_netlist, borrowed(), R"()" );
337 
338 #ifndef PYBIND11_MODULE
339  return m.ptr();
340 #endif // PYBIND11_MODULE
341  }
342 } // namespace hal
std::string get_description() const override
std::string get_name() const override
std::set< std::string > get_dependencies() const override
std::string get_version() const override
Definition: gate.h:58
Definition: net.h:58
const Netlist * get_netlist() const
Definition: clock_tree.cpp:792
const std::vector< const Gate * > get_gates() const
Definition: clock_tree.cpp:757
const std::vector< const Net * > get_nets() const
Definition: clock_tree.cpp:772
static Result< std::unique_ptr< ClockTree > > from_netlist(const Netlist *netlist)
Definition: clock_tree.cpp:160
#define log_error(channel,...)
Definition: log.h:78
const Module * module(const Gate *g, const NodeBoxes &boxes)
Definition: defines.h:45
PYBIND11_PLUGIN(hal_py)
PinType type