Beispiel #1
0
static void
read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
{
	var->index = read_leb128 (ptr, &ptr);
	var->offset = read_sleb128 (ptr, &ptr);
	var->size = read_leb128 (ptr, &ptr);
	var->begin_scope = read_leb128 (ptr, &ptr);
	var->end_scope = read_leb128 (ptr, &ptr);
	READ_UNALIGNED (gpointer, ptr, var->type);
	ptr += sizeof (gpointer);
	*rptr = ptr;
}
Beispiel #2
0
static MonoDebugMethodJitInfo *
mono_debug_read_method (MonoDebugMethodAddress *address)
{
	MonoDebugMethodJitInfo *jit;
	guint32 i;
	guint8 *ptr;

	jit = g_new0 (MonoDebugMethodJitInfo, 1);
	jit->code_start = address->code_start;
	jit->code_size = address->code_size;
	jit->wrapper_addr = address->wrapper_addr;

	ptr = (guint8 *) &address->data;

	jit->prologue_end = read_leb128 (ptr, &ptr);
	jit->epilogue_begin = read_leb128 (ptr, &ptr);

	jit->num_line_numbers = read_leb128 (ptr, &ptr);
	jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
	for (i = 0; i < jit->num_line_numbers; i++) {
		MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];

		lne->il_offset = read_sleb128 (ptr, &ptr);
		lne->native_offset = read_sleb128 (ptr, &ptr);
	}

	if (*ptr++) {
		jit->this_var = g_new0 (MonoDebugVarInfo, 1);
		read_variable (jit->this_var, ptr, &ptr);
	}

	jit->num_params = read_leb128 (ptr, &ptr);
	jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
	for (i = 0; i < jit->num_params; i++)
		read_variable (&jit->params [i], ptr, &ptr);

	jit->num_locals = read_leb128 (ptr, &ptr);
	jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
	for (i = 0; i < jit->num_locals; i++)
		read_variable (&jit->locals [i], ptr, &ptr);

	if (*ptr++) {
		jit->gsharedvt_info_var = g_new0 (MonoDebugVarInfo, 1);
		jit->gsharedvt_locals_var = g_new0 (MonoDebugVarInfo, 1);
		read_variable (jit->gsharedvt_info_var, ptr, &ptr);
		read_variable (jit->gsharedvt_locals_var, ptr, &ptr);
	}

	return jit;
}
Beispiel #3
0
static LineNumberTableFlags
method_get_lnt_flags (MonoDebugMethodInfo *minfo)
{
	MonoSymbolFile *symfile;
	const unsigned char *ptr;
	guint32 flags;

	if ((symfile = minfo->handle->symfile) == NULL)
		return (LineNumberTableFlags)0;

	ptr = symfile->raw_contents + minfo->data_offset;

	/* Has to read 'flags' which is preceeded by a bunch of other data */
	/* compile_unit_index */
	read_leb128 (ptr, &ptr);
	/* local variable table offset */
	read_leb128 (ptr, &ptr);
	/* namespace id */
	read_leb128 (ptr, &ptr);
	/* code block table offset */
	read_leb128 (ptr, &ptr);
	/* scope variable table offset */
	read_leb128 (ptr, &ptr);
	/* real name offset */
	read_leb128 (ptr, &ptr);

	flags = read_leb128 (ptr, &ptr);
	return (LineNumberTableFlags)flags;
}
static gboolean
method_has_column_info (MonoDebugMethodInfo *minfo)
{
	MonoSymbolFile *symfile;
	const unsigned char *ptr;
	guint32 flags;

	if ((symfile = minfo->handle->symfile) == NULL)
		return FALSE;

	ptr = symfile->raw_contents + minfo->data_offset;

	/* Has to read 'flags' which is preceeded by a bunch of other data */
	/* compile_unit_index */
	read_leb128 (ptr, &ptr);
	/* local variable table offset */
	read_leb128 (ptr, &ptr);
	/* namespace id */
	read_leb128 (ptr, &ptr);
	/* code block table offset */
	read_leb128 (ptr, &ptr);
	/* scope variable table offset */
	read_leb128 (ptr, &ptr);
	/* real name offset */
	read_leb128 (ptr, &ptr);

	flags = read_leb128 (ptr, &ptr);
	return (flags & 2) > 0;
}
Beispiel #5
0
static gchar *
read_string (const uint8_t *ptr, const uint8_t **endp)
{
    gchar *s;
    int len = read_leb128 (ptr, &ptr);

    s = g_filename_from_utf8 ((const char *) ptr, len, NULL, NULL, NULL);
    ptr += len;
    if (endp)
        *endp = ptr;
    return s;
}
Beispiel #6
0
/*
 * mono_debug_symfile_lookup_locals:
 *
 *   Return information about the local variables of MINFO from the symbol file.
 * Return NULL if no information can be found.
 * The result should be freed using mono_debug_symfile_free_locals ().
 */
