Portability: fix "EOFException: premature end of file" doing ELF on Windows.

OutputFile::read() was bad news; fsync() should work, but was missing.
This commit is contained in:
John Reiser 2012-07-12 14:25:28 -07:00
parent f383629282
commit 8a5d352733
10 changed files with 79 additions and 67 deletions

View File

@ -410,21 +410,16 @@ void OutputFile::seek(off_t off, int whence)
super::seek(off,whence); super::seek(off,whence);
} }
int OutputFile::read(void *buf, int len) // WARNING: fsync() does not exist in some Windows environments.
{ // This trick works only on UNIX-like systems.
InputFile infile; //int OutputFile::read(void *buf, int len)
infile.open(this->getName(), O_RDONLY); //{
infile.seek(this->tell(), SEEK_SET); // fsync(_fd);
return infile.read(buf, len); // InputFile infile;
} // infile.open(this->getName(), O_RDONLY);
// infile.seek(this->tell(), SEEK_SET);
int OutputFile::readx(void *buf, int len) // return infile.read(buf, len);
{ //}
InputFile infile;
infile.open(this->getName(), O_RDONLY);
infile.seek(this->tell(), SEEK_SET);
return infile.readx(buf, len);
}
void OutputFile::set_extent(off_t offset, off_t length) void OutputFile::set_extent(off_t offset, off_t length)
{ {

View File

@ -141,8 +141,6 @@ public:
// FIXME - these won't work when using the '--stdout' option // FIXME - these won't work when using the '--stdout' option
virtual void seek(off_t off, int whence); virtual void seek(off_t off, int whence);
virtual void rewrite(const void *buf, int len); virtual void rewrite(const void *buf, int len);
virtual int read(void *buf, int len);
virtual int readx(void *buf, int len);
// util // util
static void dump(const char *name, const void *buf, int len, int flags=-1); static void dump(const char *name, const void *buf, int len, int flags=-1);

View File

@ -196,17 +196,6 @@ PackLinuxElf::~PackLinuxElf()
delete[] file_image; file_image = NULL; delete[] file_image; file_image = NULL;
} }
// Swap the byte ranges fo[a to b] and fo[b to c].
static void swap_byte_ranges(OutputFile *fo, unsigned a, unsigned b, unsigned c)
{
MemBuffer buf(c - a);
fo->seek(a, SEEK_SET);
fo->readx(buf, c - a);
fo->seek(a, SEEK_SET);
fo->rewrite(&buf[b - a], c - b);
fo->rewrite(&buf[0], b - a);
}
void PackLinuxElf::pack3(OutputFile *fo, Filter &ft) void PackLinuxElf::pack3(OutputFile *fo, Filter &ft)
{ {
sz_pack2b = fpad4(fo); // after headers, all PT_LOAD, gaps sz_pack2b = fpad4(fo); // after headers, all PT_LOAD, gaps
@ -245,16 +234,28 @@ void PackLinuxElf::pack3(OutputFile *fo, Filter &ft)
get_te16(&linfo.l_lsize) + len - sz_pack2a)); get_te16(&linfo.l_lsize) + len - sz_pack2a));
len = fpad4(fo); len = fpad4(fo);
// Put the loader in the middle, after the compressed PT_LOADs
// and before the compressed gaps (and debuginfo!)
// As first written, loader is fo[sz_pack2b to len],
// and gaps and debuginfo are fo[sz_pack2a to sz_pack2b].
swap_byte_ranges(fo, sz_pack2a, sz_pack2b, len);
} }
void PackLinuxElf32::pack3(OutputFile *fo, Filter &ft) void PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
{ {
super::pack3(fo, ft); super::pack3(fo, ft); // loader follows compressed PT_LOADs
// Then compressed gaps (including debuginfo.)
unsigned total_in = 0, total_out = 0;
for (unsigned k = 0; k < e_phnum; ++k) {
Extent x;
x.size = find_LOAD_gap(phdri, k, e_phnum);
if (x.size) {
x.offset = get_te32(&phdri[k].p_offset) +
get_te32(&phdri[k].p_filesz);
packExtent(x, total_in, total_out, 0, fo);
}
}
// write block end marker (uncompressed size 0)
b_info hdr; memset(&hdr, 0, sizeof(hdr));
set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32);
fo->write(&hdr, sizeof(hdr));
fpad4(fo);
set_te32(&elfout.phdr[0].p_filesz, sz_pack2 + lsize); set_te32(&elfout.phdr[0].p_filesz, sz_pack2 + lsize);
set_te32(&elfout.phdr[0].p_memsz, sz_pack2 + lsize); set_te32(&elfout.phdr[0].p_memsz, sz_pack2 + lsize);
if (0!=xct_off) { // shared library if (0!=xct_off) { // shared library
@ -331,7 +332,24 @@ void PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
void PackLinuxElf64::pack3(OutputFile *fo, Filter &ft) void PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
{ {
super::pack3(fo, ft); super::pack3(fo, ft); // loader follows compressed PT_LOADs
// Then compressed gaps (including debuginfo.)
unsigned total_in = 0, total_out = 0;
for (unsigned k = 0; k < e_phnum; ++k) {
Extent x;
x.size = find_LOAD_gap(phdri, k, e_phnum);
if (x.size) {
x.offset = get_te64(&phdri[k].p_offset) +
get_te64(&phdri[k].p_filesz);
packExtent(x, total_in, total_out, 0, fo);
}
}
// write block end marker (uncompressed size 0)
b_info hdr; memset(&hdr, 0, sizeof(hdr));
set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32);
fo->write(&hdr, sizeof(hdr));
fpad4(fo);
set_te64(&elfout.phdr[0].p_filesz, sz_pack2 + lsize); set_te64(&elfout.phdr[0].p_filesz, sz_pack2 + lsize);
set_te64(&elfout.phdr[0].p_memsz, sz_pack2 + lsize); set_te64(&elfout.phdr[0].p_memsz, sz_pack2 + lsize);
if (0!=xct_off) { // shared library if (0!=xct_off) { // shared library
@ -2298,7 +2316,7 @@ unsigned PackLinuxElf32::find_LOAD_gap(
return lo - hi; return lo - hi;
} }
void PackLinuxElf32::pack2(OutputFile *fo, Filter &ft) int PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
{ {
Extent x; Extent x;
unsigned k; unsigned k;
@ -2356,17 +2374,15 @@ void PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
} }
sz_pack2a = fpad4(fo); sz_pack2a = fpad4(fo);
// Accounting only; ::pack3 will do the compression and output
for (k = 0; k < e_phnum; ++k) { for (k = 0; k < e_phnum; ++k) {
x.size = find_LOAD_gap(phdri, k, e_phnum); total_in += find_LOAD_gap(phdri, k, e_phnum);
if (x.size) {
x.offset = get_te32(&phdri[k].p_offset) +
get_te32(&phdri[k].p_filesz);
packExtent(x, total_in, total_out, 0, fo);
}
} }
if ((off_t)total_in != file_size) if ((off_t)total_in != file_size)
throwEOFException(); throwEOFException();
return 0; // omit end-of-compression bhdr for now
} }
// Determine length of gap between PT_LOAD phdr[k] and closest PT_LOAD // Determine length of gap between PT_LOAD phdr[k] and closest PT_LOAD
@ -2409,7 +2425,7 @@ unsigned PackLinuxElf64::find_LOAD_gap(
return lo - hi; return lo - hi;
} }
void PackLinuxElf64::pack2(OutputFile *fo, Filter &ft) int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
{ {
Extent x; Extent x;
unsigned k; unsigned k;
@ -2467,17 +2483,15 @@ void PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
} }
sz_pack2a = fpad4(fo); sz_pack2a = fpad4(fo);
for (k = 0; k < e_phnum; ++k) { // Accounting only; ::pack3 will do the compression and output
x.size = find_LOAD_gap(phdri, k, e_phnum); for (k = 0; k < e_phnum; ++k) { //
if (x.size) { total_in += find_LOAD_gap(phdri, k, e_phnum);
x.offset = get_te64(&phdri[k].p_offset) +
get_te64(&phdri[k].p_filesz);
packExtent(x, total_in, total_out, 0, fo);
}
} }
if ((off_t)total_in != file_size) if ((off_t)total_in != file_size)
throwEOFException(); throwEOFException();
return 0; // omit end-of-compression bhdr for now
} }
// Filter 0x50, 0x51 assume HostPolicy::isLE // Filter 0x50, 0x51 assume HostPolicy::isLE

