Skip to content

Instantly share code, notes, and snippets.

@NightFeather
Last active December 20, 2022 22:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NightFeather/cb22959977f73b3570f8ac0ceaaa8e40 to your computer and use it in GitHub Desktop.
Save NightFeather/cb22959977f73b3570f8ac0ceaaa8e40 to your computer and use it in GitHub Desktop.
class MMapEntry
attr_reader :addr_range, :permission, :offset, :devnum, :inode, :path
def self.from_procmaps line
addr, perm, offset, devnum, inode, path = line.split
saddr, eaddr = addr.split("-").map { |a| a.to_i 16 }
dev = devnum.split(":").map { |s| s.to_i 16 }
path = path[1..-2].to_sym if path =~ /\[.+\]/
MMapEntry.new saddr..eaddr, perm, offset.to_i(16), dev, inode, path
end
def initialize addr_range, permission, offset, devnum, inode, path
@addr_range = addr_range
@permission = permission
@offset = offset
@devnum = devnum
@inode = inode
@path = path
end
def annonymous?
@path.nil?
end
def special?
@path.is_a? Symbol
end
def readable?
@permission.includes? ?r
end
def writable?
@permission.includes? ?w
end
def executable?
@permission.includes? ?x
end
def private?
@permission.includes? ?p
end
def inspect
"MMapEntry<[0x%x], %s, %d, %s>" % [
@addr_range.begin,
@permission,
@offset,
annonymous? ? 'anon' : @path.to_s
]
end
alias to_s inspect
end
class PageEntry
FIELDS = [
[:pfn, 0, 55],
[:swap_type, 0, 5],
[:swap_offset, 5, 50],
[:soft_dirty, 55, 1],
[:exclusive, 56, 1],
[:write_protected, 57, 1],
[:mapped_or_shared, 61, 1],
[:swapped, 62, 1],
[:present, 63, 1],
]
def self.from_vmap uaddr, entry
PageEntry.new uaddr, entry.unpack("Q")[0]
end
PAGE_SHIFT = 12
def initialize uaddr, data
@uaddr = uaddr
@data = data
end
FIELDS.each do |(m, o, s)|
define_method(m) do
r = (@data >> o) & ((1 << s) - 1)
if s == 1
not r.zero?
else
r
end
end
end
def inspect
m = "PageEntry<#{"0x%x" % @uaddr}, #{pfn}"
if swapped
m += ", in swap, swap_offset: #{swap_offset}, swap_type: #{swap_type},"
else
m += ", in ram, paddr: #{"0x%x" % paddr}"
end
m += ", exclusive" if exclusive
m += ", dirty" if soft_dirty
m += ", mapped/shared" if mapped_or_shared
m + ">"
end
alias to_s inspect
def paddr
pfn << PAGE_SHIFT
end
# /proc/kpagecount
def refcount
end
# /proc/kpageflags
def pagetype
end
end
def parse_mmap pid = "self"
File.read("/proc/#{pid}/maps")
.lines.map(&:chomp).reject(&:empty?)
.map { |l| MMapEntry.from_procmaps l }
end
def parse_page start, stop = nil, pid: "self"
File.open("/proc/#{pid}/pagemap", mode: 'rb') do |vm|
stop = start + 0x1000 if stop.nil?
(start...stop).step(0x1000).map do |addr|
PageEntry.from_vmap addr, vm.pread(8, ((addr/0x1000)*8))
end
end
end
pid = ARGV[0] || "self"
parse_mmap(pid).each do |entry|
if entry.path == :vsyscall
puts "#{entry}, no backing page"
else
page = nil
if entry.path == :stack
page = parse_page(entry.addr_range.end - 0x1000, pid: ARGV[0] || "self")[0]
else
page = parse_page(entry.addr_range.begin, pid: pid)[0]
end
puts "#{entry}, #{entry.addr_range.step(0x1000).count} pages, #{page}"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment