Last active
December 27, 2018 08:51
-
-
Save nurse/0619b6af90df140508c2 to your computer and use it in GitHub Desktop.
Show source files and line numers of given process's threads
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# | |
# pid2line.rb | |
# | |
# Show source files and line numers of given process's threads | |
# | |
# This script works only on Linux. | |
# https://gist.github.com/nurse/0619b6af90df140508c2 | |
# | |
# Get the current EIP of threads in the given process | |
# see kstkeip of http://man7.org/linux/man-pages/man5/proc.5.html | |
def get_eips(pid) | |
Dir["/proc/#{pid}/task/*/stat"].map do |path| | |
lwpid = path[/task\/(\d+)/, 1].to_i | |
stat = `sudo cat #{path}` | |
name = stat[/\((.*)\)/, 1] | |
ary = $'.split | |
state = ary[0] | |
eip = ary[27].to_i | |
utime = ary[11].to_i | |
[lwpid, eip, name, state, utime] | |
end | |
end | |
# Get [executable or library path, relative_address] | |
def search_maps(lwpid, eip) | |
`sudo cat /proc/#{lwpid}/maps`.each_line do |line| | |
address, perms, offset, dev, inode, pathname = line.split | |
range = Range.new(*address.split('-').map{|x|x.hex}) | |
if range.include?(eip) | |
reladdr = eip - range.first | |
return [pathname, offset, reladdr] | |
end | |
end | |
end | |
# get an address in an executable or a library | |
def get_addr(path, offset, reladdr) | |
abort unless / LOAD +(0x\w+) +(0x\w+)/ =~ `readelf -Wl #{path}` | |
abort unless $1.to_i != offset | |
vaddr = reladdr + Integer($2) | |
puts "Elf vaddr: %x -> %x in %s" % [reladdr, vaddr, path] | |
vaddr | |
end | |
# http://man7.org/linux/man-pages/man1/addr2line.1.html | |
def addr2line(path, addr) | |
system('addr2line', '-fie', path, addr.to_s(16)) | |
end | |
def main | |
unless pid = ARGV.shift | |
puts "#$0: <pid>" | |
end | |
addrs = get_eips(pid) | |
addrs.each do |lwpid, eip, name, state, utime| | |
path, offset, reladdr = search_maps(lwpid, eip) | |
puts "%-15s state:%s utime:%d LWPID:%d EIP:%x -> %x" % [name, state, utime, lwpid, eip, reladdr] | |
addr = get_addr(path, offset, reladdr) | |
addr2line(path, addr) | |
end | |
end | |
main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment