Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.3.0 #18

Merged
merged 21 commits into from
Nov 5, 2023
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
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.3.0] - 2023-11-05

### Added

- Support for parsing clang lld's map fles.
- New functions:
- `MapFile.parseMapContents`/`MapFile::parse_map_contents`
- Parses the map contents passed as the argument, without requiring the map
being on an actual file.
- The map format will be guessed on the contents. Currently both the GNU ld
and clang ld.lld map formats are recognized.
- `MapFile.parseMapContentsGNU`/`MapFile::parse_map_contents_gnu`
- Parses the map contents passed as the argument, without requiring the map
being on an actual file.
- This function only parses the GNU ld map format.
- `MapFile.parseMapContentsLLD`/`MapFile::parse_map_contents_lld`
- Parses the map contents passed as the argument, without requiring the map
being on an actual file.
- This function only parses the clang ld.lld map format.
- New members:
- `Symbol.align`/`Symbol::align`, `File.align`/`File::align` and
`Segment.align`/`Segment::align`: The alignment the given type. This member
will be filled by the parser only if the mapfile provides this information.

### Changed

- `MapFile.readMapFile`/`MapFile::read_map_file` can now guess the map format
between any of the known formats.
- Some known symbol names will be automatically filtered out during the parsing
step.
- Currently only `gcc2_compiled.` is filtered out.

### Fixed

- Fix parser not detecting `*fill*` lines on GNU ld maps if they specified the
value that was used for filling/padding.
- `.sbss`, `COMMON` and `.scommon` sections are now properly considered noload
sections.

## [2.2.1] - 2023-10-08

### Fixed
Expand Down Expand Up @@ -238,6 +277,7 @@ Full changes: <https://github.com/Decompollaborate/mapfile_parser/compare/702a73
- Initial release

[unreleased]: https://github.com/Decompollaborate/mapfile_parser/compare/master...develop
[2.3.0]: https://github.com/Decompollaborate/mapfile_parser/compare/2.2.1...2.3.0
[2.2.1]: https://github.com/Decompollaborate/mapfile_parser/compare/2.2.0...2.2.1
[2.2.0]: https://github.com/Decompollaborate/mapfile_parser/compare/2.1.5...2.2.0
[2.1.5]: https://github.com/Decompollaborate/mapfile_parser/compare/2.1.4...2.1.5
Expand Down
10 changes: 8 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[package]
name = "mapfile_parser"
version = "2.2.1"
version = "2.3.0"
edition = "2021"
authors = ["Anghelo Carvajal <[email protected]>"]
description = "Map file parser library focusing decompilation projects"
Expand All @@ -23,4 +23,10 @@ crate-type = ["cdylib", "staticlib", "rlib"]

[dependencies]
regex = "1.9.5"
pyo3 = "0.19.0"
# pyo3 = { version = "0.19.0", optional = true }
pyo3 = { version = "0.19.0", optional = false }
lazy_static = "1.4.0"

[features]
python_bindings = []
# python_bindings = ["dep:pyo3"]
33 changes: 30 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ Map file parser library focusing decompilation projects.

This library is available for Python3 and Rust

## Features

