node/lib/metasm/metasm/cpu/ppc/decompile.rb
# list variable dependency for each block, remove useless writes
# returns { blockaddr => [list of vars that are needed by a following block] }
list variable dependency for each block, remove useless writes
returns { blockaddr => [list of vars that are needed by a following block] }
list variable dependency for each block remove useless writes returns { blockaddr = > [ list of vars that are needed by a following block ] }
def decompile_func_finddeps(dcmp, blocks, func)
		deps_r = {} ; deps_w = {} ; deps_to = {}
		deps_subfunc = {}	
		blocks.each { |b, to|
			deps_r[b] = [] ; deps_w[b] = [] ; deps_to[b] = to
			deps_subfunc[b] = []
			blk = dcmp.dasm.decoded[b].block
			blk.list.each { |di|
				a = di.backtrace_binding.values
				w = []
				di.backtrace_binding.keys.each { |k|
					case k
					when ::Symbol; w |= [k]
					else a |= Expression[k].externals	
					end
				}
				deps_r[b] |= a.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown] - deps_w[b]
				deps_w[b] |= w.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown]
			}
			stackoff = nil
			blk.each_to_normal { |t|
				t = dcmp.backtrace_target(t, blk.list.last.address)
				next if not t = dcmp.c_parser.toplevel.symbol[t]
				t.type = C::Function.new(C::BaseType.new(:int)) if not t.type.kind_of? C::Function	
				stackoff ||= Expression[dcmp.dasm.backtrace(:sp, blk.list.last.address, :snapshot_addr => blocks.first[0]).first, :-, :sp].reduce
			}
			if stackoff	
				deps_r[b] |= deps_subfunc[b] - deps_w[b]
			end
		}
		uninitialized = lambda { |b, r, done|
			from = deps_to.keys.find_all { |f| deps_to[f].include? b } - done
			from.empty? or from.find { |f|
				!deps_w[f].include?(r) and uninitialized[f, r, done + [b]]
			}
		}
		dw = {}
		deps_w.each { |b, deps|
			dw[b] = deps.reject { |dep|
				ret = true
				done = []
				todo = deps_to[b].dup
				while a = todo.pop
					next if done.include? a
					done << a
					if not deps_r[a] or deps_r[a].include? dep
						ret = false
						break
					elsif not deps_w[a].include? dep
						todo.concat deps_to[a]
					end
				end
				ret
			}
		}
		dw
	end
def decompile_func_finddeps ( dcmp , blocks , func ) deps_r = { } ; deps_w = { } ; deps_to = { } deps_subfunc = { } blocks . each { | b , to | deps_r [ b ] = [ ] ; deps_w [ b ] = [ ] ; deps_to [ b ] = to deps_subfunc [ b ] = [ ] blk = dcmp . dasm . decoded [ b ] . block blk . list . each { | di | a = di . backtrace_binding . values w = [ ] di . backtrace_binding . keys . each { | k | case k when :: Symbol ; w |= [ k ] else a |= Expression [ k ] . externals end } deps_r [ b ] |= a . map { | ee | Expression [ ee ] . externals . grep ( :: Symbol ) } . flatten - [ :unknown ] - deps_w [ b ] deps_w [ b ] |= w . map { | ee | Expression [ ee ] . externals . grep ( :: Symbol ) } . flatten - [ :unknown ] } stackoff = nil blk . each_to_normal { | t | t = dcmp . backtrace_target ( t , blk . list . last . address ) next if not t = dcmp . c_parser . toplevel . symbol [ t ] t . type = C :: Function . new ( C :: BaseType . new ( :int ) ) if not t . type . kind_of? C :: Function stackoff ||= Expression [ dcmp . dasm . backtrace ( :sp , blk . list . last . address , :snapshot_addr => blocks . first [ 0 ] ) . first , :- , :sp ] . reduce } if stackoff deps_r [ b ] |= deps_subfunc [ b ] - deps_w [ b ] end } uninitialized = lambda { | b , r , done | from = deps_to . keys . find_all { | f | deps_to [ f ] . include? b } - done from . empty? or from . find { | f | ! deps_w [ f ] . include? ( r ) and uninitialized [ f , r , done + [ b ] ] } } dw = { } deps_w . each { | b , deps | dw [ b ] = deps . reject { | dep | ret = true done = [ ] todo = deps_to [ b ] . dup while a = todo . pop next if done . include? a done << a if not deps_r [ a ] or deps_r [ a ] . include? dep ret = false break elsif not deps_w [ a ] . include? dep todo . concat deps_to [ a ] end end ret } } dw end
list variable dependency for each block, remove useless writes
returns { blockaddr => [list of vars that are needed by a following block] }
list variable dependency for each block remove useless writes returns { blockaddr = > [ list of vars that are needed by a following block ] }
# things read/written by subfuncs # find read/writes by each block # if dword [eax] <- 42, eax is read #a << :eax if di.opcode.name == 'ret'		# standard ABI # XXX this may seem a bit extreme, and yes, it is. # last block instr == subfunction call #deps_w[b] |= [:eax, :ecx, :edx]			# standard ABI # find regs read and never written (must have been set by caller and are part of the func ABI) # remove writes from a block if no following block read the value
dcmp
blocks
func