View File

@ -50,7 +50,7 @@ protected:
// because they depend on Elf32 or Elf64 data structures, which differ. // because they depend on Elf32 or Elf64 data structures, which differ.
virtual void pack1(OutputFile *, Filter &) = 0; // generate executable header virtual void pack1(OutputFile *, Filter &) = 0; // generate executable header
virtual void pack2(OutputFile *, Filter &) = 0; // append compressed data virtual int pack2(OutputFile *, Filter &) = 0; // append compressed data
virtual void pack3(OutputFile *, Filter &) = 0; // append loader virtual void pack3(OutputFile *, Filter &) = 0; // append loader
//virtual void pack4(OutputFile *, Filter &) = 0; // append pack header //virtual void pack4(OutputFile *, Filter &) = 0; // append pack header
@ -111,7 +111,7 @@ protected:
virtual int ARM_is_QNX(void); virtual int ARM_is_QNX(void);
virtual void pack1(OutputFile *, Filter &); // generate executable header virtual void pack1(OutputFile *, Filter &); // generate executable header
virtual void pack2(OutputFile *, Filter &); // append compressed data virtual int pack2(OutputFile *, Filter &); // append compressed data
virtual void pack3(OutputFile *, Filter &); // append loader virtual void pack3(OutputFile *, Filter &); // append loader
virtual void pack4(OutputFile *, Filter &); // append pack header virtual void pack4(OutputFile *, Filter &); // append pack header
virtual void unpack(OutputFile *fo); virtual void unpack(OutputFile *fo);
@ -228,7 +228,7 @@ protected:
virtual int checkEhdr(Elf64_Ehdr const *ehdr) const; virtual int checkEhdr(Elf64_Ehdr const *ehdr) const;
virtual void pack1(OutputFile *, Filter &); // generate executable header virtual void pack1(OutputFile *, Filter &); // generate executable header
virtual void pack2(OutputFile *, Filter &); // append compressed data virtual int pack2(OutputFile *, Filter &); // append compressed data
virtual void pack3(OutputFile *, Filter &); // append loader virtual void pack3(OutputFile *, Filter &); // append loader
virtual void pack4(OutputFile *, Filter &); // append pack header virtual void pack4(OutputFile *, Filter &); // append pack header
virtual void unpack(OutputFile *fo); virtual void unpack(OutputFile *fo);

View File

@ -124,12 +124,12 @@ void PackLinuxElf32x86interp::pack1(OutputFile *fo, Filter &)
#undef E #undef E
} }
void PackLinuxElf32x86interp::pack2(OutputFile *fo, Filter &ft) int PackLinuxElf32x86interp::pack2(OutputFile *fo, Filter &ft)
{ {
if (opt->o_unix.make_ptinterp) { if (opt->o_unix.make_ptinterp) {
return; // ignore current input file! return 1; // ignore current input file!
} }
super::pack2(fo, ft); return super::pack2(fo, ft);
} }
#undef PAGE_MASK #undef PAGE_MASK

View File

@ -54,7 +54,7 @@ public:
protected: protected:
virtual void pack1(OutputFile *, Filter &); // generate executable header virtual void pack1(OutputFile *, Filter &); // generate executable header
virtual void pack2(OutputFile *, Filter &); // append compressed data virtual int pack2(OutputFile *, Filter &); // append compressed data
virtual void pack3(OutputFile *, Filter &); // build loader virtual void pack3(OutputFile *, Filter &); // build loader
}; };

View File

@ -899,7 +899,7 @@ void PackMachBase<T>::pack3(OutputFile *fo, Filter &ft)
} }
template <class T> template <class T>
void PackMachBase<T>::pack2(OutputFile *fo, Filter &ft) // append compressed body int PackMachBase<T>::pack2(OutputFile *fo, Filter &ft) // append compressed body
{ {
unsigned const lc_seg = lc_segment[sizeof(Addr)>>3]; unsigned const lc_seg = lc_segment[sizeof(Addr)>>3];
Extent x; Extent x;
@ -977,6 +977,8 @@ void PackMachBase<T>::pack2(OutputFile *fo, Filter &ft) // append compressed bo
if ((off_t)total_in != file_size) if ((off_t)total_in != file_size)
throwEOFException(); throwEOFException();
segcmdo.filesize = fo->getBytesWritten(); segcmdo.filesize = fo->getBytesWritten();
return 1;
} }
void PackMachPPC32::pack1_setup_threado(OutputFile *const fo) void PackMachPPC32::pack1_setup_threado(OutputFile *const fo)

View File

@ -532,7 +532,7 @@ public:
// called by the generic pack() // called by the generic pack()
virtual void pack1(OutputFile *, Filter &); // generate executable header virtual void pack1(OutputFile *, Filter &); // generate executable header
virtual void pack2(OutputFile *, Filter &); // append compressed data virtual int pack2(OutputFile *, Filter &); // append compressed data
virtual void pack3(OutputFile *, Filter &) = 0; // append loader virtual void pack3(OutputFile *, Filter &) = 0; // append loader
virtual void pack4(OutputFile *, Filter &) = 0; // append PackHeader virtual void pack4(OutputFile *, Filter &) = 0; // append PackHeader

View File

@ -130,7 +130,7 @@ int PackUnix::getStrategy(Filter &/*ft*/)
return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2)); return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2));
} }
void PackUnix::pack2(OutputFile *fo, Filter &ft) int PackUnix::pack2(OutputFile *fo, Filter &ft)
{ {
// compress blocks // compress blocks
unsigned total_in = 0; unsigned total_in = 0;
@ -224,6 +224,8 @@ void PackUnix::pack2(OutputFile *fo, Filter &ft)
if ((off_t)total_in != file_size) { if ((off_t)total_in != file_size) {
throwEOFException(); throwEOFException();
} }
return 1; // default: write end-of-compression bhdr next
} }
void void
@ -285,12 +287,13 @@ void PackUnix::pack(OutputFile *fo)
set_te32(&hbuf.p_blocksize, blocksize); set_te32(&hbuf.p_blocksize, blocksize);
fo->write(&hbuf, sizeof(hbuf)); fo->write(&hbuf, sizeof(hbuf));
pack2(fo, ft); // append the compressed body // append the compressed body
if (pack2(fo, ft)) {
// write block end marker (uncompressed size 0) // write block end marker (uncompressed size 0)
b_info hdr; memset(&hdr, 0, sizeof(hdr)); b_info hdr; memset(&hdr, 0, sizeof(hdr));
set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32); set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32);
fo->write(&hdr, sizeof(hdr)); fo->write(&hdr, sizeof(hdr));
}
pack3(fo, ft); // append loader pack3(fo, ft); // append loader

View File

@ -54,7 +54,7 @@ public:
protected: protected:
// called by the generic pack() // called by the generic pack()
virtual void pack1(OutputFile *, Filter &); // generate executable header virtual void pack1(OutputFile *, Filter &); // generate executable header
virtual void pack2(OutputFile *, Filter &); // append compressed data virtual int pack2(OutputFile *, Filter &); // append compressed data
virtual void pack3(OutputFile *, Filter &); // append loader virtual void pack3(OutputFile *, Filter &); // append loader
virtual void pack4(OutputFile *, Filter &); // append PackHeader virtual void pack4(OutputFile *, Filter &); // append PackHeader