[Mono-list] My new JIT debugging code

Martin Baulig martin@gnome.org
12 Mar 2002 20:36:34 +0100


--=-=-=

Hi guys,

I'll be away from hacking two or three days (I will read my email, just don't have time to hack)
since I need to clean up my room and do some things at the university, so here's the first draft
of my new JIT debugging code.

* debug.c - almost completely rewritten:


--=-=-=
Content-Type: text/x-csrc
Content-Disposition: attachment; filename=debug.c

#include <stdlib.h>
#include <string.h>
#include <mono/metadata/class.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/tokentype.h>
#include <mono/jit/codegen.h>
#include <mono/jit/dwarf2.h>
#include <mono/jit/debug.h>

#include "debug-private.h"

MonoDebugHandle*
mono_debug_open_file (char *filename, MonoDebugFormat format)
{
	MonoDebugHandle *debug;
	
	debug = g_new0 (MonoDebugHandle, 1);
	debug->name = g_strdup (filename);
	debug->format = format;
	return debug;
}

static void
debug_load_method_lines (AssemblyDebugInfo* info)
{
	FILE *f;
	char buf [1024];
	int i, mnum;
	char *name = g_strdup_printf ("%s.il", info->name);
	int offset = -1;

	/* use an env var with directories for searching. */
	if (!(f = fopen (name, "r"))) {
		g_warning ("cannot open IL assembly file %s", name);
		g_free (name);
		return;
	}

	info->total_lines = 100;
	info->moffsets = g_malloc (info->total_lines * sizeof (int));

	g_free (name);
	i = 0;
	while (fgets (buf, sizeof (buf), f)) {
		int pos = i;

		info->moffsets [i++] = offset;
		if (i + 2 >= info->total_lines) {
			info->total_lines += 100;
			info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
			g_assert (info->moffsets);
		}

		if (!sscanf (buf, " // method line %d", &mnum))
			continue;

		offset = 0;

		if (mnum >= info->nmethods)
			break;

		while (fgets (buf, sizeof (buf), f)) {
			int newoffset;

			++i;
			if (i + 2 >= info->total_lines) {
				info->total_lines += 100;
				info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
				g_assert (info->moffsets);
			}

			if (strstr (buf, "}")) {
				offset = -1;
				break;
			}

			if (sscanf (buf, " IL_%x:", &newoffset)) {
				offset = newoffset;
				if (!offset)
					pos = i;
			}

			info->moffsets [i] = offset;
		}
		/* g_print ("method %d found at %d\n", mnum, pos); */
		info->mlines [mnum] = pos;
	}
	fclose (f);
}

static void
record_line_number (DebugMethodInfo *minfo, gpointer address, guint32 line, int is_basic_block)
{
	DebugLineNumberInfo *lni = g_new0 (DebugLineNumberInfo, 1);

	lni->address = address;
	lni->line = line;
	lni->is_basic_block = is_basic_block;
	lni->source_file = 0;

	g_ptr_array_add (minfo->line_numbers, lni);
}

static void
debug_generate_method_lines (AssemblyDebugInfo *info, DebugMethodInfo *minfo, MonoFlowGraph* cfg)
{
	guint32 st_address, st_line;
	int i;

	minfo->line_numbers = g_ptr_array_new ();

	st_line = minfo->start_line;
	st_address = 1;

	record_line_number (minfo, cfg->start + st_address, st_line, FALSE);

	/* start lines of basic blocks */
	for (i = 0; i < cfg->block_count; ++i) {
		int j;

		for (j = 0; j < cfg->bblocks [i].forest->len; ++j) {
			MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
			gint32 line_inc = 0, addr_inc;

			if (!i && !j) {
				st_line = minfo->first_line;
				st_address = t->addr;

				record_line_number (minfo, cfg->start + st_address, st_line, TRUE);
			}

			if (t->cli_addr != -1) {
				int *lines = info->moffsets + st_line;
				int *k = lines;

				while ((*k != -1) && (*k < t->cli_addr))
					k++;

				line_inc = k - lines;
			}
			addr_inc = t->addr - st_address;

			st_line += line_inc;
			st_address += addr_inc;

			record_line_number (minfo, cfg->start + st_address, st_line, j == 0);
		}
	}
}

static void
free_method_info (DebugMethodInfo *minfo)
{
	if (minfo->line_numbers)
		g_ptr_array_free (minfo->line_numbers, TRUE);
	g_free (minfo->name);
	g_free (minfo);
}

static AssemblyDebugInfo*
mono_debug_open_assembly (MonoDebugHandle* handle, MonoImage *image)
{
	GList *tmp;
	AssemblyDebugInfo* info;

	for (tmp = handle->info; tmp; tmp = tmp->next) {
		info = (AssemblyDebugInfo*)tmp->data;
		if (strcmp (info->name, image->assembly_name) == 0)
			return info;
	}
	info = g_new0 (AssemblyDebugInfo, 1);
	switch (handle->format) {
	case MONO_DEBUG_FORMAT_STABS:
		info->filename = g_strdup_printf ("%s-stabs.s", image->assembly_name);
		break;
	case MONO_DEBUG_FORMAT_DWARF2:
		info->filename = g_strdup_printf ("%s-dwarf.s", image->assembly_name);
		break;
	}
	info->image = image;
	info->name = g_strdup (image->assembly_name);
	info->methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
					       NULL, (GDestroyNotify) free_method_info);
	info->source_files = g_ptr_array_new ();

	g_ptr_array_add (info->source_files, g_strdup_printf ("%s.il", image->assembly_name));
	info->producer_name = g_strdup_printf ("Mono JIT compiler version %s", VERSION);

	switch (handle->format) {
	case MONO_DEBUG_FORMAT_STABS:
		mono_debug_open_assembly_stabs (info);
		break;
	case MONO_DEBUG_FORMAT_DWARF2:
		mono_debug_open_assembly_dwarf2 (info);
		break;
	}

	info->next_idx = 100;
	handle->info = g_list_prepend (handle->info, info);

	info->nmethods = image->tables [MONO_TABLE_METHOD].rows + 1;
	info->mlines = g_new0 (int, info->nmethods);
	debug_load_method_lines (info);
	return info;
}

void
mono_debug_make_symbols (MonoDebugHandle* debug)
{
	GList *tmp;
	char *buf;
	AssemblyDebugInfo* info;

	for (tmp = debug->info; tmp; tmp = tmp->next) {
		info = (AssemblyDebugInfo*)tmp->data;

		if (!(info->f = fopen (info->filename, "w")))
			continue;

		switch (debug->format) {
		case MONO_DEBUG_FORMAT_STABS:
			mono_debug_write_assembly_stabs (info);
			break;
		case MONO_DEBUG_FORMAT_DWARF2:
			mono_debug_write_assembly_dwarf2 (info);
			break;
		}

		fclose (info->f);
		info->f = NULL;

		/* yes, it's completely unsafe */
		buf = g_strdup_printf ("as %s -o /tmp/%s.o", info->filename, info->name);
		system (buf);
		g_free (buf);
	}
}

static void
mono_debug_close_assembly (AssemblyDebugInfo* info)
{
	g_free (info->mlines);
	g_free (info->moffsets);
	g_free (info->name);
	g_free (info->filename);
	g_ptr_array_free (info->source_files, TRUE);
	g_hash_table_destroy (info->methods);
	g_free (info->producer_name);
	g_free (info);
}

void
mono_debug_close (MonoDebugHandle* debug)
{
	GList *tmp;
	AssemblyDebugInfo* info;

	mono_debug_make_symbols (debug);

	for (tmp = debug->info; tmp; tmp = tmp->next) {
		info = (AssemblyDebugInfo*)tmp->data;

		switch (debug->format) {
		case MONO_DEBUG_FORMAT_STABS:
			mono_debug_close_assembly_stabs (info);
			break;
		case MONO_DEBUG_FORMAT_DWARF2:
			mono_debug_close_assembly_dwarf2 (info);
			break;
		}

		mono_debug_close_assembly (info);
	}

	g_free (debug->name);
	g_free (debug);
}

void
mono_debug_add_type (MonoDebugHandle* debug, MonoClass *klass)
{
#if 0
	char *name;
	int i;
	char buf [64];
	AssemblyDebugInfo* info = mono_debug_open_assembly (debug, klass->image);

	mono_class_init (klass);

	/* output enums ...*/
	if (klass->enumtype) {
		name = g_strdup_printf ("%s%s%s", klass->name_space, klass->name_space [0]? "_": "", klass->name);
		fprintf (info->f, ".stabs \"%s:T%d=e", name, ++info->next_idx);
		g_free (name);
		for (i = 0; i < klass->field.count; ++i) {
			if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_LITERAL) {
				get_enumvalue (klass, klass->field.first + i, buf);
				fprintf (info->f, "%s_%s=%s,", klass->name, klass->fields [i].name, buf);
			}
		}
		fprintf (info->f, ";\",128,0,0,0\n");
	}
	fflush (info->f);
