node/lib/metasm/metasm/gui/dasm_graph.rb
def build_ctx(ctx)
		# graph : block -> following blocks in same function
		block_rel = {}

		todo = ctx.root_addrs.dup
		done = [:default, Expression::Unknown]
		while a = todo.shift
			a = @dasm.normalize a
			next if done.include? a
			done << a
			next if not di = @dasm.di_at(a)
			if not di.block_head?
				block_rel[di.block.address] = [a]
				@dasm.split_block(a)
			end
			block_rel[a] = []
			di.block.each_to_samefunc(@dasm) { |t|
				t = @dasm.normalize t
				next if not @dasm.di_at(t)
				todo << t
				block_rel[a] << t
			}
			block_rel[a].uniq!
		end

		# populate boxes
		addr2box = {}
		todo = ctx.root_addrs.dup
		todo.delete_if { |t| not @dasm.di_at(t) }	# undefined func start
		done = []
		while a = todo.shift
			next if done.include? a
			done << a
			if not ctx.keep_split.to_a.include?(a) and from = block_rel.keys.find_all { |ba| block_rel[ba].include? a } and
					from.length == 1 and block_rel[from.first].length == 1 and
					addr2box[from.first] and lst = @dasm.decoded[from.first].block.list.last and
					lst.next_addr == a and (not lst.opcode.props[:saveip] or lst.block.to_subfuncret)
				box = addr2box[from.first]
			else
				box = ctx.new_box a, :addresses => [], :line_text_col => [], :line_address => []
			end
			@dasm.decoded[a].block.list.each { |di_|
				box[:addresses] << di_.address
				addr2box[di_.address] = box
			}
			todo.concat block_rel[a]
		end

		# link boxes
		ctx.box.each { |b|
			next if not di = @dasm.decoded[b[:addresses].last]
			a = di.block.address
			next if not block_rel[a]
			block_rel[a].each { |t|
				ctx.link_boxes(b.id, t)
				b.direct_to = t if t == di.next_addr
			}
		}

		# calc box dimensions/text
		ctx.box.each { |b|
			colstr = []
			curaddr = nil
			line = 0
			render = lambda { |str, col| colstr << [str, col] }
			nl = lambda {
				b[:line_address][line] = curaddr
				b[:line_text_col][line] = colstr
				colstr = []
				line += 1
			}
			b[:addresses].each { |addr|
				curaddr = addr
				if di = @dasm.di_at(curaddr)
					if di.block_head?
						# render dump_block_header, add a few colors
						b_header = '' ; @dasm.dump_block_header(di.block) { |l| b_header << l ; b_header << ?\n if b_header[-1] != ?\n }
						b_header.strip.each_line { |l| l.chomp!
							col = :comment
							col = :label if l[0, 2] != '//' and l[-1] == ?:
							render[l, col]
							nl[]
						}
					end
					render["#{Expression[curaddr]}   ", :address] if @show_addresses
					render[di.instruction.to_s.ljust(di.comment ? 18 : 0), :instruction]
					render[' ; ' + di.comment.join(' ')[0, 64], :comment] if di.comment
					nl[]
				else
					# TODO real data display (dwords, xrefs, strings..)
					if label = @dasm.get_label_at(curaddr)
						render[label + ' ', :label]
					end
					s = @dasm.get_section_at(curaddr)
					render['db '+((s and s[0].data.length > s[0].ptr) ? Expression[s[0].read(1)[0]].to_s : '?'), :text]
					nl[]
				end
			}
			b.w = b[:line_text_col].map { |strc| strc.map { |s, c| s }.join.length }.max.to_i * @font_width + 2
			b.w += 1 if b.w % 2 == 0	# ensure boxes have odd width -> vertical arrows are straight
			b.h = line * @font_height
		}
	end
# create the graph objects in ctx
create the graph objects in ctx
create the graph objects in ctx
def build_ctx(ctx)
		block_rel = {}
		todo = ctx.root_addrs.dup
		done = [:default, Expression::Unknown]
		while a = todo.shift
			a = @dasm.normalize a
			next if done.include? a
			done << a
			next if not di = @dasm.di_at(a)
			if not di.block_head?
				block_rel[di.block.address] = [a]
				@dasm.split_block(a)
			end
			block_rel[a] = []
			di.block.each_to_samefunc(@dasm) { |t|
				t = @dasm.normalize t
				next if not @dasm.di_at(t)
				todo << t
				block_rel[a] << t
			}
			block_rel[a].uniq!
		end
		addr2box = {}
		todo = ctx.root_addrs.dup
		todo.delete_if { |t| not @dasm.di_at(t) }	
		done = []
		while a = todo.shift
			next if done.include? a
			done << a
			if not ctx.keep_split.to_a.include?(a) and from = block_rel.keys.find_all { |ba| block_rel[ba].include? a } and
					from.length == 1 and block_rel[from.first].length == 1 and
					addr2box[from.first] and lst = @dasm.decoded[from.first].block.list.last and
					lst.next_addr == a and (not lst.opcode.props[:saveip] or lst.block.to_subfuncret)
				box = addr2box[from.first]
			else
				box = ctx.new_box a, :addresses => [], :line_text_col => [], :line_address => []
			end
			@dasm.decoded[a].block.list.each { |di_|
				box[:addresses] << di_.address
				addr2box[di_.address] = box
			}
			todo.concat block_rel[a]
		end
		ctx.box.each { |b|
			next if not di = @dasm.decoded[b[:addresses].last]
			a = di.block.address
			next if not block_rel[a]
			block_rel[a].each { |t|
				ctx.link_boxes(b.id, t)
				b.direct_to = t if t == di.next_addr
			}
		}
		ctx.box.each { |b|
			colstr = []
			curaddr = nil
			line = 0
			render = lambda { |str, col| colstr << [str, col] }
			nl = lambda {
				b[:line_address][line] = curaddr
				b[:line_text_col][line] = colstr
				colstr = []
				line += 1
			}
			b[:addresses].each { |addr|
				curaddr = addr
				if di = @dasm.di_at(curaddr)
					if di.block_head?
						b_header = '' ; @dasm.dump_block_header(di.block) { |l| b_header << l ; b_header << ?\n if b_header[-1] != ?\n }
						b_header.strip.each_line { |l| l.chomp!
							col = :comment
							col = :label if l[0, 2] != '//' and l[-1] == ?:
							render[l, col]
							nl[]
						}
					end
					render["#{Expression[curaddr]}   ", :address] if @show_addresses
					render[di.instruction.to_s.ljust(di.comment ? 18 : 0), :instruction]
					render[' ; ' + di.comment.join(' ')[0, 64], :comment] if di.comment
					nl[]
				else
					if label = @dasm.get_label_at(curaddr)
						render[label + ' ', :label]
					end
					s = @dasm.get_section_at(curaddr)
					render['db '+((s and s[0].data.length > s[0].ptr) ? Expression[s[0].read(1)[0]].to_s : '?'), :text]
					nl[]
				end
			}
			b.w = b[:line_text_col].map { |strc| strc.map { |s, c| s }.join.length }.max.to_i * @font_width + 2
			b.w += 1 if b.w % 2 == 0	
			b.h = line * @font_height
		}
	end
