[lldb-dev] lldb: how can I make it reliably scriptable?

Paul Smith paul at mad-scientist.net
Fri Feb 20 11:18:04 PST 2015


On Fri, 2015-02-20 at 10:56 -0800, Greg Clayton wrote:
> Can you post the python file you are using to do the core file
> inspection?

Here's the script, FWIW.  Note that I'm not sure if it's any particular
core that causes the problem; when I run this script on the same core
multiple times sometimes it works, sometimes Python aborts, and
sometimes Python hangs.

Of course it could well be something about my particular program that
triggers this and others wouldn't.  I'll see if I can provide a core
(presumably you'd need the executable as well... what about dSYM
content?)

We invoke this script with, basically:

  PYTHONPATH=$(lldb -P) python corescript.py core.12345 bin/myprog


#---- %>< snip ><% ----
#!/usr/bin/env python

import lldb
import sys

def load_core(debugger, exe, core):
    """

    @param exe: Path to the executable binary
    @param core: Path to the core
    @rtype: SBProcess
    @return:
    """
    target = debugger.CreateTargetWithFileAndArch(exe, lldb.LLDB_ARCH_DEFAULT)
    """ @type : SBTarget """
    if target:
        process = target.LoadCore(core)
        """ @type : SBProcess """
        if process:
            return process

        raise Exception("Could not load core")
    raise Exception("Could not create target")


def print_version(process):
    """
    @type process: SBProcess
    """
    thread = process.GetSelectedThread()
    """ @type : SBThread """
    if thread:
        frame = thread.GetSelectedFrame()
        """ @type : SBFrame """
        if frame:
            version = frame.EvaluateExpression('globals->version.data')
            """ @type : SBValue """
            if version:
                err = lldb.SBError()
                version_string = process.ReadCStringFromMemory(int(version.GetValue(), 16), 512, err)
                if err.Success():
                    print("*** Version: " + version_string)
                else:
                    print("*** Error extracting version")
                print("")
                return

            raise Exception("Invalid expression result, can't extract version")
        raise Exception("Invalid frame, can't extract version")
    raise Exception("Invalid thread, can't extract version")


def print_all_backtraces(process):
    """
    @type process: SBProcess
    """
    print("*** All Threads Backtrace:")
    for thread in reversed(process.threads):
        if thread:
            print_backtrace(thread)
        else:
            print("ERROR: Failed to print backtrace for a thread")


def print_backtrace(thread, include_label=False):
    """
    @type thread: SBThread
    """
    if include_label:
        print("*** Backtrace:")

    print("Thread %d (core thread %d):" % (thread.GetIndexID(), thread.GetThreadID()))
    for frame in thread:
        if frame:
            print(frame)
        else:
            print("ERROR: Failed to print a frame")

    print("")


def print_environment(process):
    """
    @type process: SBProcess
    """
    print("*** Environment:")
    print('  ' + '\n  '.join(read_null_term_array(process, 'globals->environment->envp')))
    print("")


def read_null_term_array(process, expr, max_length=1000):
    """
    @type process: SBProcess
    """
    thread = process.GetSelectedThread()
    """ @type : SBThread """
    if thread:
        frame = thread.GetSelectedFrame()
        """ @type : SBFrame """
        if frame:
            array_value = frame.EvaluateExpression(expr)
            """ @type : SBValue """
            if array_value:
                array_address = array_value.GetValueAsUnsigned()
                idx = 0
                ptr_err = lldb.SBError()
                array_data = []
                for i in xrange(0, max_length):
                    element_ptr = process.ReadPointerFromMemory(array_address + idx * array_value.GetByteSize(),
                                                                ptr_err)
                    if ptr_err.Success():
                        if element_ptr == 0:
                            break

                        val_err = lldb.SBError()
                        element = process.ReadCStringFromMemory(element_ptr, 1024*10, val_err)
                        if val_err.Success():
                            array_data.append(element)
                        else:
                            print("ERROR: Unable to read value at address %s" % (str(element_ptr)))

                        idx += 1
                    else:
                        print("ERROR: Unable to read pointer at address %s" %
                              (str(array_address + idx * array_value.GetByteSize()),))
                        break

                return array_data

            raise Exception("Unable to read array address for %s" % (expr,))
        raise Exception("Invalid frame for %s" % (expr,))
    raise Exception("Invalid thread for %s" % (expr,))


def main():
    if len(sys.argv) != 3:
        print("usage: python %s core_file exe_file" % (sys.argv[0],))
        exit(1)

    core = sys.argv[1]
    exe = sys.argv[2]

    debugger = lldb.SBDebugger.Create()
    """ @type : SBDebugger """

    process = load_core(debugger, exe, core)
    if process:
        print_version(process)
        print_backtrace(process.GetSelectedThread(), True)
        print_all_backtraces(process)
        print_environment(process)
    else:
        print("Failed to debug core " + core)

if __name__ == '__main__':
    main()





More information about the lldb-dev mailing list