Skip to content

Commit 38a578d

Browse files
committed
8334738: os::print_hex_dump should optionally print ASCII
Reviewed-by: dholmes, sgehwolf
1 parent 7b894bc commit 38a578d

File tree

7 files changed

+144
-92
lines changed

7 files changed

+144
-92
lines changed

src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Copyright (c) 2020, Microsoft Corporation. All rights reserved.
3-
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
66
* This code is free software; you can redistribute it and/or modify it
@@ -219,7 +219,7 @@ void os::print_tos_pc(outputStream *st, const void *context) {
219219
// this at the end, and hope for the best.
220220
address pc = (address)uc->Pc;
221221
st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc);
222-
print_hex_dump(st, pc - 32, pc + 32, sizeof(char));
222+
print_hex_dump(st, pc - 32, pc + 32, sizeof(char), /* print_ascii=*/false);
223223
st->cr();
224224
}
225225

src/hotspot/share/cds/archiveBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1273,7 +1273,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
12731273
// longs and doubles will be split into two words.
12741274
unitsize = sizeof(narrowOop);
12751275
}
1276-
os::print_hex_dump(&lsh, base, top, unitsize, 32, requested_base);
1276+
os::print_hex_dump(&lsh, base, top, unitsize, /* print_ascii=*/true, /* bytes_per_line=*/32, requested_base);
12771277
}
12781278
}
12791279

src/hotspot/share/runtime/os.cpp

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -938,56 +938,73 @@ bool os::print_function_and_library_name(outputStream* st,
938938
return have_function_name || have_library_name;
939939
}
940940

