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 {
3838 checksum_offset: ?usize,
3939};
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
4153/// Tries to write to stderr, unbuffered, and ignores any error returned.
4254/// Does not append a newline.
4355var stderr_file: File = undefined;
......@@ -714,7 +726,35 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
714726}
715727
716728pub 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 );
718758}
719759
720760fn printLineInfo(
......@@ -958,36 +998,24 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
958998 return list.toOwnedSlice();
959999}
9601000
961fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section {
1001fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DW.DwarfInfo.Section {
9621002 const elf_header = (try elf_file.findSection(name)) orelse return null;
963 return DwarfInfo.Section{
1003 return DW.DwarfInfo.Section{
9641004 .offset = elf_header.sh_offset,
9651005 .size = elf_header.sh_size,
9661006 };
9671007}
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
9811009/// TODO resources https://github.com/ziglang/zig/issues/4353
9821010pub fn openElfDebugInfo(
9831011 allocator: *mem.Allocator,
9841012 data: []u8,
985) !DwarfInfo {
1013) !DW.DwarfInfo {
9861014 var seekable_stream = io.SliceSeekableInStream.init(data);
9871015 var efile = try elf.Elf.openStream(
9881016 allocator,
989 @ptrCast(*DwarfSeekableStream, &seekable_stream.seekable_stream),
990 @ptrCast(*DwarfInStream, &seekable_stream.stream),
1017 @ptrCast(*DW.DwarfSeekableStream, &seekable_stream.seekable_stream),
1018 @ptrCast(*DW.DwarfInStream, &seekable_stream.stream),
9911019 );
9921020 defer efile.close();
9931021
......@@ -1001,7 +1029,7 @@ pub fn openElfDebugInfo(
10011029 return error.MissingDebugInfo;
10021030 const opt_debug_ranges = try efile.findSection(".debug_ranges");
10031031
1004 var di = DwarfInfo{
1032 var di = DW.DwarfInfo{
10051033 .endian = efile.endian,
10061034 .debug_info = (data[@intCast(usize, debug_info.sh_offset)..@intCast(usize, debug_info.sh_offset + debug_info.sh_size)]),
10071035 .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(
10131041 null,
10141042 };
10151043
1016 try openDwarfDebugInfo(&di, allocator);
1044 try DW.openDwarfDebugInfo(&di, allocator);
10171045 return di;
10181046}
10191047
10201048/// TODO resources https://github.com/ziglang/zig/issues/4353
1021fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo {
1049fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DW.DwarfInfo {
10221050 var exe_file = try fs.openSelfExe();
10231051 errdefer exe_file.close();
10241052
......@@ -1162,532 +1190,6 @@ const MachoSymbol = struct {
11621190 }
11631191};
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
16911193pub const DebugInfo = switch (builtin.os) {
16921194 .macosx, .ios, .watchos, .tvos => struct {
16931195 symbols: []const MachoSymbol,
......@@ -1696,7 +1198,7 @@ pub const DebugInfo = switch (builtin.os) {
16961198
16971199 const OFileTable = std.HashMap(
16981200 *macho.nlist_64,
1699 DwarfInfo,
1201 DW.DwarfInfo,
17001202 std.hash_map.getHashPtrAddrFn(*macho.nlist_64),
17011203 std.hash_map.getTrivialEqlFn(*macho.nlist_64),
17021204 );
......@@ -1711,385 +1213,9 @@ pub const DebugInfo = switch (builtin.os) {
17111213 sect_contribs: []pdb.SectionContribEntry,
17121214 modules: []Module,
17131215 },
1714 else => 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 }
1216 else => DW.DwarfInfo,
18491217};
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
20931219/// TODO resources https://github.com/ziglang/zig/issues/4353
20941220fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !LineInfo {
20951221 const ofile = symbol.ofile orelse return error.MissingDebugInfo;
......@@ -2175,7 +1301,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !
21751301 var debug_abbrev = opt_debug_abbrev orelse
21761302 return error.MissingDebugInfo;
21771303
2178 gop.kv.value = DwarfInfo{
1304 gop.kv.value = DW.DwarfInfo{
21791305 .endian = .Little,
21801306 .debug_info = exe_mmap[@intCast(usize, debug_info.offset)..@intCast(usize, debug_info.offset + debug_info.size)],
21811307 .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) !
21861312 else
21871313 null,
21881314 };
2189 try openDwarfDebugInfo(&gop.kv.value, di.allocator());
1315 try DW.openDwarfDebugInfo(&gop.kv.value, di.allocator());
21901316
21911317 break :blk &gop.kv.value;
21921318 };
......@@ -2196,23 +1322,6 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !
21961322 return dwarf_info.getLineNumberInfo(compile_unit.*, o_file_address);
21971323}
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
22161325/// TODO multithreaded awareness
22171326var debug_info_allocator: ?*mem.Allocator = null;
22181327var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;
lib/std/dwarf.zig+889-682
......@@ -1,682 +1,889 @@
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;
1const std = @import("std.zig");
2const builtin = @import("builtin");
3const debug = std.debug;
4const fs = std.fs;
5const io = std.io;
6const mem = std.mem;
7const math = std.math;
8const leb = @import("debug/leb128.zig");
9
10const ArrayList = std.ArrayList;
11
12usingnamespace @import("dwarf_bits.zig");
13
14pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
15pub const DwarfInStream = io.InStream(anyerror);
16
17const PcRange = struct {
18 start: u64,
19 end: u64,
20};
21
22const Func = struct {
23 pc_range: ?PcRange,
24 name: ?[]u8,
25};
26
27const CompileUnit = struct {
28 version: u16,
29 is_64: bool,
30 die: *Die,
31 pc_range: ?PcRange,
32};
33
34const AbbrevTable = ArrayList(AbbrevTableEntry);
35
36const AbbrevTableHeader = struct {
37 // offset from .debug_abbrev
38 offset: u64,
39 table: AbbrevTable,
40};
41
42const AbbrevTableEntry = struct {
43 has_children: bool,
44 abbrev_code: u64,
45 tag_id: u64,
46 attrs: ArrayList(AbbrevAttr),
47};
48
49const AbbrevAttr = struct {
50 attr_id: u64,
51 form_id: u64,
52};
53
54const FormValue = union(enum) {
55 Address: u64,
56 Block: []u8,
57 Const: Constant,
58 ExprLoc: []u8,
59 Flag: bool,
60 SecOffset: u64,
61 Ref: u64,
62 RefAddr: u64,
63 String: []u8,
64 StrPtr: u64,
65};
66
67const Constant = struct {
68 payload: u64,
69 signed: bool,
70
71 fn asUnsignedLe(self: *const Constant) !u64 {
72 if (self.signed) return error.InvalidDebugInfo;
73 return self.payload;
74 }
75};
76
77const Die = struct {
78 tag_id: u64,
79 has_children: bool,
80 attrs: ArrayList(Attr),
81
82 const Attr = struct {
83 id: u64,
84 value: FormValue,
85 };
86
87 fn getAttr(self: *const Die, id: u64) ?*const FormValue {
88 for (self.attrs.toSliceConst()) |*attr| {
89 if (attr.id == id) return &attr.value;
90 }
91 return null;
92 }
93
94 fn getAttrAddr(self: *const Die, id: u64) !u64 {
95 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
96 return switch (form_value.*) {
97 FormValue.Address => |value| value,
98 else => error.InvalidDebugInfo,
99 };
100 }
101
102 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
103 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
104 return switch (form_value.*) {
105 FormValue.Const => |value| value.asUnsignedLe(),
106 FormValue.SecOffset => |value| value,
107 else => error.InvalidDebugInfo,
108 };
109 }
110
111 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
112 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
113 return switch (form_value.*) {
114 FormValue.Const => |value| value.asUnsignedLe(),
115 else => error.InvalidDebugInfo,
116 };
117 }
118
119 fn getAttrRef(self: *const Die, id: u64) !u64 {
120 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
121 return switch (form_value.*) {
122 FormValue.Ref => |value| value,
123 else => error.InvalidDebugInfo,
124 };
125 }
126
127 fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
128 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
129 return switch (form_value.*) {
130 FormValue.String => |value| value,
131 FormValue.StrPtr => |offset| di.getString(offset),
132 else => error.InvalidDebugInfo,
133 };
134 }
135};
136
137const FileEntry = struct {
138 file_name: []const u8,
139 dir_index: usize,
140 mtime: usize,
141 len_bytes: usize,
142};
143
144const LineNumberProgram = struct {
145 address: usize,
146 file: usize,
147 line: i64,
148 column: u64,
149 is_stmt: bool,
150 basic_block: bool,
151 end_sequence: bool,
152
153 default_is_stmt: bool,
154 target_address: usize,
155 include_dirs: []const []const u8,
156 file_entries: *ArrayList(FileEntry),
157
158 prev_address: usize,
159 prev_file: usize,
160 prev_line: i64,
161 prev_column: u64,
162 prev_is_stmt: bool,
163 prev_basic_block: bool,
164 prev_end_sequence: bool,
165
166 // Reset the state machine following the DWARF specification
167 pub fn reset(self: *LineNumberProgram) void {
168 self.address = 0;
169 self.file = 1;
170 self.line = 1;
171 self.column = 0;
172 self.is_stmt = self.default_is_stmt;
173 self.basic_block = false;
174 self.end_sequence = false;
175 // Invalidate all the remaining fields
176 self.prev_address = 0;
177 self.prev_file = undefined;
178 self.prev_line = undefined;
179 self.prev_column = undefined;
180 self.prev_is_stmt = undefined;
181 self.prev_basic_block = undefined;
182 self.prev_end_sequence = undefined;
183 }
184
185 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram {
186 return LineNumberProgram{
187 .address = 0,
188 .file = 1,
189 .line = 1,
190 .column = 0,
191 .is_stmt = is_stmt,
192 .basic_block = false,
193 .end_sequence = false,
194 .include_dirs = include_dirs,
195 .file_entries = file_entries,
196 .default_is_stmt = is_stmt,
197 .target_address = target_address,
198 .prev_address = 0,
199 .prev_file = undefined,
200 .prev_line = undefined,
201 .prev_column = undefined,
202 .prev_is_stmt = undefined,
203 .prev_basic_block = undefined,
204 .prev_end_sequence = undefined,
205 };
206 }
207
208 pub fn checkLineMatch(self: *LineNumberProgram) !?debug.LineInfo {
209 if (self.target_address >= self.prev_address and self.target_address < self.address) {
210 const file_entry = if (self.prev_file == 0) {
211 return error.MissingDebugInfo;
212 } else if (self.prev_file - 1 >= self.file_entries.len) {
213 return error.InvalidDebugInfo;
214 } else
215 &self.file_entries.items[self.prev_file - 1];
216
217 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
218 return error.InvalidDebugInfo;
219 } else
220 self.include_dirs[file_entry.dir_index];
221 const file_name = try fs.path.join(self.file_entries.allocator, &[_][]const u8{ dir_name, file_entry.file_name });
222 errdefer self.file_entries.allocator.free(file_name);
223 return debug.LineInfo{
224 .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,
225 .column = self.prev_column,
226 .file_name = file_name,
227 .allocator = self.file_entries.allocator,
228 };
229 }
230
231 self.prev_address = self.address;
232 self.prev_file = self.file;
233 self.prev_line = self.line;
234 self.prev_column = self.column;
235 self.prev_is_stmt = self.is_stmt;
236 self.prev_basic_block = self.basic_block;
237 self.prev_end_sequence = self.end_sequence;
238 return null;
239 }
240};
241
242fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
243 const first_32_bits = try in_stream.readIntLittle(u32);
244 is_64.* = (first_32_bits == 0xffffffff);
245 if (is_64.*) {
246 return in_stream.readIntLittle(u64);
247 } else {
248 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
249 // TODO this cast should not be needed
250 return @as(u64, first_32_bits);
251 }
252}
253
254// TODO the noasyncs here are workarounds
255fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
256 const buf = try allocator.alloc(u8, size);
257 errdefer allocator.free(buf);
258 if ((try noasync in_stream.read(buf)) < size) return error.EndOfFile;
259 return buf;
260}
261
262fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
263 const buf = try readAllocBytes(allocator, in_stream, size);
264 return FormValue{ .Block = buf };
265}
266
267// TODO the noasyncs here are workarounds
268fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
269 const block_len = try noasync in_stream.readVarInt(usize, builtin.Endian.Little, size);
270 return parseFormValueBlockLen(allocator, in_stream, block_len);
271}
272
273fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue {
274 // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here.
275 // `noasync` should be removed from all the function calls once it is fixed.
276 return FormValue{
277 .Const = Constant{
278 .signed = signed,
279 .payload = switch (size) {
280 1 => try noasync in_stream.readIntLittle(u8),
281 2 => try noasync in_stream.readIntLittle(u16),
282 4 => try noasync in_stream.readIntLittle(u32),
283 8 => try noasync in_stream.readIntLittle(u64),
284 -1 => blk: {
285 if (signed) {
286 const x = try noasync leb.readILEB128(i64, in_stream);
287 break :blk @bitCast(u64, x);
288 } else {
289 const x = try noasync leb.readULEB128(u64, in_stream);
290 break :blk x;
291 }
292 },
293 else => @compileError("Invalid size"),
294 },
295 },
296 };
297}
298
299// TODO the noasyncs here are workarounds
300fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
301 return if (is_64) try noasync in_stream.readIntLittle(u64) else @as(u64, try noasync in_stream.readIntLittle(u32));
302}
303
304// TODO the noasyncs here are workarounds
305fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
306 if (@sizeOf(usize) == 4) {
307 // TODO this cast should not be needed
308 return @as(u64, try noasync in_stream.readIntLittle(u32));
309 } else if (@sizeOf(usize) == 8) {
310 return noasync in_stream.readIntLittle(u64);
311 } else {
312 unreachable;
313 }
314}
315
316// TODO the noasyncs here are workarounds
317fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue {
318 return FormValue{
319 .Ref = switch (size) {
320 1 => try noasync in_stream.readIntLittle(u8),
321 2 => try noasync in_stream.readIntLittle(u16),
322 4 => try noasync in_stream.readIntLittle(u32),
323 8 => try noasync in_stream.readIntLittle(u64),
324 -1 => try noasync leb.readULEB128(u64, in_stream),
325 else => unreachable,
326 },
327 };
328}
329
330// TODO the noasyncs here are workarounds
331fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
332 return switch (form_id) {
333 FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
334 FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
335 FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
336 FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
337 FORM_block => x: {
338 const block_len = try noasync leb.readULEB128(usize, in_stream);
339 return parseFormValueBlockLen(allocator, in_stream, block_len);
340 },
341 FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
342 FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
343 FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
344 FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
345 FORM_udata, FORM_sdata => {
346 const signed = form_id == FORM_sdata;
347 return parseFormValueConstant(allocator, in_stream, signed, -1);
348 },
349 FORM_exprloc => {
350 const size = try noasync leb.readULEB128(usize, in_stream);
351 const buf = try readAllocBytes(allocator, in_stream, size);
352 return FormValue{ .ExprLoc = buf };
353 },
354 FORM_flag => FormValue{ .Flag = (try noasync in_stream.readByte()) != 0 },
355 FORM_flag_present => FormValue{ .Flag = true },
356 FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
357
358 FORM_ref1 => parseFormValueRef(allocator, in_stream, 1),
359 FORM_ref2 => parseFormValueRef(allocator, in_stream, 2),
360 FORM_ref4 => parseFormValueRef(allocator, in_stream, 4),
361 FORM_ref8 => parseFormValueRef(allocator, in_stream, 8),
362 FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1),
363
364 FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
365 FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readIntLittle(u64) },
366
367 FORM_string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) },
368 FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
369 FORM_indirect => {
370 const child_form_id = try noasync leb.readULEB128(u64, in_stream);
371 const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, is_64));
372 var frame = try allocator.create(F);
373 defer allocator.destroy(frame);
374 return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, is_64);
375 },
376 else => error.InvalidDebugInfo,
377 };
378}
379
380fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
381 for (abbrev_table.toSliceConst()) |*table_entry| {
382 if (table_entry.abbrev_code == abbrev_code) return table_entry;
383 }
384 return null;
385}
386
387pub const DwarfInfo = struct {
388 endian: builtin.Endian,
389 // No memory is owned by the DwarfInfo
390 debug_info: []u8,
391 debug_abbrev: []u8,
392 debug_str: []u8,
393 debug_line: []u8,
394 debug_ranges: ?[]u8,
395 // Filled later by the initializer
396 abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined,
397 compile_unit_list: ArrayList(CompileUnit) = undefined,
398 func_list: ArrayList(Func) = undefined,
399
400 pub fn allocator(self: DwarfInfo) *mem.Allocator {
401 return self.abbrev_table_list.allocator;
402 }
403
404 fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
405 for (di.func_list.toSliceConst()) |*func| {
406 if (func.pc_range) |range| {
407 if (address >= range.start and address < range.end) {
408 return func.name;
409 }
410 }
411 }
412
413 return null;
414 }
415
416 fn scanAllFunctions(di: *DwarfInfo) !void {
417 var s = io.SliceSeekableInStream.init(di.debug_info);
418 var this_unit_offset: u64 = 0;
419
420 while (true) {
421 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
422 error.EndOfStream => return,
423 else => return err,
424 };
425
426 var is_64: bool = undefined;
427 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
428 if (unit_length == 0) return;
429 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
430
431 const version = try s.stream.readInt(u16, di.endian);
432 if (version < 2 or version > 5) return error.InvalidDebugInfo;
433
434 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
435
436 const address_size = try s.stream.readByte();
437 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
438
439 const compile_unit_pos = try s.seekable_stream.getPos();
440 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
441
442 try s.seekable_stream.seekTo(compile_unit_pos);
443
444 const next_unit_pos = this_unit_offset + next_offset;
445
446 while ((try s.seekable_stream.getPos()) < next_unit_pos) {
447 const die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse continue;
448 const after_die_offset = try s.seekable_stream.getPos();
449
450 switch (die_obj.tag_id) {
451 TAG_subprogram, TAG_inlined_subroutine, TAG_subroutine, TAG_entry_point => {
452 const fn_name = x: {
453 var depth: i32 = 3;
454 var this_die_obj = die_obj;
455 // Prenvent endless loops
456 while (depth > 0) : (depth -= 1) {
457 if (this_die_obj.getAttr(AT_name)) |_| {
458 const name = try this_die_obj.getAttrString(di, AT_name);
459 break :x name;
460 } else if (this_die_obj.getAttr(AT_abstract_origin)) |ref| {
461 // Follow the DIE it points to and repeat
462 const ref_offset = try this_die_obj.getAttrRef(AT_abstract_origin);
463 if (ref_offset > next_offset) return error.InvalidDebugInfo;
464 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
465 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
466 } else if (this_die_obj.getAttr(AT_specification)) |ref| {
467 // Follow the DIE it points to and repeat
468 const ref_offset = try this_die_obj.getAttrRef(AT_specification);
469 if (ref_offset > next_offset) return error.InvalidDebugInfo;
470 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
471 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
472 } else {
473 break :x null;
474 }
475 }
476
477 break :x null;
478 };
479
480 const pc_range = x: {
481 if (die_obj.getAttrAddr(AT_low_pc)) |low_pc| {
482 if (die_obj.getAttr(AT_high_pc)) |high_pc_value| {
483 const pc_end = switch (high_pc_value.*) {
484 FormValue.Address => |value| value,
485 FormValue.Const => |value| b: {
486 const offset = try value.asUnsignedLe();
487 break :b (low_pc + offset);
488 },
489 else => return error.InvalidDebugInfo,
490 };
491 break :x PcRange{
492 .start = low_pc,
493 .end = pc_end,
494 };
495 } else {
496 break :x null;
497 }
498 } else |err| {
499 if (err != error.MissingDebugInfo) return err;
500 break :x null;
501 }
502 };
503
504 try di.func_list.append(Func{
505 .name = fn_name,
506 .pc_range = pc_range,
507 });
508 },
509 else => {},
510 }
511
512 try s.seekable_stream.seekTo(after_die_offset);
513 }
514
515 this_unit_offset += next_offset;
516 }
517 }
518
519 fn scanAllCompileUnits(di: *DwarfInfo) !void {
520 var s = io.SliceSeekableInStream.init(di.debug_info);
521 var this_unit_offset: u64 = 0;
522
523 while (true) {
524 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
525 error.EndOfStream => return,
526 else => return err,
527 };
528
529 var is_64: bool = undefined;
530 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
531 if (unit_length == 0) return;
532 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
533
534 const version = try s.stream.readInt(u16, di.endian);
535 if (version < 2 or version > 5) return error.InvalidDebugInfo;
536
537 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
538
539 const address_size = try s.stream.readByte();
540 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
541
542 const compile_unit_pos = try s.seekable_stream.getPos();
543 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
544
545 try s.seekable_stream.seekTo(compile_unit_pos);
546
547 const compile_unit_die = try di.allocator().create(Die);
548 compile_unit_die.* = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
549
550 if (compile_unit_die.tag_id != TAG_compile_unit) return error.InvalidDebugInfo;
551
552 const pc_range = x: {
553 if (compile_unit_die.getAttrAddr(AT_low_pc)) |low_pc| {
554 if (compile_unit_die.getAttr(AT_high_pc)) |high_pc_value| {
555 const pc_end = switch (high_pc_value.*) {
556 FormValue.Address => |value| value,
557 FormValue.Const => |value| b: {
558 const offset = try value.asUnsignedLe();
559 break :b (low_pc + offset);
560 },
561 else => return error.InvalidDebugInfo,
562 };
563 break :x PcRange{
564 .start = low_pc,
565 .end = pc_end,
566 };
567 } else {
568 break :x null;
569 }
570 } else |err| {
571 if (err != error.MissingDebugInfo) return err;
572 break :x null;
573 }
574 };
575
576 try di.compile_unit_list.append(CompileUnit{
577 .version = version,
578 .is_64 = is_64,
579 .pc_range = pc_range,
580 .die = compile_unit_die,
581 });
582
583 this_unit_offset += next_offset;
584 }
585 }
586
587 fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
588 for (di.compile_unit_list.toSlice()) |*compile_unit| {
589 if (compile_unit.pc_range) |range| {
590 if (target_address >= range.start and target_address < range.end) return compile_unit;
591 }
592 if (di.debug_ranges) |debug_ranges| {
593 if (compile_unit.die.getAttrSecOffset(AT_ranges)) |ranges_offset| {
594 var s = io.SliceSeekableInStream.init(debug_ranges);
595
596 // All the addresses in the list are relative to the value
597 // specified by DW_AT_low_pc or to some other value encoded
598 // in the list itself.
599 // If no starting value is specified use zero.
600 var base_address = compile_unit.die.getAttrAddr(AT_low_pc) catch |err| switch (err) {
601 error.MissingDebugInfo => 0,
602 else => return err,
603 };
604
605 try s.seekable_stream.seekTo(ranges_offset);
606
607 while (true) {
608 const begin_addr = try s.stream.readIntLittle(usize);
609 const end_addr = try s.stream.readIntLittle(usize);
610 if (begin_addr == 0 and end_addr == 0) {
611 break;
612 }
613 // This entry selects a new value for the base address
614 if (begin_addr == math.maxInt(usize)) {
615 base_address = end_addr;
616 continue;
617 }
618 if (target_address >= base_address + begin_addr and target_address < base_address + end_addr) {
619 return compile_unit;
620 }
621 }
622 } else |err| {
623 if (err != error.MissingDebugInfo) return err;
624 continue;
625 }
626 }
627 }
628 return error.MissingDebugInfo;
629 }
630
631 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
632 /// seeks in the stream and parses it.
633 fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
634 for (di.abbrev_table_list.toSlice()) |*header| {
635 if (header.offset == abbrev_offset) {
636 return &header.table;
637 }
638 }
639 try di.abbrev_table_list.append(AbbrevTableHeader{
640 .offset = abbrev_offset,
641 .table = try di.parseAbbrevTable(abbrev_offset),
642 });
643 return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
644 }
645
646 fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable {
647 var s = io.SliceSeekableInStream.init(di.debug_abbrev);
648
649 try s.seekable_stream.seekTo(offset);
650 var result = AbbrevTable.init(di.allocator());
651 errdefer result.deinit();
652 while (true) {
653 const abbrev_code = try leb.readULEB128(u64, &s.stream);
654 if (abbrev_code == 0) return result;
655 try result.append(AbbrevTableEntry{
656 .abbrev_code = abbrev_code,
657 .tag_id = try leb.readULEB128(u64, &s.stream),
658 .has_children = (try s.stream.readByte()) == CHILDREN_yes,
659 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
660 });
661 const attrs = &result.items[result.len - 1].attrs;
662
663 while (true) {
664 const attr_id = try leb.readULEB128(u64, &s.stream);
665 const form_id = try leb.readULEB128(u64, &s.stream);
666 if (attr_id == 0 and form_id == 0) break;
667 try attrs.append(AbbrevAttr{
668 .attr_id = attr_id,
669 .form_id = form_id,
670 });
671 }
672 }
673 }
674
675 fn parseDie(di: *DwarfInfo, in_stream: var, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
676 const abbrev_code = try leb.readULEB128(u64, in_stream);
677 if (abbrev_code == 0) return null;
678 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
679
680 var result = Die{
681 .tag_id = table_entry.tag_id,
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;