MonoDebugLocalsInfo*
mono_debug_symfile_lookup_locals (MonoDebugMethodInfo *minfo)
{
    MonoSymbolFile *symfile = minfo->handle->symfile;
    const uint8_t *p;
    int i, len, compile_unit_index, locals_offset, num_locals, block_index;
    int namespace_id, code_block_table_offset;
    MonoDebugLocalsInfo *res;

    if (!symfile)
        return NULL;

    p = symfile->raw_contents + minfo->data_offset;

    compile_unit_index = read_leb128 (p, &p);
    locals_offset = read_leb128 (p, &p);
    namespace_id = read_leb128 (p, &p);
    code_block_table_offset = read_leb128 (p, &p);

    res = g_new0 (MonoDebugLocalsInfo, 1);

    p = symfile->raw_contents + code_block_table_offset;
    res->num_blocks = read_leb128 (p, &p);
    res->code_blocks = g_new0 (MonoDebugCodeBlock, res->num_blocks);
    for (i = 0; i < res->num_blocks; ++i) {
        res->code_blocks [i].type = read_leb128 (p, &p);
        res->code_blocks [i].parent = read_leb128 (p, &p);
        res->code_blocks [i].start_offset = read_leb128 (p, &p);
        res->code_blocks [i].end_offset = read_leb128 (p, &p);
    }

    p = symfile->raw_contents + locals_offset;
    num_locals = read_leb128 (p, &p);

    res->num_locals = num_locals;
    res->locals = g_new0 (MonoDebugLocalVar, num_locals);

    for (i = 0; i < num_locals; ++i) {
        res->locals [i].index = read_leb128 (p, &p);
        len = read_leb128 (p, &p);
        res->locals [i].name = g_malloc (len + 1);
        memcpy (res->locals [i].name, p, len);
        res->locals [i].name [len] = '\0';
        p += len;
        block_index = read_leb128 (p, &p);
        if (block_index >= 1 && block_index <= res->num_blocks)
            res->locals [i].block = &res->code_blocks [block_index - 1];
    }

    return res;
}
Beispiel #7
0
/*
 * mono_debug_symfile_get_line_numbers_full:
 *
 * On return, SOURCE_FILE_LIST will point to a GPtrArray of MonoDebugSourceFile
 * structures, and SOURCE_FILES will contain indexes into this array.
 * The MonoDebugSourceFile structures are owned by this module.
 */
void
mono_debug_symfile_get_line_numbers_full (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int *n_il_offsets, int **il_offsets, int **line_numbers, int **source_files)
{
    // FIXME: Unify this with mono_debug_symfile_lookup_location
    MonoSymbolFile *symfile;
    const unsigned char *ptr;
    StatementMachine stm;
    uint32_t i;
    GPtrArray *il_offset_array, *line_number_array, *source_file_array;

    if (source_file_list)
        *source_file_list = NULL;
    if (n_il_offsets)
        *n_il_offsets = 0;
    if (source_files)
        *source_files = NULL;
    if (source_file)
        *source_file = NULL;

    if ((symfile = minfo->handle->symfile) == NULL)
        return;

    il_offset_array = g_ptr_array_new ();
    line_number_array = g_ptr_array_new ();
    source_file_array = g_ptr_array_new ();

    stm.line_base = read32 (&symfile->offset_table->_line_number_table_line_base);
    stm.line_range = read32 (&symfile->offset_table->_line_number_table_line_range);
    stm.opcode_base = (uint8_t) read32 (&symfile->offset_table->_line_number_table_opcode_base);
    stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range;

    mono_debugger_lock ();

    ptr = symfile->raw_contents + minfo->lnt_offset;

    stm.symfile = symfile;
    stm.offset = stm.last_offset = 0;
    stm.last_file = 0;
    stm.last_line = 0;
    stm.first_file = 0;
    stm.file = 1;
    stm.line = 1;
    stm.is_hidden = FALSE;

    while (TRUE) {
        uint8_t opcode = *ptr++;

        if (opcode == 0) {
            uint8_t size = *ptr++;
            const unsigned char *end_ptr = ptr + size;

            opcode = *ptr++;

            if (opcode == DW_LNE_end_sequence) {
                if (il_offset_array->len == 0)
                    /* Empty table */
                    break;
                add_line (&stm, il_offset_array, line_number_array, source_file_array);
                break;
            } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
                stm.is_hidden = !stm.is_hidden;
            } else if ((opcode >= DW_LNE_MONO__extensions_start) &&
                       (opcode <= DW_LNE_MONO__extensions_end)) {
                ; // reserved for future extensions
            } else {
                g_warning ("Unknown extended opcode %x in LNT", opcode);
            }

            ptr = end_ptr;
            continue;
        } else if (opcode < stm.opcode_base) {
            switch (opcode) {
            case DW_LNS_copy:
                add_line (&stm, il_offset_array, line_number_array, source_file_array);
                break;
            case DW_LNS_advance_pc:
                stm.offset += read_leb128 (ptr, &ptr);
                break;
            case DW_LNS_advance_line:
                stm.line += read_leb128 (ptr, &ptr);
                break;
            case DW_LNS_set_file:
                stm.file = read_leb128 (ptr, &ptr);
                break;
            case DW_LNS_const_add_pc:
                stm.offset += stm.max_address_incr;
                break;
            default:
                g_warning ("Unknown standard opcode %x in LNT", opcode);
                g_assert_not_reached ();
            }
        } else {
            opcode -= stm.opcode_base;

            stm.offset += opcode / stm.line_range;
            stm.line += stm.line_base + (opcode % stm.line_range);

            add_line (&stm, il_offset_array, line_number_array, source_file_array);
        }
    }

    if (!stm.file && stm.first_file)
        stm.file = stm.first_file;

    if (stm.file && source_file) {
        int offset = read32(&(stm.symfile->offset_table->_source_table_offset)) +
                     (stm.file - 1) * sizeof (MonoSymbolFileSourceEntry);
        MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *)
                                        (stm.symfile->raw_contents + offset);

        if (source_file)
            *source_file = read_string (stm.symfile->raw_contents + read32(&(se->_data_offset)), NULL);
    }

    if (source_file_list) {
        int file, last_file = 0;

        *source_file_list = g_ptr_array_new ();
        if (source_files)
            *source_files = g_malloc (il_offset_array->len * sizeof (int));

        for (i = 0; i < il_offset_array->len; ++i) {
            file = GPOINTER_TO_UINT (g_ptr_array_index (source_file_array, i));
            if (file && file != last_file) {
                MonoDebugSourceInfo *info = get_source_info (symfile, file);

                g_ptr_array_add (*source_file_list, info);
            }
            last_file = file;
            if (source_files)
                (*source_files) [i] = (*source_file_list)->len - 1;
        }
        if ((*source_file_list)->len == 0 && stm.file) {
            MonoDebugSourceInfo *info = get_source_info (symfile, stm.file);

            g_ptr_array_add (*source_file_list, info);
        }
    }

    if (n_il_offsets)
        *n_il_offsets = il_offset_array->len;
    if (il_offsets && line_numbers) {
        *il_offsets = g_malloc (il_offset_array->len * sizeof (int));
        *line_numbers = g_malloc (il_offset_array->len * sizeof (int));
        for (i = 0; i < il_offset_array->len; ++i) {
            (*il_offsets) [i] = GPOINTER_TO_UINT (g_ptr_array_index (il_offset_array, i));
            (*line_numbers) [i] = GPOINTER_TO_UINT (g_ptr_array_index (line_number_array, i));
        }
    }
    g_ptr_array_free (il_offset_array, TRUE);
    g_ptr_array_free (line_number_array, TRUE);

    mono_debugger_unlock ();
    return;
}
Beispiel #8
0
/**
 * mono_debug_symfile_lookup_location:
 * @minfo: A `MonoDebugMethodInfo' which can be retrieved by
 *         mono_debug_lookup_method().
 * @offset: IL offset within the corresponding method's CIL code.
 *
 * This function is similar to mono_debug_lookup_location(), but we
 * already looked up the method and also already did the
 * `native address -> IL offset' mapping.
 */
