1#!/bin/bash 2# Copyright (C) 2023 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16set -e 17 18 19help() { 20 cat <<'EOF' 21 22 dump-jar: Dump java classes in jar files 23 24 Usage: 25 dump-jar [-v] CLASS-FILE [...] 26 27 Dump a *.class file 28 29 dump-jar [-v] [-s] [-o OUTPUT-FILENAME] JAR-FILE[: filename regex] [...] 30 31 Dump a jar file. 32 33 If a filename contains a ':', then the following part 34 will be used to filter files in the jar file. 35 36 For example, "file.jar:/MyClass$" will only dump "MyClass" in file.jar. 37 38 Options: 39 -v: Enable verbose output. 40 41 -s: Simple output mode, used to check HostStubGen output jars. 42 43 -o: Write the output to a specified file. 44EOF 45} 46 47# Parse the options. 48 49verbose=0 50simple=0 51output="" 52while getopts "hvso:" opt; do 53case "$opt" in 54 h) 55 help 56 exit 0 57 ;; 58 v) 59 verbose=1 60 ;; 61 s) 62 simple=1 63 ;; 64 o) 65 output="$OPTARG" 66 ;; 67 '?') 68 help 69 exit 1 70 ;; 71esac 72done 73shift $(($OPTIND - 1)) 74 75JAVAP_OPTS="${JAVAP_OPTS:--v -p -s -sysinfo -constants}" 76 77if (( $simple )) ; then 78 JAVAP_OPTS="-p -c -v" 79fi 80 81 82# Normalize a java class name. 83# Convert '.' to '/' 84# Remove the *.class suffix. 85normalize() { 86 local name="$1" 87 name="${name%.class}" # Remove the .class suffix. 88 echo "$name" | tr '.' '/' 89} 90 91# Convert the output for `-s` as needed. 92filter_output() { 93 if (( $simple )) ; then 94 # For "simple output" mode, 95 # - Normalize the constant numbers (replace with "#x") 96 # - Normalize byte code offsets and other similar numbers. (e.g. "0:" -> "x:") 97 # - Remove the constant pool 98 # - Remove the line number table 99 # - Some other transient lines 100 # 101 # `/PATTERN-1/,/PATTERN-1/{//!d}` is a trick to delete lines between two patterns, without 102 # the start and the end lines. 103 sed -e 's/#[0-9][0-9]*/#x/g' \ 104 -e 's/^\( *\)[0-9][0-9]*:/\1x:/' \ 105 -e '/^Constant pool:/,/^[^ ]/{//!d}' \ 106 -e '/^ *line *[0-9][0-9]*: *[0-9][0-9]*$/d' \ 107 -e '/SHA-256 checksum/d' \ 108 -e '/Last modified/d' \ 109 -e '/^Classfile jar/d' 110 else 111 cat # Print as-is. 112 fi 113} 114 115# Write to the output file (specified with -o) as needed. 116write_to_out() { 117 if [[ -n "$output" ]] ; then 118 cat >"$output" 119 echo "Wrote output to $output" 1>&2 120 else 121 cat # print to stdout 122 fi 123} 124 125for file in "${@}"; do 126 127 # *.class? 128 if echo "$file" | grep -qE '\.class$' ; then 129 echo "# Class: $file" 1>&2 130 javap $dump_code_opt $JAVAP_OPTS $file 131 132 # *.jar? 133 elif echo "$file" | grep -qE '\.jar(:.*)?$' ; then 134 # Take the regex. Remove everything up to : in $file 135 regex="" 136 if [[ "$file" =~ : ]] ; then 137 regex="$(normalize "${file##*:}")" 138 fi 139 140 # Remove everything after ':', inclusively, in $file. 141 file="${file%:*}" 142 143 # Print the filename and the regex. 144 if ! (( $simple )) ; then 145 echo -n "# Jar: $file" 146 if [[ "$regex" != "" ]] ;then 147 echo -n " (regex: $regex)" 148 fi 149 echo 150 fi 151 152 jar tf "$file" | grep '\.class$' | sort | while read -r class ; do 153 if normalize "$class" | grep -q -- "$regex" ; then 154 echo "## Class: $class" 155 javap $dump_code_opt $JAVAP_OPTS -cp $file ${class%.class} 156 else 157 (( $verbose )) && echo "## Skipping class: $class" 158 fi 159 done 160 161 else 162 echo "Unknown file type: $file" 1>&2 163 exit 1 164 fi 165done | filter_output | write_to_out 166