Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ repos:
args: ["--line-length=132"]

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.22
rev: v0.16.0
hooks:
- id: ruff
args: ["--fix", "--exit-non-zero-on-fix"]
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def get_version():
import re
from pathlib import Path

VERSION = re.compile(r'version\s*=\s*"(?P<version>\d+\.\d+(\.\d+)?)\s*"', re.M)
VERSION = re.compile(r'version\s*=\s*"(?P<version>\d+\.\d+(\.\d+)?)\s*"', re.MULTILINE)

try:
cfg = Path(r"../pyproject.toml")
Expand Down
18 changes: 9 additions & 9 deletions objutils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@

__all__ = [
"Image",
"Section",
"LazySection",
"InvalidAddressError",
"registry",
"load",
"loads",
"LazySection",
"Section",
"dump",
"dumps",
"load",
"loads",
"probe",
"probes",
"registry",
]

__copyright__ = """
Expand Down Expand Up @@ -76,9 +76,9 @@
import objutils.srec
import objutils.tek
import objutils.titxt
from objutils.image import Image, InvalidAddressError # noqa: F401
from objutils.image import Image, InvalidAddressError
from objutils.registry import registry
from objutils.section import Section, LazySection # noqa: F401
from objutils.section import Section, LazySection

# Optional developer-friendly console and tracebacks; disabled by default for library consumers.
_ENABLE_RICH = os.getenv("OBJUTILS_RICH", "0").lower() in {"1", "true", "yes"}
Expand Down Expand Up @@ -158,7 +158,7 @@ def loads(codec_name: str, data: str | bytes | bytearray, join: bool = True, **k
return registry.get(codec_name).Reader().loads(data, join=join, **kws)


def probe(fp: BinaryIO, **kws: Any) -> Optional[str]:
def probe(fp: BinaryIO, **kws: Any) -> str | None:
"""Try to guess codec from file.

Returns
Expand Down Expand Up @@ -195,7 +195,7 @@ def probe(fp: BinaryIO, **kws: Any) -> Optional[str]:
return None


def probes(data: str | bytes | bytearray, **kws: Any) -> Optional[str]:
def probes(data: str | bytes | bytearray, **kws: Any) -> str | None:
"""Try to guess codec from bytes.

Returns
Expand Down
2 changes: 1 addition & 1 deletion objutils/ash.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from functools import partial
from typing import Any

import objutils.hexfile as hexfile
from objutils import hexfile
from objutils.checksums import lrc

STX = "\x02"
Expand Down
12 changes: 6 additions & 6 deletions objutils/binfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
import io
import zipfile
from contextlib import closing
from typing import Any, BinaryIO, Union
from typing import Any, BinaryIO

import objutils.hexfile as hexfile
from objutils import hexfile
from objutils.image import Image
from objutils.section import Section

Expand All @@ -42,7 +42,7 @@ class NoContiniousError(Exception):


class Reader(hexfile.Reader):
def load(self, fp: Union[str, BinaryIO], address: int = 0x0000, **kws: Any) -> Image:
def load(self, fp: str | BinaryIO, address: int = 0x0000, **kws: Any) -> Image:
if isinstance(fp, str):
fp = open(fp, "rb")
data = fp.read()
Expand All @@ -52,7 +52,7 @@ def load(self, fp: Union[str, BinaryIO], address: int = 0x0000, **kws: Any) -> I
fp.close()
return img

def loads(self, image: Union[str, bytes, bytearray], address: int = 0x0000, **kws: Any) -> Image:
def loads(self, image: str | bytes | bytearray, address: int = 0x0000, **kws: Any) -> Image:
if isinstance(image, str):
return self.load(io.BytesIO(bytes(image, "ascii")), address)
else:
Expand Down Expand Up @@ -112,12 +112,12 @@ def probe(self, fp: BinaryIO, **kws: Any) -> bool:
except (AttributeError, io.UnsupportedOperation):
pass

def load(self, fp: Union[str, BinaryIO], **kws: Any) -> Image:
def load(self, fp: str | BinaryIO, **kws: Any) -> Image:
"""Load from zip file."""
# TODO: Implementation
return Image([], valid=True)

def loads(self, data: Union[str, bytes, bytearray], **kws: Any) -> Image:
def loads(self, data: str | bytes | bytearray, **kws: Any) -> Image:
"""Load from zip bytes."""
return self.load(io.BytesIO(data) if isinstance(data, (bytes, bytearray)) else io.BytesIO(data.encode()))

Expand Down
4 changes: 2 additions & 2 deletions objutils/cosmac.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
from collections.abc import Sequence
from typing import Any

import objutils.hexfile as hexfile
from objutils import hexfile

# Record type identifiers
DATA0 = 1 # !MAAAA DD
Expand Down Expand Up @@ -80,7 +80,7 @@ def check_line(self, line: Any, format_type: int) -> None:
Cosmac format has no checksums, validation is minimal.
"""
# Cosmac has no checksums - nothing to validate
return None
return

