Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize dwarf line numbers decoding #7413

Merged
merged 7 commits into from Feb 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/callstack.cr
Expand Up @@ -223,10 +223,7 @@ struct CallStack
read_dwarf_sections unless @@dwarf_line_numbers
if ln = @@dwarf_line_numbers
if row = ln.find(pc)
path = ln.files[row.file]?
if dirname = ln.directories[row.directory]?
path = "#{dirname}/#{path}"
end
path = "#{row.directory}/#{row.file}"
return {path, row.line, row.column}
end
end
Expand Down Expand Up @@ -279,14 +276,13 @@ struct CallStack
end

strings = mach_o.read_section?("__debug_str") do |sh, io|
Debug::DWARF::Strings.new(io, sh.offset)
Debug::DWARF::Strings.new(io, sh.offset, sh.size)
end

mach_o.read_section?("__debug_info") do |sh, io|
names = [] of {LibC::SizeT, LibC::SizeT, String}

while io.tell - sh.offset < sh.size
offset = io.tell - sh.offset
while (offset = io.pos - sh.offset) < sh.size
info = Debug::DWARF::Info.new(io, offset)

mach_o.read_section?("__debug_abbrev") do |sh, io|
Expand Down Expand Up @@ -381,14 +377,13 @@ struct CallStack
end

strings = elf.read_section?(".debug_str") do |sh, io|
Debug::DWARF::Strings.new(io, sh.offset)
Debug::DWARF::Strings.new(io, sh.offset, sh.size)
end

elf.read_section?(".debug_info") do |sh, io|
names = [] of {LibC::SizeT, LibC::SizeT, String}

while io.tell - sh.offset < sh.size
offset = io.tell - sh.offset
while (offset = io.pos - sh.offset) < sh.size
info = Debug::DWARF::Info.new(io, offset)

elf.read_section?(".debug_abbrev") do |sh, io|
Expand Down
2 changes: 1 addition & 1 deletion src/debug/dwarf/info.cr
Expand Up @@ -118,7 +118,7 @@ module Debug
when FORM::RefSig8
@io.read_bytes(UInt64)
when FORM::String
@io.gets('\0').to_s.chomp('\0')
@io.gets('\0', chomp: true).to_s
when FORM::Strp
read_ulong
when FORM::Indirect
Expand Down
45 changes: 12 additions & 33 deletions src/debug/dwarf/line_numbers.cr
Expand Up @@ -115,8 +115,8 @@ module Debug
record Row,
address : UInt64,
op_index : UInt32,
directory : Int32,
file : Int32,
directory : String,
file : String,
line : Int32,
column : Int32,
end_sequence : Bool
Expand Down Expand Up @@ -168,19 +168,11 @@ module Debug
# reduce the memory usage of repeating a String many times.
getter matrix : Array(Array(Row))

# The array of indexed directory paths.
getter directories : Array(String)

# The array of indexed file names.
getter files : Array(String)

@offset : LibC::OffT

def initialize(@io : IO::FileDescriptor, size)
@offset = @io.tell
@matrix = Array(Array(Row)).new
@directories = [] of String
@files = [] of String
decode_sequences(size)
end

Expand Down Expand Up @@ -213,10 +205,13 @@ module Debug

# Decodes the compressed matrix of addresses to line numbers.
private def decode_sequences(size)
while (@io.tell - @offset) < size
sequence = Sequence.new
while true
pos = @io.tell
offset = pos - @offset
break unless offset < size

sequence.offset = @io.tell - @offset
sequence = Sequence.new
sequence.offset = offset
sequence.unit_length = @io.read_bytes(UInt32)
sequence.version = @io.read_bytes(UInt16)
sequence.header_length = @io.read_bytes(UInt32)
Expand Down Expand Up @@ -249,15 +244,15 @@ module Debug

private def read_directory_table(sequence)
loop do
name = @io.gets('\0').to_s.chomp('\0')
name = @io.gets('\0', chomp: true).to_s
break if name.empty?
sequence.include_directories << name
end
end

private def read_filename_table(sequence)
loop do
name = @io.gets('\0').to_s.chomp('\0')
name = @io.gets('\0', chomp: true).to_s
break if name.empty?
dir = DWARF.read_unsigned_leb128(@io)
time = DWARF.read_unsigned_leb128(@io)
Expand Down Expand Up @@ -370,8 +365,8 @@ module Debug
row = Row.new(
registers.address,
registers.op_index,
register_directory(path),
register_filename(file[0]),
path,
file[0],
registers.line.to_i,
registers.column.to_i,
registers.end_sequence
Expand All @@ -388,22 +383,6 @@ module Debug
@current_sequence_matrix = nil
end
end

private def register_filename(name)
if index = @files.index(name)
return index
end
@files << name
@files.size - 1
end

private def register_directory(name)
if index = @directories.index(name)
return index
end
@directories << name
@directories.size - 1
end
end
end
end
17 changes: 15 additions & 2 deletions src/debug/dwarf/strings.cr
@@ -1,12 +1,25 @@
module Debug
module DWARF
struct Strings
def initialize(@io : IO::FileDescriptor, @offset : UInt32 | UInt64)
def initialize(@io : IO::FileDescriptor, @offset : UInt32 | UInt64, size)
# Read a good chunk of bytes to decode strings faster
# (avoid seeking/reading the IO too many times)
@buffer = Bytes.new(Math.max(16384, size))
pos = @io.pos
@io.read_fully(@buffer)
@io.pos = pos
end

def decode(strp)
# See if we can read it from the buffer
if strp < @buffer.size
index = @buffer.index('\0'.ord, offset: strp)
return String.new(@buffer[strp, index - strp]) if index
end

# If not, try directly from the IO
@io.seek(@offset + strp) do
@io.gets('\0').to_s.chomp('\0')
@io.gets('\0', chomp: true).to_s
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion src/debug/elf.cr
Expand Up @@ -201,7 +201,7 @@ module Debug
def sh_name(index)
sh = section_headers[shstrndx]
@io.seek(sh.offset + index) do
@io.gets('\0').to_s.chomp('\0')
@io.gets('\0', chomp: true).to_s
end
end

Expand Down
2 changes: 1 addition & 1 deletion src/debug/mach_o.cr
Expand Up @@ -458,7 +458,7 @@ module Debug

if nlist.strx > 0
@io.seek(symtab.stroff + nlist.strx) do
nlist.name = @io.gets('\0').to_s.chomp('\0')
nlist.name = @io.gets('\0', chomp: true).to_s
end
end

Expand Down