#endif

}

void
mono_debug_add_method (MonoDebugHandle* debug, MonoFlowGraph *cfg)
{
	MonoMethod *method = cfg->method;
	MonoClass *klass = method->klass;
	AssemblyDebugInfo* info = mono_debug_open_assembly (debug, klass->image);
	int method_number = 0, line = 0, start_line, i;
	DebugMethodInfo *minfo;
	char *name;

	mono_class_init (klass);
	/*
	 * Find the method index in the image.
	 */
	for (i = 0; klass->methods && i < klass->method.count; ++i) {
		if (klass->methods [i] == method) {
			method_number = klass->method.first + i + 1;
			line = info->mlines [method_number];
			break;
		}
	}

	if (g_hash_table_lookup (info->methods, GINT_TO_POINTER (method_number)))
		return;

	/* info->moffsets contains -1 "outside" of functions. */
	for (i = line; (i > 0) && (info->moffsets [i] == 0); i--)
		;
	start_line = i + 1;

	/* FIXME: we should mangle the name better */
	name = g_strdup_printf ("%s%s%s__%s_%p", klass->name_space, klass->name_space [0]? "_": "",
				klass->name, method->name, method);

	for (i = 0; name [i]; ++i)
		if (name [i] == '.') name [i] = '_';

	minfo = g_new0 (DebugMethodInfo, 1);
	minfo->name = name;
	minfo->start_line = start_line;
	minfo->first_line = line;
	minfo->code_start = cfg->start + 1;
	minfo->code_size = cfg->code_size;
	minfo->method_number = method_number;
	minfo->method = method;
	minfo->info = info;

	debug_generate_method_lines (info, minfo, cfg);

	g_hash_table_insert (info->methods, GINT_TO_POINTER (method_number), minfo);
}

--=-=-=


* The following header is copied from gdb and contains some enum declarations:


--=-=-=
Content-Type: text/x-chdr
Content-Disposition: attachment; filename=dwarf2.h

/* Declarations and definitions of codes relating to the DWARF2 symbolic
   debugging information format.
   Copyright 1992, 1993, 1995, 1996, 1999, 2000, 2001
   Free Software Foundation, Inc.

   Written by Gary Funck (gary@intrepid.com) The Ada Joint Program
   Office (AJPO), Florida State Unviversity and Silicon Graphics Inc.
   provided support for this effort -- June 21, 1995.

   Derived from the DWARF 1 implementation written by Ron Guilmette
   (rfg@netcom.com), November 1990.

This file is part of GNU CC.

GNU CC 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, or (at your option) any
later version.

GNU CC 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 GNU CC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

/* This file is derived from the DWARF specification (a public document)
   Revision 2.0.0 (July 27, 1993) developed by the UNIX International
   Programming Languages Special Interest Group (UI/PLSIG) and distributed
   by UNIX International.  Copies of this specification are available from
   UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.

   This file also now contains definitions from the DWARF 2.1 specification.  */

/* This file is shared between GCC and GDB, and should not contain
   prototypes.  */

#ifndef _ELF_DWARF2_H
#define _ELF_DWARF2_H

/* Tag names and codes.  */
enum dwarf_tag
  {
    DW_TAG_padding = 0x00,
    DW_TAG_array_type = 0x01,
    DW_TAG_class_type = 0x02,
    DW_TAG_entry_point = 0x03,
    DW_TAG_enumeration_type = 0x04,
    DW_TAG_formal_parameter = 0x05,
    DW_TAG_imported_declaration = 0x08,
    DW_TAG_label = 0x0a,
    DW_TAG_lexical_block = 0x0b,
    DW_TAG_member = 0x0d,
    DW_TAG_pointer_type = 0x0f,
    DW_TAG_reference_type = 0x10,
    DW_TAG_compile_unit = 0x11,
    DW_TAG_string_type = 0x12,
    DW_TAG_structure_type = 0x13,
    DW_TAG_subroutine_type = 0x15,
    DW_TAG_typedef = 0x16,
    DW_TAG_union_type = 0x17,
    DW_TAG_unspecified_parameters = 0x18,
    DW_TAG_variant = 0x19,
    DW_TAG_common_block = 0x1a,
    DW_TAG_common_inclusion = 0x1b,
    DW_TAG_inheritance = 0x1c,
    DW_TAG_inlined_subroutine = 0x1d,
    DW_TAG_module = 0x1e,
    DW_TAG_ptr_to_member_type = 0x1f,
    DW_TAG_set_type = 0x20,
    DW_TAG_subrange_type = 0x21,
    DW_TAG_with_stmt = 0x22,
    DW_TAG_access_declaration = 0x23,
    DW_TAG_base_type = 0x24,
    DW_TAG_catch_block = 0x25,
    DW_TAG_const_type = 0x26,
    DW_TAG_constant = 0x27,
    DW_TAG_enumerator = 0x28,
    DW_TAG_file_type = 0x29,
    DW_TAG_friend = 0x2a,
    DW_TAG_namelist = 0x2b,
    DW_TAG_namelist_item = 0x2c,
    DW_TAG_packed_type = 0x2d,
    DW_TAG_subprogram = 0x2e,
    DW_TAG_template_type_param = 0x2f,
    DW_TAG_template_value_param = 0x30,
    DW_TAG_thrown_type = 0x31,
    DW_TAG_try_block = 0x32,
    DW_TAG_variant_part = 0x33,
    DW_TAG_variable = 0x34,
    DW_TAG_volatile_type = 0x35,
    /* DWARF 2.1.  */
    DW_TAG_dwarf_procedure = 0x36,
    DW_TAG_restrict_type = 0x37,
    DW_TAG_interface_type = 0x38,
    DW_TAG_namespace = 0x39,
    DW_TAG_imported_module = 0x3a,
    DW_TAG_unspecified_type = 0x3b,
    DW_TAG_partial_unit = 0x3c,
    DW_TAG_imported_unit = 0x3d,
    /* SGI/MIPS Extensions.  */
    DW_TAG_MIPS_loop = 0x4081,
    /* GNU extensions.  */
    DW_TAG_format_label = 0x4101,	/* For FORTRAN 77 and Fortran 90.  */
    DW_TAG_function_template = 0x4102,	/* for C++ */
    DW_TAG_class_template = 0x4103,	/* for C++ */
    DW_TAG_GNU_BINCL = 0x4104,
    DW_TAG_GNU_EINCL = 0x4105
  };

#define DW_TAG_lo_user	0x4080
#define DW_TAG_hi_user	0xffff

/* Flag that tells whether entry has a child or not.  */
#define DW_children_no   0
#define	DW_children_yes  1

/* Form names and codes.  */
enum dwarf_form
  {
    DW_FORM_addr = 0x01,
    DW_FORM_block2 = 0x03,
    DW_FORM_block4 = 0x04,
    DW_FORM_data2 = 0x05,
    DW_FORM_data4 = 0x06,
    DW_FORM_data8 = 0x07,
    DW_FORM_string = 0x08,
    DW_FORM_block = 0x09,
    DW_FORM_block1 = 0x0a,
    DW_FORM_data1 = 0x0b,
    DW_FORM_flag = 0x0c,
    DW_FORM_sdata = 0x0d,
    DW_FORM_strp = 0x0e,
    DW_FORM_udata = 0x0f,
    DW_FORM_ref_addr = 0x10,
    DW_FORM_ref1 = 0x11,
    DW_FORM_ref2 = 0x12,
    DW_FORM_ref4 = 0x13,
    DW_FORM_ref8 = 0x14,
    DW_FORM_ref_udata = 0x15,
    DW_FORM_indirect = 0x16
  };

/* Attribute names and codes.  */

