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[: class internal name 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 that matches against class internal names. 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# Convert the output for `-s` as needed. 82filter_output() { 83 if (( $simple )) ; then 84 # For "simple output" mode, 85 # - Normalize the constant numbers (replace with "#x") 86 # - Normalize byte code offsets and other similar numbers. (e.g. "0:" -> "x:") 87 # - Remove the constant pool 88 # - Remove the line number table 89 # - Some other transient lines 90 # - Sometimes the javap shows mysterious warnings, so remove them too. 91 # 92 # `/PATTERN-1/,/PATTERN-1/{//!d}` is a trick to delete lines between two patterns, without 93 # the start and the end lines. 94 sed -e 's/#[0-9][0-9]*/#x/g' \ 95 -e 's/^\( *\)[0-9][0-9]*:/\1x:/' \ 96 -e '/^Constant pool:/,/^[^ ]/{//!d}' \ 97 -e '/^ *line *[0-9][0-9]*: *[0-9][0-9]*$/d' \ 98 -e '/SHA-256 checksum/d' \ 99 -e '/Last modified/d' \ 100 -e '/^Classfile jar/d' \ 101 -e '/\[warning\]/d' 102 else 103 cat # Print as-is. 104 fi 105} 106 107# Write to the output file (specified with -o) as needed. 108write_to_out() { 109 if [[ -n "$output" ]] ; then 110 cat >"$output" 111 echo "Wrote output to $output" 1>&2 112 else 113 cat # print to stdout 114 fi 115} 116 117# Read jar file names and remove the .class suffix. 118# Also remove non-class files. 119to_internal_names() { 120 sed -ne 's/\.class$//p' 121} 122 123for file in "${@}"; do 124 125 # *.class? 126 if echo "$file" | grep -qE '\.class$' ; then 127 echo "# Class: $file" 1>&2 128 javap $dump_code_opt $JAVAP_OPTS $file 129 130 # *.jar? 131 elif echo "$file" | grep -qE '\.jar(:.*)?$' ; then 132 # Take the regex. Remove everything up to : in $file 133 regex="" 134 if [[ "$file" =~ : ]] ; then 135 regex="${file##*:}" 136 fi 137 138 # Remove everything after ':', inclusively, in $file. 139 file="${file%:*}" 140 141 # Print the filename and the regex. 142 if ! (( $simple )) ; then 143 echo -n "# Jar: $file" 144 if [[ "$regex" != "" ]] ;then 145 echo -n " (regex: $regex)" 146 fi 147 echo 148 fi 149 150 jar tf "$file" | sort | to_internal_names | grep -- "$regex" | while read -r class ; do 151 echo "## Class: $class.class" 152 javap $dump_code_opt $JAVAP_OPTS -cp "$file" "${class}" 153 done 154 155 else 156 echo "Unknown file type: $file" 1>&2 157 exit 1 158 fi 159done | filter_output | write_to_out 160