Removed some debugging stuff and made this work for the first line in a method.
[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_RDONLY);
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, TRUE, FALSE, 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                 if (lne->offset < offset)
155                         continue;
156
157                 if (line_number) {
158                         *line_number = lne->row;
159                         return g_strdup (source_file);
160                 } else
161                         return g_strdup_printf ("%s:%d", source_file, lne->row);
162         }
163
164         return NULL;
165 }
166
167 struct MyData
168 {
169         MonoSymbolFile *symfile;
170         MonoDebugGetMethodFunc get_method_func;
171         gpointer user_data;
172 };
173
174 static void
175 update_method_func (gpointer key, gpointer value, gpointer user_data)
176 {
177         struct MyData *mydata = (struct MyData *) user_data;
178         MonoSymbolFileMethodEntry *me = (MonoSymbolFileMethodEntry *) value;
179         MonoMethod *method = (MonoMethod *) key;
180         MonoSymbolFileLineNumberEntry *lne, *lne_end;
181         const char *ptr, *end;
182         int first = TRUE;
183
184         MonoDebugMethodInfo *minfo = mydata->get_method_func
185                 (mydata->symfile, method, mydata->user_data);
186
187         if (!minfo)
188                 return;
189
190         me->start_address = minfo->code_start;
191         me->end_address = minfo->code_start + minfo->code_size;
192
193         ptr = mydata->symfile->raw_contents + me->line_number_table_offset;
194         end = mydata->symfile->raw_contents + mydata->symfile->offset_table->line_number_table_offset +
195                 mydata->symfile->offset_table->line_number_table_size;
196
197         lne = (MonoSymbolFileLineNumberEntry *) ptr;
198         lne_end = ((MonoSymbolFileLineNumberEntry *) end);
199
200         for (; (lne < lne_end) && lne->row; lne++) {
201                 guint32 address;
202                 int i;
203
204                 if (first) {
205                         lne->address = 0;
206                         first = FALSE;
207                         continue;
208                 } else if (lne->offset == 0) {
209                         lne->address = minfo->prologue_end;
210                         continue;
211                 }
212
213                 address = minfo->code_size;
214
215                 for (i = 0; i < minfo->num_il_offsets; i++) {
216                         MonoDebugILOffsetInfo *il = &minfo->il_offsets [i];
217
218                         if (il->offset >= lne->offset) {
219                                 address = il->address;
220                                 break;
221                         }
222                 }
223
224                 lne->address = address;
225         }
226
227 }
228
229 void
230 mono_debug_update_mono_symbol_file (MonoSymbolFile *symfile,
231                                     MonoDebugGetMethodFunc get_method_func,
232                                     gpointer user_data)
233 {
234         if (symfile->method_table) {
235                 struct MyData mydata = { symfile, get_method_func, user_data };
236                 g_hash_table_foreach (symfile->method_table, update_method_func, &mydata);
237         }
238
239         mono_raw_buffer_update (symfile->raw_contents, symfile->raw_contents_size);
240 }