From 89882e04bc8cfd8da31dcaeaf0ace8374479ce75 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 19:54:22 +0000 Subject: [PATCH 1/4] Initial plan From 8b163cb782743eba7484085c00fab0c78e50614b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 20:18:09 +0000 Subject: [PATCH 2/4] Remove sortParameterAnnotations function - parameter annotations are already in correct order Co-authored-by: futpib <4330357+futpib@users.noreply.github.com> --- ...ExecutableParserAgainstSmaliParser.test.ts | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/src/dalvikExecutableParserAgainstSmaliParser.test.ts b/src/dalvikExecutableParserAgainstSmaliParser.test.ts index ddb2c6e..0fc4805 100644 --- a/src/dalvikExecutableParserAgainstSmaliParser.test.ts +++ b/src/dalvikExecutableParserAgainstSmaliParser.test.ts @@ -54,31 +54,6 @@ function normalizeSmaliFilePath(smaliFilePath: string | { }; } -function sortParameterAnnotations(classDefinition: any) { - if ( - classDefinition - && typeof classDefinition === 'object' - && 'annotations' in classDefinition - && classDefinition.annotations - && typeof classDefinition.annotations === 'object' - && 'parameterAnnotations' in classDefinition.annotations - && Array.isArray(classDefinition.annotations.parameterAnnotations) - ) { - classDefinition.annotations.parameterAnnotations.sort((a: any, b: any) => { - // Sort by class name first - if (a.method.class !== b.method.class) { - return a.method.class.localeCompare(b.method.class); - } - // Then by method name - if (a.method.name !== b.method.name) { - return a.method.name.localeCompare(b.method.name); - } - // Then by shorty (prototype signature) - return a.method.prototype.shorty.localeCompare(b.method.prototype.shorty); - }); - } -} - function sortFieldAnnotations(classDefinition: any) { if ( classDefinition @@ -165,10 +140,6 @@ const parseDexAgainstSmaliMacro = test.macro({ normalizeClassDefinition(classDefinitionFromDex); normalizeClassDefinition(classDefinitionFromSmali); - // Sort parameter annotations to ensure consistent ordering between DEX and Smali - sortParameterAnnotations(classDefinitionFromDex); - sortParameterAnnotations(classDefinitionFromSmali); - // Sort field annotations to ensure consistent ordering between DEX and Smali sortFieldAnnotations(classDefinitionFromDex); sortFieldAnnotations(classDefinitionFromSmali); @@ -400,10 +371,6 @@ test.serial( normalizeClassDefinition(classDefinitionFromDex); normalizeClassDefinition(classDefinitionFromSmali); - // Sort parameter annotations to ensure consistent ordering between DEX and Smali - sortParameterAnnotations(classDefinitionFromDex); - sortParameterAnnotations(classDefinitionFromSmali); - // Sort field annotations to ensure consistent ordering between DEX and Smali sortFieldAnnotations(classDefinitionFromDex); sortFieldAnnotations(classDefinitionFromSmali); From e0e1e4ad8c20c4d3389091af474588b842a86605 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:12:41 +0000 Subject: [PATCH 3/4] Revert removal of sortParameterAnnotations - baksmali method order differs from DEX Co-authored-by: futpib <4330357+futpib@users.noreply.github.com> --- ...ExecutableParserAgainstSmaliParser.test.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/dalvikExecutableParserAgainstSmaliParser.test.ts b/src/dalvikExecutableParserAgainstSmaliParser.test.ts index 0fc4805..ddb2c6e 100644 --- a/src/dalvikExecutableParserAgainstSmaliParser.test.ts +++ b/src/dalvikExecutableParserAgainstSmaliParser.test.ts @@ -54,6 +54,31 @@ function normalizeSmaliFilePath(smaliFilePath: string | { }; } +function sortParameterAnnotations(classDefinition: any) { + if ( + classDefinition + && typeof classDefinition === 'object' + && 'annotations' in classDefinition + && classDefinition.annotations + && typeof classDefinition.annotations === 'object' + && 'parameterAnnotations' in classDefinition.annotations + && Array.isArray(classDefinition.annotations.parameterAnnotations) + ) { + classDefinition.annotations.parameterAnnotations.sort((a: any, b: any) => { + // Sort by class name first + if (a.method.class !== b.method.class) { + return a.method.class.localeCompare(b.method.class); + } + // Then by method name + if (a.method.name !== b.method.name) { + return a.method.name.localeCompare(b.method.name); + } + // Then by shorty (prototype signature) + return a.method.prototype.shorty.localeCompare(b.method.prototype.shorty); + }); + } +} + function sortFieldAnnotations(classDefinition: any) { if ( classDefinition @@ -140,6 +165,10 @@ const parseDexAgainstSmaliMacro = test.macro({ normalizeClassDefinition(classDefinitionFromDex); normalizeClassDefinition(classDefinitionFromSmali); + // Sort parameter annotations to ensure consistent ordering between DEX and Smali + sortParameterAnnotations(classDefinitionFromDex); + sortParameterAnnotations(classDefinitionFromSmali); + // Sort field annotations to ensure consistent ordering between DEX and Smali sortFieldAnnotations(classDefinitionFromDex); sortFieldAnnotations(classDefinitionFromSmali); @@ -371,6 +400,10 @@ test.serial( normalizeClassDefinition(classDefinitionFromDex); normalizeClassDefinition(classDefinitionFromSmali); + // Sort parameter annotations to ensure consistent ordering between DEX and Smali + sortParameterAnnotations(classDefinitionFromDex); + sortParameterAnnotations(classDefinitionFromSmali); + // Sort field annotations to ensure consistent ordering between DEX and Smali sortFieldAnnotations(classDefinitionFromDex); sortFieldAnnotations(classDefinitionFromSmali); From 4246184266c6140d74fc76e6740878308a890e51 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:37:46 +0000 Subject: [PATCH 4/4] Fix both DEX and Smali parsers to output parameter annotations in correct order Co-authored-by: futpib <4330357+futpib@users.noreply.github.com> --- src/dalvikExecutableParser.ts | 18 ++++++++++ ...ExecutableParserAgainstSmaliParser.test.ts | 33 ------------------- src/smaliParser.ts | 9 +++++ 3 files changed, 27 insertions(+), 33 deletions(-) diff --git a/src/dalvikExecutableParser.ts b/src/dalvikExecutableParser.ts index f73474b..f3ccfff 100644 --- a/src/dalvikExecutableParser.ts +++ b/src/dalvikExecutableParser.ts @@ -3047,6 +3047,24 @@ const createDalvikExecutableParser = ({ }; }); + // Sort parameter annotations in each class by method index in classData + for (const classDef of classDefinitions) { + if (classDef.annotations?.parameterAnnotations && classDef.classData) { + const allMethods = [...(classDef.classData.directMethods ?? []), ...(classDef.classData.virtualMethods ?? [])]; + classDef.annotations.parameterAnnotations.sort((a, b) => { + const indexA = allMethods.findIndex(m => + m.method.name === a.method.name && + m.method.prototype.shorty === a.method.prototype.shorty + ); + const indexB = allMethods.findIndex(m => + m.method.name === b.method.name && + m.method.prototype.shorty === b.method.prototype.shorty + ); + return indexA - indexB; + }); + } + } + return { classDefinitions, link, diff --git a/src/dalvikExecutableParserAgainstSmaliParser.test.ts b/src/dalvikExecutableParserAgainstSmaliParser.test.ts index ddb2c6e..0fc4805 100644 --- a/src/dalvikExecutableParserAgainstSmaliParser.test.ts +++ b/src/dalvikExecutableParserAgainstSmaliParser.test.ts @@ -54,31 +54,6 @@ function normalizeSmaliFilePath(smaliFilePath: string | { }; } -function sortParameterAnnotations(classDefinition: any) { - if ( - classDefinition - && typeof classDefinition === 'object' - && 'annotations' in classDefinition - && classDefinition.annotations - && typeof classDefinition.annotations === 'object' - && 'parameterAnnotations' in classDefinition.annotations - && Array.isArray(classDefinition.annotations.parameterAnnotations) - ) { - classDefinition.annotations.parameterAnnotations.sort((a: any, b: any) => { - // Sort by class name first - if (a.method.class !== b.method.class) { - return a.method.class.localeCompare(b.method.class); - } - // Then by method name - if (a.method.name !== b.method.name) { - return a.method.name.localeCompare(b.method.name); - } - // Then by shorty (prototype signature) - return a.method.prototype.shorty.localeCompare(b.method.prototype.shorty); - }); - } -} - function sortFieldAnnotations(classDefinition: any) { if ( classDefinition @@ -165,10 +140,6 @@ const parseDexAgainstSmaliMacro = test.macro({ normalizeClassDefinition(classDefinitionFromDex); normalizeClassDefinition(classDefinitionFromSmali); - // Sort parameter annotations to ensure consistent ordering between DEX and Smali - sortParameterAnnotations(classDefinitionFromDex); - sortParameterAnnotations(classDefinitionFromSmali); - // Sort field annotations to ensure consistent ordering between DEX and Smali sortFieldAnnotations(classDefinitionFromDex); sortFieldAnnotations(classDefinitionFromSmali); @@ -400,10 +371,6 @@ test.serial( normalizeClassDefinition(classDefinitionFromDex); normalizeClassDefinition(classDefinitionFromSmali); - // Sort parameter annotations to ensure consistent ordering between DEX and Smali - sortParameterAnnotations(classDefinitionFromDex); - sortParameterAnnotations(classDefinitionFromSmali); - // Sort field annotations to ensure consistent ordering between DEX and Smali sortFieldAnnotations(classDefinitionFromDex); sortFieldAnnotations(classDefinitionFromSmali); diff --git a/src/smaliParser.ts b/src/smaliParser.ts index df32982..c217830 100644 --- a/src/smaliParser.ts +++ b/src/smaliParser.ts @@ -2511,6 +2511,15 @@ const smaliMethodsParser: Parser = promiseCompose( invariant(false, 'Expected method type'); } + // Sort parameter annotations by method index in the combined method list + // to match the order in the DEX file's annotations directory + const allMethods = [...directMethods, ...virtualMethods]; + parameterAnnotations.sort((a, b) => { + const indexA = allMethods.findIndex(m => dalvikExecutableMethodEquals(m.method, a.method)); + const indexB = allMethods.findIndex(m => dalvikExecutableMethodEquals(m.method, b.method)); + return indexA - indexB; + }); + return { directMethods, virtualMethods,