Path: blob/master/src/java.base/share/native/libjimage/imageFile.cpp
41149 views
/*1* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031#include <assert.h>32#include <string.h>33#include <stdlib.h>3435#include "endian.hpp"36#include "imageDecompressor.hpp"37#include "imageFile.hpp"38#include "inttypes.hpp"39#include "jni.h"40#include "osSupport.hpp"4142// Map the full jimage, only with 64 bit addressing.43bool ImageFileReader::memory_map_image = sizeof(void *) == 8;4445#ifdef WIN3246const char FileSeparator = '\\';47#else48const char FileSeparator = '/';49#endif5051// Image files are an alternate file format for storing classes and resources. The52// goal is to supply file access which is faster and smaller than the jar format.53//54// (More detailed nodes in the header.)55//5657// Compute the Perfect Hashing hash code for the supplied UTF-8 string.58s4 ImageStrings::hash_code(const char* string, s4 seed) {59assert(seed > 0 && "invariant");60// Access bytes as unsigned.61u1* bytes = (u1*)string;62u4 useed = (u4)seed;63// Compute hash code.64for (u1 byte = *bytes++; byte; byte = *bytes++) {65useed = (useed * HASH_MULTIPLIER) ^ byte;66}67// Ensure the result is not signed.68return (s4)(useed & 0x7FFFFFFF);69}7071// Match up a string in a perfect hash table.72// Returns the index where the name should be.73// Result still needs validation for precise match (false positive.)74s4 ImageStrings::find(Endian* endian, const char* name, s4* redirect, u4 length) {75// If the table is empty, then short cut.76if (!redirect || !length) {77return NOT_FOUND;78}79// Compute the basic perfect hash for name.80s4 hash_code = ImageStrings::hash_code(name);81// Modulo table size.82s4 index = hash_code % length;83// Get redirect entry.84// value == 0 then not found85// value < 0 then -1 - value is true index86// value > 0 then value is seed for recomputing hash.87s4 value = endian->get(redirect[index]);88// if recompute is required.89if (value > 0 ) {90// Entry collision value, need to recompute hash.91hash_code = ImageStrings::hash_code(name, value);92// Modulo table size.93return hash_code % length;94} else if (value < 0) {95// Compute direct index.96return -1 - value;97}98// No entry found.99return NOT_FOUND;100}101102// Test to see if UTF-8 string begins with the start UTF-8 string. If so,103// return non-NULL address of remaining portion of string. Otherwise, return104// NULL. Used to test sections of a path without copying from image string105// table.106const char* ImageStrings::starts_with(const char* string, const char* start) {107char ch1, ch2;108// Match up the strings the best we can.109while ((ch1 = *string) && (ch2 = *start)) {110if (ch1 != ch2) {111// Mismatch, return NULL.112return NULL;113}114// Next characters.115string++, start++;116}117// Return remainder of string.118return string;119}120121// Inflates the attribute stream into individual values stored in the long122// array _attributes. This allows an attribute value to be quickly accessed by123// direct indexing. Unspecified values default to zero (from constructor.)124void ImageLocation::set_data(u1* data) {125// Deflate the attribute stream into an array of attributes.126u1 byte;127// Repeat until end header is found.128while ((data != NULL) && (byte = *data)) {129// Extract kind from header byte.130u1 kind = attribute_kind(byte);131assert(kind < ATTRIBUTE_COUNT && "invalid image location attribute");132// Extract length of data (in bytes).133u1 n = attribute_length(byte);134// Read value (most significant first.)135_attributes[kind] = attribute_value(data + 1, n);136// Position to next attribute by skipping attribute header and data bytes.137data += n + 1;138}139}140141// Zero all attribute values.142void ImageLocation::clear_data() {143// Set defaults to zero.144memset(_attributes, 0, sizeof(_attributes));145}146147// ImageModuleData constructor maps out sub-tables for faster access.148ImageModuleData::ImageModuleData(const ImageFileReader* image_file) :149_image_file(image_file),150_endian(image_file->endian()) {151}152153// Release module data resource.154ImageModuleData::~ImageModuleData() {155}156157158// Return the module in which a package resides. Returns NULL if not found.159const char* ImageModuleData::package_to_module(const char* package_name) {160// replace all '/' by '.'161char* replaced = new char[(int) strlen(package_name) + 1];162assert(replaced != NULL && "allocation failed");163int i;164for (i = 0; package_name[i] != '\0'; i++) {165replaced[i] = package_name[i] == '/' ? '.' : package_name[i];166}167replaced[i] = '\0';168169// build path /packages/<package_name>170const char* radical = "/packages/";171char* path = new char[(int) strlen(radical) + (int) strlen(package_name) + 1];172assert(path != NULL && "allocation failed");173strcpy(path, radical);174strcat(path, replaced);175delete[] replaced;176177// retrieve package location178ImageLocation location;179bool found = _image_file->find_location(path, location);180delete[] path;181if (!found) {182return NULL;183}184185// retrieve offsets to module name186int size = (int)location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);187u1* content = new u1[size];188assert(content != NULL && "allocation failed");189_image_file->get_resource(location, content);190u1* ptr = content;191// sequence of sizeof(8) isEmpty|offset. Use the first module that is not empty.192u4 offset = 0;193for (i = 0; i < size; i+=8) {194u4 isEmpty = _endian->get(*((u4*)ptr));195ptr += 4;196if (!isEmpty) {197offset = _endian->get(*((u4*)ptr));198break;199}200ptr += 4;201}202delete[] content;203return _image_file->get_strings().get(offset);204}205206// Manage a table of open image files. This table allows multiple access points207// to share an open image.208ImageFileReaderTable::ImageFileReaderTable() : _count(0), _max(_growth) {209_table = static_cast<ImageFileReader**>(calloc(_max, sizeof(ImageFileReader*)));210assert(_table != NULL && "allocation failed");211}212213// Add a new image entry to the table.214void ImageFileReaderTable::add(ImageFileReader* image) {215if (_count == _max) {216_max += _growth;217_table = static_cast<ImageFileReader**>(realloc(_table, _max * sizeof(ImageFileReader*)));218}219_table[_count++] = image;220}221222// Remove an image entry from the table.223void ImageFileReaderTable::remove(ImageFileReader* image) {224for (u4 i = 0; i < _count; i++) {225if (_table[i] == image) {226// Swap the last element into the found slot227_table[i] = _table[--_count];228break;229}230}231232if (_count != 0 && _count == _max - _growth) {233_max -= _growth;234_table = static_cast<ImageFileReader**>(realloc(_table, _max * sizeof(ImageFileReader*)));235}236}237238// Determine if image entry is in table.239bool ImageFileReaderTable::contains(ImageFileReader* image) {240for (u4 i = 0; i < _count; i++) {241if (_table[i] == image) {242return true;243}244}245return false;246}247248// Table to manage multiple opens of an image file.249ImageFileReaderTable ImageFileReader::_reader_table;250251SimpleCriticalSection _reader_table_lock;252253// Locate an image if file already open.254ImageFileReader* ImageFileReader::find_image(const char* name) {255// Lock out _reader_table.256SimpleCriticalSectionLock cs(&_reader_table_lock);257// Search for an exist image file.258for (u4 i = 0; i < _reader_table.count(); i++) {259// Retrieve table entry.260ImageFileReader* reader = _reader_table.get(i);261// If name matches, then reuse (bump up use count.)262assert(reader->name() != NULL && "reader->name must not be null");263if (strcmp(reader->name(), name) == 0) {264reader->inc_use();265return reader;266}267}268269return NULL;270}271272// Open an image file, reuse structure if file already open.273ImageFileReader* ImageFileReader::open(const char* name, bool big_endian) {274ImageFileReader* reader = find_image(name);275if (reader != NULL) {276return reader;277}278279// Need a new image reader.280reader = new ImageFileReader(name, big_endian);281if (reader == NULL || !reader->open()) {282// Failed to open.283delete reader;284return NULL;285}286287// Lock to update288SimpleCriticalSectionLock cs(&_reader_table_lock);289// Search for an existing image file.290for (u4 i = 0; i < _reader_table.count(); i++) {291// Retrieve table entry.292ImageFileReader* existing_reader = _reader_table.get(i);293// If name matches, then reuse (bump up use count.)294assert(reader->name() != NULL && "reader->name still must not be null");295if (strcmp(existing_reader->name(), name) == 0) {296existing_reader->inc_use();297reader->close();298delete reader;299return existing_reader;300}301}302// Bump use count and add to table.303reader->inc_use();304_reader_table.add(reader);305return reader;306}307308// Close an image file if the file is not in use elsewhere.309void ImageFileReader::close(ImageFileReader *reader) {310// Lock out _reader_table.311SimpleCriticalSectionLock cs(&_reader_table_lock);312// If last use then remove from table and then close.313if (reader->dec_use()) {314_reader_table.remove(reader);315delete reader;316}317}318319// Return an id for the specifed ImageFileReader.320u8 ImageFileReader::reader_to_ID(ImageFileReader *reader) {321// ID is just the cloaked reader address.322return (u8)reader;323}324325// Validate the image id.326bool ImageFileReader::id_check(u8 id) {327// Make sure the ID is a managed (_reader_table) reader.328SimpleCriticalSectionLock cs(&_reader_table_lock);329return _reader_table.contains((ImageFileReader*)id);330}331332// Return an id for the specifed ImageFileReader.333ImageFileReader* ImageFileReader::id_to_reader(u8 id) {334assert(id_check(id) && "invalid image id");335return (ImageFileReader*)id;336}337338// Constructor intializes to a closed state.339ImageFileReader::ImageFileReader(const char* name, bool big_endian) :340_module_data(NULL) {341// Copy the image file name.342int len = (int) strlen(name) + 1;343_name = new char[len];344assert(_name != NULL && "allocation failed");345strncpy(_name, name, len);346// Initialize for a closed file.347_fd = -1;348_endian = Endian::get_handler(big_endian);349_index_data = NULL;350}351352// Close image and free up data structures.353ImageFileReader::~ImageFileReader() {354// Ensure file is closed.355close();356// Free up name.357if (_name) {358delete[] _name;359_name = NULL;360}361362if (_module_data != NULL) {363delete _module_data;364}365}366367// Open image file for read access.368bool ImageFileReader::open() {369// If file exists open for reading.370_fd = osSupport::openReadOnly(_name);371if (_fd == -1) {372return false;373}374// Retrieve the file size.375_file_size = osSupport::size(_name);376// Read image file header and verify it has a valid header.377size_t header_size = sizeof(ImageHeader);378if (_file_size < header_size ||379!read_at((u1*)&_header, header_size, 0) ||380_header.magic(_endian) != IMAGE_MAGIC ||381_header.major_version(_endian) != MAJOR_VERSION ||382_header.minor_version(_endian) != MINOR_VERSION) {383close();384return false;385}386// Size of image index.387_index_size = index_size();388// Make sure file is large enough to contain the index.389if (_file_size < _index_size) {390return false;391}392// Memory map image (minimally the index.)393_index_data = (u1*)osSupport::map_memory(_fd, _name, 0, (size_t)map_size());394assert(_index_data && "image file not memory mapped");395// Retrieve length of index perfect hash table.396u4 length = table_length();397// Compute offset of the perfect hash table redirect table.398u4 redirect_table_offset = (u4)header_size;399// Compute offset of index attribute offsets.400u4 offsets_table_offset = redirect_table_offset + length * (u4)sizeof(s4);401// Compute offset of index location attribute data.402u4 location_bytes_offset = offsets_table_offset + length * (u4)sizeof(u4);403// Compute offset of index string table.404u4 string_bytes_offset = location_bytes_offset + locations_size();405// Compute address of the perfect hash table redirect table.406_redirect_table = (s4*)(_index_data + redirect_table_offset);407// Compute address of index attribute offsets.408_offsets_table = (u4*)(_index_data + offsets_table_offset);409// Compute address of index location attribute data.410_location_bytes = _index_data + location_bytes_offset;411// Compute address of index string table.412_string_bytes = _index_data + string_bytes_offset;413414// Initialize the module data415_module_data = new ImageModuleData(this);416// Successful open (if memory allocation succeeded).417return _module_data != NULL;418}419420// Close image file.421void ImageFileReader::close() {422// Deallocate the index.423if (_index_data) {424osSupport::unmap_memory((char*)_index_data, (size_t)map_size());425_index_data = NULL;426}427// Close file.428if (_fd != -1) {429osSupport::close(_fd);430_fd = -1;431}432433if (_module_data != NULL) {434delete _module_data;435_module_data = NULL;436}437}438439// Read directly from the file.440bool ImageFileReader::read_at(u1* data, u8 size, u8 offset) const {441return (u8)osSupport::read(_fd, (char*)data, size, offset) == size;442}443444// Find the location attributes associated with the path. Returns true if445// the location is found, false otherwise.446bool ImageFileReader::find_location(const char* path, ImageLocation& location) const {447// Locate the entry in the index perfect hash table.448s4 index = ImageStrings::find(_endian, path, _redirect_table, table_length());449// If is found.450if (index != ImageStrings::NOT_FOUND) {451// Get address of first byte of location attribute stream.452u1* data = get_location_data(index);453// Expand location attributes.454location.set_data(data);455// Make sure result is not a false positive.456return verify_location(location, path);457}458return false;459}460461// Find the location index and size associated with the path.462// Returns the location index and size if the location is found, 0 otherwise.463u4 ImageFileReader::find_location_index(const char* path, u8 *size) const {464// Locate the entry in the index perfect hash table.465s4 index = ImageStrings::find(_endian, path, _redirect_table, table_length());466// If found.467if (index != ImageStrings::NOT_FOUND) {468// Get address of first byte of location attribute stream.469u4 offset = get_location_offset(index);470u1* data = get_location_offset_data(offset);471// Expand location attributes.472ImageLocation location(data);473// Make sure result is not a false positive.474if (verify_location(location, path)) {475*size = (jlong)location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);476return offset;477}478}479return 0; // not found480}481482// Verify that a found location matches the supplied path (without copying.)483bool ImageFileReader::verify_location(ImageLocation& location, const char* path) const {484// Manage the image string table.485ImageStrings strings(_string_bytes, _header.strings_size(_endian));486// Position to first character of the path string.487const char* next = path;488// Get module name string.489const char* module = location.get_attribute(ImageLocation::ATTRIBUTE_MODULE, strings);490// If module string is not empty.491if (*module != '\0') {492// Compare '/module/' .493if (*next++ != '/') return false;494if (!(next = ImageStrings::starts_with(next, module))) return false;495if (*next++ != '/') return false;496}497// Get parent (package) string498const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings);499// If parent string is not empty string.500if (*parent != '\0') {501// Compare 'parent/' .502if (!(next = ImageStrings::starts_with(next, parent))) return false;503if (*next++ != '/') return false;504}505// Get base name string.506const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings);507// Compare with basne name.508if (!(next = ImageStrings::starts_with(next, base))) return false;509// Get extension string.510const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings);511// If extension is not empty.512if (*extension != '\0') {513// Compare '.extension' .514if (*next++ != '.') return false;515if (!(next = ImageStrings::starts_with(next, extension))) return false;516}517// True only if complete match and no more characters.518return *next == '\0';519}520521// Return the resource for the supplied location offset.522void ImageFileReader::get_resource(u4 offset, u1* uncompressed_data) const {523// Get address of first byte of location attribute stream.524u1* data = get_location_offset_data(offset);525// Expand location attributes.526ImageLocation location(data);527// Read the data528get_resource(location, uncompressed_data);529}530531// Return the resource for the supplied location.532void ImageFileReader::get_resource(ImageLocation& location, u1* uncompressed_data) const {533// Retrieve the byte offset and size of the resource.534u8 offset = location.get_attribute(ImageLocation::ATTRIBUTE_OFFSET);535u8 uncompressed_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);536u8 compressed_size = location.get_attribute(ImageLocation::ATTRIBUTE_COMPRESSED);537// If the resource is compressed.538if (compressed_size != 0) {539u1* compressed_data;540// If not memory mapped read in bytes.541if (!memory_map_image) {542// Allocate buffer for compression.543compressed_data = new u1[(size_t)compressed_size];544assert(compressed_data != NULL && "allocation failed");545// Read bytes from offset beyond the image index.546bool is_read = read_at(compressed_data, compressed_size, _index_size + offset);547assert(is_read && "error reading from image or short read");548} else {549compressed_data = get_data_address() + offset;550}551// Get image string table.552const ImageStrings strings = get_strings();553// Decompress resource.554ImageDecompressor::decompress_resource(compressed_data, uncompressed_data, uncompressed_size,555&strings, _endian);556// If not memory mapped then release temporary buffer.557if (!memory_map_image) {558delete[] compressed_data;559}560} else {561// Read bytes from offset beyond the image index.562bool is_read = read_at(uncompressed_data, uncompressed_size, _index_size + offset);563assert(is_read && "error reading from image or short read");564}565}566567// Return the ImageModuleData for this image568ImageModuleData * ImageFileReader::get_image_module_data() {569return _module_data;570}571572573