def DumpRawTraceFile()

in tools/lldbmacros/misc.py [0:0]


def DumpRawTraceFile(cmd_args=[], cmd_options={}):
    """
        support for ktrace(1)

        NB: trace is not wordsize flexible, so use ktrace(1) compiled for the compatible model,
        e.g. if you dump from __LP64__ system, you will need to run ktrace(1) compiled __LP64__ to process the raw data file.

        read the kernel's debug trace buffer, and dump to a "raw" ktrace(1) file
        Usage: dumprawtracefile <output_filename>
            -U <uptime> : specify system uptime in nsec, obtained e.g. from paniclog
        Be patient, it is teh slow.

        cf. kdbg_read()\bsd/kern/kdebug.c
    """

    #  Check if KDBG_BFINIT (0x80000000) is set in kdebug_flags 
    if (kern.globals.kd_ctrl_page.kdebug_flags & xnudefines.KDBG_BFINIT) == 0 :
        print "Trace buffer not enabled\n"
        return

    if ((kern.arch == "x86_64") or kern.arch.startswith("arm64")) :
        lp64 = True
    elif kern.arch == "arm" :
        lp64 = False
    else :
        print "unknown kern.arch {:s}\n".format(kern.arch)
        return

    # Various kern.globals are hashed by address, to
    #  a) avoid redundant kdp fetch from, and
    #  b) avoid all stores to
    # the target system kernel structures.
    # Stores to hashed structures remain strictly local to the lldb host,
    # they are never written back to the target.
    htab = {}

    if lp64 :
        KDBG_TIMESTAMP_MASK = 0xffffffffffffffff
        KDBG_CPU_SHIFT      = 0
    else :
        KDBG_TIMESTAMP_MASK = 0x00ffffffffffffff
        KDBG_CPU_SHIFT      = 56

    barrier_min     = 0
    barrier_max     = 0
    out_of_events       = False
    lostevents      = False
    lostevent_timestamp = 0
    lostevent_debugid   = (((xnudefines.DBG_TRACE & 0xff) << 24) | ((xnudefines.DBG_TRACE_INFO & 0xff) << 16) | ((2 & 0x3fff)  << 2)) # 0x01020008
    events_count_lost   = 0
    events_count_found  = 0

    opt_verbose = config['verbosity']
    opt_progress = (opt_verbose > vHUMAN) and (opt_verbose < vDETAIL)
    progress_count = 0
    progress_stride = 32

    output_filename = str(cmd_args[0])
    if opt_verbose > vHUMAN :
        print "output file : {:s}".format(output_filename)
    wfd = open(output_filename, "wb")

    uptime = long(-1)
    if "-U" in cmd_options:
        uptime = long(cmd_options["-U"])
    if opt_verbose > vHUMAN :
        print "uptime : {:d}".format(uptime)

    nkdbufs = kern.globals.nkdbufs

    kd_ctrl_page = kern.globals.kd_ctrl_page
    if not kd_ctrl_page in htab :
        htab[kd_ctrl_page] = kern.globals.kd_ctrl_page

    if opt_verbose > vHUMAN :
        print "nkdbufs {0:#x}, enabled {1:#x}, flags {2:#x}, cpus {3:#x}".format(nkdbufs, htab[kd_ctrl_page].enabled, htab[kd_ctrl_page].kdebug_flags, htab[kd_ctrl_page].kdebug_cpus)

    if nkdbufs == 0 :
        print "0 nkdbufs, nothing extracted"
        return

    if htab[kd_ctrl_page].enabled != 0 :
        barrier_max = uptime & KDBG_TIMESTAMP_MASK

        f = htab[kd_ctrl_page].kdebug_flags
        wrapped = f & xnudefines.KDBG_WRAPPED
    if wrapped != 0 :
        barrier_min = htab[kd_ctrl_page].oldest_time
        htab[kd_ctrl_page].kdebug_flags = htab[kd_ctrl_page].kdebug_flags & ~xnudefines.KDBG_WRAPPED
        htab[kd_ctrl_page].oldest_time = 0

        for cpu in range(htab[kd_ctrl_page].kdebug_cpus) :
            kdbp = unsigned(addressof(kern.globals.kdbip[cpu]))
            if not kdbp in htab :
                htab[kdbp] = kern.globals.kdbip[cpu]

            kdsp = htab[kdbp].kd_list_head.raw
            if kdsp == xnudefines.KDS_PTR_NULL :
                continue

            ix = htab[kdbp].kd_list_head.buffer_index
            off = htab[kdbp].kd_list_head.offset
            kdsp_actual = unsigned(addressof(kern.globals.kd_bufs[ix].kdsb_addr[off]))
            if not kdsp_actual in htab :
                htab[kdsp_actual] = kern.globals.kd_bufs[ix].kdsb_addr[off]
            htab[kdsp_actual].kds_lostevents = False


    # generate trace file header; threadmap is stubbed/TBD
    version_no = xnudefines.RAW_VERSION1
    thread_count = 0
    TOD_secs = uptime
    TOD_usecs = 0
    header = struct.pack('IIqI', version_no, thread_count, TOD_secs, TOD_usecs)
    pad_bytes = 4096 - (len(header) & 4095)
    header += "\x00" * pad_bytes
    wfd.write(buffer(header))

    count = nkdbufs
    while count != 0 :
        tempbuf = ""
        tempbuf_number = 0
        tempbuf_count = min(count, xnudefines.KDCOPYBUF_COUNT)

        # while space
        while tempbuf_count != 0 :

            if opt_progress == True :
                progress_count += 1
                if (progress_count % progress_stride) == 0 :
                    sys.stderr.write('.')
                    sys.stderr.flush()

            earliest_time = 0xffffffffffffffff
            min_kdbp = None
            min_cpu = 0

            # Check all CPUs
            for cpu in range(htab[kd_ctrl_page].kdebug_cpus) :

                kdbp = unsigned(addressof(kern.globals.kdbip[cpu]))
                if not kdbp in htab :
                    htab[kdbp] = kern.globals.kdbip[cpu]

                # Skip CPUs without data.
                kdsp = htab[kdbp].kd_list_head
                if kdsp.raw == xnudefines.KDS_PTR_NULL :
                    continue

                kdsp_shadow = kdsp

                # Get from cpu data to buffer header to buffer
                ix = kdsp.buffer_index
                off = kdsp.offset
                kdsp_actual = unsigned(addressof(kern.globals.kd_bufs[ix].kdsb_addr[off]))
                if not kdsp_actual in htab :
                    htab[kdsp_actual] = kern.globals.kd_bufs[ix].kdsb_addr[off]

                kdsp_actual_shadow = kdsp_actual

                # Skip buffer if there are no events left.
                rcursor = htab[kdsp_actual].kds_readlast
                if rcursor == htab[kdsp_actual].kds_bufindx :
                    continue

                t = htab[kdsp_actual].kds_records[rcursor].timestamp & KDBG_TIMESTAMP_MASK

                # Ignore events that have aged out due to wrapping.
                goto_next_cpu = False;
                while (t < unsigned(barrier_min)) :
                    r = htab[kdsp_actual].kds_readlast
                    htab[kdsp_actual].kds_readlast = r + 1
                    rcursor = r + 1

                    if rcursor >= xnudefines.EVENTS_PER_STORAGE_UNIT :

                        kdsp = htab[kdbp].kd_list_head
                        if kdsp.raw == xnudefines.KDS_PTR_NULL :
                            goto_next_cpu = True
                            break

                        kdsp_shadow = kdsp;

                        ix  = kdsp.buffer_index
                        off = kdsp.offset
                        kdsp_actual = unsigned(addressof(kern.globals.kd_bufs[ix].kdsb_addr[off]))

                        kdsp_actual_shadow = kdsp_actual;
                        rcursor = htab[kdsp_actual].kds_readlast;

                    t = htab[kdsp_actual].kds_records[rcursor].timestamp & KDBG_TIMESTAMP_MASK

                if goto_next_cpu == True :
                    continue

                if (t > barrier_max) and (barrier_max > 0) :
                    # Need to flush IOPs again before we
                    # can sort any more data from the
                    # buffers.  
                    out_of_events = True
                    break

                if t < (htab[kdsp_actual].kds_timestamp & KDBG_TIMESTAMP_MASK) :
                    # indicates we've not yet completed filling
                    # in this event...
                    # this should only occur when we're looking
                    # at the buf that the record head is utilizing
                    # we'll pick these events up on the next
                    # call to kdbg_read
                    # we bail at this point so that we don't
                    # get an out-of-order timestream by continuing
                    # to read events from the other CPUs' timestream(s)
                    out_of_events = True
                    break

                if t < earliest_time :
                    earliest_time = t
                    min_kdbp = kdbp
                    min_cpu = cpu


            if (min_kdbp is None) or (out_of_events == True) :
                # all buffers ran empty
                                out_of_events = True
                                break

            kdsp = htab[min_kdbp].kd_list_head

            ix = kdsp.buffer_index
            off = kdsp.offset
            kdsp_actual = unsigned(addressof(kern.globals.kd_bufs[ix].kdsb_addr[off]))
            if not kdsp_actual in htab :
                htab[kdsp_actual] = kern.globals.kd_bufs[ix].kdsb_addr[off]

            # Copy earliest event into merged events scratch buffer.
            r = htab[kdsp_actual].kds_readlast
            htab[kdsp_actual].kds_readlast = r + 1
            e = htab[kdsp_actual].kds_records[r]

            # Concatenate event into buffer
            # XXX condition here is on __LP64__
            if lp64 :
                tempbuf += struct.pack('QQQQQQIIQ', 
                        unsigned(e.timestamp),
                        unsigned(e.arg1),
                        unsigned(e.arg2),
                        unsigned(e.arg3),
                        unsigned(e.arg4),
                        unsigned(e.arg5),
                        unsigned(e.debugid),
                        unsigned(e.cpuid),
                        unsigned(e.unused))
            else :
                tempbuf += struct.pack('QIIIIII',
                        unsigned(e.timestamp),
                        unsigned(e.arg1),
                        unsigned(e.arg2),
                        unsigned(e.arg3),
                        unsigned(e.arg4),
                        unsigned(e.arg5),
                        unsigned(e.debugid))

            # Watch for out of order timestamps
            if earliest_time < (htab[min_kdbp].kd_prev_timebase & KDBG_TIMESTAMP_MASK) :
                ## if so, use the previous timestamp + 1 cycle
                htab[min_kdbp].kd_prev_timebase += 1

                e.timestamp = htab[min_kdbp].kd_prev_timebase & KDBG_TIMESTAMP_MASK
                if not lp64:
                    e.timestamp |= (min_cpu << KDBG_CPU_SHIFT)
            else :
                htab[min_kdbp].kd_prev_timebase = earliest_time

            if opt_verbose >= vDETAIL :
                print "{0:#018x} {1:#018x} {2:#018x} {3:#018x} {4:#018x} {5:#018x} {6:#010x} {7:#010x} {8:#018x}".format(
                    e.timestamp, e.arg1, e.arg2, e.arg3, e.arg4, e.arg5, e.debugid, e.cpuid, e.unused)

            events_count_found += 1

            # nextevent:
            tempbuf_count -= 1
            tempbuf_number += 1

        if opt_progress == True :
            sys.stderr.write('\n')
            sys.stderr.flush()

        if opt_verbose > vHUMAN :
            print "events_count_lost {0:#x}, events_count_found {1:#x}, progress_count {2:#x}".format(events_count_lost, events_count_found, progress_count)

        # write trace events to output file
        if tempbuf_number != 0 :
            count -= tempbuf_number
            wfd.write(buffer(tempbuf))

        if out_of_events == True :
            # all trace buffers are empty
            if opt_verbose > vHUMAN :
                print "out of events"
            break

    wfd.close()

    return