objutils 0.10.5__tar.gz → 0.10.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. {objutils-0.10.5 → objutils-0.10.7}/PKG-INFO +4 -4
  2. {objutils-0.10.5 → objutils-0.10.7}/objutils/__init__.py +1 -1
  3. {objutils-0.10.5 → objutils-0.10.7}/objutils/dwarf/readers.py +3 -3
  4. {objutils-0.10.5 → objutils-0.10.7}/objutils/dwarf/sm.py +155 -89
  5. {objutils-0.10.5 → objutils-0.10.7}/objutils/dwarf/traverser.py +134 -1
  6. {objutils-0.10.5 → objutils-0.10.7}/objutils/elf/defs.py +76 -2
  7. {objutils-0.10.5 → objutils-0.10.7}/objutils/pecoff/__init__.py +0 -12
  8. {objutils-0.10.5 → objutils-0.10.7}/objutils/pecoff/pdb/__init__.py +1446 -1056
  9. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_coff_syms.py +5 -3
  10. objutils-0.10.7/objutils/symbols.py +442 -0
  11. objutils-0.10.7/objutils/tests/test_sm.py +61 -0
  12. {objutils-0.10.5 → objutils-0.10.7}/objutils/version.py +1 -1
  13. {objutils-0.10.5 → objutils-0.10.7}/pyproject.toml +6 -6
  14. objutils-0.10.5/objutils/dwarf/.traverser.py.un~ +0 -0
  15. objutils-0.10.5/objutils/tests/test_sm.py +0 -19
  16. {objutils-0.10.5 → objutils-0.10.7}/CMakeLists.txt +0 -0
  17. {objutils-0.10.5 → objutils-0.10.7}/LICENSE +0 -0
  18. {objutils-0.10.5 → objutils-0.10.7}/build_ext.py +0 -0
  19. {objutils-0.10.5 → objutils-0.10.7}/docs/README.rst +0 -0
  20. {objutils-0.10.5 → objutils-0.10.7}/objutils/.coveragerc +0 -0
  21. {objutils-0.10.5 → objutils-0.10.7}/objutils/.vscode/launch.json +0 -0
  22. {objutils-0.10.5 → objutils-0.10.7}/objutils/.vscode/settings.json +0 -0
  23. {objutils-0.10.5 → objutils-0.10.7}/objutils/a2l_test.shf +0 -0
  24. {objutils-0.10.5 → objutils-0.10.7}/objutils/ash.py +0 -0
  25. {objutils-0.10.5 → objutils-0.10.7}/objutils/binfile.py +0 -0
  26. {objutils-0.10.5 → objutils-0.10.7}/objutils/checksums.py +0 -0
  27. {objutils-0.10.5 → objutils-0.10.7}/objutils/cosmac.py +0 -0
  28. {objutils-0.10.5 → objutils-0.10.7}/objutils/dwarf/__init__.py +0 -0
  29. {objutils-0.10.5 → objutils-0.10.7}/objutils/dwarf/attrparser.py +0 -0
  30. {objutils-0.10.5 → objutils-0.10.7}/objutils/dwarf/c_generator.py +0 -0
  31. {objutils-0.10.5 → objutils-0.10.7}/objutils/dwarf/constants.py +0 -0
  32. {objutils-0.10.5 → objutils-0.10.7}/objutils/dwarf/encoding.py +0 -0
  33. {objutils-0.10.5 → objutils-0.10.7}/objutils/dwarf/lineprog.py +0 -0
  34. {objutils-0.10.5 → objutils-0.10.7}/objutils/elf/__init__.py +0 -0
  35. {objutils-0.10.5 → objutils-0.10.7}/objutils/elf/arm/__init__.py +0 -0
  36. {objutils-0.10.5 → objutils-0.10.7}/objutils/elf/arm/attributes.py +0 -0
  37. {objutils-0.10.5 → objutils-0.10.7}/objutils/elf/model.py +0 -0
  38. {objutils-0.10.5 → objutils-0.10.7}/objutils/emon52.py +0 -0
  39. {objutils-0.10.5 → objutils-0.10.7}/objutils/etek.py +0 -0
  40. {objutils-0.10.5 → objutils-0.10.7}/objutils/exceptions.py +0 -0
  41. {objutils-0.10.5 → objutils-0.10.7}/objutils/extensions/__init__.py +0 -0
  42. {objutils-0.10.5 → objutils-0.10.7}/objutils/extensions/ctre.hpp +0 -0
  43. {objutils-0.10.5 → objutils-0.10.7}/objutils/extensions/difflib.h +0 -0
  44. {objutils-0.10.5 → objutils-0.10.7}/objutils/extensions/exceptions.cpp +0 -0
  45. {objutils-0.10.5 → objutils-0.10.7}/objutils/extensions/exceptions.hpp +0 -0
  46. {objutils-0.10.5 → objutils-0.10.7}/objutils/extensions/hexfile.cpp +0 -0
  47. {objutils-0.10.5 → objutils-0.10.7}/objutils/extensions/wrapper.cpp +0 -0
  48. {objutils-0.10.5 → objutils-0.10.7}/objutils/fpc.py +0 -0
  49. {objutils-0.10.5 → objutils-0.10.7}/objutils/hexdump.py +0 -0
  50. {objutils-0.10.5 → objutils-0.10.7}/objutils/hexfile.py +0 -0
  51. {objutils-0.10.5 → objutils-0.10.7}/objutils/ieee695.py +0 -0
  52. {objutils-0.10.5 → objutils-0.10.7}/objutils/ihex.py +0 -0
  53. {objutils-0.10.5 → objutils-0.10.7}/objutils/image.py +0 -0
  54. {objutils-0.10.5 → objutils-0.10.7}/objutils/logger.py +0 -0
  55. {objutils-0.10.5 → objutils-0.10.7}/objutils/mostec.py +0 -0
  56. {objutils-0.10.5 → objutils-0.10.7}/objutils/objutils.code-workspace +0 -0
  57. {objutils-0.10.5 → objutils-0.10.7}/objutils/pecoff/defs.py +0 -0
  58. {objutils-0.10.5 → objutils-0.10.7}/objutils/pecoff/model.py +0 -0
  59. {objutils-0.10.5 → objutils-0.10.7}/objutils/pickleif.py +0 -0
  60. {objutils-0.10.5 → objutils-0.10.7}/objutils/rca.py +0 -0
  61. {objutils-0.10.5 → objutils-0.10.7}/objutils/readers.py +0 -0
  62. {objutils-0.10.5 → objutils-0.10.7}/objutils/registry.py +0 -0
  63. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/arduino_build_artifacts.py +0 -0
  64. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_cgen.py +0 -0
  65. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_coff_extract.py +0 -0
  66. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_coff_import.py +0 -0
  67. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_coff_info.py +0 -0
  68. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_dwarf_import.py +0 -0
  69. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_dwarf_info.py +0 -0
  70. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_elf_arm_attrs.py +0 -0
  71. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_elf_extract.py +0 -0
  72. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_elf_import.py +0 -0
  73. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_elf_info.py +0 -0
  74. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_elf_syms.py +0 -0
  75. {objutils-0.10.5 → objutils-0.10.7}/objutils/scripts/oj_hex_info.py +0 -0
  76. {objutils-0.10.5 → objutils-0.10.7}/objutils/section.py +0 -0
  77. {objutils-0.10.5 → objutils-0.10.7}/objutils/shf.py +0 -0
  78. {objutils-0.10.5 → objutils-0.10.7}/objutils/sig.py +0 -0
  79. {objutils-0.10.5 → objutils-0.10.7}/objutils/srec.py +0 -0
  80. {objutils-0.10.5 → objutils-0.10.7}/objutils/tek.py +0 -0
  81. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/__init__.py +0 -0
  82. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_arm_attributes.py +0 -0
  83. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_ash.py +0 -0
  84. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_c_generator.py +0 -0
  85. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_checksums.py +0 -0
  86. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_cygpath.py +0 -0
  87. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_diff_bin.py +0 -0
  88. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_elf.py +0 -0
  89. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_emon52.py +0 -0
  90. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_etek.py +0 -0
  91. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_examples_cgen.py +0 -0
  92. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_fpc.py +0 -0
  93. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_hexdump.py +0 -0
  94. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_hexfile.py +0 -0
  95. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_ihex.py +0 -0
  96. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_image.py +0 -0
  97. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_mostec.py +0 -0
  98. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_readers.py +0 -0
  99. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_registry.py +0 -0
  100. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_repr.py +0 -0
  101. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_section.py +0 -0
  102. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_section_join.py +0 -0
  103. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_shf.py +0 -0
  104. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_srec.py +0 -0
  105. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_tek.py +0 -0
  106. {objutils-0.10.5 → objutils-0.10.7}/objutils/tests/test_titext.py +0 -0
  107. {objutils-0.10.5 → objutils-0.10.7}/objutils/titxt.py +0 -0
  108. {objutils-0.10.5 → objutils-0.10.7}/objutils/utils/__init__.py +0 -0
  109. {objutils-0.10.5 → objutils-0.10.7}/objutils/utils/arduino.py +0 -0
  110. {objutils-0.10.5 → objutils-0.10.7}/objutils/utils/diff.py +0 -0
@@ -1,29 +1,29 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: objutils
3
- Version: 0.10.5
3
+ Version: 0.10.7
4
4
  Summary: Objectfile library for Python
5
5
  License: GPLv2
6
6
  License-File: LICENSE
7
7
  Keywords: hex files,intel hex,s19,srec,srecords,object files,map files,embedded,microcontroller,ECU,shf,rfc4194
8
8
  Author: Christoph Schueler
9
9
  Author-email: cpu12.gems@googlemail.com
10
- Requires-Python: >=3.9,<4.0
10
+ Requires-Python: >=3.10,<4.0
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
14
14
  Classifier: License :: Other/Proprietary License
15
15
  Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.9
17
16
  Classifier: Programming Language :: Python :: 3.10
18
17
  Classifier: Programming Language :: Python :: 3.11
19
18
  Classifier: Programming Language :: Python :: 3.12
20
19
  Classifier: Programming Language :: Python :: 3.13
21
20
  Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: 3.9
22
22
  Classifier: Topic :: Scientific/Engineering
23
23
  Classifier: Topic :: Software Development
24
24
  Requires-Dist: construct (>=2.10.70,<3.0.0)
25
25
  Requires-Dist: mako (>=1.3.3,<2.0.0)
26
- Requires-Dist: numpy (<=2.2.5)
26
+ Requires-Dist: numpy (>=2.2.5)
27
27
  Requires-Dist: rich (>=14.2,<15.0)
