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

Try to improve C debugging experience #2134

Merged
merged 22 commits into from
Feb 5, 2024
Merged

Try to improve C debugging experience #2134

merged 22 commits into from
Feb 5, 2024

Conversation

bugadani
Copy link
Contributor

@bugadani bugadani commented Feb 3, 2024

  • We need to set frame_section.set_address_size as gimli defaults to host (8) which is just incorrect
  • This PR propagates (some?) CFA information to the evaluation as required by my elf
  • This PR moves CFA calculation to before determining frame base. In my case, the reverse failed due to CFA being None.

With 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.

@@ -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
Copy link
Contributor Author

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.

@bugadani
Copy link
Contributor Author

bugadani commented Feb 4, 2024

Two changes stand out in the failing test:

 8279       │-- function_name: "<unknown function @ 0x0000013c>"
       8288 │+- function_name: "<unknown function @ 0x0000013c> : ERROR: UNWIND: Tried to unwind `RegisterRule` at CFA = None."

Not sure why, is this PR is passing CFA to more places, is this exposing some other issue, or is the PR incorrect somewhere?

 8571       │-      value:
 8572       │-        U32: 536887296
       8581 │+      value: ~

I have no idea what happened here.

@noppej noppej self-requested a review February 4, 2024 18:45
Copy link
Contributor

@noppej noppej left a 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.

@Yatekii
Copy link
Member

Yatekii commented Feb 4, 2024

I have the source code for the test cases setup

Can you publish the source code? :)

@noppej
Copy link
Contributor

noppej commented Feb 4, 2024

Can you publish the source code? :)

Remember these ... https://github.com/probe-rs/probe-rs-debugger-test/blob/master/README.md ;-)

@noppej
Copy link
Contributor

noppej commented Feb 5, 2024

Two changes stand out in the failing test:

@bugadani I've reviewed these changes and you can go ahead and 'accept' them with cargo insta review.

Also, is there a reason why this is still in DRAFT?

@bugadani
Copy link
Contributor Author

bugadani commented Feb 5, 2024

Also, is there a reason why this is still in DRAFT?

yes, I'm not ready :)

Copy link
Contributor

@noppej noppej left a 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>,
Copy link
Contributor

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?

Copy link
Contributor Author

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
Copy link
Contributor

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.

Copy link
Contributor Author

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 {
Copy link
Contributor

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;
Copy link
Contributor

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?

Copy link
Contributor Author

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.

@bugadani bugadani marked this pull request as ready for review February 5, 2024 17:05
@bugadani
Copy link
Contributor Author

bugadani commented Feb 5, 2024

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:

  • struct fields seem to be read with wrong byte counts
  • enums aren't evaluated
  • the above question

@noppej
Copy link
Contributor

noppej commented Feb 5, 2024

  • struct fields seem to be read with wrong byte counts
  • enums aren't evaluated

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?

  • the above question

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 main trampoline.

@bugadani
Copy link
Contributor Author

bugadani commented Feb 5, 2024

If not, can you give an example?

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.

@noppej
Copy link
Contributor

noppej commented Feb 5, 2024

I've marked the PR ready in case you want to merge it in this state. I'll follow up with more work

Even if this doesn't achieve end result, it does already change the api (for StackFrame). Would you mind adding a small CHANGELOG?

@noppej
Copy link
Contributor

noppej commented Feb 5, 2024

If not, can you give an example?

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.

Ouch!

@noppej
Copy link
Contributor

noppej commented Feb 5, 2024

Awesome. I'm gonna merge so that we can do additional work in new PR's ... it will make it easier to review :)

@noppej noppej added this pull request to the merge queue Feb 5, 2024
Merged via the queue into probe-rs:master with commit e75bff6 Feb 5, 2024
18 checks passed
@bugadani bugadani deleted the cfa branch February 5, 2024 17:43
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.

None yet

3 participants