unpack.h revision 0
325N/A/*
325N/A * Copyright 2002-2005 Sun Microsystems, Inc. All Rights Reserved.
325N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
325N/A *
325N/A * This code is free software; you can redistribute it and/or modify it
325N/A * under the terms of the GNU General Public License version 2 only, as
325N/A * published by the Free Software Foundation. Sun designates this
325N/A * particular file as subject to the "Classpath" exception as provided
325N/A * by Sun in the LICENSE file that accompanied this code.
325N/A *
325N/A * This code is distributed in the hope that it will be useful, but WITHOUT
325N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
325N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
325N/A * version 2 for more details (a copy is included in the LICENSE file that
325N/A * accompanied this code).
325N/A *
325N/A * You should have received a copy of the GNU General Public License version
325N/A * 2 along with this work; if not, write to the Free Software Foundation,
325N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
325N/A *
325N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
325N/A * CA 95054 USA or visit www.sun.com if you need additional information or
325N/A * have any questions.
325N/A */
325N/A
325N/A
325N/A
325N/A// Global Structures
325N/Astruct jar;
325N/Astruct gunzip;
325N/Astruct band;
325N/Astruct cpool;
325N/Astruct entry;
325N/Astruct cpindex;
325N/Astruct inner_class;
325N/Astruct value_stream;
325N/A
325N/Astruct cpindex {
325N/A uint len;
325N/A entry* base1; // base of primary index
325N/A entry** base2; // base of secondary index
325N/A byte ixTag; // type of entries (!= CONSTANT_None), plus 64 if sub-index
325N/A enum { SUB_TAG = 64 };
325N/A
325N/A entry* get(uint i);
325N/A
325N/A void init(int len_, entry* base1_, int ixTag_) {
325N/A len = len_;
325N/A base1 = base1_;
325N/A base2 = null;
325N/A ixTag = ixTag_;
325N/A }
325N/A void init(int len_, entry** base2_, int ixTag_) {
325N/A len = len_;
325N/A base1 = null;
325N/A base2 = base2_;
325N/A ixTag = ixTag_;
325N/A }
325N/A};
325N/A
325N/Astruct cpool {
325N/A uint nentries;
325N/A entry* entries;
325N/A entry* first_extra_entry;
325N/A uint maxentries; // total allocated size of entries
325N/A
325N/A // Position and size of each homogeneous subrange:
325N/A int tag_count[CONSTANT_Limit];
325N/A int tag_base[CONSTANT_Limit];
325N/A cpindex tag_index[CONSTANT_Limit];
325N/A ptrlist tag_extras[CONSTANT_Limit];
325N/A
325N/A cpindex* member_indexes; // indexed by 2*CONSTANT_Class.inord
325N/A cpindex* getFieldIndex(entry* classRef);
325N/A cpindex* getMethodIndex(entry* classRef);
325N/A
325N/A inner_class** ic_index;
325N/A inner_class** ic_child_index;
325N/A inner_class* getIC(entry* inner);
325N/A inner_class* getFirstChildIC(entry* outer);
325N/A inner_class* getNextChildIC(inner_class* child);
325N/A
325N/A int outputIndexLimit; // index limit after renumbering
325N/A ptrlist outputEntries; // list of entry* needing output idx assigned
325N/A
325N/A entry** hashTab;
325N/A uint hashTabLength;
325N/A entry*& hashTabRef(byte tag, bytes& b);
325N/A entry* ensureUtf8(bytes& b);
325N/A entry* ensureClass(bytes& b);
325N/A
325N/A // Well-known Utf8 symbols.
325N/A enum {
325N/A #define SNAME(n,s) s_##s,
325N/A ALL_ATTR_DO(SNAME)
325N/A #undef SNAME
325N/A s_lt_init_gt, // <init>
325N/A s_LIMIT
325N/A };
325N/A entry* sym[s_LIMIT];
325N/A
325N/A // read counts from hdr, allocate main arrays
325N/A enum { NUM_COUNTS = 12 };
325N/A void init(unpacker* u, int counts[NUM_COUNTS]);
325N/A
325N/A // pointer to outer unpacker, for error checks etc.
325N/A unpacker* u;
325N/A
325N/A int getCount(byte tag) {
325N/A assert((uint)tag < CONSTANT_Limit);
325N/A return tag_count[tag];
325N/A }
325N/A cpindex* getIndex(byte tag) {
325N/A assert((uint)tag < CONSTANT_Limit);
325N/A return &tag_index[tag];
325N/A }
325N/A cpindex* getKQIndex(); // uses cur_descr
325N/A
325N/A void expandSignatures();
325N/A void initMemberIndexes();
325N/A
325N/A void computeOutputOrder();
325N/A void computeOutputIndexes();
325N/A void resetOutputIndexes();
325N/A
325N/A // error handling
325N/A inline void abort(const char* msg);
325N/A inline bool aborting();
325N/A};
325N/A
325N/A/*
325N/A * The unpacker provides the entry points to the unpack engine,
325N/A * as well as maintains the state of the engine.
325N/A */
325N/Astruct unpacker {
325N/A // One element of the resulting JAR.
325N/A struct file {
325N/A const char* name;
325N/A julong size;
325N/A int modtime;
325N/A int options;
325N/A bytes data[2];
325N/A // Note: If Sum(data[*].len) < size,
325N/A // remaining bytes must be read directly from the input stream.
325N/A bool deflate_hint() { return ((options & FO_DEFLATE_HINT) != 0); }
325N/A };
325N/A
325N/A // back pointer to NativeUnpacker obj and Java environment
325N/A void* jniobj;
325N/A void* jnienv;
325N/A
325N/A // global pointer to self, if not running under JNI (not multi-thread safe)
325N/A static unpacker* non_mt_current;
325N/A
325N/A // if running Unix-style, here are the inputs and outputs
325N/A FILE* infileptr; // buffered
325N/A int infileno; // unbuffered
325N/A bytes inbytes; // direct
325N/A gunzip* gzin; // gunzip filter, if any
325N/A jar* jarout; // output JAR file
325N/A
325N/A#ifndef PRODUCT
325N/A int nowrite;
325N/A int skipfiles;
325N/A int verbose_bands;
325N/A#endif
325N/A
325N/A // pointer to self, for U_NEW macro
325N/A unpacker* u;
325N/A
325N/A // private abort message string, allocated to PATH_MAX*2
325N/A const char* abort_message;
325N/A ptrlist mallocs; // list of guys to free when we are all done
325N/A ptrlist tmallocs; // list of guys to free on next client request
325N/A fillbytes smallbuf; // supplies small alloc requests
325N/A fillbytes tsmallbuf; // supplies temporary small alloc requests
325N/A
325N/A // option management members
325N/A int verbose; // verbose level, 0 means no output
325N/A bool strip_compile;
325N/A bool strip_debug;
325N/A bool strip_jcov;
325N/A bool remove_packfile;
325N/A int deflate_hint_or_zero; // ==0 means not set, otherwise -1 or 1
325N/A int modification_time_or_zero;
325N/A
325N/A FILE* errstrm;
325N/A const char* errstrm_name;
325N/A
325N/A const char* log_file;
325N/A
325N/A // input stream
325N/A fillbytes input; // the whole block (size is predicted, has slop too)
325N/A bool live_input; // is the data in this block live?
325N/A bool free_input; // must the input buffer be freed?
325N/A byte* rp; // read pointer (< rplimit <= input.limit())
325N/A byte* rplimit; // how much of the input block has been read?
325N/A julong bytes_read;
325N/A int unsized_bytes_read;
325N/A
325N/A // callback to read at least one byte, up to available input
325N/A typedef jlong (*read_input_fn_t)(unpacker* self, void* buf, jlong minlen, jlong maxlen);
325N/A read_input_fn_t read_input_fn;
325N/A
325N/A // archive header fields
325N/A int magic, minver, majver;
325N/A julong archive_size;
325N/A int archive_next_count, archive_options, archive_modtime;
325N/A int band_headers_size;
325N/A int file_count, attr_definition_count, ic_count, class_count;
325N/A int default_class_minver, default_class_majver;
325N/A int default_file_options, suppress_file_options; // not header fields
325N/A int default_archive_modtime, default_file_modtime; // not header fields
325N/A int code_count; // not a header field
325N/A int files_remaining; // not a header field
325N/A
325N/A // engine state
325N/A band* all_bands; // indexed by band_number
325N/A byte* meta_rp; // read-pointer into (copy of) band_headers
325N/A cpool cp; // all constant pool information
325N/A inner_class* ics; // InnerClasses
325N/A
325N/A // output stream
325N/A bytes output; // output block (either classfile head or tail)
325N/A byte* wp; // write pointer (< wplimit == output.limit())
325N/A byte* wpbase; // write pointer starting address (<= wp)
325N/A byte* wplimit; // how much of the output block has been written?
325N/A
325N/A // output state
325N/A file cur_file;
325N/A entry* cur_class; // CONSTANT_Class entry
325N/A entry* cur_super; // CONSTANT_Class entry or null
325N/A entry* cur_descr; // CONSTANT_NameandType entry
325N/A int cur_descr_flags; // flags corresponding to cur_descr
325N/A int cur_class_minver, cur_class_majver;
325N/A bool cur_class_has_local_ics;
fillbytes cur_classfile_head;
fillbytes cur_classfile_tail;
int files_written; // also tells which file we're working on
int classes_written; // also tells which class we're working on
julong bytes_written;
intlist bcimap;
fillbytes class_fixup_type;
intlist class_fixup_offset;
ptrlist class_fixup_ref;
fillbytes code_fixup_type; // which format of branch operand?
intlist code_fixup_offset; // location of operand needing fixup
intlist code_fixup_source; // encoded ID of branch insn
ptrlist requested_ics; // which ics need output?
// stats pertaining to multiple segments (updated on reset)
julong bytes_read_before_reset;
julong bytes_written_before_reset;
int files_written_before_reset;
int classes_written_before_reset;
int segments_read_before_reset;
// attribute state
struct layout_definition {
uint idx; // index (0..31...) which identifies this layout
const char* name; // name of layout
entry* nameEntry;
const char* layout; // string of layout (not yet parsed)
band** elems; // array of top-level layout elems (or callables)
bool hasCallables() { return layout[0] == '['; }
band** bands() { assert(elems != null); return elems; }
};
struct attr_definitions {
unpacker* u; // pointer to self, for U_NEW macro
int xxx_flags_hi_bn;// locator for flags, count, indexes, calls bands
int attrc; // ATTR_CONTEXT_CLASS, etc.
uint flag_limit; // 32 or 63, depending on archive_options bit
julong predef; // mask of built-in definitions
julong redef; // mask of local flag definitions or redefinitions
ptrlist layouts; // local (compressor-defined) defs, in index order
int flag_count[X_ATTR_LIMIT_FLAGS_HI];
intlist overflow_count;
ptrlist strip_names; // what attribute names are being stripped?
ptrlist band_stack; // Temp., used during layout parsing.
ptrlist calls_to_link; // (ditto)
int bands_made; // (ditto)
void free() {
layouts.free();
overflow_count.free();
strip_names.free();
band_stack.free();
calls_to_link.free();
}
// Locate the five fixed bands.
band& xxx_flags_hi();
band& xxx_flags_lo();
band& xxx_attr_count();
band& xxx_attr_indexes();
band& xxx_attr_calls();
band& fixed_band(int e_class_xxx);
// Register a new layout, and make bands for it.
layout_definition* defineLayout(int idx, const char* name, const char* layout);
layout_definition* defineLayout(int idx, entry* nameEntry, const char* layout);
band** buildBands(layout_definition* lo);
// Parse a layout string or part of one, recursively if necessary.
const char* parseLayout(const char* lp, band** &res, int curCble);
const char* parseNumeral(const char* lp, int &res);
const char* parseIntLayout(const char* lp, band* &res, byte le_kind,
bool can_be_signed = false);
band** popBody(int band_stack_base); // pops a body off band_stack
// Read data into the bands of the idx-th layout.
void readBandData(int idx); // parse layout, make bands, read data
void readBandData(band** body, uint count); // recursive helper
layout_definition* getLayout(uint idx) {
if (idx >= layouts.length()) return null;
return (layout_definition*) layouts.get(idx);
}
void setHaveLongFlags(bool z) {
assert(flag_limit == 0); // not set up yet
flag_limit = (z? X_ATTR_LIMIT_FLAGS_HI: X_ATTR_LIMIT_NO_FLAGS_HI);
}
bool haveLongFlags() {
assert(flag_limit == X_ATTR_LIMIT_NO_FLAGS_HI ||
flag_limit == X_ATTR_LIMIT_FLAGS_HI);
return flag_limit == X_ATTR_LIMIT_FLAGS_HI;
}
// Return flag_count if idx is predef and not redef, else zero.
int predefCount(uint idx);
bool isRedefined(uint idx) {
assert(idx < flag_limit);
return ((redef >> idx) & 1);
}
bool isPredefined(uint idx) {
assert(idx < flag_limit);
return (((predef & ~redef) >> idx) & 1);
}
julong flagIndexMask() {
return (predef | redef);
}
bool isIndex(uint idx) {
assert(flag_limit != 0); // must be set up already
if (idx < flag_limit)
return (((predef | redef) >> idx) & 1);
else
return (idx - flag_limit < overflow_count.length());
}
int& getCount(uint idx) {
assert(isIndex(idx));
if (idx < flag_limit)
return flag_count[idx];
else
return overflow_count.get(idx - flag_limit);
}
bool aborting() { return u->aborting(); }
void abort(const char* msg) { u->abort(msg); }
};
attr_definitions attr_defs[ATTR_CONTEXT_LIMIT];
// Initialization
void init(read_input_fn_t input_fn = null);
// Resets to a known sane state
void reset();
// Deallocates all storage.
void free();
// Deallocates temporary storage (volatile after next client call).
void free_temps() { tsmallbuf.init(); tmallocs.freeAll(); }
// Option management methods
bool set_option(const char* option, const char* value);
const char* get_option(const char* option);
void dump_options();
// Fetching input.
bool ensure_input(jlong more);
byte* input_scan() { return rp; }
size_t input_remaining() { return rplimit - rp; }
size_t input_consumed() { return rp - input.base(); }
// Entry points to the unpack engine
static int run(int argc, char **argv); // Unix-style entry point.
void check_options();
void start(void* packptr = null, size_t len = 0);
void redirect_stdio();
void write_file_to_jar(file* f);
void finish();
// Public post unpack methods
int get_files_remaining() { return files_remaining; }
int get_segments_remaining() { return archive_next_count; }
file* get_next_file(); // returns null on last file
// General purpose methods
void* alloc(size_t size) { return alloc_heap(size, true); }
void* temp_alloc(size_t size) { return alloc_heap(size, true, true); }
void* alloc_heap(size_t size, bool smallOK = false, bool temp = false);
void saveTo(bytes& b, const char* str) { saveTo(b, (byte*)str, strlen(str)); }
void saveTo(bytes& b, bytes& data) { saveTo(b, data.ptr, data.len); }
void saveTo(bytes& b, byte* ptr, size_t len); //{ b.ptr = U_NEW...}
const char* saveStr(const char* str) { bytes buf; saveTo(buf, str); return buf.strval(); }
const char* saveIntStr(int num) { char buf[30]; sprintf(buf, "%d", num); return saveStr(buf); }
#ifndef PRODUCT
int printcr_if_verbose(int level, const char* fmt,...);
#endif
const char* get_abort_message();
void abort(const char* s = null);
bool aborting() { return abort_message != null; }
static unpacker* current(); // find current instance
// Output management
void set_output(fillbytes* which) {
assert(wp == null);
which->ensureSize(1 << 12); // covers the average classfile
wpbase = which->base();
wp = which->limit();
wplimit = which->end();
}
fillbytes* close_output(fillbytes* which = null); // inverse of set_output
// These take an implicit parameter of wp/wplimit, and resize as necessary:
byte* put_space(size_t len); // allocates space at wp, returns pointer
size_t put_empty(size_t s) { byte* p = put_space(s); return p - wpbase; }
void ensure_put_space(size_t len);
void put_bytes(bytes& b) { b.writeTo(put_space(b.len)); }
void putu1(int n) { putu1_at(put_space(1), n); }
void putu1_fast(int n) { putu1_at(wp++, n); }
void putu2(int n); // { putu2_at(put_space(2), n); }
void putu4(int n); // { putu4_at(put_space(4), n); }
void putu8(jlong n); // { putu8_at(put_space(8), n); }
void putref(entry* e); // { putu2_at(put_space(2), putref_index(e, 2)); }
void putu1ref(entry* e); // { putu1_at(put_space(1), putref_index(e, 1)); }
int putref_index(entry* e, int size); // size in [1..2]
void put_label(int curIP, int size); // size in {2,4}
void putlayout(band** body);
void put_stackmap_type();
size_t wpoffset() { return (size_t)(wp - wpbase); } // (unvariant across overflow)
byte* wp_at(size_t offset) { return wpbase + offset; }
uint to_bci(uint bii);
void get_code_header(int& max_stack,
int& max_na_locals,
int& handler_count,
int& cflags);
band* ref_band_for_self_op(int bc, bool& isAloadVar, int& origBCVar);
band* ref_band_for_op(int bc);
// Definitions of standard classfile int formats:
static void putu1_at(byte* wp, int n) { assert(n == (n & 0xFF)); wp[0] = n; }
static void putu2_at(byte* wp, int n);
static void putu4_at(byte* wp, int n);
static void putu8_at(byte* wp, jlong n);
// Private stuff
void reset_cur_classfile();
void write_classfile_tail();
void write_classfile_head();
void write_code();
void write_bc_ops();
void write_members(int num, int attrc); // attrc=ATTR_CONTEXT_FIELD/METHOD
int write_attrs(int attrc, julong indexBits);
// The readers
void read_bands();
void read_file_header();
void read_cp();
void read_cp_counts(value_stream& hdr);
void read_attr_defs();
void read_ics();
void read_attrs(int attrc, int obj_count);
void read_classes();
void read_code_headers();
void read_bcs();
void read_bc_ops();
void read_files();
void read_Utf8_values(entry* cpMap, int len);
void read_single_words(band& cp_band, entry* cpMap, int len);
void read_double_words(band& cp_bands, entry* cpMap, int len);
void read_single_refs(band& cp_band, byte refTag, entry* cpMap, int len);
void read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag, entry* cpMap, int len);
void read_signature_values(entry* cpMap, int len);
};
inline void cpool::abort(const char* msg) { u->abort(msg); }
inline bool cpool::aborting() { return u->aborting(); }