MonoDebugSourceLocation *
mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset)
{
    MonoDebugSourceLocation *location = NULL;
    MonoSymbolFile *symfile;
    const unsigned char *ptr;
    StatementMachine stm;

#define DW_LNS_copy 1
#define DW_LNS_advance_pc 2
#define DW_LNS_advance_line 3
#define DW_LNS_set_file 4
#define DW_LNS_const_add_pc 8

#define DW_LNE_end_sequence 1
#define DW_LNE_MONO_negate_is_hidden 0x40

#define DW_LNE_MONO__extensions_start 0x40
#define DW_LNE_MONO__extensions_end 0x7f

    if ((symfile = minfo->handle->symfile) == NULL)
        return NULL;

    stm.line_base = read32 (&symfile->offset_table->_line_number_table_line_base);
    stm.line_range = read32 (&symfile->offset_table->_line_number_table_line_range);
    stm.opcode_base = (uint8_t) read32 (&symfile->offset_table->_line_number_table_opcode_base);
    stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range;

    mono_debugger_lock ();

    ptr = symfile->raw_contents + minfo->lnt_offset;

    stm.symfile = symfile;
    stm.offset = stm.last_offset = 0;
    stm.last_file = 0;
    stm.last_line = 0;
    stm.first_file = 0;
    stm.file = 1;
    stm.line = 1;
    stm.is_hidden = FALSE;

    while (TRUE) {
        uint8_t opcode = *ptr++;

        if (opcode == 0) {
            uint8_t size = *ptr++;
            const unsigned char *end_ptr = ptr + size;

            opcode = *ptr++;

            if (opcode == DW_LNE_end_sequence) {
                if (check_line (&stm, -1, &location))
                    goto out_success;
                break;
            } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
                stm.is_hidden = !stm.is_hidden;
            } else if ((opcode >= DW_LNE_MONO__extensions_start) &&
                       (opcode <= DW_LNE_MONO__extensions_end)) {
                ; // reserved for future extensions
            } else {
                g_warning ("Unknown extended opcode %x in LNT", opcode);
            }

            ptr = end_ptr;
            continue;
        } else if (opcode < stm.opcode_base) {
            switch (opcode) {
            case DW_LNS_copy:
                if (check_line (&stm, offset, &location))
                    goto out_success;
                break;
            case DW_LNS_advance_pc:
                stm.offset += read_leb128 (ptr, &ptr);
                break;
            case DW_LNS_advance_line:
                stm.line += read_leb128 (ptr, &ptr);
                break;
            case DW_LNS_set_file:
                stm.file = read_leb128 (ptr, &ptr);
                break;
            case DW_LNS_const_add_pc:
                stm.offset += stm.max_address_incr;
                break;
            default:
                g_warning ("Unknown standard opcode %x in LNT", opcode);
                goto error_out;
            }
        } else {
            opcode -= stm.opcode_base;

            stm.offset += opcode / stm.line_range;
            stm.line += stm.line_base + (opcode % stm.line_range);

            if (check_line (&stm, offset, &location))
                goto out_success;
        }
    }

error_out:
    mono_debugger_unlock ();
    return NULL;

out_success:
    mono_debugger_unlock ();
    return location;
}
Beispiel #9
0
static bool
read_uleb128(struct dwbuf *d, uint64_t *v)
{
	return (read_leb128(d, v, false));
}
Beispiel #10
0
static bool
read_sleb128(struct dwbuf *d, int64_t *v)
{
	return (read_leb128(d, (uint64_t *)v, true));
}
Beispiel #11
0
/*
 * mono_debug_symfile_get_seq_points:
 *
 * On return, SOURCE_FILE_LIST will point to a GPtrArray of MonoDebugSourceFile
 * structures, and SOURCE_FILES will contain indexes into this array.
 * The MonoDebugSourceFile structures are owned by this module.
 */
