authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-02-08 14:15:28+01:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-02-20 19:41:28+01:00
log3620b67c264c853442f0c1156f72ed699efe5fea
tree09e8ee9d4a3dd60338613783c67f6ea2c8eadd0e
parent3d53a95718bbf7abd17cf69c623aff4e9a97a0b4

debug: Split the DWARF stuff in its own file


3 files changed, 1624 insertions(+), 1626 deletions(-)

lib/std/debug.zig+53-944
...@@ -38,6 +38,18 @@ const Module = struct {...@@ -38,6 +38,18 @@ const Module = struct {
38 checksum_offset: ?usize,38 checksum_offset: ?usize,
39};39};
4040
41pub const LineInfo = struct {
42 line: u64,
43 column: u64,
44 file_name: []const u8,
45 allocator: ?*mem.Allocator,
46
47 fn deinit(self: LineInfo) void {
48 const allocator = self.allocator orelse return;
49 allocator.free(self.file_name);
50 }
51};
52
41/// Tries to write to stderr, unbuffered, and ignores any error returned.53/// Tries to write to stderr, unbuffered, and ignores any error returned.
42/// Does not append a newline.54/// Does not append a newline.
43var stderr_file: File = undefined;55var stderr_file: File = undefined;
...@@ -714,7 +726,35 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt...@@ -714,7 +726,35 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
714}726}
715727
716pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {728pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {
717 return debug_info.printSourceAtAddress(out_stream, address, tty_config, printLineFromFileAnyOs);729 const compile_unit = debug_info.findCompileUnit(address) catch {
730 return printLineInfo(
731 out_stream,
732 null,
733 address,
734 "???",
735 "???",
736 tty_config,
737 printLineFromFileAnyOs,
738 );
739 };
740
741 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
742 const symbol_name = debug_info.getSymbolName(address) orelse "???";
743 const line_info = debug_info.getLineNumberInfo(compile_unit.*, address) catch |err| switch (err) {
744 error.MissingDebugInfo, error.InvalidDebugInfo => null,
745 else => return err,
746 };
747 defer if (line_info) |li| li.deinit();
748
749 try printLineInfo(
750 out_stream,
751 line_info,
752 address,
753 symbol_name,
754 compile_unit_name,
755 tty_config,
756 printLineFromFileAnyOs,
757 );
718}758}
719759
720fn printLineInfo(760fn printLineInfo(
...@@ -958,36 +998,24 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {...@@ -958,36 +998,24 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
958 return list.toOwnedSlice();998 return list.toOwnedSlice();
959}999}
9601000
961fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section {1001fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DW.DwarfInfo.Section {
962 const elf_header = (try elf_file.findSection(name)) orelse return null;1002 const elf_header = (try elf_file.findSection(name)) orelse return null;
963 return DwarfInfo.Section{1003 return DW.DwarfInfo.Section{
964 .offset = elf_header.sh_offset,1004 .offset = elf_header.sh_offset,
965 .size = elf_header.sh_size,1005 .size = elf_header.sh_size,
966 };1006 };
967}1007}
9681008
969/// Initialize DWARF info. The caller has the responsibility to initialize most
970/// the DwarfInfo fields before calling. These fields can be left undefined:
971/// * abbrev_table_list
972/// * compile_unit_list
973pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
974 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
975 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
976 di.func_list = ArrayList(Func).init(allocator);
977 try di.scanAllFunctions();
978 try di.scanAllCompileUnits();
979}
980
981/// TODO resources https://github.com/ziglang/zig/issues/43531009/// TODO resources https://github.com/ziglang/zig/issues/4353
982pub fn openElfDebugInfo(1010pub fn openElfDebugInfo(
983 allocator: *mem.Allocator,1011 allocator: *mem.Allocator,
984 data: []u8,1012 data: []u8,
985) !DwarfInfo {1013) !DW.DwarfInfo {
986 var seekable_stream = io.SliceSeekableInStream.init(data);1014 var seekable_stream = io.SliceSeekableInStream.init(data);
987 var efile = try elf.Elf.openStream(1015 var efile = try elf.Elf.openStream(
988 allocator,1016 allocator,
989 @ptrCast(*DwarfSeekableStream, &seekable_stream.seekable_stream),1017 @ptrCast(*DW.DwarfSeekableStream, &seekable_stream.seekable_stream),
990 @ptrCast(*DwarfInStream, &seekable_stream.stream),1018 @ptrCast(*DW.DwarfInStream, &seekable_stream.stream),
991 );1019 );
992 defer efile.close();1020 defer efile.close();
9931021
...@@ -1001,7 +1029,7 @@ pub fn openElfDebugInfo(...@@ -1001,7 +1029,7 @@ pub fn openElfDebugInfo(
1001 return error.MissingDebugInfo;1029 return error.MissingDebugInfo;
1002 const opt_debug_ranges = try efile.findSection(".debug_ranges");1030 const opt_debug_ranges = try efile.findSection(".debug_ranges");
10031031
1004 var di = DwarfInfo{1032 var di = DW.DwarfInfo{
1005 .endian = efile.endian,1033 .endian = efile.endian,
1006 .debug_info = (data[@intCast(usize, debug_info.sh_offset)..@intCast(usize, debug_info.sh_offset + debug_info.sh_size)]),1034 .debug_info = (data[@intCast(usize, debug_info.sh_offset)..@intCast(usize, debug_info.sh_offset + debug_info.sh_size)]),
1007 .debug_abbrev = (data[@intCast(usize, debug_abbrev.sh_offset)..@intCast(usize, debug_abbrev.sh_offset + debug_abbrev.sh_size)]),1035 .debug_abbrev = (data[@intCast(usize, debug_abbrev.sh_offset)..@intCast(usize, debug_abbrev.sh_offset + debug_abbrev.sh_size)]),
...@@ -1013,12 +1041,12 @@ pub fn openElfDebugInfo(...@@ -1013,12 +1041,12 @@ pub fn openElfDebugInfo(
1013 null,1041 null,
1014 };1042 };
10151043
1016 try openDwarfDebugInfo(&di, allocator);1044 try DW.openDwarfDebugInfo(&di, allocator);
1017 return di;1045 return di;
1018}1046}
10191047
1020/// TODO resources https://github.com/ziglang/zig/issues/43531048/// TODO resources https://github.com/ziglang/zig/issues/4353
1021fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo {1049fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DW.DwarfInfo {
1022 var exe_file = try fs.openSelfExe();1050 var exe_file = try fs.openSelfExe();
1023 errdefer exe_file.close();1051 errdefer exe_file.close();
10241052
...@@ -1162,532 +1190,6 @@ const MachoSymbol = struct {...@@ -1162,532 +1190,6 @@ const MachoSymbol = struct {
1162 }1190 }
1163};1191};
11641192
1165pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
1166pub const DwarfInStream = io.InStream(anyerror);
1167
1168pub const DwarfInfo = struct {
1169 endian: builtin.Endian,
1170 // No memory is owned by the DwarfInfo
1171 debug_info: []u8,
1172 debug_abbrev: []u8,
1173 debug_str: []u8,
1174 debug_line: []u8,
1175 debug_ranges: ?[]u8,
1176 // Filled later by the initializer
1177 abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined,
1178 compile_unit_list: ArrayList(CompileUnit) = undefined,
1179 func_list: ArrayList(Func) = undefined,
1180
1181 pub fn allocator(self: DwarfInfo) *mem.Allocator {
1182 return self.abbrev_table_list.allocator;
1183 }
1184
1185 /// This function works in freestanding mode.
1186 /// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
1187 pub fn printSourceAtAddress(
1188 self: *DwarfInfo,
1189 out_stream: var,
1190 address: usize,
1191 tty_config: TTY.Config,
1192 comptime printLineFromFile: var,
1193 ) !void {
1194 const compile_unit = self.findCompileUnit(address) catch {
1195 return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFile);
1196 };
1197
1198 const compile_unit_name = try compile_unit.die.getAttrString(self, DW.AT_name);
1199 const symbol_name = self.getSymbolName(address) orelse "???";
1200 const line_info = self.getLineNumberInfo(compile_unit.*, address) catch |err| switch (err) {
1201 error.MissingDebugInfo, error.InvalidDebugInfo => null,
1202 else => return err,
1203 };
1204 defer if (line_info) |li| li.deinit();
1205
1206 try printLineInfo(
1207 out_stream,
1208 line_info,
1209 address,
1210 symbol_name,
1211 compile_unit_name,
1212 tty_config,
1213 printLineFromFile,
1214 );
1215 }
1216
1217 fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
1218 for (di.func_list.toSliceConst()) |*func| {
1219 if (func.pc_range) |range| {
1220 if (address >= range.start and address < range.end) {
1221 return func.name;
1222 }
1223 }
1224 }
1225
1226 return null;
1227 }
1228
1229 fn scanAllFunctions(di: *DwarfInfo) !void {
1230 var s = io.SliceSeekableInStream.init(di.debug_info);
1231 var this_unit_offset: u64 = 0;
1232
1233 while (true) {
1234 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
1235 error.EndOfStream => return,
1236 else => return err,
1237 };
1238
1239 var is_64: bool = undefined;
1240 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
1241 if (unit_length == 0) return;
1242 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
1243
1244 const version = try s.stream.readInt(u16, di.endian);
1245 if (version < 2 or version > 5) return error.InvalidDebugInfo;
1246
1247 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
1248
1249 const address_size = try s.stream.readByte();
1250 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
1251
1252 const compile_unit_pos = try s.seekable_stream.getPos();
1253 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
1254
1255 try s.seekable_stream.seekTo(compile_unit_pos);
1256
1257 const next_unit_pos = this_unit_offset + next_offset;
1258
1259 while ((try s.seekable_stream.getPos()) < next_unit_pos) {
1260 const die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse continue;
1261 const after_die_offset = try s.seekable_stream.getPos();
1262
1263 switch (die_obj.tag_id) {
1264 DW.TAG_subprogram, DW.TAG_inlined_subroutine, DW.TAG_subroutine, DW.TAG_entry_point => {
1265 const fn_name = x: {
1266 var depth: i32 = 3;
1267 var this_die_obj = die_obj;
1268 // Prenvent endless loops
1269 while (depth > 0) : (depth -= 1) {
1270 if (this_die_obj.getAttr(DW.AT_name)) |_| {
1271 const name = try this_die_obj.getAttrString(di, DW.AT_name);
1272 break :x name;
1273 } else if (this_die_obj.getAttr(DW.AT_abstract_origin)) |ref| {
1274 // Follow the DIE it points to and repeat
1275 const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin);
1276 if (ref_offset > next_offset) return error.InvalidDebugInfo;
1277 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
1278 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
1279 } else if (this_die_obj.getAttr(DW.AT_specification)) |ref| {
1280 // Follow the DIE it points to and repeat
1281 const ref_offset = try this_die_obj.getAttrRef(DW.AT_specification);
1282 if (ref_offset > next_offset) return error.InvalidDebugInfo;
1283 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
1284 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
1285 } else {
1286 break :x null;
1287 }
1288 }
1289
1290 break :x null;
1291 };
1292
1293 const pc_range = x: {
1294 if (die_obj.getAttrAddr(DW.AT_low_pc)) |low_pc| {
1295 if (die_obj.getAttr(DW.AT_high_pc)) |high_pc_value| {
1296 const pc_end = switch (high_pc_value.*) {
1297 FormValue.Address => |value| value,
1298 FormValue.Const => |value| b: {
1299 const offset = try value.asUnsignedLe();
1300 break :b (low_pc + offset);
1301 },
1302 else => return error.InvalidDebugInfo,
1303 };
1304 break :x PcRange{
1305 .start = low_pc,
1306 .end = pc_end,
1307 };
1308 } else {
1309 break :x null;
1310 }
1311 } else |err| {
1312 if (err != error.MissingDebugInfo) return err;
1313 break :x null;
1314 }
1315 };
1316
1317 try di.func_list.append(Func{
1318 .name = fn_name,
1319 .pc_range = pc_range,
1320 });
1321 },
1322 else => {},
1323 }
1324
1325 try s.seekable_stream.seekTo(after_die_offset);
1326 }
1327
1328 this_unit_offset += next_offset;
1329 }
1330 }
1331
1332 fn scanAllCompileUnits(di: *DwarfInfo) !void {
1333 var s = io.SliceSeekableInStream.init(di.debug_info);
1334 var this_unit_offset: u64 = 0;
1335
1336 while (true) {
1337 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
1338 error.EndOfStream => return,
1339 else => return err,
1340 };
1341
1342 var is_64: bool = undefined;
1343 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
1344 if (unit_length == 0) return;
1345 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
1346
1347 const version = try s.stream.readInt(u16, di.endian);
1348 if (version < 2 or version > 5) return error.InvalidDebugInfo;
1349
1350 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
1351
1352 const address_size = try s.stream.readByte();
1353 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
1354
1355 const compile_unit_pos = try s.seekable_stream.getPos();
1356 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
1357
1358 try s.seekable_stream.seekTo(compile_unit_pos);
1359
1360 const compile_unit_die = try di.allocator().create(Die);
1361 compile_unit_die.* = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
1362
1363 if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
1364
1365 const pc_range = x: {
1366 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
1367 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
1368 const pc_end = switch (high_pc_value.*) {
1369 FormValue.Address => |value| value,
1370 FormValue.Const => |value| b: {
1371 const offset = try value.asUnsignedLe();
1372 break :b (low_pc + offset);
1373 },
1374 else => return error.InvalidDebugInfo,
1375 };
1376 break :x PcRange{
1377 .start = low_pc,
1378 .end = pc_end,
1379 };
1380 } else {
1381 break :x null;
1382 }
1383 } else |err| {
1384 if (err != error.MissingDebugInfo) return err;
1385 break :x null;
1386 }
1387 };
1388
1389 try di.compile_unit_list.append(CompileUnit{
1390 .version = version,
1391 .is_64 = is_64,
1392 .pc_range = pc_range,
1393 .die = compile_unit_die,
1394 });
1395
1396 this_unit_offset += next_offset;
1397 }
1398 }
1399
1400 fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
1401 for (di.compile_unit_list.toSlice()) |*compile_unit| {
1402 if (compile_unit.pc_range) |range| {
1403 if (target_address >= range.start and target_address < range.end) return compile_unit;
1404 }
1405 if (di.debug_ranges) |debug_ranges| {
1406 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
1407 var s = io.SliceSeekableInStream.init(debug_ranges);
1408
1409 // All the addresses in the list are relative to the value
1410 // specified by DW_AT_low_pc or to some other value encoded
1411 // in the list itself.
1412 // If no starting value is specified use zero.
1413 var base_address = compile_unit.die.getAttrAddr(DW.AT_low_pc) catch |err| switch (err) {
1414 error.MissingDebugInfo => 0,
1415 else => return err,
1416 };
1417
1418 try s.seekable_stream.seekTo(ranges_offset);
1419
1420 while (true) {
1421 const begin_addr = try s.stream.readIntLittle(usize);
1422 const end_addr = try s.stream.readIntLittle(usize);
1423 if (begin_addr == 0 and end_addr == 0) {
1424 break;
1425 }
1426 // This entry selects a new value for the base address
1427 if (begin_addr == maxInt(usize)) {
1428 base_address = end_addr;
1429 continue;
1430 }
1431 if (target_address >= base_address + begin_addr and target_address < base_address + end_addr) {
1432 return compile_unit;
1433 }
1434 }
1435 } else |err| {
1436 if (err != error.MissingDebugInfo) return err;
1437 continue;
1438 }
1439 }
1440 }
1441 return error.MissingDebugInfo;
1442 }
1443
1444 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
1445 /// seeks in the stream and parses it.
1446 fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
1447 for (di.abbrev_table_list.toSlice()) |*header| {
1448 if (header.offset == abbrev_offset) {
1449 return &header.table;
1450 }
1451 }
1452 try di.abbrev_table_list.append(AbbrevTableHeader{
1453 .offset = abbrev_offset,
1454 .table = try di.parseAbbrevTable(abbrev_offset),
1455 });
1456 return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
1457 }
1458
1459 fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable {
1460 var s = io.SliceSeekableInStream.init(di.debug_abbrev);
1461
1462 try s.seekable_stream.seekTo(offset);
1463 var result = AbbrevTable.init(di.allocator());
1464 errdefer result.deinit();
1465 while (true) {
1466 const abbrev_code = try leb.readULEB128(u64, &s.stream);
1467 if (abbrev_code == 0) return result;
1468 try result.append(AbbrevTableEntry{
1469 .abbrev_code = abbrev_code,
1470 .tag_id = try leb.readULEB128(u64, &s.stream),
1471 .has_children = (try s.stream.readByte()) == DW.CHILDREN_yes,
1472 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
1473 });
1474 const attrs = &result.items[result.len - 1].attrs;
1475
1476 while (true) {
1477 const attr_id = try leb.readULEB128(u64, &s.stream);
1478 const form_id = try leb.readULEB128(u64, &s.stream);
1479 if (attr_id == 0 and form_id == 0) break;
1480 try attrs.append(AbbrevAttr{
1481 .attr_id = attr_id,
1482 .form_id = form_id,
1483 });
1484 }
1485 }
1486 }
1487
1488 fn parseDie(di: *DwarfInfo, in_stream: var, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
1489 const abbrev_code = try leb.readULEB128(u64, in_stream);
1490 if (abbrev_code == 0) return null;
1491 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
1492
1493 var result = Die{
1494 .tag_id = table_entry.tag_id,
1495 .has_children = table_entry.has_children,
1496 .attrs = ArrayList(Die.Attr).init(di.allocator()),
1497 };
1498 try result.attrs.resize(table_entry.attrs.len);
1499 for (table_entry.attrs.toSliceConst()) |attr, i| {
1500 result.attrs.items[i] = Die.Attr{
1501 .id = attr.attr_id,
1502 .value = try parseFormValue(di.allocator(), in_stream, attr.form_id, is_64),
1503 };
1504 }
1505 return result;
1506 }
1507
1508 fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
1509 var s = io.SliceSeekableInStream.init(di.debug_line);
1510
1511 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
1512 const line_info_offset = try compile_unit.die.getAttrSecOffset(DW.AT_stmt_list);
1513
1514 try s.seekable_stream.seekTo(line_info_offset);
1515
1516 var is_64: bool = undefined;
1517 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
1518 if (unit_length == 0) {
1519 return error.MissingDebugInfo;
1520 }
1521 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
1522
1523 const version = try s.stream.readInt(u16, di.endian);
1524 // TODO support 3 and 5
1525 if (version != 2 and version != 4) return error.InvalidDebugInfo;
1526
1527 const prologue_length = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
1528 const prog_start_offset = (try s.seekable_stream.getPos()) + prologue_length;
1529
1530 const minimum_instruction_length = try s.stream.readByte();
1531 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
1532
1533 if (version >= 4) {
1534 // maximum_operations_per_instruction
1535 _ = try s.stream.readByte();
1536 }
1537
1538 const default_is_stmt = (try s.stream.readByte()) != 0;
1539 const line_base = try s.stream.readByteSigned();
1540
1541 const line_range = try s.stream.readByte();
1542 if (line_range == 0) return error.InvalidDebugInfo;
1543
1544 const opcode_base = try s.stream.readByte();
1545
1546 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
1547
1548 {
1549 var i: usize = 0;
1550 while (i < opcode_base - 1) : (i += 1) {
1551 standard_opcode_lengths[i] = try s.stream.readByte();
1552 }
1553 }
1554
1555 var include_directories = ArrayList([]u8).init(di.allocator());
1556 try include_directories.append(compile_unit_cwd);
1557 while (true) {
1558 const dir = try readStringRaw(di.allocator(), &s.stream);
1559 if (dir.len == 0) break;
1560 try include_directories.append(dir);
1561 }
1562
1563 var file_entries = ArrayList(FileEntry).init(di.allocator());
1564 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
1565
1566 while (true) {
1567 const file_name = try readStringRaw(di.allocator(), &s.stream);
1568 if (file_name.len == 0) break;
1569 const dir_index = try leb.readULEB128(usize, &s.stream);
1570 const mtime = try leb.readULEB128(usize, &s.stream);
1571 const len_bytes = try leb.readULEB128(usize, &s.stream);
1572 try file_entries.append(FileEntry{
1573 .file_name = file_name,
1574 .dir_index = dir_index,
1575 .mtime = mtime,
1576 .len_bytes = len_bytes,
1577 });
1578 }
1579
1580 try s.seekable_stream.seekTo(prog_start_offset);
1581
1582 const next_unit_pos = line_info_offset + next_offset;
1583
1584 while ((try s.seekable_stream.getPos()) < next_unit_pos) {
1585 const opcode = try s.stream.readByte();
1586
1587 if (opcode == DW.LNS_extended_op) {
1588 const op_size = try leb.readULEB128(u64, &s.stream);
1589 if (op_size < 1) return error.InvalidDebugInfo;
1590 var sub_op = try s.stream.readByte();
1591 switch (sub_op) {
1592 DW.LNE_end_sequence => {
1593 prog.end_sequence = true;
1594 if (try prog.checkLineMatch()) |info| return info;
1595 prog.reset();
1596 },
1597 DW.LNE_set_address => {
1598 const addr = try s.stream.readInt(usize, di.endian);
1599 prog.address = addr;
1600 },
1601 DW.LNE_define_file => {
1602 const file_name = try readStringRaw(di.allocator(), &s.stream);
1603 const dir_index = try leb.readULEB128(usize, &s.stream);
1604 const mtime = try leb.readULEB128(usize, &s.stream);
1605 const len_bytes = try leb.readULEB128(usize, &s.stream);
1606 try file_entries.append(FileEntry{
1607 .file_name = file_name,
1608 .dir_index = dir_index,
1609 .mtime = mtime,
1610 .len_bytes = len_bytes,
1611 });
1612 },
1613 else => {
1614 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
1615 try s.seekable_stream.seekBy(fwd_amt);
1616 },
1617 }
1618 } else if (opcode >= opcode_base) {
1619 // special opcodes
1620 const adjusted_opcode = opcode - opcode_base;
1621 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
1622 const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);
1623 prog.line += inc_line;
1624 prog.address += inc_addr;
1625 if (try prog.checkLineMatch()) |info| return info;
1626 prog.basic_block = false;
1627 } else {
1628 switch (opcode) {
1629 DW.LNS_copy => {
1630 if (try prog.checkLineMatch()) |info| return info;
1631 prog.basic_block = false;
1632 },
1633 DW.LNS_advance_pc => {
1634 const arg = try leb.readULEB128(usize, &s.stream);
1635 prog.address += arg * minimum_instruction_length;
1636 },
1637 DW.LNS_advance_line => {
1638 const arg = try leb.readILEB128(i64, &s.stream);
1639 prog.line += arg;
1640 },
1641 DW.LNS_set_file => {
1642 const arg = try leb.readULEB128(usize, &s.stream);
1643 prog.file = arg;
1644 },
1645 DW.LNS_set_column => {
1646 const arg = try leb.readULEB128(u64, &s.stream);
1647 prog.column = arg;
1648 },
1649 DW.LNS_negate_stmt => {
1650 prog.is_stmt = !prog.is_stmt;
1651 },
1652 DW.LNS_set_basic_block => {
1653 prog.basic_block = true;
1654 },
1655 DW.LNS_const_add_pc => {
1656 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
1657 prog.address += inc_addr;
1658 },
1659 DW.LNS_fixed_advance_pc => {
1660 const arg = try s.stream.readInt(u16, di.endian);
1661 prog.address += arg;
1662 },
1663 DW.LNS_set_prologue_end => {},
1664 else => {
1665 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
1666 const len_bytes = standard_opcode_lengths[opcode - 1];
1667 try s.seekable_stream.seekBy(len_bytes);
1668 },
1669 }
1670 }
1671 }
1672
1673 return error.MissingDebugInfo;
1674 }
1675
1676 fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
1677 if (offset > di.debug_str.len)
1678 return error.InvalidDebugInfo;
1679 const casted_offset = math.cast(usize, offset) catch
1680 return error.InvalidDebugInfo;
1681
1682 // Valid strings always have a terminating zero byte
1683 if (mem.indexOfScalarPos(u8, di.debug_str, casted_offset, 0)) |last| {
1684 return di.debug_str[casted_offset..last];
1685 }
1686
1687 return error.InvalidDebugInfo;
1688 }
1689};
1690
1691pub const DebugInfo = switch (builtin.os) {1193pub const DebugInfo = switch (builtin.os) {
1692 .macosx, .ios, .watchos, .tvos => struct {1194 .macosx, .ios, .watchos, .tvos => struct {
1693 symbols: []const MachoSymbol,1195 symbols: []const MachoSymbol,
...@@ -1696,7 +1198,7 @@ pub const DebugInfo = switch (builtin.os) {...@@ -1696,7 +1198,7 @@ pub const DebugInfo = switch (builtin.os) {
16961198
1697 const OFileTable = std.HashMap(1199 const OFileTable = std.HashMap(
1698 *macho.nlist_64,1200 *macho.nlist_64,
1699 DwarfInfo,1201 DW.DwarfInfo,
1700 std.hash_map.getHashPtrAddrFn(*macho.nlist_64),1202 std.hash_map.getHashPtrAddrFn(*macho.nlist_64),
1701 std.hash_map.getTrivialEqlFn(*macho.nlist_64),1203 std.hash_map.getTrivialEqlFn(*macho.nlist_64),
1702 );1204 );
...@@ -1711,385 +1213,9 @@ pub const DebugInfo = switch (builtin.os) {...@@ -1711,385 +1213,9 @@ pub const DebugInfo = switch (builtin.os) {
1711 sect_contribs: []pdb.SectionContribEntry,1213 sect_contribs: []pdb.SectionContribEntry,
1712 modules: []Module,1214 modules: []Module,
1713 },1215 },
1714 else => DwarfInfo,1216 else => DW.DwarfInfo,
1715};
1716
1717const PcRange = struct {
1718 start: u64,
1719 end: u64,
1720};
1721
1722const CompileUnit = struct {
1723 version: u16,
1724 is_64: bool,
1725 die: *Die,
1726 pc_range: ?PcRange,
1727};
1728
1729const AbbrevTable = ArrayList(AbbrevTableEntry);
1730
1731const AbbrevTableHeader = struct {
1732 // offset from .debug_abbrev
1733 offset: u64,
1734 table: AbbrevTable,
1735};
1736
1737const AbbrevTableEntry = struct {
1738 has_children: bool,
1739 abbrev_code: u64,
1740 tag_id: u64,
1741 attrs: ArrayList(AbbrevAttr),
1742};
1743
1744const AbbrevAttr = struct {
1745 attr_id: u64,
1746 form_id: u64,
1747};
1748
1749const FormValue = union(enum) {
1750 Address: u64,
1751 Block: []u8,
1752 Const: Constant,
1753 ExprLoc: []u8,
1754 Flag: bool,
1755 SecOffset: u64,
1756 Ref: u64,
1757 RefAddr: u64,
1758 String: []u8,
1759 StrPtr: u64,
1760};
1761
1762const Constant = struct {
1763 payload: u64,
1764 signed: bool,
1765
1766 fn asUnsignedLe(self: *const Constant) !u64 {
1767 if (self.signed) return error.InvalidDebugInfo;
1768 return self.payload;
1769 }
1770};
1771
1772const Die = struct {
1773 tag_id: u64,
1774 has_children: bool,
1775 attrs: ArrayList(Attr),
1776
1777 const Attr = struct {
1778 id: u64,
1779 value: FormValue,
1780 };
1781
1782 fn getAttr(self: *const Die, id: u64) ?*const FormValue {
1783 for (self.attrs.toSliceConst()) |*attr| {
1784 if (attr.id == id) return &attr.value;
1785 }
1786 return null;
1787 }
1788
1789 fn getAttrAddr(self: *const Die, id: u64) !u64 {
1790 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1791 return switch (form_value.*) {
1792 FormValue.Address => |value| value,
1793 else => error.InvalidDebugInfo,
1794 };
1795 }
1796
1797 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
1798 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1799 return switch (form_value.*) {
1800 FormValue.Const => |value| value.asUnsignedLe(),
1801 FormValue.SecOffset => |value| value,
1802 else => error.InvalidDebugInfo,
1803 };
1804 }
1805
1806 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
1807 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1808 return switch (form_value.*) {
1809 FormValue.Const => |value| value.asUnsignedLe(),
1810 else => error.InvalidDebugInfo,
1811 };
1812 }
1813
1814 fn getAttrRef(self: *const Die, id: u64) !u64 {
1815 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1816 return switch (form_value.*) {
1817 FormValue.Ref => |value| value,
1818 else => error.InvalidDebugInfo,
1819 };
1820 }
1821
1822 fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
1823 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1824 return switch (form_value.*) {
1825 FormValue.String => |value| value,
1826 FormValue.StrPtr => |offset| di.getString(offset),
1827 else => error.InvalidDebugInfo,
1828 };
1829 }
1830};
1831
1832const FileEntry = struct {
1833 file_name: []const u8,
1834 dir_index: usize,
1835 mtime: usize,
1836 len_bytes: usize,
1837};
1838
1839pub const LineInfo = struct {
1840 line: u64,
1841 column: u64,
1842 file_name: []const u8,
1843 allocator: ?*mem.Allocator,
1844
1845 fn deinit(self: LineInfo) void {
1846 const allocator = self.allocator orelse return;
1847 allocator.free(self.file_name);
1848 }
1849};1217};
18501218
1851const LineNumberProgram = struct {
1852 address: usize,
1853 file: usize,
1854 line: i64,
1855 column: u64,
1856 is_stmt: bool,
1857 basic_block: bool,
1858 end_sequence: bool,
1859
1860 default_is_stmt: bool,
1861 target_address: usize,
1862 include_dirs: []const []const u8,
1863 file_entries: *ArrayList(FileEntry),
1864
1865 prev_address: usize,
1866 prev_file: usize,
1867 prev_line: i64,
1868 prev_column: u64,
1869 prev_is_stmt: bool,
1870 prev_basic_block: bool,
1871 prev_end_sequence: bool,
1872
1873 // Reset the state machine following the DWARF specification
1874 pub fn reset(self: *LineNumberProgram) void {
1875 self.address = 0;
1876 self.file = 1;
1877 self.line = 1;
1878 self.column = 0;
1879 self.is_stmt = self.default_is_stmt;
1880 self.basic_block = false;
1881 self.end_sequence = false;
1882 // Invalidate all the remaining fields
1883 self.prev_address = 0;
1884 self.prev_file = undefined;
1885 self.prev_line = undefined;
1886 self.prev_column = undefined;
1887 self.prev_is_stmt = undefined;
1888 self.prev_basic_block = undefined;
1889 self.prev_end_sequence = undefined;
1890 }
1891
1892 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram {
1893 return LineNumberProgram{
1894 .address = 0,
1895 .file = 1,
1896 .line = 1,
1897 .column = 0,
1898 .is_stmt = is_stmt,
1899 .basic_block = false,
1900 .end_sequence = false,
1901 .include_dirs = include_dirs,
1902 .file_entries = file_entries,
1903 .default_is_stmt = is_stmt,
1904 .target_address = target_address,
1905 .prev_address = 0,
1906 .prev_file = undefined,
1907 .prev_line = undefined,
1908 .prev_column = undefined,
1909 .prev_is_stmt = undefined,
1910 .prev_basic_block = undefined,
1911 .prev_end_sequence = undefined,
1912 };
1913 }
1914
1915 pub fn checkLineMatch(self: *LineNumberProgram) !?LineInfo {
1916 if (self.target_address >= self.prev_address and self.target_address < self.address) {
1917 const file_entry = if (self.prev_file == 0) {
1918 return error.MissingDebugInfo;
1919 } else if (self.prev_file - 1 >= self.file_entries.len) {
1920 return error.InvalidDebugInfo;
1921 } else
1922 &self.file_entries.items[self.prev_file - 1];
1923
1924 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
1925 return error.InvalidDebugInfo;
1926 } else
1927 self.include_dirs[file_entry.dir_index];
1928 const file_name = try fs.path.join(self.file_entries.allocator, &[_][]const u8{ dir_name, file_entry.file_name });
1929 errdefer self.file_entries.allocator.free(file_name);
1930 return LineInfo{
1931 .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,
1932 .column = self.prev_column,
1933 .file_name = file_name,
1934 .allocator = self.file_entries.allocator,
1935 };
1936 }
1937
1938 self.prev_address = self.address;
1939 self.prev_file = self.file;
1940 self.prev_line = self.line;
1941 self.prev_column = self.column;
1942 self.prev_is_stmt = self.is_stmt;
1943 self.prev_basic_block = self.basic_block;
1944 self.prev_end_sequence = self.end_sequence;
1945 return null;
1946 }
1947};
1948
1949// TODO the noasyncs here are workarounds
1950fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
1951 var buf = ArrayList(u8).init(allocator);
1952 while (true) {
1953 const byte = try noasync in_stream.readByte();
1954 if (byte == 0) break;
1955 try buf.append(byte);
1956 }
1957 return buf.toSlice();
1958}
1959
1960// TODO the noasyncs here are workarounds
1961fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
1962 const buf = try allocator.alloc(u8, size);
1963 errdefer allocator.free(buf);
1964 if ((try noasync in_stream.read(buf)) < size) return error.EndOfFile;
1965 return buf;
1966}
1967
1968fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
1969 const buf = try readAllocBytes(allocator, in_stream, size);
1970 return FormValue{ .Block = buf };
1971}
1972
1973// TODO the noasyncs here are workarounds
1974fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
1975 const block_len = try noasync in_stream.readVarInt(usize, builtin.Endian.Little, size);
1976 return parseFormValueBlockLen(allocator, in_stream, block_len);
1977}
1978
1979fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue {
1980 // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here.
1981 // `noasync` should be removed from all the function calls once it is fixed.
1982 return FormValue{
1983 .Const = Constant{
1984 .signed = signed,
1985 .payload = switch (size) {
1986 1 => try noasync in_stream.readIntLittle(u8),
1987 2 => try noasync in_stream.readIntLittle(u16),
1988 4 => try noasync in_stream.readIntLittle(u32),
1989 8 => try noasync in_stream.readIntLittle(u64),
1990 -1 => blk: {
1991 if (signed) {
1992 const x = try noasync leb.readILEB128(i64, in_stream);
1993 break :blk @bitCast(u64, x);
1994 } else {
1995 const x = try noasync leb.readULEB128(u64, in_stream);
1996 break :blk x;
1997 }
1998 },
1999 else => @compileError("Invalid size"),
2000 },
2001 },
2002 };
2003}
2004
2005// TODO the noasyncs here are workarounds
2006fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
2007 return if (is_64) try noasync in_stream.readIntLittle(u64) else @as(u64, try noasync in_stream.readIntLittle(u32));
2008}
2009
2010// TODO the noasyncs here are workarounds
2011fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
2012 if (@sizeOf(usize) == 4) {
2013 // TODO this cast should not be needed
2014 return @as(u64, try noasync in_stream.readIntLittle(u32));
2015 } else if (@sizeOf(usize) == 8) {
2016 return noasync in_stream.readIntLittle(u64);
2017 } else {
2018 unreachable;
2019 }
2020}
2021
2022// TODO the noasyncs here are workarounds
2023fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue {
2024 return FormValue{
2025 .Ref = switch (size) {
2026 1 => try noasync in_stream.readIntLittle(u8),
2027 2 => try noasync in_stream.readIntLittle(u16),
2028 4 => try noasync in_stream.readIntLittle(u32),
2029 8 => try noasync in_stream.readIntLittle(u64),
2030 -1 => try noasync leb.readULEB128(u64, in_stream),
2031 else => unreachable,
2032 },
2033 };
2034}
2035
2036// TODO the noasyncs here are workarounds
2037fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
2038 return switch (form_id) {
2039 DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
2040 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
2041 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
2042 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
2043 DW.FORM_block => x: {
2044 const block_len = try noasync leb.readULEB128(usize, in_stream);
2045 return parseFormValueBlockLen(allocator, in_stream, block_len);
2046 },
2047 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
2048 DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
2049 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
2050 DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
2051 DW.FORM_udata, DW.FORM_sdata => {
2052 const signed = form_id == DW.FORM_sdata;
2053 return parseFormValueConstant(allocator, in_stream, signed, -1);
2054 },
2055 DW.FORM_exprloc => {
2056 const size = try noasync leb.readULEB128(usize, in_stream);
2057 const buf = try readAllocBytes(allocator, in_stream, size);
2058 return FormValue{ .ExprLoc = buf };
2059 },
2060 DW.FORM_flag => FormValue{ .Flag = (try noasync in_stream.readByte()) != 0 },
2061 DW.FORM_flag_present => FormValue{ .Flag = true },
2062 DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
2063
2064 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, 1),
2065 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, 2),
2066 DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, 4),
2067 DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, 8),
2068 DW.FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1),
2069
2070 DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
2071 DW.FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readIntLittle(u64) },
2072
2073 DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
2074 DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
2075 DW.FORM_indirect => {
2076 const child_form_id = try noasync leb.readULEB128(u64, in_stream);
2077 const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, is_64));
2078 var frame = try allocator.create(F);
2079 defer allocator.destroy(frame);
2080 return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, is_64);
2081 },
2082 else => error.InvalidDebugInfo,
2083 };
2084}
2085
2086fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
2087 for (abbrev_table.toSliceConst()) |*table_entry| {
2088 if (table_entry.abbrev_code == abbrev_code) return table_entry;
2089 }
2090 return null;
2091}
2092
2093/// TODO resources https://github.com/ziglang/zig/issues/43531219/// TODO resources https://github.com/ziglang/zig/issues/4353
2094fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !LineInfo {1220fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !LineInfo {
2095 const ofile = symbol.ofile orelse return error.MissingDebugInfo;1221 const ofile = symbol.ofile orelse return error.MissingDebugInfo;
...@@ -2175,7 +1301,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !...@@ -2175,7 +1301,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !
2175 var debug_abbrev = opt_debug_abbrev orelse1301 var debug_abbrev = opt_debug_abbrev orelse
2176 return error.MissingDebugInfo;1302 return error.MissingDebugInfo;
21771303
2178 gop.kv.value = DwarfInfo{1304 gop.kv.value = DW.DwarfInfo{
2179 .endian = .Little,1305 .endian = .Little,
2180 .debug_info = exe_mmap[@intCast(usize, debug_info.offset)..@intCast(usize, debug_info.offset + debug_info.size)],1306 .debug_info = exe_mmap[@intCast(usize, debug_info.offset)..@intCast(usize, debug_info.offset + debug_info.size)],
2181 .debug_abbrev = exe_mmap[@intCast(usize, debug_abbrev.offset)..@intCast(usize, debug_abbrev.offset + debug_abbrev.size)],1307 .debug_abbrev = exe_mmap[@intCast(usize, debug_abbrev.offset)..@intCast(usize, debug_abbrev.offset + debug_abbrev.size)],
...@@ -2186,7 +1312,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !...@@ -2186,7 +1312,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !
2186 else1312 else
2187 null,1313 null,
2188 };1314 };
2189 try openDwarfDebugInfo(&gop.kv.value, di.allocator());1315 try DW.openDwarfDebugInfo(&gop.kv.value, di.allocator());
21901316
2191 break :blk &gop.kv.value;1317 break :blk &gop.kv.value;
2192 };1318 };
...@@ -2196,23 +1322,6 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !...@@ -2196,23 +1322,6 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !
2196 return dwarf_info.getLineNumberInfo(compile_unit.*, o_file_address);1322 return dwarf_info.getLineNumberInfo(compile_unit.*, o_file_address);
2197}1323}
21981324
2199const Func = struct {
2200 pc_range: ?PcRange,
2201 name: ?[]u8,
2202};
2203
2204fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
2205 const first_32_bits = try in_stream.readIntLittle(u32);
2206 is_64.* = (first_32_bits == 0xffffffff);
2207 if (is_64.*) {
2208 return in_stream.readIntLittle(u64);
2209 } else {
2210 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
2211 // TODO this cast should not be needed
2212 return @as(u64, first_32_bits);
2213 }
2214}
2215
2216/// TODO multithreaded awareness1325/// TODO multithreaded awareness
2217var debug_info_allocator: ?*mem.Allocator = null;1326var debug_info_allocator: ?*mem.Allocator = null;
2218var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;1327var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;
lib/std/dwarf.zig+889-682
...@@ -1,682 +1,889 @@...@@ -1,682 +1,889 @@
1pub const TAG_padding = 0x00;1const std = @import("std.zig");
2pub const TAG_array_type = 0x01;2const builtin = @import("builtin");
3pub const TAG_class_type = 0x02;3const debug = std.debug;
4pub const TAG_entry_point = 0x03;4const fs = std.fs;
5pub const TAG_enumeration_type = 0x04;5const io = std.io;
6pub const TAG_formal_parameter = 0x05;6const mem = std.mem;
7pub const TAG_imported_declaration = 0x08;7const math = std.math;
8pub const TAG_label = 0x0a;8const leb = @import("debug/leb128.zig");
9pub const TAG_lexical_block = 0x0b;9
10pub const TAG_member = 0x0d;10const ArrayList = std.ArrayList;
11pub const TAG_pointer_type = 0x0f;11
12pub const TAG_reference_type = 0x10;12usingnamespace @import("dwarf_bits.zig");
13pub const TAG_compile_unit = 0x11;13
14pub const TAG_string_type = 0x12;14pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
15pub const TAG_structure_type = 0x13;15pub const DwarfInStream = io.InStream(anyerror);
16pub const TAG_subroutine = 0x14;16
17pub const TAG_subroutine_type = 0x15;17const PcRange = struct {
18pub const TAG_typedef = 0x16;18 start: u64,
19pub const TAG_union_type = 0x17;19 end: u64,
20pub const TAG_unspecified_parameters = 0x18;20};
21pub const TAG_variant = 0x19;21
22pub const TAG_common_block = 0x1a;22const Func = struct {
23pub const TAG_common_inclusion = 0x1b;23 pc_range: ?PcRange,
24pub const TAG_inheritance = 0x1c;24 name: ?[]u8,
25pub const TAG_inlined_subroutine = 0x1d;25};
26pub const TAG_module = 0x1e;26
27pub const TAG_ptr_to_member_type = 0x1f;27const CompileUnit = struct {
28pub const TAG_set_type = 0x20;28 version: u16,
29pub const TAG_subrange_type = 0x21;29 is_64: bool,
30pub const TAG_with_stmt = 0x22;30 die: *Die,
31pub const TAG_access_declaration = 0x23;31 pc_range: ?PcRange,
32pub const TAG_base_type = 0x24;32};
33pub const TAG_catch_block = 0x25;33
34pub const TAG_const_type = 0x26;34const AbbrevTable = ArrayList(AbbrevTableEntry);
35pub const TAG_constant = 0x27;35
36pub const TAG_enumerator = 0x28;36const AbbrevTableHeader = struct {
37pub const TAG_file_type = 0x29;37 // offset from .debug_abbrev
38pub const TAG_friend = 0x2a;38 offset: u64,
39pub const TAG_namelist = 0x2b;39 table: AbbrevTable,
40pub const TAG_namelist_item = 0x2c;40};
41pub const TAG_packed_type = 0x2d;41
42pub const TAG_subprogram = 0x2e;42const AbbrevTableEntry = struct {
43pub const TAG_template_type_param = 0x2f;43 has_children: bool,
44pub const TAG_template_value_param = 0x30;44 abbrev_code: u64,
45pub const TAG_thrown_type = 0x31;45 tag_id: u64,
46pub const TAG_try_block = 0x32;46 attrs: ArrayList(AbbrevAttr),
47pub const TAG_variant_part = 0x33;47};
48pub const TAG_variable = 0x34;48
49pub const TAG_volatile_type = 0x35;49const AbbrevAttr = struct {
5050 attr_id: u64,
51// DWARF 351 form_id: u64,
52pub const TAG_dwarf_procedure = 0x36;52};
53pub const TAG_restrict_type = 0x37;53
54pub const TAG_interface_type = 0x38;54const FormValue = union(enum) {
55pub const TAG_namespace = 0x39;55 Address: u64,
56pub const TAG_imported_module = 0x3a;56 Block: []u8,
57pub const TAG_unspecified_type = 0x3b;57 Const: Constant,
58pub const TAG_partial_unit = 0x3c;58 ExprLoc: []u8,
59pub const TAG_imported_unit = 0x3d;59 Flag: bool,
60pub const TAG_condition = 0x3f;60 SecOffset: u64,
61pub const TAG_shared_type = 0x40;61 Ref: u64,
6262 RefAddr: u64,
63// DWARF 463 String: []u8,
64pub const TAG_type_unit = 0x41;64 StrPtr: u64,
65pub const TAG_rvalue_reference_type = 0x42;65};
66pub const TAG_template_alias = 0x43;66
6767const Constant = struct {
68pub const TAG_lo_user = 0x4080;68 payload: u64,
69pub const TAG_hi_user = 0xffff;69 signed: bool,
7070
71// SGI/MIPS Extensions.71 fn asUnsignedLe(self: *const Constant) !u64 {
72pub const DW_TAG_MIPS_loop = 0x4081;72 if (self.signed) return error.InvalidDebugInfo;
7373 return self.payload;
74// HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz .74 }
75pub const TAG_HP_array_descriptor = 0x4090;75};
76pub const TAG_HP_Bliss_field = 0x4091;76
77pub const TAG_HP_Bliss_field_set = 0x4092;77const Die = struct {
7878 tag_id: u64,
79// GNU extensions.79 has_children: bool,
80pub const TAG_format_label = 0x4101; // For FORTRAN 77 and Fortran 90.80 attrs: ArrayList(Attr),
81pub const TAG_function_template = 0x4102; // For C++.81
82pub const TAG_class_template = 0x4103; //For C++.82 const Attr = struct {
83pub const TAG_GNU_BINCL = 0x4104;83 id: u64,
84pub const TAG_GNU_EINCL = 0x4105;84 value: FormValue,
8585 };
86// Template template parameter.86
87// See http://gcc.gnu.org/wiki/TemplateParmsDwarf .87 fn getAttr(self: *const Die, id: u64) ?*const FormValue {
88pub const TAG_GNU_template_template_param = 0x4106;88 for (self.attrs.toSliceConst()) |*attr| {
8989 if (attr.id == id) return &attr.value;
90// Template parameter pack extension = specified at90 }
91// http://wiki.dwarfstd.org/index.php?title=C%2B%2B0x:_Variadic_templates91 return null;
92// The values of these two TAGS are in the DW_TAG_GNU_* space until the tags92 }
93// are properly part of DWARF 5.93
94pub const TAG_GNU_template_parameter_pack = 0x4107;94 fn getAttrAddr(self: *const Die, id: u64) !u64 {
95pub const TAG_GNU_formal_parameter_pack = 0x4108;95 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
96// The GNU call site extension = specified at96 return switch (form_value.*) {
97// http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open .97 FormValue.Address => |value| value,
98// The values of these two TAGS are in the DW_TAG_GNU_* space until the tags98 else => error.InvalidDebugInfo,
99// are properly part of DWARF 5.99 };
100pub const TAG_GNU_call_site = 0x4109;100 }
101pub const TAG_GNU_call_site_parameter = 0x410a;101
102// Extensions for UPC. See: http://dwarfstd.org/doc/DWARF4.pdf.102 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
103pub const TAG_upc_shared_type = 0x8765;103 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
104pub const TAG_upc_strict_type = 0x8766;104 return switch (form_value.*) {
105pub const TAG_upc_relaxed_type = 0x8767;105 FormValue.Const => |value| value.asUnsignedLe(),
106// PGI (STMicroelectronics; extensions. No documentation available.106 FormValue.SecOffset => |value| value,
107pub const TAG_PGI_kanji_type = 0xA000;107 else => error.InvalidDebugInfo,
108pub const TAG_PGI_interface_block = 0xA020;108 };
109109 }
110pub const FORM_addr = 0x01;110
111pub const FORM_block2 = 0x03;111 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
112pub const FORM_block4 = 0x04;112 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
113pub const FORM_data2 = 0x05;113 return switch (form_value.*) {
114pub const FORM_data4 = 0x06;114 FormValue.Const => |value| value.asUnsignedLe(),
115pub const FORM_data8 = 0x07;115 else => error.InvalidDebugInfo,
116pub const FORM_string = 0x08;116 };
117pub const FORM_block = 0x09;117 }
118pub const FORM_block1 = 0x0a;118
119pub const FORM_data1 = 0x0b;119 fn getAttrRef(self: *const Die, id: u64) !u64 {
120pub const FORM_flag = 0x0c;120 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
121pub const FORM_sdata = 0x0d;121 return switch (form_value.*) {
122pub const FORM_strp = 0x0e;122 FormValue.Ref => |value| value,
123pub const FORM_udata = 0x0f;123 else => error.InvalidDebugInfo,
124pub const FORM_ref_addr = 0x10;124 };
125pub const FORM_ref1 = 0x11;125 }
126pub const FORM_ref2 = 0x12;126
127pub const FORM_ref4 = 0x13;127 fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
128pub const FORM_ref8 = 0x14;128 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
129pub const FORM_ref_udata = 0x15;129 return switch (form_value.*) {
130pub const FORM_indirect = 0x16;130 FormValue.String => |value| value,
131pub const FORM_sec_offset = 0x17;131 FormValue.StrPtr => |offset| di.getString(offset),
132pub const FORM_exprloc = 0x18;132 else => error.InvalidDebugInfo,
133pub const FORM_flag_present = 0x19;133 };
134pub const FORM_ref_sig8 = 0x20;134 }
135135};
136// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.136
137pub const FORM_GNU_addr_index = 0x1f01;137const FileEntry = struct {
138pub const FORM_GNU_str_index = 0x1f02;138 file_name: []const u8,
139139 dir_index: usize,
140// Extensions for DWZ multifile.140 mtime: usize,
141// See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open .141 len_bytes: usize,
142pub const FORM_GNU_ref_alt = 0x1f20;142};
143pub const FORM_GNU_strp_alt = 0x1f21;143
144144const LineNumberProgram = struct {
145pub const AT_sibling = 0x01;145 address: usize,
146pub const AT_location = 0x02;146 file: usize,
147pub const AT_name = 0x03;147 line: i64,
148pub const AT_ordering = 0x09;148 column: u64,
149pub const AT_subscr_data = 0x0a;149 is_stmt: bool,
150pub const AT_byte_size = 0x0b;150 basic_block: bool,
151pub const AT_bit_offset = 0x0c;151 end_sequence: bool,
152pub const AT_bit_size = 0x0d;152
153pub const AT_element_list = 0x0f;153 default_is_stmt: bool,
154pub const AT_stmt_list = 0x10;154 target_address: usize,
155pub const AT_low_pc = 0x11;155 include_dirs: []const []const u8,
156pub const AT_high_pc = 0x12;156 file_entries: *ArrayList(FileEntry),
157pub const AT_language = 0x13;157
158pub const AT_member = 0x14;158 prev_address: usize,
159pub const AT_discr = 0x15;159 prev_file: usize,
160pub const AT_discr_value = 0x16;160 prev_line: i64,
161pub const AT_visibility = 0x17;161 prev_column: u64,
162pub const AT_import = 0x18;162 prev_is_stmt: bool,
163pub const AT_string_length = 0x19;163 prev_basic_block: bool,
164pub const AT_common_reference = 0x1a;164 prev_end_sequence: bool,
165pub const AT_comp_dir = 0x1b;165
166pub const AT_const_value = 0x1c;166 // Reset the state machine following the DWARF specification
167pub const AT_containing_type = 0x1d;167 pub fn reset(self: *LineNumberProgram) void {
168pub const AT_default_value = 0x1e;168 self.address = 0;
169pub const AT_inline = 0x20;169 self.file = 1;
170pub const AT_is_optional = 0x21;170 self.line = 1;
171pub const AT_lower_bound = 0x22;171 self.column = 0;
172pub const AT_producer = 0x25;172 self.is_stmt = self.default_is_stmt;
173pub const AT_prototyped = 0x27;173 self.basic_block = false;
174pub const AT_return_addr = 0x2a;174 self.end_sequence = false;
175pub const AT_start_scope = 0x2c;175 // Invalidate all the remaining fields
176pub const AT_bit_stride = 0x2e;176 self.prev_address = 0;
177pub const AT_upper_bound = 0x2f;177 self.prev_file = undefined;
178pub const AT_abstract_origin = 0x31;178 self.prev_line = undefined;
179pub const AT_accessibility = 0x32;179 self.prev_column = undefined;
180pub const AT_address_class = 0x33;180 self.prev_is_stmt = undefined;
181pub const AT_artificial = 0x34;181 self.prev_basic_block = undefined;
182pub const AT_base_types = 0x35;182 self.prev_end_sequence = undefined;
183pub const AT_calling_convention = 0x36;183 }
184pub const AT_count = 0x37;184
185pub const AT_data_member_location = 0x38;185 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram {
186pub const AT_decl_column = 0x39;186 return LineNumberProgram{
187pub const AT_decl_file = 0x3a;187 .address = 0,
188pub const AT_decl_line = 0x3b;188 .file = 1,
189pub const AT_declaration = 0x3c;189 .line = 1,
190pub const AT_discr_list = 0x3d;190 .column = 0,
191pub const AT_encoding = 0x3e;191 .is_stmt = is_stmt,
192pub const AT_external = 0x3f;192 .basic_block = false,
193pub const AT_frame_base = 0x40;193 .end_sequence = false,
194pub const AT_friend = 0x41;194 .include_dirs = include_dirs,
195pub const AT_identifier_case = 0x42;195 .file_entries = file_entries,
196pub const AT_macro_info = 0x43;196 .default_is_stmt = is_stmt,
197pub const AT_namelist_items = 0x44;197 .target_address = target_address,
198pub const AT_priority = 0x45;198 .prev_address = 0,
199pub const AT_segment = 0x46;199 .prev_file = undefined,
200pub const AT_specification = 0x47;200 .prev_line = undefined,
201pub const AT_static_link = 0x48;201 .prev_column = undefined,
202pub const AT_type = 0x49;202 .prev_is_stmt = undefined,
203pub const AT_use_location = 0x4a;203 .prev_basic_block = undefined,
204pub const AT_variable_parameter = 0x4b;204 .prev_end_sequence = undefined,
205pub const AT_virtuality = 0x4c;205 };
206pub const AT_vtable_elem_location = 0x4d;206 }
207207
208// DWARF 3 values.208 pub fn checkLineMatch(self: *LineNumberProgram) !?debug.LineInfo {
209pub const AT_allocated = 0x4e;209 if (self.target_address >= self.prev_address and self.target_address < self.address) {
210pub const AT_associated = 0x4f;210 const file_entry = if (self.prev_file == 0) {
211pub const AT_data_location = 0x50;211 return error.MissingDebugInfo;
212pub const AT_byte_stride = 0x51;212 } else if (self.prev_file - 1 >= self.file_entries.len) {
213pub const AT_entry_pc = 0x52;213 return error.InvalidDebugInfo;
214pub const AT_use_UTF8 = 0x53;214 } else
215pub const AT_extension = 0x54;215 &self.file_entries.items[self.prev_file - 1];
216pub const AT_ranges = 0x55;216
217pub const AT_trampoline = 0x56;217 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
218pub const AT_call_column = 0x57;218 return error.InvalidDebugInfo;
219pub const AT_call_file = 0x58;219 } else
220pub const AT_call_line = 0x59;220 self.include_dirs[file_entry.dir_index];
221pub const AT_description = 0x5a;221 const file_name = try fs.path.join(self.file_entries.allocator, &[_][]const u8{ dir_name, file_entry.file_name });
222pub const AT_binary_scale = 0x5b;222 errdefer self.file_entries.allocator.free(file_name);
223pub const AT_decimal_scale = 0x5c;223 return debug.LineInfo{
224pub const AT_small = 0x5d;224 .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,
225pub const AT_decimal_sign = 0x5e;225 .column = self.prev_column,
226pub const AT_digit_count = 0x5f;226 .file_name = file_name,
227pub const AT_picture_string = 0x60;227 .allocator = self.file_entries.allocator,
228pub const AT_mutable = 0x61;228 };
229pub const AT_threads_scaled = 0x62;229 }
230pub const AT_explicit = 0x63;230
231pub const AT_object_pointer = 0x64;231 self.prev_address = self.address;
232pub const AT_endianity = 0x65;232 self.prev_file = self.file;
233pub const AT_elemental = 0x66;233 self.prev_line = self.line;
234pub const AT_pure = 0x67;234 self.prev_column = self.column;
235pub const AT_recursive = 0x68;235 self.prev_is_stmt = self.is_stmt;
236236 self.prev_basic_block = self.basic_block;
237// DWARF 4.237 self.prev_end_sequence = self.end_sequence;
238pub const AT_signature = 0x69;238 return null;
239pub const AT_main_subprogram = 0x6a;239 }
240pub const AT_data_bit_offset = 0x6b;240};
241pub const AT_const_expr = 0x6c;241
242pub const AT_enum_class = 0x6d;242fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
243pub const AT_linkage_name = 0x6e;243 const first_32_bits = try in_stream.readIntLittle(u32);
244244 is_64.* = (first_32_bits == 0xffffffff);
245// DWARF 5245 if (is_64.*) {
246pub const AT_alignment = 0x88;246 return in_stream.readIntLittle(u64);
247247 } else {
248pub const AT_lo_user = 0x2000; // Implementation-defined range start.248 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
249pub const AT_hi_user = 0x3fff; // Implementation-defined range end.249 // TODO this cast should not be needed
250250 return @as(u64, first_32_bits);
251// SGI/MIPS extensions.251 }
252pub const AT_MIPS_fde = 0x2001;252}
253pub const AT_MIPS_loop_begin = 0x2002;253
254pub const AT_MIPS_tail_loop_begin = 0x2003;254// TODO the noasyncs here are workarounds
255pub const AT_MIPS_epilog_begin = 0x2004;255fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
256pub const AT_MIPS_loop_unroll_factor = 0x2005;256 const buf = try allocator.alloc(u8, size);
257pub const AT_MIPS_software_pipeline_depth = 0x2006;257 errdefer allocator.free(buf);
258pub const AT_MIPS_linkage_name = 0x2007;258 if ((try noasync in_stream.read(buf)) < size) return error.EndOfFile;
259pub const AT_MIPS_stride = 0x2008;259 return buf;
260pub const AT_MIPS_abstract_name = 0x2009;260}
261pub const AT_MIPS_clone_origin = 0x200a;261
262pub const AT_MIPS_has_inlines = 0x200b;262fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
263263 const buf = try readAllocBytes(allocator, in_stream, size);
264// HP extensions.264 return FormValue{ .Block = buf };
265pub const AT_HP_block_index = 0x2000;265}
266pub const AT_HP_unmodifiable = 0x2001; // Same as DW_AT_MIPS_fde.266
267pub const AT_HP_prologue = 0x2005; // Same as DW_AT_MIPS_loop_unroll.267// TODO the noasyncs here are workarounds
268pub const AT_HP_epilogue = 0x2008; // Same as DW_AT_MIPS_stride.268fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
269pub const AT_HP_actuals_stmt_list = 0x2010;269 const block_len = try noasync in_stream.readVarInt(usize, builtin.Endian.Little, size);
270pub const AT_HP_proc_per_section = 0x2011;270 return parseFormValueBlockLen(allocator, in_stream, block_len);
271pub const AT_HP_raw_data_ptr = 0x2012;271}
272pub const AT_HP_pass_by_reference = 0x2013;272
273pub const AT_HP_opt_level = 0x2014;273fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue {
274pub const AT_HP_prof_version_id = 0x2015;274 // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here.
275pub const AT_HP_opt_flags = 0x2016;275 // `noasync` should be removed from all the function calls once it is fixed.
276pub const AT_HP_cold_region_low_pc = 0x2017;276 return FormValue{
277pub const AT_HP_cold_region_high_pc = 0x2018;277 .Const = Constant{
278pub const AT_HP_all_variables_modifiable = 0x2019;278 .signed = signed,
279pub const AT_HP_linkage_name = 0x201a;279 .payload = switch (size) {
280pub const AT_HP_prof_flags = 0x201b; // In comp unit of procs_info for -g.280 1 => try noasync in_stream.readIntLittle(u8),
281pub const AT_HP_unit_name = 0x201f;281 2 => try noasync in_stream.readIntLittle(u16),
282pub const AT_HP_unit_size = 0x2020;282 4 => try noasync in_stream.readIntLittle(u32),
283pub const AT_HP_widened_byte_size = 0x2021;283 8 => try noasync in_stream.readIntLittle(u64),
284pub const AT_HP_definition_points = 0x2022;284 -1 => blk: {
285pub const AT_HP_default_location = 0x2023;285 if (signed) {
286pub const AT_HP_is_result_param = 0x2029;286 const x = try noasync leb.readILEB128(i64, in_stream);
287287 break :blk @bitCast(u64, x);
288// GNU extensions.288 } else {
289pub const AT_sf_names = 0x2101;289 const x = try noasync leb.readULEB128(u64, in_stream);
290pub const AT_src_info = 0x2102;290 break :blk x;
291pub const AT_mac_info = 0x2103;291 }
292pub const AT_src_coords = 0x2104;292 },
293pub const AT_body_begin = 0x2105;293 else => @compileError("Invalid size"),
294pub const AT_body_end = 0x2106;294 },
295pub const AT_GNU_vector = 0x2107;295 },
296// Thread-safety annotations.296 };
297// See http://gcc.gnu.org/wiki/ThreadSafetyAnnotation .297}
298pub const AT_GNU_guarded_by = 0x2108;298
299pub const AT_GNU_pt_guarded_by = 0x2109;299// TODO the noasyncs here are workarounds
300pub const AT_GNU_guarded = 0x210a;300fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
301pub const AT_GNU_pt_guarded = 0x210b;301 return if (is_64) try noasync in_stream.readIntLittle(u64) else @as(u64, try noasync in_stream.readIntLittle(u32));
302pub const AT_GNU_locks_excluded = 0x210c;302}
303pub const AT_GNU_exclusive_locks_required = 0x210d;303
304pub const AT_GNU_shared_locks_required = 0x210e;304// TODO the noasyncs here are workarounds
305// One-definition rule violation detection.305fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
306// See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo .306 if (@sizeOf(usize) == 4) {
307pub const AT_GNU_odr_signature = 0x210f;307 // TODO this cast should not be needed
308// Template template argument name.308 return @as(u64, try noasync in_stream.readIntLittle(u32));
309// See http://gcc.gnu.org/wiki/TemplateParmsDwarf .309 } else if (@sizeOf(usize) == 8) {
310pub const AT_GNU_template_name = 0x2110;310 return noasync in_stream.readIntLittle(u64);
311// The GNU call site extension.311 } else {
312// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open .312 unreachable;
313pub const AT_GNU_call_site_value = 0x2111;313 }
314pub const AT_GNU_call_site_data_value = 0x2112;314}
315pub const AT_GNU_call_site_target = 0x2113;315
316pub const AT_GNU_call_site_target_clobbered = 0x2114;316// TODO the noasyncs here are workarounds
317pub const AT_GNU_tail_call = 0x2115;317fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue {
318pub const AT_GNU_all_tail_call_sites = 0x2116;318 return FormValue{
319pub const AT_GNU_all_call_sites = 0x2117;319 .Ref = switch (size) {
320pub const AT_GNU_all_source_call_sites = 0x2118;320 1 => try noasync in_stream.readIntLittle(u8),
321// Section offset into .debug_macro section.321 2 => try noasync in_stream.readIntLittle(u16),
322pub const AT_GNU_macros = 0x2119;322 4 => try noasync in_stream.readIntLittle(u32),
323// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.323 8 => try noasync in_stream.readIntLittle(u64),
324pub const AT_GNU_dwo_name = 0x2130;324 -1 => try noasync leb.readULEB128(u64, in_stream),
325pub const AT_GNU_dwo_id = 0x2131;325 else => unreachable,
326pub const AT_GNU_ranges_base = 0x2132;326 },
327pub const AT_GNU_addr_base = 0x2133;327 };
328pub const AT_GNU_pubnames = 0x2134;328}
329pub const AT_GNU_pubtypes = 0x2135;329
330// VMS extensions.330// TODO the noasyncs here are workarounds
331pub const AT_VMS_rtnbeg_pd_address = 0x2201;331fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
332// GNAT extensions.332 return switch (form_id) {
333// GNAT descriptive type.333 FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
334// See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type .334 FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
335pub const AT_use_GNAT_descriptive_type = 0x2301;335 FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
336pub const AT_GNAT_descriptive_type = 0x2302;336 FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
337// UPC extension.337 FORM_block => x: {
338pub const AT_upc_threads_scaled = 0x3210;338 const block_len = try noasync leb.readULEB128(usize, in_stream);
339// PGI (STMicroelectronics) extensions.339 return parseFormValueBlockLen(allocator, in_stream, block_len);
340pub const AT_PGI_lbase = 0x3a00;340 },
341pub const AT_PGI_soffset = 0x3a01;341 FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
342pub const AT_PGI_lstride = 0x3a02;342 FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
343343 FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
344pub const OP_addr = 0x03;344 FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
345pub const OP_deref = 0x06;345 FORM_udata, FORM_sdata => {
346pub const OP_const1u = 0x08;346 const signed = form_id == FORM_sdata;
347pub const OP_const1s = 0x09;347 return parseFormValueConstant(allocator, in_stream, signed, -1);
348pub const OP_const2u = 0x0a;348 },
349pub const OP_const2s = 0x0b;349 FORM_exprloc => {
350pub const OP_const4u = 0x0c;350 const size = try noasync leb.readULEB128(usize, in_stream);
351pub const OP_const4s = 0x0d;351 const buf = try readAllocBytes(allocator, in_stream, size);
352pub const OP_const8u = 0x0e;352 return FormValue{ .ExprLoc = buf };
353pub const OP_const8s = 0x0f;353 },
354pub const OP_constu = 0x10;354 FORM_flag => FormValue{ .Flag = (try noasync in_stream.readByte()) != 0 },
355pub const OP_consts = 0x11;355 FORM_flag_present => FormValue{ .Flag = true },
356pub const OP_dup = 0x12;356 FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
357pub const OP_drop = 0x13;357
358pub const OP_over = 0x14;358 FORM_ref1 => parseFormValueRef(allocator, in_stream, 1),
359pub const OP_pick = 0x15;359 FORM_ref2 => parseFormValueRef(allocator, in_stream, 2),
360pub const OP_swap = 0x16;360 FORM_ref4 => parseFormValueRef(allocator, in_stream, 4),
361pub const OP_rot = 0x17;361 FORM_ref8 => parseFormValueRef(allocator, in_stream, 8),
362pub const OP_xderef = 0x18;362 FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1),
363pub const OP_abs = 0x19;363
364pub const OP_and = 0x1a;364 FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
365pub const OP_div = 0x1b;365 FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readIntLittle(u64) },
366pub const OP_minus = 0x1c;366
367pub const OP_mod = 0x1d;367 FORM_string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) },
368pub const OP_mul = 0x1e;368 FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
369pub const OP_neg = 0x1f;369 FORM_indirect => {
370pub const OP_not = 0x20;370 const child_form_id = try noasync leb.readULEB128(u64, in_stream);
371pub const OP_or = 0x21;371 const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, is_64));
372pub const OP_plus = 0x22;372 var frame = try allocator.create(F);
373pub const OP_plus_uconst = 0x23;373 defer allocator.destroy(frame);
374pub const OP_shl = 0x24;374 return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, is_64);
375pub const OP_shr = 0x25;375 },
376pub const OP_shra = 0x26;376 else => error.InvalidDebugInfo,
377pub const OP_xor = 0x27;377 };
378pub const OP_bra = 0x28;378}
379pub const OP_eq = 0x29;379
380pub const OP_ge = 0x2a;380fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
381pub const OP_gt = 0x2b;381 for (abbrev_table.toSliceConst()) |*table_entry| {
382pub const OP_le = 0x2c;382 if (table_entry.abbrev_code == abbrev_code) return table_entry;
383pub const OP_lt = 0x2d;383 }
384pub const OP_ne = 0x2e;384 return null;
385pub const OP_skip = 0x2f;385}
386pub const OP_lit0 = 0x30;386
387pub const OP_lit1 = 0x31;387pub const DwarfInfo = struct {
388pub const OP_lit2 = 0x32;388 endian: builtin.Endian,
389pub const OP_lit3 = 0x33;389 // No memory is owned by the DwarfInfo
390pub const OP_lit4 = 0x34;390 debug_info: []u8,
391pub const OP_lit5 = 0x35;391 debug_abbrev: []u8,
392pub const OP_lit6 = 0x36;392 debug_str: []u8,
393pub const OP_lit7 = 0x37;393 debug_line: []u8,
394pub const OP_lit8 = 0x38;394 debug_ranges: ?[]u8,
395pub const OP_lit9 = 0x39;395 // Filled later by the initializer
396pub const OP_lit10 = 0x3a;396 abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined,
397pub const OP_lit11 = 0x3b;397 compile_unit_list: ArrayList(CompileUnit) = undefined,
398pub const OP_lit12 = 0x3c;398 func_list: ArrayList(Func) = undefined,
399pub const OP_lit13 = 0x3d;399
400pub const OP_lit14 = 0x3e;400 pub fn allocator(self: DwarfInfo) *mem.Allocator {
401pub const OP_lit15 = 0x3f;401 return self.abbrev_table_list.allocator;
402pub const OP_lit16 = 0x40;402 }
403pub const OP_lit17 = 0x41;403
404pub const OP_lit18 = 0x42;404 fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
405pub const OP_lit19 = 0x43;405 for (di.func_list.toSliceConst()) |*func| {
406pub const OP_lit20 = 0x44;406 if (func.pc_range) |range| {
407pub const OP_lit21 = 0x45;407 if (address >= range.start and address < range.end) {
408pub const OP_lit22 = 0x46;408 return func.name;
409pub const OP_lit23 = 0x47;409 }
410pub const OP_lit24 = 0x48;410 }
411pub const OP_lit25 = 0x49;411 }
412pub const OP_lit26 = 0x4a;412
413pub const OP_lit27 = 0x4b;413 return null;
414pub const OP_lit28 = 0x4c;414 }
415pub const OP_lit29 = 0x4d;415
416pub const OP_lit30 = 0x4e;416 fn scanAllFunctions(di: *DwarfInfo) !void {
417pub const OP_lit31 = 0x4f;417 var s = io.SliceSeekableInStream.init(di.debug_info);
418pub const OP_reg0 = 0x50;418 var this_unit_offset: u64 = 0;
419pub const OP_reg1 = 0x51;419
420pub const OP_reg2 = 0x52;420 while (true) {
421pub const OP_reg3 = 0x53;421 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
422pub const OP_reg4 = 0x54;422 error.EndOfStream => return,
423pub const OP_reg5 = 0x55;423 else => return err,
424pub const OP_reg6 = 0x56;424 };
425pub const OP_reg7 = 0x57;425
426pub const OP_reg8 = 0x58;426 var is_64: bool = undefined;
427pub const OP_reg9 = 0x59;427 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
428pub const OP_reg10 = 0x5a;428 if (unit_length == 0) return;
429pub const OP_reg11 = 0x5b;429 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
430pub const OP_reg12 = 0x5c;430
431pub const OP_reg13 = 0x5d;431 const version = try s.stream.readInt(u16, di.endian);
432pub const OP_reg14 = 0x5e;432 if (version < 2 or version > 5) return error.InvalidDebugInfo;
433pub const OP_reg15 = 0x5f;433
434pub const OP_reg16 = 0x60;434 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
435pub const OP_reg17 = 0x61;435
436pub const OP_reg18 = 0x62;436 const address_size = try s.stream.readByte();
437pub const OP_reg19 = 0x63;437 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
438pub const OP_reg20 = 0x64;438
439pub const OP_reg21 = 0x65;439 const compile_unit_pos = try s.seekable_stream.getPos();
440pub const OP_reg22 = 0x66;440 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
441pub const OP_reg23 = 0x67;441
442pub const OP_reg24 = 0x68;442 try s.seekable_stream.seekTo(compile_unit_pos);
443pub const OP_reg25 = 0x69;443
444pub const OP_reg26 = 0x6a;444 const next_unit_pos = this_unit_offset + next_offset;
445pub const OP_reg27 = 0x6b;445
446pub const OP_reg28 = 0x6c;446 while ((try s.seekable_stream.getPos()) < next_unit_pos) {
447pub const OP_reg29 = 0x6d;447 const die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse continue;
448pub const OP_reg30 = 0x6e;448 const after_die_offset = try s.seekable_stream.getPos();
449pub const OP_reg31 = 0x6f;449
450pub const OP_breg0 = 0x70;450 switch (die_obj.tag_id) {
451pub const OP_breg1 = 0x71;451 TAG_subprogram, TAG_inlined_subroutine, TAG_subroutine, TAG_entry_point => {
452pub const OP_breg2 = 0x72;452 const fn_name = x: {
453pub const OP_breg3 = 0x73;453 var depth: i32 = 3;
454pub const OP_breg4 = 0x74;454 var this_die_obj = die_obj;
455pub const OP_breg5 = 0x75;455 // Prenvent endless loops
456pub const OP_breg6 = 0x76;456 while (depth > 0) : (depth -= 1) {
457pub const OP_breg7 = 0x77;457 if (this_die_obj.getAttr(AT_name)) |_| {
458pub const OP_breg8 = 0x78;458 const name = try this_die_obj.getAttrString(di, AT_name);
459pub const OP_breg9 = 0x79;459 break :x name;
460pub const OP_breg10 = 0x7a;460 } else if (this_die_obj.getAttr(AT_abstract_origin)) |ref| {
461pub const OP_breg11 = 0x7b;461 // Follow the DIE it points to and repeat
462pub const OP_breg12 = 0x7c;462 const ref_offset = try this_die_obj.getAttrRef(AT_abstract_origin);
463pub const OP_breg13 = 0x7d;463 if (ref_offset > next_offset) return error.InvalidDebugInfo;
464pub const OP_breg14 = 0x7e;464 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
465pub const OP_breg15 = 0x7f;465 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
466pub const OP_breg16 = 0x80;466 } else if (this_die_obj.getAttr(AT_specification)) |ref| {
467pub const OP_breg17 = 0x81;467 // Follow the DIE it points to and repeat
468pub const OP_breg18 = 0x82;468 const ref_offset = try this_die_obj.getAttrRef(AT_specification);
469pub const OP_breg19 = 0x83;469 if (ref_offset > next_offset) return error.InvalidDebugInfo;
470pub const OP_breg20 = 0x84;470 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
471pub const OP_breg21 = 0x85;471 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
472pub const OP_breg22 = 0x86;472 } else {
473pub const OP_breg23 = 0x87;473 break :x null;
474pub const OP_breg24 = 0x88;474 }
475pub const OP_breg25 = 0x89;475 }
476pub const OP_breg26 = 0x8a;476
477pub const OP_breg27 = 0x8b;477 break :x null;
478pub const OP_breg28 = 0x8c;478 };
479pub const OP_breg29 = 0x8d;479
480pub const OP_breg30 = 0x8e;480 const pc_range = x: {
481pub const OP_breg31 = 0x8f;481 if (die_obj.getAttrAddr(AT_low_pc)) |low_pc| {
482pub const OP_regx = 0x90;482 if (die_obj.getAttr(AT_high_pc)) |high_pc_value| {
483pub const OP_fbreg = 0x91;483 const pc_end = switch (high_pc_value.*) {
484pub const OP_bregx = 0x92;484 FormValue.Address => |value| value,
485pub const OP_piece = 0x93;485 FormValue.Const => |value| b: {
486pub const OP_deref_size = 0x94;486 const offset = try value.asUnsignedLe();
487pub const OP_xderef_size = 0x95;487 break :b (low_pc + offset);
488pub const OP_nop = 0x96;488 },
489489 else => return error.InvalidDebugInfo,
490// DWARF 3 extensions.490 };
491pub const OP_push_object_address = 0x97;491 break :x PcRange{
492pub const OP_call2 = 0x98;492 .start = low_pc,
493pub const OP_call4 = 0x99;493 .end = pc_end,
494pub const OP_call_ref = 0x9a;494 };
495pub const OP_form_tls_address = 0x9b;495 } else {
496pub const OP_call_frame_cfa = 0x9c;496 break :x null;
497pub const OP_bit_piece = 0x9d;497 }
498498 } else |err| {
499// DWARF 4 extensions.499 if (err != error.MissingDebugInfo) return err;
500pub const OP_implicit_value = 0x9e;500 break :x null;
501pub const OP_stack_value = 0x9f;501 }
502502 };
503pub const OP_lo_user = 0xe0; // Implementation-defined range start.503
504pub const OP_hi_user = 0xff; // Implementation-defined range end.504 try di.func_list.append(Func{
505505 .name = fn_name,
506// GNU extensions.506 .pc_range = pc_range,
507pub const OP_GNU_push_tls_address = 0xe0;507 });
508// The following is for marking variables that are uninitialized.508 },
509pub const OP_GNU_uninit = 0xf0;509 else => {},
510pub const OP_GNU_encoded_addr = 0xf1;510 }
511// The GNU implicit pointer extension.511
512// See http://www.dwarfstd.org/ShowIssue.php?issue=100831.1&type=open .512 try s.seekable_stream.seekTo(after_die_offset);
513pub const OP_GNU_implicit_pointer = 0xf2;513 }
514// The GNU entry value extension.514
515// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open .515 this_unit_offset += next_offset;
516pub const OP_GNU_entry_value = 0xf3;516 }
517// The GNU typed stack extension.517 }
518// See http://www.dwarfstd.org/doc/040408.1.html .518
519pub const OP_GNU_const_type = 0xf4;519 fn scanAllCompileUnits(di: *DwarfInfo) !void {
520pub const OP_GNU_regval_type = 0xf5;520 var s = io.SliceSeekableInStream.init(di.debug_info);
521pub const OP_GNU_deref_type = 0xf6;521 var this_unit_offset: u64 = 0;
522pub const OP_GNU_convert = 0xf7;522
523pub const OP_GNU_reinterpret = 0xf9;523 while (true) {
524// The GNU parameter ref extension.524 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
525pub const OP_GNU_parameter_ref = 0xfa;525 error.EndOfStream => return,
526// Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission.526 else => return err,
527pub const OP_GNU_addr_index = 0xfb;527 };
528pub const OP_GNU_const_index = 0xfc;528
529// HP extensions.529 var is_64: bool = undefined;
530pub const OP_HP_unknown = 0xe0; // Ouch, the same as GNU_push_tls_address.530 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
531pub const OP_HP_is_value = 0xe1;531 if (unit_length == 0) return;
532pub const OP_HP_fltconst4 = 0xe2;532 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
533pub const OP_HP_fltconst8 = 0xe3;533
534pub const OP_HP_mod_range = 0xe4;534 const version = try s.stream.readInt(u16, di.endian);
535pub const OP_HP_unmod_range = 0xe5;535 if (version < 2 or version > 5) return error.InvalidDebugInfo;
536pub const OP_HP_tls = 0xe6;536
537// PGI (STMicroelectronics) extensions.537 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
538pub const OP_PGI_omp_thread_num = 0xf8;538
539539 const address_size = try s.stream.readByte();
540pub const ATE_void = 0x0;540 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
541pub const ATE_address = 0x1;541
542pub const ATE_boolean = 0x2;542 const compile_unit_pos = try s.seekable_stream.getPos();
543pub const ATE_complex_float = 0x3;543 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
544pub const ATE_float = 0x4;544
545pub const ATE_signed = 0x5;545 try s.seekable_stream.seekTo(compile_unit_pos);
546pub const ATE_signed_char = 0x6;546
547pub const ATE_unsigned = 0x7;547 const compile_unit_die = try di.allocator().create(Die);
548pub const ATE_unsigned_char = 0x8;548 compile_unit_die.* = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
549549
550// DWARF 3.550 if (compile_unit_die.tag_id != TAG_compile_unit) return error.InvalidDebugInfo;
551pub const ATE_imaginary_float = 0x9;551
552pub const ATE_packed_decimal = 0xa;552 const pc_range = x: {
553pub const ATE_numeric_string = 0xb;553 if (compile_unit_die.getAttrAddr(AT_low_pc)) |low_pc| {
554pub const ATE_edited = 0xc;554 if (compile_unit_die.getAttr(AT_high_pc)) |high_pc_value| {
555pub const ATE_signed_fixed = 0xd;555 const pc_end = switch (high_pc_value.*) {
556pub const ATE_unsigned_fixed = 0xe;556 FormValue.Address => |value| value,
557pub const ATE_decimal_float = 0xf;557 FormValue.Const => |value| b: {
558558 const offset = try value.asUnsignedLe();
559// DWARF 4.559 break :b (low_pc + offset);
560pub const ATE_UTF = 0x10;560 },
561561 else => return error.InvalidDebugInfo,
562pub const ATE_lo_user = 0x80;562 };
563pub const ATE_hi_user = 0xff;563 break :x PcRange{
564564 .start = low_pc,
565// HP extensions.565 .end = pc_end,
566pub const ATE_HP_float80 = 0x80; // Floating-point (80 bit).566 };
567pub const ATE_HP_complex_float80 = 0x81; // Complex floating-point (80 bit).567 } else {
568pub const ATE_HP_float128 = 0x82; // Floating-point (128 bit).568 break :x null;
569pub const ATE_HP_complex_float128 = 0x83; // Complex fp (128 bit).569 }
570pub const ATE_HP_floathpintel = 0x84; // Floating-point (82 bit IA64).570 } else |err| {
571pub const ATE_HP_imaginary_float80 = 0x85;571 if (err != error.MissingDebugInfo) return err;
572pub const ATE_HP_imaginary_float128 = 0x86;572 break :x null;
573pub const ATE_HP_VAX_float = 0x88; // F or G floating.573 }
574pub const ATE_HP_VAX_float_d = 0x89; // D floating.574 };
575pub const ATE_HP_packed_decimal = 0x8a; // Cobol.575
576pub const ATE_HP_zoned_decimal = 0x8b; // Cobol.576 try di.compile_unit_list.append(CompileUnit{
577pub const ATE_HP_edited = 0x8c; // Cobol.577 .version = version,
578pub const ATE_HP_signed_fixed = 0x8d; // Cobol.578 .is_64 = is_64,
579pub const ATE_HP_unsigned_fixed = 0x8e; // Cobol.579 .pc_range = pc_range,
580pub const ATE_HP_VAX_complex_float = 0x8f; // F or G floating complex.580 .die = compile_unit_die,
581pub const ATE_HP_VAX_complex_float_d = 0x90; // D floating complex.581 });
582582
583pub const CFA_advance_loc = 0x40;583 this_unit_offset += next_offset;
584pub const CFA_offset = 0x80;584 }
585pub const CFA_restore = 0xc0;585 }
586pub const CFA_nop = 0x00;586
587pub const CFA_set_loc = 0x01;587 fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
588pub const CFA_advance_loc1 = 0x02;588 for (di.compile_unit_list.toSlice()) |*compile_unit| {
589pub const CFA_advance_loc2 = 0x03;589 if (compile_unit.pc_range) |range| {
590pub const CFA_advance_loc4 = 0x04;590 if (target_address >= range.start and target_address < range.end) return compile_unit;
591pub const CFA_offset_extended = 0x05;591 }
592pub const CFA_restore_extended = 0x06;592 if (di.debug_ranges) |debug_ranges| {
593pub const CFA_undefined = 0x07;593 if (compile_unit.die.getAttrSecOffset(AT_ranges)) |ranges_offset| {
594pub const CFA_same_value = 0x08;594 var s = io.SliceSeekableInStream.init(debug_ranges);
595pub const CFA_register = 0x09;595
596pub const CFA_remember_state = 0x0a;596 // All the addresses in the list are relative to the value
597pub const CFA_restore_state = 0x0b;597 // specified by DW_AT_low_pc or to some other value encoded
598pub const CFA_def_cfa = 0x0c;598 // in the list itself.
599pub const CFA_def_cfa_register = 0x0d;599 // If no starting value is specified use zero.
600pub const CFA_def_cfa_offset = 0x0e;600 var base_address = compile_unit.die.getAttrAddr(AT_low_pc) catch |err| switch (err) {
601601 error.MissingDebugInfo => 0,
602// DWARF 3.602 else => return err,
603pub const CFA_def_cfa_expression = 0x0f;603 };
604pub const CFA_expression = 0x10;604
605pub const CFA_offset_extended_sf = 0x11;605 try s.seekable_stream.seekTo(ranges_offset);
606pub const CFA_def_cfa_sf = 0x12;606
607pub const CFA_def_cfa_offset_sf = 0x13;607 while (true) {
608pub const CFA_val_offset = 0x14;608 const begin_addr = try s.stream.readIntLittle(usize);
609pub const CFA_val_offset_sf = 0x15;609 const end_addr = try s.stream.readIntLittle(usize);
610pub const CFA_val_expression = 0x16;610 if (begin_addr == 0 and end_addr == 0) {
611611 break;
612pub const CFA_lo_user = 0x1c;612 }
613pub const CFA_hi_user = 0x3f;613 // This entry selects a new value for the base address
614614 if (begin_addr == math.maxInt(usize)) {
615// SGI/MIPS specific.615 base_address = end_addr;
616pub const CFA_MIPS_advance_loc8 = 0x1d;616 continue;
617617 }
618// GNU extensions.618 if (target_address >= base_address + begin_addr and target_address < base_address + end_addr) {
619pub const CFA_GNU_window_save = 0x2d;619 return compile_unit;
620pub const CFA_GNU_args_size = 0x2e;620 }
621pub const CFA_GNU_negative_offset_extended = 0x2f;621 }
622622 } else |err| {
623pub const CHILDREN_no = 0x00;623 if (err != error.MissingDebugInfo) return err;
624pub const CHILDREN_yes = 0x01;624 continue;
625625 }
626pub const LNS_extended_op = 0x00;626 }
627pub const LNS_copy = 0x01;627 }
628pub const LNS_advance_pc = 0x02;628 return error.MissingDebugInfo;
629pub const LNS_advance_line = 0x03;629 }
630pub const LNS_set_file = 0x04;630
631pub const LNS_set_column = 0x05;631 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
632pub const LNS_negate_stmt = 0x06;632 /// seeks in the stream and parses it.
633pub const LNS_set_basic_block = 0x07;633 fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
634pub const LNS_const_add_pc = 0x08;634 for (di.abbrev_table_list.toSlice()) |*header| {
635pub const LNS_fixed_advance_pc = 0x09;635 if (header.offset == abbrev_offset) {
636pub const LNS_set_prologue_end = 0x0a;636 return &header.table;
637pub const LNS_set_epilogue_begin = 0x0b;637 }
638pub const LNS_set_isa = 0x0c;638 }
639639 try di.abbrev_table_list.append(AbbrevTableHeader{
640pub const LNE_end_sequence = 0x01;640 .offset = abbrev_offset,
641pub const LNE_set_address = 0x02;641 .table = try di.parseAbbrevTable(abbrev_offset),
642pub const LNE_define_file = 0x03;642 });
643pub const LNE_set_discriminator = 0x04;643 return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
644pub const LNE_lo_user = 0x80;644 }
645pub const LNE_hi_user = 0xff;645
646646 fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable {
647pub const LANG_C89 = 0x0001;647 var s = io.SliceSeekableInStream.init(di.debug_abbrev);
648pub const LANG_C = 0x0002;648
649pub const LANG_Ada83 = 0x0003;649 try s.seekable_stream.seekTo(offset);
650pub const LANG_C_plus_plus = 0x0004;650 var result = AbbrevTable.init(di.allocator());
651pub const LANG_Cobol74 = 0x0005;651 errdefer result.deinit();
652pub const LANG_Cobol85 = 0x0006;652 while (true) {
653pub const LANG_Fortran77 = 0x0007;653 const abbrev_code = try leb.readULEB128(u64, &s.stream);
654pub const LANG_Fortran90 = 0x0008;654 if (abbrev_code == 0) return result;
655pub const LANG_Pascal83 = 0x0009;655 try result.append(AbbrevTableEntry{
656pub const LANG_Modula2 = 0x000a;656 .abbrev_code = abbrev_code,
657pub const LANG_Java = 0x000b;657 .tag_id = try leb.readULEB128(u64, &s.stream),
658pub const LANG_C99 = 0x000c;658 .has_children = (try s.stream.readByte()) == CHILDREN_yes,
659pub const LANG_Ada95 = 0x000d;659 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
660pub const LANG_Fortran95 = 0x000e;660 });
661pub const LANG_PLI = 0x000f;661 const attrs = &result.items[result.len - 1].attrs;
662pub const LANG_ObjC = 0x0010;662
663pub const LANG_ObjC_plus_plus = 0x0011;663 while (true) {
664pub const LANG_UPC = 0x0012;664 const attr_id = try leb.readULEB128(u64, &s.stream);
665pub const LANG_D = 0x0013;665 const form_id = try leb.readULEB128(u64, &s.stream);
666pub const LANG_Python = 0x0014;666 if (attr_id == 0 and form_id == 0) break;
667pub const LANG_Go = 0x0016;667 try attrs.append(AbbrevAttr{
668pub const LANG_C_plus_plus_11 = 0x001a;668 .attr_id = attr_id,
669pub const LANG_Rust = 0x001c;669 .form_id = form_id,
670pub const LANG_C11 = 0x001d;670 });
671pub const LANG_C_plus_plus_14 = 0x0021;671 }
672pub const LANG_Fortran03 = 0x0022;672 }
673pub const LANG_Fortran08 = 0x0023;673 }
674pub const LANG_lo_user = 0x8000;674
675pub const LANG_hi_user = 0xffff;675 fn parseDie(di: *DwarfInfo, in_stream: var, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
676pub const LANG_Mips_Assembler = 0x8001;676 const abbrev_code = try leb.readULEB128(u64, in_stream);
677pub const LANG_Upc = 0x8765;677 if (abbrev_code == 0) return null;
678pub const LANG_HP_Bliss = 0x8003;678 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
679pub const LANG_HP_Basic91 = 0x8004;679
680pub const LANG_HP_Pascal91 = 0x8005;680 var result = Die{
681pub const LANG_HP_IMacro = 0x8006;681 .tag_id = table_entry.tag_id,
682pub const LANG_HP_Assembler = 0x8007;682 .has_children = table_entry.has_children,
683 .attrs = ArrayList(Die.Attr).init(di.allocator()),
684 };
685 try result.attrs.resize(table_entry.attrs.len);
686 for (table_entry.attrs.toSliceConst()) |attr, i| {
687 result.attrs.items[i] = Die.Attr{
688 .id = attr.attr_id,
689 .value = try parseFormValue(di.allocator(), in_stream, attr.form_id, is_64),
690 };
691 }
692 return result;
693 }
694
695 fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !debug.LineInfo {
696 var s = io.SliceSeekableInStream.init(di.debug_line);
697
698 const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT_comp_dir);
699 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT_stmt_list);
700
701 try s.seekable_stream.seekTo(line_info_offset);
702
703 var is_64: bool = undefined;
704 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
705 if (unit_length == 0) {
706 return error.MissingDebugInfo;
707 }
708 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
709
710 const version = try s.stream.readInt(u16, di.endian);
711 // TODO support 3 and 5
712 if (version != 2 and version != 4) return error.InvalidDebugInfo;
713
714 const prologue_length = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
715 const prog_start_offset = (try s.seekable_stream.getPos()) + prologue_length;
716
717 const minimum_instruction_length = try s.stream.readByte();
718 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
719
720 if (version >= 4) {
721 // maximum_operations_per_instruction
722 _ = try s.stream.readByte();
723 }
724
725 const default_is_stmt = (try s.stream.readByte()) != 0;
726 const line_base = try s.stream.readByteSigned();
727
728 const line_range = try s.stream.readByte();
729 if (line_range == 0) return error.InvalidDebugInfo;
730
731 const opcode_base = try s.stream.readByte();
732
733 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
734 defer di.allocator().free(standard_opcode_lengths);
735
736 {
737 var i: usize = 0;
738 while (i < opcode_base - 1) : (i += 1) {
739 standard_opcode_lengths[i] = try s.stream.readByte();
740 }
741 }
742
743 var include_directories = ArrayList([]u8).init(di.allocator());
744 try include_directories.append(compile_unit_cwd);
745 while (true) {
746 const dir = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
747 if (dir.len == 0) break;
748 try include_directories.append(dir);
749 }
750
751 var file_entries = ArrayList(FileEntry).init(di.allocator());
752 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
753
754 while (true) {
755 const file_name = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
756 if (file_name.len == 0) break;
757 const dir_index = try leb.readULEB128(usize, &s.stream);
758 const mtime = try leb.readULEB128(usize, &s.stream);
759 const len_bytes = try leb.readULEB128(usize, &s.stream);
760 try file_entries.append(FileEntry{
761 .file_name = file_name,
762 .dir_index = dir_index,
763 .mtime = mtime,
764 .len_bytes = len_bytes,
765 });
766 }
767
768 try s.seekable_stream.seekTo(prog_start_offset);
769
770 const next_unit_pos = line_info_offset + next_offset;
771
772 while ((try s.seekable_stream.getPos()) < next_unit_pos) {
773 const opcode = try s.stream.readByte();
774
775 if (opcode == LNS_extended_op) {
776 const op_size = try leb.readULEB128(u64, &s.stream);
777 if (op_size < 1) return error.InvalidDebugInfo;
778 var sub_op = try s.stream.readByte();
779 switch (sub_op) {
780 LNE_end_sequence => {
781 prog.end_sequence = true;
782 if (try prog.checkLineMatch()) |info| return info;
783 prog.reset();
784 },
785 LNE_set_address => {
786 const addr = try s.stream.readInt(usize, di.endian);
787 prog.address = addr;
788 },
789 LNE_define_file => {
790 const file_name = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
791 const dir_index = try leb.readULEB128(usize, &s.stream);
792 const mtime = try leb.readULEB128(usize, &s.stream);
793 const len_bytes = try leb.readULEB128(usize, &s.stream);
794 try file_entries.append(FileEntry{
795 .file_name = file_name,
796 .dir_index = dir_index,
797 .mtime = mtime,
798 .len_bytes = len_bytes,
799 });
800 },
801 else => {
802 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
803 try s.seekable_stream.seekBy(fwd_amt);
804 },
805 }
806 } else if (opcode >= opcode_base) {
807 // special opcodes
808 const adjusted_opcode = opcode - opcode_base;
809 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
810 const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);
811 prog.line += inc_line;
812 prog.address += inc_addr;
813 if (try prog.checkLineMatch()) |info| return info;
814 prog.basic_block = false;
815 } else {
816 switch (opcode) {
817 LNS_copy => {
818 if (try prog.checkLineMatch()) |info| return info;
819 prog.basic_block = false;
820 },
821 LNS_advance_pc => {
822 const arg = try leb.readULEB128(usize, &s.stream);
823 prog.address += arg * minimum_instruction_length;
824 },
825 LNS_advance_line => {
826 const arg = try leb.readILEB128(i64, &s.stream);
827 prog.line += arg;
828 },
829 LNS_set_file => {
830 const arg = try leb.readULEB128(usize, &s.stream);
831 prog.file = arg;
832 },
833 LNS_set_column => {
834 const arg = try leb.readULEB128(u64, &s.stream);
835 prog.column = arg;
836 },
837 LNS_negate_stmt => {
838 prog.is_stmt = !prog.is_stmt;
839 },
840 LNS_set_basic_block => {
841 prog.basic_block = true;
842 },
843 LNS_const_add_pc => {
844 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
845 prog.address += inc_addr;
846 },
847 LNS_fixed_advance_pc => {
848 const arg = try s.stream.readInt(u16, di.endian);
849 prog.address += arg;
850 },
851 LNS_set_prologue_end => {},
852 else => {
853 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
854 const len_bytes = standard_opcode_lengths[opcode - 1];
855 try s.seekable_stream.seekBy(len_bytes);
856 },
857 }
858 }
859 }
860
861 return error.MissingDebugInfo;
862 }
863
864 fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
865 if (offset > di.debug_str.len)
866 return error.InvalidDebugInfo;
867 const casted_offset = math.cast(usize, offset) catch
868 return error.InvalidDebugInfo;
869
870 // Valid strings always have a terminating zero byte
871 if (mem.indexOfScalarPos(u8, di.debug_str, casted_offset, 0)) |last| {
872 return di.debug_str[casted_offset..last];
873 }
874
875 return error.InvalidDebugInfo;
876 }
877};
878
879/// Initialize DWARF info. The caller has the responsibility to initialize most
880/// the DwarfInfo fields before calling. These fields can be left undefined:
881/// * abbrev_table_list
882/// * compile_unit_list
883pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
884 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
885 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
886 di.func_list = ArrayList(Func).init(allocator);
887 try di.scanAllFunctions();
888 try di.scanAllCompileUnits();
889}
lib/std/dwarf_bits.zig created+682
...@@ -0,0 +1,682 @@
1pub const TAG_padding = 0x00;
2pub const TAG_array_type = 0x01;
3pub const TAG_class_type = 0x02;
4pub const TAG_entry_point = 0x03;
5pub const TAG_enumeration_type = 0x04;
6pub const TAG_formal_parameter = 0x05;
7pub const TAG_imported_declaration = 0x08;
8pub const TAG_label = 0x0a;
9pub const TAG_lexical_block = 0x0b;
10pub const TAG_member = 0x0d;
11pub const TAG_pointer_type = 0x0f;
12pub const TAG_reference_type = 0x10;
13pub const TAG_compile_unit = 0x11;
14pub const TAG_string_type = 0x12;
15pub const TAG_structure_type = 0x13;
16pub const TAG_subroutine = 0x14;
17pub const TAG_subroutine_type = 0x15;
18pub const TAG_typedef = 0x16;
19pub const TAG_union_type = 0x17;
20pub const TAG_unspecified_parameters = 0x18;
21pub const TAG_variant = 0x19;
22pub const TAG_common_block = 0x1a;
23pub const TAG_common_inclusion = 0x1b;
24pub const TAG_inheritance = 0x1c;
25pub const TAG_inlined_subroutine = 0x1d;
26pub const TAG_module = 0x1e;
27pub const TAG_ptr_to_member_type = 0x1f;
28pub const TAG_set_type = 0x20;
29pub const TAG_subrange_type = 0x21;
30pub const TAG_with_stmt = 0x22;
31pub const TAG_access_declaration = 0x23;
32pub const TAG_base_type = 0x24;
33pub const TAG_catch_block = 0x25;
34pub const TAG_const_type = 0x26;
35pub const TAG_constant = 0x27;
36pub const TAG_enumerator = 0x28;
37pub const TAG_file_type = 0x29;
38pub const TAG_friend = 0x2a;
39pub const TAG_namelist = 0x2b;
40pub const TAG_namelist_item = 0x2c;
41pub const TAG_packed_type = 0x2d;
42pub const TAG_subprogram = 0x2e;
43pub const TAG_template_type_param = 0x2f;
44pub const TAG_template_value_param = 0x30;
45pub const TAG_thrown_type = 0x31;
46pub const TAG_try_block = 0x32;
47pub const TAG_variant_part = 0x33;
48pub const TAG_variable = 0x34;
49pub const TAG_volatile_type = 0x35;
50
51// DWARF 3
52pub const TAG_dwarf_procedure = 0x36;
53pub const TAG_restrict_type = 0x37;
54pub const TAG_interface_type = 0x38;
55pub const TAG_namespace = 0x39;
56pub const TAG_imported_module = 0x3a;
57pub const TAG_unspecified_type = 0x3b;
58pub const TAG_partial_unit = 0x3c;
59pub const TAG_imported_unit = 0x3d;
60pub const TAG_condition = 0x3f;
61pub const TAG_shared_type = 0x40;
62
63// DWARF 4
64pub const TAG_type_unit = 0x41;
65pub const TAG_rvalue_reference_type = 0x42;
66pub const TAG_template_alias = 0x43;
67
68pub const TAG_lo_user = 0x4080;
69pub const TAG_hi_user = 0xffff;
70
71// SGI/MIPS Extensions.
72pub const DW_TAG_MIPS_loop = 0x4081;
73
74// HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz .
75pub const TAG_HP_array_descriptor = 0x4090;
76pub const TAG_HP_Bliss_field = 0x4091;
77pub const TAG_HP_Bliss_field_set = 0x4092;
78
79// GNU extensions.
80pub const TAG_format_label = 0x4101; // For FORTRAN 77 and Fortran 90.
81pub const TAG_function_template = 0x4102; // For C++.
82pub const TAG_class_template = 0x4103; //For C++.
83pub const TAG_GNU_BINCL = 0x4104;
84pub const TAG_GNU_EINCL = 0x4105;
85
86// Template template parameter.
87// See http://gcc.gnu.org/wiki/TemplateParmsDwarf .
88pub const TAG_GNU_template_template_param = 0x4106;
89
90// Template parameter pack extension = specified at
91// http://wiki.dwarfstd.org/index.php?title=C%2B%2B0x:_Variadic_templates
92// The values of these two TAGS are in the DW_TAG_GNU_* space until the tags
93// are properly part of DWARF 5.
94pub const TAG_GNU_template_parameter_pack = 0x4107;
95pub const TAG_GNU_formal_parameter_pack = 0x4108;
96// The GNU call site extension = specified at
97// http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open .
98// The values of these two TAGS are in the DW_TAG_GNU_* space until the tags
99// are properly part of DWARF 5.
100pub const TAG_GNU_call_site = 0x4109;
101pub const TAG_GNU_call_site_parameter = 0x410a;
102// Extensions for UPC. See: http://dwarfstd.org/doc/DWARF4.pdf.
103pub const TAG_upc_shared_type = 0x8765;
104pub const TAG_upc_strict_type = 0x8766;
105pub const TAG_upc_relaxed_type = 0x8767;
106// PGI (STMicroelectronics; extensions. No documentation available.
107pub const TAG_PGI_kanji_type = 0xA000;
108pub const TAG_PGI_interface_block = 0xA020;
109
110pub const FORM_addr = 0x01;
111pub const FORM_block2 = 0x03;
112pub const FORM_block4 = 0x04;
113pub const FORM_data2 = 0x05;
114pub const FORM_data4 = 0x06;
115pub const FORM_data8 = 0x07;
116pub const FORM_string = 0x08;
117pub const FORM_block = 0x09;
118pub const FORM_block1 = 0x0a;
119pub const FORM_data1 = 0x0b;
120pub const FORM_flag = 0x0c;
121pub const FORM_sdata = 0x0d;
122pub const FORM_strp = 0x0e;
123pub const FORM_udata = 0x0f;
124pub const FORM_ref_addr = 0x10;
125pub const FORM_ref1 = 0x11;
126pub const FORM_ref2 = 0x12;
127pub const FORM_ref4 = 0x13;
128pub const FORM_ref8 = 0x14;
129pub const FORM_ref_udata = 0x15;
130pub const FORM_indirect = 0x16;
131pub const FORM_sec_offset = 0x17;
132pub const FORM_exprloc = 0x18;
133pub const FORM_flag_present = 0x19;
134pub const FORM_ref_sig8 = 0x20;
135
136// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
137pub const FORM_GNU_addr_index = 0x1f01;
138pub const FORM_GNU_str_index = 0x1f02;
139
140// Extensions for DWZ multifile.
141// See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open .
142pub const FORM_GNU_ref_alt = 0x1f20;
143pub const FORM_GNU_strp_alt = 0x1f21;
144
145pub const AT_sibling = 0x01;
146pub const AT_location = 0x02;
147pub const AT_name = 0x03;
148pub const AT_ordering = 0x09;
149pub const AT_subscr_data = 0x0a;
150pub const AT_byte_size = 0x0b;
151pub const AT_bit_offset = 0x0c;
152pub const AT_bit_size = 0x0d;
153pub const AT_element_list = 0x0f;
154pub const AT_stmt_list = 0x10;
155pub const AT_low_pc = 0x11;
156pub const AT_high_pc = 0x12;
157pub const AT_language = 0x13;
158pub const AT_member = 0x14;
159pub const AT_discr = 0x15;
160pub const AT_discr_value = 0x16;
161pub const AT_visibility = 0x17;
162pub const AT_import = 0x18;
163pub const AT_string_length = 0x19;
164pub const AT_common_reference = 0x1a;
165pub const AT_comp_dir = 0x1b;
166pub const AT_const_value = 0x1c;
167pub const AT_containing_type = 0x1d;
168pub const AT_default_value = 0x1e;
169pub const AT_inline = 0x20;
170pub const AT_is_optional = 0x21;
171pub const AT_lower_bound = 0x22;
172pub const AT_producer = 0x25;
173pub const AT_prototyped = 0x27;
174pub const AT_return_addr = 0x2a;
175pub const AT_start_scope = 0x2c;
176pub const AT_bit_stride = 0x2e;
177pub const AT_upper_bound = 0x2f;
178pub const AT_abstract_origin = 0x31;
179pub const AT_accessibility = 0x32;
180pub const AT_address_class = 0x33;
181pub const AT_artificial = 0x34;
182pub const AT_base_types = 0x35;
183pub const AT_calling_convention = 0x36;
184pub const AT_count = 0x37;
185pub const AT_data_member_location = 0x38;
186pub const AT_decl_column = 0x39;
187pub const AT_decl_file = 0x3a;
188pub const AT_decl_line = 0x3b;
189pub const AT_declaration = 0x3c;
190pub const AT_discr_list = 0x3d;
191pub const AT_encoding = 0x3e;
192pub const AT_external = 0x3f;
193pub const AT_frame_base = 0x40;
194pub const AT_friend = 0x41;
195pub const AT_identifier_case = 0x42;
196pub const AT_macro_info = 0x43;
197pub const AT_namelist_items = 0x44;
198pub const AT_priority = 0x45;
199pub const AT_segment = 0x46;
200pub const AT_specification = 0x47;
201pub const AT_static_link = 0x48;
202pub const AT_type = 0x49;
203pub const AT_use_location = 0x4a;
204pub const AT_variable_parameter = 0x4b;
205pub const AT_virtuality = 0x4c;
206pub const AT_vtable_elem_location = 0x4d;
207
208// DWARF 3 values.
209pub const AT_allocated = 0x4e;
210pub const AT_associated = 0x4f;
211pub const AT_data_location = 0x50;
212pub const AT_byte_stride = 0x51;
213pub const AT_entry_pc = 0x52;
214pub const AT_use_UTF8 = 0x53;
215pub const AT_extension = 0x54;
216pub const AT_ranges = 0x55;
217pub const AT_trampoline = 0x56;
218pub const AT_call_column = 0x57;
219pub const AT_call_file = 0x58;
220pub const AT_call_line = 0x59;
221pub const AT_description = 0x5a;
222pub const AT_binary_scale = 0x5b;
223pub const AT_decimal_scale = 0x5c;
224pub const AT_small = 0x5d;
225pub const AT_decimal_sign = 0x5e;
226pub const AT_digit_count = 0x5f;
227pub const AT_picture_string = 0x60;
228pub const AT_mutable = 0x61;
229pub const AT_threads_scaled = 0x62;
230pub const AT_explicit = 0x63;
231pub const AT_object_pointer = 0x64;
232pub const AT_endianity = 0x65;
233pub const AT_elemental = 0x66;
234pub const AT_pure = 0x67;
235pub const AT_recursive = 0x68;
236
237// DWARF 4.
238pub const AT_signature = 0x69;
239pub const AT_main_subprogram = 0x6a;
240pub const AT_data_bit_offset = 0x6b;
241pub const AT_const_expr = 0x6c;
242pub const AT_enum_class = 0x6d;
243pub const AT_linkage_name = 0x6e;
244
245// DWARF 5
246pub const AT_alignment = 0x88;
247
248pub const AT_lo_user = 0x2000; // Implementation-defined range start.
249pub const AT_hi_user = 0x3fff; // Implementation-defined range end.
250
251// SGI/MIPS extensions.
252pub const AT_MIPS_fde = 0x2001;
253pub const AT_MIPS_loop_begin = 0x2002;
254pub const AT_MIPS_tail_loop_begin = 0x2003;
255pub const AT_MIPS_epilog_begin = 0x2004;
256pub const AT_MIPS_loop_unroll_factor = 0x2005;
257pub const AT_MIPS_software_pipeline_depth = 0x2006;
258pub const AT_MIPS_linkage_name = 0x2007;
259pub const AT_MIPS_stride = 0x2008;
260pub const AT_MIPS_abstract_name = 0x2009;
261pub const AT_MIPS_clone_origin = 0x200a;
262pub const AT_MIPS_has_inlines = 0x200b;
263
264// HP extensions.
265pub const AT_HP_block_index = 0x2000;
266pub const AT_HP_unmodifiable = 0x2001; // Same as DW_AT_MIPS_fde.
267pub const AT_HP_prologue = 0x2005; // Same as DW_AT_MIPS_loop_unroll.
268pub const AT_HP_epilogue = 0x2008; // Same as DW_AT_MIPS_stride.
269pub const AT_HP_actuals_stmt_list = 0x2010;
270pub const AT_HP_proc_per_section = 0x2011;
271pub const AT_HP_raw_data_ptr = 0x2012;
272pub const AT_HP_pass_by_reference = 0x2013;
273pub const AT_HP_opt_level = 0x2014;
274pub const AT_HP_prof_version_id = 0x2015;
275pub const AT_HP_opt_flags = 0x2016;
276pub const AT_HP_cold_region_low_pc = 0x2017;
277pub const AT_HP_cold_region_high_pc = 0x2018;
278pub const AT_HP_all_variables_modifiable = 0x2019;
279pub const AT_HP_linkage_name = 0x201a;
280pub const AT_HP_prof_flags = 0x201b; // In comp unit of procs_info for -g.
281pub const AT_HP_unit_name = 0x201f;
282pub const AT_HP_unit_size = 0x2020;
283pub const AT_HP_widened_byte_size = 0x2021;
284pub const AT_HP_definition_points = 0x2022;
285pub const AT_HP_default_location = 0x2023;
286pub const AT_HP_is_result_param = 0x2029;
287
288// GNU extensions.
289pub const AT_sf_names = 0x2101;
290pub const AT_src_info = 0x2102;
291pub const AT_mac_info = 0x2103;
292pub const AT_src_coords = 0x2104;
293pub const AT_body_begin = 0x2105;
294pub const AT_body_end = 0x2106;
295pub const AT_GNU_vector = 0x2107;
296// Thread-safety annotations.
297// See http://gcc.gnu.org/wiki/ThreadSafetyAnnotation .
298pub const AT_GNU_guarded_by = 0x2108;
299pub const AT_GNU_pt_guarded_by = 0x2109;
300pub const AT_GNU_guarded = 0x210a;
301pub const AT_GNU_pt_guarded = 0x210b;
302pub const AT_GNU_locks_excluded = 0x210c;
303pub const AT_GNU_exclusive_locks_required = 0x210d;
304pub const AT_GNU_shared_locks_required = 0x210e;
305// One-definition rule violation detection.
306// See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo .
307pub const AT_GNU_odr_signature = 0x210f;
308// Template template argument name.
309// See http://gcc.gnu.org/wiki/TemplateParmsDwarf .
310pub const AT_GNU_template_name = 0x2110;
311// The GNU call site extension.
312// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open .
313pub const AT_GNU_call_site_value = 0x2111;
314pub const AT_GNU_call_site_data_value = 0x2112;
315pub const AT_GNU_call_site_target = 0x2113;
316pub const AT_GNU_call_site_target_clobbered = 0x2114;
317pub const AT_GNU_tail_call = 0x2115;
318pub const AT_GNU_all_tail_call_sites = 0x2116;
319pub const AT_GNU_all_call_sites = 0x2117;
320pub const AT_GNU_all_source_call_sites = 0x2118;
321// Section offset into .debug_macro section.
322pub const AT_GNU_macros = 0x2119;
323// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
324pub const AT_GNU_dwo_name = 0x2130;
325pub const AT_GNU_dwo_id = 0x2131;
326pub const AT_GNU_ranges_base = 0x2132;
327pub const AT_GNU_addr_base = 0x2133;
328pub const AT_GNU_pubnames = 0x2134;
329pub const AT_GNU_pubtypes = 0x2135;
330// VMS extensions.
331pub const AT_VMS_rtnbeg_pd_address = 0x2201;
332// GNAT extensions.
333// GNAT descriptive type.
334// See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type .
335pub const AT_use_GNAT_descriptive_type = 0x2301;
336pub const AT_GNAT_descriptive_type = 0x2302;
337// UPC extension.
338pub const AT_upc_threads_scaled = 0x3210;
339// PGI (STMicroelectronics) extensions.
340pub const AT_PGI_lbase = 0x3a00;
341pub const AT_PGI_soffset = 0x3a01;
342pub const AT_PGI_lstride = 0x3a02;
343
344pub const OP_addr = 0x03;
345pub const OP_deref = 0x06;
346pub const OP_const1u = 0x08;
347pub const OP_const1s = 0x09;
348pub const OP_const2u = 0x0a;
349pub const OP_const2s = 0x0b;
350pub const OP_const4u = 0x0c;
351pub const OP_const4s = 0x0d;
352pub const OP_const8u = 0x0e;
353pub const OP_const8s = 0x0f;
354pub const OP_constu = 0x10;
355pub const OP_consts = 0x11;
356pub const OP_dup = 0x12;
357pub const OP_drop = 0x13;
358pub const OP_over = 0x14;
359pub const OP_pick = 0x15;
360pub const OP_swap = 0x16;
361pub const OP_rot = 0x17;
362pub const OP_xderef = 0x18;
363pub const OP_abs = 0x19;
364pub const OP_and = 0x1a;
365pub const OP_div = 0x1b;
366pub const OP_minus = 0x1c;
367pub const OP_mod = 0x1d;
368pub const OP_mul = 0x1e;
369pub const OP_neg = 0x1f;
370pub const OP_not = 0x20;
371pub const OP_or = 0x21;
372pub const OP_plus = 0x22;
373pub const OP_plus_uconst = 0x23;
374pub const OP_shl = 0x24;
375pub const OP_shr = 0x25;
376pub const OP_shra = 0x26;
377pub const OP_xor = 0x27;
378pub const OP_bra = 0x28;
379pub const OP_eq = 0x29;
380pub const OP_ge = 0x2a;
381pub const OP_gt = 0x2b;
382pub const OP_le = 0x2c;
383pub const OP_lt = 0x2d;
384pub const OP_ne = 0x2e;
385pub const OP_skip = 0x2f;
386pub const OP_lit0 = 0x30;
387pub const OP_lit1 = 0x31;
388pub const OP_lit2 = 0x32;
389pub const OP_lit3 = 0x33;
390pub const OP_lit4 = 0x34;
391pub const OP_lit5 = 0x35;
392pub const OP_lit6 = 0x36;
393pub const OP_lit7 = 0x37;
394pub const OP_lit8 = 0x38;
395pub const OP_lit9 = 0x39;
396pub const OP_lit10 = 0x3a;
397pub const OP_lit11 = 0x3b;
398pub const OP_lit12 = 0x3c;
399pub const OP_lit13 = 0x3d;
400pub const OP_lit14 = 0x3e;
401pub const OP_lit15 = 0x3f;
402pub const OP_lit16 = 0x40;
403pub const OP_lit17 = 0x41;
404pub const OP_lit18 = 0x42;
405pub const OP_lit19 = 0x43;
406pub const OP_lit20 = 0x44;
407pub const OP_lit21 = 0x45;
408pub const OP_lit22 = 0x46;
409pub const OP_lit23 = 0x47;
410pub const OP_lit24 = 0x48;
411pub const OP_lit25 = 0x49;
412pub const OP_lit26 = 0x4a;
413pub const OP_lit27 = 0x4b;
414pub const OP_lit28 = 0x4c;
415pub const OP_lit29 = 0x4d;
416pub const OP_lit30 = 0x4e;
417pub const OP_lit31 = 0x4f;
418pub const OP_reg0 = 0x50;
419pub const OP_reg1 = 0x51;
420pub const OP_reg2 = 0x52;
421pub const OP_reg3 = 0x53;
422pub const OP_reg4 = 0x54;
423pub const OP_reg5 = 0x55;
424pub const OP_reg6 = 0x56;
425pub const OP_reg7 = 0x57;
426pub const OP_reg8 = 0x58;
427pub const OP_reg9 = 0x59;
428pub const OP_reg10 = 0x5a;
429pub const OP_reg11 = 0x5b;
430pub const OP_reg12 = 0x5c;
431pub const OP_reg13 = 0x5d;
432pub const OP_reg14 = 0x5e;
433pub const OP_reg15 = 0x5f;
434pub const OP_reg16 = 0x60;
435pub const OP_reg17 = 0x61;
436pub const OP_reg18 = 0x62;
437pub const OP_reg19 = 0x63;
438pub const OP_reg20 = 0x64;
439pub const OP_reg21 = 0x65;
440pub const OP_reg22 = 0x66;
441pub const OP_reg23 = 0x67;
442pub const OP_reg24 = 0x68;
443pub const OP_reg25 = 0x69;
444pub const OP_reg26 = 0x6a;
445pub const OP_reg27 = 0x6b;
446pub const OP_reg28 = 0x6c;
447pub const OP_reg29 = 0x6d;
448pub const OP_reg30 = 0x6e;
449pub const OP_reg31 = 0x6f;
450pub const OP_breg0 = 0x70;
451pub const OP_breg1 = 0x71;
452pub const OP_breg2 = 0x72;
453pub const OP_breg3 = 0x73;
454pub const OP_breg4 = 0x74;
455pub const OP_breg5 = 0x75;
456pub const OP_breg6 = 0x76;
457pub const OP_breg7 = 0x77;
458pub const OP_breg8 = 0x78;
459pub const OP_breg9 = 0x79;
460pub const OP_breg10 = 0x7a;
461pub const OP_breg11 = 0x7b;
462pub const OP_breg12 = 0x7c;
463pub const OP_breg13 = 0x7d;
464pub const OP_breg14 = 0x7e;
465pub const OP_breg15 = 0x7f;
466pub const OP_breg16 = 0x80;
467pub const OP_breg17 = 0x81;
468pub const OP_breg18 = 0x82;
469pub const OP_breg19 = 0x83;
470pub const OP_breg20 = 0x84;
471pub const OP_breg21 = 0x85;
472pub const OP_breg22 = 0x86;
473pub const OP_breg23 = 0x87;
474pub const OP_breg24 = 0x88;
475pub const OP_breg25 = 0x89;
476pub const OP_breg26 = 0x8a;
477pub const OP_breg27 = 0x8b;
478pub const OP_breg28 = 0x8c;
479pub const OP_breg29 = 0x8d;
480pub const OP_breg30 = 0x8e;
481pub const OP_breg31 = 0x8f;
482pub const OP_regx = 0x90;
483pub const OP_fbreg = 0x91;
484pub const OP_bregx = 0x92;
485pub const OP_piece = 0x93;
486pub const OP_deref_size = 0x94;
487pub const OP_xderef_size = 0x95;
488pub const OP_nop = 0x96;
489
490// DWARF 3 extensions.
491pub const OP_push_object_address = 0x97;
492pub const OP_call2 = 0x98;
493pub const OP_call4 = 0x99;
494pub const OP_call_ref = 0x9a;
495pub const OP_form_tls_address = 0x9b;
496pub const OP_call_frame_cfa = 0x9c;
497pub const OP_bit_piece = 0x9d;
498
499// DWARF 4 extensions.
500pub const OP_implicit_value = 0x9e;
501pub const OP_stack_value = 0x9f;
502
503pub const OP_lo_user = 0xe0; // Implementation-defined range start.
504pub const OP_hi_user = 0xff; // Implementation-defined range end.
505
506// GNU extensions.
507pub const OP_GNU_push_tls_address = 0xe0;
508// The following is for marking variables that are uninitialized.
509pub const OP_GNU_uninit = 0xf0;
510pub const OP_GNU_encoded_addr = 0xf1;
511// The GNU implicit pointer extension.
512// See http://www.dwarfstd.org/ShowIssue.php?issue=100831.1&type=open .
513pub const OP_GNU_implicit_pointer = 0xf2;
514// The GNU entry value extension.
515// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open .
516pub const OP_GNU_entry_value = 0xf3;
517// The GNU typed stack extension.
518// See http://www.dwarfstd.org/doc/040408.1.html .
519pub const OP_GNU_const_type = 0xf4;
520pub const OP_GNU_regval_type = 0xf5;
521pub const OP_GNU_deref_type = 0xf6;
522pub const OP_GNU_convert = 0xf7;
523pub const OP_GNU_reinterpret = 0xf9;
524// The GNU parameter ref extension.
525pub const OP_GNU_parameter_ref = 0xfa;
526// Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission.
527pub const OP_GNU_addr_index = 0xfb;
528pub const OP_GNU_const_index = 0xfc;
529// HP extensions.
530pub const OP_HP_unknown = 0xe0; // Ouch, the same as GNU_push_tls_address.
531pub const OP_HP_is_value = 0xe1;
532pub const OP_HP_fltconst4 = 0xe2;
533pub const OP_HP_fltconst8 = 0xe3;
534pub const OP_HP_mod_range = 0xe4;
535pub const OP_HP_unmod_range = 0xe5;
536pub const OP_HP_tls = 0xe6;
537// PGI (STMicroelectronics) extensions.
538pub const OP_PGI_omp_thread_num = 0xf8;
539
540pub const ATE_void = 0x0;
541pub const ATE_address = 0x1;
542pub const ATE_boolean = 0x2;
543pub const ATE_complex_float = 0x3;
544pub const ATE_float = 0x4;
545pub const ATE_signed = 0x5;
546pub const ATE_signed_char = 0x6;
547pub const ATE_unsigned = 0x7;
548pub const ATE_unsigned_char = 0x8;
549
550// DWARF 3.
551pub const ATE_imaginary_float = 0x9;
552pub const ATE_packed_decimal = 0xa;
553pub const ATE_numeric_string = 0xb;
554pub const ATE_edited = 0xc;
555pub const ATE_signed_fixed = 0xd;
556pub const ATE_unsigned_fixed = 0xe;
557pub const ATE_decimal_float = 0xf;
558
559// DWARF 4.
560pub const ATE_UTF = 0x10;
561
562pub const ATE_lo_user = 0x80;
563pub const ATE_hi_user = 0xff;
564
565// HP extensions.
566pub const ATE_HP_float80 = 0x80; // Floating-point (80 bit).
567pub const ATE_HP_complex_float80 = 0x81; // Complex floating-point (80 bit).
568pub const ATE_HP_float128 = 0x82; // Floating-point (128 bit).
569pub const ATE_HP_complex_float128 = 0x83; // Complex fp (128 bit).
570pub const ATE_HP_floathpintel = 0x84; // Floating-point (82 bit IA64).
571pub const ATE_HP_imaginary_float80 = 0x85;
572pub const ATE_HP_imaginary_float128 = 0x86;
573pub const ATE_HP_VAX_float = 0x88; // F or G floating.
574pub const ATE_HP_VAX_float_d = 0x89; // D floating.
575pub const ATE_HP_packed_decimal = 0x8a; // Cobol.
576pub const ATE_HP_zoned_decimal = 0x8b; // Cobol.
577pub const ATE_HP_edited = 0x8c; // Cobol.
578pub const ATE_HP_signed_fixed = 0x8d; // Cobol.
579pub const ATE_HP_unsigned_fixed = 0x8e; // Cobol.
580pub const ATE_HP_VAX_complex_float = 0x8f; // F or G floating complex.
581pub const ATE_HP_VAX_complex_float_d = 0x90; // D floating complex.
582
583pub const CFA_advance_loc = 0x40;
584pub const CFA_offset = 0x80;
585pub const CFA_restore = 0xc0;
586pub const CFA_nop = 0x00;
587pub const CFA_set_loc = 0x01;
588pub const CFA_advance_loc1 = 0x02;
589pub const CFA_advance_loc2 = 0x03;
590pub const CFA_advance_loc4 = 0x04;
591pub const CFA_offset_extended = 0x05;
592pub const CFA_restore_extended = 0x06;
593pub const CFA_undefined = 0x07;
594pub const CFA_same_value = 0x08;
595pub const CFA_register = 0x09;
596pub const CFA_remember_state = 0x0a;
597pub const CFA_restore_state = 0x0b;
598pub const CFA_def_cfa = 0x0c;
599pub const CFA_def_cfa_register = 0x0d;
600pub const CFA_def_cfa_offset = 0x0e;
601
602// DWARF 3.
603pub const CFA_def_cfa_expression = 0x0f;
604pub const CFA_expression = 0x10;
605pub const CFA_offset_extended_sf = 0x11;
606pub const CFA_def_cfa_sf = 0x12;
607pub const CFA_def_cfa_offset_sf = 0x13;
608pub const CFA_val_offset = 0x14;
609pub const CFA_val_offset_sf = 0x15;
610pub const CFA_val_expression = 0x16;
611
612pub const CFA_lo_user = 0x1c;
613pub const CFA_hi_user = 0x3f;
614
615// SGI/MIPS specific.
616pub const CFA_MIPS_advance_loc8 = 0x1d;
617
618// GNU extensions.
619pub const CFA_GNU_window_save = 0x2d;
620pub const CFA_GNU_args_size = 0x2e;
621pub const CFA_GNU_negative_offset_extended = 0x2f;
622
623pub const CHILDREN_no = 0x00;
624pub const CHILDREN_yes = 0x01;
625
626pub const LNS_extended_op = 0x00;
627pub const LNS_copy = 0x01;
628pub const LNS_advance_pc = 0x02;
629pub const LNS_advance_line = 0x03;
630pub const LNS_set_file = 0x04;
631pub const LNS_set_column = 0x05;
632pub const LNS_negate_stmt = 0x06;
633pub const LNS_set_basic_block = 0x07;
634pub const LNS_const_add_pc = 0x08;
635pub const LNS_fixed_advance_pc = 0x09;
636pub const LNS_set_prologue_end = 0x0a;
637pub const LNS_set_epilogue_begin = 0x0b;
638pub const LNS_set_isa = 0x0c;
639
640pub const LNE_end_sequence = 0x01;
641pub const LNE_set_address = 0x02;
642pub const LNE_define_file = 0x03;
643pub const LNE_set_discriminator = 0x04;
644pub const LNE_lo_user = 0x80;
645pub const LNE_hi_user = 0xff;
646
647pub const LANG_C89 = 0x0001;
648pub const LANG_C = 0x0002;
649pub const LANG_Ada83 = 0x0003;
650pub const LANG_C_plus_plus = 0x0004;
651pub const LANG_Cobol74 = 0x0005;
652pub const LANG_Cobol85 = 0x0006;
653pub const LANG_Fortran77 = 0x0007;
654pub const LANG_Fortran90 = 0x0008;
655pub const LANG_Pascal83 = 0x0009;
656pub const LANG_Modula2 = 0x000a;
657pub const LANG_Java = 0x000b;
658pub const LANG_C99 = 0x000c;
659pub const LANG_Ada95 = 0x000d;
660pub const LANG_Fortran95 = 0x000e;
661pub const LANG_PLI = 0x000f;
662pub const LANG_ObjC = 0x0010;
663pub const LANG_ObjC_plus_plus = 0x0011;
664pub const LANG_UPC = 0x0012;
665pub const LANG_D = 0x0013;
666pub const LANG_Python = 0x0014;
667pub const LANG_Go = 0x0016;
668pub const LANG_C_plus_plus_11 = 0x001a;
669pub const LANG_Rust = 0x001c;
670pub const LANG_C11 = 0x001d;
671pub const LANG_C_plus_plus_14 = 0x0021;
672pub const LANG_Fortran03 = 0x0022;
673pub const LANG_Fortran08 = 0x0023;
674pub const LANG_lo_user = 0x8000;
675pub const LANG_hi_user = 0xffff;
676pub const LANG_Mips_Assembler = 0x8001;
677pub const LANG_Upc = 0x8765;
678pub const LANG_HP_Bliss = 0x8003;
679pub const LANG_HP_Basic91 = 0x8004;
680pub const LANG_HP_Pascal91 = 0x8005;
681pub const LANG_HP_IMacro = 0x8006;
682pub const LANG_HP_Assembler = 0x8007;