enum dwarf_attribute
  {
    DW_AT_sibling = 0x01,
    DW_AT_location = 0x02,
    DW_AT_name = 0x03,
    DW_AT_ordering = 0x09,
    DW_AT_subscr_data = 0x0a,
    DW_AT_byte_size = 0x0b,
    DW_AT_bit_offset = 0x0c,
    DW_AT_bit_size = 0x0d,
    DW_AT_element_list = 0x0f,
    DW_AT_stmt_list = 0x10,
    DW_AT_low_pc = 0x11,
    DW_AT_high_pc = 0x12,
    DW_AT_language = 0x13,
    DW_AT_member = 0x14,
    DW_AT_discr = 0x15,
    DW_AT_discr_value = 0x16,
    DW_AT_visibility = 0x17,
    DW_AT_import = 0x18,
    DW_AT_string_length = 0x19,
    DW_AT_common_reference = 0x1a,
    DW_AT_comp_dir = 0x1b,
    DW_AT_const_value = 0x1c,
    DW_AT_containing_type = 0x1d,
    DW_AT_default_value = 0x1e,
    DW_AT_inline = 0x20,
    DW_AT_is_optional = 0x21,
    DW_AT_lower_bound = 0x22,
    DW_AT_producer = 0x25,
    DW_AT_prototyped = 0x27,
    DW_AT_return_addr = 0x2a,
    DW_AT_start_scope = 0x2c,
    DW_AT_stride_size = 0x2e,
    DW_AT_upper_bound = 0x2f,
    DW_AT_abstract_origin = 0x31,
    DW_AT_accessibility = 0x32,
    DW_AT_address_class = 0x33,
    DW_AT_artificial = 0x34,
    DW_AT_base_types = 0x35,
    DW_AT_calling_convention = 0x36,
    DW_AT_count = 0x37,
    DW_AT_data_member_location = 0x38,
    DW_AT_decl_column = 0x39,
    DW_AT_decl_file = 0x3a,
    DW_AT_decl_line = 0x3b,
    DW_AT_declaration = 0x3c,
    DW_AT_discr_list = 0x3d,
    DW_AT_encoding = 0x3e,
    DW_AT_external = 0x3f,
    DW_AT_frame_base = 0x40,
    DW_AT_friend = 0x41,
    DW_AT_identifier_case = 0x42,
    DW_AT_macro_info = 0x43,
    DW_AT_namelist_items = 0x44,
    DW_AT_priority = 0x45,
    DW_AT_segment = 0x46,
    DW_AT_specification = 0x47,
    DW_AT_static_link = 0x48,
    DW_AT_type = 0x49,
    DW_AT_use_location = 0x4a,
    DW_AT_variable_parameter = 0x4b,
    DW_AT_virtuality = 0x4c,
    DW_AT_vtable_elem_location = 0x4d,
    /* DWARF 2.1 values.  */
    DW_AT_allocated     = 0x4e,
    DW_AT_associated    = 0x4f,
    DW_AT_data_location = 0x50,
    DW_AT_stride        = 0x51,
    DW_AT_entry_pc      = 0x52,
    DW_AT_use_UTF8      = 0x53,
    DW_AT_extension     = 0x54,
    DW_AT_ranges        = 0x55,
    DW_AT_trampoline    = 0x56,
    DW_AT_call_column   = 0x57,
    DW_AT_call_file     = 0x58,
    DW_AT_call_line     = 0x59,
    /* SGI/MIPS Extensions.  */
    DW_AT_MIPS_fde = 0x2001,
    DW_AT_MIPS_loop_begin = 0x2002,
    DW_AT_MIPS_tail_loop_begin = 0x2003,
    DW_AT_MIPS_epilog_begin = 0x2004,
    DW_AT_MIPS_loop_unroll_factor = 0x2005,
    DW_AT_MIPS_software_pipeline_depth = 0x2006,
    DW_AT_MIPS_linkage_name = 0x2007,
    DW_AT_MIPS_stride = 0x2008,
    DW_AT_MIPS_abstract_name = 0x2009,
    DW_AT_MIPS_clone_origin = 0x200a,
    DW_AT_MIPS_has_inlines = 0x200b,
    /* GNU extensions.  */
    DW_AT_sf_names   = 0x2101,
    DW_AT_src_info   = 0x2102,
    DW_AT_mac_info   = 0x2103,
    DW_AT_src_coords = 0x2104,
    DW_AT_body_begin = 0x2105,
    DW_AT_body_end   = 0x2106
  };

#define DW_AT_lo_user	0x2000	/* Implementation-defined range start.  */
#define DW_AT_hi_user	0x3ff0	/* Implementation-defined range end.  */

/* Location atom names and codes.  */
enum dwarf_location_atom
  {
    DW_OP_addr = 0x03,
    DW_OP_deref = 0x06,
    DW_OP_const1u = 0x08,
    DW_OP_const1s = 0x09,
    DW_OP_const2u = 0x0a,
    DW_OP_const2s = 0x0b,
    DW_OP_const4u = 0x0c,
    DW_OP_const4s = 0x0d,
    DW_OP_const8u = 0x0e,
    DW_OP_const8s = 0x0f,
    DW_OP_constu = 0x10,
    DW_OP_consts = 0x11,
    DW_OP_dup = 0x12,
    DW_OP_drop = 0x13,
    DW_OP_over = 0x14,
    DW_OP_pick = 0x15,
    DW_OP_swap = 0x16,
    DW_OP_rot = 0x17,
    DW_OP_xderef = 0x18,
    DW_OP_abs = 0x19,
    DW_OP_and = 0x1a,
    DW_OP_div = 0x1b,
    DW_OP_minus = 0x1c,
    DW_OP_mod = 0x1d,
    DW_OP_mul = 0x1e,
    DW_OP_neg = 0x1f,
    DW_OP_not = 0x20,
    DW_OP_or = 0x21,
    DW_OP_plus = 0x22,
    DW_OP_plus_uconst = 0x23,
    DW_OP_shl = 0x24,
    DW_OP_shr = 0x25,
    DW_OP_shra = 0x26,
    DW_OP_xor = 0x27,
    DW_OP_bra = 0x28,
    DW_OP_eq = 0x29,
    DW_OP_ge = 0x2a,
    DW_OP_gt = 0x2b,
    DW_OP_le = 0x2c,
    DW_OP_lt = 0x2d,
    DW_OP_ne = 0x2e,
    DW_OP_skip = 0x2f,
    DW_OP_lit0 = 0x30,
    DW_OP_lit1 = 0x31,
    DW_OP_lit2 = 0x32,
    DW_OP_lit3 = 0x33,
    DW_OP_lit4 = 0x34,
    DW_OP_lit5 = 0x35,
    DW_OP_lit6 = 0x36,
    DW_OP_lit7 = 0x37,
    DW_OP_lit8 = 0x38,
    DW_OP_lit9 = 0x39,
    DW_OP_lit10 = 0x3a,
    DW_OP_lit11 = 0x3b,
    DW_OP_lit12 = 0x3c,
    DW_OP_lit13 = 0x3d,
    DW_OP_lit14 = 0x3e,
    DW_OP_lit15 = 0x3f,
    DW_OP_lit16 = 0x40,
    DW_OP_lit17 = 0x41,
    DW_OP_lit18 = 0x42,
    DW_OP_lit19 = 0x43,
    DW_OP_lit20 = 0x44,
    DW_OP_lit21 = 0x45,
    DW_OP_lit22 = 0x46,
    DW_OP_lit23 = 0x47,
    DW_OP_lit24 = 0x48,
    DW_OP_lit25 = 0x49,
    DW_OP_lit26 = 0x4a,
    DW_OP_lit27 = 0x4b,
    DW_OP_lit28 = 0x4c,
    DW_OP_lit29 = 0x4d,
    DW_OP_lit30 = 0x4e,
    DW_OP_lit31 = 0x4f,
    DW_OP_reg0 = 0x50,
    DW_OP_reg1 = 0x51,
    DW_OP_reg2 = 0x52,
    DW_OP_reg3 = 0x53,
    DW_OP_reg4 = 0x54,
    DW_OP_reg5 = 0x55,
    DW_OP_reg6 = 0x56,
    DW_OP_reg7 = 0x57,
    DW_OP_reg8 = 0x58,
    DW_OP_reg9 = 0x59,
    DW_OP_reg10 = 0x5a,
    DW_OP_reg11 = 0x5b,
    DW_OP_reg12 = 0x5c,
    DW_OP_reg13 = 0x5d,
    DW_OP_reg14 = 0x5e,
    DW_OP_reg15 = 0x5f,
    DW_OP_reg16 = 0x60,
    DW_OP_reg17 = 0x61,
    DW_OP_reg18 = 0x62,
    DW_OP_reg19 = 0x63,
    DW_OP_reg20 = 0x64,
    DW_OP_reg21 = 0x65,
    DW_OP_reg22 = 0x66,
    DW_OP_reg23 = 0x67,
    DW_OP_reg24 = 0x68,
    DW_OP_reg25 = 0x69,
    DW_OP_reg26 = 0x6a,
    DW_OP_reg27 = 0x6b,
    DW_OP_reg28 = 0x6c,
    DW_OP_reg29 = 0x6d,
    DW_OP_reg30 = 0x6e,
    DW_OP_reg31 = 0x6f,
    DW_OP_breg0 = 0x70,
    DW_OP_breg1 = 0x71,
    DW_OP_breg2 = 0x72,
    DW_OP_breg3 = 0x73,
    DW_OP_breg4 = 0x74,
    DW_OP_breg5 = 0x75,
    DW_OP_breg6 = 0x76,
    DW_OP_breg7 = 0x77,
    DW_OP_breg8 = 0x78,
    DW_OP_breg9 = 0x79,
    DW_OP_breg10 = 0x7a,
    DW_OP_breg11 = 0x7b,
    DW_OP_breg12 = 0x7c,
    DW_OP_breg13 = 0x7d,
    DW_OP_breg14 = 0x7e,
    DW_OP_breg15 = 0x7f,
    DW_OP_breg16 = 0x80,
    DW_OP_breg17 = 0x81,
    DW_OP_breg18 = 0x82,
    DW_OP_breg19 = 0x83,
    DW_OP_breg20 = 0x84,
    DW_OP_breg21 = 0x85,
    DW_OP_breg22 = 0x86,
    DW_OP_breg23 = 0x87,
    DW_OP_breg24 = 0x88,
    DW_OP_breg25 = 0x89,
    DW_OP_breg26 = 0x8a,
    DW_OP_breg27 = 0x8b,
    DW_OP_breg28 = 0x8c,
    DW_OP_breg29 = 0x8d,
    DW_OP_breg30 = 0x8e,
    DW_OP_breg31 = 0x8f,
    DW_OP_regx = 0x90,
    DW_OP_fbreg = 0x91,
    DW_OP_bregx = 0x92,
    DW_OP_piece = 0x93,
    DW_OP_deref_size = 0x94,
    DW_OP_xderef_size = 0x95,
    DW_OP_nop = 0x96,
    /* DWARF 2.1 extensions.  */
    DW_OP_push_object_address = 0x97,
    DW_OP_call2 = 0x98, /* 1 2-byte offset of DIE.  */
    DW_OP_call4 = 0x99, /* 1 4-byte offset of DIE.  */
    DW_OP_calli = 0x9a
  };

