Membangun debug information untuk mini language menggunakan DIBuilder: generate DWARF metadata agar bisa didebug di gdb/lldb, memahami metadata nodes vs named metadata, TBAA untuk alias analysis, dan step-through mini language di lldb.

Setelah di episode 13 kita mengintegrasikan optimasi dan menangani variabel mutable dengan alloca-bump, pada episode ini kita menambahkan aspek yang sering dilewatkan tetapi sangat penting untuk production: debug information.
Tanpa debug info, kalian tidak bisa mendebug kode yang dihasilkan LLVM di gdb/lldb. Debug info dalam LLVM direpresentasikan sebagai metadata — data tambahan yang melekat pada IR tanpa mempengaruhi codegen. Untuk mini language kita, debug info memungkinkan step-through baris per baris di debugger.
LLVM menyediakan DIBuilder untuk membuat debug info dalam format DWARF:
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
// Di setup module
DIBuilder *DBuilder = new DIBuilder(*M);
// Buat file debug
DIFile *File = DBuilder->createFile("repl.kaleidoscope", ".");
// Buat compile unit
DICompileUnit *CU = DBuilder->createCompileUnit(
dwarf::DW_LANG_C, File, "Kaleidoscope REPL", false, "", 0);
// Buat fungsi debug info
DISubroutineType *FuncType = DBuilder->createSubroutineType(
DBuilder->getOrCreateTypeArray({DBuilder->createBasicType(
"double", 64, dwarf::DW_ATE_float)}));
DISubprogram *SP = DBuilder->createFunction(
File, "fib", "fib", File, 0, FuncType,
0, llvm::DISPFlags::SPFlagDefinition, 0);Function *F = ...;
F->setSubprogram(SP);
// Set debug location untuk instruksi
Builder->SetCurrentDebugLocation(
llvm::DebugLoc::get(1, 0, SP));
// Buat variabel debug
auto *DIVar = DBuilder->createAutoVariable(
SP, "x", File, 1, DBuilder->createBasicType("double", 64, dwarf::DW_ATE_float));
DBuilder->insertDbgValueIntrinsic(
&F->arg_begin()[0], llvm::_DBG_VALUE_LIST{}, DIVar,
DBuilder->createExpression(nullptr),
llvm::DebugLoc::get(1, 0, SP),
Builder->GetInsertBlock());DIBuilder akan menghasilkan metadata DWARF yang dikenali oleh gdb/lldb.
Metadata nodes adalah data terstruktur yang melekat pada instruksi:
%sum = add i32 %a, !tbaa !5Named metadata adalah metadata module-level dengan nama:
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!1, !2}
!0 = distinct !DICompileUnit(...)
!1 = !{i32 7, !"Dwarf Version", i32 5}TBAA membantu optimizer menentukan apakah dua pointer bisa menunjuk ke memory yang sama:
; Struktur TBAA: type node → parent node
!tbaa = !{!1, !2, !6}
!1 = !{!"Simple C/C++ TBAA"}
!2 = !{!"omnipotent char", !1, i64 0}
!6 = !{!"int", !2, i64 0}
; Penggunaan
%val = load i32, ptr %p, !tbaa !6Note
TBAA memberitahu optimizer: "load ini dari tipe int; ia tidak bisa tumpang tindih dengan pointer ke float." Ini memungkinkan optimizer menghapus load redundan dan reorder instruksi dengan aman. Tanpa TBAA, optimizer harus asumsikan semua pointer bisa tumpang tindih (alias).
Build mini language dengan debug info, lalu debug:
clang++ -g -O0 -o kaleidoscope kaleidoscope.cpp \
$(llvm-config --cxxflags --ldflags --libs core)lldb ./kaleidoscope
(lldb) b main
(lldb) r
(lldb) n # step over
(lldb) s # step into
(lldb) v x # print variable
(lldb) bt # backtraceDengan debug info yang benar, kalian bisa set breakpoint di baris spesifik, melihat nilai variabel, dan step-through kode — bahkan untuk bahasa yang baru kalian ciptakan.
Inti yang harus dibawa pulang:
-g -O0 untuk debugging; attach debug info untuk bahasa custom.Di episode 15 selanjutnya kita akan membahas Clang AST & libTooling — eksplorasi AST Clang dengan clang -ast-dump, ASTMatchers, ClangTool driver, dan menulis clang-tidy check sendiri. Sampai jumpa di episode 15!