- Fast parsing written in Rust.
- Support map formats:
- GNU ld
- clang lld
- Built-in cli utilities to process the parsed map file (see [Examples](#examples)).

## Installing

### Python version
Expand All @@ -27,7 +35,7 @@ If you use a `requirements.txt` file in your repository, then you can add
this library with the following line:

```txt
mapfile_parser>=2.2.0,<3.0.0
mapfile_parser>=2.3.0,<3.0.0
```

#### Development version
Expand Down Expand Up @@ -57,9 +65,28 @@ you are doing. Proceed at your own risk.

See this crate at <https://crates.io/crates/mapfile_parser>.

To add this library to your project using Cargo:

```bash
cargo add mapfile_parser
```

Or add the following line manually to your `Cargo.toml` file:

```toml
[build]
mapfile_parser = "2.2.0"
mapfile_parser = "2.3.0"
```

#### System-wide dependencies

Due to how intrusive `pyo3` is (and even impossible to disable via Cargo
features), Python development files are required to build and use the Rust
version of this library

To install those dependencies on a Debian/Ubuntu Linux distro:

```bash
sudo apt install libpython3-dev
```

## Versioning and changelog
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[project]
name = "mapfile_parser"
version = "2.2.1"
version = "2.3.0"
description = "Map file parser library focusing decompilation projects"
readme = "README.md"
requires-python = ">=3.7"
Expand All @@ -28,6 +28,6 @@ build-backend = "maturin"
skip = ["cp36-*"]

[tool.maturin]
features = ["pyo3/extension-module"]
features = ["pyo3/extension-module", "python_bindings"]
# https://github.com/PyO3/maturin/blob/0dee40510083c03607834c821eea76964140a126/Readme.md#mixed-rustpython-projects
python-source = "src"
2 changes: 1 addition & 1 deletion src/mapfile_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from __future__ import annotations

__version_info__ = (2, 2, 1)
__version_info__ = (2, 3, 0)
__version__ = ".".join(map(str, __version_info__))
__author__ = "Decompollaborate"

Expand Down
75 changes: 66 additions & 9 deletions src/mapfile_parser/mapfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .progress_stats import ProgressStats
from . import utils

from .mapfile_rs import MapFile as MapFileRs

regex_fileDataEntry = re.compile(r"^\s+(?P<section>\.[^\s]+)\s+(?P<vram>0x[^\s]+)\s+(?P<size>0x[^\s]+)\s+(?P<name>[^\s]+)$")
regex_functionEntry = re.compile(r"^\s+(?P<vram>0x[^\s]+)\s+(?P<name>[^\s]+)$")
Expand Down Expand Up @@ -64,6 +65,7 @@ class Symbol:
vram: int
size: int|None = None # in bytes
vrom: int|None = None
align: int|None = None

def getVramStr(self) -> str:
return f"0x{self.vram:08X}"
Expand Down Expand Up @@ -140,6 +142,7 @@ class File:
size: int # in bytes
sectionType: str
vrom: int|None = None
align: int|None = None
_symbols: list[Symbol] = dataclasses.field(default_factory=list)

@property
Expand Down Expand Up @@ -307,6 +310,7 @@ class Segment:
vram: int
size: int
vrom: int
align: int|None = None
_filesList: list[File] = dataclasses.field(default_factory=list)

def serializeVram(self, humanReadable: bool=True) -> str|int|None:
Expand Down Expand Up @@ -478,23 +482,76 @@ def __init__(self):
#! @deprecated
self.debugging: bool = False

def readMapFile(self, mapPath: Path):
from .mapfile_rs import MapFile

nativeMapFile = MapFile()
nativeMapFile.readMapFile(mapPath)

def _transferContentsFromNativeMapFile(self, nativeMapFile: MapFileRs):
for segment in nativeMapFile:
newSegment = Segment(segment.name, segment.vram, segment.size, segment.vrom)
newSegment = Segment(segment.name, segment.vram, segment.size, segment.vrom, segment.align)
for file in segment:
newFile = File(file.filepath, file.vram, file.size, file.sectionType, file.vrom)
newFile = File(file.filepath, file.vram, file.size, file.sectionType, file.vrom, file.align)
for symbol in file:
newSymbol = Symbol(symbol.name, symbol.vram, symbol.size, symbol.vrom)
newSymbol = Symbol(symbol.name, symbol.vram, symbol.size, symbol.vrom, symbol.align)

newFile._symbols.append(newSymbol)
newSegment._filesList.append(newFile)
self._segmentsList.append(newSegment)

def readMapFile(self, mapPath: Path):
"""
Opens the mapfile pointed by the `mapPath` argument and parses it.

The format of the map will be guessed based on its contents.

Currently supported map formats:
- GNU ld
- clang ld.lld
"""

nativeMapFile = MapFileRs()
nativeMapFile.readMapFile(mapPath)

self._transferContentsFromNativeMapFile(nativeMapFile)

def parseMapContents(self, mapContents: str):
"""
Parses the contents of the map.

The `mapContents` argument must contain the contents of a mapfile.

The format of the map will be guessed based on its contents.

Currently supported mapfile formats:
- GNU ld
- clang ld.lld
"""

nativeMapFile = MapFileRs()
nativeMapFile.parseMapContents(mapContents)

self._transferContentsFromNativeMapFile(nativeMapFile)

def parseMapContentsGNU(self, mapContents: str):
"""
Parses the contents of a GNU ld map.

The `mapContents` argument must contain the contents of a GNU ld mapfile.
"""

nativeMapFile = MapFileRs()
nativeMapFile.parseMapContentsGNU(mapContents)

self._transferContentsFromNativeMapFile(nativeMapFile)

def parseMapContentsLLD(self, mapContents: str):
"""
Parses the contents of a clang ld.lld map.

The `mapContents` argument must contain the contents of a clang ld.lld mapfile.
"""

nativeMapFile = MapFileRs()
nativeMapFile.parseMapContentsLLD(mapContents)

self._transferContentsFromNativeMapFile(nativeMapFile)


def filterBySectionType(self, sectionType: str) -> MapFile:
newMapFile = MapFile()
Expand Down
12 changes: 9 additions & 3 deletions src/mapfile_parser/mapfile_parser.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ class Symbol:
vram: int
size: int|None # in bytes
vrom: int|None
align: int|None

def __init__(self, name: str, vram: int, size: int|None=None, vrom: int|None=None): ...
def __init__(self, name: str, vram: int, size: int|None=None, vrom: int|None=None, align: int|None=None): ...

def getVramStr(self) -> str: ...
def getSizeStr(self) -> str: ...
Expand Down Expand Up @@ -92,9 +93,10 @@ class File:
size: int # in bytes
sectionType: str
vrom: int|None
align: int|None
# _symbols: list[Symbol]

def __init__(self, filepath: Path, vram: int, size: int, section_type: str, vrom: int|None=None) -> None: ...
def __init__(self, filepath: Path, vram: int, size: int, section_type: str, vrom: int|None=None, align: int|None=None) -> None: ...

@property
def filepath(self) -> Path: ...
Expand Down Expand Up @@ -147,9 +149,10 @@ class Segment:
vram: int
size: int
vrom: int
align: int|None
# _filesList: list[File] = dataclasses.field(default_factory=list)

def __init__(self, name: str, vram: int, size: int, vrom: int): ...
def __init__(self, name: str, vram: int, size: int, vrom: int, align: int|None=None): ...

def serializeVram(self, humanReadable: bool=True) -> str|int|None: ...
def serializeSize(self, humanReadable: bool=True) -> str|int|None: ...
Expand Down Expand Up @@ -192,6 +195,9 @@ class MapFile:
def __init__(self) -> None: ...

def readMapFile(self, mapPath: Path) -> None: ...
def parseMapContents(self, mapContents: str) -> None: ...
def parseMapContentsGNU(self, mapContents: str) -> None: ...
def parseMapContentsLLD(self, mapContents: str) -> None: ...

def filterBySectionType(self, sectionType: str) -> MapFile: ...
def getEveryFileExceptSectionType(self, sectionType: str) -> MapFile: ...
Expand Down
Loading
Loading