#define DW_OP_lo_user	0x80	/* Implementation-defined range start.  */
#define DW_OP_hi_user	0xff	/* Implementation-defined range end.  */

/* Type encodings.  */
enum dwarf_type
  {
    DW_ATE_void = 0x0,
    DW_ATE_address = 0x1,
    DW_ATE_boolean = 0x2,
    DW_ATE_complex_float = 0x3,
    DW_ATE_float = 0x4,
    DW_ATE_signed = 0x5,
    DW_ATE_signed_char = 0x6,
    DW_ATE_unsigned = 0x7,
    DW_ATE_unsigned_char = 0x8,
    /* DWARF 2.1.  */
    DW_ATE_imaginary_float = 0x9
  };

#define	DW_ATE_lo_user 0x80
#define	DW_ATE_hi_user 0xff

/* Array ordering names and codes.  */
enum dwarf_array_dim_ordering
  {
    DW_ORD_row_major = 0,
    DW_ORD_col_major = 1
  };

/* Access attribute.  */
enum dwarf_access_attribute
  {
    DW_ACCESS_public = 1,
    DW_ACCESS_protected = 2,
    DW_ACCESS_private = 3
  };

/* Visibility.  */
enum dwarf_visibility_attribute
  {
    DW_VIS_local = 1,
    DW_VIS_exported = 2,
    DW_VIS_qualified = 3
  };

/* Virtuality.  */
enum dwarf_virtuality_attribute
  {
    DW_VIRTUALITY_none = 0,
    DW_VIRTUALITY_virtual = 1,
    DW_VIRTUALITY_pure_virtual = 2
  };

/* Case sensitivity.  */
enum dwarf_id_case
  {
    DW_ID_case_sensitive = 0,
    DW_ID_up_case = 1,
    DW_ID_down_case = 2,
    DW_ID_case_insensitive = 3
  };

/* Calling convention.  */
enum dwarf_calling_convention
  {
    DW_CC_normal = 0x1,
    DW_CC_program = 0x2,
    DW_CC_nocall = 0x3
  };

#define DW_CC_lo_user 0x40
#define DW_CC_hi_user 0xff

/* Inline attribute.  */
enum dwarf_inline_attribute
  {
    DW_INL_not_inlined = 0,
    DW_INL_inlined = 1,
    DW_INL_declared_not_inlined = 2,
    DW_INL_declared_inlined = 3
  };

/* Discriminant lists.  */
enum dwarf_discrim_list
  {
    DW_DSC_label = 0,
    DW_DSC_range = 1
  };

/* Line number opcodes.  */
enum dwarf_line_number_ops
  {
    DW_LNS_extended_op = 0,
    DW_LNS_copy = 1,
    DW_LNS_advance_pc = 2,
    DW_LNS_advance_line = 3,
    DW_LNS_set_file = 4,
    DW_LNS_set_column = 5,
    DW_LNS_negate_stmt = 6,
    DW_LNS_set_basic_block = 7,
    DW_LNS_const_add_pc = 8,
    DW_LNS_fixed_advance_pc = 9
  };

/* Line number extended opcodes.  */
enum dwarf_line_number_x_ops
  {
    DW_LNE_end_sequence = 1,
    DW_LNE_set_address = 2,
    DW_LNE_define_file = 3
  };

/* Call frame information.  */
enum dwarf_call_frame_info
  {
    DW_CFA_advance_loc = 0x40,
    DW_CFA_offset = 0x80,
    DW_CFA_restore = 0xc0,
    DW_CFA_nop = 0x00,
    DW_CFA_set_loc = 0x01,
    DW_CFA_advance_loc1 = 0x02,
    DW_CFA_advance_loc2 = 0x03,
    DW_CFA_advance_loc4 = 0x04,
    DW_CFA_offset_extended = 0x05,
    DW_CFA_restore_extended = 0x06,
    DW_CFA_undefined = 0x07,
    DW_CFA_same_value = 0x08,
    DW_CFA_register = 0x09,
    DW_CFA_remember_state = 0x0a,
    DW_CFA_restore_state = 0x0b,
    DW_CFA_def_cfa = 0x0c,
    DW_CFA_def_cfa_register = 0x0d,
    DW_CFA_def_cfa_offset = 0x0e,
    DW_CFA_def_cfa_expression = 0x0f,
    DW_CFA_expression = 0x10,
    /* Dwarf 2.1.  */
    DW_CFA_offset_extended_sf = 0x11,
    DW_CFA_def_cfa_sf = 0x12,
    DW_CFA_def_cfa_offset_sf = 0x13,

    /* SGI/MIPS specific.  */
    DW_CFA_MIPS_advance_loc8 = 0x1d,

    /* GNU extensions.  */
    DW_CFA_GNU_window_save = 0x2d,
    DW_CFA_GNU_args_size = 0x2e,
    DW_CFA_GNU_negative_offset_extended = 0x2f
  };

#define DW_CIE_ID	  0xffffffff
#define DW_CIE_VERSION	  1

#define DW_CFA_extended   0
#define DW_CFA_low_user   0x1c
#define DW_CFA_high_user  0x3f

#define DW_CHILDREN_no		     0x00
#define DW_CHILDREN_yes		     0x01

#define DW_ADDR_none		0

/* Source language names and codes.  */
enum dwarf_source_language
  {
    DW_LANG_C89 = 0x0001,
    DW_LANG_C = 0x0002,
    DW_LANG_Ada83 = 0x0003,
    DW_LANG_C_plus_plus = 0x0004,
    DW_LANG_Cobol74 = 0x0005,
    DW_LANG_Cobol85 = 0x0006,
    DW_LANG_Fortran77 = 0x0007,
    DW_LANG_Fortran90 = 0x0008,
    DW_LANG_Pascal83 = 0x0009,
    DW_LANG_Modula2 = 0x000a,
    DW_LANG_Java = 0x000b,
    /* DWARF 2.1.  */
    DW_LANG_C99 = 0x000c,
    DW_LANG_Ada95 = 0x000d,
    DW_LANG_Fortran95 = 0x000e,
    /* MIPS.  */
    DW_LANG_Mips_Assembler = 0x8001
  };


#define DW_LANG_lo_user 0x8000	/* Implementation-defined range start.  */
#define DW_LANG_hi_user 0xffff	/* Implementation-defined range start.  */

/* Names and codes for macro information.  */
enum dwarf_macinfo_record_type
  {
    DW_MACINFO_define = 1,
    DW_MACINFO_undef = 2,
    DW_MACINFO_start_file = 3,
    DW_MACINFO_end_file = 4,
    DW_MACINFO_vendor_ext = 255
  };


/* @@@ For use with GNU frame unwind information.  */

#define DW_EH_PE_absptr		0x00
#define DW_EH_PE_omit		0xff