28
28
  Requires-Dist: sqlalchemy (>=2.0.29,<3.0.0)
29
29
  Project-URL: Homepage, https://github.com/christoph2/objutils
@@ -13,7 +13,7 @@ Registers CODECS and implements an interface to them.
13
13
  The first parameter is always the codec name.
14
14
  """
15
15
 
16
- __version__ = "0.10.5"
16
+ __version__ = "0.10.7"
17
17
 
18
18
  __all__ = [
19
19
  "Image",
@@ -174,7 +174,7 @@ class DwarfReaders:
174
174
  constants.AttributeForm.DW_FORM_block2,
175
175
  constants.AttributeForm.DW_FORM_block4,
176
176
  ):
177
- return self.stack_machine.evaluate(expr)
177
+ return self.stack_machine.evaluate(expr).value.value
178
178
  elif form in (
179
179
  constants.AttributeForm.DW_FORM_data1,
180
180
  constants.AttributeForm.DW_FORM_data2,
@@ -182,13 +182,13 @@ class DwarfReaders:
182
182
  constants.AttributeForm.DW_FORM_data8,
183
183
  constants.AttributeForm.DW_FORM_data16,
184
184
  ):
185
- return f"0x{int(expr):08x}"
185
+ return int(expr)
186
186
  elif form == constants.AttributeForm.DW_FORM_udata:
187
187
  return ULEB.parse(expr)
188
188
  elif form == constants.AttributeForm.DW_FORM_sdata:
189
189
  return SLEB.parse(expr)
190
190
  elif form in (constants.AttributeForm.DW_FORM_sec_offset, constants.AttributeForm.DW_FORM_loclistx):
191
- return f"0x{int(expr):08x}"
191
+ return int(expr)
192
192
  else:
193
193
  print("Unsupported DWARF expression form:", form, list(expr))
194
194
  raise NotImplementedError(f"Unsupported DWARF expression form: {form}")
@@ -140,58 +140,60 @@ from construct import Array
140
140
  from objutils.dwarf import constants
141
141
 
142
142
 
143
+ @dataclass
144
+ class TypedValue:
145
+ """Represents a value on the DWARF stack with an associated type.
146
+
147
+ Attributes:
148
+ value: The actual numeric or address value.
149
+ type_offset: Offset of the DW_TAG_base_type in .debug_info,
150
+ or 0 for the generic type.
151
+ """
152
+
153
+ value: Any
154
+ type_offset: int = 0 # 0 means generic type
155
+
156
+ def __int__(self):
157
+ return int(self.value)
158
+
159
+
143
160
  class Stack:
144
161
  """Simple LIFO stack for DWARF expression evaluation.
