debug.c (15788B)
1 /* Debug producer: state, type DIE pool, function/scope/var lifecycle, and 2 * line-row accumulator. Emit-side serialization lives in debug_emit.c. */ 3 4 #include <string.h> 5 6 #include "core/core.h" 7 #include "core/heap.h" 8 #include "core/pool.h" 9 #include "core/slice.h" 10 #include "core/vec.h" 11 #include "debug/debug_internal.h" 12 13 /* ---- internal helpers ---- */ 14 15 static _Noreturn void debug_oom(Debug* d, const char* what) { 16 SrcLoc nl = {0, 0, 0}; 17 compiler_panic(d->c, nl, "debug: oom (%.*s)", 18 SLICE_ARG(slice_from_cstr(what))); 19 } 20 21 static DebugTypeId type_alloc(Debug* d) { 22 DebugType* slot; 23 if (VEC_GROW(d->heap, d->types, d->types_cap, d->ntypes + 1)) 24 debug_oom(d, "type pool"); 25 slot = &d->types[d->ntypes++]; 26 memset(slot, 0, sizeof(*slot)); 27 return (DebugTypeId)d->ntypes; 28 } 29 30 DebugType* debug_type_at(Debug* d, DebugTypeId id); 31 DebugType* debug_type_at(Debug* d, DebugTypeId id) { 32 if (id == DEBUG_TYPE_NONE || id > d->ntypes) return NULL; 33 return &d->types[id - 1]; 34 } 35 36 /* ---- public API: lifecycle ---- */ 37 38 Debug* debug_new(Compiler* c, ObjBuilder* ob) { 39 Heap* h = (Heap*)c->ctx->heap; 40 Debug* d = (Debug*)h->alloc(h, sizeof(*d), _Alignof(Debug)); 41 SrcLoc no_loc = {0, 0, 0}; 42 if (!d) return NULL; 43 memset(d, 0, sizeof(*d)); 44 d->c = c; 45 d->ob = ob; 46 d->heap = h; 47 d->cur_func = -1; 48 d->pending_loc = no_loc; 49 U32ToU32_init(&d->src_to_file, h); 50 return d; 51 } 52 53 static void func_free(Debug* d, DebugFunc* f) { 54 if (f->vars) d->heap->free(d->heap, f->vars, sizeof(*f->vars) * f->vars_cap); 55 if (f->scopes) 56 d->heap->free(d->heap, f->scopes, sizeof(*f->scopes) * f->scopes_cap); 57 if (f->scope_stack) 58 d->heap->free(d->heap, f->scope_stack, 59 sizeof(*f->scope_stack) * f->scope_stack_cap); 60 if (f->rows) d->heap->free(d->heap, f->rows, sizeof(*f->rows) * f->rows_cap); 61 } 62 63 static void type_free(Debug* d, DebugType* t) { 64 if (t->params) 65 d->heap->free(d->heap, t->params, sizeof(*t->params) * t->nparams); 66 if (t->fields) 67 d->heap->free(d->heap, t->fields, sizeof(*t->fields) * t->nfields); 68 if (t->enum_vals) 69 d->heap->free(d->heap, t->enum_vals, sizeof(*t->enum_vals) * t->nenums); 70 } 71 72 void debug_free(Debug* d) { 73 u32 i; 74 if (!d) return; 75 for (i = 0; i < d->nfuncs; ++i) func_free(d, &d->funcs[i]); 76 if (d->funcs) 77 d->heap->free(d->heap, d->funcs, sizeof(*d->funcs) * d->funcs_cap); 78 if (d->globals) 79 d->heap->free(d->heap, d->globals, sizeof(*d->globals) * d->globals_cap); 80 for (i = 0; i < d->ntypes; ++i) type_free(d, &d->types[i]); 81 if (d->types) 82 d->heap->free(d->heap, d->types, sizeof(*d->types) * d->types_cap); 83 if (d->files) 84 d->heap->free(d->heap, d->files, sizeof(*d->files) * d->files_cap); 85 U32ToU32_fini(&d->src_to_file); 86 d->heap->free(d->heap, d, sizeof(*d)); 87 } 88 89 /* ---- file table ---- */ 90 91 static void split_path(Pool* p, Sym path, Sym* dir_out, Sym* base_out) { 92 Slice sl = pool_slice(p, path); 93 const char* s = sl.s; 94 size_t len = sl.len; 95 size_t i; 96 size_t slash = (size_t)-1; 97 if (!s || len == 0) { 98 *dir_out = pool_intern_slice(p, SLICE_LIT("")); 99 *base_out = path ? path : pool_intern_slice(p, SLICE_LIT("")); 100 return; 101 } 102 for (i = 0; i < len; ++i) { 103 if (s[i] == '/') slash = i; 104 } 105 if (slash == (size_t)-1) { 106 *dir_out = pool_intern_slice(p, SLICE_LIT("")); 107 *base_out = path; 108 return; 109 } 110 *dir_out = pool_intern_slice(p, (Slice){.s = s, .len = slash}); 111 *base_out = 112 pool_intern_slice(p, (Slice){.s = s + slash + 1, .len = len - slash - 1}); 113 } 114 115 u32 debug_file(Debug* d, u32 source_file_id) { 116 u32* found = U32ToU32_get(&d->src_to_file, source_file_id + 1); 117 if (found) return *found; 118 { 119 const SourceFile* sf = source_file(d->c->sources, source_file_id); 120 DebugFile* slot; 121 Sym path = 0, dir, base; 122 if (sf) path = sf->path ? sf->path : sf->name; 123 if (!path) path = pool_intern_slice(d->c->global, SLICE_LIT("")); 124 split_path(d->c->global, path, &dir, &base); 125 if (VEC_GROW(d->heap, d->files, d->files_cap, d->nfiles + 1)) 126 debug_oom(d, "file table"); 127 slot = &d->files[d->nfiles]; 128 slot->src_file_id = source_file_id; 129 slot->dir = dir; 130 slot->base = base; 131 { 132 u32 idx = d->nfiles; 133 d->nfiles++; 134 U32ToU32_set(&d->src_to_file, source_file_id + 1, idx); 135 return idx; 136 } 137 } 138 } 139 140 /* ---- type DIEs ---- */ 141 142 DebugTypeId debug_type_base(Debug* d, Sym name, DebugBaseEncoding enc, 143 u32 byte_size) { 144 DebugTypeId id = type_alloc(d); 145 DebugType* t = debug_type_at(d, id); 146 t->kind = DTK_BASE; 147 t->name = name; 148 t->byte_size = byte_size; 149 t->base_encoding = (u8)enc; 150 return id; 151 } 152 153 DebugTypeId debug_type_void(Debug* d) { 154 if (d->void_type) return d->void_type; 155 { 156 DebugTypeId id = type_alloc(d); 157 DebugType* t = debug_type_at(d, id); 158 t->kind = DTK_VOID; 159 d->void_type = id; 160 return id; 161 } 162 } 163 164 DebugTypeId debug_type_ptr(Debug* d, DebugTypeId pointee) { 165 DebugTypeId id = type_alloc(d); 166 DebugType* t = debug_type_at(d, id); 167 t->kind = DTK_PTR; 168 t->inner = pointee; 169 t->byte_size = d->c->target.ptr_size; 170 return id; 171 } 172 173 DebugTypeId debug_type_array(Debug* d, DebugTypeId elem, u32 count) { 174 DebugTypeId id = type_alloc(d); 175 DebugType* t = debug_type_at(d, id); 176 t->kind = DTK_ARRAY; 177 t->inner = elem; 178 t->array_count = count; 179 return id; 180 } 181 182 DebugTypeId debug_type_const(Debug* d, DebugTypeId base) { 183 DebugTypeId id = type_alloc(d); 184 DebugType* t = debug_type_at(d, id); 185 t->kind = DTK_CONST; 186 t->inner = base; 187 return id; 188 } 189 190 DebugTypeId debug_type_volatile(Debug* d, DebugTypeId base) { 191 DebugTypeId id = type_alloc(d); 192 DebugType* t = debug_type_at(d, id); 193 t->kind = DTK_VOLATILE; 194 t->inner = base; 195 return id; 196 } 197 198 DebugTypeId debug_type_restrict(Debug* d, DebugTypeId base) { 199 DebugTypeId id = type_alloc(d); 200 DebugType* t = debug_type_at(d, id); 201 t->kind = DTK_RESTRICT; 202 t->inner = base; 203 return id; 204 } 205 206 DebugTypeId debug_type_typedef(Debug* d, Sym name, DebugTypeId base) { 207 DebugTypeId id = type_alloc(d); 208 DebugType* t = debug_type_at(d, id); 209 t->kind = DTK_TYPEDEF; 210 t->name = name; 211 t->inner = base; 212 return id; 213 } 214 215 DebugTypeId debug_type_func(Debug* d, DebugTypeId ret, 216 const DebugTypeId* params, u32 nparams, 217 int variadic) { 218 DebugTypeId id = type_alloc(d); 219 DebugType* t = debug_type_at(d, id); 220 t->kind = DTK_FUNC; 221 t->inner = ret; 222 t->variadic = (u8)(variadic ? 1 : 0); 223 if (nparams) { 224 t->params = (DebugTypeId*)d->heap->alloc( 225 d->heap, sizeof(DebugTypeId) * nparams, _Alignof(DebugTypeId)); 226 if (!t->params) debug_oom(d, "func params"); 227 memcpy(t->params, params, sizeof(DebugTypeId) * nparams); 228 t->nparams = nparams; 229 } 230 return id; 231 } 232 233 /* ---- record builders ---- */ 234 235 DebugTypeBuilder* debug_type_record_begin(Debug* d, Sym tag, int is_union, 236 u32 byte_size, u32 align) { 237 DebugTypeId id; 238 DebugType* t; 239 DebugTypeBuilder* b = (DebugTypeBuilder*)d->heap->alloc( 240 d->heap, sizeof(*b), _Alignof(DebugTypeBuilder)); 241 if (!b) debug_oom(d, "rec builder"); 242 memset(b, 0, sizeof(*b)); 243 id = type_alloc(d); 244 t = debug_type_at(d, id); 245 t->kind = DTK_RECORD; 246 t->is_union = (u8)(is_union ? 1 : 0); 247 t->name = tag; 248 t->byte_size = byte_size; 249 t->align = align; 250 b->d = d; 251 b->id = id; 252 b->is_union = (u8)(is_union ? 1 : 0); 253 b->tag = tag; 254 b->byte_size = byte_size; 255 b->align = align; 256 return b; 257 } 258 259 DebugTypeId debug_type_record_id(DebugTypeBuilder* b) { 260 return b ? b->id : DEBUG_TYPE_NONE; 261 } 262 263 void debug_type_record_field(DebugTypeBuilder* b, Sym name, DebugTypeId type, 264 u32 byte_offset) { 265 DebugRecField* f; 266 if (VEC_GROW(b->d->heap, b->fields, b->fields_cap, b->nfields + 1)) 267 debug_oom(b->d, "rec field"); 268 f = &b->fields[b->nfields++]; 269 f->name = name; 270 f->type = type; 271 f->byte_offset = byte_offset; 272 f->bit_offset = 0; 273 f->bit_width = 0; 274 } 275 276 void debug_type_record_bitfield(DebugTypeBuilder* b, Sym name, DebugTypeId type, 277 u32 byte_offset, u16 bit_offset, 278 u16 bit_width) { 279 DebugRecField* f; 280 if (VEC_GROW(b->d->heap, b->fields, b->fields_cap, b->nfields + 1)) 281 debug_oom(b->d, "rec field"); 282 f = &b->fields[b->nfields++]; 283 f->name = name; 284 f->type = type; 285 f->byte_offset = byte_offset; 286 f->bit_offset = bit_offset; 287 f->bit_width = bit_width; 288 } 289 290 DebugTypeId debug_type_record_end(DebugTypeBuilder* b) { 291 Debug* d = b->d; 292 DebugTypeId id = b->id; 293 DebugType* t = debug_type_at(d, id); 294 t->kind = DTK_RECORD; 295 t->is_union = b->is_union; 296 t->name = b->tag; 297 t->byte_size = b->byte_size; 298 t->align = b->align; 299 if (b->nfields) { 300 t->fields = (DebugRecField*)d->heap->alloc( 301 d->heap, sizeof(DebugRecField) * b->nfields, _Alignof(DebugRecField)); 302 if (!t->fields) debug_oom(d, "rec fields"); 303 memcpy(t->fields, b->fields, sizeof(DebugRecField) * b->nfields); 304 t->nfields = b->nfields; 305 } 306 if (b->fields) 307 d->heap->free(d->heap, b->fields, sizeof(*b->fields) * b->fields_cap); 308 d->heap->free(d->heap, b, sizeof(*b)); 309 return id; 310 } 311 312 DebugEnumBuilder* debug_type_enum_begin(Debug* d, Sym tag, DebugTypeId base) { 313 DebugEnumBuilder* b = (DebugEnumBuilder*)d->heap->alloc( 314 d->heap, sizeof(*b), _Alignof(DebugEnumBuilder)); 315 if (!b) debug_oom(d, "enum builder"); 316 memset(b, 0, sizeof(*b)); 317 b->d = d; 318 b->tag = tag; 319 b->base = base; 320 return b; 321 } 322 323 void debug_type_enum_value(DebugEnumBuilder* b, Sym name, i64 value) { 324 DebugEnumVal* v; 325 if (VEC_GROW(b->d->heap, b->vals, b->vals_cap, b->nvals + 1)) 326 debug_oom(b->d, "enum val"); 327 v = &b->vals[b->nvals++]; 328 v->name = name; 329 v->value = value; 330 } 331 332 DebugTypeId debug_type_enum_end(DebugEnumBuilder* b) { 333 Debug* d = b->d; 334 DebugTypeId id = type_alloc(d); 335 DebugType* t = debug_type_at(d, id); 336 t->kind = DTK_ENUM; 337 t->name = b->tag; 338 t->inner = b->base; 339 if (b->nvals) { 340 t->enum_vals = (DebugEnumVal*)d->heap->alloc( 341 d->heap, sizeof(DebugEnumVal) * b->nvals, _Alignof(DebugEnumVal)); 342 if (!t->enum_vals) debug_oom(d, "enum vals"); 343 memcpy(t->enum_vals, b->vals, sizeof(DebugEnumVal) * b->nvals); 344 t->nenums = b->nvals; 345 } 346 if (b->vals) d->heap->free(d->heap, b->vals, sizeof(*b->vals) * b->vals_cap); 347 d->heap->free(d->heap, b, sizeof(*b)); 348 return id; 349 } 350 351 /* ---- function lifecycle ---- */ 352 353 void debug_func_begin(Debug* d, ObjSymId sym, DebugTypeId fn_type, 354 SrcLoc decl) { 355 DebugFunc* f; 356 if (VEC_GROW(d->heap, d->funcs, d->funcs_cap, d->nfuncs + 1)) 357 debug_oom(d, "func table"); 358 f = &d->funcs[d->nfuncs]; 359 memset(f, 0, sizeof(*f)); 360 f->sym = sym; 361 f->fn_type = fn_type; 362 f->decl = decl; 363 f->text_section = OBJ_SEC_NONE; 364 d->cur_func = (i32)d->nfuncs; 365 d->nfuncs++; 366 } 367 368 void debug_func_select(Debug* d, ObjSymId sym) { 369 if (!d || sym == OBJ_SYM_NONE) return; 370 for (u32 i = 0; i < d->nfuncs; ++i) { 371 if (d->funcs[i].sym == sym) { 372 d->cur_func = (i32)i; 373 return; 374 } 375 } 376 } 377 378 void debug_func_pc_range(Debug* d, ObjSecId text_section, u32 begin_ofs, 379 u32 end_ofs) { 380 if (d->cur_func < 0) return; 381 { 382 DebugFunc* f = &d->funcs[d->cur_func]; 383 f->text_section = text_section; 384 f->begin_ofs = begin_ofs; 385 f->end_ofs = end_ofs; 386 f->has_pc_range = 1; 387 } 388 } 389 390 void debug_func_end(Debug* d) { 391 if (d->cur_func < 0) return; 392 d->cur_func = -1; 393 } 394 395 void debug_prune_removed_funcs(Debug* d) { 396 u32 w = 0; 397 if (!d) return; 398 for (u32 r = 0; r < d->nfuncs; ++r) { 399 DebugFunc* f = &d->funcs[r]; 400 const ObjSym* sym = obj_symbol_get(d->ob, f->sym); 401 if (!sym || sym->removed) { 402 func_free(d, f); 403 continue; 404 } 405 if (w != r) d->funcs[w] = *f; 406 ++w; 407 } 408 d->nfuncs = w; 409 d->cur_func = -1; 410 } 411 412 /* ---- scopes ---- */ 413 414 void debug_scope_begin(Debug* d, SrcLoc loc) { 415 DebugFunc* f; 416 i32 scope_idx; 417 if (d->cur_func < 0) return; 418 f = &d->funcs[d->cur_func]; 419 if (VEC_GROW(d->heap, f->scopes, f->scopes_cap, f->nscopes + 1)) 420 debug_oom(d, "scopes"); 421 if (VEC_GROW(d->heap, f->scope_stack, f->scope_stack_cap, 422 f->scope_stack_n + 1)) 423 debug_oom(d, "scope stack"); 424 scope_idx = (i32)f->nscopes; 425 f->scopes[scope_idx].parent_idx = 426 f->scope_stack_n ? f->scope_stack[f->scope_stack_n - 1] : -1; 427 f->scopes[scope_idx].begin = loc; 428 f->scopes[scope_idx].end = loc; 429 f->scopes[scope_idx].die_offset = 0; 430 f->nscopes++; 431 f->scope_stack[f->scope_stack_n++] = scope_idx; 432 } 433 434 void debug_scope_end(Debug* d, SrcLoc loc) { 435 DebugFunc* f; 436 if (d->cur_func < 0) return; 437 f = &d->funcs[d->cur_func]; 438 if (f->scope_stack_n == 0) return; 439 { 440 i32 top = f->scope_stack[--f->scope_stack_n]; 441 f->scopes[top].end = loc; 442 } 443 } 444 445 /* ---- variables ---- */ 446 447 static i32 cur_scope_idx(DebugFunc* f) { 448 if (f->scope_stack_n == 0) return -1; 449 return f->scope_stack[f->scope_stack_n - 1]; 450 } 451 452 void debug_param(Debug* d, Sym name, DebugTypeId type, SrcLoc loc, u32 idx, 453 DebugVarLoc vloc) { 454 DebugFunc* f; 455 DebugVarDIE* v; 456 if (d->cur_func < 0) return; 457 f = &d->funcs[d->cur_func]; 458 if (VEC_GROW(d->heap, f->vars, f->vars_cap, f->nvars + 1)) 459 debug_oom(d, "vars"); 460 v = &f->vars[f->nvars++]; 461 v->is_param = 1; 462 v->param_idx = idx; 463 v->name = name; 464 v->type = type; 465 v->decl = loc; 466 v->loc = vloc; 467 v->scope_idx = -1; 468 v->die_offset = 0; 469 } 470 471 void debug_local(Debug* d, Sym name, DebugTypeId type, SrcLoc loc, 472 DebugVarLoc vloc) { 473 DebugFunc* f; 474 DebugVarDIE* v; 475 if (d->cur_func < 0) return; 476 f = &d->funcs[d->cur_func]; 477 if (VEC_GROW(d->heap, f->vars, f->vars_cap, f->nvars + 1)) 478 debug_oom(d, "vars"); 479 v = &f->vars[f->nvars++]; 480 v->is_param = 0; 481 v->name = name; 482 v->type = type; 483 v->decl = loc; 484 v->loc = vloc; 485 v->scope_idx = cur_scope_idx(f); 486 v->die_offset = 0; 487 } 488 489 void debug_global(Debug* d, Sym name, DebugTypeId type, SrcLoc loc, 490 DebugVarLoc vloc, int external) { 491 DebugVarDIE* v; 492 u32 i; 493 if (!d || vloc.kind != DVL_GLOBAL) return; 494 for (i = 0; i < d->nglobals; ++i) { 495 v = &d->globals[i]; 496 if (v->loc.kind == DVL_GLOBAL && v->loc.v.global == vloc.v.global) { 497 v->is_param = 0; 498 v->external = (u8)(external ? 1 : 0); 499 v->param_idx = 0; 500 v->name = name; 501 v->type = type; 502 v->decl = loc; 503 v->loc = vloc; 504 v->scope_idx = -1; 505 v->die_offset = 0; 506 return; 507 } 508 } 509 if (VEC_GROW(d->heap, d->globals, d->globals_cap, d->nglobals + 1)) 510 debug_oom(d, "globals"); 511 v = &d->globals[d->nglobals++]; 512 v->is_param = 0; 513 v->external = (u8)(external ? 1 : 0); 514 v->param_idx = 0; 515 v->name = name; 516 v->type = type; 517 v->decl = loc; 518 v->loc = vloc; 519 v->scope_idx = -1; 520 v->die_offset = 0; 521 } 522 523 /* ---- line program input ---- */ 524 525 void debug_set_pending_loc(Debug* d, SrcLoc loc) { 526 if (!d) return; 527 d->pending_loc = loc; 528 } 529 530 void debug_emit_row(Debug* d, ObjSecId text_section_id, u32 text_offset, 531 SrcLoc loc) { 532 debug_line(d, text_section_id, text_offset, loc, 1); 533 } 534 535 void debug_line(Debug* d, ObjSecId text_section_id, u32 text_offset, SrcLoc loc, 536 int is_stmt) { 537 DebugFunc* f; 538 LineRow* prev; 539 LineRow* row; 540 if (d->cur_func < 0) return; 541 f = &d->funcs[d->cur_func]; 542 if (f->nrows) { 543 prev = &f->rows[f->nrows - 1]; 544 if (prev->section_id == text_section_id && prev->offset == text_offset && 545 prev->loc.file_id == loc.file_id && prev->loc.line == loc.line && 546 prev->loc.col == loc.col) { 547 return; 548 } 549 } 550 if (VEC_GROW(d->heap, f->rows, f->rows_cap, f->nrows + 1)) 551 debug_oom(d, "rows"); 552 row = &f->rows[f->nrows++]; 553 row->section_id = text_section_id; 554 row->offset = text_offset; 555 row->loc = loc; 556 row->is_stmt = (u8)(is_stmt ? 1 : 0); 557 }