#!/usr/bin/tclsh
#########################################################################################
# Parse output from ld_classic that complains about missing symbols and look them
# up in the named object file
#

proc parse_line {line} {

    global last_fname

    set toks [split $line]
    if { ![regexp "ld_classic:" [lindex $toks 0]] } {
	puts "ignoring garbage '$line'"
	return
    }

    set fname [lindex $toks 1]
    set relent [lindex $toks 7]
    set sect [lindex $toks 10]

    # strip archive member name if present
    set ppos [string last "(" $fname];
    if {$ppos != -1} {
	set fname [string range $fname 0 [expr $ppos - 1]];
    }

    #puts "% $fname % $relent % $sect"

    set relname [find_sym $fname $relent $sect]

    if {$last_fname != $fname} {
	puts "$fname:"
	set last_fname $fname
    }

    puts "  $relname"
}

proc find_sym {fname relent sect} {

    global reloc_$fname

    if {![array exists reloc_$fname]} {
	get_relocs $fname
    }
    upvar 0 reloc_$fname relocs
    if {[array names relocs -exact $sect:$relent] == ""} {
	puts "Don't know reloc $relent for $fname"
	exit 1
    }
    return $relocs($sect:$relent)
}

proc get_relocs {fname} {
    
    global reloc_$fname
    upvar 0 reloc_$fname relocs

    set body [exec otool -rv $fname]
    set lines [split $body "\n"]

    set curr_sect "none"

    foreach line $lines {

	set toks [split [collapse $line]]

	if {[lindex $toks 0] == "Relocation"} {
	    set sect [lindex $toks 2]
	    set count [lindex $toks 3]
	    set curr_sect $sect
	    set counter 0
	    continue
	}

	if {[string is xdigit [lindex $toks 0]]} {
	    if {[llength $toks] == 7} {
		set relocs($curr_sect:$counter) [lindex $toks 6]
	    }
	    incr counter
	}
    } 
}

proc collapse {str} {

    set before ""
    set after $str

    while {$before != $after} {
	set before $after

	set after [string map [list "  " " "] $before]
    }
    return $after
}

# Suck from standard input
set last_fname ""
while {[gets stdin line] > 0} {
    parse_line $line
}