941-
ATTRIBUTE_NO_ASAN static bool read_safely_from(intptr_t* p, intptr_t* result) {
942-
const intptr_t errval = 0x1717;
943-
intptr_t i = SafeFetchN(p, errval);
941+
ATTRIBUTE_NO_ASAN static bool read_safely_from(const uintptr_t* p, uintptr_t* result) {
942+
DEBUG_ONLY(*result = 0xAAAA;)
943+
const uintptr_t errval = 0x1717;
944+
uintptr_t i = (uintptr_t)SafeFetchN((intptr_t*)p, errval);
944945
if (i == errval) {
945-
i = SafeFetchN(p, ~errval);
946+
i = (uintptr_t)SafeFetchN((intptr_t*)p, ~errval);
946947
if (i == ~errval) {
947948
return false;
948949
}
949950
}
950-
(*result) = i;
951+
(*result) = (uintptr_t)i;
951952
return true;
952953
}
953954

954-
static void print_hex_location(outputStream* st, address p, int unitsize) {
955+
// Helper for os::print_hex_dump
956+
static void print_ascii_form(stringStream& ascii_form, uint64_t value, int unitsize) {
957+
union {
958+
uint64_t v;
959+
uint8_t c[sizeof(v)];
960+
} u = { value };
961+
for (int i = 0; i < unitsize; i++) {
962+
const int idx = LITTLE_ENDIAN_ONLY(i) BIG_ENDIAN_ONLY(sizeof(u.v) - 1 - i);
963+
const uint8_t c = u.c[idx];
964+
ascii_form.put(isprint(c) && isascii(c) ? c : '.');
965+
}
966+
}
967+
968+
// Helper for os::print_hex_dump
969+
static void print_hex_location(outputStream* st, const_address p, int unitsize, stringStream& ascii_form) {
955970
assert(is_aligned(p, unitsize), "Unaligned");
956-
address pa = align_down(p, sizeof(intptr_t));
971+
const uintptr_t* pa = (const uintptr_t*) align_down(p, sizeof(intptr_t));
957972
#ifndef _LP64
958973
// Special handling for printing qwords on 32-bit platforms
959974
if (unitsize == 8) {
960-
intptr_t i1, i2;
961-
if (read_safely_from((intptr_t*)pa, &i1) &&
962-
read_safely_from((intptr_t*)pa + 1, &i2)) {
975+
uintptr_t i1 = 0, i2 = 0;
976+
if (read_safely_from(pa, &i1) &&
977+
read_safely_from(pa + 1, &i2)) {
963978
const uint64_t value =
964979
LITTLE_ENDIAN_ONLY((((uint64_t)i2) << 32) | i1)
965980
BIG_ENDIAN_ONLY((((uint64_t)i1) << 32) | i2);
966981
st->print("%016" FORMAT64_MODIFIER "x", value);
982+
print_ascii_form(ascii_form, value, unitsize);
967983
} else {
968984
st->print_raw("????????????????");
969985
}
970986
return;
971987
}
972988
#endif // 32-bit, qwords
973-
intptr_t i = 0;
974-
if (read_safely_from((intptr_t*)pa, &i)) {
989+
uintptr_t i = 0;
990+
if (read_safely_from(pa, &i)) {
975991
// bytes: CA FE BA BE DE AD C0 DE
976992
// bytoff: 0 1 2 3 4 5 6 7
977993
// LE bits: 0 8 16 24 32 40 48 56
978994
// BE bits: 56 48 40 32 24 16 8 0
979-
const int offset = (int)(p - (address)pa);
995+
const int offset = (int)(p - (const_address)pa);
980996
const int bitoffset =
981997
LITTLE_ENDIAN_ONLY(offset * BitsPerByte)
982998
BIG_ENDIAN_ONLY((int)((sizeof(intptr_t) - unitsize - offset) * BitsPerByte));
983999
const int bitfieldsize = unitsize * BitsPerByte;
984-
intptr_t value = bitfield(i, bitoffset, bitfieldsize);
1000+
uintptr_t value = bitfield(i, bitoffset, bitfieldsize);
9851001
switch (unitsize) {
9861002
case 1: st->print("%02x", (u1)value); break;
9871003
case 2: st->print("%04x", (u2)value); break;
9881004
case 4: st->print("%08x", (u4)value); break;
9891005
case 8: st->print("%016" FORMAT64_MODIFIER "x", (u8)value); break;
9901006
}
1007+
print_ascii_form(ascii_form, value, unitsize);
9911008
} else {
9921009
switch (unitsize) {
9931010
case 1: st->print_raw("??"); break;
@@ -998,36 +1015,56 @@ static void print_hex_location(outputStream* st, address p, int unitsize) {
9981015
}
9991016
}
10001017

1001-
void os::print_hex_dump(outputStream* st, address start, address end, int unitsize,
1002-
int bytes_per_line, address logical_start) {
1018+
void os::print_hex_dump(outputStream* st, const_address start, const_address end, int unitsize,
1019+
bool print_ascii, int bytes_per_line, const_address logical_start) {
1020+
constexpr int max_bytes_per_line = 64;
10031021
assert(unitsize == 1 || unitsize == 2 || unitsize == 4 || unitsize == 8, "just checking");
1022+
assert(bytes_per_line > 0 && bytes_per_line <= max_bytes_per_line &&
1023+
is_power_of_2(bytes_per_line), "invalid bytes_per_line");
10041024

10051025
start = align_down(start, unitsize);
10061026
logical_start = align_down(logical_start, unitsize);
10071027
bytes_per_line = align_up(bytes_per_line, 8);
10081028

10091029
int cols = 0;
1010-
int cols_per_line = bytes_per_line / unitsize;
1030+
const int cols_per_line = bytes_per_line / unitsize;
10111031

1012-
address p = start;
1013-
address logical_p = logical_start;
1032+
const_address p = start;
1033+
const_address logical_p = logical_start;
1034+
1035+
stringStream ascii_form;
10141036

10151037
// Print out the addresses as if we were starting from logical_start.
1016-
st->print(PTR_FORMAT ": ", p2i(logical_p));
10171038
while (p < end) {
1018-
print_hex_location(st, p, unitsize);
1039+
if (cols == 0) {
1040+
st->print(PTR_FORMAT ": ", p2i(logical_p));
1041+
}
1042+
print_hex_location(st, p, unitsize, ascii_form);
10191043
p += unitsize;
10201044
logical_p += unitsize;
10211045
cols++;
1022-
if (cols >= cols_per_line && p < end) {
1023-
cols = 0;
1046+
if (cols >= cols_per_line) {
1047+
if (print_ascii && !ascii_form.is_empty()) {
1048+
st->print(" %s", ascii_form.base());
1049+
}
1050+
ascii_form.reset();
10241051
st->cr();
1025-
st->print(PTR_FORMAT ": ", p2i(logical_p));
1052+
cols = 0;
10261053
} else {
10271054
st->print(" ");
10281055
}
10291056
}
1030-
st->cr();
1057+
1058+
if (cols > 0) { // did not print a full line
1059+
if (print_ascii) {
1060+
// indent last ascii part to match that of full lines
1061+
const int size_of_printed_unit = unitsize * 2;
1062+
const int space_left = (cols_per_line - cols) * (size_of_printed_unit + 1);
1063+
st->sp(space_left);
1064+
st->print(" %s", ascii_form.base());
1065+
}
1066+
st->cr();
1067+
}
10311068
}
10321069

10331070
void os::print_dhm(outputStream* st, const char* startStr, long sec) {
@@ -1045,7 +1082,7 @@ void os::print_tos(outputStream* st, address sp) {
10451082

10461083
void os::print_instructions(outputStream* st, address pc, int unitsize) {
10471084
st->print_cr("Instructions: (pc=" PTR_FORMAT ")", p2i(pc));
1048-
print_hex_dump(st, pc - 256, pc + 256, unitsize);
1085+
print_hex_dump(st, pc - 256, pc + 256, unitsize, /* print_ascii=*/false);
10491086
}
10501087

10511088
void os::print_environment_variables(outputStream* st, const char** env_list) {

src/hotspot/share/runtime/os.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -856,10 +856,10 @@ class os: AllStatic {
856856
// return current frame. pc() and sp() are set to null on failure.
857857
static frame current_frame();
858858

859-
static void print_hex_dump(outputStream* st, address start, address end, int unitsize,
860-
int bytes_per_line, address logical_start);
861-
static void print_hex_dump(outputStream* st, address start, address end, int unitsize) {
862-
print_hex_dump(st, start, end, unitsize, /*bytes_per_line=*/16, /*logical_start=*/start);
859+
static void print_hex_dump(outputStream* st, const_address start, const_address end, int unitsize, bool print_ascii,
860+
int bytes_per_line, const_address logical_start);
861+
static void print_hex_dump(outputStream* st, const_address start, const_address end, int unitsize, bool print_ascii = true) {
862+
print_hex_dump(st, start, end, unitsize, print_ascii, /*bytes_per_line=*/16, /*logical_start=*/start);
863863
}
864864

865865
// returns a string to describe the exception/signal;

src/hotspot/share/utilities/globalDefinitions.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ typedef unsigned int uint; NEEDS_CLEANUP
455455
typedef signed char s_char;
456456
typedef unsigned char u_char;
457457
typedef u_char* address;
458+
typedef const u_char* const_address;
458459

459460
// Pointer subtraction.
460461
// The idea here is to avoid ptrdiff_t, which is signed and so doesn't have

src/hotspot/share/utilities/ostream.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ class stringStream : public outputStream {
267267
return _buffer;
268268
};
269269
void reset();
270+
bool is_empty() const { return _buffer[0] == '\0'; }
270271
// Copy to a resource, or C-heap, array as requested
271272
char* as_string(bool c_heap = false) const;
272273
};

test/hotspot/gtest/runtime/test_os.cpp

Lines changed: 72 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -167,82 +167,95 @@ TEST_VM_ASSERT_MSG(os, page_size_for_region_with_zero_min_pages,
167167
}
168168
#endif
169169

170-
static void do_test_print_hex_dump(address addr, size_t len, int unitsize, const char* expected) {
171-
char buf[256];
170+
#ifndef AIX
171+
// Test relies on the ability to protect memory allocated with os::reserve_memory. AIX may not be able
172+
// to do that (mprotect won't work on System V shm).
173+
static void do_test_print_hex_dump(const_address from, const_address to, int unitsize, int bytes_per_line,
174+
const_address logical_start, const char* expected) {
175+
char buf[2048];
172176
buf[0] = '\0';
173177
stringStream ss(buf, sizeof(buf));
174-
os::print_hex_dump(&ss, addr, addr + len, unitsize);
175-
// tty->print_cr("expected: %s", expected);
176-
// tty->print_cr("result: %s", buf);
177-
EXPECT_THAT(buf, HasSubstr(expected));
178+
os::print_hex_dump(&ss, from, to, unitsize, /* print_ascii=*/true, bytes_per_line, logical_start);
179+
EXPECT_STREQ(buf, expected);
178180
}
179181

180182
TEST_VM(os, test_print_hex_dump) {
181-
const char* pattern [4] = {
182-
#ifdef VM_LITTLE_ENDIAN
183-
"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f",
184-
"0100 0302 0504 0706 0908 0b0a 0d0c 0f0e",
185-
"03020100 07060504 0b0a0908 0f0e0d0c",
186-
"0706050403020100 0f0e0d0c0b0a0908"
183+
184+
#ifdef _LP64
185+
#define ADDRESS1 "0x0000aaaaaaaaaa00"
186+
#define ADDRESS2 "0x0000aaaaaaaaaa20"
187+
#define ADDRESS3 "0x0000aaaaaaaaaa40"
187188
#else
188-
"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f",
189-
"0001 0203 0405 0607 0809 0a0b 0c0d 0e0f",
190-
"00010203 04050607 08090a0b 0c0d0e0f",
191-
"0001020304050607 08090a0b0c0d0e0f"
189+
#define ADDRESS1 "0xaaaaaa00"
190+
#define ADDRESS2 "0xaaaaaa20"
191+
#define ADDRESS3 "0xaaaaaa40"
192192
#endif
193-
};
194193

195-
const char* pattern_not_readable [4] = {
196-
"?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??",
197-
"???? ???? ???? ???? ???? ???? ???? ????",
198-
"???????? ???????? ???????? ????????",
199-
"???????????????? ????????????????"
200-
};
194+
#define ASCII_1 "....#.jdk/internal/loader/Native"
195+
#define ASCII_2 "Libraries......."
201196

202-
// On AIX, zero page is readable.
203-
address unreadable =
204-
#ifdef AIX
205-
(address) 0xFFFFFFFFFFFF0000ULL;
197+
#define PAT_1 ADDRESS1 ": ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??\n" \
198+
ADDRESS2 ": ff ff e0 dc 23 00 6a 64 6b 2f 69 6e 74 65 72 6e 61 6c 2f 6c 6f 61 64 65 72 2f 4e 61 74 69 76 65 " ASCII_1 "\n" \
199+
ADDRESS3 ": 4c 69 62 72 61 72 69 65 73 00 00 00 00 00 00 00 " ASCII_2 "\n"
200+
201+
#ifdef VM_LITTLE_ENDIAN
202+
#define PAT_2 ADDRESS1 ": ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ????\n" \
203+
ADDRESS2 ": ffff dce0 0023 646a 2f6b 6e69 6574 6e72 6c61 6c2f 616f 6564 2f72 614e 6974 6576 " ASCII_1 "\n" \
204+
ADDRESS3 ": 694c 7262 7261 6569 0073 0000 0000 0000 " ASCII_2 "\n"
205+
206+
#define PAT_4 ADDRESS1 ": ???????? ???????? ???????? ???????? ???????? ???????? ???????? ????????\n" \
207+
ADDRESS2 ": dce0ffff 646a0023 6e692f6b 6e726574 6c2f6c61 6564616f 614e2f72 65766974 " ASCII_1 "\n" \
208+
ADDRESS3 ": 7262694c 65697261 00000073 00000000 " ASCII_2 "\n"
209+
210+
#define PAT_8 ADDRESS1 ": ???????????????? ???????????????? ???????????????? ????????????????\n" \
211+
ADDRESS2 ": 646a0023dce0ffff 6e7265746e692f6b 6564616f6c2f6c61 65766974614e2f72 " ASCII_1 "\n" \
212+
ADDRESS3 ": 656972617262694c 0000000000000073 " ASCII_2 "\n"
206213
#else
207-
(address) 0
208-
#endif
209-
;
214+
#define PAT_2 ADDRESS1 ": ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ????\n" \
215+
ADDRESS2 ": ffff e0dc 2300 6a64 6b2f 696e 7465 726e 616c 2f6c 6f61 6465 722f 4e61 7469 7665 " ASCII_1 "\n" \
216+
ADDRESS3 ": 4c69 6272 6172 6965 7300 0000 0000 0000 " ASCII_2 "\n"
210217

211-
ResourceMark rm;
212-
char buf[64];
213-
stringStream ss(buf, sizeof(buf));
214-
outputStream* out = &ss;
215-
// outputStream* out = tty; // enable for printout
216-
217-
// Test dumping unreadable memory
218-
// Exclude test for Windows for now, since it needs SEH handling to work which cannot be
219-
// guaranteed when we call directly into VM code. (see JDK-8220220)
220-
#ifndef _WIN32
221-
do_test_print_hex_dump(unreadable, 100, 1, pattern_not_readable[0]);
222-
do_test_print_hex_dump(unreadable, 100, 2, pattern_not_readable[1]);
223-
do_test_print_hex_dump(unreadable, 100, 4, pattern_not_readable[2]);
224-
do_test_print_hex_dump(unreadable, 100, 8, pattern_not_readable[3]);
218+
#define PAT_4 ADDRESS1 ": ???????? ???????? ???????? ???????? ???????? ???????? ???????? ????????\n" \
219+
ADDRESS2 ": ffffe0dc 23006a64 6b2f696e 7465726e 616c2f6c 6f616465 722f4e61 74697665 " ASCII_1 "\n" \
220+
ADDRESS3 ": 4c696272 61726965 73000000 00000000 " ASCII_2 "\n"
221+
222+
#define PAT_8 ADDRESS1 ": ???????????????? ???????????????? ???????????????? ????????????????\n" \
223+
ADDRESS2 ": ffffe0dc23006a64 6b2f696e7465726e 616c2f6c6f616465 722f4e6174697665 " ASCII_1 "\n" \
224+
ADDRESS3 ": 4c69627261726965 7300000000000000 " ASCII_2 "\n"
225225
#endif
226226

227-
// Test dumping readable memory
228-
address arr = (address)os::malloc(100, mtInternal);
229-
for (u1 c = 0; c < 100; c++) {
230-
arr[c] = c;
231-
}
227+
constexpr uint8_t bytes[] = {
228+
0xff, 0xff, 0xe0, 0xdc, 0x23, 0x00, 0x6a, 0x64, 0x6b, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
229+
0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x2f, 0x4e, 0x61, 0x74, 0x69, 0x76, 0x65,
230+
0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
231+
};
232+
233+
// two pages, first one protected.
234+
const size_t ps = os::vm_page_size();
235+
char* two_pages = os::reserve_memory(ps * 2, false, mtTest);
236+
os::commit_memory(two_pages, ps * 2, false);
237+
os::protect_memory(two_pages, ps, os::MEM_PROT_NONE, true);
238+
239+
memcpy(two_pages + ps, bytes, sizeof(bytes));
240+
241+
// print
242+
const const_address from = (const_address) two_pages + ps - 32;
243+
const const_address to = (const_address) from + 32 + sizeof(bytes);
244+
const const_address logical_start = (const_address) LP64_ONLY(0xAAAAAAAAAA00ULL) NOT_LP64(0xAAAAAA00ULL);
232245

233-
// properly aligned
234-
do_test_print_hex_dump(arr, 100, 1, pattern[0]);
235-
do_test_print_hex_dump(arr, 100, 2, pattern[1]);
236-
do_test_print_hex_dump(arr, 100, 4, pattern[2]);
237-
do_test_print_hex_dump(arr, 100, 8, pattern[3]);
246+
do_test_print_hex_dump(from, to, 1, 32, logical_start, PAT_1);
247+
do_test_print_hex_dump(from, to, 2, 32, logical_start, PAT_2);
248+
do_test_print_hex_dump(from, to, 4, 32, logical_start, PAT_4);
249+
do_test_print_hex_dump(from, to, 8, 32, logical_start, PAT_8);
238250

239-
// Not properly aligned. Should automatically down-align by unitsize
240-
do_test_print_hex_dump(arr + 1, 100, 2, pattern[1]);
241-
do_test_print_hex_dump(arr + 1, 100, 4, pattern[2]);
242-
do_test_print_hex_dump(arr + 1, 100, 8, pattern[3]);
251+
// unaligned printing, should align to next lower unitsize
252+
do_test_print_hex_dump(from + 1, to, 2, 32, logical_start, PAT_2);
253+
do_test_print_hex_dump(from + 1, to, 4, 32, logical_start, PAT_4);
254+
do_test_print_hex_dump(from + 1, to, 8, 32, logical_start, PAT_8);
243255

244-
os::free(arr);
256+
os::release_memory(two_pages, ps * 2);
245257
}
258+
#endif // not AIX
246259

247260
//////////////////////////////////////////////////////////////////////////////
248261
// Test os::vsnprintf and friends.

0 commit comments

Comments
 (0)