node/lib/metasm/metasm/disassemble.rb
def backtrace_check_funcret(btt, funcaddr, instraddr)
		if di = @decoded[instraddr] and @function[funcaddr] and btt.type == :x and
				not btt.from_subfuncret and
				@cpu.backtrace_is_function_return(btt.expr, @decoded[btt.origin]) and
				retaddr = backtrace_emu_instr(di, btt.expr) and
				not need_backtrace(retaddr)
puts "  backtrace addrs_todo << #{Expression[retaddr]} from #{di} (funcret)" if debug_backtrace
			di.block.add_to_subfuncret normalize(retaddr)
			if @decoded[funcaddr].kind_of? DecodedInstruction
				# check that all callers :saveip returns (eg recursive call that was resolved
				# before we found funcaddr was a function)
				@decoded[funcaddr].block.each_from_normal { |fm|
					if fdi = di_at(fm) and fdi.opcode.props[:saveip] and not fdi.block.to_subfuncret
						backtrace_check_funcret(btt, funcaddr, fm)
					end
				}
			end
			if not @function[funcaddr].finalized
				# the function is not fully disassembled: arrange for the retaddr to be
				#  disassembled only after the subfunction is finished
				# for that we walk the code from the call, mark each block start, and insert the sfret
				#  just before the 1st function block address in @addrs_todo (which is pop()ed by dasm_step)
				faddrlist = []
				todo = []
				di.block.each_to_normal { |t| todo << normalize(t) }
				while a = todo.pop
					next if faddrlist.include? a or not get_section_at(a)
					faddrlist << a
					if @decoded[a].kind_of? DecodedInstruction
						@decoded[a].block.each_to_samefunc(self) { |t| todo << normalize(t) }
					end
				end

				idx = @addrs_todo.index(@addrs_todo.find { |r, i, sfr| faddrlist.include? normalize(r) }) || -1
				@addrs_todo.insert(idx, [retaddr, instraddr, true])
			else
				@addrs_todo << [retaddr, instraddr, true]
			end
			true
		end
	end
# checks if the BacktraceTrace is a call to a known subfunction
# returns true and updates self.addrs_todo
checks if the BacktraceTrace is a call to a known subfunction
returns true and updates self.addrs_todo
checks if the BacktraceTrace is a call to a known subfunction returns true and updates self . addrs_todo
def backtrace_check_funcret(btt, funcaddr, instraddr)
		if di = @decoded[instraddr] and @function[funcaddr] and btt.type == :x and
				not btt.from_subfuncret and
				@cpu.backtrace_is_function_return(btt.expr, @decoded[btt.origin]) and
				retaddr = backtrace_emu_instr(di, btt.expr) and
				not need_backtrace(retaddr)
puts "  backtrace addrs_todo << #{Expression[retaddr]} from #{di} (funcret)" if debug_backtrace
			di.block.add_to_subfuncret normalize(retaddr)
			if @decoded[funcaddr].kind_of? DecodedInstruction
				@decoded[funcaddr].block.each_from_normal { |fm|
					if fdi = di_at(fm) and fdi.opcode.props[:saveip] and not fdi.block.to_subfuncret
						backtrace_check_funcret(btt, funcaddr, fm)
					end
				}
			end
			if not @function[funcaddr].finalized
				faddrlist = []
				todo = []
				di.block.each_to_normal { |t| todo << normalize(t) }
				while a = todo.pop
					next if faddrlist.include? a or not get_section_at(a)
					faddrlist << a
					if @decoded[a].kind_of? DecodedInstruction
						@decoded[a].block.each_to_samefunc(self) { |t| todo << normalize(t) }
					end
				end
				idx = @addrs_todo.index(@addrs_todo.find { |r, i, sfr| faddrlist.include? normalize(r) }) || -1
				@addrs_todo.insert(idx, [retaddr, instraddr, true])
			else
				@addrs_todo << [retaddr, instraddr, true]
			end
			true
		end
	end
def backtrace_check_funcret ( btt , funcaddr , instraddr ) if di = @decoded [ instraddr ] and @function [ funcaddr ] and btt . type == :x and not btt . from_subfuncret and @cpu . backtrace_is_function_return ( btt . expr , @decoded [ btt . origin ] ) and retaddr = backtrace_emu_instr ( di , btt . expr ) and not need_backtrace ( retaddr ) puts "  backtrace addrs_todo << #{Expression[retaddr]} from #{di} (funcret)" if debug_backtrace di . block . add_to_subfuncret normalize ( retaddr ) if @decoded [ funcaddr ] . kind_of? DecodedInstruction @decoded [ funcaddr ] . block . each_from_normal { | fm | if fdi = di_at ( fm ) and fdi . opcode . props [ :saveip ] and not fdi . block . to_subfuncret backtrace_check_funcret ( btt , funcaddr , fm ) end } end if not @function [ funcaddr ] . finalized faddrlist = [ ] todo = [ ] di . block . each_to_normal { | t | todo << normalize ( t ) } while a = todo . pop next if faddrlist . include? a or not get_section_at ( a ) faddrlist << a if @decoded [ a ] . kind_of? DecodedInstruction @decoded [ a ] . block . each_to_samefunc ( self ) { | t | todo << normalize ( t ) } end end idx = @addrs_todo . index ( @addrs_todo . find { | r , i , sfr | faddrlist . include? normalize ( r ) } ) || - 1 @addrs_todo . insert ( idx , [ retaddr , instraddr , true ] ) else @addrs_todo << [ retaddr , instraddr , true ] end true end end
checks if the BacktraceTrace is a call to a known subfunction
returns true and updates self.addrs_todo
checks if the BacktraceTrace is a call to a known subfunction returns true and updates self . addrs_todo
# check that all callers :saveip returns (eg recursive call that was resolved # before we found funcaddr was a function) # the function is not fully disassembled: arrange for the retaddr to be #  disassembled only after the subfunction is finished # for that we walk the code from the call, mark each block start, and insert the sfret #  just before the 1st function block address in @addrs_todo (which is pop()ed by dasm_step)
btt
funcaddr
instraddr