]> git.saurik.com Git - apple/libpthread.git/blobdiff - lldbmacros/init.py
libpthread-330.201.1.tar.gz
[apple/libpthread.git] / lldbmacros / init.py
diff --git a/lldbmacros/init.py b/lldbmacros/init.py
new file mode 100644 (file)
index 0000000..af7fe69
--- /dev/null
@@ -0,0 +1,310 @@
+from xnu import *
+import struct
+
+def GetSeqCount(seq):
+       return (seq >> 8)
+
+def GetLSeqBits(seq):
+       rv = ""
+       if seq & 0x1:
+               rv += "K"
+       if seq & 0x2:
+               rv += "E"
+       if seq & 0x4:
+               rv += "W"
+       if seq & 0x20:
+               rv += "M"
+       if seq & 0x40:
+               rv += "U"
+       if seq & 0x80:
+               rv += "I"
+       return rv
+
+def GetSSeqBits(seq):
+       rv = ""
+       if seq & 0x1:
+               rv += "S"
+       if seq & 0x2:
+               rv += "I"
+       if seq & 0x4:
+               rv += "Ws"
+       return rv
+
+def GetLSeqSummary(seq):
+       return "{:d} {:s}".format(GetSeqCount(seq), GetLSeqBits(seq))
+
+def GetSSeqSummary(seq):
+       return "{:d} {:s}".format(GetSeqCount(seq), GetSSeqBits(seq))
+
+@header("{0: <24s} {1: <16s} {2: <16s} {3: <16s} {4: <16s}".format('sig', 'tid', 'options', 'lseq', 'useq'))
+def GetUserMutexSummary(task, uaddr):
+       if int(task.t_flags) & 0x1:
+               mtxlayout = "QIIhhIQIII"
+               padoffset = 1
+       else:
+               mtxlayout = "QIIhhQIII"
+               padoffset = 0
+
+       data = GetUserDataAsString(task, unsigned(uaddr), struct.calcsize(mtxlayout))
+       info = struct.unpack(mtxlayout, data)
+
+       format = "{0: <24s} {1: <16s} {2: <16s} {3: <16s} {4: <16s}"
+       sigstr = str("{0: <#020x}".format(info[0]))
+
+       # the options field dictates whether we were created misaligned
+       if info[2] & 0x800:
+               lseq = info[7+padoffset]
+               useq = info[8+padoffset]
+       else:
+               lseq = info[6+padoffset]
+               useq = info[7+padoffset]
+
+       return format.format(sigstr, hex(info[5+padoffset]), hex(info[2]), hex(lseq), hex(useq))
+
+@lldb_command('showusermutex')
+def PthreadShowUserMutex(cmd_args=None):
+       """
+       display information about a userspace mutex at a given address
+       Syntax: (lldb) showusermutex <task_t> <uaddr>
+       """
+       if not cmd_args:
+               raise ArgumentError("No arguments passed")
+       task = kern.GetValueFromAddress(cmd_args[0], "task_t")
+       uaddr = kern.GetValueFromAddress(cmd_args[1], "user_addr_t")
+
+       print GetUserMutexSummary.header
+       print GetUserMutexSummary(task, uaddr)
+
+@lldb_type_summary(['ksyn_wait_queue *', 'ksyn_wait_queue_t'])
+@header("{:<20s} {:<20s} {:<10s} {:<6s} {:<6s} {:<8s} {:<8s} {:<8s} {:<8s}".format('kwq', 'uaddr', 'type', 'pflags', 'kflags', 'refs', 'indrop', 'waiters', 'preposts'))
+def GetKwqSummary(kwq):
+       format = "{:<#20x} {:<#20x} {:<10s} {:<6s} {:<6s} {:<8d} {:<8d} {:<8d} {:<8d}\n"
+       kwq = Cast(kwq, "ksyn_wait_queue_t")
+
+       kwqtype = ""
+       if kwq.kw_type & 0xff == 0x01:
+               kwqtype = "mtx"
+       if kwq.kw_type & 0xff == 0x02:
+               kwqtype = "cvar"
+       if kwq.kw_type & 0xff == 0x04:
+               kwqtype = "rwl"
+       if kwq.kw_type & 0xff == 0x05:
+               kwqtype = "sema"
+
+       if kwq.kw_type & 0x1000 == 0x1000:
+               kwqtype += "W" # INWAIT
+       if kwq.kw_type & 0x2000 == 0x2000:
+               kwqtype += "D" # INDROP
+
+       pflags = ""
+       if kwq.kw_pflags & 0x2:
+               pflags += "H" # INHASH
+       if kwq.kw_pflags & 0x4:
+               pflags += "S" # SHARED
+       if kwq.kw_pflags & 0x8:
+               pflags += "W" # WAITING
+       if kwq.kw_pflags & 0x10:
+               pflags += "F" # FREELIST
+
+       kflags = ""
+       if kwq.kw_kflags & 0x1:
+               kflags += "C" # INITCLEARED
+       if kwq.kw_kflags & 0x2:
+               kflags += "Z" # ZEROED
+       if kwq.kw_kflags & 0x4:
+               kflags += "Q" # QOS APPLIED
+       if kwq.kw_kflags & 0x8:
+               kflags += "O" # OVERLAP
+
+       rs = format.format(kwq, kwq.kw_addr, kwqtype, pflags, kflags, kwq.kw_iocount, kwq.kw_dropcount, kwq.kw_inqueue, kwq.kw_fakecount)
+
+       rs += "\t{:<10s} {:<10s} {:<10s} {:<10s} {:<10s} {:<10s} {:<10s}\n".format('lowest', 'highest', 'lword', 'uword', 'sword', 'last', 'next')
+       rs += "\t{:<10d} {:<10d} {:<10s} {:<10d} {:<10s} {:<10s} {:<10s}\n".format(
+                       GetSeqCount(kwq.kw_lowseq), GetSeqCount(kwq.kw_highseq),
+                       GetLSeqSummary(kwq.kw_lword), GetSeqCount(kwq.kw_uword),
+                       GetSSeqSummary(kwq.kw_sword), GetSSeqSummary(kwq.kw_lastseqword),
+                       GetSSeqSummary(kwq.kw_nextseqword))
+
+       rs += "\t{:<10s} {:<10s} {:<10s} {:<10s} {:<10s} {:<10s} {:<10s}\n".format(
+                       'pposts', 'lseq', 'sseq', 'intr', 'count', 'seq', 'bits')
+
+       intr_type = "NONE"
+       if kwq.kw_intr.type == 0x1:
+               intr_type = "READ"
+       elif kwq.kw_intr.type == 0x2:
+               intr_type = "WRITE"
+
+       rs += "\t{:<10d} {:<10s} {:<10s} {:<10s} {:<10d} {:<10s} {:<10s}\n".format(
+                       kwq.kw_prepost.count,
+                       GetLSeqSummary(kwq.kw_prepost.lseq), GetSSeqSummary(kwq.kw_prepost.sseq),
+                       intr_type, kwq.kw_intr.count,
+                       GetSSeqSummary(kwq.kw_intr.seq), GetSSeqSummary(kwq.kw_intr.returnbits))
+
+       rs += "\twaiting readers:\n"
+       for kwe in IterateTAILQ_HEAD(kwq.kw_ksynqueues[0].ksynq_kwelist, 'kwe_list'):
+               rs += "\t" + GetKweSummary.header + "\n"
+               rs += "\t" + GetKweSummary(kwe) + "\n"
+
+       rs += "\twaiting writers:\n"
+       for kwe in IterateTAILQ_HEAD(kwq.kw_ksynqueues[1].ksynq_kwelist, 'kwe_list'):
+               rs += "\t" + GetKweSummary.header + "\n"
+               rs += "\t" + GetKweSummary(kwe) + "\n"
+
+       if kwq.kw_turnstile:
+               rs += GetTurnstileSummary.header + "\n"
+               rs += GetTurnstileSummary(Cast(kwq.kw_turnstile, "struct turnstile *"))
+
+       return rs
+
+@lldb_type_summary(['ksyn_waitq_element *', 'ksyn_waitq_element_t'])
+@header("{:<20s} {:<20s} {:<10s} {:<10s} {:<20s} {:<20s}".format('kwe', 'kwq', 'lseq', 'state', 'uthread', 'thread'))
+def GetKweSummary(kwe):
+       format = "{:<#20x} {:<#20x} {:<10s} {:<10s} {:<#20x} {:<#20x}"
+       kwe = Cast(kwe, 'struct ksyn_waitq_element *')
+       state = ""
+       if kwe.kwe_state == 1:
+               state = "INWAIT"
+       elif kwe.kwe_state == 2:
+               state = "PPOST"
+       elif kwe.kwe_state == 3:
+               state = "BROAD"
+       else:
+               state = "{:#10x}".format(kwe.kwe_state)
+       return format.format(kwe, kwe.kwe_kwqqueue, GetLSeqSummary(kwe.kwe_lockseq), state, kwe.kwe_uth, kwe.kwe_thread)
+
+@header("{0: <24s} {1: <24s} {2: <24s}".format('thread', 'thread_id', 'uthread'))
+def GetPthreadSummary(thread):
+       format = "{0: <24s} {1: <24s} {2: <24s}"
+
+       threadstr = str("{0: <#020x}".format(thread))
+       if int(thread.static_param):
+               threadstr += "[WQ]"
+
+       uthread = Cast(thread.uthread, "uthread_t")
+       uthreadstr = str("{0: <#020x}".format(uthread))
+
+
+       return format.format(threadstr, hex(thread.thread_id), uthreadstr)
+
+@header("{0: <24s} {1: <24s} {2: <10s} {3: <10s} {4: <10s} {5: <10s} {6: <10s}".format('proc', 'wq', 'sched', 'req', 'idle', 'wq_flags', 'wq_lflags'))
+def GetPthreadWorkqueueSummary(wq):
+       format = "{0: <24s} {1: <24s} {2: <10d} {3: <10d} {4: <10d} {5: <10s} {6: <10s}"
+       procstr = str("{0: <#020x}".format(wq.wq_proc))
+       wqstr = str("{0: <#020x}".format(wq))
+       
+       flags = []
+       if wq.wq_flags & 0x1:
+               flags.append("I")
+       if wq.wq_flags & 0x2:
+               flags.append("R")
+       if wq.wq_flags & 0x4:
+               flags.append("E")
+               
+       wqflags = []
+       if wq.wq_lflags & 0x1:
+               wqflags.append("B")
+       if wq.wq_lflags & 0x2:
+               wqflags.append("W")
+       if wq.wq_lflags & 0x4:
+               wqflags.append("C")
+       if wq.wq_lflags & 0x8:
+               wqflags.append("L")
+       
+       return format.format(procstr, wqstr, wq.wq_threads_scheduled, wq.wq_reqcount, wq.wq_thidlecount, "".join(flags), "".join(wqflags))
+
+@header("{0: <24s} {1: <5s} {2: <5s} {3: <5s} {4: <5s} {5: <5s} {6: <5s} {7: <5s}".format('category', 'uint', 'uinit', 'lgcy', 'util', 'bckgd', 'maint', 'event'))
+def GetPthreadWorkqueueDetail(wq):
+       format = "  {0: <22s} {1: <5d} {2: <5d} {3: <5d} {4: <5d} {5: <5d} {6: <5d} {7: <5d}"
+       # requests
+       schedstr = format.format('scheduled', wq.wq_thscheduled_count[0], wq.wq_thscheduled_count[1], wq.wq_thscheduled_count[2], wq.wq_thscheduled_count[3], wq.wq_thscheduled_count[4], wq.wq_thscheduled_count[5], wq.wq_thscheduled_count[6])
+       activestr = format.format('active', wq.wq_thactive_count[0], wq.wq_thactive_count[1], wq.wq_thactive_count[2], wq.wq_thactive_count[3], wq.wq_thactive_count[4], wq.wq_thactive_count[5], wq.wq_thactive_count[6])
+       return "\n".join([schedstr, activestr])
+
+@lldb_command('showthreadpsynch')
+def PthreadCurrentMutex(cmd_args=None):
+       """
+       display information about a thread's pthread state
+       Syntax: (lldb) showthreadpsync <thread_t>
+       """
+       if not cmd_args:
+               raise ArgumentError("No arguments passed")
+
+       thread = kern.GetValueFromAddress(cmd_args[0], "thread_t")
+       print GetPthreadSummary.header
+       print GetPthreadSummary(thread)
+
+       uthread = Cast(thread.uthread, "uthread_t")
+       kwe = Cast(addressof(uthread.uu_save.uus_kwe), 'struct ksyn_waitq_element *')
+       if not kwe or not kwe.kwe_kwqqueue:
+               print GetKweSummary.header
+               print GetKweSummary(kwe)
+       else:
+               print GetKwqSummary.header
+               print GetKwqSummary(kwe.kwe_kwqqueue)
+
+@lldb_command('showpthreadkwq')
+def PthreadShowKsynQueue(cmd_args=None):
+       """
+       display information about a pthread ksyn_wait_queue_t
+       Syntax: (lldb) showpthreadkwq <ksyn_wait_queue_t>
+       """
+       if not cmd_args:
+               raise ArgumentError("No arguments passed")
+
+       kwq = kern.GetValueFromAddress(cmd_args[0], "ksyn_wait_queue_t")
+       print GetKwqSummary.header
+       print GetKwqSummary(kwq)
+
+@lldb_command('showpthreadkwe')
+def PthreadShowKsynElement(cmd_args=None):
+       """
+       display information about a thread's ksyn_waitq_element
+       Syntax: (lldb) showpthreadkwe <ksyn_waitq_element_t>    
+       """
+       if not cmd_args:
+               raise ArgumentError("No arguments passed")
+
+       kwe = kern.GetValueFromAddress(cmd_args[0], "struct ksyn_waitq_element *")
+       print GetKweSummary.header
+       print GetKweSummary(kwe)
+
+@lldb_command('showpthreadworkqueue')
+def ShowPthreadWorkqueue(cmd_args=None):
+       """
+       display information about a processes' pthread workqueue
+       Syntax: (lldb) showpthreadworkqueue <proc_t>
+       """
+       
+       if not cmd_args:
+               raise ArgumentError("No arguments passed")
+               
+       proc = kern.GetValueFromAddress(cmd_args[0], "proc_t")
+       wq = Cast(proc.p_wqptr, "struct workqueue *");
+       
+       print GetPthreadWorkqueueSummary.header
+       print GetPthreadWorkqueueSummary(wq)
+       
+       print GetPthreadWorkqueueDetail.header
+       print GetPthreadWorkqueueDetail(wq)
+
+def IterateTAILQ_HEAD(headval, element_name):
+    """ iterate over a TAILQ_HEAD in kernel. refer to bsd/sys/queue.h
+        params:
+            headval     - value : value object representing the head of the list
+            element_name- str          :  string name of the field which holds the list links.
+        returns:
+            A generator does not return. It is used for iterating.
+            value : an object that is of type as headval->tqh_first. Always a pointer object
+        example usage:
+          list_head = kern.GetGlobalVariable('mountlist')
+          for entryobj in IterateTAILQ_HEAD(list_head, 'mnt_list'):
+            print GetEntrySummary(entryobj)
+    """
+    iter_val = headval.tqh_first
+    while unsigned(iter_val) != 0 :
+        yield iter_val
+        iter_val = iter_val.__getattr__(element_name).tqe_next
+    #end of yield loop
+
+def __lldb_init_module(debugger, internal_dict):
+       pass