#define DW_EH_PE_uleb128	0x01
#define DW_EH_PE_udata2		0x02
#define DW_EH_PE_udata4		0x03
#define DW_EH_PE_udata8		0x04
#define DW_EH_PE_sleb128	0x09
#define DW_EH_PE_sdata2		0x0A
#define DW_EH_PE_sdata4		0x0B
#define DW_EH_PE_sdata8		0x0C
#define DW_EH_PE_signed		0x08

#endif /* _ELF_DWARF2_H */

--=-=-=


* New private header file:


--=-=-=
Content-Type: text/x-chdr
Content-Disposition: attachment; filename=debug-private.h

#ifndef __MONO_JIT_DEBUG_PRIVATE_H__
#define __MONO_JIT_DEBUG_PRIVATE_H__

#include "debug.h"

typedef struct {
	gpointer address;
	guint32 line;
	int is_basic_block;
	int source_file;
} DebugLineNumberInfo;

typedef struct _AssemblyDebugInfo AssemblyDebugInfo;

typedef struct {
	gchar *name;
	int source_file;
	MonoMethod *method;
	guint32 method_number;
	guint32 start_line;
	guint32 first_line;
	gpointer code_start;
	guint32 code_size;
	GPtrArray *line_numbers;
	AssemblyDebugInfo *info;
} DebugMethodInfo;

struct _AssemblyDebugInfo {
	FILE *f;
	char *filename;
	char *name;
	char *producer_name;
	int total_lines;
	int *mlines;
	int *moffsets;
	int nmethods;
	int next_idx;
	MonoImage *image;
	GHashTable *methods;
	GPtrArray *source_files;
};

struct _MonoDebugHandle {
	char *name;
	MonoDebugFormat format;
	GList *info;
};

void           mono_debug_open_assembly_stabs   (AssemblyDebugInfo *info);

void           mono_debug_open_assembly_dwarf2  (AssemblyDebugInfo *info);

void           mono_debug_write_assembly_stabs  (AssemblyDebugInfo *info);

void           mono_debug_write_assembly_dwarf2 (AssemblyDebugInfo *info);

void           mono_debug_close_assembly_stabs  (AssemblyDebugInfo *info);

void           mono_debug_close_assembly_dwarf2 (AssemblyDebugInfo *info);

#endif /* __MONO_JIT_DEBUG_PRIVATE_H__ */

--=-=-=


* debug-stabs.c - this file now contains the stabs code


--=-=-=
Content-Type: text/x-csrc
Content-Disposition: attachment; filename=debug-stabs.c

#include <stdlib.h>
#include <string.h>
#include <mono/metadata/class.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/tokentype.h>
#include <mono/jit/codegen.h>
#include <mono/jit/dwarf2.h>
#include <mono/jit/debug.h>

#include "debug-private.h"

typedef struct {
	char *name;
	char *spec;
} BaseTypes;

/*
 * Not 64 bit clean.
 * Note: same order of MonoTypeEnum.
 */
static BaseTypes
base_types[] = {
	{"", NULL},
	{"Void", "(0,1)"},
	{"Boolean", ";0;255;"},
	{"Char", ";0;65535;"},
	{"SByte", ";-128;127;"},
	{"Byte", ";0;255;"},
	{"Int16", ";-32768;32767;"},
	{"UInt16", ";0;65535;"},
	{"Int32", ";0020000000000;0017777777777;"},
	{"UInt32", ";0000000000000;0037777777777;"},
	{"Int64", ";01000000000000000000000;0777777777777777777777;"},
	{"UInt64", ";0000000000000;01777777777777777777777;"},
	{"Single", "r(0,8);4;0;"},
	{"Double", "r(0,8);8;0;"},
	{"String", "(0,41)=*(0,42)=xsMonoString:"}, /*string*/
	{"", }, /*ptr*/
	{"", }, /*byref*/
	{"", }, /*valuetype*/
	{"Class", "(0,44)=*(0,45)=xsMonoObject:"}, /*class*/
	{"", }, /*unused*/
	{"Array", }, /*array*/
	{"", }, /*typedbyref*/
	{"", }, /*unused*/
	{"", }, /*unused*/
	{"IntPtr", ";0020000000000;0017777777777;"},
	{"UIntPtr", ";0000000000000;0037777777777;"},
	{"", }, /*unused*/
	{"FnPtr", "*(0,1)"}, /*fnptr*/
	{"Object", "(0,47)=*(0,48)=xsMonoObject:"}, /*object*/
	{"SzArray", "(0,50)=*(0,51))=xsMonoArray:"}, /*szarray*/
	{NULL, NULL}
};

void
mono_debug_open_assembly_stabs (AssemblyDebugInfo* info)
{
}

void
mono_debug_close_assembly_stabs (AssemblyDebugInfo* info)
{
}

static void
write_method_stabs (AssemblyDebugInfo *info, DebugMethodInfo *minfo)
{
	int i;
	MonoMethod *method = minfo->method;
	MonoClass *klass = method->klass;
	MonoMethodSignature *sig = method->signature;
	char **names = g_new (char*, sig->param_count);

	/*
	 * We need to output all the basic info, if we change filename...
	 * fprintf (info->f, ".stabs \"%s.il\",100,0,0,0\n", klass->image->assembly_name);
	 */
	fprintf (info->f, ".stabs \"%s:F(0,%d)\",36,0,%d,%p\n", minfo->name, sig->ret->type,
		 minfo->start_line, minfo->code_start);

	/* params */
	mono_method_get_param_names (method, (const char **)names);
	if (sig->hasthis)
		fprintf (info->f, ".stabs \"this:p(0,%d)=(0,%d)\",160,0,%d,%d\n",
			 info->next_idx++, klass->byval_arg.type, minfo->start_line, 8); /* FIXME */
#if 0 // FIXME
	for (i = 0; i < sig->param_count; ++i) {
		int stack_offset = g_array_index (cfg->varinfo, MonoVarInfo, cfg->args_start_index + i + sig->hasthis).offset;
		fprintf (info->f, ".stabs \"%s:p(0,%d)=(0,%d)\",160,0,%d,%d\n", names [i], info->next_idx++, sig->params [i]->type, line, stack_offset);
	}
	/* local vars */
	if (!method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
		MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
		for (i = 0; i < header->num_locals; ++i) {
			int stack_offset = g_array_index (cfg->varinfo, MonoVarInfo, cfg->locals_start_index + i).offset;
			fprintf (info->f, ".stabs \"local_%d:(0,%d)=(0,%d)\",128,0,%d,%d\n", i, info->next_idx++, header->locals [i]->type, line, stack_offset);
		}
	}
#endif

	fprintf (info->f, ".stabn 68,0,%d,%d\n", minfo->start_line, 0);

	for (i = 1; i < minfo->line_numbers->len; i++) {
		DebugLineNumberInfo *lni = g_ptr_array_index (minfo->line_numbers, i);

		fprintf (info->f, ".stabn 68,0,%d,%d\n", lni->line, lni->address - minfo->code_start);
	}

	/* end of function */
	fprintf (info->f, ".stabs \"\",36,0,0,%d\n", minfo->code_size);

	g_free (names);
	fflush (info->f);
}

static void
get_enumvalue (MonoClass *klass, int index, char *buf)
{
	guint32 const_cols [MONO_CONSTANT_SIZE];
	const char *ptr;
	guint32 crow = mono_metadata_get_constant_index (klass->image, MONO_TOKEN_FIELD_DEF | (index + 1));

	if (!crow) {
		buf [0] = '0';
		buf [1] = 0;
		return;
	}
	mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_CONSTANT], crow-1, const_cols, MONO_CONSTANT_SIZE);
	ptr = mono_metadata_blob_heap (klass->image, const_cols [MONO_CONSTANT_VALUE]);
	switch (const_cols [MONO_CONSTANT_TYPE]) {
	case MONO_TYPE_U4:
	case MONO_TYPE_I4:
		/* FIXME: add other types... */
	default:
		g_snprintf (buf, 64, "%d", *(gint32*)ptr);
	}
}

static void
write_method_func (gpointer key, gpointer value, gpointer user_data)
{
	write_method_stabs (user_data, value);
}

void
mono_debug_write_assembly_stabs (AssemblyDebugInfo* info)
{
	int i;
	for (i = 0; base_types [i].name; ++i) {
		if (! base_types [i].spec)
			continue;
		fprintf (info->f, ".stabs \"%s:t(0,%d)=", base_types [i].name, i);
		if (base_types [i].spec [0] == ';') {
			fprintf (info->f, "r(0,%d)%s\"", i, base_types [i].spec);
		} else {
			fprintf (info->f, "%s\"", base_types [i].spec);
		}
		fprintf (info->f, ",128,0,0,0\n");
	}

	g_hash_table_foreach (info->methods, write_method_func, info);
}

--=-=-=


* debug-dwarf2.c - this file now contains the dwarf2 code


