#!/usr/bin/env python
###
### Safe Stack Hash
### (based on the print_stacktrace function of lldbutil.py)
###

import lldb
import sys

### global setting = how many back traces?
stack_count = 5

def get_filenames( thread ):
    """
    Returns a sequence of file names from the stack frames of this thread.
    """
    def GetFilename( i ):
        return thread.GetFrameAtIndex( i ).GetLineEntry().GetFileSpec().GetFilename()

    return map( GetFilename, range( thread.GetNumFrames() ) )

def get_line_numbers( thread ):
    """
    Returns a sequence of line numbers from the stack frames of this thread.
    """
    def GetLineNumber( i ):
        return thread.GetFrameAtIndex( i ).GetLineEntry().GetLine()

    return map( GetLineNumber, range( thread.GetNumFrames() ) )

def get_pc_addresses( thread ):
    """
    Returns a sequence of pc addresses for this thread.
    """
    def GetPCAddress( i ):
        return thread.GetFrameAtIndex( i ).GetPCAddress()

    return map( GetPCAddress, range( thread.GetNumFrames() ) )

def print_stacktrace( thread ):
    """Prints a simple stack trace of this thread."""

    target = thread.GetProcess().GetTarget()

    depth = thread.GetNumFrames()

    files = get_filenames(thread)
    lines = get_line_numbers(thread)
    addrs = get_pc_addresses(thread)

    stacks = []
    for i in range(depth):
        frame = thread.GetFrameAtIndex(i)
        function = frame.GetFunction()

        load_addr = addrs[i].GetLoadAddress(target)
        if not function:
            stacks.append( "%x" % load_addr )
        else:
            stacks.append( "%s:%d" % (files[i], lines[i]) )

    stacks = stacks[:stack_count]
    if len( stacks ) > 0:
        return "|".join(stacks)
    else:
        return "EMPTY"

def stack_trace( debugger, command, result, dict ):
    target = debugger.GetSelectedTarget()
    thread = target.GetProcess().GetSelectedThread()
    bt = print_stacktrace( thread )
    f = open( "triage.txt", "w" )
    f.write( bt )
    f.close()
    exit(0)

def __lldb_init_module( debugger, dict ):
    debugger.HandleCommand( 'command script add -f triage.stack_trace stack_trace' )

