8273152: Refactor CDS FileMapHeader loading code

Reviewed-by: ccheung, iklam
This commit is contained in:
Yumin Qi 2021-10-07 21:33:32 +00:00
parent 920e70701d
commit 8de77634c4
11 changed files with 465 additions and 232 deletions

View File

@ -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.

View File

@ -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[] = {

View File

@ -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());

View File

@ -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;
}

View File

@ -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(); }

View File

@ -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

View File

@ -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 {

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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"});
}
}

View File

@ -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);
}
}