--=-=-=
Content-Type: text/x-csrc
Content-Disposition: attachment; filename=debug-dwarf2.c

#include <stdlib.h>
#include <string.h>
#include <mono/metadata/class.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/tokentype.h>
#include <mono/jit/codegen.h>
#include <mono/jit/dwarf2.h>
#include <mono/jit/debug.h>

#include "debug-private.h"

#define ABBREV_GLOBAL_COMPILE_UNIT	1
#define ABBREV_COMPILE_UNIT		2
#define ABBREV_COMPILE_UNIT_NOLINES	3
#define ABBREV_SUBPROGRAM		4
#define ABBREV_SUBPROGRAM_RETVAL	5
#define ABBREV_BASE_TYPE		6
#define ABBREV_FORMAL_PARAMETER		7


void
mono_debug_open_assembly_dwarf2 (AssemblyDebugInfo *info)
{
}

void
mono_debug_close_assembly_dwarf2 (AssemblyDebugInfo *info)
{
}

static void
dwarf2_write_byte (FILE *f, int byte)
{
	fprintf (f, "\t.byte\t\t%d\n", byte);
}

static void
dwarf2_write_2byte (FILE *f, int word)
{
	fprintf (f, "\t.2byte\t\t%d\n", word);
}

static void
dwarf2_write_pair (FILE *f, int a, int b)
{
	fprintf (f, "\t.byte\t\t%d, %d\n", a, b);
}

static void
dwarf2_write_address (FILE *f, void *address)
{
	fprintf (f, "\t.long\t\t%p\n", address);
}

static void
dwarf2_write_string (FILE *f, const char *string)
{
	fprintf (f, "\t.string\t\t\"%s\"\n", string);
}

static void
dwarf2_write_sleb128 (FILE *f, int value)
{
	fprintf (f, "\t.sleb128\t%d\n", value);
}

static void
dwarf2_write_uleb128 (FILE *f, int value)
{
	fprintf (f, "\t.uleb128\t%d\n", value);
}

static void
dwarf2_write_section_start (FILE *f, const char *section)
{
	fprintf (f, "\t.section\t.%s\n", section);
}

static void
dwarf2_write_section_end (FILE *f)
{
	fprintf (f, "\t.previous\n\n");
}

static void
dwarf2_write_label (FILE *f, int section, const char *label)
{
	fprintf (f, ".L_%d_%s:\n", section, label);
}

static void
dwarf2_write_section_size (FILE *f, int section, const char *start_label,
			   const char *end_label)
{
	fprintf (f, "\t.long\t\t.L_%d_%s - .L_%d_%s\n",
		 section, end_label, section, start_label);
}

static void
dwarf2_write_abs_ref (FILE *f, int target_section, const char *target_label)
{
	fprintf (f, "\t.long\t\t.L_%d_%s\n", target_section, target_label);
}

static void
dwarf2_write_type_ref (FILE *f, int section, int type_index)
{
	fprintf (f, "\t.long\t\t.L_%d_TYPE_%d - .L_%d_debug_info_b\n",
		 section, type_index, section);
}

static void
dwarf2_write_dw_lns_copy (FILE *f)
{
	dwarf2_write_byte (f, DW_LNS_copy);
}

static void
dwarf2_write_dw_lns_advance_pc (FILE *f, unsigned value)
{
	dwarf2_write_byte (f, DW_LNS_advance_pc);
	dwarf2_write_uleb128 (f, value);
}

static void
dwarf2_write_dw_lns_advance_line (FILE *f, int value)
{
	dwarf2_write_byte (f, DW_LNS_advance_line);
	dwarf2_write_sleb128 (f, value);
}

static void
dwarf2_write_dw_lns_negate_stmt (FILE *f)
{
	dwarf2_write_byte (f, DW_LNS_negate_stmt);
}

static void
dwarf2_write_dw_lns_set_basic_block (FILE *f)
{
	dwarf2_write_byte (f, DW_LNS_set_basic_block);
}

static void
dwarf2_write_dw_lne_end_sequence (FILE *f)
{
	dwarf2_write_byte (f, 0);
	dwarf2_write_byte (f, 1);
	dwarf2_write_byte (f, DW_LNE_end_sequence);
}

static void
dwarf2_write_dw_lne_set_address (FILE *f, void *address)
{
	dwarf2_write_byte (f, 0);
	dwarf2_write_byte (f, sizeof (address) + 1);
	dwarf2_write_byte (f, DW_LNE_set_address);
	dwarf2_write_address (f, address);
}

static void
dwarf2_write_compile_unit_header (AssemblyDebugInfo *info, int section)
{
	// Compile unit header
	dwarf2_write_section_start (info->f, "debug_info");
	dwarf2_write_label (info->f, section, "debug_info_b");
	dwarf2_write_section_size (info->f, section, "DI1", "debug_info_e");
	dwarf2_write_label (info->f, section, "DI1");
	dwarf2_write_2byte (info->f, 2);
	dwarf2_write_abs_ref (info->f, 0, "debug_abbrev_b");
	dwarf2_write_byte (info->f, sizeof (gpointer));
}

static void
dwarf2_write_basic_type (AssemblyDebugInfo *info, int section, int index,
			 int type, int size, gchar *name)
{
	char buffer [BUFSIZ];

	sprintf (buffer, "TYPE_%d", index);
	dwarf2_write_label (info->f, section, buffer);
	// DW_TAG_basic_type
	dwarf2_write_byte (info->f, ABBREV_BASE_TYPE);
	dwarf2_write_string (info->f, name);
	dwarf2_write_byte (info->f, type);
	dwarf2_write_byte (info->f, size);
}

static void
write_basic_types (AssemblyDebugInfo *info, DebugMethodInfo *minfo)
{
	int section = minfo ? minfo->method_number : 0;

	dwarf2_write_basic_type (info, section, MONO_TYPE_BOOLEAN,
				 DW_ATE_boolean, 1, "Boolean");
	dwarf2_write_basic_type (info, section, MONO_TYPE_CHAR,
				 DW_ATE_unsigned_char, 2, "Char");
	dwarf2_write_basic_type (info, section, MONO_TYPE_I1,
				 DW_ATE_signed, 1, "SByte");
	dwarf2_write_basic_type (info, section, MONO_TYPE_U1,
				 DW_ATE_unsigned, 1, "Byte");
	dwarf2_write_basic_type (info, section, MONO_TYPE_I2,
				 DW_ATE_signed, 2, "Int16");
	dwarf2_write_basic_type (info, section, MONO_TYPE_U2,
				 DW_ATE_unsigned, 2, "UInt16");
	dwarf2_write_basic_type (info, section, MONO_TYPE_I4,
				 DW_ATE_signed, 4, "Int32");
	dwarf2_write_basic_type (info, section, MONO_TYPE_U4,
				 DW_ATE_unsigned, 4, "UInt32");
	dwarf2_write_basic_type (info, section, MONO_TYPE_I8,
				 DW_ATE_signed, 8, "Int64");
	dwarf2_write_basic_type (info, section, MONO_TYPE_U8,
				 DW_ATE_unsigned, 8, "UInt64");
	dwarf2_write_basic_type (info, section, MONO_TYPE_R4,
				 DW_ATE_signed, 4, "Float");
	dwarf2_write_basic_type (info, section, MONO_TYPE_R8,
				 DW_ATE_unsigned, 8, "Double");
}

static guint
debug_get_type_index (AssemblyDebugInfo *info, GHashTable *type_hash, MonoType *type)
{
	guint hash;

	hash = mono_metadata_type_hash (type);
	if (g_hash_table_lookup (type_hash, GINT_TO_POINTER (hash)))
		return hash;

	g_hash_table_insert (type_hash, GINT_TO_POINTER (hash), type);

	return hash;
}

