-
-
Notifications
You must be signed in to change notification settings - Fork 326
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
Try to improve C debugging experience #2134
Conversation
@@ -95,6 +96,8 @@ impl DebugInfo { | |||
|
|||
while let Ok(Some(header)) = iter.next() { | |||
if let Ok(unit) = dwarf_cow.unit(header) { | |||
// TODO: maybe it's not correct to read from arbitrary units |
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.
This is probably just a coincidence and not a general truth. Still, this was the easiest 4-byte pointer size I found nearby.
Two changes stand out in the failing test:
Not sure why, is this PR is passing CFA to more places, is this exposing some other issue, or is the PR incorrect somewhere?
I have no idea what happened here. |
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.
@bugadani Thank you for this. I have the source code for the test cases setup, so will be debugging those test cases to understand the changes, and let you know. Chances are they are easily resolved, but the unwind is hard to fix once it is broken, so I will temporarily (1-2 days) block this merge, until we can understand the root cause of those changes.
Can you publish the source code? :) |
Remember these ... https://github.com/probe-rs/probe-rs-debugger-test/blob/master/README.md ;-) |
@bugadani I've reviewed these changes and you can go ahead and 'accept' them with Also, is there a reason why this is still in DRAFT? |
yes, I'm not ready :) |
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.
@bugadani I know this is in draft status, but I'm approving the changes you've made so far, in case you want to think about doing further work in a new PR.
Thank you for moving forward the functionality for C binaries, and also, thank you for taking the extra time to do code cleanup when you see opportunities to do so. Your contributions are very valuable!
/// - Complex variables and pointers will have additional children. | ||
/// - This structure is recursive until a base type is encountered. | ||
pub local_variables: Option<VariableCache>, | ||
/// The value of the stack pointer just before the CALL instruction in the parent function. | ||
pub canonical_frame_address: Option<u64>, |
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'm curious ... you instroduced a new struct for StackFrameInfo
, and all the contents is duplicated in StackFrame
... should we just have a StackFrameInfo
inside StackFrame
?
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.
There's a difference: StackFrameInfo just borrows the registers from StackFrame and does not own them. At first I wanted to pass StackFrame around but it wasn't available everywhere, though maybe that has changed now?
@@ -646,6 +642,36 @@ impl Variable { | |||
|value| VariableValue::Valid(value.to_string()), | |||
), | |||
"None" => VariableValue::Valid("None".to_string()), | |||
|
|||
// C types - should probably branch on the language |
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.
We would have to pretty confident that it is only types that are exclusive C, and not 'overlapped' in other languages. Ideally if we find types with different names, but same underlying storage, then we should not duplicate the code required to resolve (and/or udpdate) values.
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.
char
is painful, I want to branch on the language here.
) -> Result<ExpressionResult, DebugError> { | ||
trait ResultExt { |
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.
Nice little mechanism to reduce code duplication later on ... after this, I won't go to bed stupid tonight. Thanks :-)
continue; | ||
if !function_dies.is_empty() { | ||
functions = Some((unit_info, function_dies)); | ||
break; |
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 you help me understand why you changed the continue
to break
?
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 also changed the condition from is_empty
to !is_empty
. I split the original loop into a "find" loop and the code afterwards that handles the found data.
I read that you're find with the snapshot changes, but do you know their root cause, too? I would prefer not to introduce an issue if we already know its cause. I've marked the PR ready in case you want to merge it in this state. I'll follow up with more work, there are two outstanding issues right now:
|
The tests (and snapshots) have extensive struct fields and enums, and they unwind correctly. Are you bumping into this issue when you test locally? If so, I think we should fix that in a separate PR. If not, can you give an example?
Those belong to stack frames that are incorrectly unwound as it is. We should either stop unwinding, or preferably (#1667) fix the way we unwind past the |
any of my C enums :) I specifically have issues with C, not with Rust code, so I think their debug info are just encoded differently. |
Even if this doesn't achieve end result, it does already change the api (for |
Ouch! |
Awesome. I'm gonna merge so that we can do additional work in new PR's ... it will make it easier to review :) |
frame_section.set_address_size
as gimli defaults to host (8) which is just incorrectWith this, I now have a decent call stack, but variable values are still not filly implemented (enums!). Also, struct fields are always read with the same byte count as the struct itself, it looks like.