2

I need help with the SBValue class used in the lldb Python module which is used for creating scripts for lldb debugging sessions.

I am in the process of porting my kext test and debug system from gdb to lldb so I can start using the latest version of Xcode and Mac OS 10.9.1. Part of this process is rewriting my gdb debug scripts in python so they can be used with lldb.

I have the two mac setup working, can drop into lldb and poke around in the kernel of the victim Mac. I can also my Python script to be called when I am running an lldb session. I'm stuck though in that I am unable to figure out how to display the contents of an array of records.

For instance, given an array of TraceRecs:

typedef struct
{

    mach_timespec_t timeStamp;
    thread_t thread;
    TraceRecordType recordType;
    char entry[kEntrySize];
} TraceRec;

a class which holds an array of trace records

class com_softraid_TraceLog
{
    private:
        UInt32 fMaxNumberEntries;
        UInt32 fNextEntryNumber;
        TraceRec * fTraceRecArray;
        .
        .
        .

and a global in the kernel which points to an object of this class:

extern com_softraid_TraceLog * com_softraid_gTraceLogPtr;

I can use the following Python script to get the value of com_softraid_gTraceLogPtr in lldb:

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import lldb
import commands
import optparse
import shlex

def __lldb_init_module(debugger, internal_dict):
    debugger.HandleCommand('command script add -f sr_debug_macros.srtrace srtrace')

def srtrace(debugger, user_input, result, internal_dict):
    """srtrace [number_entries]  dump out that number of entries, default = 0 = all entries"""

    target = debugger.GetSelectedTarget()
    traceLog = target.FindFirstGlobalVariable("com_softraid_gTraceLogPtr")
    traceRecordArray = traceLog.GetChildMemberWithName("fTraceRecArray")
    maxNumberEntries = traceLog.GetChildMemberWithName("fMaxNumberEntries").GetValueAsUnsigned()
    nextEntryNumber = traceLog.GetChildMemberWithName("fNextEntryNumber").GetValueAsUnsigned()

    print >>result, "SRLog Current Entry: %d, Log Size: %d" % (nextEntryNumber, maxNumberEntries)

    print >>result, traceRecordArray

and the output is:

(lldb) srtrace
SRLog Current Entry: 388, Log Size: 8192
(TraceRec *) fTraceRecArray = 0xffffff80a48fd000

but I can't figure out how to display the values in fields of any of records in the array. I have tried most of the methods in the SBValue class without any luck.

Does anyone understand how this is supposed to work? Any help would be great.

P. S.: If anyone else is trying to get this to work, the first step should be to update to Xcode 5.1 b5. The version of lldb which ships with Xcode 5.1 b3 crashes frequently when displaying the contents subclasses of IOKit classes.

Ankur Ankan
  • 2,953
  • 2
  • 23
  • 38

1 Answers1

1

You're looking for SBValue::GetChildAtIndex() but you need to use the long form of that API. For instance, with a standalone user process C file,

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct
{
    int datum;
} TraceRec;

typedef struct
{
        uint32_t fMaxNumberEntries;
        uint32_t fNextEntryNumber;
        TraceRec *fTraceRecArray;
} com_softraid_TraceLog;

com_softraid_TraceLog *com_softraid_gTraceLogPtr;

int main ()
{
    com_softraid_TraceLog log;
    com_softraid_gTraceLogPtr = &log;
    log.fTraceRecArray = (TraceRec *) malloc (sizeof (TraceRec) * 100);
    log.fMaxNumberEntries = 100;
    log.fNextEntryNumber = 4;
    log.fTraceRecArray[0].datum = 0;
    log.fTraceRecArray[1].datum = 1;
    log.fTraceRecArray[2].datum = 2;
    log.fTraceRecArray[3].datum = 3;

    puts ("break here");

    return 0;
}

we can experiment a little in the interactive script mode:

(lldb) br s -p break
(lldb) r
(lldb) scri
>>> debugger = lldb.debugger
>>> target = debugger.GetSelectedTarget()
>>> traceLog = target.FindFirstGlobalVariable("com_softraid_gTraceLogPtr")
>>> traceRecordArray = traceLog.GetChildMemberWithName("fTraceRecArray")
>>> print traceRecordArray.GetChildAtIndex(1, lldb.eNoDynamicValues, 1)
(TraceRec) [1] = {
  datum = 1
}
>>> print traceRecordArray.GetChildAtIndex(2, lldb.eNoDynamicValues, 1)
(TraceRec) [2] = {
  datum = 2
}
>>> 

There's also SBValue::GetPointeeData() which would give you the raw bytes of each member of the array in an SBData object but then you'd need to coerce those bytes back into your structure so I wouldn't go that way.

Jason Molenda
  • 14,835
  • 1
  • 59
  • 61
  • When I try, I get, "No Value" (I entered your lines exactly). I can print traceRecordArray but cannot print the result from GetChildAtIndex() – Tim Standing Feb 11 '14 at 16:51
  • Hm, that was with Xcode 5.0's lldb (lldb-300.2.53). I'll double-check with the Xcode you're using later - but there's nothing hidden up my sleeve with the example here. I can't think of anything in the lldb you're using which would cause a difference in behavior ... there may be something else going on with why it's not working for you. Just to be clear -- you tried this on the user process test file I wrote above and it didn't work? Or on the kext? – Jason Molenda Feb 11 '14 at 18:01
  • I tried it on the kext with remote debugging. Both Macs running 10.9.1. Development Mac running Xcode 5.1 b5. I launch lldb by running xcrun lldb -s lldb_init (where lldb_init is my initialization file for the session). The lldb version is: lldb-310.2.34. – Tim Standing Feb 11 '14 at 18:13
  • It looks like it's not a problem with the python module but rather with the kdp interface. I can't get lldb to output a `TraceRec` either. Trying to print the record which fTraceRecArray points to results in: `(lldb) p *(TraceRec *) com_softraid_gTraceLogPtr->fTraceRecArray error: incomplete type 'TraceRec' (aka '') where a complete type is required note: forward declaration of '' error: 1 errors parsing expression ` – Tim Standing Feb 11 '14 at 18:23
  • Interesting, it might be best to go with a bug report over at http://bugreport.apple.com/ at this point to investigate further. If possible, please include a copy of your softraid.kext and softraid.kext.dSYM, and at the point where you couldn't do the print, include the output of `image lookup -v -a $pc` which will show exactly where you were stopped in the kext at the time. – Jason Molenda Feb 11 '14 at 18:28
  • I rebuild my kext with Xcode 5.1 b5 and your suggested solution now works. It looks like it was a fix beta 5. It also fixed the bug which caused lldb to crash if I printed an object derived from an IOKit base class (e.g. IOService). Thanks for your help. – Tim Standing Feb 11 '14 at 20:49