Sophie

Sophie

distrib > Mandriva > 2009.1 > x86_64 > media > contrib-release-src > by-pkgid > 9f420a7d7aa29cf90eae6ccd9fd40268 > files > 1

cxmon-3.2-2mdv2009.1.src.rpm

2006-03-13  Gwenole Beauchesne  <gb.public@free.fr>

	* 64-bit fixes, cleanups, adjust main/init/term function offsets.

2006-03-12  Gwenole Beauchesne  <gb.public@free.fr>

	* Add PEF decoder.

--- cxmon-3.1/src/Makefile.am.pef-decoder	2002-01-19 02:55:22.000000000 +0100
+++ cxmon-3.1/src/Makefile.am	2006-03-13 03:05:23.000000000 +0100
@@ -5,6 +5,6 @@ SUBDIRS = disass
 bin_PROGRAMS = cxmon
 cxmon_SOURCES = main.cpp mon.cpp mon.h mon_6502.cpp mon_z80.cpp mon_atraps.h \
   mon_cmd.cpp mon_cmd.h mon_disass.cpp mon_disass.h mon_lowmem.cpp mon_lowmem.h \
-  mon_ppc.cpp sysdeps.h
+  mon_ppc.cpp sysdeps.h mon_pef.cpp
 
 cxmon_LDADD = disass/libdisass.a
--- cxmon-3.1/src/Makefile.in.pef-decoder	2006-03-13 11:24:00.000000000 +0100
+++ cxmon-3.1/src/Makefile.in	2006-03-13 13:53:20.000000000 +0100
@@ -51,7 +51,7 @@ binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 PROGRAMS = $(bin_PROGRAMS)
 am_cxmon_OBJECTS = main.$(OBJEXT) mon.$(OBJEXT) mon_6502.$(OBJEXT) \
 	mon_z80.$(OBJEXT) mon_cmd.$(OBJEXT) mon_disass.$(OBJEXT) \
-	mon_lowmem.$(OBJEXT) mon_ppc.$(OBJEXT)
+	mon_lowmem.$(OBJEXT) mon_ppc.$(OBJEXT) mon_pef.$(OBJEXT)
 cxmon_OBJECTS = $(am_cxmon_OBJECTS)
 cxmon_DEPENDENCIES = disass/libdisass.a
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
@@ -161,7 +161,7 @@ target_alias = @target_alias@
 SUBDIRS = disass
 cxmon_SOURCES = main.cpp mon.cpp mon.h mon_6502.cpp mon_z80.cpp mon_atraps.h \
   mon_cmd.cpp mon_cmd.h mon_disass.cpp mon_disass.h mon_lowmem.cpp mon_lowmem.h \
-  mon_ppc.cpp sysdeps.h
+  mon_ppc.cpp mon_pef.cpp sysdeps.h
 
 cxmon_LDADD = disass/libdisass.a
 all: all-recursive
@@ -237,6 +237,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mon_disass.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mon_lowmem.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mon_ppc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mon_pef.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mon_z80.Po@am__quote@
 
 .cpp.o:
--- cxmon-3.1/src/mon.cpp.pef-decoder	2004-04-20 21:31:01.000000000 +0200
+++ cxmon-3.1/src/mon.cpp	2006-03-13 03:05:23.000000000 +0100
@@ -1058,6 +1058,7 @@ void mon_init()
 	mon_add_command("yb", apply_byte, NULL);
 	mon_add_command("yh", apply_half, NULL);
 	mon_add_command("yw", apply_word, NULL);
+	mon_add_command("pef", dump_pef,				"pef start                Dump PEF image\n");
 	mon_add_command("t", transfer,					"t start end dest         Transfer memory\n");
 	mon_add_command("c", compare,					"c start end dest         Compare memory\n");
 	mon_add_command("h", help_or_hunt,				"h start end string       Search for byte string\n");
--- cxmon-3.1/src/mon_cmd.h.pef-decoder	2004-04-20 21:31:01.000000000 +0200
+++ cxmon-3.1/src/mon_cmd.h	2006-03-13 03:05:23.000000000 +0100
@@ -42,5 +42,6 @@ extern void compare(void);
 extern void hunt(void);
 extern void load_data(void);
 extern void save_data(void);
+extern void dump_pef(void);
 
 #endif