static void
write_line_numbers (AssemblyDebugInfo *info, DebugMethodInfo *minfo)
{
	/* State machine registers. */
	const int line_base = 1, line_range = 8, opcode_base = 10;
	const int standard_opcode_sizes [10] = {
		0, 0, 1, 1, 1, 1, 0, 0, 0, 0
	};
	const int section = minfo->method_number;
	guint32 st_line = 0;
	gpointer st_address = 0;
	const char *source_file;
	int i;
	
	if (!minfo->line_numbers)
		return;

	source_file = (gchar *) g_ptr_array_index (info->source_files, minfo->source_file);

	// Line number information.
	dwarf2_write_section_start (info->f, "debug_line");
	dwarf2_write_label (info->f, section, "debug_line_b");
	dwarf2_write_section_size (info->f, section, "DL1", "debug_line_e");
	dwarf2_write_label (info->f, section, "DL1");
	dwarf2_write_2byte (info->f, 2);
	dwarf2_write_section_size (info->f, section, "DL2", "DL3");
	dwarf2_write_label (info->f, section, "DL2");
	// minimum instruction length
	dwarf2_write_byte (info->f, 1);
	// default is statement
	dwarf2_write_byte (info->f, 1);
	// line base
	dwarf2_write_byte (info->f, line_base);
	// line range
	dwarf2_write_byte (info->f, line_range);
	// opcode base
	dwarf2_write_byte (info->f, opcode_base);
	// standard opcode sizes
	for (i = 0; i < opcode_base; i++)
		dwarf2_write_byte (info->f, standard_opcode_sizes [i]);
	// include directories
	dwarf2_write_byte (info->f, 0);
	// file names
	{
		// File 0
		dwarf2_write_string (info->f, source_file);
		dwarf2_write_uleb128 (info->f, 0);
		dwarf2_write_uleb128 (info->f, 0);
		dwarf2_write_uleb128 (info->f, 0);
		// end of list
		dwarf2_write_byte (info->f, 0);
	}
	dwarf2_write_label (info->f, section, "DL3");

	// Start of statement program
	dwarf2_write_dw_lns_advance_line (info->f, minfo->start_line - 1);
	dwarf2_write_dw_lne_set_address (info->f, minfo->code_start);
	dwarf2_write_dw_lns_negate_stmt (info->f);
	dwarf2_write_dw_lns_copy (info->f);

	st_line = minfo->start_line;
	st_address = minfo->code_start;

	for (i = 1; i < minfo->line_numbers->len; i++) {
		DebugLineNumberInfo *lni = g_ptr_array_index (minfo->line_numbers, i);
		gint32 line_inc, addr_inc, opcode;
		int used_standard_opcode = 0;

		line_inc = lni->line - st_line;
		addr_inc = lni->address - st_address;

		if (addr_inc < 0) {
			dwarf2_write_dw_lne_set_address (info->f, lni->address);
			used_standard_opcode = 1;
		} else if (addr_inc && !line_inc) {
			dwarf2_write_dw_lns_advance_pc (info->f, addr_inc);
			used_standard_opcode = 1;
		}

		if ((line_inc < 0) || (line_inc >= line_range)) {
			dwarf2_write_dw_lns_advance_pc (info->f, addr_inc);
			dwarf2_write_dw_lns_advance_line (info->f, line_inc);
			used_standard_opcode = 1;
		} else if (line_inc > 0) {
			opcode = (line_inc - 1) + (line_range * addr_inc) + opcode_base;
			g_assert (opcode >= 0);

			if (opcode >= 256) {
				dwarf2_write_dw_lns_advance_pc (info->f, addr_inc);
				dwarf2_write_dw_lns_advance_line (info->f, line_inc);
				used_standard_opcode = 1;
			} else
				dwarf2_write_byte (info->f, opcode);
		}

		if (used_standard_opcode)
			dwarf2_write_dw_lns_copy (info->f);

		st_line += line_inc;
		st_address += addr_inc;
	}

	dwarf2_write_dw_lne_set_address (info->f, minfo->code_start + minfo->code_size);
	dwarf2_write_dw_lns_copy (info->f);
	dwarf2_write_dw_lne_end_sequence (info->f);
	dwarf2_write_label (info->f, section, "debug_line_e");
	dwarf2_write_section_end (info->f);
}

static void
write_type_dwarf2 (DebugMethodInfo *minfo, MonoType *type, guint index)
{
	switch (type->type) {
	case MONO_TYPE_BOOLEAN:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_BOOLEAN,
					 DW_ATE_boolean, 1, "Boolean");
		return;
	case MONO_TYPE_CHAR:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_CHAR,
					 DW_ATE_unsigned_char, 2, "Char");
		return;
	case MONO_TYPE_I1:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_I1,
					 DW_ATE_signed, 1, "SByte");
		return;
	case MONO_TYPE_U1:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_U1,
					 DW_ATE_unsigned, 1, "Byte");
		return;
	case MONO_TYPE_I2:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_I2,
					 DW_ATE_signed, 2, "Int16");
		return;
	case MONO_TYPE_U2:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_U2,
					 DW_ATE_unsigned, 2, "UInt16");
		return;
	case MONO_TYPE_I4:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_I4,
					 DW_ATE_signed, 4, "Int32");
		return;
	case MONO_TYPE_U4:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_U4,
					 DW_ATE_unsigned, 4, "UInt32");
		return;
	case MONO_TYPE_I8:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_I8,
					 DW_ATE_signed, 8, "Int64");
		return;
	case MONO_TYPE_U8:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_U8,
					 DW_ATE_unsigned, 8, "UInt64");
		return;
	case MONO_TYPE_R4:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_R4,
					 DW_ATE_signed, 4, "Float");
		return;
	case MONO_TYPE_R8:
		dwarf2_write_basic_type (minfo->info, minfo->method_number, MONO_TYPE_R8,
					 DW_ATE_unsigned, 8, "Double");
		return;
	default:
		g_message (G_STRLOC ": %p - %u", type, index);
		break;
	}
}

static void
write_type (gpointer key, gpointer value, gpointer user_data)
{
	write_type_dwarf2 (user_data, value, GPOINTER_TO_INT (key));
}

static void
write_method_dwarf2 (AssemblyDebugInfo *info, DebugMethodInfo *minfo)
{
	gchar **names, *source_file;
	int is_external = 0, i;
	GHashTable *type_hash;
	MonoType *ret_type;

	write_line_numbers (info, minfo);

	dwarf2_write_compile_unit_header (info, minfo->method_number);

	source_file = (gchar *) g_ptr_array_index (info->source_files, minfo->source_file);

	if (minfo->method->signature->ret->type != MONO_TYPE_VOID)
		ret_type = minfo->method->signature->ret;
	else
		ret_type = NULL;

	// DW_TAG_compile_unit
	if (minfo->line_numbers)
		dwarf2_write_byte (info->f, ABBREV_COMPILE_UNIT);
	else
		dwarf2_write_byte (info->f, ABBREV_COMPILE_UNIT_NOLINES);
	dwarf2_write_string (info->f, source_file);
	dwarf2_write_2byte (info->f, DW_LANG_C_plus_plus);
	dwarf2_write_string (info->f, info->producer_name);
	if (minfo->line_numbers)
		dwarf2_write_abs_ref (info->f, minfo->method_number, "debug_lines_b");

	type_hash = g_hash_table_new (NULL, NULL);

	// DW_TAG_subprogram
	if (ret_type)
		dwarf2_write_byte (info->f, ABBREV_SUBPROGRAM_RETVAL);
	else
		dwarf2_write_byte (info->f, ABBREV_SUBPROGRAM);
	dwarf2_write_string (info->f, minfo->name);
	dwarf2_write_byte (info->f, is_external);
	dwarf2_write_address (info->f, minfo->code_start);
	dwarf2_write_address (info->f, minfo->code_start + minfo->code_size);
	dwarf2_write_byte (info->f, DW_CC_nocall);
	if (ret_type) {
		int type_index = debug_get_type_index (info, type_hash, ret_type);
		dwarf2_write_type_ref (info->f, minfo->method_number, type_index);
	}

	names = g_new (char *, minfo->method->signature->param_count);
	mono_method_get_param_names (minfo->method, (const char **) names);

	for (i = 0; i < minfo->method->signature->param_count; i++) {
		MonoType *type = minfo->method->signature->params [i];
		int type_index = debug_get_type_index (info, type_hash, type);

		// DW_TAG_format_parameter
		dwarf2_write_byte (info->f, ABBREV_FORMAL_PARAMETER);
		dwarf2_write_string (info->f, names [i]);
		dwarf2_write_type_ref (info->f, minfo->method_number, type_index);
	}

	g_free (names);

	dwarf2_write_byte (info->f, 0);
	// DW_TAG_subprogram ends here

	g_hash_table_foreach (type_hash, write_type, minfo);

	dwarf2_write_byte (info->f, 0);
	// DW_TAG_compile_unit ends here

	dwarf2_write_label (info->f, minfo->method_number, "debug_info_e");
	dwarf2_write_section_end (info->f);

	g_hash_table_destroy (type_hash);
}

static void
write_method_func (gpointer key, gpointer value, gpointer user_data)
{
	write_method_dwarf2 (user_data, value);
}

