in tools/lldbmacros/kcdata.py [0:0]
def SaveStackshotReport(j, outfile_name, incomplete):
import time
from operator import itemgetter, attrgetter
ss = j.get('kcdata_stackshot')
if not ss:
print "No KCDATA_BUFFER_BEGIN_STACKSHOT object found. Skipping writing report."
return
timestamp = ss.get('usecs_since_epoch')
try:
timestamp = time.strftime("%Y-%m-%d %H:%M:%S +0000",time.gmtime(timestamp / 1000000 if timestamp else None))
except ValueError, e:
print "couldn't convert timestamp:", str(e)
timestamp = None
os_version = ss.get('osversion', 'Unknown')
timebase = ss.get('mach_timebase_info', {"denom": 1, "numer": 1})
sc_note = None
extra_note = None
dsc_common = None
shared_cache_info = ss.get('shared_cache_dyld_load_info')
if shared_cache_info:
shared_cache_base_addr = shared_cache_info['imageSlidBaseAddress']
# If we have a slidFirstMapping and it's >= base_address, use that.
#
# Otherwise we're processing a stackshot from before the slidFirstMapping
# field was introduced and corrected. On ARM the SlidBaseAddress is the
# same, but on x86 it's off by 0x20000000. We use 'X86_64' in the
# kernel version string plus checking kern_page_size == 4k' as
# proxy for x86_64, and only adjust SlidBaseAddress if the unslid
# address is precisely the expected incorrect value.
#
is_intel = ('X86_64' in ss.get('osversion', "") and
ss.get('kernel_page_size', 0) == 4096)
slidFirstMapping = shared_cache_info.get(SC_SLID_FIRSTMAPPING_KEY, -1);
if slidFirstMapping >= shared_cache_base_addr:
shared_cache_base_addr = slidFirstMapping
sc_note = "base-accurate"
elif is_intel:
sc_slide = shared_cache_info['imageLoadAddress']
if (shared_cache_base_addr - sc_slide) == 0x7fff00000000:
shared_cache_base_addr += 0x20000000
sc_note = "base-x86-adjusted"
extra_note = "Shared cache base adjusted for x86. "
else:
sc_note = "base-x86-unknown"
dsc_common = [format_uuid(shared_cache_info['imageUUID']),
shared_cache_base_addr, "S" ]
print "Shared cache UUID found from the binary data is <%s> " % str(dsc_common[0])
dsc_layout = ss.get('system_shared_cache_layout')
dsc_libs = []
if dsc_layout:
print "Found in memory system shared cache layout with {} images".format(len(dsc_layout))
slide = ss.get('shared_cache_dyld_load_info')['imageLoadAddress']
for image in dsc_layout:
dsc_libs.append([format_uuid(image['imageUUID']), image['imageLoadAddress'] + slide, "C"])
AllImageCatalog = []
obj = {}
obj["kernel"] = os_version
if timestamp is not None:
obj["date"] = timestamp
obj["reason"] = "kernel panic stackshot"
obj["incident"] = "ABCDEFGH-1234-56IJ-789K-0LMNOPQRSTUV"
obj["crashReporterKey"] = "12ab34cd45aabbccdd6712ab34cd45aabbccdd67"
obj["bootArgs"] = ss.get('boot_args','')
obj["frontmostPids"] = [0]
obj["exception"] = "0xDEADF157"
obj["processByPid"] = {}
if sc_note is not None:
obj["sharedCacheNote"] = sc_note
if incomplete:
obj["reason"] = "!!!INCOMPLETE!!! kernel panic stackshot"
obj["notes"] = "This stackshot report generated from incomplete data! Some information is missing! "
if extra_note is not None:
obj["notes"] = obj.get("notes", "") + extra_note
processByPid = obj["processByPid"]
ssplist = ss.get('task_snapshots', {})
kern_load_info = []
if "0" in ssplist:
kc_uuid = ssplist["0"].get('kernelcache_load_info', None)
if kc_uuid:
kernelcache_uuid = [format_uuid(kc_uuid['imageUUID']), kc_uuid['imageLoadAddress'], "U" ]
kern_load_info.append(kernelcache_uuid)
kl_infos = ssplist["0"].get("dyld_load_info", [])
for dlinfo in kl_infos:
kern_load_info.append([format_uuid(dlinfo['imageUUID']), dlinfo['imageLoadAddress'], "K"])
kl_infos_text_exec = ssplist["0"].get("dyld_load_info_text_exec", [])
for dlinfo in kl_infos_text_exec:
kern_load_info.append([format_uuid(dlinfo['imageUUID']), dlinfo['imageLoadAddress'], "T"])
for pid,piddata in ssplist.iteritems():
processByPid[str(pid)] = {}
tsnap = processByPid[str(pid)]
pr_lib_dsc = dsc_common
if 'shared_cache_dyld_load_info' in tsnap:
if 'imageSlidBaseAddress' in tsnap.get('shared_cache_dyld_load_info'):
shared_cache_base_addr = tsnap.get('shared_cache_dyld_load_info')['imageSlidBaseAddress']
else:
print "Specific task shared cache format does not include slid shared cache base address. Skipping writing report."
return
pr_lib_dsc = [format_uuid(tsnap.get('shared_cache_dyld_load_info')['imageUUID']),
tsnap.get('shared_cache_dyld_load_info')['imageSlidBaseAddress'],
"S"]
pr_libs = []
if len(dsc_libs) == 0 and pr_lib_dsc:
pr_libs.append(pr_lib_dsc)
_lib_type = "P"
if int(pid) == 0:
_lib_type = "K"
pr_libs = []
else:
for dlinfo in piddata.get('dyld_load_info',[]):
pr_libs.append([format_uuid(dlinfo['imageUUID']), dlinfo['imageLoadAddress'], _lib_type])
pr_libs.extend(kern_load_info)
pr_libs.extend(dsc_libs)
pr_libs.sort(key=itemgetter(1))
if 'task_snapshot' not in piddata:
continue
tasksnap = piddata['task_snapshot']
tsnap["pid"] = tasksnap["ts_pid"]
if 'ts_asid' in piddata:
tsnap["asid"] = piddata["ts_asid"]
if 'ts_pagetable' in piddata:
pagetables = []
for tte in piddata["ts_pagetable"]:
pagetables.append(tte)
tsnap["pageTables"] = pagetables
tsnap["residentMemoryBytes"] = tasksnap["ts_task_size"]
tsnap["timesDidThrottle"] = tasksnap["ts_did_throttle"]
tsnap["systemTimeTask"] = GetSecondsFromMATime(tasksnap["ts_system_time_in_terminated_th"], timebase)
tsnap["pageIns"] = tasksnap["ts_pageins"]
tsnap["pageFaults"] = tasksnap["ts_faults"]
tsnap["userTimeTask"] = GetSecondsFromMATime(tasksnap[ "ts_user_time_in_terminated_thre"], timebase)
tsnap["procname"] = tasksnap["ts_p_comm"]
tsnap["copyOnWriteFaults"] = tasksnap["ts_cow_faults"]
tsnap["timesThrottled"] = tasksnap["ts_was_throttled"]
tsnap["threadById"] = {}
threadByID = tsnap["threadById"]
thlist = piddata.get('thread_snapshots', {})
for tid,thdata in thlist.iteritems():
threadByID[str(tid)] = {}
thsnap = threadByID[str(tid)]
if "thread_snapshot" not in thdata:
print "Found broken thread state for thread ID: %s." % tid
break
threadsnap = thdata["thread_snapshot"]
thsnap["userTime"] = GetSecondsFromMATime(threadsnap["ths_user_time"], timebase)
thsnap["id"] = threadsnap["ths_thread_id"]
thsnap["basePriority"] = threadsnap["ths_base_priority"]
thsnap["systemTime"] = threadsnap["ths_sys_time"]
thsnap["schedPriority"] = threadsnap["ths_sched_priority"]
thsnap["state"] = GetStateDescription(threadsnap['ths_state'])
thsnap["qosEffective"] = threadsnap["ths_eqos"]
thsnap["qosRequested"] = threadsnap["ths_rqos"]
if "pth_name" in thdata:
thsnap["name"] = thdata["pth_name"];
if threadsnap['ths_continuation']:
thsnap["continuation"] = GetSymbolInfoForFrame(AllImageCatalog, pr_libs, threadsnap['ths_continuation'])
if "kernel_stack_frames" in thdata:
kuserframes = []
for f in thdata["kernel_stack_frames"]:
kuserframes.append(GetSymbolInfoForFrame(AllImageCatalog, pr_libs, f['lr']))
thsnap["kernelFrames"] = kuserframes
if "user_stack_frames" in thdata:
uframes = []
for f in thdata["user_stack_frames"]:
uframes.append(GetSymbolInfoForFrame(AllImageCatalog, pr_libs, f['lr']))
thsnap["userFrames"] = uframes
if "user_stacktop" in thdata:
(address,) = struct.unpack("<Q", struct.pack("B"*8, *thdata["user_stacktop"]["stack_contents"]))
thsnap["userStacktop"] = GetSymbolInfoForFrame(AllImageCatalog, pr_libs, address)
if threadsnap['ths_wait_event']:
thsnap["waitEvent"] = GetSymbolInfoForFrame(AllImageCatalog, pr_libs, threadsnap['ths_wait_event'])
if 'thread_waitinfo' in piddata and 'thread_turnstileinfo' in piddata:
tsnap['waitInfo'] = formatWaitInfoWithTurnstiles(piddata['thread_waitinfo'] , piddata['thread_turnstileinfo'])
elif 'thread_waitinfo' in piddata:
tsnap['waitInfo'] = map(formatWaitInfo, piddata['thread_waitinfo'])
obj['binaryImages'] = AllImageCatalog
if outfile_name == '-':
fh = sys.stdout
else:
fh = open(outfile_name, "w")
header = {}
header['bug_type'] = 288
if timestamp is not None:
header['timestamp'] = timestamp
header['os_version'] = os_version
fh.write(json.dumps(header))
fh.write("\n")
fh.write(json.dumps(obj, sort_keys=False, indent=2, separators=(',', ': ')))
fh.close()