Skip to content

feat(pe): add parse_imports option to ParseOptions#522

Merged
m4b merged 1 commit into
m4b:masterfrom
supervacuus:feat/add_parse_imports_pe_option
May 25, 2026
Merged

feat(pe): add parse_imports option to ParseOptions#522
m4b merged 1 commit into
m4b:masterfrom
supervacuus:feat/add_parse_imports_pe_option

Conversation

@supervacuus

@supervacuus supervacuus commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

Parsing PE import tables is expensive: for each DLL, the parser does a full pass over the import lookup table (resolving every symbol RVA via a linear scan over sections), a second pass over the import address table, and then a third reshaping pass in Import::parse. For binaries with large or malformed import tables, this adds up fast, especially when the caller only needs headers, debug info, or exports.

This PR adds a parse_imports flag to ParseOptions (default: true) with a with_parse_imports builder method, allowing callers to skip import table parsing entirely. When set to false, import_data, imports, and libraries remain empty while everything else is parsed as usual.

This is a follow-up to #506 (#508).

@supervacuus

Copy link
Copy Markdown
Contributor Author

Just wanted to ping if this kind of change is of interest.

I have also now added a new PR (#527) that fixes the underlying issue. It might still make sense to be able to turn off import parsing, but if #527 is accepted, I could understand if you didn't want to add another parser option. The resulting runtimes are now essentially the same for either PR.

@m4b

m4b commented Apr 20, 2026

Copy link
Copy Markdown
Owner

I'm ok with this i think, @kkent030315 is this something you think is fine?

@kkent030315 kkent030315 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

Comment thread src/pe/mod.rs Outdated
Comment on lines +197 to +198
if opts.parse_imports {
if let Some(&import_table) = optional_header.data_directories.get_import_table() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we merge it to one?

Suggested change
if opts.parse_imports {
if let Some(&import_table) = optional_header.data_directories.get_import_table() {
if opts.parse_imports && let Some(&import_table) = optional_header.data_directories.get_import_table()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rust is pinned at 1.85 in CI which complains about the let chain.

Otherwise fixed in: 9f632ae

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use

if let (true, Some(&import_table)) = (                                                                                                                              
    opts.parse_imports,                                                                                                                                             
    optional_header.data_directories.get_import_table(),                                                                                                            
) {                                                                                                                                                                 

}

if you prefer it to if-nesting. However, that means get_import_table() will be called unconditionally (which is not a costly invocation, but a change in behavior nonetheless).

Changed here: db951f2

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the approach in db951f2 sufficient?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so

@m4b

m4b commented May 25, 2026

Copy link
Copy Markdown
Owner

I'm sorry @supervacuus there's a merge conflict with another pr that touched options, would you mind to rebase? I'll merge it asap as I want to cut a release tonight or tomorrow at latest. If don't hear I'll manually resolve it in editor though I'd prefer not

@supervacuus supervacuus force-pushed the feat/add_parse_imports_pe_option branch from db951f2 to b6d0a11 Compare May 25, 2026 07:32
@supervacuus supervacuus force-pushed the feat/add_parse_imports_pe_option branch from b6d0a11 to 0efa02f Compare May 25, 2026 07:33
@supervacuus

Copy link
Copy Markdown
Contributor Author

I'm sorry @supervacuus there's a merge conflict with another pr that touched options, would you mind to rebase? I'll merge it asap as I want to cut a release tonight or tomorrow at latest. If don't hear I'll manually resolve it in editor though I'd prefer not

I rebased and squashed my commits in 0efa02f.

@m4b m4b left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you!

@m4b m4b merged commit 95fb19d into m4b:master May 25, 2026
5 checks passed
@m4b

m4b commented May 25, 2026

Copy link
Copy Markdown
Owner

NB: backwards compatible

@m4b

m4b commented May 25, 2026

Copy link
Copy Markdown
Owner

released in 0.10.6

@supervacuus supervacuus deleted the feat/add_parse_imports_pe_option branch May 26, 2026 06:44
supervacuus added a commit to getsentry/symbolic that referenced this pull request May 26, 2026
…964)

This is a follow-up to #960 and depends on an upstream change in
`goblin` that has not yet been accepted
(m4b/goblin#522).

It makes the integration of PE+DWARF debug companions into the DIF
pipeline practical (see
getsentry/sentry-cli#3240)

---------

Co-authored-by: David Herberth <[email protected]>
szokeasaurusrex pushed a commit to getsentry/sentry-cli that referenced this pull request Jun 2, 2026
### Description

Extracted from #3237

Some tests currently fail, because `symbolic` updated its `zip`
dependency (`2.4.2` to `7.2.0`) since the last bump. This changed the
encoding and invalidated a bunch of test assertions. A fix proposal for
the failing tests is #3239.

This change was triggered by bumping `symbolic` to `12.17.3` to include
getsentry/symbolic#960.

The new permissive PE parser fixes in
getsentry/symbolic#960 exposed performance edge
cases for some of the debug companions during PE import-table parsing,
the result of which neither `symbolic` nor `sentry-cli` really needs.

The PR addresses the issue in the following way:

I introduced a new `goblin` option that excludes the `PE` import table
from parsing. Of course, this requires further upstream PRs (`cargo`
points `goblin` and `symbolic` to dev branches) before we can merge
this, but I wanted to check whether you are generally in agreement with
these changes before going upstream.

Upstream changes required:

- m4b/goblin#522
- getsentry/symbolic#964


Ideally, this PR gets merged after
#3238 and
#3239, because both solve
issues this PR is affected by. If we drop or defer
#3239, we need to update all
snapshots and magic digests here first.

### Issues

At least partially fixes
getsentry/sentry#104738

### Legal Boilerplate
Look, I get it. The entity doing business as "Sentry" was incorporated
in the State of Delaware in 2015 as Functional Software, Inc. and is
gonna need some rights from me in order to utilize my contributions in
this here PR. So here's the deal: I retain all rights, title and
interest in and to my contributions, and by keeping this boilerplate
intact I confirm that Sentry can use, modify, copy, and redistribute my
contributions, under Sentry's choice of terms.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants