Skip to content

Commit

Permalink
Allow remapping just a method without line numbers
Browse files Browse the repository at this point in the history
This takes a conservative approach and will ignore mappings that
are ambiguous.
  • Loading branch information
Swatinem committed Oct 16, 2023
1 parent 1a4d3d7 commit 7bb58c6
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 2 deletions.
24 changes: 22 additions & 2 deletions src/mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl<'m> Iterator for RemappedFrameIter<'m> {
let (frame, ref mut members) = self.inner.as_mut()?;

for member in members {
// skip any members which do not match our the frames line
// skip any members which do not match our frames line
if member.endline > 0 && (frame.line < member.startline || frame.line > member.endline)
{
continue;
Expand Down Expand Up @@ -190,6 +190,26 @@ impl<'s> ProguardMapper<'s> {
self.classes.get(class).map(|class| class.original)
}

/// Remaps an obfuscated Class Method.
///
/// The `class` argument has to be the fully-qualified obfuscated name of the
/// class, with its complete module prefix.
///
/// The `method` will be resolved if that can be done unambiguously,
/// otherwise `None` is being returned.
pub fn remap_method(&'s self, class: &str, method: &str) -> Option<&'s str> {
let class = self.classes.get(class)?;
let mut members = class.members.get(method)?.iter();
let first = members.next()?;

// We conservatively check that all the mappings point to the same method,
// as we don’t have line numbers to disambiguate.
// We could potentially skip inlined functions here, but lets rather be conservative.
let all_matching = members.all(|member| member.original == first.original);

all_matching.then_some(first.original)
}

/// Remaps a single Stackframe.
///
/// Returns zero or more [`StackFrame`]s, based on the information in
Expand Down Expand Up @@ -231,7 +251,7 @@ impl<'s> ProguardMapper<'s> {
})
}

/// Remaps a complete Java StackTrace, similar to [`Self::remap_stacktrace`] but instead works on
/// Remaps a complete Java StackTrace, similar to [`Self::remap_stacktrace_typed`] but instead works on
/// strings as input and output.
pub fn remap_stacktrace(&self, input: &str) -> Result<String, std::fmt::Error> {
let mut stacktrace = String::new();
Expand Down
20 changes: 20 additions & 0 deletions tests/retrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,23 @@ fn test_remap_kotlin() {
.trim()
);
}

#[test]
fn test_remap_just_method() {
let mapper = ProguardMapper::from(
r#"com.exmaple.app.MainActivity -> com.exmaple.app.MainActivity:
com.example1.domain.MyBean myBean -> p
1:1:void <init>():11:11 -> <init>
1:1:void buttonClicked(android.view.View):29:29 -> buttonClicked
2:2:void com.example1.domain.MyBean.doWork():16:16 -> buttonClicked
2:2:void buttonClicked(android.view.View):29 -> buttonClicked
1:1:void onCreate(android.os.Bundle):17:17 -> onCreate
2:5:void onCreate(android.os.Bundle):22:25 -> onCreate"#,
);

let unambiguous = mapper.remap_method("com.exmaple.app.MainActivity", "onCreate");
assert_eq!(unambiguous, Some("onCreate"));

let ambiguous = mapper.remap_method("com.exmaple.app.MainActivity", "buttonClicked");
assert_eq!(ambiguous, None);
}

0 comments on commit 7bb58c6

Please sign in to comment.