void
mono_debug_write_assembly_dwarf2 (AssemblyDebugInfo *info)
{
	gchar *source_file = g_ptr_array_index (info->source_files, 0);

	// DWARF 2 Abbreviation table.
	dwarf2_write_section_start (info->f, "debug_abbrev");
	dwarf2_write_label (info->f, 0, "debug_abbrev");

	dwarf2_write_byte (info->f, ABBREV_GLOBAL_COMPILE_UNIT);
	dwarf2_write_byte (info->f, DW_TAG_compile_unit);
	dwarf2_write_byte (info->f, DW_CHILDREN_yes);
	dwarf2_write_pair (info->f, DW_AT_name, DW_FORM_string);
	dwarf2_write_pair (info->f, DW_AT_language, DW_FORM_data2);
	dwarf2_write_pair (info->f, DW_AT_producer, DW_FORM_string);
	dwarf2_write_pair (info->f, 0, 0);

	dwarf2_write_byte (info->f, ABBREV_COMPILE_UNIT);
	dwarf2_write_byte (info->f, DW_TAG_compile_unit);
	dwarf2_write_byte (info->f, DW_CHILDREN_yes);
	dwarf2_write_pair (info->f, DW_AT_name, DW_FORM_string);
	dwarf2_write_pair (info->f, DW_AT_language, DW_FORM_data2);
	dwarf2_write_pair (info->f, DW_AT_producer, DW_FORM_string);
	dwarf2_write_pair (info->f, DW_AT_stmt_list, DW_FORM_ref4);
	dwarf2_write_pair (info->f, 0, 0);

	dwarf2_write_byte (info->f, ABBREV_COMPILE_UNIT_NOLINES);
	dwarf2_write_byte (info->f, DW_TAG_compile_unit);
	dwarf2_write_byte (info->f, DW_CHILDREN_yes);
	dwarf2_write_pair (info->f, DW_AT_name, DW_FORM_string);
	dwarf2_write_pair (info->f, DW_AT_language, DW_FORM_data2);
	dwarf2_write_pair (info->f, DW_AT_producer, DW_FORM_string);
	dwarf2_write_pair (info->f, 0, 0);

	dwarf2_write_byte (info->f, ABBREV_SUBPROGRAM);
	dwarf2_write_byte (info->f, DW_TAG_subprogram);
	dwarf2_write_byte (info->f, DW_CHILDREN_yes);
	dwarf2_write_pair (info->f, DW_AT_name, DW_FORM_string);
	dwarf2_write_pair (info->f, DW_AT_external, DW_FORM_flag);
	dwarf2_write_pair (info->f, DW_AT_low_pc, DW_FORM_addr);
	dwarf2_write_pair (info->f, DW_AT_high_pc, DW_FORM_addr);
	dwarf2_write_pair (info->f, DW_AT_calling_convention, DW_FORM_data1);
	dwarf2_write_pair (info->f, 0, 0);

	dwarf2_write_byte (info->f, ABBREV_SUBPROGRAM_RETVAL);
	dwarf2_write_byte (info->f, DW_TAG_subprogram);
	dwarf2_write_byte (info->f, DW_CHILDREN_yes);
	dwarf2_write_pair (info->f, DW_AT_name, DW_FORM_string);
	dwarf2_write_pair (info->f, DW_AT_external, DW_FORM_flag);
	dwarf2_write_pair (info->f, DW_AT_low_pc, DW_FORM_addr);
	dwarf2_write_pair (info->f, DW_AT_high_pc, DW_FORM_addr);
	dwarf2_write_pair (info->f, DW_AT_calling_convention, DW_FORM_data1);
	dwarf2_write_pair (info->f, DW_AT_type, DW_FORM_ref4);
	dwarf2_write_pair (info->f, 0, 0);

	dwarf2_write_byte (info->f, ABBREV_BASE_TYPE);
	dwarf2_write_byte (info->f, DW_TAG_base_type);
	dwarf2_write_byte (info->f, DW_CHILDREN_no);
	dwarf2_write_pair (info->f, DW_AT_name, DW_FORM_string);
	dwarf2_write_pair (info->f, DW_AT_encoding, DW_FORM_data1);
	dwarf2_write_pair (info->f, DW_AT_byte_size, DW_FORM_data1);
	dwarf2_write_pair (info->f, 0, 0);

	dwarf2_write_byte (info->f, ABBREV_FORMAL_PARAMETER);
	dwarf2_write_byte (info->f, DW_TAG_formal_parameter);
	dwarf2_write_byte (info->f, DW_CHILDREN_no);
	dwarf2_write_pair (info->f, DW_AT_name, DW_FORM_string);
	dwarf2_write_pair (info->f, DW_AT_type, DW_FORM_ref4);
	dwarf2_write_pair (info->f, 0, 0);

	dwarf2_write_label (info->f, 0, "debug_abbrev_e");
	dwarf2_write_section_end (info->f);

	// Global compile unit header
	dwarf2_write_compile_unit_header (info, 0);

	// DW_TAG_compile_unit
	dwarf2_write_byte (info->f, ABBREV_GLOBAL_COMPILE_UNIT);
	dwarf2_write_string (info->f, source_file);
	dwarf2_write_2byte (info->f, DW_LANG_C_plus_plus);
	dwarf2_write_string (info->f, info->producer_name);

	write_basic_types (info, NULL);

	dwarf2_write_byte (info->f, 0);
	// DW_TAG_compile_unit ends here

	dwarf2_write_label (info->f, 0, "debug_info_e");

	dwarf2_write_section_end (info->f);

	g_hash_table_foreach (info->methods, write_method_func, info);
}

--=-=-=


* Patches for debug.h and jit.c:


--=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=diff

? debug-dwarf2.c
? debug-private.h
? debug-stabs.c
? dwarf2.h
Index: Makefile.am
===================================================================
RCS file: /cvs/public/mono/mono/jit/Makefile.am,v
retrieving revision 1.15
diff -u -u -r1.15 Makefile.am
--- Makefile.am	2002/03/07 19:08:11	1.15
+++ Makefile.am	2002/03/12 15:40:57
@@ -15,7 +15,10 @@
 	regset.h		\
 	regset.c		\
 	debug.h			\
+	debug-private.h		\
 	debug.c			\
+	debug-stabs.c		\
+	debug-dwarf2.c		\
 	jit.c
 
 mono_LDADD =				\
Index: debug.h
===================================================================
RCS file: /cvs/public/mono/mono/jit/debug.h,v
retrieving revision 1.1
diff -u -u -r1.1 debug.h
--- debug.h	2001/11/27 11:46:56	1.1
+++ debug.h	2002/03/12 15:40:57
@@ -8,10 +8,15 @@
 
 typedef struct _MonoDebugHandle MonoDebugHandle;
 
+typedef enum {
+	MONO_DEBUG_FORMAT_STABS,
+	MONO_DEBUG_FORMAT_DWARF2
+} MonoDebugFormat;
+
 extern MonoDebugHandle *mono_debug_handle;
 extern GList *mono_debug_methods;
 
-MonoDebugHandle* mono_debug_open_file (char *filename);
+MonoDebugHandle* mono_debug_open_file (char *filename, MonoDebugFormat format);
 
 void           mono_debug_close (MonoDebugHandle* debug);
 
Index: jit.c
===================================================================
RCS file: /cvs/public/mono/mono/jit/jit.c,v
retrieving revision 1.112
diff -u -u -r1.112 jit.c
--- jit.c	2002/03/08 06:08:46	1.112
+++ jit.c	2002/03/12 15:41:00
@@ -3218,6 +3218,7 @@
 		 "--share-code     force jit to produce shared code\n"
 		 "--print-vtable   print the VTable of all used classes\n"
 		 "--stabs          write stabs debug information\n"
+		 "--dwarf          write dwarf2 debug information\n"
 		 "--stats          print statistics about the jit operations\n"
 		 "--compile cname  compile methods in given class (namespace.name[:methodname])\n"
 		 "--ncompile num   compile methods num times (default: 1000)\n"
@@ -3377,7 +3378,9 @@
 			memset (&mono_jit_stats, 0, sizeof (MonoJitStats));
 			mono_jit_stats.enabled = TRUE;
 		} else if (strcmp (argv [i], "--stabs") == 0) {
-			mono_debug_handle = mono_debug_open_file ("");
+			mono_debug_handle = mono_debug_open_file ("", MONO_DEBUG_FORMAT_STABS);
+		} else if (strcmp (argv [i], "--dwarf") == 0) {
+			mono_debug_handle = mono_debug_open_file ("", MONO_DEBUG_FORMAT_DWARF2);
 		} else if (strcmp (argv [i], "--verbose") == 0) {
 			verbose = TRUE;;
 		} else
@@ -3498,6 +3501,9 @@
 		retval = mono_jit_exec (domain, assembly, argc - i, argv + i);
 		printf ("RESULT: %d\n", retval);
 	}
+
+	if (mono_debug_handle)
+		mono_debug_close (mono_debug_handle);
 
 	mono_network_cleanup();
 	mono_thread_cleanup();

--=-=-=


Comments and suggestions are very welcome :-)

-- 
Martin Baulig
martin@gnome.org


--=-=-=--