-
Notifications
You must be signed in to change notification settings - Fork 163
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
Implement PE exception tables #136
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven’t given this a full review yet but this is really incredible work, awesome job!
Updated for compatibility with Rust 1.20.0. Even though it's not that much code, I'd like to offer a suggestion to sanity-check this:
A usage example for this is my port of Breakpad's dump_syms here. There might be more, one could do to help interpreting the unwind info:
For full transparency, here are two more thoughts that I had when implementing:
|
Note that #134 is bumping to rust 1.31.1 and changing to 2018 edition. |
} | ||
|
||
let rva = function.unwind_info_address as usize; | ||
let offset = utils::find_offset(rva, sections, self.file_alignment).ok_or_else(|| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we store the RVA bias in ExceptionData
instead of looking it up every time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent point. I wasn't sure if the RVAs always point into the same section. This would make sense generally, but I don't trust this is the case for every PE. Especially the tooling Microsoft applies to their DLLs might invalidate this assumption. I'll try to investigate this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think you're right. breakpad doesn't appear to do anything clever either.
Maybe transmute to |
Yeah, I was playing around with something similar for a moment... I'll let you choose what you like more 😄 type Placeholder = [u32; 3];
let slice = unsafe { std::slice::from_raw_parts(
self.bytes.as_ptr() as *const Placeholder,
self.bytes.len() / RUNTIME_FUNCTION_SIZE,
) };
let index = match slice.binary_search_by_key(&rva, |p| u32::from_le(p[0])) {
Ok(i) => i,
Err(0) => return Ok(None),
Err(i) => i - 1,
};
let function = self.get_function(index)?;
if function.end_address > rva {
Ok(Some(function))
} else {
Ok(None)
} I'm just learning about |
Let's stick with the version that doesn't use unsafe. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
yes, I agree with @philipc , lets leave out unsafe.
I'm curious though, @jan-auer , so |
If you or someone else wants to start on the pwrite implementation for a PE binary I would be super excited, or at least getting the ball rolling. m4b/faerie#46 is be major reason for this :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this has to be rebased for the R2018 changes, yes? After that LGTM, and we can merge
After this PR lands i'm going to release 0.22, got some great stuff in this release! |
@m4b, It is rebased 👍 Tests are still missing, though. I hope to finish that today.
Unfortunately, that reads the entire thing into a secondary buffer, which is not really in the spirit of memory mapped binary search :/ I was probably more looking for something along the lines of what we did in the PDB crate (and here the corresponding struct, which could be derived). As I've seen this pop a couple of times now, I might try to make some time for a PR to scroll.
Phew 😅 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, great work!
@m4b do you have an idea when you'll be able to run a release? |
Sorry got distracted I can try for this evening otherwise for sure this weekend! |
Ok 0.0.22 is published :) |
//! equal to the prolog size encoded in the unwind info. The effects of the prolog are unwound | ||
//! by scanning forward through the unwind codes array for the first entry with an offset less | ||
//! than or equal to the offset of the RIP from the function start, then undoing the effect of | ||
//! all remaining items in the unwind code array. Step 1 is then repeated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*step 2?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it's step 1 from https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=vs-2017#unwind-procedure (the 1,2,3 here are actually case a,b,c from that doc).
/// An x64 register used during unwinding. | ||
/// | ||
/// - `0` - `15`: General purpose registers | ||
/// - `17` - `32`: XMM registers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you please add 16 (rip) to the list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be added, but please note that for unwinding $rip
can never occur as it cannot be represented.
30 => "$xmm13", | ||
31 => "$xmm14", | ||
32 => "$xmm15", | ||
_ => "", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you please return something like "" here?
This implements parsing for the exception tables data directory and x64 unwind codes. Respective documentation from Microsoft is located here: https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=vs-2017.
The exception directory is only present on x64 builds, so the entire implementation can assume x64 exception handling.
Tests are still missing as I haven't taken the time to extract relevant bits from an actual executable for realistic testing yet.