#    This file is part of Metasm, the Ruby assembly manipulation suite
#    Copyright (C) 2006-2009 Yoann GUILLOT
#
#    Licence is LGPL, see LICENCE in the top-level directory


# metasm dasm plugin
# decompose immediate values from C constants, adds a comment with the decomposition

# find immediate exprs in the instruction at addr, yield them
def imm_to_const(addr)
	return if not di = di_at(addr)
	# TODO enter into memrefs ?
	di.instruction.args.grep(Expression).each { |a|
		i = a.reduce
		next if not i.kind_of? Integer
		next if not cstbase = yield(i)
		if c = imm_to_const_decompose(i, cstbase)
			di.add_comment c
		end
	}
end

# find the bitwise decomposition of imm into constants whose name include cstbase
def imm_to_const_decompose(imm, cstbase)
	cstbase = /#{cstbase}/i if not cstbase.kind_of? Regexp
	dict = {}
	c_parser.lexer.definition.keys.grep(cstbase).each { |cst|
		if i = c_parser.macro_numeric(cst)
			dict[cst] = i
		end
	}
	c_parser.toplevel.symbol.each { |k, v|
		dict[k] = v if v.kind_of? Integer and k =~ cstbase
	}
	dict.delete_if { |k, v| imm & v != v }
	if cst = dict.index(imm)
		cst
	else
		# a => 1, b => 2, c => 4, all => 7: discard abc, keep 'all'
		dict.delete_if { |k, v| dict.find { |kk, vv| vv > v and vv & v == v } }
		dict.keys.join(' | ') if not dict.empty?
	end
end

if gui
	gui.keyboard_callback[?K] = lambda { |*a|
		addr = gui.curaddr
		imm_to_const(addr) { |i|
			gui.inputbox("const name for #{Expression[i]}") { |name|
				imm_to_const(addr) { |ii| name if ii == i }
				gui.gui_update
			}
			nil
		}
	}
end