145
162
 
146
163
  Provides basic stack operations for the DWARF stack machine.
147
- Stores arbitrary Python values (integers, addresses, etc.).
148
-
149
- Attributes:
150
- _values: Internal list storing stack contents (private)
151
-
152
- Example:
153
- ```python
154
- stack = Stack()
155
- stack.push(42)
156
- stack.push(10)
157
- result = stack.pop() # 10
158
- top = stack.tos # 42
159
- stack.tos = 100 # Modify top without pop/push
160
- ```
164
+ Stores TypedValue instances.
161
165
  """
162
166
 
163
167
  def __init__(self):
164
168
  """Initialize empty stack."""
165
- self._values: list[Any] = []
169
+ self._values: list[TypedValue] = []
166
170
 
167
- def push(self, value: Any) -> None:
171
+ def push(self, value: Any, type_offset: int = 0) -> None:
168
172
  """Push value onto stack.
169
173
 
170
174
  Args:
171
- value: Value to push (typically int or address)
175
+ value: Value to push (typically int or address) or TypedValue
176
+ type_offset: Offset of the base type (0 for generic)
172
177
  """
173
- self._values.append(value)
178
+ if isinstance(value, TypedValue):
179
+ self._values.append(value)
180
+ else:
181
+ self._values.append(TypedValue(value, type_offset))
174
182
 
175
- def pop(self) -> Any:
183
+ def pop(self) -> TypedValue:
176
184
  """Pop and return top value from stack.
177
185
 
178
186
  Returns:
179
- Top stack value
180
-
181
- Raises:
182
- IndexError: If stack is empty
187
+ Top stack TypedValue
183
188
  """
184
189
  return self._values.pop()
185
190
 
186
191
  @property
187
- def tos(self) -> Any:
192
+ def tos(self) -> TypedValue:
188
193
  """Get top-of-stack value without popping.
189
194
 
190
195
  Returns:
191
- Top stack value
192
-
193
- Raises:
194
- IndexError: If stack is empty
196
+ Top stack TypedValue
195
197
  """
196
198
  return self._values[-1]
197
199
 
@@ -200,36 +202,22 @@ class Stack:
200
202
  """Set top-of-stack value without popping.
201
203
 
202
204
  Args:
