From 0fae05ddc83ee034344d50a6d4d618cfb10ee491 Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Tue, 19 Jun 2001 03:37:46 +0000 Subject: Initial revision svn path=/trunk/mono/; revision=9 --- AUTHORS | 1 + ChangeLog | 4 + Makefile.am | 1 + NEWS | 3 + README | 3 + config.h.in | 11 ++ configure.in | 34 +++++ mono/Makefile.am | 1 + mono/dis/Makefile.am | 10 ++ mono/dis/main.c | 77 ++++++++++++ mono/metadata/Makefile.am | 19 +++ mono/metadata/assembly.c | 303 +++++++++++++++++++++++++++++++++++++++++++++ mono/metadata/assembly.h | 20 +++ mono/metadata/cil-coff.h | 156 +++++++++++++++++++++++ mono/metadata/metadata.c | 13 ++ mono/metadata/metadata.h | 18 +++ mono/metadata/pedump.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++ mono/metadata/rawbuffer.c | 70 +++++++++++ mono/metadata/rawbuffer.h | 3 + 19 files changed, 1056 insertions(+) create mode 100644 AUTHORS create mode 100644 ChangeLog create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 config.h.in create mode 100644 configure.in create mode 100644 mono/Makefile.am create mode 100644 mono/dis/Makefile.am create mode 100644 mono/dis/main.c create mode 100644 mono/metadata/Makefile.am create mode 100644 mono/metadata/assembly.c create mode 100644 mono/metadata/assembly.h create mode 100644 mono/metadata/cil-coff.h create mode 100644 mono/metadata/metadata.c create mode 100644 mono/metadata/metadata.h create mode 100644 mono/metadata/pedump.c create mode 100644 mono/metadata/rawbuffer.c create mode 100644 mono/metadata/rawbuffer.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000000..25e66d4943c --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Miguel de Icaza (miguel@ximian.com) diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000000..1a76f446632 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,4 @@ +2001-05-30 Miguel de Icaza + + * NEWS: + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000000..7a0d4a47da8 --- /dev/null +++ b/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = mono diff --git a/NEWS b/NEWS new file mode 100644 index 00000000000..37b3c8595b0 --- /dev/null +++ b/NEWS @@ -0,0 +1,3 @@ +2001-05-30 Miguel de Icaza + + Project started diff --git a/README b/README new file mode 100644 index 00000000000..27f2ef4c497 --- /dev/null +++ b/README @@ -0,0 +1,3 @@ +This is MonoNet. + +Ximian's portable implementation of .NET diff --git a/config.h.in b/config.h.in new file mode 100644 index 00000000000..f871c4edf55 --- /dev/null +++ b/config.h.in @@ -0,0 +1,11 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Name of package */ +#undef PACKAGE + +/* Version number of package */ +#undef VERSION + diff --git a/configure.in b/configure.in new file mode 100644 index 00000000000..b146447d4d7 --- /dev/null +++ b/configure.in @@ -0,0 +1,34 @@ +AC_INIT(README) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(mononet, 0.1) +AM_MAINTAINER_MODE + +AC_PROG_CC +AM_PROG_CC_STDC +AC_PROG_INSTALL + +# Set STDC_HEADERS +AC_HEADER_STDC +AM_PROG_LIBTOOL + +dnl *************************** +dnl *** Checks for glib 1.2 *** +dnl *************************** +AM_PATH_GLIB(1.2.0,, + AC_MSG_ERROR([Cannot find GLIB: Is glib-config in path?])) + +GLIB_CFLAGS=`glib-config --cflags glib` +GLIB_LIBS=`glib-config --libs glib` + +AC_SUBST(GLIB_CFLAGS) +AC_SUBST(GLIB_LIBS) + +CFLAGS='-g -Wall -Wunused -Wmissing-prototypes -Wmissing-declarations' +AC_SUBST(CFLAGS) + +AC_OUTPUT([ +Makefile +mono/Makefile +mono/metadata/Makefile +mono/dis/Makefile +]) \ No newline at end of file diff --git a/mono/Makefile.am b/mono/Makefile.am new file mode 100644 index 00000000000..89d68d86d83 --- /dev/null +++ b/mono/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = metadata dis \ No newline at end of file diff --git a/mono/dis/Makefile.am b/mono/dis/Makefile.am new file mode 100644 index 00000000000..fdb8662c28c --- /dev/null +++ b/mono/dis/Makefile.am @@ -0,0 +1,10 @@ +INCLUDES = $(GLIB_CFLAGS) -I$(top_srcdir) + +bin_PROGRAMS = monodis + +monodis_SOURCES = \ + main.c + +monodis_LDADD = \ + ../metadata/libmetadata.a \ + $(GLIB_LIBS) diff --git a/mono/dis/main.c b/mono/dis/main.c new file mode 100644 index 00000000000..49f9027c1e2 --- /dev/null +++ b/mono/dis/main.c @@ -0,0 +1,77 @@ +/* + * dis.c: Sample disassembler + * + * Author: + * Miguel de Icaza (miguel@ximian.com) + * + * (C) 2001 Ximian, Inc. + */ +#include +#include +#include +#include +#include + +FILE *output; + +/* True if you want to get a dump of the header data */ +gboolean dump_header_data_p = FALSE; + +static void +dump_header_data (MonoAssembly *ass) +{ + if (!dump_header_data_p) + return; + + fprintf (output, + "// Ximian's CIL disassembler, version 1.0\n" + "// Copyright (C) 2001 Ximian, Inc.\n\n"); +} + +static void +disassemble_file (const char *file) +{ + enum MonoAssemblyOpenStatus status; + MonoAssembly *ass; + + ass = mono_assembly_open (file, &status); + if (ass == NULL){ + fprintf (stderr, "Error while trying to process %s\n", file); + + } + + dump_header_data (ass); + + mono_assembly_close (ass); +} + +static void +usage (void) +{ + fprintf (stderr, "Usage is: monodis file1 ..\n"); + exit (1); +} + +int +main (int argc, char *argv []) +{ + GList *input_files = NULL, *l; + int i; + + output = stdout; + for (i = 1; i < argc; i++){ + if (argv [i][0] == '-'){ + if (argv [i][1] == 'h') + usage (); + else if (argv [i][1] == 'd') + dump_header_data_p = TRUE; + } else + input_files = g_list_append (input_files, argv [i]); + } + + if (input_files == NULL) + usage (); + + for (l = input_files; l; l = l->next) + disassemble_file (l->data); +} diff --git a/mono/metadata/Makefile.am b/mono/metadata/Makefile.am new file mode 100644 index 00000000000..505141d5abc --- /dev/null +++ b/mono/metadata/Makefile.am @@ -0,0 +1,19 @@ +noinst_PROGRAMS = pedump + +lib_LIBRARIES = libmetadata.a + +INCLUDES = $(GLIB_CFLAGS) -I$(top_srcdir) + +libmetadata_a_SOURCES = \ + assembly.h \ + assembly.c \ + cil-coff.h \ + metadata.c \ + metadata.h \ + rawbuffer.c \ + rawbuffer.h + +pedump_SOURCES = \ + pedump.c $(libmetadata_a_SOURCES) + +pedump_LDADD = $(GLIB_LIBS) diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c new file mode 100644 index 00000000000..6d6b2602d7f --- /dev/null +++ b/mono/metadata/assembly.c @@ -0,0 +1,303 @@ +/* + * assembly.c: Routines for manipulating and assembly stored in an + * extended PE/COFF file. + * + * Author: + * Miguel de Icaza (miguel@ximian.com) + * + * (C) 2001 Ximian, Inc. http://www.ximian.com + * + * TODO: + * Do byteswaps for big-endian systems on the various headers. + */ +#include +#include +#include +#include +#include +#include "assembly.h" +#include "cil-coff.h" +#include "rawbuffer.h" + +#define INVALID_ADDRESS 0xffffffff + +/* FIXME: implement big endian versions */ +#define le64_to_cpu(x) (x) +#define le32_to_cpu(x) (x) +#define le16_to_cpu(x) (x) +#define read32(x) le32_to_cpu (*((guint32 *) (x))) +#define read16(x) le16_to_cpu (*((guint16 *) (x))) +#define read64(x) le64_to_cpu (*((guint64 *) (x))) + +static guint32 +coff_map (dotnet_image_info_t *iinfo, guint32 addr) +{ + const int top = iinfo->dn_section_count; + section_table_t *tables = iinfo->dn_section_tables; + int i; + + for (i = 0; i < top; i++){ + if ((addr >= tables->st_virtual_address) && + (addr < tables->st_virtual_address + tables->st_raw_data_size)){ + return addr - tables->st_virtual_address + tables->st_raw_data_ptr; + } + tables++; + } + return INVALID_ADDRESS; +} + +static int +load_section_tables (MonoAssembly *assembly, dotnet_image_info_t *iinfo) +{ + const int top = iinfo->dn_header.coff.coff_sections; + int i; + + iinfo->dn_section_count = top; + iinfo->dn_section_tables = g_new (section_table_t, top); + + for (i = 0; i < top; i++){ + section_table_t *t = &iinfo->dn_section_tables [i]; + + if (fread (t, sizeof (section_table_t), 1, assembly->f) != 1) + return FALSE; + + t->st_virtual_size = le32_to_cpu (t->st_virtual_size); + t->st_virtual_address = le32_to_cpu (t->st_virtual_address); + t->st_raw_data_size = le32_to_cpu (t->st_raw_data_size); + t->st_raw_data_ptr = le32_to_cpu (t->st_raw_data_ptr); + t->st_reloc_ptr = le32_to_cpu (t->st_reloc_ptr); + t->st_lineno_ptr = le32_to_cpu (t->st_lineno_ptr); + t->st_reloc_count = le16_to_cpu (t->st_reloc_count); + t->st_line_count = le16_to_cpu (t->st_line_count); + } + + return TRUE; +} + +static gboolean +load_cli_header (MonoAssembly *assembly, dotnet_image_info_t *iinfo) +{ + guint32 offset; + int n; + + offset = coff_map (iinfo, iinfo->dn_header.datadir.pe_cli_header.rva); + if (offset == INVALID_ADDRESS) + return FALSE; + + if (fseek (assembly->f, offset, 0) != 0) + return FALSE; + + if ((n = fread (&iinfo->dn_cli_header, sizeof (cli_header_t), 1, assembly->f)) != 1) + return FALSE; + + /* Catch new uses of the fields that are supposed to be zero */ + + if ((iinfo->dn_cli_header.ch_eeinfo_table.rva != 0) || + (iinfo->dn_cli_header.ch_helper_table.rva != 0) || + (iinfo->dn_cli_header.ch_dynamic_info.rva != 0) || + (iinfo->dn_cli_header.ch_delay_load_info.rva != 0) || + (iinfo->dn_cli_header.ch_module_image.rva != 0) || + (iinfo->dn_cli_header.ch_external_fixups.rva != 0) || + (iinfo->dn_cli_header.ch_ridmap.rva != 0) || + (iinfo->dn_cli_header.ch_debug_map.rva != 0) || + (iinfo->dn_cli_header.ch_ip_map.rva != 0)){ + g_message ("Some fields in the CLI header which should have been zero are not zero"); + } + + return TRUE; +} + +static gboolean +load_metadata_ptrs (MonoAssembly *assembly, dotnet_image_info_t *iinfo) +{ + metadata_t *metadata = &iinfo->dn_metadata; + guint32 offset, size; + guint16 records; + int i; + char *ptr; + + offset = coff_map (iinfo, iinfo->dn_cli_header.ch_metadata.rva); + size = iinfo->dn_cli_header.ch_metadata.size; + + metadata->raw_metadata = raw_buffer_load (fileno (assembly->f), FALSE, offset, size); + if (metadata->raw_metadata == NULL) + return FALSE; + + ptr = metadata->raw_metadata; + + /* + * Handle Beta 1 and ECMA versions of the metadata root + */ + if (strncmp (ptr, "COM+", 4) == 0){ + ptr += 10; + } else if (strncmp (ptr, "BSJB", 4) == 0){ + guint32 version_string_len; + + ptr += 8; + version_string_len = read32 (ptr); + ptr += version_string_len; + if (((guint32) ptr) % 4) + ptr += 4 - (((guint32) ptr) %4); + } + + records = read16 (ptr); + ptr += 2; + + for (i = 0; i < records; i++){ + if (strncmp (ptr + 8, "#~", 3) == 0){ + metadata->heap_tables.sh_offset = read32 (ptr); + metadata->heap_tables.sh_size = read32 (ptr + 4); + ptr += 8 + 3; + } else if (strncmp (ptr + 8, "#Strings", 9) == 0){ + metadata->heap_strings.sh_offset = read32 (ptr); + metadata->heap_strings.sh_size = read32 (ptr + 4); + ptr += 8 + 9; + } else if (strncmp (ptr + 8, "#US", 4) == 0){ + metadata->heap_us.sh_offset = read32 (ptr); + metadata->heap_us.sh_size = read32 (ptr + 4); + ptr += 8 + 4; + } else if (strncmp (ptr + 8, "#Blob", 6) == 0){ + metadata->heap_blob.sh_offset = read32 (ptr); + metadata->heap_blob.sh_size = read32 (ptr + 4); + ptr += 8 + 6; + } else if (strncmp (ptr + 8, "#GUID", 6) == 0){ + metadata->heap_guid.sh_offset = read32 (ptr); + metadata->heap_guid.sh_size = read32 (ptr + 4); + ptr += 8 + 6; + } else + g_message ("Unknown heap type: %s\n", ptr + 8); + if (((guint32)ptr) % 4){ + ptr += 4 - (((guint32)ptr) % 4); + } + } + return TRUE; +} + +static gboolean +load_tables (MonoAssembly *assembly, metadata_t *meta) +{ + char *heap_tables = meta->raw_metadata + meta->heap_tables.sh_offset; + guint32 *rows; + guint64 valid_mask; + int valid = 0, table; + + valid_mask = read64 (heap_tables + 8); + rows = (guint32 *) (heap_tables + 24); + + for (table = 0; table < 64; table++){ + if ((valid_mask & ((guint64) 1 << table)) == 0){ + meta->rows [table] = 0; + continue; + } + meta->rows [table] = *rows; + rows++; + valid++; + } + + return TRUE; +} + +static gboolean +load_metadata (MonoAssembly *assembly, dotnet_image_info_t *iinfo) +{ + if (!load_metadata_ptrs (assembly, iinfo)) + return FALSE; + + return load_tables (assembly, &iinfo->dn_metadata); +} + +MonoAssembly * +mono_assembly_open (const char *fname, enum MonoAssemblyOpenStatus *status) +{ + dotnet_image_info_t *iinfo; + dotnet_header_t *header; + msdos_header_t msdos; + MonoAssembly *assembly; + int n; + + assembly = g_new (MonoAssembly, 1); + assembly->f = fopen (fname, "r"); + iinfo = g_new (dotnet_image_info_t, 1); + assembly->image_info = iinfo; + + header = &iinfo->dn_header; + + if (assembly->f == NULL){ + if (status) + *status = MONO_ASSEMBLY_ERROR_ERRNO; + mono_assembly_close (assembly); + return NULL; + } + + if (status) + *status = MONO_ASSEMBLY_IMAGE_INVALID; + + if (fread (&msdos, sizeof (msdos), 1, assembly->f) != 1) + goto invalid_image; + + if (!(msdos.msdos_header [0] == 0x4d && msdos.msdos_header [1] == 0x5a)) + goto invalid_image; + + if ((n = fread (header, sizeof (dotnet_header_t), 1, assembly->f)) != 1) + goto invalid_image; + + /* + * FIXME: byte swap all addresses here for header. + */ + + if (!load_section_tables (assembly, iinfo)) + goto invalid_image; + + /* Load the CLI header */ + if (!load_cli_header (assembly, iinfo)) + goto invalid_image; + + if (!load_metadata (assembly, iinfo)) + goto invalid_image; + + if (status) + *status = MONO_ASSEMBLY_OK; + + return assembly; + +invalid_image: + mono_assembly_close (assembly); + return NULL; +} + +void +mono_assembly_close (MonoAssembly *assembly) +{ + g_return_if_fail (assembly != NULL); + + if (assembly->f) + fclose (assembly->f); + + if (assembly->image_info){ + dotnet_image_info_t *ii = assembly->image_info; + + if (ii->dn_metadata.raw_metadata != NULL) + raw_buffer_free (ii->dn_metadata.raw_metadata); + + if (ii->dn_section_tables) + g_free (ii->dn_section_tables); + + g_free (assembly->image_info); + } + + g_free (assembly); +} + +const char * +mono_assembly_strerror (enum MonoAssemblyOpenStatus status) +{ + switch (status){ + case MONO_ASSEMBLY_OK: + return "succes"; + case MONO_ASSEMBLY_ERROR_ERRNO: + return strerror (errno); + case MONO_ASSEMBLY_IMAGE_INVALID: + return "File does not contain a valid CIL image"; + } + return "Internal error"; +} diff --git a/mono/metadata/assembly.h b/mono/metadata/assembly.h new file mode 100644 index 00000000000..dcec354f007 --- /dev/null +++ b/mono/metadata/assembly.h @@ -0,0 +1,20 @@ +#ifndef _MONONET_METADATA_ASSEMBLY_H_ +#define _MONONET_METADATA_ASSEMBLY_H_ + +typedef struct { + FILE *f; + void *image_info; +} MonoAssembly; + +enum MonoAssemblyOpenStatus { + MONO_ASSEMBLY_OK, + MONO_ASSEMBLY_ERROR_ERRNO, + MONO_ASSEMBLY_IMAGE_INVALID +}; + +MonoAssembly *mono_assembly_open (const char *fname, enum MonoAssemblyOpenStatus *status); +void mono_assembly_close (MonoAssembly *assembly); + +const char *mono_assembly_strerror (enum MonoAssemblyOpenStatus status); + +#endif diff --git a/mono/metadata/cil-coff.h b/mono/metadata/cil-coff.h new file mode 100644 index 00000000000..ee4f001e2b0 --- /dev/null +++ b/mono/metadata/cil-coff.h @@ -0,0 +1,156 @@ +#include + +/* A metadata token */ +typedef guint32 mtoken_t; + +typedef struct { + char msdos_header [128]; +} msdos_header_t; + +typedef struct { + guint16 coff_machine; + guint16 coff_sections; + guint32 coff_time; + guint32 coff_symptr; + guint32 coff_symcount; + guint16 coff_opt_header_size; + guint16 coff_attributes; +} coff_header_t; + +#define COFF_ATTRIBUTE_EXECUTABLE_IMAGE 0x0002 +#define COFF_ATTRIBUTE_LIBRARY_IMAGE 0x2000 + +typedef struct { + guint16 pe_magic; + guchar pe_major; + guchar pe_minor; + guint32 pe_code_size; + guint32 pe_data_size; + guint32 pe_uninit_data_size; + guint32 pe_rva_entry_point; + guint32 pe_rva_code_base; + guint32 pe_rva_data_base; +} pe_header_t; + +typedef struct { + guint32 pe_image_base; /* must be 0x400000 */ + guint32 pe_section_align; /* must be 8192 */ + guint32 pe_file_alignment; /* must be 512 or 4096 */ + guint16 pe_os_major; /* must be 4 */ + guint16 pe_os_minor; /* must be 0 */ + guint16 pe_user_major; + guint16 pe_user_minor; + guint16 pe_subsys_major; + guint16 pe_subsys_minor; + guint32 pe_reserved_1; + guint32 pe_image_size; + guint32 pe_header_size; + guint32 pe_checksum; + guint16 pe_subsys_required; + guint16 pe_dll_flags; + guint32 pe_stack_reserve; + guint32 pe_stack_commit; + guint32 pe_heap_reserve; + guint32 pe_heap_commit; + guint32 pe_loader_flags; + guint32 pe_data_dir_count; +} pe_header_nt_t; + +typedef struct { + guint32 rva; + guint32 size; +} pe_dir_entry_t; + +typedef struct { + pe_dir_entry_t pe_export_table; + pe_dir_entry_t pe_import_table; + pe_dir_entry_t pe_resource_table; + pe_dir_entry_t pe_exception_table; + pe_dir_entry_t pe_certificate_table; + pe_dir_entry_t pe_reloc_table; + pe_dir_entry_t pe_debug; + pe_dir_entry_t pe_copyright; + pe_dir_entry_t pe_global_ptr; + pe_dir_entry_t pe_tls_table; + pe_dir_entry_t pe_load_config_table; + pe_dir_entry_t pe_bound_import; + pe_dir_entry_t pe_iat; + pe_dir_entry_t pe_delay_import_desc; + pe_dir_entry_t pe_cli_header; + pe_dir_entry_t pe_reserved; +} pe_datadir_t; + +typedef struct { + char pesig [4]; + coff_header_t coff; + pe_header_t pe; + pe_header_nt_t nt; + pe_datadir_t datadir; +} dotnet_header_t; + +typedef struct { + char st_name [8]; + guint32 st_virtual_size; + guint32 st_virtual_address; + guint32 st_raw_data_size; + guint32 st_raw_data_ptr; + guint32 st_reloc_ptr; + guint32 st_lineno_ptr; + guint16 st_reloc_count; + guint16 st_line_count; + +#define SECT_FLAGS_HAS_CODE 0x20 +#define SECT_FLAGS_HAS_INITIALIZED_DATA 0x40 +#define SECT_FLAGS_HAS_UNINITIALIZED_DATA 0x80 +#define SECT_FLAGS_MEM_DISCARDABLE 0x02000000 +#define SECT_FLAGS_MEM_NOT_CACHED 0x04000000 +#define SECT_FLAGS_MEM_NOT_PAGED 0x08000000 +#define SECT_FLAGS_MEM_SHARED 0x10000000 +#define SECT_FLAGS_MEM_EXECUTE 0x20000000 +#define SECT_FLAGS_MEM_READ 0x40000000 +#define SECT_FLAGS_MEM_WRITE 0x80000000 + guint32 st_flags; +} section_table_t; + +typedef struct { + guint32 ch_size; + guint16 ch_runtime_major; + guint16 ch_runtime_minor; + pe_dir_entry_t ch_metadata; + +#define CLI_FLAGS_ILONLY 0x01 +#define CLI_FLAGS_32BITREQUIRED 0x02 +#define CLI_FLAGS_TRACKDEBUGDATA 0x00010000 + guint32 ch_flags; + + mtoken_t ch_entry_point; + pe_dir_entry_t ch_resources; + pe_dir_entry_t ch_strong_name; + pe_dir_entry_t ch_code_manager_table; + pe_dir_entry_t ch_vtable_fixups; + pe_dir_entry_t ch_export_address_table_jumps; + + /* The following are zero in the current docs */ + pe_dir_entry_t ch_eeinfo_table; + pe_dir_entry_t ch_helper_table; + pe_dir_entry_t ch_dynamic_info; + pe_dir_entry_t ch_delay_load_info; + pe_dir_entry_t ch_module_image; + pe_dir_entry_t ch_external_fixups; + pe_dir_entry_t ch_ridmap; + pe_dir_entry_t ch_debug_map; + pe_dir_entry_t ch_ip_map; +} cli_header_t; + +/* This is not an on-disk structure */ +typedef struct { + dotnet_header_t dn_header; + int dn_section_count; + section_table_t *dn_section_tables; + cli_header_t dn_cli_header; + + metadata_t dn_metadata; +} dotnet_image_info_t; + + + diff --git a/mono/metadata/metadata.c b/mono/metadata/metadata.c new file mode 100644 index 00000000000..02db6e5c04b --- /dev/null +++ b/mono/metadata/metadata.c @@ -0,0 +1,13 @@ +/* + * metadata.c: Routines for accessing the metadata + * + * Author: + * Miguel de Icaza (miguel@ximian.com) + * + * (C) 2001 Ximian, Inc. + */ + +#include +#include +#include "metadata.h" + diff --git a/mono/metadata/metadata.h b/mono/metadata/metadata.h new file mode 100644 index 00000000000..6e34877013f --- /dev/null +++ b/mono/metadata/metadata.h @@ -0,0 +1,18 @@ + +typedef struct { + guint32 sh_offset; + guint32 sh_size; +} stream_header_t; + +typedef struct { + char *raw_metadata; + + stream_header_t heap_strings; + stream_header_t heap_us; + stream_header_t heap_blob; + stream_header_t heap_guid; + stream_header_t heap_tables; + + guint32 rows [64]; +} metadata_t; + diff --git a/mono/metadata/pedump.c b/mono/metadata/pedump.c new file mode 100644 index 00000000000..7a716cf3ea7 --- /dev/null +++ b/mono/metadata/pedump.c @@ -0,0 +1,309 @@ +/* + * pedump.c: Dumps the contents of an extended PE/COFF file + * + * Author: + * Miguel de Icaza (miguel@ximian.com) + * + * (C) 2001 Ximian, Inc. + */ +#include +#include +#include "assembly.h" +#include +#include "cil-coff.h" + +static void +hex_dump (char *buffer, int base, int count) +{ + int i; + + for (i = 0; i < count; i++){ + if ((i % 16) == 0) + printf ("\n0x%08x: ", (unsigned char) base + i); + + printf ("%02x ", (unsigned char) (buffer [i])); + } +} + +static void +hex8 (char *label, unsigned char x) +{ + printf ("\t%s: 0x%02x\n", label, (unsigned char) x); +} + +static void +hex16 (char *label, guint16 x) +{ + printf ("\t%s: 0x%04x\n", label, x); +} + +static void +hex32 (char *label, guint32 x) +{ + printf ("\t%s: 0x%08x\n", label, x); +} + +static void +dump_coff_header (coff_header_t *coff) +{ + printf ("\nCOFF Header:\n"); + hex16 (" Machine", coff->coff_machine); + hex16 (" Sections", coff->coff_sections); + hex32 (" Time stamp", coff->coff_time); + hex32 ("Pointer to Symbol Table", coff->coff_symptr); + hex32 (" Symbol Count", coff->coff_symcount); + hex16 (" Optional Header Size", coff->coff_opt_header_size); + hex16 (" Characteristics", coff->coff_attributes); + +} + +static void +dump_pe_header (pe_header_t *pe) +{ + printf ("\nPE Header:\n"); + hex16 (" Magic (0x010b)", pe->pe_magic); + hex8 (" LMajor (6)", pe->pe_major); + hex8 (" LMinor (0)", pe->pe_minor); + hex32 (" Code Size", pe->pe_code_size); + hex32 (" Initialized Data Size", pe->pe_data_size); + hex32 ("Uninitialized Data Size", pe->pe_uninit_data_size); + hex32 (" Entry Point RVA", pe->pe_rva_entry_point); + hex32 (" Code Base RVA", pe->pe_rva_code_base); + hex32 (" Data Base RVA", pe->pe_rva_data_base); + printf ("\n"); +} + +static void +dump_nt_header (pe_header_nt_t *nt) +{ + printf ("\nNT Header:\n"); + + hex32 (" Image Base (0x400000)", nt->pe_image_base); + hex32 ("Section Alignment (8192)", nt->pe_section_align); + hex32 (" File Align (512/4096)", nt->pe_file_alignment); + hex16 (" OS Major (4)", nt->pe_os_major); + hex16 (" OS Minor (0)", nt->pe_os_minor); + hex16 (" User Major (0)", nt->pe_user_major); + hex16 (" User Minor (0)", nt->pe_user_minor); + hex16 (" Subsys major (4)", nt->pe_subsys_major); + hex16 (" Subsys minor (0)", nt->pe_subsys_minor); + hex32 (" Reserverd", nt->pe_reserved_1); + hex32 (" Image Size", nt->pe_image_size); + hex32 (" Header Size", nt->pe_header_size); + hex32 (" Checksum (0)", nt->pe_checksum); + hex16 (" Subsystem", nt->pe_subsys_required); + hex16 (" DLL Flags (0)", nt->pe_dll_flags); + hex32 (" Stack Reserve Size (1M)", nt->pe_stack_reserve); + hex32 ("Stack commit Size (4096)", nt->pe_stack_commit); + hex32 (" Heap Reserve Size (1M)", nt->pe_heap_reserve); + hex32 (" Heap Commit Size (4096)", nt->pe_heap_commit); + hex32 (" Loader flags (0x1)", nt->pe_loader_flags); + hex32 (" Data Directories (16)", nt->pe_data_dir_count); +} + +static void +dent (const char *label, pe_dir_entry_t de) +{ + printf ("\t%s: 0x%08x [0x%08x]\n", label, de.rva, de.size); +} + +static void +dump_datadir (pe_datadir_t *dd) +{ + printf ("\nData directories:\n"); + dent (" Export Table", dd->pe_export_table); + dent (" Import Table", dd->pe_import_table); + dent (" Resource Table", dd->pe_resource_table); + dent (" Exception Table", dd->pe_exception_table); + dent ("Certificate Table", dd->pe_certificate_table); + dent (" Reloc Table", dd->pe_reloc_table); + dent (" Debug", dd->pe_debug); + dent (" Copyright", dd->pe_copyright); + dent (" Global Ptr", dd->pe_global_ptr); + dent (" TLS Table", dd->pe_tls_table); + dent ("Load Config Table", dd->pe_load_config_table); + dent (" Bound Import", dd->pe_bound_import); + dent (" IAT", dd->pe_iat); + dent ("Delay Import Desc", dd->pe_delay_import_desc); + dent (" CLI Header", dd->pe_cli_header); +} + +static void +dump_dotnet_header (dotnet_header_t *header) +{ + dump_coff_header (&header->coff); + dump_pe_header (&header->pe); + dump_nt_header (&header->nt); + dump_datadir (&header->datadir); +} + +static void +dump_section_table (section_table_t *st) +{ + guint32 flags = st->st_flags; + + printf ("\n\tName: %s\n", st->st_name); + hex32 (" Virtual Size", st->st_virtual_size); + hex32 ("Virtual Address", st->st_virtual_address); + hex32 (" Raw Data Size", st->st_raw_data_size); + hex32 (" Raw Data Ptr", st->st_raw_data_ptr); + hex32 (" Reloc Ptr", st->st_reloc_ptr); + hex32 (" LineNo Ptr", st->st_lineno_ptr); + hex16 (" Reloc Count", st->st_reloc_count); + hex16 (" Line Count", st->st_line_count); + + printf ("\tFlags: %s%s%s%s%s%s%s%s%s%s\n", + (flags & SECT_FLAGS_HAS_CODE) ? "code, " : "", + (flags & SECT_FLAGS_HAS_INITIALIZED_DATA) ? "data, " : "", + (flags & SECT_FLAGS_HAS_UNINITIALIZED_DATA) ? "bss, " : "", + (flags & SECT_FLAGS_MEM_DISCARDABLE) ? "discard, " : "", + (flags & SECT_FLAGS_MEM_NOT_CACHED) ? "nocache, " : "", + (flags & SECT_FLAGS_MEM_NOT_PAGED) ? "nopage, " : "", + (flags & SECT_FLAGS_MEM_SHARED) ? "shared, " : "", + (flags & SECT_FLAGS_MEM_EXECUTE) ? "exec, " : "", + (flags & SECT_FLAGS_MEM_READ) ? "read, " : "", + (flags & SECT_FLAGS_MEM_WRITE) ? "write" : ""); +} + +static void +dump_sections (dotnet_image_info_t *iinfo) +{ + const int top = iinfo->dn_header.coff.coff_sections; + int i; + + for (i = 0; i < top; i++) + dump_section_table (&iinfo->dn_section_tables [i]); +} + +static void +dump_cli_header (cli_header_t *ch) +{ + printf ("\n"); + printf (" CLI header size: %d\n", ch->ch_size); + printf (" Runtime required: %d.%d\n", ch->ch_runtime_major, ch->ch_runtime_minor); + printf (" Flags: %s, %s, %s\n", + (ch->ch_flags & CLI_FLAGS_ILONLY ? "ilonly" : "contains native"), + (ch->ch_flags & CLI_FLAGS_32BITREQUIRED ? "32bits" : "32/64"), + (ch->ch_flags & CLI_FLAGS_ILONLY ? "trackdebug" : "no-trackdebug")); + dent (" Metadata", ch->ch_metadata); + hex32 ("Entry Point Token", ch->ch_entry_point); + dent (" Resources at", ch->ch_resources); + dent (" Strong Name at", ch->ch_strong_name); + dent (" Code Manager at", ch->ch_code_manager_table); + dent (" VTableFixups at", ch->ch_vtable_fixups); + dent (" EAT jumps at", ch->ch_export_address_table_jumps); +} + +static void +dsh (char *label, dotnet_image_info_t *iinfo, stream_header_t *sh) +{ + printf ("%s: 0x%08x - 0x%08x [%d == 0x%08x]\n", + label, + sh->sh_offset, sh->sh_offset + sh->sh_size, + sh->sh_size, sh->sh_size); +} + +static void +dump_metadata_ptrs (dotnet_image_info_t *iinfo) +{ + metadata_t *meta = &iinfo->dn_metadata; + + printf ("\nMetadata pointers:\n"); + dsh ("\tTables (#~)", iinfo, &meta->heap_tables); + dsh ("\t Strings", iinfo, &meta->heap_strings); + dsh ("\t Blob", iinfo, &meta->heap_blob); + dsh ("\tUser string", iinfo, &meta->heap_us); + dsh ("\t GUID", iinfo, &meta->heap_guid); +} + +static const char * +table_to_string (int table) +{ + char *map_table_to_string [] = { + /* 0 */ "Module", "TypeRef", "TypeDef", "FieldPtr", + /* 4 */ "FieldDef", "MethodPtr", "MethodDef", "ParamPtr", + /* 8 */ "ParamDef", "InterfaceImpl", "MemberRef", "FieldInit", + /* 12 */ "CustomAttr", "MarshalDef", "Permission", "LayoutDef", + /* 16 */ "FieldOffset", "Signature", "EventAssoc", "EventPtr", + /* 20 */ "Event", "PropertyAssoc", "PropertyPtr", "Property", + /* 24 */ "MethodAssoc", "MethodImpl", "ModuleRef", "TypeSpec", + /* 28 */ "PInvoke", "Data", "EncLog", "EncAssoc", + /* 32 */ "Assembly", "ProcessorDef", "OSDef", "AssemblyRef", + /* 36 */ "ProcessorRef", "OSRef", "File", "ComType", + /* 40 */ "ManifestResource", "ExeLocation", "42", "43", + /* 44 */ "44", "45", "NestedClass", "47" + /* 48 */ "48", "49", "50", "51", + /* 52 */ "52", "53", "54", "55" + /* 56 */ "56", "57", "58", "59" + /* 60 */ "60", "61", "62", "63" + }; + + if (table < 0 || table > 63) + return "Unknown table name"; + + return map_table_to_string [table]; +} + +static void +dump_metadata (dotnet_image_info_t *iinfo) +{ + metadata_t *meta = &iinfo->dn_metadata; + int table; + + dump_metadata_ptrs (iinfo); + + printf ("Rows:\n"); + for (table = 0; table < 64; table++){ + if (meta->rows [table] == 0) + continue; + printf ("Table %s (%d): %d rows\n", table_to_string (table), table, meta->rows [table]); + } +} + +static void +dump_dotnet_iinfo (dotnet_image_info_t *iinfo) +{ + dump_dotnet_header (&iinfo->dn_header); + dump_sections (iinfo); + dump_cli_header (&iinfo->dn_cli_header); + dump_metadata (iinfo); +} + +static void +usage (void) +{ + printf ("Usage is: pedump [-m] file.exe\n"); + exit (1); +} + +int +main (int argc, char *argv []) +{ + dotnet_image_info_t *iinfo; + MonoAssembly *assembly; + char *file = NULL; + int i; + + for (i = 1; i < argc; i++){ + if (argv [i][0] != '-'){ + file = argv [1]; + continue; + } + + if (argv [i][1] == 'h') + usage (); + } + + if (!file) + usage (); + + assembly = mono_assembly_open (file, NULL); + iinfo = assembly->image_info; + + dump_dotnet_iinfo (iinfo); + + mono_assembly_close (assembly); + + return 0; +} + diff --git a/mono/metadata/rawbuffer.c b/mono/metadata/rawbuffer.c new file mode 100644 index 00000000000..a72705af35e --- /dev/null +++ b/mono/metadata/rawbuffer.c @@ -0,0 +1,70 @@ +/* + * rawbuffer.c: Manages buffers that might have been mmapped or malloced + * + * Author: + * Miguel de Icaza (miguel@ximian.com) + * + * (C) 2001 Ximian, Inc. + */ +#include +#include +#include +#include +#include +#include "rawbuffer.h" + +#define PAGESIZE 8192 + +GHashTable *malloc_map; + +void * +raw_buffer_load (int fd, int is_writable, guint32 base, size_t size) +{ + size_t start, end; + int prot = PROT_READ; + int flags = 0; + void *ptr, *mmap_ptr; + + if (is_writable){ + prot |= PROT_WRITE; + } + flags = MAP_PRIVATE; + + start = base & ~(PAGESIZE - 1); + end = (base + size + PAGESIZE - 1) & ~(PAGESIZE - 1); + + mmap_ptr = mmap (0, end - start, prot, flags, fd, start); + if (mmap_ptr == (void *) -1){ + ptr = g_malloc (size); + if (ptr == NULL) + return NULL; + if (lseek (fd, base, 0) == (off_t) -1) + return NULL; + read (fd, ptr, size); + return ptr; + } + if (malloc_map == NULL) + malloc_map = g_hash_table_new (g_direct_hash, g_direct_equal); + + g_hash_table_insert (malloc_map, mmap_ptr, GINT_TO_POINTER (size)); + + return ((char *)mmap_ptr) + (base - start); +} + +void +raw_buffer_free (void *buffer) +{ + int size, diff; + char *base; + + if (!malloc_map){ + g_free (buffer); + return; + } + + diff = ((unsigned int) buffer) & (PAGESIZE - 1); + base = ((char *)buffer) - diff; + + size = GPOINTER_TO_INT (g_hash_table_lookup (malloc_map, base)); + munmap (base, size); +} diff --git a/mono/metadata/rawbuffer.h b/mono/metadata/rawbuffer.h new file mode 100644 index 00000000000..4091fc434c2 --- /dev/null +++ b/mono/metadata/rawbuffer.h @@ -0,0 +1,3 @@ + +void *raw_buffer_load (int fd, int writable, guint32 base, size_t size); +void raw_buffer_free (void *buffer); -- cgit v1.2.3