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 75 filename_delete_one(/*@only@*/ void *d) 76 { 77 yasm_xfree(d); 78 } 79 80 void 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 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 * 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 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 209 yasm_linemap_get_current(yasm_linemap *linemap) 210 { 211 return linemap->current; 212 } 213 214 void 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 240 yasm_linemap_goto_next(yasm_linemap *linemap) 241 { 242 return ++(linemap->current); 243 } 244 245 void 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 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 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