11/*
2- * Copyright (c) 2020, 2023 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2020, 2024 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2727 * @summary The same JDK build should always generate the same archive file (no randomness).
2828 * @requires vm.cds & vm.flagless
2929 * @library /test/lib
30- * @run driver DeterministicDump
30+ * @build jdk.test.whitebox.WhiteBox
31+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
32+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
33+ * -XX:+WhiteBoxAPI DeterministicDump
3134 */
3235
36+ import jdk .test .lib .cds .CDSArchiveUtils ;
3337import jdk .test .lib .cds .CDSOptions ;
3438import jdk .test .lib .cds .CDSTestUtils ;
3539import jdk .test .lib .Platform ;
40+ import java .io .BufferedReader ;
41+ import java .io .File ;
3642import java .io .FileInputStream ;
43+ import java .io .FileReader ;
3744import java .io .IOException ;
45+ import java .util .ArrayDeque ;
3846import java .util .ArrayList ;
3947
4048public class DeterministicDump {
49+
50+ static long HEADER_SIZE ; // Size of header in bytes
51+ static int HEADER_LEN = 106 ; // Number of lines in CDS map file header
52+ static int LINE_OFFSET = 22 ; // Offset from address to first word of data
53+ static int NUM_LINES = 5 ; // Number of lines to be printed
54+ static int WORD_LEN = 16 + 1 ; // Length of word in map file
55+
4156 public static void main (String [] args ) throws Exception {
4257 doTest (false );
4358
@@ -62,17 +77,19 @@ public static void doTest(boolean compressed) throws Exception {
6277 }
6378
6479 String baseArchive = dump (baseArgs );
80+ File baseArchiveFile = new File (baseArchive + ".jsa" );
81+ HEADER_SIZE = CDSArchiveUtils .fileHeaderSize (baseArchiveFile );
6582
6683 // (1) Dump with the same args. Should produce the same archive.
6784 String baseArchive2 = dump (baseArgs );
68- compare (baseArchive , baseArchive2 );
85+ compare (baseArchive , baseArchive2 , baseArchiveFile );
6986
7087 // (2) This will cause the archive to be relocated during dump time. We should
7188 // still get the same bits. This simulates relocation that happens when
7289 // Address Space Layout Randomization prevents the archive space to
7390 // be mapped at the default location.
7491 String relocatedArchive = dump (baseArgs , "-XX:+UnlockDiagnosticVMOptions" , "-XX:ArchiveRelocationMode=1" );
75- compare (baseArchive , relocatedArchive );
92+ compare (baseArchive , relocatedArchive , baseArchiveFile );
7693 }
7794
7895 static int id = 0 ;
@@ -89,14 +106,14 @@ static String dump(ArrayList<String> args, String... more) throws Exception {
89106 .addSuffix (more );
90107 CDSTestUtils .createArchiveAndCheck (opts );
91108
92- return archiveName ;
109+ return logName ;
93110 }
94111
95- static void compare (String file0 , String file1 ) throws Exception {
112+ static void compare (String file0 , String file1 , File archiveFile ) throws Exception {
96113 byte [] buff0 = new byte [4096 ];
97114 byte [] buff1 = new byte [4096 ];
98- try (FileInputStream in0 = new FileInputStream (file0 );
99- FileInputStream in1 = new FileInputStream (file1 )) {
115+ try (FileInputStream in0 = new FileInputStream (file0 + ".jsa" );
116+ FileInputStream in1 = new FileInputStream (file1 + ".jsa" )) {
100117 int total = 0 ;
101118 while (true ) {
102119 int n0 = read (in0 , buff0 );
@@ -113,7 +130,12 @@ static void compare(String file0, String file1) throws Exception {
113130 byte b0 = buff0 [i ];
114131 byte b1 = buff1 [i ];
115132 if (b0 != b1 ) {
116- throw new RuntimeException ("File content different at byte #" + (total + i ) + ", b0 = " + b0 + ", b1 = " + b1 );
133+ // The checksums are stored in the header so it should be skipped
134+ // since we want to see the first meaningful diff between the archives
135+ if (total + i > HEADER_SIZE ) {
136+ print_diff (file0 + ".map" , file1 + ".map" , archiveFile , total + i );
137+ throw new RuntimeException ("File content different at byte #" + (total + i ) + ", b0 = " + b0 + ", b1 = " + b1 );
138+ }
117139 }
118140 }
119141 total += n0 ;
@@ -133,4 +155,115 @@ static int read(FileInputStream in, byte[] buff) throws IOException {
133155
134156 return total ;
135157 }
158+
159+ // CDS map file doesn't print the alignment bytes so they need to be considered
160+ // when mapping the byte number in the archive to the word in the map file
161+ static int archiveByteToMapWord (File archiveFile , int location ) throws Exception {
162+ int totalSize = 0 ;
163+ int word = location ;
164+
165+ long len = HEADER_SIZE ;
166+ long aligned = CDSArchiveUtils .fileHeaderSizeAligned (archiveFile );
167+ for (int i = 0 ; i < CDSArchiveUtils .num_regions (); i ++) {
168+ if (i != 0 ) {
169+ len = CDSArchiveUtils .usedRegionSize (archiveFile , i );
170+ aligned = CDSArchiveUtils .usedRegionSizeAligned (archiveFile , i );
171+ }
172+ totalSize += len ;
173+ if (location > totalSize ) {
174+ word -= (aligned - len - 16 );
175+ }
176+ }
177+ return word /8 ;
178+ }
179+
180+ // Read the mapfile and print out the lines associated with the location
181+ static void print_diff (String mapName0 , String mapName1 , File archiveFile , int location ) throws Exception {
182+ FileReader f0 = new FileReader (mapName0 );
183+ BufferedReader b0 = new BufferedReader (f0 );
184+
185+ FileReader f1 = new FileReader (mapName1 );
186+ BufferedReader b1 = new BufferedReader (f1 );
187+
188+ int word = archiveByteToMapWord (archiveFile , location );
189+ int wordOffset = word % 4 ; // Each line in the map file prints four words
190+ String region = "" ;
191+
192+ // Skip header text and go to first line
193+ for (int i = 0 ; i < HEADER_LEN ; i ++) {
194+ b0 .readLine ();
195+ b1 .readLine ();
196+ }
197+
198+ int line_num = HEADER_LEN ;
199+ String s0 = "" ;
200+ String s1 = "" ;
201+ int count = 0 ;
202+
203+ // Store lines before and including the diff
204+ ArrayDeque <String > prefix0 = new ArrayDeque <String >();
205+ ArrayDeque <String > prefix1 = new ArrayDeque <String >();
206+
207+ // A line may contain 1-4 words so we iterate by word
208+ do {
209+ s0 = b0 .readLine ();
210+ s1 = b1 .readLine ();
211+ line_num ++;
212+
213+ if (prefix0 .size () >= NUM_LINES / 2 + 1 ) {
214+ prefix0 .removeFirst ();
215+ prefix1 .removeFirst ();
216+ }
217+ prefix0 .addLast (s0 );
218+ prefix1 .addLast (s1 );
219+
220+ // Skip lines with headers when counting words e.g.
221+ // [rw region 0x0000000800000000 - 0x00000008005a1f88 5906312 bytes]
222+ // or
223+ // 0x0000000800000b28: @@ TypeArrayU1 16
224+ if (!s0 .contains (": @@" ) && !s0 .contains ("bytes]" )) {
225+ int words = (s0 .length () - LINE_OFFSET - 70 ) / 8 ;
226+ count += words ;
227+ } else if (s0 .contains ("bytes]" )) {
228+ region = s0 ;
229+ }
230+ } while (count < word );
231+
232+ // Print the diff with the region name above it
233+ System .out .println ("[First diff: map file #1 (" + mapName0 + ")]" );
234+ System .out .println (region );
235+ String diff0 = print_diff_helper (b0 , wordOffset , prefix0 );
236+
237+ System .out .println ("\n [First diff: map file #2 (" + mapName1 + ")]" );
238+ System .out .println (region );
239+ String diff1 = print_diff_helper (b1 , wordOffset , prefix1 );
240+
241+ System .out .printf ("\n Byte #%d at line #%d word #%d:\n " , location , line_num , wordOffset );
242+ System .out .printf ("%s: %s\n %s: %s\n " , mapName0 , diff0 , mapName1 , diff1 );
243+
244+ f0 .close ();
245+ f1 .close ();
246+ }
247+
248+ static String print_diff_helper (BufferedReader b , int wordOffset , ArrayDeque <String > prefix ) throws Exception {
249+ int start = LINE_OFFSET + WORD_LEN * wordOffset ;
250+ int end = start + WORD_LEN ;
251+ String line = prefix .getLast ();
252+ String diff = line .substring (start , end );
253+
254+ // Print previous lines
255+ for (String s : prefix ) {
256+ if (s .equals (line )) {
257+ System .out .println (">" + s );
258+ } else {
259+ System .out .println (" " + s );
260+ }
261+ }
262+
263+ // Print extra lines
264+ for (int i = 0 ; i < NUM_LINES / 2 ; i ++) {
265+ System .out .println (" " + b .readLine ());
266+ }
267+ return diff ;
268+ }
136269}
0 commit comments