redex icon indicating copy to clipboard operation
redex copied to clipboard

Line number mappings not properly emitted for DebugInfoKind::NoCustomSymbolication

Open benjaminRomano opened this issue 4 years ago • 0 comments

Background

When using DebugInfoKind::NoCustomSymbolication, line numbers are not properly emitted in the final proguard mapping. There are two causes:

  1. Line Number mappings from original proguard file are not passed through to final mapping file
  2. Line number mappings are not provided for methods inlined by Redex.

Problem

Example 1 Suppose there is a method callerMethod that has had a method called existingInlinedMethod inlined into it by a prior optimizer. This would generate the following mapping:

com.android.Test -> a:
    1:5:java.lang.Object callerMethod() -> b
    1:1:java.lang.Object existingInlinedMethod():3:3 -> b
    # Note: the original line numbers for this method inlined previously does not need to be contiguous 
    2:2:java.lang.Object existingInlinedMethod():5:5 -> b

After Redex is ran the mapping file would look like the following:

com.android.Test -> a
   1:5java.lang.Object callerMethod() -> b

Example 2

Suppose there is a method calleeMethod to be inlined into callerMethod by Redex. Due to be a previous optimizer (R8), a method existingInlinedMethod was already inlined into calleeMethod. The mapping file may look like the following:

com.android.Test -> a:
    1:5:java.lang.Object calleeMethod() -> b
    1:3:java.lang.Object existingInlinedMethod():3:4 -> b
com.android.Test2 -> c
   1:5:java.lang.Object callerMethod() -> d

After Redex is ran the mapping file would look like the following:

com.android.Test2 -> c
   1:5:java.lang.Object callerMethod() -> d

Expectation

Example 1 The expectation is that the original line number mappings would be preserved (assuming the lines remain unchanged by other optimization passes during Redex).

com.android.Test -> a:
    1:5:java.lang.Object callerMethod(java.io.OutputStream) -> b
    1:1:java.lang.Object existingInlinedMethod():3:3 -> b
    2:2:java.lang.Object existingInlinedMethod():5:5 -> b

Example 2

The expectation is that all of the original line number mappings would be preserved and passed through to the final location.

com.android.Test2 -> c
    1:5:java.lang.Object callerMethod() ->d
    1:5:java.lang.Object calleeMethod() -> d
    1:3:java.lang.Object existingInlinedMethod():3:4 -> d

Solution

  1. Pass through ProguardMap to DexOutput::write_pg_mapping.
  2. Create a method -> min/max line number mapping for every method referenced within DexPosition entries of the IRCode.
  3. Iterate through IRCode and adjust min/max line number as necessary when a DexPosition is encountered.
  4. For every method in the mapping, find existing line number entries from the proguard mapping file that are within the min/max line number range and re-emit them. If no entries are found in the existing proguard mapping, emit a simple min/max line number mapping entry.

benjaminRomano avatar Sep 02 '20 23:09 benjaminRomano