def probe(self, fp: Any, **kws: Any) -> bool:
"""Check if file matches RCA Cosmac format.
Expand Down
5 changes: 1 addition & 4 deletions objutils/dwarf/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python
# ruff: noqa: E402
# Imports come after module docstring

"""DWARF 4 debug information parser and processor.
Expand Down Expand Up @@ -266,7 +265,7 @@ class Attribute:

encoding: constants.AttributeEncoding
form: constants.AttributeForm
special_value: Optional[Any] = None
special_value: Any | None = None

def __iter__(self):
yield self.encoding
Expand Down Expand Up @@ -300,7 +299,6 @@ class Readers:
Used internally by DwarfReaders to organize parsers.
"""

pass


@dataclass
Expand Down Expand Up @@ -531,7 +529,6 @@ def _fetch(self, abbr_offset, item):
)
continue
if attr.attrValue != 0 and attr.formValue != 0:
#
try:
self.abbrevations[key].attrs.append(
Attribute(
Expand Down
2 changes: 1 addition & 1 deletion objutils/dwarf/attrparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ def _type_summary(self, offset: int) -> str:
tag = t.get("tag", "<type>")
name = ""
attrs = t.get("attrs", {}) if isinstance(t.get("attrs"), dict) else {}
if "name" in attrs and attrs["name"]:
if attrs.get("name"):
try:
name = str(attrs["name"])
except (UnicodeDecodeError, ValueError, TypeError):
Expand Down
14 changes: 6 additions & 8 deletions objutils/dwarf/encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,11 @@ class Endianess(IntEnum):
class ULEBError(ConstructError):
"""Raised when ULEB128 parsing or building encounters an error."""

pass


class SLEBError(ConstructError):
"""Raised when SLEB128 parsing or building encounters an error."""

pass


@singleton
Expand All @@ -96,7 +94,7 @@ class ULEB(Construct):
"""

def __init__(self, *args) -> None:
super(__class__, self).__init__()
super().__init__()

def _parse(self, stream, context, path: str | None = None) -> int:
"""Parse a ULEB128-encoded value from stream.
Expand Down Expand Up @@ -171,7 +169,7 @@ class SLEB(Construct):
"""

def __init__(self, *args) -> None:
super(__class__, self).__init__()
super().__init__()

def _parse(self, stream, context, path: str | None = None) -> int:
"""Parse a SLEB128-encoded value from stream.
Expand Down Expand Up @@ -235,7 +233,7 @@ class One(Construct):
"""

def __init__(self, *args) -> None:
super(__class__, self).__init__()
super().__init__()

def _parse(self, stream, context, path: str | None = None) -> int:
"""Parse returns constant 1."""
Expand Down Expand Up @@ -266,7 +264,7 @@ class Block(Construct):
MASK: str | None = None

def __init__(self, *args) -> None:
super(__class__, self).__init__()
super().__init__()

def _parse(self, stream, context, path: str | None = None) -> bytes:
"""Parse block data with fixed-size length prefix.
Expand Down Expand Up @@ -410,7 +408,7 @@ def __init__(self, size: int, endianess: Endianess) -> None:
Raises:
ValueError: If size not in (1, 2, 4, 8).
"""
super(__class__, self).__init__()
super().__init__()
idx = 0 if endianess == Endianess.Little else 1
if size not in (1, 2, 4, 8):
raise ValueError(f"Address size '{size}' not supported.")
Expand Down Expand Up @@ -473,7 +471,7 @@ def __init__(self, image: bytes, endianess: Endianess) -> None:
self.endianess = endianess
self.ntype = (Int32ul, Int32ub)[0 if endianess == Endianess.Little else 1]
self.stype = CString(encoding="utf8")
super(__class__, self).__init__()
super().__init__()

def _parse(self, stream, context, path: str | None = None) -> str:
"""Parse string pointer and resolve to actual string.
Expand Down
1 change: 0 additions & 1 deletion objutils/dwarf/readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ class Readers:
strp, line_strp: String pointer readers.
"""

pass


class DwarfReaders:
Expand Down
2 changes: 0 additions & 2 deletions objutils/dwarf/sm.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python
# ruff: noqa: E402
# Imports come after module docstring (standard Python practice)

__copyright__ = """
Expand Down Expand Up @@ -370,7 +369,6 @@ def stack_op(self, stack):
Default implementation does nothing (no-op).
Operations that modify the stack must override this.
"""
pass

def __str__(self):
"""Return textual representation of operation with parameters.
Expand Down
34 changes: 17 additions & 17 deletions objutils/dwarf/traverser.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
from dataclasses import dataclass, field
from functools import lru_cache
from itertools import groupby
from typing import Any, Optional, Union
from typing import Any

from objutils import Image, Section, symbols
from objutils.dwarf.constants import (
Expand Down Expand Up @@ -174,7 +174,7 @@
"""


def is_type_encoding(encoding: Union[int, AttributeEncoding]) -> bool:
def is_type_encoding(encoding: int | AttributeEncoding) -> bool:
"""Check if a DWARF tag represents a type definition.

Args:
Expand Down Expand Up @@ -359,11 +359,11 @@ class Variable:
"""