203
- value: New value for top of stack
204
-
205
- Raises:
206
- IndexError: If stack is empty
205
+ value: New value or TypedValue for top of stack
207
206
  """
208
- self._values[-1] = value
207
+ if isinstance(value, TypedValue):
208
+ self._values[-1] = value
209
+ else:
210
+ current_type = self._values[-1].type_offset
211
+ self._values[-1] = TypedValue(value, current_type)
209
212
 
210
- def get_at(self, index: int) -> Any:
213
+ def get_at(self, index: int) -> TypedValue:
211
214
  """Get value at index from top of stack.
212
215
 
213
216
  Args:
214
217
  index: Index from top (0 = top, 1 = second, etc.)
215
218
 
216
219
  Returns:
217
- Value at specified index
218
-
219
- Raises:
220
- IndexError: If index out of range
221
-
222
- Example:
223
- >>> stack = Stack()
224
- >>> stack.push(10) # bottom
225
- >>> stack.push(20)
226
- >>> stack.push(30) # top
227
- >>> stack.get_at(0) # 30 (top)
228
- 30
229
- >>> stack.get_at(1) # 20
230
- 20
231
- >>> stack.get_at(2) # 10
232
- 10
220
+ TypedValue at specified index
233
221
  """
234
222
  return self._values[-(index + 1)]
235
223
 
@@ -246,20 +234,6 @@ class Stack:
246
234
  return f"Stack({self._values!r})"
247
235
 
248
236
 
249
- @dataclass
250
- class EvaluationResult:
251
- """Result of DWARF expression evaluation.
252
-
253
- Placeholder for future expansion. Could contain:
254
- - Final stack state
255
- - Expression interpretation
256
- - Error information
257
- - Location type (memory, register, etc.)
258
- """
259
-
260
- pass
261
-
262
-
263
237
  ######################
264
238
  ## Operation Classes ##
265
239
  ######################
@@ -736,7 +710,7 @@ class Abs(OperationBase):
736
710
 
737
711
  def stack_op(self, stack):
738
712
  a = stack.pop()
739
- stack.push(abs(a))
713
+ stack.push(abs(a.value), a.type_offset)
740
714
 
741
715
 
742
716
  class And_(OperationBase):
@@ -750,7 +724,7 @@ class And_(OperationBase):
750
724
  def stack_op(self, stack):
751
725
  b = stack.pop()
752
726
  a = stack.pop()
753
- stack.push(a & b)
727
+ stack.push(a.value & b.value, a.type_offset)
754
728
 
755
729
 
756
730
  class Div(OperationBase):
@@ -764,7 +738,7 @@ class Div(OperationBase):
764
738
  def stack_op(self, stack):
765
739
  b = stack.pop()
766
740
  a = stack.pop()
767
- stack.push(a // b)
741
+ stack.push(a.value // b.value, a.type_offset)
768
742
 
769
743
 
770
744
  class Minus(OperationBase):
@@ -778,7 +752,7 @@ class Minus(OperationBase):
778
752
  def stack_op(self, stack):
779
753
  b = stack.pop()
780
754
  a = stack.pop()
781
- stack.push(a - b)
755
+ stack.push(a.value - b.value, a.type_offset)
782
756
 
783
757
 
784
758
  class Mod(OperationBase):
@@ -792,7 +766,7 @@ class Mod(OperationBase):
792
766
  def stack_op(self, stack):
793
767
  b = stack.pop()
794
768
  a = stack.pop()
795
- stack.push(a % b)
769
+ stack.push(a.value % b.value, a.type_offset)
796
770
 
797
771
 
798
772
  class Mul(OperationBase):
@@ -806,7 +780,7 @@ class Mul(OperationBase):
806
780
  def stack_op(self, stack):
807
781
  b = stack.pop()
808
782
  a = stack.pop()
809
- stack.push(a * b)
783
+ stack.push(a.value * b.value, a.type_offset)
810
784
 
811
785
 
812
786
  class Neg(OperationBase):
@@ -819,7 +793,7 @@ class Neg(OperationBase):
819
793
 
820
794
  def stack_op(self, stack):
821
795
  a = stack.pop()
822
- stack.push(-a)
796
+ stack.push(-a.value, a.type_offset)
823
797
 
824
798
 
825
799
  class Not_(OperationBase):
@@ -832,7 +806,7 @@ class Not_(OperationBase):
832
806
 
833
807
  def stack_op(self, stack):
834
808
  a = stack.pop()
835
- stack.push(~a)
809
+ stack.push(~a.value, a.type_offset)
836
810
 
837
811
 
838
812
  class Or_(OperationBase):
@@ -846,7 +820,7 @@ class Or_(OperationBase):
846
820
  def stack_op(self, stack):
847
821
  b = stack.pop()
848
822
  a = stack.pop()
849
- stack.push(a | b)
823
+ stack.push(a.value | b.value, a.type_offset)
850
824
 
851
825
 
852
826
  class Plus(OperationBase):
@@ -860,7 +834,7 @@ class Plus(OperationBase):
860
834
  def stack_op(self, stack):
861
835
  b = stack.pop()
862
836
  a = stack.pop()
863
- stack.push(a + b)
837
+ stack.push(a.value + b.value, a.type_offset)
864
838
 
865
839
 
866
840
  class Plus_Uconst(OperationBase):
@@ -879,9 +853,18 @@ class Plus_Uconst(OperationBase):
879
853
  PARAMETERS = ["uleb"]
880
854
 
881
855
  def stack_op(self, stack):
882
- a = stack.pop()
856
+ try:
857
+ a = stack.pop()
858
+ val = a.value
859
+ type_offset = a.type_offset
860
+ except IndexError:
861
+ # Note: many location expressions (like for member offsets)
862
+ # assume a base address is already on the stack.
863
+ # If the stack is empty, we treat the base as 0.
864
+ val = 0
865
+ type_offset = 0
883
866
  constant = self.result[0]
884
- stack.push(a + constant)
867
+ stack.push(val + constant, type_offset)
885
868
 
886
869
 
887
870
  class Shl(OperationBase):
@@ -893,9 +876,9 @@ class Shl(OperationBase):
893
876
  DISPLAY_NAME = "shl"
894
877
 
895
878
  def stack_op(self, stack):
896
- shift = stack.pop()
879
+ shift = stack.pop().value
897
880
  value = stack.pop()
898
- stack.push(value << shift)
881
+ stack.push(value.value << shift, value.type_offset)
899
882
 
900
883
 
901
884
  class Shr(OperationBase):
@@ -907,9 +890,9 @@ class Shr(OperationBase):
907
890
  DISPLAY_NAME = "shr"
908
891
 
909
892
  def stack_op(self, stack):
910
- shift = stack.pop()
893
+ shift = stack.pop().value
911
894
  value = stack.pop()
912
- stack.push(value >> shift)
895
+ stack.push(value.value >> shift, value.type_offset)
913
896
 
914
897
 
915
898
  class Shra(OperationBase):
@@ -921,10 +904,10 @@ class Shra(OperationBase):
921
904
  DISPLAY_NAME = "shra"
922
905
 
923
906
  def stack_op(self, stack):
924
- shift = stack.pop()
907
+ shift = stack.pop().value
925
908
  value = stack.pop()
926
909
  # Python's >> is arithmetic for negative numbers
927
- stack.push(value >> shift)
910
+ stack.push(value.value >> shift, value.type_offset)
928
911
 
929
912
 
930
913
  class Xor(OperationBase):
@@ -938,7 +921,7 @@ class Xor(OperationBase):
938
921
  def stack_op(self, stack):
939
922
  b = stack.pop()
940
923
  a = stack.pop()
941
- stack.push(a ^ b)
924
+ stack.push(a.value ^ b.value, a.type_offset)
942
925
 
943
926
 
944
927
  #############################
@@ -1908,6 +1891,11 @@ class Addrx(OperationBase):
1908
1891
  DISPLAY_NAME = "addrx"
1909
1892
  PARAMETERS = ["uleb"]
1910
1893
 
1894
+ def stack_op(self, stack):
1895
+ index = self.result[0]
1896
+ # In a real implementation, we would look up the address in .debug_addr
1897
+ stack.push(0)
1898
+
1911
1899
 
1912
1900
  class Constx(OperationBase):
1913
1901
  """DW_OP_constx: Push constant from .debug_addr. Stack Effect: [] -> [constant]"""
@@ -1915,6 +1903,11 @@ class Constx(OperationBase):
1915
1903
  DISPLAY_NAME = "constx"
1916
1904
  PARAMETERS = ["uleb"]
1917
1905
 
1906
+ def stack_op(self, stack):
1907
+ index = self.result[0]
1908
+ # In a real implementation, we would look up the constant in .debug_addr
1909
+ stack.push(0)
1910
+
1918
1911
 
1919
1912
  class Entry_Value(OperationBase):
1920
1913
  """DW_OP_entry_value: Value at function entry. Stack Effect: varies"""
@@ -1929,6 +1922,21 @@ class Const_Type(OperationBase):
1929
1922
  DISPLAY_NAME = "const_type"
1930
1923
  PARAMETERS = ["uleb", "u8"]
1931
1924
 
1925
+ def parse(self, image):
1926
+ super().parse(image)
1927
+ size = self.result[1]
1928
+ self.data_block = image.read(size)
1929
+
1930
+ def stack_op(self, stack):
1931
+ type_offset = self.result[0]
1932
+ # For simplicity, we interpret the data block as an integer
1933
+ # In a real implementation, we would use the type information
1934
+ value = int.from_bytes(self.data_block, byteorder="little") # Assuming little-endian for now
1935
+ stack.push(value, type_offset)
1936
+
1937
+ def __str__(self):
1938
+ return f"{self.DISPLAY_NAME}(type_offset={self.result[0]}, size={self.result[1]}, value=0x{self.data_block.hex()})"
1939
+
1932
1940
 
1933
1941
  class Regval_Type(OperationBase):
1934
1942
  """DW_OP_regval_type: Typed register value. Stack Effect: [] -> [value]"""
@@ -1936,6 +1944,13 @@ class Regval_Type(OperationBase):
1936
1944
  DISPLAY_NAME = "regval_type"
1937
1945
  PARAMETERS = ["uleb", "uleb"]
1938
1946
 
1947
+ def stack_op(self, stack):
1948
+ reg_num = self.result[0]
1949
+ type_offset = self.result[1]
1950
+ # In a real implementation, we would fetch the register value here
1951
+ # For now, we push a placeholder
1952
+ stack.push(0, type_offset)
1953
+
1939
1954
 
1940
1955
  class Deref_Type(OperationBase):
1941
1956
  """DW_OP_deref_type: Typed dereference. Stack Effect: [address] -> [typed_value]"""
@@ -1943,6 +1958,13 @@ class Deref_Type(OperationBase):
1943
1958
  DISPLAY_NAME = "deref_type"
1944
1959
  PARAMETERS = ["u8", "uleb"]
1945
1960
 
1961
+ def stack_op(self, stack):
1962
+ addr = stack.pop().value
1963
+ # size = self.result[0]
1964
+ type_offset = self.result[1]
1965
+ # In a real implementation, we would read from memory here
1966
+ stack.push(0, type_offset)
1967
+
1946
1968
 
1947
1969
  class Xderef_Type(OperationBase):
1948
1970
  """DW_OP_xderef_type: Typed extended dereference. Stack Effect: [addr_space, address] -> [typed_value]"""
@@ -1950,6 +1972,14 @@ class Xderef_Type(OperationBase):
1950
1972
  DISPLAY_NAME = "xderef_type"
1951
1973
  PARAMETERS = ["u8", "uleb"]
1952
1974
 
1975
+ def stack_op(self, stack):
1976
+ addr = stack.pop().value
1977
+ # addr_space = stack.pop().value
1978
+ # size = self.result[0]
1979
+ type_offset = self.result[1]
1980
+ # In a real implementation, we would read from memory here
1981
+ stack.push(0, type_offset)
1982
+
1953
1983
 
1954
1984
  class Convert(OperationBase):
1955
1985
  """DW_OP_convert: Convert value to different type. Stack Effect: [value] -> [converted_value]"""
@@ -1957,6 +1987,11 @@ class Convert(OperationBase):
1957
1987
  DISPLAY_NAME = "convert"
1958
1988
  PARAMETERS = ["uleb"]
1959
1989
 
1990
+ def stack_op(self, stack):
1991
+ val = stack.pop()
1992
+ new_type = self.result[0]
1993
+ stack.push(val.value, new_type)
1994
+
1960
1995
 
1961
1996
  class Reinterpret(OperationBase):
1962
1997
  """DW_OP_reinterpret: Reinterpret value as different type. Stack Effect: [value] -> [reinterpreted_value]"""
@@ -1964,6 +1999,11 @@ class Reinterpret(OperationBase):
1964
1999
  DISPLAY_NAME = "reinterpret"
1965
2000
  PARAMETERS = ["uleb"]
1966
2001
 
2002
+ def stack_op(self, stack):
2003
+ val = stack.pop()
2004
+ new_type = self.result[0]
2005
+ stack.push(val.value, new_type)
2006
+
1967
2007
 
1968
2008
  ##################################
1969
2009
  ## Vendor-Specific Extensions ##
@@ -2301,11 +2341,28 @@ OP_MAP = {
2301
2341
  constants.Operation.PGI_omp_thread_num: Gi_Omp_Thread_Num,
2302
2342
  }
2303
2343
 
2344
+
2304
2345
  ######################
2305
2346
  ######################
2306
2347
  ######################
2307
2348
 
2308
2349
 
2350
+ @dataclass(frozen=True)
2351
+ class EvaluationResult:
2352
+ """Result of DWARF expression evaluation.
2353
+
2354
+ Future expansion could contain:
2355
+ - Final stack state
2356
+ - Expression interpretation
2357
+ - Error information
2358
+ - Location type (memory, register, etc.)
2359
+
2360
+ """
2361
+
2362
+ value: TypedValue
2363
+ representation: str
2364
+
2365
+
2309
2366
  class StackMachine:
2310
2367
  """DWARF expression stack machine evaluator.
