• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * YASM assembler virtual line mapping handling (for parse stage)
3  *
4  *  Copyright (C) 2002-2007  Peter Johnson
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include "util.h"
28 
29 #include "coretype.h"
30 #include "hamt.h"
31 
32 #include "errwarn.h"
33 #include "linemap.h"
34 
35 
36 typedef struct line_mapping {
37     /* monotonically increasing virtual line */
38     unsigned long line;
39 
40     /* related info */
41     /* "original" source filename */
42     /*@null@*/ /*@dependent@*/ const char *filename;
43     /* "original" source base line number */
44     unsigned long file_line;
45     /* "original" source line number increment (for following lines) */
46     unsigned long line_inc;
47 } line_mapping;
48 
49 typedef struct line_source_info {
50     /* first bytecode on line; NULL if no bytecodes on line */
51     /*@null@*/ /*@dependent@*/ yasm_bytecode *bc;
52 
53     /* source code line */
54     /*@owned@*/ char *source;
55 } line_source_info;
56 
57 struct yasm_linemap {
58     /* Shared storage for filenames */
59     /*@only@*/ /*@null@*/ HAMT *filenames;
60 
61     /* Current virtual line number. */
62     unsigned long current;
63 
64     /* Mappings from virtual to physical line numbers */
65     struct line_mapping *map_vector;
66     unsigned long map_size;
67     unsigned long map_allocated;
68 
69     /* Bytecode and source line information */
70     /*@only@*/ line_source_info *source_info;
71     size_t source_info_size;
72 };
73 
74 static void
filename_delete_one(void * d)75 filename_delete_one(/*@only@*/ void *d)
76 {
77     yasm_xfree(d);
78 }
79 
80 void
yasm_linemap_set(yasm_linemap * linemap,const char * filename,unsigned long virtual_line,unsigned long file_line,unsigned long line_inc)81 yasm_linemap_set(yasm_linemap *linemap, const char *filename,
82                  unsigned long virtual_line, unsigned long file_line,
83                  unsigned long line_inc)
84 {
85     char *copy;
86     unsigned long i;
87     int replace = 0;
88     line_mapping *mapping = NULL;
89 
90     if (virtual_line == 0) {
91         virtual_line = linemap->current;
92     }
93 
94     /* Replace all existing mappings that have line numbers >= this one. */
95     for (i = linemap->map_size; i > 0; i--) {
96         if (linemap->map_vector[i-1].line < virtual_line) {
97             if (i < linemap->map_size) {
98                 mapping = &linemap->map_vector[i];
99                 linemap->map_size = i + 1;
100             }
101             break;
102         }
103     }
104 
105     if (mapping == NULL) {
106         /* Create a new mapping in the map */
107         if (linemap->map_size >= linemap->map_allocated) {
108             /* allocate another size bins when full for 2x space */
109             linemap->map_vector = yasm_xrealloc(linemap->map_vector,
110                 2*linemap->map_allocated*sizeof(line_mapping));
111             linemap->map_allocated *= 2;
112         }
113         mapping = &linemap->map_vector[linemap->map_size];
114         linemap->map_size++;
115     }
116 
117     /* Fill it */
118 
119     if (!filename) {
120         if (linemap->map_size >= 2)
121             mapping->filename =
122                 linemap->map_vector[linemap->map_size-2].filename;
123         else
124             filename = "unknown";
125     }
126     if (filename) {
127         /* Copy the filename (via shared storage) */
128         copy = yasm__xstrdup(filename);
129         /*@-aliasunique@*/
130         mapping->filename = HAMT_insert(linemap->filenames, copy, copy,
131                                         &replace, filename_delete_one);
132         /*@=aliasunique@*/
133     }
134 
135     mapping->line = virtual_line;
136     mapping->file_line = file_line;
137     mapping->line_inc = line_inc;
138 }
139 
140 unsigned long
yasm_linemap_poke(yasm_linemap * linemap,const char * filename,unsigned long file_line)141 yasm_linemap_poke(yasm_linemap *linemap, const char *filename,
142                   unsigned long file_line)
143 {
144     unsigned long line;
145     line_mapping *mapping;
146 
147     linemap->current++;
148     yasm_linemap_set(linemap, filename, 0, file_line, 0);
149 
150     mapping = &linemap->map_vector[linemap->map_size-1];
151 
152     line = linemap->current;
153 
154     linemap->current++;
155     yasm_linemap_set(linemap, mapping->filename, 0,
156                      mapping->file_line +
157                      mapping->line_inc*(linemap->current-2-mapping->line),
158                      mapping->line_inc);
159 
160     return line;
161 }
162 
163 yasm_linemap *
yasm_linemap_create(void)164 yasm_linemap_create(void)
165 {
166     size_t i;
167     yasm_linemap *linemap = yasm_xmalloc(sizeof(yasm_linemap));
168 
169     linemap->filenames = HAMT_create(0, yasm_internal_error_);
170 
171     linemap->current = 1;
172 
173     /* initialize mapping vector */
174     linemap->map_vector = yasm_xmalloc(8*sizeof(line_mapping));
175     linemap->map_size = 0;
176     linemap->map_allocated = 8;
177 
178     /* initialize source line information array */
179     linemap->source_info_size = 2;
180     linemap->source_info = yasm_xmalloc(linemap->source_info_size *
181                                         sizeof(line_source_info));
182     for (i=0; i<linemap->source_info_size; i++) {
183         linemap->source_info[i].bc = NULL;
184         linemap->source_info[i].source = NULL;
185     }
186 
187     return linemap;
188 }
189 
190 void
yasm_linemap_destroy(yasm_linemap * linemap)191 yasm_linemap_destroy(yasm_linemap *linemap)
192 {
193     size_t i;
194     for (i=0; i<linemap->source_info_size; i++) {
195         if (linemap->source_info[i].source)
196             yasm_xfree(linemap->source_info[i].source);
197     }
198     yasm_xfree(linemap->source_info);
199 
200     yasm_xfree(linemap->map_vector);
201 
202     if (linemap->filenames)
203         HAMT_destroy(linemap->filenames, filename_delete_one);
204 
205     yasm_xfree(linemap);
206 }
207 
208 unsigned long
yasm_linemap_get_current(yasm_linemap * linemap)209 yasm_linemap_get_current(yasm_linemap *linemap)
210 {
211     return linemap->current;
212 }
213 
214 void
yasm_linemap_add_source(yasm_linemap * linemap,yasm_bytecode * bc,const char * source)215 yasm_linemap_add_source(yasm_linemap *linemap, yasm_bytecode *bc,
216                         const char *source)
217 {
218     size_t i;
219 
220     while (linemap->current > linemap->source_info_size) {
221         /* allocate another size bins when full for 2x space */
222         linemap->source_info = yasm_xrealloc(linemap->source_info,
223             2*linemap->source_info_size*sizeof(line_source_info));
224         for (i=linemap->source_info_size; i<linemap->source_info_size*2; i++) {
225             linemap->source_info[i].bc = NULL;
226             linemap->source_info[i].source = NULL;
227         }
228         linemap->source_info_size *= 2;
229     }
230 
231     /* Delete existing info for that line (if any) */
232     if (linemap->source_info[linemap->current-1].source)
233         yasm_xfree(linemap->source_info[linemap->current-1].source);
234 
235     linemap->source_info[linemap->current-1].bc = bc;
236     linemap->source_info[linemap->current-1].source = yasm__xstrdup(source);
237 }
238 
239 unsigned long
yasm_linemap_goto_next(yasm_linemap * linemap)240 yasm_linemap_goto_next(yasm_linemap *linemap)
241 {
242     return ++(linemap->current);
243 }
244 
245 void
yasm_linemap_lookup(yasm_linemap * linemap,unsigned long line,const char ** filename,unsigned long * file_line)246 yasm_linemap_lookup(yasm_linemap *linemap, unsigned long line,
247                     const char **filename, unsigned long *file_line)
248 {
249     line_mapping *mapping;
250     unsigned long vindex, step;
251 
252     assert(line <= linemap->current);
253 
254     /* Binary search through map to find highest line_index <= index */
255     vindex = 0;
256     /* start step as the greatest power of 2 <= size */
257     step = 1;
258     while (step*2<=linemap->map_size)
259         step*=2;
260     while (step>0) {
261         if (vindex+step < linemap->map_size
262                 && linemap->map_vector[vindex+step].line <= line)
263             vindex += step;
264         step /= 2;
265     }
266     mapping = &linemap->map_vector[vindex];
267 
268     *filename = mapping->filename;
269     *file_line = (line ? mapping->file_line + mapping->line_inc*(line-mapping->line) : 0);
270 }
271 
272 int
yasm_linemap_traverse_filenames(yasm_linemap * linemap,void * d,int (* func)(const char * filename,void * d))273 yasm_linemap_traverse_filenames(yasm_linemap *linemap, /*@null@*/ void *d,
274                                 int (*func) (const char *filename, void *d))
275 {
276     return HAMT_traverse(linemap->filenames, d, (int (*) (void *, void *))func);
277 }
278 
279 int
yasm_linemap_get_source(yasm_linemap * linemap,unsigned long line,yasm_bytecode ** bcp,const char ** sourcep)280 yasm_linemap_get_source(yasm_linemap *linemap, unsigned long line,
281                         yasm_bytecode **bcp, const char **sourcep)
282 {
283     if (line > linemap->source_info_size) {
284         *bcp = NULL;
285         *sourcep = NULL;
286         return 1;
287     }
288 
289     *bcp = linemap->source_info[line-1].bc;
290     *sourcep = linemap->source_info[line-1].source;
291 
292     return (!(*sourcep));
293 }
294