name: str
section: Optional[str] = field(default=None)
elf_location: Optional[int] = field(default=None)
dwarf_location: Optional[str] = field(default=None)
section: str | None = field(default=None)
elf_location: int | None = field(default=None)
dwarf_location: str | None = field(default=None)
static: bool = field(default=False)
type_desc: Optional[DIE] = field(default=None)
type_desc: DIE | None = field(default=None)
_allocated: bool = field(default=False, repr=False)


Expand Down Expand Up @@ -400,7 +400,7 @@ class Variable:
# 'data_member_location': b'#\x00',


def get_attribute(attrs: dict[str, DIEAttribute], key: str, default: Union[int, str]) -> Union[int, str]:
def get_attribute(attrs: dict[str, DIEAttribute], key: str, default: int | str) -> int | str:
"""Get attribute value from attributes_map with fallback default.

Args:
Expand All @@ -417,7 +417,7 @@ def get_attribute(attrs: dict[str, DIEAttribute], key: str, default: Union[int,
size = get_attribute(die.attributes_map, "byte_size", 0)
```
"""
attr: Optional[DIEAttribute] = attrs.get(key)
attr: DIEAttribute | None = attrs.get(key)
if attr is None:
return default
else:
Expand Down Expand Up @@ -760,7 +760,7 @@ def _safe_expression(self, attr):
return f"<expr-error:{exc}>"

@lru_cache(maxsize=64 * 1024)
def type_tree(self, obj: Union[int, model.DebugInformationEntry, DIEAttribute]) -> dict[str, Any] | CircularReference:
def type_tree(self, obj: int | model.DebugInformationEntry | DIEAttribute) -> dict[str, Any] | CircularReference:
"""Resolve and return complete type tree for a DIE, offset, or attribute.

This method accepts multiple input types for convenience:
Expand Down Expand Up @@ -810,7 +810,7 @@ def type_tree(self, obj: Union[int, model.DebugInformationEntry, DIEAttribute])
# Case 2: attribute object (expected to be DW_AT_type)
if isinstance(obj, DIEAttribute):
# Try to resolve relative ref forms to absolute offset using the parent DIE if available
parent: Optional[model.DebugInformationEntry] = getattr(obj, "entry", None)
parent: model.DebugInformationEntry | None = getattr(obj, "entry", None)
off = self._resolve_type_offset(obj, parent)
if off is None:
return {"tag": "<invalid>", "attrs": {}}
Expand Down Expand Up @@ -879,7 +879,7 @@ def variable(self, obj: model.DebugInformationEntry) -> Variable:
_allocated=section_name in self.allocated_sections,
)

def get_value(self, var: Variable) -> Optional[Any]:
def get_value(self, var: Variable) -> Any | None:
"""Extract variable value from ELF section image.

This method resolves the variable's address and extracts its value based
Expand Down Expand Up @@ -926,7 +926,7 @@ def get_value(self, var: Variable) -> Optional[Any]:
# No image for variable, i.e. .bss section and the like.
return None
# 1) Resolve address
addr: Optional[int] = None
addr: int | None = None
if isinstance(var.elf_location, int):
addr = var.elf_location
elif var.dwarf_location is not None:
Expand All @@ -948,7 +948,7 @@ def get_value(self, var: Variable) -> Optional[Any]:
return None

# 2a) Helpers to work with both dict-based and DIE-based nodes
def _get_tag(node: Any) -> Optional[str]:
def _get_tag(node: Any) -> str | None:
if node is None:
return None
if isinstance(node, dict):
Expand Down Expand Up @@ -1010,7 +1010,7 @@ def _unwrap_qualifiers_until_array(node: Any) -> Any:
return cur

# 2d) Unwrap qualifiers all the way down to base_type
def unwrap_to_base(d: Optional[DIE | dict | CircularReference]) -> Optional[DIE]:
def unwrap_to_base(d: DIE | dict | CircularReference | None) -> DIE | None:
# Accept DIE or dict-like from older structures
seen = 0
current = d
Expand Down Expand Up @@ -1101,7 +1101,7 @@ def _reshape(flat: list[Any], dims: list[int]) -> list[Any]:
out.append(_reshape(chunk, dims[1:]))
return out

def _element_size(elem: Any) -> Optional[int]:
def _element_size(elem: Any) -> int | None:
t = _get_tag(elem)
attrs = _get_attrs(elem)
if t in {"base_type", "pointer_type"}:
Expand Down Expand Up @@ -1249,8 +1249,8 @@ def _element_size(elem: Any) -> Optional[int]:
def _resolve_type_offset(
self,
type_attr: DIEAttribute,
context_die: Optional[model.DebugInformationEntry],
) -> Optional[int]:
context_die: model.DebugInformationEntry | None,
) -> int | None:
"""Resolve DW_AT_type attribute value to absolute DIE offset.

Handles CU-relative reference forms (DW_FORM_ref1/2/4/8/udata) by adding
Expand Down
Loading
Loading