| ... | @@ -337,50 +337,74 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres | ... | @@ -337,50 +337,74 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres |
| 337 | | 337 | |
| 338 | switch (subsect_hdr.Kind) { | 338 | switch (subsect_hdr.Kind) { |
| 339 | pdb.DebugSubsectionKind.Lines => { | 339 | pdb.DebugSubsectionKind.Lines => { |
| 340 | var line_index: usize = sect_offset; | 340 | var line_index = sect_offset; |
| 341 | | 341 | |
| 342 | const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]); | 342 | const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]); |
| 343 | if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo; | 343 | if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo; |
| 344 | line_index += @sizeOf(pdb.LineFragmentHeader); | 344 | line_index += @sizeOf(pdb.LineFragmentHeader); |
| 345 | | | |
| 346 | const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]); | | |
| 347 | line_index += @sizeOf(pdb.LineBlockFragmentHeader); | | |
| 348 | | | |
| 349 | const has_column = line_hdr.Flags.LF_HaveColumns; | | |
| 350 | | | |
| 351 | const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset; | 345 | const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset; |
| 352 | const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize; | 346 | const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize; |
| 353 | if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) { | 347 | |
| 354 | var line_i: usize = 0; | 348 | // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records) |
| | 349 | // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in, |
| | 350 | // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection. |
| | 351 | const subsection_end_index = sect_offset + subsect_hdr.Length; |
| | 352 | while (line_index < subsection_end_index) { |
| | 353 | const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]); |
| | 354 | line_index += @sizeOf(pdb.LineBlockFragmentHeader); |
| 355 | const start_line_index = line_index; | 355 | const start_line_index = line_index; |
| 356 | while (line_i < block_hdr.NumLines) : (line_i += 1) { | 356 | |
| 357 | const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]); | 357 | const has_column = line_hdr.Flags.LF_HaveColumns; |
| 358 | line_index += @sizeOf(pdb.LineNumberEntry); | 358 | |
| 359 | const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags); | 359 | if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) { |
| 360 | const vaddr_start = frag_vaddr_start + line_num_entry.Offset; | 360 | // All line entries are stored inside their line block by ascending start address. |
| 361 | const vaddr_end = if (flags.End == 0) frag_vaddr_end else vaddr_start + flags.End; | 361 | // Heuristic: we want to find the last line entry that has a vaddr_start <= relative_address. |
| 362 | if (relative_address >= vaddr_start and relative_address < vaddr_end) { | 362 | // This is done with a simple linear search. |
| | 363 | var line_i: u32 = 0; |
| | 364 | while (line_i < block_hdr.NumLines) : (line_i += 1) { |
| | 365 | const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]); |
| | 366 | line_index += @sizeOf(pdb.LineNumberEntry); |
| | 367 | |
| | 368 | const vaddr_start = frag_vaddr_start + line_num_entry.Offset; |
| | 369 | if (relative_address <= vaddr_start) { |
| | 370 | break; |
| | 371 | } |
| | 372 | } |
| | 373 | |
| | 374 | // line_i == 0 would mean that no matching LineNumberEntry was found. |
| | 375 | if (line_i > 0) { |
| 363 | const subsect_index = checksum_offset + block_hdr.NameIndex; | 376 | const subsect_index = checksum_offset + block_hdr.NameIndex; |
| 364 | const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]); | 377 | const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]); |
| 365 | const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset; | 378 | const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset; |
| 366 | try di.pdb.string_table.seekTo(strtab_offset); | 379 | try di.pdb.string_table.seekTo(strtab_offset); |
| 367 | const source_file_name = try di.pdb.string_table.readNullTermString(allocator); | 380 | const source_file_name = try di.pdb.string_table.readNullTermString(allocator); |
| 368 | const line = flags.Start; | 381 | |
| | 382 | const line_entry_idx = line_i - 1; |
| | 383 | |
| 369 | const column = if (has_column) blk: { | 384 | const column = if (has_column) blk: { |
| 370 | line_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines; | 385 | const start_col_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines; |
| 371 | line_index += @sizeOf(pdb.ColumnNumberEntry) * line_i; | 386 | const col_index = start_col_index + @sizeOf(pdb.ColumnNumberEntry) * line_entry_idx; |
| 372 | const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[line_index]); | 387 | const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[col_index]); |
| 373 | break :blk col_num_entry.StartColumn; | 388 | break :blk col_num_entry.StartColumn; |
| 374 | } else 0; | 389 | } else 0; |
| | 390 | |
| | 391 | const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry); |
| | 392 | const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[found_line_index]); |
| | 393 | const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags); |
| | 394 | |
| 375 | break :subsections LineInfo{ | 395 | break :subsections LineInfo{ |
| 376 | .allocator = allocator, | 396 | .allocator = allocator, |
| 377 | .file_name = source_file_name, | 397 | .file_name = source_file_name, |
| 378 | .line = line, | 398 | .line = flags.Start, |
| 379 | .column = column, | 399 | .column = column, |
| 380 | }; | 400 | }; |
| 381 | } | 401 | } |
| 382 | } | 402 | } |
| 383 | break :subsections null; | 403 | } |
| | 404 | |
| | 405 | // Checking that we are not reading garbage after the (possibly) multiple block fragments. |
| | 406 | if (line_index != subsection_end_index) { |
| | 407 | return error.InvalidDebugInfo; |
| 384 | } | 408 | } |
| 385 | }, | 409 | }, |
| 386 | else => {}, | 410 | else => {}, |