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