void
mono_debug_symfile_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points)
{
	// FIXME: Unify this with mono_debug_symfile_lookup_location
	MonoSymbolFile *symfile;
	const unsigned char *ptr;
	StatementMachine stm;
	uint32_t i, j, n;
	LineNumberTableFlags flags;
	GPtrArray *il_offset_array, *line_number_array, *source_file_array, *hidden_array;
	gboolean has_column_info, has_end_info;
	MonoSymSeqPoint *sps;

	if (source_file_list)
		*source_file_list = NULL;
	if (seq_points)
		*seq_points = NULL;
	if (n_seq_points)
		*n_seq_points = 0;
	if (source_files)
		*source_files = NULL;
	if (source_file)
		*source_file = NULL;

	if ((symfile = minfo->handle->symfile) == NULL)
		return;

	flags = method_get_lnt_flags (minfo);
	has_column_info = (flags & LNT_FLAG_HAS_COLUMN_INFO) > 0;
	has_end_info = (flags & LNT_FLAG_HAS_END_INFO) > 0;

	il_offset_array = g_ptr_array_new ();
	line_number_array = g_ptr_array_new ();
	source_file_array = g_ptr_array_new ();
	hidden_array = g_ptr_array_new();

	stm.line_base = read32 (&symfile->offset_table->_line_number_table_line_base);
	stm.line_range = read32 (&symfile->offset_table->_line_number_table_line_range);
	stm.opcode_base = (uint8_t) read32 (&symfile->offset_table->_line_number_table_opcode_base);
	stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range;

	mono_debugger_lock ();

	ptr = symfile->raw_contents + minfo->lnt_offset;

	stm.symfile = symfile;
	stm.offset = stm.last_offset = 0;
	stm.last_file = 0;
	stm.last_line = 0;
	stm.first_file = 0;
	stm.file = 1;
	stm.line = 1;
	stm.is_hidden = FALSE;

	while (TRUE) {
		uint8_t opcode = *ptr++;

		if (opcode == 0) {
			uint8_t size = *ptr++;
			const unsigned char *end_ptr = ptr + size;

			opcode = *ptr++;

			if (opcode == DW_LNE_end_sequence) {
				if (il_offset_array->len == 0)
					/* Empty table */
					break;
				break;
			} else if (opcode == DW_LNE_MONO_negate_is_hidden) {
				stm.is_hidden = !stm.is_hidden;
			} else if ((opcode >= DW_LNE_MONO__extensions_start) &&
				   (opcode <= DW_LNE_MONO__extensions_end)) {
				; // reserved for future extensions
			} else {
				g_warning ("Unknown extended opcode %x in LNT", opcode);
			}

			ptr = end_ptr;
			continue;
		} else if (opcode < stm.opcode_base) {
			switch (opcode) {
			case DW_LNS_copy:
				add_line (&stm, il_offset_array, line_number_array, source_file_array, hidden_array);
				break;
			case DW_LNS_advance_pc:
				stm.offset += read_leb128 (ptr, &ptr);
				break;
			case DW_LNS_advance_line:
				stm.line += read_leb128 (ptr, &ptr);
				break;
			case DW_LNS_set_file:
				stm.file = read_leb128 (ptr, &ptr);
				break;
			case DW_LNS_const_add_pc:
				stm.offset += stm.max_address_incr;
				break;
			default:
				g_warning ("Unknown standard opcode %x in LNT", opcode);
				g_assert_not_reached ();
			}
		} else {
			opcode -= stm.opcode_base;

			stm.offset += opcode / stm.line_range;
			stm.line += stm.line_base + (opcode % stm.line_range);

			add_line (&stm, il_offset_array, line_number_array, source_file_array, hidden_array);
		}
	}

	if (!stm.file && stm.first_file)
		stm.file = stm.first_file;

	if (stm.file && source_file) {
		int offset = read32(&(stm.symfile->offset_table->_source_table_offset)) +
			(stm.file - 1) * sizeof (MonoSymbolFileSourceEntry);
		MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *)
			(stm.symfile->raw_contents + offset);

		if (source_file)
			*source_file = read_string (stm.symfile->raw_contents + read32(&(se->_data_offset)), NULL);
	}

	if (source_file_list) {
		int file, last_file = 0;

		*source_file_list = g_ptr_array_new ();
		if (source_files)
			*source_files = (int *)g_malloc (il_offset_array->len * sizeof (int));

		for (i = 0; i < il_offset_array->len; ++i) {
			file = GPOINTER_TO_UINT (g_ptr_array_index (source_file_array, i));
			if (file && file != last_file) {
				MonoDebugSourceInfo *info = get_source_info (symfile, file);

				g_ptr_array_add (*source_file_list, info);
			}
			last_file = file;
			if (source_files)
				(*source_files) [i] = (*source_file_list)->len - 1;
		}
		if ((*source_file_list)->len == 0 && stm.file) {
			MonoDebugSourceInfo *info = get_source_info (symfile, stm.file);

			g_ptr_array_add (*source_file_list, info);
		}
	}				

	if (n_seq_points) {
		g_assert (seq_points);

		n = il_offset_array->len;
		for (i = 0; i < il_offset_array->len; i++) {
			if (GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) {
				n --;
			}
		}

		*n_seq_points = n;
		*seq_points = sps = g_new0 (MonoSymSeqPoint, n);
		j = 0;
		for (i = 0; i < il_offset_array->len; ++i) {
			MonoSymSeqPoint *sp = &(sps [j]);
			if (!GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) {
				sp->il_offset = GPOINTER_TO_UINT (g_ptr_array_index (il_offset_array, i));
				sp->line = GPOINTER_TO_UINT (g_ptr_array_index (line_number_array, i));
				sp->column = -1;
				sp->end_line = -1;
				sp->end_column = -1;
				j ++;
			}
		}

		if (has_column_info) {
			j = 0;
			for (i = 0; i < il_offset_array->len; ++i) {
				MonoSymSeqPoint *sp = &(sps [j]);
				int column = read_leb128 (ptr, &ptr);
				if (!GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) {
					sp->column = column;
					j++;
				}
			}
		}

		if (has_end_info) {
			j = 0;
			for (i = 0; i < il_offset_array->len; ++i) {
				MonoSymSeqPoint *sp = &(sps [j]);
				int end_row, end_column = -1;

				end_row = read_leb128 (ptr, &ptr);
				if (end_row != 0xffffff) {
					end_row += GPOINTER_TO_UINT (g_ptr_array_index (line_number_array, i));
					end_column = read_leb128 (ptr, &ptr);
					if (!GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) {
						sp->end_line = end_row;
						sp->end_column = end_column;
						j++;
					}
				}
			}
		}
	}

	g_ptr_array_free (il_offset_array, TRUE);
	g_ptr_array_free (line_number_array, TRUE);
	g_ptr_array_free (hidden_array, TRUE);

	mono_debugger_unlock ();
	return;
}
Beispiel #12
0
void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz )
{
  DWARF2_External_LineInfo * external;
  DWARF2_Internal_LineInfo   info;
  UChar *            standard_opcodes;
  UChar *            data = dwarf2;
  UChar *            end  = dwarf2 + dwarf2_sz;
  UChar *            end_of_sequence;
  Char  **           fnames = NULL;

  /* Fails due to gcc padding ...
  vg_assert(sizeof(DWARF2_External_LineInfo)
            == sizeof(DWARF2_Internal_LineInfo));
  */

  while (data < end)
    {
      external = (DWARF2_External_LineInfo *) data;

      /* Check the length of the block.  */
      info.li_length = * ((UInt *)(external->li_length));

      if (info.li_length == 0xffffffff)
       {
         VG_(symerr)("64-bit DWARF line info is not supported yet.");
         break;
       }

      if (info.li_length + sizeof (external->li_length) > dwarf2_sz)
       {
        VG_(symerr)("DWARF line info appears to be corrupt "
                  "- the section is too small");
         return;
       }

      /* Check its version number.  */
      info.li_version = * ((UShort *) (external->li_version));
      if (info.li_version != 2)
       {
         VG_(symerr)("Only DWARF version 2 line info "
                   "is currently supported.");
         return;
       }

      info.li_prologue_length = * ((UInt *) (external->li_prologue_length));
      info.li_min_insn_length = * ((UChar *)(external->li_min_insn_length));

      info.li_default_is_stmt = True; 
         /* WAS: = * ((UChar *)(external->li_default_is_stmt)); */
         /* Josef Weidendorfer (20021021) writes:

            It seems to me that the Intel Fortran compiler generates
            bad DWARF2 line info code: It sets "is_stmt" of the state
            machine in the the line info reader to be always
            false. Thus, there is never a statement boundary generated
            and therefore never a instruction range/line number
            mapping generated for valgrind.

            Please have a look at the DWARF2 specification, Ch. 6.2
            (x86.ddj.com/ftp/manuals/tools/dwarf.pdf).  Perhaps I
            understand this wrong, but I don't think so.

            I just had a look at the GDB DWARF2 reader...  They
            completely ignore "is_stmt" when recording line info ;-)
            That's the reason "objdump -S" works on files from the the
            intel fortran compiler.  
         */


      /* JRS: changed (UInt*) to (UChar*) */
      info.li_line_base       = * ((UChar *)(external->li_line_base));

      info.li_line_range      = * ((UChar *)(external->li_line_range));
      info.li_opcode_base     = * ((UChar *)(external->li_opcode_base)); 

      if (0) VG_(printf)("dwarf2: line base: %d, range %d, opc base: %d\n",
		  info.li_line_base, info.li_line_range, info.li_opcode_base);

      /* Sign extend the line base field.  */
      info.li_line_base <<= 24;
      info.li_line_base >>= 24;

      end_of_sequence = data + info.li_length 
                             + sizeof (external->li_length);

      reset_state_machine (info.li_default_is_stmt);

      /* Read the contents of the Opcodes table.  */
      standard_opcodes = data + sizeof (* external);

      /* Read the contents of the Directory table.  */
      data = standard_opcodes + info.li_opcode_base - 1;

      if (* data == 0) 
       {
       }
      else
       {
         /* We ignore the directory table, since gcc gives the entire
            path as part of the filename */
         while (* data != 0)
           {
             data += VG_(strlen) ((char *) data) + 1;
           }
       }

      /* Skip the NUL at the end of the table.  */
      if (*data != 0) {
         VG_(symerr)("can't find NUL at end of DWARF2 directory table");
         return;
      }
      data ++;

      /* Read the contents of the File Name table.  */
      if (* data == 0)
       {
       }
      else
       {
         while (* data != 0)
           {
             UChar * name;
             Int bytes_read;

             ++ state_machine_regs.last_file_entry;
             name = data;
             /* Since we don't have realloc (0, ....) == malloc (...)
		semantics, we need to malloc the first time. */

             if (fnames == NULL)
               fnames = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof (UInt) * 2);
             else
               fnames = VG_(arena_realloc)(VG_AR_SYMTAB, fnames,
                           VG_MIN_MALLOC_SZB,
                           sizeof(UInt) 
                              * (state_machine_regs.last_file_entry + 1));
             data += VG_(strlen) ((Char *) data) + 1;
             fnames[state_machine_regs.last_file_entry] = VG_(addStr) (si,name, -1);

             read_leb128 (data, & bytes_read, 0);
             data += bytes_read;
             read_leb128 (data, & bytes_read, 0);
             data += bytes_read;
             read_leb128 (data, & bytes_read, 0);
             data += bytes_read;
           }
       }

      /* Skip the NUL at the end of the table.  */
      if (*data != 0) {
         VG_(symerr)("can't find NUL at end of DWARF2 file name table");
         return;
      }
      data ++;

      /* Now display the statements.  */

      while (data < end_of_sequence)
       {
         UChar op_code;
         Int           adv;
         Int           bytes_read;

         op_code = * data ++;

	 if (0) VG_(printf)("dwarf2: OPC: %d\n", op_code);

         if (op_code >= info.li_opcode_base)
           {
             Int advAddr;
             op_code -= info.li_opcode_base;
             adv      = (op_code / info.li_line_range) 
                           * info.li_min_insn_length;
             advAddr = adv;
             state_machine_regs.address += adv;
             if (0) VG_(printf)("smr.a += %p\n", adv );
             adv = (op_code % info.li_line_range) + info.li_line_base;
             if (0) VG_(printf)("1002: si->o %p, smr.a %p\n", 
                                si->offset, state_machine_regs.address );
             state_machine_regs.line += adv;

	     if (state_machine_regs.is_stmt) {
		 /* only add a statement if there was a previous boundary */
		 if (state_machine_regs.last_address) 
		     VG_(addLineInfo) (si, fnames[state_machine_regs.last_file], 
				       si->offset + state_machine_regs.last_address, 
				       si->offset + state_machine_regs.address, 
				       state_machine_regs.last_line, 0);
		 state_machine_regs.last_address = state_machine_regs.address;
		 state_machine_regs.last_file = state_machine_regs.file;
		 state_machine_regs.last_line = state_machine_regs.line;
	     }
           }
         else switch (op_code)
           {
           case DW_LNS_extended_op:
             data += process_extended_line_op (
                        si, &fnames, data, 
                        info.li_default_is_stmt, sizeof (Addr));
             break;

           case DW_LNS_copy:
             if (0) VG_(printf)("1002: si->o %p, smr.a %p\n", 
                                si->offset, state_machine_regs.address );
	     if (state_machine_regs.is_stmt) {
		/* only add a statement if there was a previous boundary */
		if (state_machine_regs.last_address) 
		     VG_(addLineInfo) (si, fnames[state_machine_regs.last_file], 
				       si->offset + state_machine_regs.last_address, 
				       si->offset + state_machine_regs.address,
				       state_machine_regs.last_line, 0);
		 state_machine_regs.last_address = state_machine_regs.address;
		 state_machine_regs.last_file = state_machine_regs.file;
		 state_machine_regs.last_line = state_machine_regs.line;
	     }
             state_machine_regs.basic_block = 0; /* JRS added */
             break;

           case DW_LNS_advance_pc:
             adv = info.li_min_insn_length 
                      * read_leb128 (data, & bytes_read, 0);
             data += bytes_read;
             state_machine_regs.address += adv;
             if (0) VG_(printf)("smr.a += %p\n", adv );
             break;

           case DW_LNS_advance_line:
             adv = read_leb128 (data, & bytes_read, 1);
             data += bytes_read;
             state_machine_regs.line += adv;
             break;

           case DW_LNS_set_file:
             adv = read_leb128 (data, & bytes_read, 0);
             data += bytes_read;
             state_machine_regs.file = adv;
             break;

           case DW_LNS_set_column:
             adv = read_leb128 (data, & bytes_read, 0);
             data += bytes_read;
             state_machine_regs.column = adv;
             break;

           case DW_LNS_negate_stmt:
             adv = state_machine_regs.is_stmt;
             adv = ! adv;
             state_machine_regs.is_stmt = adv;
             break;

           case DW_LNS_set_basic_block:
             state_machine_regs.basic_block = 1;
             break;

           case DW_LNS_const_add_pc:
             adv = (((255 - info.li_opcode_base) / info.li_line_range)
                    * info.li_min_insn_length);
             state_machine_regs.address += adv;
             if (0) VG_(printf)("smr.a += %p\n", adv );
             break;

           case DW_LNS_fixed_advance_pc:
             /* XXX: Need something to get 2 bytes */
             adv = *((UShort *)data);
             data += 2;
             state_machine_regs.address += adv;
             if (0) VG_(printf)("smr.a += %p\n", adv );
             break;

           case DW_LNS_set_prologue_end:
             break;

           case DW_LNS_set_epilogue_begin:
             break;

           case DW_LNS_set_isa:
             adv = read_leb128 (data, & bytes_read, 0);
             data += bytes_read;
             break;

           default:
             {
               int j;
               for (j = standard_opcodes[op_code - 1]; j > 0 ; --j)
                 {
                   read_leb128 (data, &bytes_read, 0);
                   data += bytes_read;
                 }
             }
             break;
           }
       }
      VG_(arena_free)(VG_AR_SYMTAB, fnames);
      fnames = NULL;
    }
}
Beispiel #13
0
/* Handled an extend line op.  Returns true if this is the end
   of sequence.  */
