| 1 | /* | 
| 2 |  * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. | 
| 3 |  * | 
| 4 |  * Redistribution and use in source and binary forms, with or without | 
| 5 |  * modification, are permitted provided that the following conditions | 
| 6 |  * are met: | 
| 7 |  * | 
| 8 |  *   - Redistributions of source code must retain the above copyright | 
| 9 |  *     notice, this list of conditions and the following disclaimer. | 
| 10 |  * | 
| 11 |  *   - Redistributions in binary form must reproduce the above copyright | 
| 12 |  *     notice, this list of conditions and the following disclaimer in the | 
| 13 |  *     documentation and/or other materials provided with the distribution. | 
| 14 |  * | 
| 15 |  *   - Neither the name of Oracle nor the names of its | 
| 16 |  *     contributors may be used to endorse or promote products derived | 
| 17 |  *     from this software without specific prior written permission. | 
| 18 |  * | 
| 19 |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | 
| 20 |  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | 
| 21 |  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
| 22 |  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR | 
| 23 |  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
| 24 |  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
| 25 |  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
| 26 |  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | 
| 27 |  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 
| 28 |  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 
| 29 |  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
| 30 |  */ | 
| 31 |  | 
| 32 | #include <string.h> | 
| 33 |  | 
| 34 | #include "jimage.hpp" | 
| 35 |  | 
| 36 | #include "imageFile.hpp" | 
| 37 |  | 
| 38 | /* | 
| 39 |  * JImageOpen - Given the supplied full path file name, open an image file. This | 
| 40 |  * function will also initialize tables and retrieve meta-data necessary to | 
| 41 |  * satisfy other functions in the API. If the image file has been previously | 
| 42 |  * open, a new open request will share memory and resources used by the previous | 
| 43 |  * open. A call to JImageOpen should be balanced by a call to JImageClose, to | 
| 44 |  * release memory and resources used. If the image file is not found or cannot | 
| 45 |  * be open, then NULL is returned and error will contain a reason for the | 
| 46 |  * failure; a positive value for a system error number, negative for a jimage | 
| 47 |  * specific error (see JImage Error Codes.) | 
| 48 |  * | 
| 49 |  *  Ex. | 
| 50 |  *   jint error; | 
| 51 |  *   JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules", &error); | 
| 52 |  *   if (image == NULL) { | 
| 53 |  *     tty->print_cr("JImage failed to open: %d", error); | 
| 54 |  *     ... | 
| 55 |  *   } | 
| 56 |  *   ... | 
| 57 |  */ | 
| 58 | extern "C"  JNIEXPORT JImageFile* | 
| 59 | JIMAGE_Open(const char *name, jint* error) { | 
| 60 |     // TODO - return a meaningful error code | 
| 61 |     *error = 0; | 
| 62 |     ImageFileReader* jfile = ImageFileReader::open(name); | 
| 63 |     return (JImageFile*) jfile; | 
| 64 | } | 
| 65 |  | 
| 66 | /* | 
| 67 |  * JImageClose - Given the supplied open image file (see JImageOpen), release | 
| 68 |  * memory and resources used by the open file and close the file. If the image | 
| 69 |  * file is shared by other uses, release and close is deferred until the last use | 
| 70 |  * is also closed. | 
| 71 |  * | 
| 72 |  * Ex. | 
| 73 |  *  (*JImageClose)(image); | 
| 74 |  */ | 
| 75 | extern "C"  JNIEXPORT void | 
| 76 | JIMAGE_Close(JImageFile* image) { | 
| 77 |     ImageFileReader::close((ImageFileReader*) image); | 
| 78 | } | 
| 79 |  | 
| 80 | /* | 
| 81 |  * JImagePackageToModule - Given an open image file (see JImageOpen) and the name | 
| 82 |  * of a package, return the name of module where the package resides. If the | 
| 83 |  * package does not exist in the image file, the function returns NULL. | 
| 84 |  * The resulting string does/should not have to be released. All strings are | 
| 85 |  * utf-8, zero byte terminated. | 
| 86 |  * | 
| 87 |  * Ex. | 
| 88 |  *  const char* package = (*JImagePackageToModule)(image, "java/lang"); | 
| 89 |  *  tty->print_cr(package); | 
| 90 |  *  -> java.base | 
| 91 |  */ | 
| 92 | extern "C"  JNIEXPORT const char* | 
| 93 | JIMAGE_PackageToModule(JImageFile* image, const char* package_name) { | 
| 94 |     return ((ImageFileReader*) image)->get_image_module_data()->package_to_module(package_name); | 
| 95 | } | 
| 96 |  | 
| 97 | /* | 
| 98 |  * JImageFindResource - Given an open image file (see JImageOpen), a module | 
| 99 |  * name, a version string and the name of a class/resource, return location | 
| 100 |  * information describing the resource and its size. If no resource is found, the | 
| 101 |  * function returns JIMAGE_NOT_FOUND and the value of size is undefined. | 
| 102 |  * The version number should be "9.0" and is not used in locating the resource. | 
| 103 |  * The resulting location does/should not have to be released. | 
| 104 |  * All strings are utf-8, zero byte terminated. | 
| 105 |  * | 
| 106 |  *  Ex. | 
| 107 |  *   jlong size; | 
| 108 |  *   JImageLocationRef location = (*JImageFindResource)(image, | 
| 109 |  *                                 "java.base", "9.0", "java/lang/String.class", &size); | 
| 110 |  */ | 
| 111 | extern "C"  JNIEXPORT JImageLocationRef | 
| 112 | JIMAGE_FindResource(JImageFile* image, | 
| 113 |         const char* module_name, const char* version, const char* name, | 
| 114 |         jlong* size) { | 
| 115 |     // Concatenate to get full path | 
| 116 |     char fullpath[IMAGE_MAX_PATH]; | 
| 117 |     size_t moduleNameLen = strlen(module_name); | 
| 118 |     size_t nameLen = strlen(name); | 
| 119 |     size_t index; | 
| 120 |  | 
| 121 |     // TBD:   assert(moduleNameLen > 0 && "module name must be non-empty"); | 
| 122 |     assert(nameLen > 0 && "name must non-empty" ); | 
| 123 |  | 
| 124 |     // If the concatenated string is too long for the buffer, return not found | 
| 125 |     if (1 + moduleNameLen + 1 + nameLen + 1 > IMAGE_MAX_PATH) { | 
| 126 |         return 0L; | 
| 127 |     } | 
| 128 |  | 
| 129 |     index = 0; | 
| 130 |     fullpath[index++] = '/'; | 
| 131 |     memcpy(&fullpath[index], module_name, moduleNameLen); | 
| 132 |     index += moduleNameLen; | 
| 133 |     fullpath[index++] = '/'; | 
| 134 |     memcpy(&fullpath[index], name, nameLen); | 
| 135 |     index += nameLen; | 
| 136 |     fullpath[index++] = '\0'; | 
| 137 |  | 
| 138 |     JImageLocationRef loc = | 
| 139 |             (JImageLocationRef) ((ImageFileReader*) image)->find_location_index(fullpath, (u8*) size); | 
| 140 |     return loc; | 
| 141 | } | 
| 142 |  | 
| 143 | /* | 
| 144 |  * JImageGetResource - Given an open image file (see JImageOpen), a resource's | 
| 145 |  * location information (see JImageFindResource), a buffer of appropriate | 
| 146 |  * size and the size, retrieve the bytes associated with the | 
| 147 |  * resource. If the size is less than the resource size then the read is truncated. | 
| 148 |  * If the size is greater than the resource size then the remainder of the buffer | 
| 149 |  * is zero filled.  The function will return the actual size of the resource. | 
| 150 |  * | 
| 151 |  * Ex. | 
| 152 |  *  jlong size; | 
| 153 |  *   JImageLocationRef location = (*JImageFindResource)(image, | 
| 154 |  *                                 "java.base", "9.0", "java/lang/String.class", &size); | 
| 155 |  *  char* buffer = new char[size]; | 
| 156 |  *  (*JImageGetResource)(image, location, buffer, size); | 
| 157 |  */ | 
| 158 | extern "C"  JNIEXPORT jlong | 
| 159 | JIMAGE_GetResource(JImageFile* image, JImageLocationRef location, | 
| 160 |         char* buffer, jlong size) { | 
| 161 |     ((ImageFileReader*) image)->get_resource((u4) location, (u1*) buffer); | 
| 162 |     return size; | 
| 163 | } | 
| 164 |  | 
| 165 | /* | 
| 166 |  * JImageResourceIterator - Given an open image file (see JImageOpen), a visitor | 
| 167 |  * function and a visitor argument, iterator through each of the image's resources. | 
| 168 |  * The visitor function is called with the image file, the module name, the | 
| 169 |  * package name, the base name, the extension and the visitor argument. The return | 
| 170 |  * value of the visitor function should be true, unless an early iteration exit is | 
| 171 |  * required. All strings are utf-8, zero byte terminated.file. | 
| 172 |  * | 
| 173 |  * Ex. | 
| 174 |  *   bool ctw_visitor(JImageFile* jimage, const char* module_name, const char* version, | 
| 175 |  *                  const char* package, const char* name, const char* extension, void* arg) { | 
| 176 |  *     if (strcmp(extension, "class") == 0) { | 
| 177 |  *       char path[JIMAGE_MAX_PATH]; | 
| 178 |  *       Thread* THREAD = Thread::current(); | 
| 179 |  *       jio_snprintf(path, JIMAGE_MAX_PATH - 1, "/%s/%s", package, name); | 
| 180 |  *       ClassLoader::compile_the_world_in(path, (Handle)arg, THREAD); | 
| 181 |  *       return !HAS_PENDING_EXCEPTION; | 
| 182 |  *     } | 
| 183 |  *     return true; | 
| 184 |  *   } | 
| 185 |  *   (*JImageResourceIterator)(image, ctw_visitor, loader); | 
| 186 |  */ | 
| 187 | extern "C"  JNIEXPORT void | 
| 188 | JIMAGE_ResourceIterator(JImageFile* image, | 
| 189 |         JImageResourceVisitor_t visitor, void* arg) { | 
| 190 |     ImageFileReader* imageFile = (ImageFileReader*) image; | 
| 191 |     u4 nEntries = imageFile->table_length(); | 
| 192 |     const ImageStrings strings = imageFile->get_strings(); | 
| 193 |     for (u4 i = 0; i < nEntries; i++) { | 
| 194 |         ImageLocation location(imageFile->get_location_data(i)); | 
| 195 |  | 
| 196 |         u4 moduleOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_MODULE); | 
| 197 |         if (moduleOffset == 0) { | 
| 198 |             continue; // skip non-modules | 
| 199 |         } | 
| 200 |         const char *module = strings.get(moduleOffset); | 
| 201 |         if (strcmp(module, "modules" ) == 0 | 
| 202 |             || strcmp(module, "packages" ) == 0) { | 
| 203 |             continue; // always skip | 
| 204 |         } | 
| 205 |  | 
| 206 |         u4 parentOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_PARENT); | 
| 207 |         const char *parent = strings.get(parentOffset); | 
| 208 |         u4 baseOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_BASE); | 
| 209 |         const char *base = strings.get(baseOffset); | 
| 210 |         u4 extOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION); | 
| 211 |         const char *extension = strings.get(extOffset); | 
| 212 |  | 
| 213 |         if (!(*visitor)(image, module, "9" , parent, base, extension, arg)) { | 
| 214 |             break; | 
| 215 |         } | 
| 216 |     } | 
| 217 | } | 
| 218 |  |