2002-08-24 Martin Baulig <martin@gnome.org>
[mono.git] / mono / metadata / debug-mono-symfile.c
1 #include <config.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <signal.h>
5 #include <mono/metadata/metadata.h>
6 #include <mono/metadata/rawbuffer.h>
7 #include <mono/metadata/tokentype.h>
8 #include <mono/metadata/appdomain.h>
9 #include <mono/metadata/exception.h>
10 #include <mono/metadata/debug-mono-symfile.h>
11
12 #include <fcntl.h>
13 #include <unistd.h>
14
15
16 static int
17 load_symfile (MonoSymbolFile *symfile)
18 {
19         MonoSymbolFileMethodEntry *me, *me_end;
20         const char *ptr, *start, *end;
21         guint64 magic;
22         long version;
23
24         ptr = start = symfile->raw_contents;
25
26         magic = *((guint64 *) ptr)++;
27         if (magic != MONO_SYMBOL_FILE_MAGIC) {
28                 g_warning ("Symbol file %s has is not a mono symbol file", symfile->file_name);
29                 return FALSE;
30         }
31
32         version = *((guint32 *) ptr)++;
33         if (version != MONO_SYMBOL_FILE_VERSION) {
34                 g_warning ("Symbol file %s has incorrect line number table version "
35                            "(expected %d, got %ld)", symfile->file_name,
36                            MONO_SYMBOL_FILE_VERSION, version);
37                 return FALSE;
38         }
39
40         symfile->offset_table = (MonoSymbolFileOffsetTable *) ptr;
41
42         /*
43          * Read method table.
44          *
45          */
46
47         symfile->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
48                                                        NULL, (GDestroyNotify) g_free);
49
50         ptr = symfile->raw_contents + symfile->offset_table->method_table_offset;
51         end = ptr + symfile->offset_table->method_table_size;
52
53         me = (MonoSymbolFileMethodEntry *) ptr;
54         me_end = ((MonoSymbolFileMethodEntry *) end);
55
56         for (; me < me_end; me++) {
57                 MonoMethod *method = mono_get_method (symfile->image, me->token, NULL);
58
59                 if (!method)
60                         continue;
61
62                 g_hash_table_insert (symfile->method_table, method, me);
63         }
64
65         return TRUE;
66 }
67
68 MonoSymbolFile *
69 mono_debug_open_mono_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
70 {
71         MonoSymbolFile *symfile;
72         off_t file_size;
73         void *ptr;
74         int fd;
75
76         fd = open (filename, O_RDWR);
77         if (fd == -1) {
78                 if (emit_warnings)
79                         g_warning ("Can't open symbol file: %s", filename);
80                 return NULL;
81         }
82
83         file_size = lseek (fd, 0, SEEK_END);
84         lseek (fd, 0, SEEK_SET);
85
86         if (file_size == (off_t) -1) {
87                 if (emit_warnings)
88                         g_warning ("Can't get size of symbol file: %s", filename);
89                 return NULL;
90         }
91
92         ptr = mono_raw_buffer_load (fd, 1, 0, file_size);
93         if (!ptr) {
94                 if (emit_warnings)
95                         g_warning ("Can't read symbol file: %s", filename);
96                 return NULL;
97         }
98
99         symfile = g_new0 (MonoSymbolFile, 1);
100         symfile->fd = fd;
101         symfile->file_name = g_strdup (filename);
102         symfile->image = image;
103         symfile->raw_contents = ptr;
104         symfile->raw_contents_size = file_size;
105
106         if (!load_symfile (symfile)) {
107                 mono_debug_close_mono_symbol_file (symfile);
108                 return NULL;
109         }
110
111         return symfile;
112 }
113
114 void
115 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
116 {
117         if (!symfile)
118                 return;
119
120         if (symfile->raw_contents)
121                 mono_raw_buffer_free (symfile->raw_contents);
122         if (symfile->fd)
123                 close (symfile->fd);
124
125         g_free (symfile->file_name);
126         g_free (symfile);
127 }
128
129 gchar *
130 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
131                                  guint32 *line_number)
132 {
133         MonoSymbolFileMethodEntry *me;
134         MonoSymbolFileLineNumberEntry *lne, *lne_end;
135         const char *ptr, *end, *source_file;
136
137         if (!symfile->method_table)
138                 return NULL;
139
140         me = g_hash_table_lookup (symfile->method_table, method);
141         if (!me)
142                 return NULL;
143
144         source_file = symfile->raw_contents + me->source_file_offset;
145
146         ptr = symfile->raw_contents + me->line_number_table_offset;
147         end = symfile->raw_contents + symfile->offset_table->line_number_table_offset +
148                 symfile->offset_table->line_number_table_size;
149
150         lne = (MonoSymbolFileLineNumberEntry *) ptr;
151         lne_end = ((MonoSymbolFileLineNumberEntry *) end);
152
153         for (; (lne < lne_end) && lne->row; lne++) {
154                 g_message (G_STRLOC ": %d - %d", lne->row, lne->offset);
155
156                 if (lne->offset < offset)
157                         continue;
158
159                 if (line_number) {
160                         *line_number = lne->row;
161                         return g_strdup (source_file);
162                 } else
163                         return g_strdup_printf ("%s:%d", source_file, lne->row);
164         }
165
166         return NULL;
167 }