
class Strtab
  def initialize(strtab_file)
    array = []
    File.open(strtab_file).each_byte { |x| array.push(x) }

    @table = []
    @table[0] = ""

    i = 0
    while i < array.size
      if (array[i] != 0)
	str = ""
	index = i
	while array[i] != 0
	  str += array[i].chr
	  i += 1
	end
	@table[index] = str
      end
      i += 1
    end
  end

  def [] (key)
    return @table[key]
  end
end

class Packet
  attr_reader :type, :flags, :cache_size, :cache_name_id,
    :objp, :jiffies, :eip, :interrupt, :pid, :pgrp, :comm_id, :internal_id

  @@last_id = 0 

  def Packet.Create(io)
    return nil if !(bin = io.read(11*4))
    @@last_id += 1
    Packet.new(@@last_id, bin.to_s.unpack ("I11"))
  end

  def initialize(id, xxx)
    @internal_id = id
    @type,@flags,@cache_size,@cache_name_id,
    @objp,@jiffies,@eip,@interrupt,@pid,@pgrp,@comm_id = xxx
  end
end

class LifeManager
  def initialize
    @repositry = Hash.new
  end

  def alloc_pair(pkt)
    if (pkt.type == 0)	# ALLOC
      @repositry[pkt.objp] = pkt
    else		# FREE
      if (p = @repositry[pkt.objp])
	@repositry.delete(pkt.objp)
	return p
      end
    end
    return nil
  end
end

def display_header
  printf("  index   type    pid life           command      name             size function\n")
  printf("--------- ----- ----- ---- --------- ------------ --------------- ----- --------\n")
end

def display_packet(packet, ksyms, strtab, pair)

  life = '  ---------'
  if pair != nil
    life = sprintf("%4d #%08x", packet.jiffies - pair.jiffies, pair.internal_id)
  end

  comm = strtab[packet.comm_id]
  comm = '[Interrupt]' if packet.interrupt == 1

  printf("#%08x %-5s %5d %14s %-12s %-15s %5d %s\n",
  packet.internal_id,
  ((packet.type == 0) ? "Alloc" : "Free"),
  packet.pid,
  life,
  comm,
  strtab[packet.cache_name_id],
  packet.cache_size,
  ksyms.addr2symname(packet.eip))
end

#
# Main
#

require 'ksyms'
require 'getoptlong'

ksyms_file = '/proc/ksyms'
system_map = '/boot/System.map'

opts = GetoptLong.new(
  [ "--ksyms", "-k", GetoptLong::REQUIRED_ARGUMENT],
  [ "--system-map", "-s", GetoptLong::REQUIRED_ARGUMENT]
  )
opts.each do |opt, arg|
  ksyms_file = arg.to_s if opt == "--ksyms"
  system_map = arg.to_s if opt == "--system-map"
end

ksyms = KSyms.new(ksyms_file, system_map)
life_mgr = LifeManager.new
strtab = Strtab.new(ARGV[1].to_s)
logbuf = File.open(ARGV[0].to_s)

# display

display_header()
while (packet = Packet.Create(logbuf))
  pair = life_mgr.alloc_pair(packet)
  display_packet(packet, ksyms, strtab, pair)
end