--- cxmon-3.1/src/mon_pef.cpp.pef-decoder	2006-03-13 03:05:23.000000000 +0100
+++ cxmon-3.1/src/mon_pef.cpp	2006-03-13 11:13:49.000000000 +0100
@@ -0,0 +1,1157 @@
+/*
+ *  mon_pef.cpp - PEF decoder
+ *
+ *  cxmon (C) 1997-2006 Christian Bauer, Marc Hellwig
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *  SEE ALSO
+ *    Inside Macintosh: Mac OS Runtime Architectures, chapter 8 "PEF Structure"
+ *    Binutils for parsing Stubs and Traceback tables
+ */
+
+#ifndef TEST
+#include "sysdeps.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <netinet/in.h>
+
+#include <new>
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#ifndef TEST
+#include "mon.h"
+#include "mon_disass.h"
+#endif
+
+#define DEBUG 1
+
+#if DEBUG
+#define D(x) x
+#else
+#define D(x)
+#endif
+
+#ifndef bug
+#define bug printf
+#endif
+
+#ifndef NO_STD_NAMESPACE
+using std::string;
+using std::vector;
+#endif
+
+
+// Data types (only valid for ILP32, LP64)
+#ifdef TEST
+typedef signed char		int8;
+typedef signed short	int16;
+typedef signed int		int32;
+typedef signed long		intptr;
+typedef unsigned char	uint8;
+typedef unsigned short	uint16;
+typedef unsigned int	uint32;
+typedef unsigned long	uintptr;
+#endif
+
+
+/*
+ *  Structures
+ */
+
+#if __MWERKS__ && __POWERPC__
+#define PRAGMA_ALIGN_SUPPORTED 1
+#define PACKED__
+#elif defined __GNUC__
+#define PACKED__ __attribute__ ((packed))
+#elif defined __sgi
+#define PRAGMA_PACK_SUPPORTED 1
+#define PACKED__
+#else
+#error "Packed attribute or pragma shall be supported"
+#endif
+
+// Container header
+struct PEFContainerHeader {
+	char tag1[4];
+	char tag2[4];
+	char architecture[4];
+	uint32 formatVersion;
+	uint32 dateTimeStamp;
+	uint32 oldDefVersion;
+	uint32 oldImpVersion;
+	uint32 currentVersion;
+	uint16 sectionCount;
+	uint16 instSectionCount;
+	uint32 reservedA;
+};
+
+// Section header
+struct PEFSectionHeader {
+	int32 nameOffset;
+	uint32 defaultAddress;
+	uint32 totalSize;
+	uint32 unpackedSize;
+	uint32 packedSize;
+	uint32 containerOffset;
+	uint8 sectionKind;
+	uint8 shareKind;
+	uint8 alignment;
+	uint8 reserved;
+};
+
+// Loader header
+struct PEFLoaderInfoHeader {
+	int32 mainSection;
+	uint32 mainOffset;
+	int32 initSection;
+	uint32 initOffset;
+	int32 termSection;
+	uint32 termOffset;
+	uint32 importedLibraryCount;
+	uint32 totalImportedSymbolCount;
+	uint32 relocSectionCount;
+	uint32 relocInstrOffset;
+	uint32 loaderStringsOffset;
+	uint32 exportHashOffset;
+	uint32 exportHashTablePower;
+	uint32 exportedSymbolCount;
+};
+
+// Imported library description
+struct PEFImportedLibrary {
+	uint32 nameOffset;
+	uint32 oldImpVersion;
+	uint32 currentVersion;
+	uint32 importedSymbolCount;
+	uint32 firstImportedSymbol;
+	uint8 options;
+	uint8 reservedA;
+	uint16 reservedB;
+};
+
+#ifdef PRAGMA_ALIGN_SUPPORTED
+#pragma options align=mac68k
+#endif
+
+#ifdef PRAGMA_PACK_SUPPORTED
+#pragma pack(1)
+#endif
+
+// Relocation headers table
+struct PEFLoaderRelocationHeader {
+	uint16 sectionIndex;
+	uint16 reservedA;
+	uint32 relocCount;
+	uint32 firstRelocOffset;
+} PACKED__;
+
+// Loader import symbol table entry
+struct PEFImportedSymbol {
+	uint32 flags		: 4;
+	uint32 symbolClass	: 4;
+	uint32 nameOffset	: 24;
+	uint32 symbolValue;
+} PACKED__;
+
+// Loader export hash slot table entry
+struct PEFExportHash {
+	uint32 chainCount	: 14;
+	uint32 tableIndex	: 18;
+} PACKED__;
+
+// Loader export hash chain table entry
+struct PEFExportKey {
+	uint32 length		: 16;
+	uint32 encodedName	: 16;
+} PACKED__;
+
+// Loader export symbol table entry
+struct PEFExportedSymbol {
+	uint32 classAndName;
+	uint32 symbolValue;
+	int16 sectionIndex;
+} PACKED__;
+
+// Traceback table entry
+struct PEFTracebackTable {
+	uint8 version;
+	uint8 lang;
+	uint8 flags1;
+	uint8 flags2;
+	uint8 flags3;
+	uint8 flags4;
+	uint8 fixedparams;
+	uint8 flags5;
+} PACKED__;
+
+#ifdef PRAGMA_PACK_SUPPORTED
+#pragma pack(0)
+#endif
+
+#ifdef PRAGMA_ALIGN_SUPPORTED
+#pragma options align=reset
+#endif
+
+
+/*
+ *  Constants
+ */
+
+// Section kind
+enum {
+	kPEFSectionCode				= 0,
+	kPEFSectionUnpackedData		= 1,
+	kPEFSectionPackedData		= 2,
+	kPEFSectionConstant			= 3,
+	kPEFSectionLoader			= 4,
+	kPEFSectionDebug			= 5,
+	kPEFSectionExecutableData	= 6,
+	kPEFSectionException		= 7,
+	kPEFSectionTraceback		= 8,
+};
+
+// Sharing options
+enum {
+	kPEFShareProcess			= 1,
+	kPEFShareGlobal				= 4,
+	kPEFShareProtected			= 5,
+};
+
+// Symbol classes
+enum {
+	kPEFCodeSymbol				= 0,
+	kPEFDataSymbol				= 1,
+	kPEFTVectSymbol				= 2,
+	kPEFTOCSymbol				= 3,
+	kPEFGlueSymbol				= 4,
+};
+
+// Relocation opcodes
+enum {
+	kPEFRelocBySectDWithSkip	= 0x00, // 00xxxxx
+	kPEFRelocBySectC			= 0x20, // 0100000
+	kPEFRelocBySectD			= 0x21, // 0100001
+	kPEFRelocTVector12			= 0x22, // 0100010
+	kPEFRelocTVector8			= 0x23, // 0100011
+	kPEFRelocVTable8			= 0x24, // 0100100
+	kPEFRelocImportRun			= 0x25, // 0100101
+	kPEFRelocSmByImport			= 0x30, // 0110000
+	kPEFRelocSmSetSectC			= 0x31, // 0110001
+	kPEFRelocSmSetSectD			= 0x32, // 0110010
+	kPEFRelocSmBySection		= 0x33, // 0110011
+	kPEFRelocIncrPosition		= 0x40, // 1000xxx
+	kPEFRelocSmRepeat			= 0x48, // 1001xxx
+	kPEFRelocSetPosition		= 0x50, // 101000x
+	kPEFRelocLgByImport			= 0x52, // 101001x
+	kPEFRelocLgRepeat			= 0x58, // 101100x
+	kPEFRelocLgSetOrBySection	= 0x5A, // 101101x
+};
+
+// Traceback flags
+enum {
+	TB_C						= 0,	// C
+	TB_CPLUSPLUS				= 9,	// C++
+	TB_HAS_TBOFF				= 0x20,	// tb_offset set (extension field)
+	TB_HAS_CTL					= 0x08,	// Has controlled automatic storage
+	TB_INT_HNDL					= 0x80,	// Routine is an interrupt handler
+	TB_NAME_PRESENT				= 0x40,	// Name set (extension field)
+	TB_USES_ALLOCA				= 0x20,	// Uses alloca() to allocate storage
+	TB_HAS_VEC_INFO				= 0x80,	// Routine uses vectors
+	TB_FLOATPARAMS				= 0xfe, // Number of floating point parameters
+};
+
+
+/*
+ *  Memory access
+ */
+
+#if defined TEST
+static inline uint32 pef_get8(uintptr adr)  { return *(uint8 *)adr; }
+static inline uint32 pef_get16(uintptr adr) { return ntohs(*(uint16 *)adr); }
+static inline uint32 pef_get32(uintptr adr) { return ntohl(*(uint32 *)adr); }
+#else
+static inline uint32 pef_get8(uintptr adr)  { return mon_read_byte(adr); }
+static inline uint32 pef_get16(uintptr adr) { return mon_read_half(adr); }
+static inline uint32 pef_get32(uintptr adr) { return mon_read_word(adr); }
+#endif
+
+static string pef_get_string(uintptr adr)
+{
+	string str;
+	char ch;
+	while ((ch = pef_get8(adr)) != 0) {
+		str += ch;
+		adr ++;
+	}
+	return str;
+}
+
+static void pef_memcpy(uint8 *dest, uintptr src, uint32 length)
+{
+	while (length-- > 0)
+		*dest++ = pef_get8(src++);
+}
+
+
+/*
+ *  Monitor output
+ */
+
+#ifdef TEST
+#define monout stdout
+#endif
+
+static void pef_printf(const char *format, ...)
+{
+	va_list args;
+	va_start(args, format);
+	vfprintf(monout, format, args);
+	va_end(args);
+}
+
+
+/*
+ *  Decoded PEF section
+ */
+
+struct PEFSection : PEFSectionHeader {
+	string name;
+	union {
+		uintptr data;
+		uint8 *pdata;
+	};
+	bool is_packed_data;
+
+	PEFSection();
+	~PEFSection();
+	uint16 get16(uintptr adr) const;
+	uint32 get32(uintptr adr) const;
+};
+
+PEFSection::PEFSection()
+	: data(0), is_packed_data(false)
+{
+}
+
+PEFSection::~PEFSection()
+{
+	if (is_packed_data)
+		delete pdata;
+}
+
+inline uint16 PEFSection::get16(uintptr adr) const
+{
+	uint16 value;
+	if (is_packed_data)
+		value = ntohs(*(uint16 *)(pdata + adr));
+	else
+		value = pef_get16(data + adr);
+	return value;
+}
+
+inline uint32 PEFSection::get32(uintptr adr) const
+{
+	uint32 value;
+	if (is_packed_data)
+		value = ntohl(*(uint32 *)(pdata + adr));
+	else
+		value = pef_get32(data + adr);
+	return value;
+}
+
+
+/*
+ *  Decoded PEF loader section
+ */
+
+struct PEFLoader {
+	PEFLoaderInfoHeader loaderHeader;
+	PEFImportedLibrary *importedLibraryTable;
+	PEFImportedSymbol *importedSymbolTable;
+	PEFLoaderRelocationHeader *relocationHeadersTable;
+	uintptr loaderStringTable;
+	PEFExportHash *exportHashTable;
+	PEFExportKey *exportKeyTable;
+	PEFExportedSymbol *exportedSymbolTable;
+
+	PEFLoader();
+	~PEFLoader();
+};
+
+PEFLoader::PEFLoader()
+	: importedLibraryTable(NULL),
+	  importedSymbolTable(NULL),
+	  relocationHeadersTable(NULL),
+	  loaderStringTable(0),
+	  exportHashTable(NULL),
+	  exportKeyTable(NULL),
+	  exportedSymbolTable(NULL)
+{
+}
+
+PEFLoader::~PEFLoader()
+{
+	if (importedLibraryTable)
+		delete[] importedLibraryTable;
+	if (importedSymbolTable)
+		delete[] importedSymbolTable;
+	if (relocationHeadersTable)
+		delete[] relocationHeadersTable;
+	if (exportHashTable)
+		delete[] exportHashTable;
+	if (exportKeyTable)
+		delete[] exportKeyTable;
+	if (exportedSymbolTable)
+		delete[] exportedSymbolTable;
+}
+
+
+/*
+ *  Decoded PEF symbol
+ */
+
+struct PEFSymbol {
+	uint32 value;
+	uint32 name;
+	uint16 namelen;
+	uint16 namesec;
+	uint16 shndx;
+	uint8  type;
+	uint8  _pad;
+};
+
+inline bool operator< (PEFSymbol const &a, PEFSymbol const &b)
+{
+	return a.shndx < b.shndx || (a.shndx == b.shndx && a.value < b.value);
+}
+
+typedef vector<PEFSymbol> PEFSymbolTable;
+
+
+/*
+ *  Decoded PEF object
+ */
+
+struct PEFObject {
+	PEFContainerHeader hdr;
+	PEFSection *shdr;
+	PEFLoader loader;
+	uintptr nameTable;
+	uintptr data;
+	int code_shndx;
+	int loader_shndx;
+	PEFSymbolTable symtab;
+
+	PEFObject();
+	~PEFObject();
+	bool decode(uintptr adr);
+	void dump(bool relative = false);
+	bool valid_section(int shndx);
+};
+
+PEFObject::PEFObject()
+	: shdr(NULL), nameTable(0), data(0), code_shndx(-1), loader_shndx(-1)
+{
+}
+
+PEFObject::~PEFObject()
+{
+	if (shdr)
+		delete[] shdr;
+}
+
+inline bool PEFObject::valid_section(int shndx)
+{
+	return shndx >= 0 && shndx < hdr.sectionCount;
+}
+
+
+/*
+ *  Helpers to read PEF data structures
+ */
+
+#define FIELD_OFFSET(NAME, FIELD)		((uint8 *)&(NAME)->FIELD - (uint8 *)(NAME))
+#define GET_FIELD(WIDTH, NAME, FIELD)	(NAME)->FIELD = pef_get##WIDTH(adr + FIELD_OFFSET(NAME, FIELD))
+#define GET_FIELD_ARRAY(N, NAME, FIELD)	pef_memcpy((uint8 *)&(NAME)->FIELD[0], adr + FIELD_OFFSET(NAME, FIELD), (N))
+
+static void pef_read_container_header(PEFContainerHeader *h, uintptr adr)
+{
+	assert(sizeof(PEFContainerHeader) == 40);
+
+	GET_FIELD_ARRAY(4, h, tag1);
+	GET_FIELD_ARRAY(4, h, tag2);
+	GET_FIELD_ARRAY(4, h, architecture);
+	GET_FIELD(32, h, formatVersion);
+	GET_FIELD(32, h, dateTimeStamp);
+	GET_FIELD(32, h, oldDefVersion);
+	GET_FIELD(32, h, oldImpVersion);
+	GET_FIELD(32, h, currentVersion);
+	GET_FIELD(16, h, sectionCount);
+	GET_FIELD(16, h, instSectionCount);
+}
+
+static void pef_read_section_header(PEFSectionHeader *h, uintptr adr)
+{
+	assert(sizeof(PEFSectionHeader) == 28);
+
+	GET_FIELD(32, h, nameOffset);
+	GET_FIELD(32, h, defaultAddress);
+	GET_FIELD(32, h, totalSize);
+	GET_FIELD(32, h, unpackedSize);
+	GET_FIELD(32, h, packedSize);
+	GET_FIELD(32, h, containerOffset);
+	GET_FIELD( 8, h, sectionKind);
+	GET_FIELD( 8, h, shareKind);
+	GET_FIELD( 8, h, alignment);
+}
+
+static void pef_read_loader_info_header(PEFLoaderInfoHeader *h, uintptr adr)
+{
+	assert(sizeof(PEFLoaderInfoHeader) == 56);
+
+	GET_FIELD(32, h, mainSection);
+	GET_FIELD(32, h, mainOffset);
+	GET_FIELD(32, h, initSection);
+	GET_FIELD(32, h, initOffset);
+	GET_FIELD(32, h, termSection);
+	GET_FIELD(32, h, termOffset);
+	GET_FIELD(32, h, importedLibraryCount);
+	GET_FIELD(32, h, totalImportedSymbolCount);
+	GET_FIELD(32, h, relocSectionCount);
+	GET_FIELD(32, h, relocInstrOffset);
+	GET_FIELD(32, h, loaderStringsOffset);
+	GET_FIELD(32, h, exportHashOffset);
+	GET_FIELD(32, h, exportHashTablePower);
+	GET_FIELD(32, h, exportedSymbolCount);
+}
+
+static void pef_read_imported_library(PEFImportedLibrary *l, uintptr adr)
+{
+	assert(sizeof(PEFImportedLibrary) == 24);
+
+	GET_FIELD(32, l, nameOffset);
+	GET_FIELD(32, l, oldImpVersion);
+	GET_FIELD(32, l, currentVersion);
+	GET_FIELD(32, l, importedSymbolCount);
+	GET_FIELD(32, l, firstImportedSymbol);
+	GET_FIELD( 8, l, options);
+}
+
+static void pef_read_exported_symbol(PEFExportedSymbol *s, uintptr adr)
+{
+	assert(sizeof(PEFExportedSymbol) == 10);
+
+	GET_FIELD(32, s, classAndName);
+	GET_FIELD(32, s, symbolValue);
+	GET_FIELD(16, s, sectionIndex);
+}
+
+static void pef_read_traceback_table(PEFTracebackTable *tb, uintptr adr)
+{
+	assert(sizeof(PEFTracebackTable) == 8);
+
+	GET_FIELD(8, tb, version);
+	GET_FIELD(8, tb, lang);
+	GET_FIELD(8, tb, flags1);
+	GET_FIELD(8, tb, flags2);
+	GET_FIELD(8, tb, flags3);
+	GET_FIELD(8, tb, flags4);
+	GET_FIELD(8, tb, fixedparams);
+	GET_FIELD(8, tb, flags5);
+}
+
+#undef GET_FIELD_ARRAY
+#undef GET_FIELD
+#undef FIELD_OFFSET
+
+static string pef_sym_name(PEFObject *pef, PEFSymbol const & sym)
+{
+	string name;
+	name.reserve(sym.namelen + 1);
+	if (sym.namesec == pef->loader_shndx)
+		pef_memcpy((uint8 *)&name[0], pef->loader.loaderStringTable + sym.name, sym.namelen);
+	else {
+		PEFSection const & sec = pef->shdr[sym.namesec];
+		if (sec.is_packed_data)
+			memcpy((uint8 *)&name[0], sec.pdata, sym.namelen);
+		else
+			pef_memcpy((uint8 *)&name[0], sec.data + sym.name, sym.namelen);
+	}
+	name[sym.namelen] = '\0'; // XXX add continuation '...' for too long symbol names
+	return name;
+}
+
+static const char *pef_sym_class_name(int type)
+{
+	switch (type) {
+	case kPEFCodeSymbol:	return "CODE";	break;
+	case kPEFDataSymbol:	return "DATA";	break;
+	case kPEFTVectSymbol:	return "TVECT";	break;
+	case kPEFTOCSymbol:		return "TOC";	break;
+	case kPEFGlueSymbol:	return "GLUE";	break;
+	default:				return "";		break;
+	}
+}
+
+static uint32 pef_get_packed_data_count(uintptr & s)
+{
+	uint8 inst;
+	uint32 count = 0;
+
+	do {
+		inst = pef_get8(s++);
+		count = (count << 7) | (inst & 0x7f);
+	} while (inst & 0x80);
+
+	return count;
+}
+
+static bool pef_load_packed_data_section(PEFSection *sec)
+{
+	sec->is_packed_data = true;
+	uintptr s = sec->data;
+	const uintptr e = sec->data + sec->packedSize;
+	uint8 *d = sec->pdata = new uint8[sec->unpackedSize];
+
+	while (s < e) {
+		uint8 inst = pef_get8(s++);
+		uint32 opcode = (inst >> 5) & 0x07;
+		uint32 count = inst & 0x1f;
+
+		if (count == 0)
+			count = pef_get_packed_data_count(s);
+
+		switch (opcode) {
+		case 0:		// Zero
+			memset(d, 0, count);
+			d += count;
+			break;
+		case 1:		// blockCopy
+			pef_memcpy(d, s, count);
+			s += count;
+			d += count;
+			break;
+		case 2: {	// repeatedBlock
+			const int repeatCount = 1 + pef_get_packed_data_count(s);
+			for (int i = 0; i < repeatCount; i++) {
+				pef_memcpy(d, s, count);
+				d += count;
+			}
+			s += count;
+			break;
+		}
+		case 3: {	// interleaveRepeatBlockWithBlockCopy
+			const int customSize = pef_get_packed_data_count(s);
+			const int repeatCount = pef_get_packed_data_count(s);
+			const uintptr c = s; s += count;
+			for (int i = 0; i < repeatCount; i++) {
+				pef_memcpy(d, c, count);
+				d += count;
+				pef_memcpy(d, s, customSize);
+				s += customSize;
+				d += customSize;
+			}
+			pef_memcpy(d, c, count);
+			d += count;
+			break;
+		}
+		case 4: {	// interleaveRepeatBlockWithZero
+			const int customSize = pef_get_packed_data_count(s);
+			const int repeatCount = pef_get_packed_data_count(s);
+			for (int i = 0; i < repeatCount; i++) {
+				memset(d, 0, count);
+				d += count;
+				pef_memcpy(d, s, customSize);
+				s += customSize;
+				d += customSize;
+			}
+			memset(d, 0, count);
+			d += count;
+			break;
+		}
+		default:
+			D(bug("ERROR: unknown packed-data opcode %d\n", opcode));
+			return false;
+		}
+	}
+
+	if (s != e) {
+		D(bug("ERROR: packed-data input overflow\n"));
+		return false;
+	}
+
+	if ((d - sec->pdata) != sec->unpackedSize) {
+		D(bug("ERROR: packed-data output overflow\n"));
+		return false;
+	}
+
+	return true;
+}
+
+static bool pef_load_loader_section(PEFLoader *loader, PEFSection *loader_sec)
+{
+	// Get loader header
+	uintptr adr = loader_sec->data;
+	pef_read_loader_info_header(&loader->loaderHeader, adr);
+	adr += sizeof(PEFLoaderInfoHeader);
+
+	// Get imported symbols
+	const int n_imported_libraries = loader->loaderHeader.importedLibraryCount;
+	loader->importedLibraryTable = new PEFImportedLibrary[n_imported_libraries];
+	for (int i = 0; i < n_imported_libraries; i++, adr += sizeof(PEFImportedLibrary))
+		pef_read_imported_library(&loader->importedLibraryTable[i], adr);
+
+	const int n_imported_symbols = loader->loaderHeader.totalImportedSymbolCount;
+	PEFImportedSymbol *import_table = new PEFImportedSymbol[n_imported_symbols];
+	for (int i = 0; i < n_imported_symbols; i++, adr += 4) {
+		uint32 value = pef_get32(adr);
+		import_table[i].flags = (value >> 28) & 0xf;
+		import_table[i].symbolClass = (value >> 24) & 0xf;
+		import_table[i].nameOffset = value & 0x00ffffff;
+		import_table[i].symbolValue = 0xffffffff;
+	}
+	loader->importedSymbolTable = import_table;
+
+	// Get relocations (TODO)
+
+	// Get loader string table
+	adr = loader_sec->data + loader->loaderHeader.loaderStringsOffset;
+	loader->loaderStringTable = adr;
+
+	// Get export hash table
+	adr = loader_sec->data + loader->loaderHeader.exportHashOffset;
+	const int hash_table_size = 1 << loader->loaderHeader.exportHashTablePower;
+	PEFExportHash *hash_table = new PEFExportHash[hash_table_size];
+	for (int i = 0; i < hash_table_size; i++, adr += 4) {
+		uint32 value = pef_get32(adr);
+		hash_table[i].chainCount = (value >> 18) & 0x3fff;
+		hash_table[i].tableIndex = value & 0x3ffff;
+	}
+	loader->exportHashTable = hash_table;
+
+	// Get export key table
+	const int key_table_size = loader->loaderHeader.exportedSymbolCount;
+	PEFExportKey *key_table = new PEFExportKey[key_table_size];
+	for (int i = 0; i < key_table_size; i++, adr += 4) {
+		uint32 value = pef_get32(adr);
+		key_table[i].length = value >> 16;
+		key_table[i].encodedName = value & 0xffff;
+	}
+	loader->exportKeyTable = key_table;
+
+	// Get exported symbol table
+	const int symbol_table_size = loader->loaderHeader.exportedSymbolCount;
+	PEFExportedSymbol *symbol_table = new PEFExportedSymbol[symbol_table_size];
+	for (int i = 0; i < symbol_table_size; i++, adr += sizeof(PEFExportedSymbol))
+		pef_read_exported_symbol(&symbol_table[i], adr);
+	loader->exportedSymbolTable = symbol_table;
+
+	return true;
+}
+
+bool PEFObject::decode(uintptr adr)
+{
+	// Get PEF container
+	data = adr;
+	pef_read_container_header(&hdr, data);
+
+	// Check PEF identification
+	if (strncmp(hdr.tag1, "Joy!", 4) != 0)
+		return false;
+	if (strncmp(hdr.tag2, "peff", 4) != 0)
+		return false;
+
+	// Record section name table
+	nameTable = data + sizeof(PEFContainerHeader) + hdr.sectionCount * sizeof(PEFSectionHeader);
+
+	// Read section headers
+	shdr = new PEFSection[hdr.sectionCount];
+	for (int i = 0; i < hdr.sectionCount; i++) {
+		PEFSection * const sec = &shdr[i];
+		pef_read_section_header(sec, data + sizeof(PEFContainerHeader) + i * sizeof(PEFSectionHeader));
+		if (sec->nameOffset != -1)
+			sec->name = pef_get_string(nameTable + sec->nameOffset);
+		else {
+			switch (sec->sectionKind) {
+			case kPEFSectionCode:				sec->name = "code";				break;
+			case kPEFSectionUnpackedData:		sec->name = "unpacked-data";	break;
+			case kPEFSectionPackedData:			sec->name = "packed-data";		break;
+			case kPEFSectionConstant:			sec->name = "constant";			break;
+			case kPEFSectionLoader:				sec->name = "loader";			break;
+			case kPEFSectionDebug:				sec->name = "debug";			break;
+			case kPEFSectionExecutableData:		sec->name = "executable-data";	break;
+			case kPEFSectionException:			sec->name = "exception";		break;
+			case kPEFSectionTraceback:			sec->name = "traceback";		break;
+			default:							sec->name = "";					break;
+			}
+		}
+		switch (sec->sectionKind) {
+		case kPEFSectionCode:	code_shndx = i;		break;
+		case kPEFSectionLoader:	loader_shndx = i;	break;
+		}
+		sec->data = data + sec->containerOffset;
+
+		// Expand Pattern-Initialized Data
+		if (sec->sectionKind == kPEFSectionPackedData) {
+			if (!pef_load_packed_data_section(sec))
+				return false;
+		}
+	}
+
+	// Read loader header
+	if (loader_shndx != -1) {
+		if (!pef_load_loader_section(&loader, &shdr[loader_shndx]))
+			return false;
+
+		// Adjust main offset
+		if (valid_section(loader.loaderHeader.mainSection)) {
+			const PEFSection *sec = &shdr[loader.loaderHeader.mainSection];
+			if (sec->is_packed_data) { // TVECT
+				loader.loaderHeader.mainOffset = sec->get32(loader.loaderHeader.mainOffset);
+				loader.loaderHeader.mainSection = code_shndx;
+				sec = &shdr[code_shndx];
+			}
+			loader.loaderHeader.mainOffset += sec->containerOffset;
+		}
+
+		// Adjust initialization function offset
+		if (valid_section(loader.loaderHeader.initSection)) {
+			const PEFSection *sec = &shdr[loader.loaderHeader.initSection];
+			if (sec->is_packed_data) { // TVECT
+				loader.loaderHeader.initOffset = sec->get32(loader.loaderHeader.initOffset);
+				loader.loaderHeader.initSection = code_shndx;
+				sec = &shdr[code_shndx];
+			}
+			loader.loaderHeader.initOffset += sec->containerOffset;
+		}
+
+		// Adjust termination function offset
+		if (valid_section(loader.loaderHeader.termSection)) {
+			const PEFSection *sec = &shdr[loader.loaderHeader.termSection];
+			if (sec->is_packed_data) { // TVECT
+				loader.loaderHeader.termOffset = sec->get32(loader.loaderHeader.termOffset);
+				loader.loaderHeader.termSection = code_shndx;
+				sec = &shdr[code_shndx];
+			}
+			loader.loaderHeader.termOffset += sec->containerOffset;
+		}
+
+		// Decode stubs for imported functions
+		if (code_shndx != -1) {
+			const PEFSection * const sec = &shdr[code_shndx];
+			const uintptr code_end = sec->data + sec->unpackedSize;
+			for (uintptr code = sec->data; code < code_end; code += 4) {
+				uint32 inst = pef_get32(code);
+				if ((inst & 0xffff0000) == 0x81820000) {		// lwz	 r12,$0000(r2)
+					if (code + 24 > code_end)
+						break;
+					if (pef_get32(code + 4*1) != 0x90410014)	// stw   r2,$0014(r1)
+						continue;
+					if (pef_get32(code + 4*2) != 0x800c0000)	// lwz   r0,$0000(r12)
+						continue;
+					if (pef_get32(code + 4*3) != 0x804c0004)	// lwz   r2,$0004(r12)
+						continue;
+					if (pef_get32(code + 4*4) != 0x7c0903a6)	// mtctr r0
+						continue;
+					if (pef_get32(code + 4*5) != 0x4e800420)	// bctr
+						continue;
+					uint32 index = (inst & 0x0000ffff) / 4;
+					if (index < loader.loaderHeader.totalImportedSymbolCount) {
+						PEFImportedSymbol & sym = loader.importedSymbolTable[index];
+						sym.symbolClass = kPEFCodeSymbol;
+						sym.symbolValue = sec->containerOffset + code - sec->data;
+					}
+					code += 20;
+				}
+			}
+		}
+
+		// Try to build symbol table from traceback tables first
+		symtab.clear();
+		if (code_shndx != -1) {
+			const PEFSection * const sec = &shdr[code_shndx];
+			const uintptr code = sec->data;
+			for (uint32 pos = 0; pos < sec->unpackedSize; pos += 4) {
+				if (pef_get8(code + pos + 0) != 0)
+					continue;
+				if (pef_get8(code + pos + 1) != 0)
+					continue;
+				if (pef_get8(code + pos + 2) != 0)
+					continue;
+				if (pef_get8(code + pos + 3) != 0)
+					continue;
+				if (4 + pos + 8 > sec->unpackedSize)
+					break;
+				struct PEFTracebackTable tb;
+				pef_read_traceback_table(&tb, code + 4 + pos);
+				if (tb.lang != TB_C && tb.lang != TB_CPLUSPLUS)
+					continue;
+				if ((tb.flags2 & TB_NAME_PRESENT) == 0)
+					continue;
+				if ((tb.flags1 & TB_HAS_TBOFF) == 0)
+					continue;
+				int offset = 8;
+				if ((tb.flags5 & TB_FLOATPARAMS) || tb.fixedparams)
+					offset += 4;
+				PEFSymbol sym;
+				if (tb.flags1 & TB_HAS_TBOFF) {
+					if (4 + pos + offset + 4 > sec->unpackedSize)
+						break;
+					sym.value = sec->containerOffset + pos - pef_get32(code + 4 + pos + offset);
+					offset += 4;
+				}
+				if (tb.flags2 & TB_INT_HNDL)
+					offset += 4;
+				if (tb.flags1 & TB_HAS_CTL) {
+					if (4 + pos + offset + 4 > sec->unpackedSize)
+						break;
+					const int n_ctl_info = pef_get32(code + 4 + pos + offset);
+					offset += 4;
+					if (n_ctl_info > 1024)
+						continue;
+					offset += n_ctl_info * 4;
+				}
+				if (tb.flags2 & TB_NAME_PRESENT) {
+					if (4 + pos + offset + 2 > sec->unpackedSize)
+						break;
+					uint32 namelen = pef_get16(code + 4 + pos + offset);
+					offset += 2;
+					uint32 nameoff = 4 + pos + offset;
+					offset += namelen;
+					if (nameoff + namelen > sec->unpackedSize)
+						break;
+					if (pef_get8(code + nameoff) == '.') // strip leading '.'
+						nameoff++, namelen--;
+					sym.name = nameoff;
+					sym.namelen = namelen;
+				}
+				if (tb.flags2 & TB_USES_ALLOCA)
+					offset += 4;
+				if (tb.flags4 & TB_HAS_VEC_INFO)
+					offset += 4;
+				offset = (offset + 3) & -4;
+
+				sym.namesec = code_shndx;
+				sym.type  = kPEFCodeSymbol;
+				sym.shndx = code_shndx;
+				symtab.push_back(sym);
+
+				pos += offset;
+			}
+		}
+
+		// Expand table with export symbols
+		const PEFExportKey * const key_table = loader.exportKeyTable;
+		const PEFExportedSymbol * const symbol_table = loader.exportedSymbolTable;
+		for (unsigned int i = 0; i < loader.loaderHeader.exportedSymbolCount; i++) {
+			PEFSymbol sym;
+			sym.value = symbol_table[i].symbolValue;
+			sym.name  = symbol_table[i].classAndName & 0xffffff;
+			sym.namelen = key_table[i].length;
+			sym.namesec = loader_shndx;
+			sym.type  = symbol_table[i].classAndName >> 24;
+			sym.shndx = symbol_table[i].sectionIndex;
+			symtab.push_back(sym);
+
+			// Try to match a function from its TVECT
+			if (sym.type == kPEFTVectSymbol && valid_section(code_shndx) && valid_section(sym.shndx)) {
+				const PEFSection * const sec = &shdr[sym.shndx];
+				if (sym.value + 4 <= sec->unpackedSize) {
+					sym.value = shdr[code_shndx].containerOffset + sec->get32(sym.value);
+					sym.type  = kPEFCodeSymbol;
+					sym.shndx = code_shndx;
+					symtab.push_back(sym);
+				}
+			}
+		}
+
+		// Sort symbol table by section index and address in that section
+		std::sort(symtab.begin(), symtab.end());
+	}
+	
+	return true;
+}
+
+static PEFObject *PEF_Decode(uintptr adr)
+{
+	PEFObject *p = new(std::nothrow) PEFObject;
+	if (p == NULL)
+		return NULL;
+
+	if (!p->decode(adr)) {
+		delete p;
+		return NULL;
+	}
+
+	return p;
+}
+
+void PEFObject::dump(bool relative)
+{
+	// XXX fix this mess
+	const uintptr base = relative ? 0 : data;
+
+	pef_printf("PEF Container Header:\n");
+	pef_printf("  %-32s: '%c%c%c%c'\n", "Architecture", hdr.architecture[0], hdr.architecture[1], hdr.architecture[2], hdr.architecture[3]);
+	pef_printf("  %-32s: %d\n", "Version", hdr.formatVersion);
+	pef_printf("  %-32s: %d\n", "Number of sections", hdr.sectionCount);
+	pef_printf("  %-32s: %d\n", "Number of instantiated sections", hdr.instSectionCount);
+	pef_printf("\n");
+
+	pef_printf("Section Headers:\n");
+	pef_printf("[Nr] %-28s %-*s %-8s %-8s %-5s %-5s\n",
+			   "Name", 2 * sizeof(uintptr), "Addr", "File off", "Size", "Share", "Algn");
+	for (int i = 0; i < hdr.sectionCount; i++) {
+		PEFSection *sec = &shdr[i];
+		const char *shareKind = "";
+		switch (sec->shareKind) {
+		case kPEFShareProcess:			shareKind = "PROC"; break;
+		case kPEFShareGlobal:			shareKind = "GLOB"; break;
+		case kPEFShareProtected:		shareKind = "PROT"; break;
+		}
+		pef_printf("[%2d] %-28s %0*lx %08x %08x %-5s 2**%d\n", i, sec->name.c_str(),
+				   2 * sizeof(uintptr), base + sec->containerOffset, sec->containerOffset,
+				   sec->packedSize, shareKind, sec->alignment);
+	}
+	pef_printf("\n");
+
+	if (loader_shndx != -1) {
+		pef_printf("Loader section [%2d]:\n", loader_shndx);
+		PEFLoaderInfoHeader *ldr = &loader.loaderHeader;
+		pef_printf("  %-32s: ", "Main symbol");
+		if (ldr->mainSection == -1)
+			pef_printf("NONE\n");
+		else
+			pef_printf("%0*lx\n", 2 * sizeof(uintptr), base + ldr->mainOffset);
+		pef_printf("  %-32s: ", "Initialization function");
+		if (ldr->initSection == -1)
+			pef_printf("NONE\n");
+		else
+			pef_printf("%0*lx\n", 2 * sizeof(uintptr), base + ldr->initOffset);
+		pef_printf("  %-32s: ", "Termination function");
+		if (ldr->termSection == -1)
+			pef_printf("NONE\n");
+		else
+			pef_printf("%0*lx\n", 2 * sizeof(uintptr), base + ldr->termOffset);
+		pef_printf("  %-32s: %d\n", "Number of imported libraries", ldr->importedLibraryCount);
+		pef_printf("  %-32s: %d\n", "Number of imported symbols", ldr->totalImportedSymbolCount);
+		pef_printf("  %-32s: %d\n", "Number of exported symbols", ldr->exportedSymbolCount);
+	}
+	pef_printf("\n");
+
+	for (unsigned int i = 0; i < loader.loaderHeader.importedLibraryCount; i++) {
+		PEFImportedLibrary *lib = &loader.importedLibraryTable[i];
+		const string & lib_name = pef_get_string(loader.loaderStringTable + lib->nameOffset);
+		pef_printf("Import symbol table for '%s' contains %d entries:\n", lib_name.c_str(), lib->importedSymbolCount);
+		pef_printf("%5s: %-*s %-5s %-5s %s\n", "Num", 2 * sizeof(uintptr), "Value", "Class", "Flags", "Name");
+		for (unsigned int j = 0; j < lib->importedSymbolCount; j++) {
+			PEFImportedSymbol const & sym = loader.importedSymbolTable[lib->firstImportedSymbol + j];
+			const string & sym_name = pef_get_string(loader.loaderStringTable + sym.nameOffset);
+			const char *sym_class = (sym.flags & 0x80) ? "WEAK" : "NONE";
+			uintptr sym_value = sym.symbolValue == 0xffffffff ? ~0UL : base + sym.symbolValue;
+			pef_printf("%5d: %0*lx %5s %5s __stub_%s\n",
+					   j, 2 * sizeof(uintptr), sym_value, pef_sym_class_name(sym.symbolClass), sym_class, sym_name.c_str());
+		}
+		pef_printf("\n");
+	}
+
+	if (symtab.size() > 0) {
+		pef_printf("Symbol table contains %d entries:\n", symtab.size());
+		pef_printf("%5s: %-8s %-5s %-5s %s\n", "Num", "Value", "Class", "Shndx", "Name");
+		for (unsigned int i = 0; i < symtab.size(); i++) {
+			PEFSymbol const & sym = symtab[i];
+			const string & sym_name = pef_sym_name(this, sym);
+			pef_printf("%5d: %0*lx %-5s %5d %s\n",
+					   i, 2 * sizeof(uintptr), base + sym.value, pef_sym_class_name(sym.type), sym.shndx, sym_name.c_str());
+		}
+		pef_printf("\n");
+	}
+}
+
+
+/*
+ *  Dump PEF object
+ *  pef start
+ */
+
+#ifndef TEST
+void dump_pef(void)
+{
+	uintptr adr;
+
+	if (!mon_expression(&adr))
+		return;
+
+	PEFObject *pef = PEF_Decode(adr);
+	if (pef) {
+		pef->dump();
+		delete pef;
+	}
+}
+#endif
+
+
+/*
+ *  Standalone test program
+ */
+
+#ifdef TEST
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+int main(int argc, char *argv[])
+{
+	for (int i = 1; i < argc; i++) {
+		const char *file_name = argv[i];
+		int fd = open(file_name, O_RDONLY);
+		if (fd < 0) {
+			perror("open");
+			continue;
+		}
+		struct stat st;
+		if (fstat(fd, &st) < 0) {
+			perror("fstat");
+			close(fd);
+			continue;
+		}
+		const uint32 page_size = getpagesize();
+		const uint32 file_size = (st.st_size + page_size - 1) & -page_size;
+		char *file_map = (char *)mmap(0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
+		if (file_map == MAP_FAILED) {
+			perror("mmap");
+			close(fd);
+			continue;
+		}
+		PEFObject *pef = PEF_Decode((uintptr)file_map);
+		if (pef) {
+			pef->dump(true);
+			delete pef;
+		}
+		munmap(file_map, file_size);
+		close(fd);
+	}
+}
+#endif