2311
2368
 
@@ -2365,14 +2422,23 @@ class StackMachine:
2365
2422
  try:
2366
2423
  opcode = OPs(opcode_num)
2367
2424
  except ValueError:
2368
- print(f"Opcode not found {opcode_num!r}")
2369
- opcode_name = "<unk>"
2370
- else:
2371
- opcode_name = opcode.name # noqa: F841
2425
+ # print(f"Opcode not found {opcode_num!r}")
2426
+ result.append(f"<unk>({opcode_num:#x})")
2427
+ continue
2428
+
2372
2429
  op_klass = OP_MAP.get(opcode_num)
2373
2430
  if op_klass:
2374
2431
  operation = op_klass()
2375
2432
  operation.parse(image)
2376
2433
  result.append(str(operation))
2377
- operation.stack_op(self.stack)
2378
- return "; ".join(result)
2434
+ try:
2435
+ operation.stack_op(self.stack)
2436
+ except (IndexError, AttributeError):
2437
+ # Some operations might fail if context is missing
2438
+ pass
2439
+ else:
2440
+ result.append(f"{opcode.name}()")
2441
+
2442
+ # Return summary of executed ops
2443
+ res_val = self.stack.pop() if not self.stack.empty() else None
2444
+ return EvaluationResult(value=res_val, representation="; ".join(result))