8273152: Refactor CDS FileMapHeader loading code
Reviewed-by: ccheung, iklam
This commit is contained in:
parent
920e70701d
commit
8de77634c4
@ -1128,10 +1128,6 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo,
|
||||
print_region_stats(mapinfo, closed_heap_regions, open_heap_regions);
|
||||
|
||||
mapinfo->set_requested_base((char*)MetaspaceShared::requested_base_address());
|
||||
if (mapinfo->header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
||||
mapinfo->set_header_base_archive_name_size(strlen(Arguments::GetSharedArchivePath()) + 1);
|
||||
mapinfo->set_header_base_archive_is_default(FLAG_IS_DEFAULT(SharedArchiveFile));
|
||||
}
|
||||
mapinfo->set_header_crc(mapinfo->compute_header_crc());
|
||||
// After this point, we should not write any data into mapinfo->header() since this
|
||||
// would corrupt its checksum we have calculated before.
|
||||
|
@ -31,15 +31,17 @@
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
CDSConst CDSConstants::offsets[] = {
|
||||
{ "CDSFileMapHeaderBase::_magic", offset_of(CDSFileMapHeaderBase, _magic) },
|
||||
{ "CDSFileMapHeaderBase::_crc", offset_of(CDSFileMapHeaderBase, _crc) },
|
||||
{ "CDSFileMapHeaderBase::_version", offset_of(CDSFileMapHeaderBase, _version) },
|
||||
{ "CDSFileMapHeaderBase::_space[0]", offset_of(CDSFileMapHeaderBase, _space) },
|
||||
{ "FileMapHeader::_jvm_ident", offset_of(FileMapHeader, _jvm_ident) },
|
||||
{ "FileMapHeader::_base_archive_name_size", offset_of(FileMapHeader, _base_archive_name_size) },
|
||||
{ "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc) },
|
||||
{ "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used) },
|
||||
{ "DynamicArchiveHeader::_base_region_crc", offset_of(DynamicArchiveHeader, _base_region_crc) }
|
||||
{ "GenericCDSFileMapHeader::_magic", offset_of(GenericCDSFileMapHeader, _magic) },
|
||||
{ "GenericCDSFileMapHeader::_crc", offset_of(GenericCDSFileMapHeader, _crc) },
|
||||
{ "GenericCDSFileMapHeader::_version", offset_of(GenericCDSFileMapHeader, _version) },
|
||||
{ "GenericCDSFileMapHeader::_header_size", offset_of(GenericCDSFileMapHeader, _header_size) },
|
||||
{ "GenericCDSFileMapHeader::_base_archive_path_offset", offset_of(GenericCDSFileMapHeader, _base_archive_path_offset) },
|
||||
{ "GenericCDSFileMapHeader::_base_archive_name_size", offset_of(GenericCDSFileMapHeader, _base_archive_name_size) },
|
||||
{ "CDSFileMapHeaderBase::_space[0]", offset_of(CDSFileMapHeaderBase, _space) },
|
||||
{ "FileMapHeader::_jvm_ident", offset_of(FileMapHeader, _jvm_ident) },
|
||||
{ "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc) },
|
||||
{ "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used) },
|
||||
{ "DynamicArchiveHeader::_base_region_crc", offset_of(DynamicArchiveHeader, _base_region_crc) }
|
||||
};
|
||||
|
||||
CDSConst CDSConstants::constants[] = {
|
||||
|
@ -180,14 +180,15 @@ public:
|
||||
void DynamicArchiveBuilder::init_header() {
|
||||
FileMapInfo* mapinfo = new FileMapInfo(false);
|
||||
assert(FileMapInfo::dynamic_info() == mapinfo, "must be");
|
||||
FileMapInfo* base_info = FileMapInfo::current_info();
|
||||
// header only be available after populate_header
|
||||
mapinfo->populate_header(base_info->core_region_alignment());
|
||||
_header = mapinfo->dynamic_header();
|
||||
|
||||
FileMapInfo* base_info = FileMapInfo::current_info();
|
||||
_header->set_base_header_crc(base_info->crc());
|
||||
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
|
||||
_header->set_base_region_crc(i, base_info->space_crc(i));
|
||||
}
|
||||
_header->populate(base_info, base_info->core_region_alignment());
|
||||
}
|
||||
|
||||
void DynamicArchiveBuilder::release_header() {
|
||||
@ -325,7 +326,7 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data) {
|
||||
size_t file_size = pointer_delta(top, base, sizeof(char));
|
||||
|
||||
log_info(cds, dynamic)("Written dynamic archive " PTR_FORMAT " - " PTR_FORMAT
|
||||
" [" SIZE_FORMAT " bytes header, " SIZE_FORMAT " bytes total]",
|
||||
" [" UINT32_FORMAT " bytes header, " SIZE_FORMAT " bytes total]",
|
||||
p2i(base), p2i(top), _header->header_size(), file_size);
|
||||
|
||||
log_info(cds, dynamic)("%d klasses; %d symbols", klasses()->length(), symbols()->length());
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/globals_extension.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
@ -169,21 +170,13 @@ template <int N> static void get_header_version(char (&header_version) [N]) {
|
||||
FileMapInfo::FileMapInfo(bool is_static) {
|
||||
memset((void*)this, 0, sizeof(FileMapInfo));
|
||||
_is_static = is_static;
|
||||
size_t header_size;
|
||||
if (is_static) {
|
||||
if (_is_static) {
|
||||
assert(_current_info == NULL, "must be singleton"); // not thread safe
|
||||
_current_info = this;
|
||||
header_size = sizeof(FileMapHeader);
|
||||
} else {
|
||||
assert(_dynamic_archive_info == NULL, "must be singleton"); // not thread safe
|
||||
_dynamic_archive_info = this;
|
||||
header_size = sizeof(DynamicArchiveHeader);
|
||||
}
|
||||
_header = (FileMapHeader*)os::malloc(header_size, mtInternal);
|
||||
memset((void*)_header, 0, header_size);
|
||||
_header->set_header_size(header_size);
|
||||
_header->set_version(INVALID_CDS_ARCHIVE_VERSION);
|
||||
_header->set_has_platform_or_app_classes(true);
|
||||
_file_offset = 0;
|
||||
_file_open = false;
|
||||
}
|
||||
@ -199,16 +192,49 @@ FileMapInfo::~FileMapInfo() {
|
||||
}
|
||||
|
||||
void FileMapInfo::populate_header(size_t core_region_alignment) {
|
||||
header()->populate(this, core_region_alignment);
|
||||
assert(_header == NULL, "Sanity check");
|
||||
size_t c_header_size;
|
||||
size_t header_size;
|
||||
size_t base_archive_name_size = 0;
|
||||
size_t base_archive_path_offset = 0;
|
||||
if (is_static()) {
|
||||
c_header_size = sizeof(FileMapHeader);
|
||||
header_size = c_header_size;
|
||||
} else {
|
||||
// dynamic header including base archive name for non-default base archive
|
||||
c_header_size = sizeof(DynamicArchiveHeader);
|
||||
header_size = c_header_size;
|
||||
if (!FLAG_IS_DEFAULT(SharedArchiveFile)) {
|
||||
base_archive_name_size = strlen(Arguments::GetSharedArchivePath()) + 1;
|
||||
header_size += base_archive_name_size;
|
||||
base_archive_path_offset = c_header_size;
|
||||
}
|
||||
}
|
||||
_header = (FileMapHeader*)os::malloc(header_size, mtInternal);
|
||||
memset((void*)_header, 0, header_size);
|
||||
_header->populate(this,
|
||||
core_region_alignment,
|
||||
header_size,
|
||||
base_archive_name_size,
|
||||
base_archive_path_offset);
|
||||
}
|
||||
|
||||
void FileMapHeader::populate(FileMapInfo* mapinfo, size_t core_region_alignment) {
|
||||
if (DynamicDumpSharedSpaces) {
|
||||
_magic = CDS_DYNAMIC_ARCHIVE_MAGIC;
|
||||
} else {
|
||||
_magic = CDS_ARCHIVE_MAGIC;
|
||||
void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
|
||||
size_t header_size, size_t base_archive_name_size,
|
||||
size_t base_archive_path_offset) {
|
||||
// 1. We require _generic_header._magic to be at the beginning of the file
|
||||
// 2. FileMapHeader also assumes that _generic_header is at the beginning of the file
|
||||
assert(offset_of(FileMapHeader, _generic_header) == 0, "must be");
|
||||
set_header_size((unsigned int)header_size);
|
||||
set_base_archive_path_offset((unsigned int)base_archive_path_offset);
|
||||
set_base_archive_name_size((unsigned int)base_archive_name_size);
|
||||
set_magic(DynamicDumpSharedSpaces ? CDS_DYNAMIC_ARCHIVE_MAGIC : CDS_ARCHIVE_MAGIC);
|
||||
set_version(CURRENT_CDS_ARCHIVE_VERSION);
|
||||
|
||||
if (!info->is_static() && base_archive_name_size != 0) {
|
||||
// copy base archive name
|
||||
copy_base_archive_name(Arguments::GetSharedArchivePath());
|
||||
}
|
||||
_version = CURRENT_CDS_ARCHIVE_VERSION;
|
||||
_core_region_alignment = core_region_alignment;
|
||||
_obj_alignment = ObjectAlignmentInBytes;
|
||||
_compact_strings = CompactStrings;
|
||||
@ -245,22 +271,29 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t core_region_alignment)
|
||||
_requested_base_address = (char*)SharedBaseAddress;
|
||||
_mapped_base_address = (char*)SharedBaseAddress;
|
||||
_allow_archiving_with_java_agent = AllowArchivingWithJavaAgent;
|
||||
// the following 2 fields will be set in write_header for dynamic archive header
|
||||
_base_archive_name_size = 0;
|
||||
_base_archive_is_default = false;
|
||||
|
||||
if (!DynamicDumpSharedSpaces) {
|
||||
set_shared_path_table(mapinfo->_shared_path_table);
|
||||
set_shared_path_table(info->_shared_path_table);
|
||||
CDS_JAVA_HEAP_ONLY(_heap_obj_roots = CompressedOops::encode(HeapShared::roots());)
|
||||
}
|
||||
}
|
||||
|
||||
void FileMapHeader::copy_base_archive_name(const char* archive) {
|
||||
assert(base_archive_name_size() != 0, "_base_archive_name_size not set");
|
||||
assert(base_archive_path_offset() != 0, "_base_archive_path_offset not set");
|
||||
assert(header_size() > sizeof(*this), "_base_archive_name_size not included in header size?");
|
||||
memcpy((char*)this + base_archive_path_offset(), archive, base_archive_name_size());
|
||||
}
|
||||
|
||||
void FileMapHeader::print(outputStream* st) {
|
||||
ResourceMark rm;
|
||||
|
||||
st->print_cr("- magic: 0x%08x", _magic);
|
||||
st->print_cr("- crc: 0x%08x", _crc);
|
||||
st->print_cr("- version: %d", _version);
|
||||
st->print_cr("- magic: 0x%08x", magic());
|
||||
st->print_cr("- crc: 0x%08x", crc());
|
||||
st->print_cr("- version: %d", version());
|
||||
st->print_cr("- header_size: " UINT32_FORMAT, header_size());
|
||||
st->print_cr("- base_archive_path_offset: " UINT32_FORMAT, base_archive_path_offset());
|
||||
st->print_cr("- base_archive_name_size: " UINT32_FORMAT, base_archive_name_size());
|
||||
|
||||
for (int i = 0; i < NUM_CDS_REGIONS; i++) {
|
||||
FileMapRegion* si = space_at(i);
|
||||
@ -268,7 +301,6 @@ void FileMapHeader::print(outputStream* st) {
|
||||
}
|
||||
st->print_cr("============ end regions ======== ");
|
||||
|
||||
st->print_cr("- header_size: " SIZE_FORMAT, _header_size);
|
||||
st->print_cr("- core_region_alignment: " SIZE_FORMAT, _core_region_alignment);
|
||||
st->print_cr("- obj_alignment: %d", _obj_alignment);
|
||||
st->print_cr("- narrow_oop_base: " INTPTR_FORMAT, p2i(_narrow_oop_base));
|
||||
@ -283,9 +315,7 @@ void FileMapHeader::print(outputStream* st) {
|
||||
st->print_cr("- cloned_vtables_offset: " SIZE_FORMAT_HEX, _cloned_vtables_offset);
|
||||
st->print_cr("- serialized_data_offset: " SIZE_FORMAT_HEX, _serialized_data_offset);
|
||||
st->print_cr("- heap_end: " INTPTR_FORMAT, p2i(_heap_end));
|
||||
st->print_cr("- base_archive_is_default: %d", _base_archive_is_default);
|
||||
st->print_cr("- jvm_ident: %s", _jvm_ident);
|
||||
st->print_cr("- base_archive_name_size: " SIZE_FORMAT, _base_archive_name_size);
|
||||
st->print_cr("- shared_path_table_offset: " SIZE_FORMAT_HEX, _shared_path_table_offset);
|
||||
st->print_cr("- shared_path_table_size: %d", _shared_path_table_size);
|
||||
st->print_cr("- app_class_paths_start_index: %d", _app_class_paths_start_index);
|
||||
@ -1012,119 +1042,166 @@ void FileMapInfo::validate_non_existent_class_paths() {
|
||||
}
|
||||
}
|
||||
|
||||
// a utility class for checking file header
|
||||
class FileHeaderHelper {
|
||||
int _fd;
|
||||
GenericCDSFileMapHeader _header;
|
||||
|
||||
public:
|
||||
FileHeaderHelper() {
|
||||
_fd = -1;
|
||||
}
|
||||
|
||||
~FileHeaderHelper() {
|
||||
if (_fd != -1) {
|
||||
os::close(_fd);
|
||||
}
|
||||
}
|
||||
|
||||
bool initialize(const char* archive_name) {
|
||||
_fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
|
||||
if (_fd < 0) {
|
||||
return false;
|
||||
}
|
||||
return initialize(_fd);
|
||||
}
|
||||
|
||||
// for an already opened file, do not set _fd
|
||||
bool initialize(int fd) {
|
||||
assert(fd != -1, "Archive should be opened");
|
||||
size_t size = sizeof(GenericCDSFileMapHeader);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
size_t n = os::read(fd, (void*)&_header, (unsigned int)size);
|
||||
if (n != size) {
|
||||
vm_exit_during_initialization("Unable to read generic CDS file map header from shared archive");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
GenericCDSFileMapHeader* get_generic_file_header() {
|
||||
return &_header;
|
||||
}
|
||||
|
||||
bool read_base_archive_name(char** target) {
|
||||
assert(_fd != -1, "Archive should be open");
|
||||
size_t name_size = (size_t)_header._base_archive_name_size;
|
||||
assert(name_size != 0, "For non-default base archive, name size should be non-zero!");
|
||||
*target = NEW_C_HEAP_ARRAY(char, name_size, mtInternal);
|
||||
lseek(_fd, _header._base_archive_path_offset, SEEK_SET); // position to correct offset.
|
||||
size_t n = os::read(_fd, *target, (unsigned int)name_size);
|
||||
if (n != name_size) {
|
||||
log_info(cds)("Unable to read base archive name from archive");
|
||||
FREE_C_HEAP_ARRAY(char, *target);
|
||||
return false;
|
||||
}
|
||||
if (!os::file_exists(*target)) {
|
||||
log_info(cds)("Base archive %s does not exist", *target);
|
||||
FREE_C_HEAP_ARRAY(char, *target);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {
|
||||
int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
|
||||
if (fd < 0) {
|
||||
FileHeaderHelper file_helper;
|
||||
if (!file_helper.initialize(archive_name)) {
|
||||
// do not vm_exit_during_initialization here because Arguments::init_shared_archive_paths()
|
||||
// requires a shared archive name. The open_for_read() function will log a message regarding
|
||||
// failure in opening a shared archive.
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t sz = is_static ? sizeof(FileMapHeader) : sizeof(DynamicArchiveHeader);
|
||||
void* header = os::malloc(sz, mtInternal);
|
||||
memset(header, 0, sz);
|
||||
size_t n = os::read(fd, header, (unsigned int)sz);
|
||||
if (n != sz) {
|
||||
os::free(header);
|
||||
os::close(fd);
|
||||
vm_exit_during_initialization("Unable to read header from shared archive", archive_name);
|
||||
return false;
|
||||
}
|
||||
GenericCDSFileMapHeader* header = file_helper.get_generic_file_header();
|
||||
if (is_static) {
|
||||
FileMapHeader* static_header = (FileMapHeader*)header;
|
||||
if (static_header->magic() != CDS_ARCHIVE_MAGIC) {
|
||||
os::free(header);
|
||||
os::close(fd);
|
||||
if (header->_magic != CDS_ARCHIVE_MAGIC) {
|
||||
vm_exit_during_initialization("Not a base shared archive", archive_name);
|
||||
return false;
|
||||
}
|
||||
if (header->_base_archive_path_offset != 0) {
|
||||
log_info(cds)("_base_archive_path_offset should be 0");
|
||||
log_info(cds)("_base_archive_path_offset = " UINT32_FORMAT, header->_base_archive_path_offset);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)header;
|
||||
if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
||||
os::free(header);
|
||||
os::close(fd);
|
||||
if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
||||
vm_exit_during_initialization("Not a top shared archive", archive_name);
|
||||
return false;
|
||||
}
|
||||
unsigned int name_size = header->_base_archive_name_size;
|
||||
unsigned int path_offset = header->_base_archive_path_offset;
|
||||
unsigned int header_size = header->_header_size;
|
||||
if (path_offset + name_size != header_size) {
|
||||
log_info(cds)("_header_size should be equal to _base_archive_path_offset plus _base_archive_name_size");
|
||||
log_info(cds)(" _base_archive_name_size = " UINT32_FORMAT, name_size);
|
||||
log_info(cds)(" _base_archive_path_offset = " UINT32_FORMAT, path_offset);
|
||||
log_info(cds)(" _header_size = " UINT32_FORMAT, header_size);
|
||||
return false;
|
||||
}
|
||||
char* base_name = NULL;
|
||||
if (!file_helper.read_base_archive_name(&base_name)) {
|
||||
return false;
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(char, base_name);
|
||||
}
|
||||
os::free(header);
|
||||
os::close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
|
||||
int* size, char** base_archive_name) {
|
||||
int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
|
||||
if (fd < 0) {
|
||||
*size = 0;
|
||||
char** base_archive_name) {
|
||||
FileHeaderHelper file_helper;
|
||||
if (!file_helper.initialize(archive_name)) {
|
||||
return false;
|
||||
}
|
||||
GenericCDSFileMapHeader* header = file_helper.get_generic_file_header();
|
||||
if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
||||
// Not a dynamic header, no need to proceed further.
|
||||
return false;
|
||||
}
|
||||
|
||||
// read the header as a dynamic archive header
|
||||
size_t sz = sizeof(DynamicArchiveHeader);
|
||||
DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)os::malloc(sz, mtInternal);
|
||||
size_t n = os::read(fd, dynamic_header, (unsigned int)sz);
|
||||
if (n != sz) {
|
||||
fail_continue("Unable to read the file header.");
|
||||
os::free(dynamic_header);
|
||||
os::close(fd);
|
||||
if ((header->_base_archive_name_size == 0 && header->_base_archive_path_offset != 0) ||
|
||||
(header->_base_archive_name_size != 0 && header->_base_archive_path_offset == 0)) {
|
||||
fail_continue("Default base archive not set correct");
|
||||
return false;
|
||||
}
|
||||
if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
||||
// Not a dynamic header, no need to proceed further.
|
||||
*size = 0;
|
||||
os::free(dynamic_header);
|
||||
os::close(fd);
|
||||
return false;
|
||||
}
|
||||
if (dynamic_header->base_archive_is_default()) {
|
||||
if (header->_base_archive_name_size == 0 &&
|
||||
header->_base_archive_path_offset == 0) {
|
||||
*base_archive_name = Arguments::get_default_shared_archive_path();
|
||||
} else {
|
||||
// read the base archive name
|
||||
size_t name_size = dynamic_header->base_archive_name_size();
|
||||
if (name_size == 0) {
|
||||
os::free(dynamic_header);
|
||||
os::close(fd);
|
||||
return false;
|
||||
}
|
||||
*base_archive_name = NEW_C_HEAP_ARRAY(char, name_size, mtInternal);
|
||||
n = os::read(fd, *base_archive_name, (unsigned int)name_size);
|
||||
if (n != name_size) {
|
||||
fail_continue("Unable to read the base archive name from the header.");
|
||||
FREE_C_HEAP_ARRAY(char, *base_archive_name);
|
||||
if (!file_helper.read_base_archive_name(base_archive_name)) {
|
||||
*base_archive_name = NULL;
|
||||
os::free(dynamic_header);
|
||||
os::close(fd);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
os::free(dynamic_header);
|
||||
os::close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read the FileMapInfo information from the file.
|
||||
|
||||
bool FileMapInfo::init_from_file(int fd) {
|
||||
size_t sz = is_static() ? sizeof(FileMapHeader) : sizeof(DynamicArchiveHeader);
|
||||
size_t n = os::read(fd, header(), (unsigned int)sz);
|
||||
if (n != sz) {
|
||||
FileHeaderHelper file_helper;
|
||||
if (!file_helper.initialize(fd)) {
|
||||
fail_continue("Unable to read the file header.");
|
||||
return false;
|
||||
}
|
||||
GenericCDSFileMapHeader* gen_header = file_helper.get_generic_file_header();
|
||||
|
||||
if (!Arguments::has_jimage()) {
|
||||
FileMapInfo::fail_continue("The shared archive file cannot be used with an exploded module build.");
|
||||
unsigned int expected_magic = is_static() ? CDS_ARCHIVE_MAGIC : CDS_DYNAMIC_ARCHIVE_MAGIC;
|
||||
if (gen_header->_magic != expected_magic) {
|
||||
log_info(cds)("_magic expected: 0x%08x", expected_magic);
|
||||
log_info(cds)(" actual: 0x%08x", gen_header->_magic);
|
||||
FileMapInfo::fail_continue("The shared archive file has a bad magic number.");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int expected_magic = is_static() ? CDS_ARCHIVE_MAGIC : CDS_DYNAMIC_ARCHIVE_MAGIC;
|
||||
if (header()->magic() != expected_magic) {
|
||||
log_info(cds)("_magic expected: 0x%08x", expected_magic);
|
||||
log_info(cds)(" actual: 0x%08x", header()->magic());
|
||||
FileMapInfo::fail_continue("The shared archive file has a bad magic number.");
|
||||
_header = (FileMapHeader*)os::malloc(gen_header->_header_size, mtInternal);
|
||||
lseek(fd, 0, SEEK_SET); // reset to begin of the archive
|
||||
size_t size = gen_header->_header_size;
|
||||
size_t n = os::read(fd, (void*)_header, (unsigned int)size);
|
||||
if (n != size) {
|
||||
fail_continue("Failed to read file header from the top archive file\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1135,11 +1212,17 @@ bool FileMapInfo::init_from_file(int fd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header()->header_size() != sz) {
|
||||
log_info(cds)("_header_size expected: " SIZE_FORMAT, sz);
|
||||
log_info(cds)(" actual: " SIZE_FORMAT, header()->header_size());
|
||||
FileMapInfo::fail_continue("The shared archive file has an incorrect header size.");
|
||||
return false;
|
||||
unsigned int base_offset = header()->base_archive_path_offset();
|
||||
unsigned int name_size = header()->base_archive_name_size();
|
||||
unsigned int header_size = header()->header_size();
|
||||
if (base_offset != 0 && name_size != 0) {
|
||||
if (header_size != base_offset + name_size) {
|
||||
log_info(cds)("_header_size: " UINT32_FORMAT, header_size);
|
||||
log_info(cds)("base_archive_name_size: " UINT32_FORMAT, name_size);
|
||||
log_info(cds)("base_archive_path_offset: " UINT32_FORMAT, base_offset);
|
||||
FileMapInfo::fail_continue("The shared archive file has an incorrect header size.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const char* actual_ident = header()->jvm_ident();
|
||||
@ -1169,7 +1252,7 @@ bool FileMapInfo::init_from_file(int fd) {
|
||||
}
|
||||
}
|
||||
|
||||
_file_offset = n + header()->base_archive_name_size(); // accounts for the size of _base_archive_name
|
||||
_file_offset = header()->header_size(); // accounts for the size of _base_archive_name
|
||||
|
||||
if (is_static()) {
|
||||
// just checking the last region is sufficient since the archive is written
|
||||
@ -1253,16 +1336,12 @@ void FileMapInfo::open_for_write(const char* path) {
|
||||
// Seek past the header. We will write the header after all regions are written
|
||||
// and their CRCs computed.
|
||||
size_t header_bytes = header()->header_size();
|
||||
if (header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
||||
header_bytes += strlen(Arguments::GetSharedArchivePath()) + 1;
|
||||
}
|
||||
|
||||
header_bytes = align_up(header_bytes, MetaspaceShared::core_region_alignment());
|
||||
_file_offset = header_bytes;
|
||||
seek_to_position(_file_offset);
|
||||
}
|
||||
|
||||
|
||||
// Write the header to the file, seek to the next allocation boundary.
|
||||
|
||||
void FileMapInfo::write_header() {
|
||||
@ -1270,13 +1349,6 @@ void FileMapInfo::write_header() {
|
||||
seek_to_position(_file_offset);
|
||||
assert(is_file_position_aligned(), "must be");
|
||||
write_bytes(header(), header()->header_size());
|
||||
|
||||
if (header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
||||
char* base_archive_name = (char*)Arguments::GetSharedArchivePath();
|
||||
if (base_archive_name != NULL) {
|
||||
write_bytes(base_archive_name, header()->base_archive_name_size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t FileMapRegion::used_aligned() const {
|
||||
@ -2220,6 +2292,11 @@ bool FileMapInfo::initialize() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Arguments::has_jimage()) {
|
||||
FileMapInfo::fail_continue("The shared archive file cannot be used with an exploded module build.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!open_for_read()) {
|
||||
return false;
|
||||
}
|
||||
@ -2258,9 +2335,9 @@ void FileMapHeader::set_as_offset(char* p, size_t *offset) {
|
||||
|
||||
int FileMapHeader::compute_crc() {
|
||||
char* start = (char*)this;
|
||||
// start computing from the field after _crc
|
||||
char* buf = (char*)&_crc + sizeof(_crc);
|
||||
size_t sz = _header_size - (buf - start);
|
||||
// start computing from the field after _crc to end of base archive name.
|
||||
char* buf = (char*)&(_generic_header._crc) + sizeof(_generic_header._crc);
|
||||
size_t sz = header_size() - (buf - start);
|
||||
int crc = ClassLoader::crc32(0, buf, (jint)sz);
|
||||
return crc;
|
||||
}
|
||||
|
@ -184,8 +184,6 @@ class FileMapHeader: private CDSFileMapHeaderBase {
|
||||
friend class VMStructs;
|
||||
|
||||
private:
|
||||
size_t _header_size;
|
||||
|
||||
// The following fields record the states of the VM during dump time.
|
||||
// They are compared with the runtime states to see if the archive
|
||||
// can be used.
|
||||
@ -203,15 +201,12 @@ private:
|
||||
size_t _serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize()
|
||||
address _heap_begin; // heap begin at dump time.
|
||||
address _heap_end; // heap end at dump time.
|
||||
bool _base_archive_is_default; // indicates if the base archive is the system default one
|
||||
bool _has_non_jar_in_classpath; // non-jar file entry exists in classpath
|
||||
|
||||
// The following fields are all sanity checks for whether this archive
|
||||
// will function correctly with this JVM and the bootclasspath it's
|
||||
// invoked with.
|
||||
char _jvm_ident[JVM_IDENT_MAX]; // identifier string of the jvm that created this dump
|
||||
// size of the base archive name including NULL terminator
|
||||
size_t _base_archive_name_size;
|
||||
|
||||
// The following is a table of all the boot/app/module path entries that were used
|
||||
// during dumping. At run time, we validate these entries according to their
|
||||
@ -243,17 +238,21 @@ private:
|
||||
}
|
||||
void set_as_offset(char* p, size_t *offset);
|
||||
public:
|
||||
// Accessors -- fields declared in CDSFileMapHeaderBase
|
||||
unsigned int magic() const { return _magic; }
|
||||
int crc() const { return _crc; }
|
||||
int version() const { return _version; }
|
||||
// Accessors -- fields declared in GenericCDSFileMapHeader
|
||||
unsigned int magic() const { return _generic_header._magic; }
|
||||
int crc() const { return _generic_header._crc; }
|
||||
int version() const { return _generic_header._version; }
|
||||
unsigned int header_size() const { return _generic_header._header_size; }
|
||||
unsigned int base_archive_path_offset() const { return _generic_header._base_archive_path_offset; }
|
||||
unsigned int base_archive_name_size() const { return _generic_header._base_archive_name_size; }
|
||||
|
||||
void set_crc(int crc_value) { _crc = crc_value; }
|
||||
void set_version(int v) { _version = v; }
|
||||
void set_magic(unsigned int m) { _generic_header._magic = m; }
|
||||
void set_crc(int crc_value) { _generic_header._crc = crc_value; }
|
||||
void set_version(int v) { _generic_header._version = v; }
|
||||
void set_header_size(unsigned int s) { _generic_header._header_size = s; }
|
||||
void set_base_archive_path_offset(unsigned int s) { _generic_header._base_archive_path_offset = s; }
|
||||
void set_base_archive_name_size(unsigned int s) { _generic_header._base_archive_name_size = s; }
|
||||
|
||||
// Accessors -- fields declared in FileMapHeader
|
||||
|
||||
size_t header_size() const { return _header_size; }
|
||||
size_t core_region_alignment() const { return _core_region_alignment; }
|
||||
int obj_alignment() const { return _obj_alignment; }
|
||||
address narrow_oop_base() const { return _narrow_oop_base; }
|
||||
@ -267,9 +266,7 @@ public:
|
||||
char* serialized_data() const { return from_mapped_offset(_serialized_data_offset); }
|
||||
address heap_begin() const { return _heap_begin; }
|
||||
address heap_end() const { return _heap_end; }
|
||||
bool base_archive_is_default() const { return _base_archive_is_default; }
|
||||
const char* jvm_ident() const { return _jvm_ident; }
|
||||
size_t base_archive_name_size() const { return _base_archive_name_size; }
|
||||
char* requested_base_address() const { return _requested_base_address; }
|
||||
char* mapped_base_address() const { return _mapped_base_address; }
|
||||
bool has_platform_or_app_classes() const { return _has_platform_or_app_classes; }
|
||||
@ -287,12 +284,10 @@ public:
|
||||
void set_has_platform_or_app_classes(bool v) { _has_platform_or_app_classes = v; }
|
||||
void set_cloned_vtables(char* p) { set_as_offset(p, &_cloned_vtables_offset); }
|
||||
void set_serialized_data(char* p) { set_as_offset(p, &_serialized_data_offset); }
|
||||
void set_base_archive_name_size(size_t s) { _base_archive_name_size = s; }
|
||||
void set_base_archive_is_default(bool b) { _base_archive_is_default = b; }
|
||||
void set_header_size(size_t s) { _header_size = s; }
|
||||
void set_ptrmap_size_in_bits(size_t s) { _ptrmap_size_in_bits = s; }
|
||||
void set_mapped_base_address(char* p) { _mapped_base_address = p; }
|
||||
void set_heap_obj_roots(narrowOop r) { _heap_obj_roots = r; }
|
||||
void copy_base_archive_name(const char* name);
|
||||
|
||||
void set_shared_path_table(SharedPathTable table) {
|
||||
set_as_offset((char*)table.table(), &_shared_path_table_offset);
|
||||
@ -317,8 +312,8 @@ public:
|
||||
return FileMapRegion::cast(&_space[i]);
|
||||
}
|
||||
|
||||
void populate(FileMapInfo* info, size_t core_region_alignment);
|
||||
|
||||
void populate(FileMapInfo *info, size_t core_region_alignment, size_t header_size,
|
||||
size_t base_archive_name_size, size_t base_archive_path_offset);
|
||||
static bool is_valid_region(int region) {
|
||||
return (0 <= region && region < NUM_CDS_REGIONS);
|
||||
}
|
||||
@ -363,7 +358,7 @@ private:
|
||||
|
||||
public:
|
||||
static bool get_base_archive_name_from_header(const char* archive_name,
|
||||
int* size, char** base_archive_name);
|
||||
char** base_archive_name);
|
||||
static bool check_archive(const char* archive_name, bool is_static);
|
||||
static SharedPathTable shared_path_table() {
|
||||
return _shared_path_table;
|
||||
@ -398,9 +393,6 @@ public:
|
||||
int narrow_klass_shift() const { return header()->narrow_klass_shift(); }
|
||||
size_t core_region_alignment() const { return header()->core_region_alignment(); }
|
||||
|
||||
void set_header_base_archive_name_size(size_t size) { header()->set_base_archive_name_size(size); }
|
||||
void set_header_base_archive_is_default(bool is_default) { header()->set_base_archive_is_default(is_default); }
|
||||
|
||||
CompressedOops::Mode narrow_oop_mode() const { return header()->narrow_oop_mode(); }
|
||||
jshort app_module_paths_start_index() const { return header()->app_module_paths_start_index(); }
|
||||
jshort app_class_paths_start_index() const { return header()->app_class_paths_start_index(); }
|
||||
|
@ -38,10 +38,9 @@
|
||||
#define NUM_CDS_REGIONS 7 // this must be the same as MetaspaceShared::n_regions
|
||||
#define CDS_ARCHIVE_MAGIC 0xf00baba2
|
||||
#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
|
||||
#define CURRENT_CDS_ARCHIVE_VERSION 11
|
||||
#define INVALID_CDS_ARCHIVE_VERSION -1
|
||||
#define CURRENT_CDS_ARCHIVE_VERSION 12
|
||||
|
||||
struct CDSFileMapRegion {
|
||||
typedef struct CDSFileMapRegion {
|
||||
int _crc; // CRC checksum of this region.
|
||||
int _read_only; // read only region?
|
||||
int _allow_exec; // executable code in this region?
|
||||
@ -58,15 +57,37 @@ struct CDSFileMapRegion {
|
||||
size_t _oopmap_offset; // Bitmap for relocating embedded oops (offset from SharedBaseAddress).
|
||||
size_t _oopmap_size_in_bits;
|
||||
char* _mapped_base; // Actually mapped address (NULL if this region is not mapped).
|
||||
};
|
||||
} CDSFileMapRegion;
|
||||
|
||||
struct CDSFileMapHeaderBase {
|
||||
unsigned int _magic; // identify file type
|
||||
int _crc; // header crc checksum
|
||||
int _version; // must be CURRENT_CDS_ARCHIVE_VERSION
|
||||
struct CDSFileMapRegion _space[NUM_CDS_REGIONS];
|
||||
};
|
||||
// This portion of the archive file header must remain unchanged for _version >= 12.
|
||||
// This makes it possible to read important information from a CDS archive created by
|
||||
// a different version of HotSpot, so that we can automatically regenerate the archive as necessary.
|
||||
typedef struct GenericCDSFileMapHeader {
|
||||
unsigned int _magic; // identification of file type
|
||||
int _crc; // header crc checksum
|
||||
int _version; // CURRENT_CDS_ARCHIVE_VERSION of the jdk that dumped the this archive
|
||||
unsigned int _header_size; // total size of the header, in bytes
|
||||
unsigned int _base_archive_path_offset; // offset where the base archive name is stored
|
||||
// static archive: 0
|
||||
// dynamic archive:
|
||||
// 0 for default base archive
|
||||
// non-zero for non-default base archive
|
||||
// (char*)this + _base_archive_path_offset
|
||||
// points to a 0-terminated string for the base archive name
|
||||
unsigned int _base_archive_name_size; // size of base archive name including ending '\0'
|
||||
// static: 0
|
||||
// dynamic:
|
||||
// 0 for default base archive
|
||||
// non-zero for non-default base archive
|
||||
} GenericCDSFileMapHeader;
|
||||
|
||||
typedef struct CDSFileMapHeaderBase CDSFileMapHeaderBase;
|
||||
// This type is used by the Serviceability Agent to access the contents of
|
||||
// a memory-mapped CDS archive.
|
||||
typedef struct CDSFileMapHeaderBase {
|
||||
// We cannot inherit from GenericCDSFileMapHeader as this type may be used
|
||||
// by both C and C++ code.
|
||||
GenericCDSFileMapHeader _generic_header;
|
||||
CDSFileMapRegion _space[NUM_CDS_REGIONS];
|
||||
} CDSFileMapHeaderBase;
|
||||
|
||||
#endif // SHARE_INCLUDE_CDS_H
|
||||
|
@ -3531,9 +3531,8 @@ bool Arguments::init_shared_archive_paths() {
|
||||
}
|
||||
if (archives == 1) {
|
||||
char* temp_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments);
|
||||
int name_size;
|
||||
bool success =
|
||||
FileMapInfo::get_base_archive_name_from_header(temp_archive_path, &name_size, &SharedArchivePath);
|
||||
FileMapInfo::get_base_archive_name_from_header(temp_archive_path, &SharedArchivePath);
|
||||
if (!success) {
|
||||
SharedArchivePath = temp_archive_path;
|
||||
} else {
|
||||
|
@ -356,26 +356,27 @@ bool init_classsharing_workaround(struct ps_prochandle* ph) {
|
||||
}
|
||||
|
||||
// read CDSFileMapHeaderBase from the file
|
||||
memset(&header, 0, sizeof(CDSFileMapHeaderBase));
|
||||
if ((n = read(fd, &header, sizeof(CDSFileMapHeaderBase)))
|
||||
!= sizeof(CDSFileMapHeaderBase)) {
|
||||
size_t header_size = sizeof(CDSFileMapHeaderBase);
|
||||
memset(&header, 0, header_size);
|
||||
if ((n = read(fd, &header, header_size))
|
||||
!= header_size) {
|
||||
print_debug("can't read shared archive file map header from %s\n", classes_jsa);
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check file magic
|
||||
if (header._magic != CDS_ARCHIVE_MAGIC) {
|
||||
if (header._generic_header._magic != CDS_ARCHIVE_MAGIC) {
|
||||
print_debug("%s has bad shared archive file magic number 0x%x, expecting 0x%x\n",
|
||||
classes_jsa, header._magic, CDS_ARCHIVE_MAGIC);
|
||||
classes_jsa, header._generic_header._magic, CDS_ARCHIVE_MAGIC);
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check version
|
||||
if (header._version != CURRENT_CDS_ARCHIVE_VERSION) {
|
||||
if (header._generic_header._version != CURRENT_CDS_ARCHIVE_VERSION) {
|
||||
print_debug("%s has wrong shared archive file version %d, expecting %d\n",
|
||||
classes_jsa, header._version, CURRENT_CDS_ARCHIVE_VERSION);
|
||||
classes_jsa, header._generic_header._version, CURRENT_CDS_ARCHIVE_VERSION);
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
@ -58,6 +58,8 @@ public class SharedArchiveConsistency {
|
||||
|
||||
public static int num_regions = shared_region_name.length;
|
||||
public static String[] matchMessages = {
|
||||
"UseSharedSpaces: Header checksum verification failed.",
|
||||
"The shared archive file has an incorrect header size.",
|
||||
"Unable to use shared archive",
|
||||
"An error has occurred while processing the shared archive file.",
|
||||
"Checksum verification failed.",
|
||||
@ -158,7 +160,7 @@ public class SharedArchiveConsistency {
|
||||
System.out.println("\n2c. Corrupt _magic, should fail\n");
|
||||
String modMagic = startNewArchive("modify-magic");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modMagic);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetMagic, -1);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetMagic(), -1);
|
||||
output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs);
|
||||
output.shouldContain("The shared archive file has a bad magic number");
|
||||
output.shouldNotContain("Checksum verification failed");
|
||||
@ -170,7 +172,7 @@ public class SharedArchiveConsistency {
|
||||
System.out.println("\n2d. Corrupt _version, should fail\n");
|
||||
String modVersion = startNewArchive("modify-version");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modVersion);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion, 0x00000000);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), 0x00000000);
|
||||
output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs);
|
||||
output.shouldContain("The shared archive file has the wrong version");
|
||||
output.shouldNotContain("Checksum verification failed");
|
||||
@ -213,10 +215,22 @@ public class SharedArchiveConsistency {
|
||||
CDSArchiveUtils.deleteBytesAtRandomPositionAfterHeader(orgJsaFile, deleteBytes, 4096 /*bytes*/);
|
||||
testAndCheck(verifyExecArgs);
|
||||
|
||||
// modify contents in random area
|
||||
System.out.println("\n7. modify Content in random areas, should fail\n");
|
||||
String randomAreas = startNewArchive("random-areas");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, randomAreas);
|
||||
CDSArchiveUtils.modifyRegionContentRandomly(copiedJsa);
|
||||
testAndCheck(verifyExecArgs);
|
||||
|
||||
// modify _base_archive_path_offet to non-zero
|
||||
System.out.println("\n8. modify _base_archive_path_offset to non-zero\n");
|
||||
String baseArchivePathOffsetName = startNewArchive("base-arhive-path-offset");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, baseArchivePathOffsetName);
|
||||
int baseArchivePathOffset = CDSArchiveUtils.baseArchivePathOffset(copiedJsa);
|
||||
System.out.println(" baseArchivePathOffset = " + baseArchivePathOffset);
|
||||
CDSArchiveUtils.writeData(copiedJsa, CDSArchiveUtils.offsetBaseArchivePathOffset(), 1024);
|
||||
baseArchivePathOffset = CDSArchiveUtils.baseArchivePathOffset(copiedJsa);
|
||||
System.out.println("new baseArchivePathOffset = " + baseArchivePathOffset);
|
||||
testAndCheck(verifyExecArgs);
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import jdk.test.lib.cds.CDSArchiveUtils;
|
||||
import jdk.test.lib.cds.CDSTestUtils;
|
||||
import jdk.test.lib.helpers.ClassFileInstaller;
|
||||
|
||||
public class ArchiveConsistency extends DynamicArchiveTestBase {
|
||||
@ -52,6 +53,31 @@ public class ArchiveConsistency extends DynamicArchiveTestBase {
|
||||
doTest(baseArchiveName, topArchiveName);
|
||||
}
|
||||
|
||||
static void runTwo(String base, String top,
|
||||
String jarName, String mainClassName, int exitValue,
|
||||
String ... checkMessages) throws Exception {
|
||||
CDSTestUtils.Result result = run2(base, top,
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=debug",
|
||||
"-XX:+VerifySharedSpaces",
|
||||
"-cp",
|
||||
jarName,
|
||||
mainClassName);
|
||||
if (exitValue == 0) {
|
||||
result.assertNormalExit( output -> {
|
||||
for (String s : checkMessages) {
|
||||
output.shouldContain(s);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
result.assertAbnormalExit( output -> {
|
||||
for (String s : checkMessages) {
|
||||
output.shouldContain(s);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
|
||||
String appJar = ClassFileInstaller.getJarPath("hello.jar");
|
||||
String mainClass = "Hello";
|
||||
@ -68,20 +94,66 @@ public class ArchiveConsistency extends DynamicArchiveTestBase {
|
||||
throw new IOException(jsa + " does not exist!");
|
||||
}
|
||||
|
||||
// Modify the CRC values in the header of the top archive.
|
||||
// 1. Modify the CRC values in the header of the top archive.
|
||||
System.out.println("\n1. Modify the CRC values in the header of the top archive");
|
||||
String modTop = getNewArchiveName("modTopRegionsCrc");
|
||||
File copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, modTop);
|
||||
CDSArchiveUtils.modifyAllRegionsCrc(copiedJsa);
|
||||
|
||||
run2(baseArchiveName, modTop,
|
||||
"-Xlog:class+load",
|
||||
"-Xlog:cds+dynamic=debug,cds=debug",
|
||||
"-XX:+VerifySharedSpaces",
|
||||
"-cp", appJar, mainClass)
|
||||
.assertAbnormalExit(output -> {
|
||||
output.shouldContain("Header checksum verification failed")
|
||||
.shouldContain("Unable to use shared archive")
|
||||
.shouldHaveExitValue(1);
|
||||
});
|
||||
runTwo(baseArchiveName, modTop,
|
||||
appJar, mainClass, 1,
|
||||
new String[] {"Header checksum verification failed",
|
||||
"Unable to use shared archive"});
|
||||
|
||||
// 2. Make header size larger than the archive size
|
||||
System.out.println("\n2. Make header size larger than the archive size");
|
||||
String largerHeaderSize = getNewArchiveName("largerHeaderSize");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, largerHeaderSize);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetHeaderSize(), (int)copiedJsa.length() + 1024);
|
||||
runTwo(baseArchiveName, largerHeaderSize,
|
||||
appJar, mainClass, 1,
|
||||
new String[] {"_header_size should be equal to _base_archive_path_offset plus _base_archive_name_size",
|
||||
"Unable to use shared archive"});
|
||||
|
||||
// 3. Make base archive path offset beyond of header size
|
||||
System.out.println("\n3. Make base archive path offset beyond of header size.");
|
||||
String wrongBaseArchivePathOffset = getNewArchiveName("wrongBaseArchivePathOffset");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseArchivePathOffset);
|
||||
int fileHeaderSize = (int)CDSArchiveUtils.fileHeaderSize(copiedJsa);
|
||||
int baseArchivePathOffset = CDSArchiveUtils.baseArchivePathOffset(copiedJsa);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetBaseArchivePathOffset(), baseArchivePathOffset + 1024);
|
||||
runTwo(baseArchiveName, wrongBaseArchivePathOffset,
|
||||
appJar, mainClass, 1,
|
||||
new String[] {"_header_size should be equal to _base_archive_path_offset plus _base_archive_name_size",
|
||||
"The shared archive file has an incorrect header size",
|
||||
"Unable to use shared archive"});
|
||||
|
||||
// 4. Make base archive path offset points to middle of name size
|
||||
System.out.println("\n4. Make base archive path offset points to middle of name size");
|
||||
String wrongBasePathOffset = getNewArchiveName("wrongBasePathOffset");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBasePathOffset);
|
||||
int baseArchiveNameSize = CDSArchiveUtils.baseArchiveNameSize(copiedJsa);
|
||||
baseArchivePathOffset = CDSArchiveUtils.baseArchivePathOffset(copiedJsa);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, baseArchivePathOffset,
|
||||
baseArchivePathOffset + baseArchiveNameSize/2);
|
||||
runTwo(baseArchiveName, wrongBasePathOffset,
|
||||
appJar, mainClass, 1,
|
||||
new String[] {"An error has occurred while processing the shared archive file.",
|
||||
"Header checksum verification failed",
|
||||
"Unable to use shared archive"});
|
||||
// 5. Make base archive name not terminated with '\0'
|
||||
System.out.println("\n5. Make base archive name not terminated with '\0'");
|
||||
String wrongBaseName = getNewArchiveName("wrongBaseName");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseName);
|
||||
baseArchivePathOffset = CDSArchiveUtils.baseArchivePathOffset(copiedJsa);
|
||||
baseArchiveNameSize = CDSArchiveUtils.baseArchiveNameSize(copiedJsa);
|
||||
long offset = baseArchivePathOffset + baseArchiveNameSize - 1; // end of line
|
||||
CDSArchiveUtils.writeData(copiedJsa, offset, new byte[] {(byte)'X'});
|
||||
|
||||
runTwo(baseArchiveName, wrongBaseName,
|
||||
appJar, mainClass, 1,
|
||||
new String[] {"Base archive " + baseArchiveName,
|
||||
" does not exist",
|
||||
"Header checksum verification failed"});
|
||||
}
|
||||
}
|
||||
|
@ -46,25 +46,28 @@ import sun.hotspot.WhiteBox;
|
||||
// This class performs operations on shared archive file
|
||||
public class CDSArchiveUtils {
|
||||
// offsets
|
||||
public static int offsetMagic; // CDSFileMapHeaderBase::_magic
|
||||
public static int offsetVersion; // CDSFileMapHeaderBase::_version
|
||||
public static int offsetJvmIdent; // FileMapHeader::_jvm_ident
|
||||
public static int offsetBaseArchiveNameSize; // FileMapHeader::_base_archive_name_size
|
||||
public static int spOffsetCrc; // CDSFileMapRegion::_crc
|
||||
public static int spOffset; // offset of CDSFileMapRegion
|
||||
public static int spUsedOffset; // offset of CDSFileMapRegion::_used
|
||||
private static int offsetMagic; // offset of GenericCDSFileMapHeader::_magic
|
||||
private static int offsetCrc; // offset of GenericCDSFileMapHeader::_crc
|
||||
private static int offsetVersion; // offset of GenericCDSFileMapHeader::_version
|
||||
private static int offsetHeaderSize; // offset of GenericCDSFileMapHeader::_header_size
|
||||
private static int offsetBaseArchivePathOffset;// offset of GenericCDSFileMapHeader::_base_archive_path_offset
|
||||
private static int offsetBaseArchiveNameSize; // offset of GenericCDSFileMapHeader::_base_archive_name_size
|
||||
private static int offsetJvmIdent; // offset of FileMapHeader::_jvm_ident
|
||||
private static int spOffsetCrc; // offset of CDSFileMapRegion::_crc
|
||||
private static int spOffset; // offset of CDSFileMapRegion
|
||||
private static int spUsedOffset; // offset of CDSFileMapRegion::_used
|
||||
// constants
|
||||
public static int staticMagic; // static magic value defined in hotspot
|
||||
public static int dynamicMagic; // dyamic magic value defined in hotspot
|
||||
public static int sizetSize; // size of size_t
|
||||
public static int intSize; // size of int
|
||||
public static int staticArchiveHeaderSize; // static archive file header size
|
||||
public static int dynamicArchiveHeaderSize; // dynamic archive file header size
|
||||
public static int cdsFileMapRegionSize; // size of CDSFileMapRegion
|
||||
public static long alignment; // MetaspaceShared::core_region_alignment
|
||||
private static int staticMagic; // static magic value defined in hotspot
|
||||
private static int dynamicMagic; // dyamic magic value defined in hotspot
|
||||
private static int sizetSize; // size of size_t
|
||||
private static int intSize; // size of int
|
||||
private static int staticArchiveHeaderSize; // static archive file header size
|
||||
private static int dynamicArchiveHeaderSize; // dynamic archive file header size
|
||||
private static int cdsFileMapRegionSize; // size of CDSFileMapRegion
|
||||
private static long alignment; // MetaspaceShared::core_region_alignment
|
||||
|
||||
// The following should be consistent with the enum in the C++ MetaspaceShared class
|
||||
public static String[] shared_region_name = {
|
||||
private static String[] shared_region_name = {
|
||||
"rw", // ReadWrite
|
||||
"ro", // ReadOnly
|
||||
"bm", // relocation bitmaps
|
||||
@ -73,31 +76,33 @@ public class CDSArchiveUtils {
|
||||
"first_open_archive",
|
||||
"last_open_archive"
|
||||
};
|
||||
public static int num_regions = shared_region_name.length;
|
||||
private static int num_regions = shared_region_name.length;
|
||||
|
||||
static {
|
||||
WhiteBox wb;
|
||||
try {
|
||||
wb = WhiteBox.getWhiteBox();
|
||||
// offsets
|
||||
offsetMagic = wb.getCDSOffsetForName("CDSFileMapHeaderBase::_magic");
|
||||
offsetVersion = wb.getCDSOffsetForName("CDSFileMapHeaderBase::_version");
|
||||
offsetMagic = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_magic");
|
||||
offsetCrc = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_crc");
|
||||
offsetVersion = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_version");
|
||||
offsetHeaderSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_header_size");
|
||||
offsetBaseArchivePathOffset = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_base_archive_path_offset");
|
||||
offsetBaseArchiveNameSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_base_archive_name_size");
|
||||
offsetJvmIdent = wb.getCDSOffsetForName("FileMapHeader::_jvm_ident");
|
||||
offsetBaseArchiveNameSize = wb.getCDSOffsetForName("FileMapHeader::_base_archive_name_size");
|
||||
spOffsetCrc = wb.getCDSOffsetForName("CDSFileMapRegion::_crc");
|
||||
spUsedOffset = wb.getCDSOffsetForName("CDSFileMapRegion::_used") - spOffsetCrc;
|
||||
spOffset = wb.getCDSOffsetForName("CDSFileMapHeaderBase::_space[0]") - offsetMagic;
|
||||
// constants
|
||||
staticMagic = wb.getCDSConstantForName("static_magic");
|
||||
dynamicMagic = wb.getCDSConstantForName("dynamic_magic");
|
||||
// following two sizes are runtime values
|
||||
staticArchiveHeaderSize = wb.getCDSConstantForName("static_file_header_size");
|
||||
dynamicArchiveHeaderSize = wb.getCDSConstantForName("dynamic_archive_header_size");
|
||||
sizetSize = wb.getCDSConstantForName("size_t_size");
|
||||
intSize = wb.getCDSConstantForName("int_size");
|
||||
cdsFileMapRegionSize = wb.getCDSConstantForName("CDSFileMapRegion_size");
|
||||
alignment = wb.metaspaceSharedRegionAlignment();
|
||||
// file_header_size is structure size, real size aligned with alignment
|
||||
// so must be calculated after alignment is available
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
@ -110,17 +115,51 @@ public class CDSArchiveUtils {
|
||||
}
|
||||
}
|
||||
|
||||
// accessors
|
||||
// offsets
|
||||
public static int offsetMagic() { return offsetMagic; }
|
||||
public static int offsetCrc() { return offsetCrc; }
|
||||
public static int offsetVersion() { return offsetVersion; }
|
||||
public static int offsetHeaderSize() { return offsetHeaderSize; }
|
||||
public static int offsetBaseArchivePathOffset() { return offsetBaseArchivePathOffset; }
|
||||
public static int offsetBaseArchiveNameSize() { return offsetBaseArchiveNameSize; }
|
||||
public static int offsetJvmIdent() { return offsetJvmIdent; }
|
||||
public static int spOffsetCrc() { return spOffsetCrc; }
|
||||
public static int spOffset() { return spOffset; }
|
||||
public static int spUsedOffset() { return spUsedOffset; }
|
||||
// constants
|
||||
public static int staticMagic() { return staticMagic; }
|
||||
public static int dynamicMagic() { return dynamicMagic; }
|
||||
public static int sizetSize() { return sizetSize; }
|
||||
public static int staticArchiveHeaderSize() { return staticArchiveHeaderSize; }
|
||||
public static int dynamicArchiveHeaderSize() { return dynamicArchiveHeaderSize; }
|
||||
public static int cdsFileMapRegionSize() { return cdsFileMapRegionSize; }
|
||||
public static long alignment() { return alignment; }
|
||||
|
||||
|
||||
|
||||
public static long fileHeaderSize(File jsaFile) throws Exception {
|
||||
long magicValue = readInt(jsaFile, offsetMagic, 4);
|
||||
if (magicValue == staticMagic) {
|
||||
return alignUpWithAlignment((long)staticArchiveHeaderSize);
|
||||
} else if (magicValue == dynamicMagic) {
|
||||
// dynamic archive store base archive name after header, so we count it in header size.
|
||||
int baseArchiveNameSize = (int)readInt(jsaFile, (long)offsetBaseArchiveNameSize, 4);
|
||||
return alignUpWithAlignment((long)dynamicArchiveHeaderSize + baseArchiveNameSize);
|
||||
} else {
|
||||
throw new RuntimeException("Wrong magic value from archive file: " + magicValue);
|
||||
}
|
||||
long headerSize = readInt(jsaFile, offsetHeaderSize, 4);
|
||||
return headerSize;
|
||||
}
|
||||
|
||||
public static long fileHeaderSizeAligned(File jsaFile) throws Exception {
|
||||
long size = fileHeaderSize(jsaFile);
|
||||
return alignUpWithAlignment(size);
|
||||
}
|
||||
|
||||
public static int baseArchivePathOffset(File jsaFile) throws Exception {
|
||||
return (int)readInt(jsaFile, offsetBaseArchivePathOffset, 4);
|
||||
}
|
||||
|
||||
public static int baseArchiveNameSize(File jsaFile) throws Exception {
|
||||
return (int)readInt(jsaFile, offsetBaseArchiveNameSize, 4);
|
||||
}
|
||||
|
||||
public static String baseArchiveName(File jsaFile) throws Exception {
|
||||
int size = baseArchiveNameSize(jsaFile);
|
||||
int baseArchivePathOffset = (int)readInt(jsaFile, offsetBaseArchivePathOffset, 4);
|
||||
return readString(jsaFile, baseArchivePathOffset, size - 1); // exclude terminating '\0'
|
||||
}
|
||||
|
||||
private static long alignUpWithAlignment(long l) {
|
||||
@ -159,7 +198,7 @@ public class CDSArchiveUtils {
|
||||
int bufSize;
|
||||
|
||||
System.out.printf("%-24s%12s%12s%16s\n", "Space Name", "Used bytes", "Reg Start", "Random Offset");
|
||||
start0 = fileHeaderSize(jsaFile);
|
||||
start0 = fileHeaderSizeAligned(jsaFile);
|
||||
for (int i = 0; i < num_regions; i++) {
|
||||
used[i] = usedRegionSizeAligned(jsaFile, i);
|
||||
start = start0;
|
||||
@ -188,7 +227,7 @@ public class CDSArchiveUtils {
|
||||
int bufSize;
|
||||
|
||||
System.out.printf("%-24s%12s%12s%16s\n", "Space Name", "Used bytes", "Reg Start", "Random Offset");
|
||||
start0 = fileHeaderSize(jsaFile);
|
||||
start0 = fileHeaderSizeAligned(jsaFile);
|
||||
for (int i = 0; i < num_regions; i++) {
|
||||
used[i] = usedRegionSizeAligned(jsaFile, i);
|
||||
start = start0;
|
||||
@ -225,12 +264,12 @@ public class CDSArchiveUtils {
|
||||
}
|
||||
byte[] buf = new byte[4096];
|
||||
System.out.printf("%-24s%12d\n", "Total: ", total);
|
||||
long regionStartOffset = fileHeaderSize(jsaFile);
|
||||
long regionStartOffset = fileHeaderSizeAligned(jsaFile);
|
||||
for (int i = 0; i < region; i++) {
|
||||
regionStartOffset += used[i];
|
||||
}
|
||||
System.out.println("Corrupt " + shared_region_name[region] + " section, start = " + regionStartOffset
|
||||
+ " (header_size + 0x" + Long.toHexString(regionStartOffset - fileHeaderSize(jsaFile)) + ")");
|
||||
+ " (header_size + 0x" + Long.toHexString(regionStartOffset - fileHeaderSizeAligned(jsaFile)) + ")");
|
||||
long bytesWritten = 0L;
|
||||
while (bytesWritten < used[region]) {
|
||||
bytesWritten += writeData(jsaFile, regionStartOffset + bytesWritten, buf);
|
||||
@ -262,16 +301,17 @@ public class CDSArchiveUtils {
|
||||
writeData(jsaFile, 0, buf);
|
||||
}
|
||||
|
||||
public static void modifyFileHeaderSize(File jsaFile, int newHeaderSize) throws Exception {
|
||||
modifyHeaderIntField(jsaFile, offsetHeaderSize, newHeaderSize);
|
||||
}
|
||||
|
||||
public static void modifyJvmIdent(File jsaFile, String newJvmIdent) throws Exception {
|
||||
byte[] buf = newJvmIdent.getBytes();
|
||||
writeData(jsaFile, (long)offsetJvmIdent, buf);
|
||||
}
|
||||
|
||||
public static void modifyHeaderIntField(File jsaFile, long offset, int value) throws Exception {
|
||||
System.out.println(" offset " + offset);
|
||||
|
||||
byte[] bytes = ByteBuffer.allocate(4).putInt(value).array();
|
||||
writeData(jsaFile, offset, bytes);
|
||||
writeData(jsaFile, offset, value);
|
||||
}
|
||||
|
||||
// copy archive and set copied read/write permit
|
||||
@ -300,16 +340,30 @@ public class CDSArchiveUtils {
|
||||
return FileChannel.open(file.toPath(), new HashSet<StandardOpenOption>(arry));
|
||||
}
|
||||
|
||||
public static long readInt(File file, long offset, int nBytes) throws Exception {
|
||||
private static long readInt(File file, long offset, int nBytes) throws Exception {
|
||||
try (FileChannel fc = getFileChannel(file, false /*read only*/)) {
|
||||
ByteBuffer bb = ByteBuffer.allocate(nBytes);
|
||||
bb.order(ByteOrder.nativeOrder());
|
||||
ByteBuffer bb = ByteBuffer.allocate(nBytes).order(ByteOrder.nativeOrder());
|
||||
fc.position(offset);
|
||||
fc.read(bb);
|
||||
bb.rewind();
|
||||
return (nBytes > 4 ? bb.getLong(0) : bb.getInt(0));
|
||||
}
|
||||
}
|
||||
|
||||
private static String readString(File file, long offset, int nBytes) throws Exception {
|
||||
try (FileChannel fc = getFileChannel(file, false /*read only*/)) {
|
||||
ByteBuffer bb = ByteBuffer.allocate(nBytes).order(ByteOrder.nativeOrder());
|
||||
fc.position(offset);
|
||||
fc.read(bb);
|
||||
byte[] arr = bb.flip().array();
|
||||
for (byte i : arr) {
|
||||
System.out.print((char)i);
|
||||
}
|
||||
System.out.println("");
|
||||
return new String(arr);
|
||||
}
|
||||
}
|
||||
|
||||
private static long writeData(FileChannel fc, long offset, ByteBuffer bb) throws Exception {
|
||||
fc.position(offset);
|
||||
return fc.write(bb);
|
||||
@ -318,13 +372,17 @@ public class CDSArchiveUtils {
|
||||
public static long writeData(File file, long offset, byte[] array) throws Exception {
|
||||
try (FileChannel fc = getFileChannel(file, true /*write*/)) {
|
||||
ByteBuffer bbuf = ByteBuffer.wrap(array);
|
||||
bbuf.order(ByteOrder.nativeOrder());
|
||||
return writeData(fc, offset, bbuf);
|
||||
}
|
||||
}
|
||||
|
||||
public static long writeData(File file, long offset, int value) throws Exception {
|
||||
try (FileChannel fc = getFileChannel(file, true /*write*/)) {
|
||||
ByteBuffer bbuf = ByteBuffer.allocate(4).putInt(value).position(0);
|
||||
ByteBuffer bbuf = ByteBuffer.allocate(4)
|
||||
.order(ByteOrder.nativeOrder())
|
||||
.putInt(value)
|
||||
.rewind();
|
||||
return writeData(fc, offset, bbuf);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user