def build_ctx ( ctx ) block_rel = { } todo = ctx . root_addrs . dup done = [ :default , Expression :: Unknown ] while a = todo . shift a = @dasm . normalize a next if done . include? a done << a next if not di = @dasm . di_at ( a ) if not di . block_head? block_rel [ di . block . address ] = [ a ] @dasm . split_block ( a ) end block_rel [ a ] = [ ] di . block . each_to_samefunc ( @dasm ) { | t | t = @dasm . normalize t next if not @dasm . di_at ( t ) todo << t block_rel [ a ] << t } block_rel [ a ] . uniq! end addr2box = { } todo = ctx . root_addrs . dup todo . delete_if { | t | not @dasm . di_at ( t ) } done = [ ] while a = todo . shift next if done . include? a done << a if not ctx . keep_split . to_a . include? ( a ) and from = block_rel . keys . find_all { | ba | block_rel [ ba ] . include? a } and from . length == 1 and block_rel [ from . first ] . length == 1 and addr2box [ from . first ] and lst = @dasm . decoded [ from . first ] . block . list . last and lst . next_addr == a and ( not lst . opcode . props [ :saveip ] or lst . block . to_subfuncret ) box = addr2box [ from . first ] else box = ctx . new_box a , :addresses => [ ] , :line_text_col => [ ] , :line_address => [ ] end @dasm . decoded [ a ] . block . list . each { | di_ | box [ :addresses ] << di_ . address addr2box [ di_ . address ] = box } todo . concat block_rel [ a ] end ctx . box . each { | b | next if not di = @dasm . decoded [ b [ :addresses ] . last ] a = di . block . address next if not block_rel [ a ] block_rel [ a ] . each { | t | ctx . link_boxes ( b . id , t ) b . direct_to = t if t == di . next_addr } } ctx . box . each { | b | colstr = [ ] curaddr = nil line = 0 render = lambda { | str , col | colstr << [ str , col ] } nl = lambda { b [ :line_address ] [ line ] = curaddr b [ :line_text_col ] [ line ] = colstr colstr = [ ] line += 1 } b [ :addresses ] . each { | addr | curaddr = addr if di = @dasm . di_at ( curaddr ) if di . block_head? b_header = '' ; @dasm . dump_block_header ( di . block ) { | l | b_header << l ; b_header << ?\n if b_header [ - 1 ] != ?\n } b_header . strip . each_line { | l | l . chomp! col = :comment col = :label if l [ 0 , 2 ] != '//' and l [ - 1 ] == ?: render [ l , col ] nl [ ] } end render [ "#{Expression[curaddr]}   " , :address ] if @show_addresses render [ di . instruction . to_s . ljust ( di . comment ? 18 : 0 ) , :instruction ] render [ ' ; ' + di . comment . join ( ' ' ) [ 0 , 64 ] , :comment ] if di . comment nl [ ] else if label = @dasm . get_label_at ( curaddr ) render [ label + ' ' , :label ] end s = @dasm . get_section_at ( curaddr ) render [ 'db ' + ( ( s and s [ 0 ] . data . length > s [ 0 ] . ptr ) ? Expression [ s [ 0 ] . read ( 1 ) [ 0 ] ] . to_s : '?' ) , :text ] nl [ ] end } b . w = b [ :line_text_col ] . map { | strc | strc . map { | s , c | s } . join . length } . max . to_i * @font_width + 2 b . w += 1 if b . w % 2 == 0 b . h = line * @font_height } end
create the graph objects in ctx
create the graph objects in ctx
# graph : block -> following blocks in same function # populate boxes # undefined func start # link boxes # calc box dimensions/text # render dump_block_header, add a few colors # TODO real data display (dwords, xrefs, strings..) # ensure boxes have odd width -> vertical arrows are straight
ctx