static 
int process_extended_line_op( SegInfo *si, Char*** fnames, 
                              UChar* data, Int is_stmt, Int pointer_size)
{
  UChar   op_code;
  Int     bytes_read;
  UInt    len;
  UChar * name;
  Addr    adr;

  len = read_leb128 (data, & bytes_read, 0);
  data += bytes_read;

  if (len == 0)
    {
      VG_(message)(Vg_UserMsg,
         "badly formed extended line op encountered!\n");
      return bytes_read;
    }

  len += bytes_read;
  op_code = * data ++;

  if (0) VG_(printf)("dwarf2: ext OPC: %d\n", op_code);

  switch (op_code)
    {
    case DW_LNE_end_sequence:
      if (0) VG_(printf)("1001: si->o %p, smr.a %p\n", 
                         si->offset, state_machine_regs.address );
      state_machine_regs.end_sequence = 1; /* JRS: added for compliance
         with spec; is pointless due to reset_state_machine below 
      */
      if (state_machine_regs.is_stmt) {
	 if (state_machine_regs.last_address)
	    VG_(addLineInfo) (si, (*fnames)[state_machine_regs.last_file], 
			      si->offset + state_machine_regs.last_address, 
			      si->offset + state_machine_regs.address, 
			      state_machine_regs.last_line, 0);
      }
      reset_state_machine (is_stmt);
      break;

    case DW_LNE_set_address:
      /* XXX: Pointer size could be 8 */
      vg_assert(pointer_size == 4);
      adr = *((Addr *)data);
      if (0) VG_(printf)("smr.a := %p\n", adr );
      state_machine_regs.address = adr;
      break;

    case DW_LNE_define_file:
      ++ state_machine_regs.last_file_entry;
      name = data;
      if (*fnames == NULL)
        *fnames = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof (UInt) * 2);
      else
        *fnames = VG_(arena_realloc)(
                     VG_AR_SYMTAB, *fnames, VG_MIN_MALLOC_SZB,
                     sizeof(UInt) 
                        * (state_machine_regs.last_file_entry + 1));
      (*fnames)[state_machine_regs.last_file_entry] = VG_(addStr) (si,name, -1);
      data += VG_(strlen) ((char *) data) + 1;
      read_leb128 (data, & bytes_read, 0);
      data += bytes_read;
      read_leb128 (data, & bytes_read, 0);
      data += bytes_read;
      read_leb128 (data, & bytes_read, 0);
      break;

    default:
      break;
    }

  return len;
}