4 // Some of these tests here verify that kdd is able to parse old
5 // kcdata files and generate the correct output. To do so, we include
6 // compressed versions of the raw kcdata and as well as the expected
9 // NOTE: If you're adding sample data/plist files, you'll need to first
10 // add them to the project and then make sure each is part of the
13 // Other tests verify the expected behavior of libkdd for certain
21 // Swift's bridging to uuid_t is awkward.
23 func nsuuid2uuid_t(_ nsuuid : NSUUID) -> uuid_t {
24 let dat = nsuuid2array(nsuuid)
25 return nsarray2uuid(dat)
28 func nsarray2uuid(_ a : [Int]) -> uuid_t {
29 return uuid_t(UInt8(a[0]),
47 func nsuuid2array(_ uuid: NSUUID) -> [Int] {
49 let ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: 16)
51 defer { ptr.deallocate(capacity:16) }
55 ret.append(Int(ptr[i]))
60 func decompress(_ data:NSData) throws -> NSData {
61 var stream = z_stream(next_in: nil, avail_in: 0, total_in: 0, next_out: nil, avail_out: 0, total_out: 0, msg: nil, state: nil, zalloc: nil, zfree: nil, opaque: nil, data_type: 0, adler: 0, reserved: 0)
63 let bufsize : Int = 1000
64 let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufsize)
65 defer { buffer.deallocate(capacity:bufsize) }
66 let output = NSMutableData()
67 stream.next_out = buffer
68 stream.avail_out = UInt32(bufsize)
69 stream.next_in = UnsafeMutablePointer(mutating:data.bytes.assumingMemoryBound(to:Bytef.self))
70 stream.avail_in = UInt32(data.length)
71 inflateInit2_(&stream, 16+MAX_WBITS, ZLIB_VERSION, Int32(MemoryLayout<z_stream>.size))
74 let z = inflate(&stream, Z_NO_FLUSH);
75 if (z == Z_OK || z == Z_STREAM_END) {
76 output.append(buffer, length: bufsize - Int(stream.avail_out))
77 stream.avail_out = UInt32(bufsize)
78 stream.next_out = buffer
79 if (z == Z_STREAM_END) {
83 throw NSError(domain: "zlib", code: Int(z), userInfo: nil)
89 extension Dictionary {
90 func value(forKeyPath s:String) -> Any? {
91 return (self as NSDictionary).value(forKeyPath:s)
96 class Tests: XCTestCase {
98 override func setUp() {
100 continueAfterFailure = false
103 override func tearDown() {
104 // Put teardown code here. This method is called after the invocation of each test method in the class.
108 func parseBuffer(_ buffer:NSData) throws -> [AnyHashable:Any] {
110 guard let dict = parseKCDataBuffer(UnsafeMutablePointer(mutating:buffer.bytes.assumingMemoryBound(to:UInt8.self)), UInt32(buffer.length), &error)
112 XCTAssert(error != nil)
118 func testPaddingFlags(_ pad : Int) {
119 let buffer = NSMutableData(capacity:1000)!
121 var item = kcdata_item()
123 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
126 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
128 item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
129 item.flags = UInt64(pad)
130 item.size = UInt32(MemoryLayout<dyld_uuid_info_32>.size)
131 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
133 let uuid = NSUUID(uuidString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
135 var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
136 buffer.append(&payload, length:MemoryLayout<dyld_uuid_info_32>.size)
138 item.type = KCDATA_TYPE_BUFFER_END
141 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
143 guard let dict = try? self.parseBuffer(buffer)
144 else { XCTFail(); return; }
146 var uuidarray = nsuuid2array(uuid)
148 uuidarray.removeLast()
151 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info.imageLoadAddress") as? Int == 42)
152 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info.imageUUID") as! [Int] == uuidarray)
155 func testPaddingFlags() {
160 func testBootArgs() {
161 let s = "hello, I am some boot args"
163 let buffer = NSMutableData(capacity:1000)!
165 var item = kcdata_item()
167 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
170 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
172 item.type = UInt32(STACKSHOT_KCTYPE_BOOTARGS)
174 item.size = UInt32(s.utf8.count + 1)
175 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
176 s.utf8CString.withUnsafeBufferPointer({
177 buffer.append($0.baseAddress!, length:s.utf8.count + 1)
179 item.type = KCDATA_TYPE_BUFFER_END
182 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
184 guard let dict = try? self.parseBuffer(buffer) else { XCTFail(); return; }
185 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.boot_args") as? String == s)
188 func testBootArgsMissingNul() {
189 let s = "hello, I am some boot args"
191 let buffer = NSMutableData(capacity:1000)!
193 var item = kcdata_item()
195 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
198 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
200 item.type = UInt32(STACKSHOT_KCTYPE_BOOTARGS)
202 item.size = UInt32(s.utf8.count)
203 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
204 s.utf8CString.withUnsafeBufferPointer({
205 buffer.append($0.baseAddress!, length:s.utf8.count)
208 item.type = KCDATA_TYPE_BUFFER_END
211 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
213 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
216 func testLoadInfo() {
217 let buffer = NSMutableData(capacity:1000)!
219 var item = kcdata_item()
221 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
224 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
226 item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
228 item.size = UInt32(MemoryLayout<dyld_uuid_info_32>.size)
229 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
231 let uuid = NSUUID(uuidString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
233 var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
234 buffer.append(&payload, length:MemoryLayout<dyld_uuid_info_32>.size)
236 item.type = KCDATA_TYPE_BUFFER_END
239 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
241 guard let dict = try? self.parseBuffer(buffer)
242 else { XCTFail(); return; }
244 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info.imageLoadAddress") as? Int == 42)
245 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info.imageUUID") as! [Int] == nsuuid2array(uuid))
248 func testLoadInfoWrongSize() {
249 // test what happens when a struct size is short
251 let buffer = NSMutableData(capacity:1000)!
253 var item = kcdata_item()
255 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
258 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
260 item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
262 item.size = UInt32(MemoryLayout<dyld_uuid_info_32>.size) - 1
263 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
265 let uuid = NSUUID(uuidString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
267 var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
268 buffer.append(&payload, length:MemoryLayout<dyld_uuid_info_32>.size - 1)
270 item.type = KCDATA_TYPE_BUFFER_END
273 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
275 guard let dict = try? self.parseBuffer(buffer)
276 else { XCTFail(); return; }
277 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info.imageLoadAddress") as? Int == 42)
278 var uuidarray = nsuuid2array(uuid)
279 uuidarray.removeLast()
280 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info.imageUUID") as! [Int] == uuidarray)
283 func testLoadInfoWayWrongSize() {
284 // test what happens when a struct size is short
286 let buffer = NSMutableData(capacity:1000)!
288 var item = kcdata_item()
290 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
293 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
295 item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
297 item.size = UInt32(MemoryLayout<dyld_uuid_info_32>.size) - 16
298 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
300 let uuid = NSUUID(uuidString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
302 var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
303 buffer.append(&payload, length:MemoryLayout<dyld_uuid_info_32>.size - 16)
305 item.type = KCDATA_TYPE_BUFFER_END
308 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
309 guard let dict = try? self.parseBuffer(buffer)
310 else { XCTFail(); return; }
311 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info.imageLoadAddress") as? Int == 42)
312 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info.imageUUID") == nil)
315 func testLoadInfoPreposterousWrongSize() {
316 // test what happens when a struct size is short
318 let buffer = NSMutableData(capacity:1000)!
320 var item = kcdata_item()
322 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
325 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
327 item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
329 item.size = UInt32(1)
330 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
332 var payload = UInt8(42)
333 buffer.append(&payload, length:1)
335 item.type = KCDATA_TYPE_BUFFER_END
338 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
340 guard let dict = try? self.parseBuffer(buffer)
341 else { XCTFail(); return; }
342 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info.imageLoadAddress") == nil)
343 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info.imageUUID") == nil)
347 func testNewArray(n : Int, pad : Int) {
348 let buffer = NSMutableData(capacity:1000)!
349 var item = kcdata_item()
351 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
354 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
356 item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0) + UInt32(pad)
357 item.flags = UInt64(STACKSHOT_KCTYPE_DONATING_PIDS) << 32 | UInt64(n)
358 item.size = UInt32(n * MemoryLayout<UInt32>.size + pad)
359 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
362 var payload = UInt32(42 * i)
363 buffer.append(&payload, length:MemoryLayout<UInt32>.size)
367 var payload = UInt8(42-i)
368 buffer.append(&payload, length:MemoryLayout<UInt8>.size)
371 item.type = KCDATA_TYPE_BUFFER_END
374 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
376 guard let dict = try? self.parseBuffer(buffer)
377 else { XCTFail(); return; }
378 XCTAssert((dict.value(forKeyPath:"kcdata_crashinfo.donating_pids") as! [Any]).count == n)
380 let x = dict["kcdata_crashinfo"] as? NSDictionary
381 let y = x?["donating_pids"] as? NSArray
382 XCTAssert((y?[i]) as? Int == 42 * i)
386 func testNewArrays() {
387 self.testNewArray(n:0,pad:0)
390 self.testNewArray(n:i, pad:pad)
396 func testArrayLoadInfo(n : Int) {
397 let buffer = NSMutableData(capacity:1000)!
398 var item = kcdata_item()
400 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
403 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
405 item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
406 item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
407 item.size = UInt32(n * MemoryLayout<dyld_uuid_info_32>.size)
408 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
410 let uuid = NSUUID(uuidString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
414 var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid))
416 buffer.append(&payload, length:MemoryLayout<dyld_uuid_info_32>.size)
419 item.type = KCDATA_TYPE_BUFFER_END
422 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
424 guard let dict = try? self.parseBuffer(buffer)
425 else { XCTFail(); return; }
426 XCTAssert((dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info") as! [Any]).count == n)
428 guard let loadinfo = dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info") as? [Any]
429 else { XCTFail(); return; }
430 guard let loadinfo_i = loadinfo[i] as? [AnyHashable:Any]
431 else { XCTFail(); return; }
432 XCTAssert(loadinfo_i["imageLoadAddress"] as? Int == 42 + i)
433 XCTAssert(loadinfo_i["imageUUID"] as! [Int] == nsuuid2array(uuid))
437 func testArrayLoadInfo() {
439 testArrayLoadInfo(n: n)
443 func testArrayLoadInfoWrongSize() {
444 // test what happens when array element sizes are too short
448 let buffer = NSMutableData(capacity:1000)!
449 var item = kcdata_item()
451 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
454 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
456 item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
457 item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
458 item.size = UInt32(n * (MemoryLayout<dyld_uuid_info_32>.size - wrong))
459 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
461 let uuid = NSUUID(uuidString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
464 var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid))
465 buffer.append(&payload, length:MemoryLayout<dyld_uuid_info_32>.size-wrong)
468 item.type = KCDATA_TYPE_BUFFER_END
471 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
472 var uuidarray = nsuuid2array(uuid)
473 uuidarray.removeLast()
475 guard let dict = try? self.parseBuffer(buffer)
476 else { XCTFail(); return; }
477 XCTAssert((dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info") as! [Any]).count == n)
479 guard let loadinfo = dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info") as? [Any]
480 else { XCTFail(); return; }
481 guard let loadinfo_i = loadinfo[i] as? [AnyHashable:Any]
482 else { XCTFail(); return; }
483 XCTAssert(loadinfo_i["imageLoadAddress"] as? Int == 42 + i)
484 XCTAssert(loadinfo_i["imageUUID"] as! [Int] == uuidarray)
490 func testArrayLoadInfoWayWrongSize() {
491 // test what happens when array element sizes are too short
495 let buffer = NSMutableData(capacity:1000)!
496 var item = kcdata_item()
498 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
501 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
503 item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
504 item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
505 item.size = UInt32(n * (MemoryLayout<dyld_uuid_info_32>.size - wrong))
506 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
508 let uuid = NSUUID(uuidString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
511 var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid))
512 buffer.append(&payload, length:MemoryLayout<dyld_uuid_info_32>.size-wrong)
515 item.type = KCDATA_TYPE_BUFFER_END
518 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
521 guard let dict = try? self.parseBuffer(buffer)
522 else { XCTFail(); return; }
523 XCTAssert((dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info") as! [Any]).count == n)
525 guard let loadinfo = dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info") as? [Any]
526 else { XCTFail(); return; }
527 guard let loadinfo_i = loadinfo[i] as? [AnyHashable:Any]
528 else { XCTFail(); return; }
529 XCTAssert(loadinfo_i["imageLoadAddress"] as? Int == 42 + i)
530 XCTAssert(loadinfo_i["imageUUID"] == nil)
534 func testArrayLoadInfoPreposterouslyWrongSize() {
535 // test what happens when array element sizes are too short
539 let buffer = NSMutableData(capacity:1000)!
540 var item = kcdata_item()
542 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
545 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
547 item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
548 item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
549 item.size = UInt32(n * (MemoryLayout<dyld_uuid_info_32>.size - wrong))
550 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
553 var payload = UInt8(42*i)
554 buffer.append(&payload, length:1)
557 item.type = KCDATA_TYPE_BUFFER_END
560 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
563 guard let dict = try? self.parseBuffer(buffer)
564 else { XCTFail(); return; }
565 XCTAssert((dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info") as! [Any]).count == n)
567 guard let loadinfo = dict.value(forKeyPath:"kcdata_crashinfo.dyld_load_info") as? [Any]
568 else { XCTFail(); return; }
569 guard let loadinfo_i = loadinfo[i] as? [AnyHashable:Any]
570 else { XCTFail(); return; }
571 XCTAssert(loadinfo_i["imageLoadAddress"] == nil)
572 XCTAssert(loadinfo_i["imageUUID"] == nil)
578 let buffer = NSMutableData(capacity:1000)!
580 var item = kcdata_item()
582 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
585 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
587 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
589 item.size = UInt32(MemoryLayout<UInt64>.size)
590 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
592 var payload : UInt64 = 42
593 buffer.append(&payload, length:MemoryLayout<UInt64>.size)
595 item.type = KCDATA_TYPE_BUFFER_END
598 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
600 let buffer2 = NSMutableData(capacity:1000)!
602 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
605 buffer2.append(&item, length: MemoryLayout<kcdata_item>.size)
607 item.type = UInt32(KCDATA_TYPE_NESTED_KCDATA)
609 item.size = UInt32(buffer.length)
610 buffer2.append(&item, length: MemoryLayout<kcdata_item>.size)
611 buffer2.append(buffer as Data)
613 item.type = KCDATA_TYPE_BUFFER_END
616 buffer2.append(&item, length: MemoryLayout<kcdata_item>.size)
618 guard let dict2 = try? self.parseBuffer(buffer2)
619 else { XCTFail(); return; }
621 XCTAssert(dict2.value(forKeyPath:"kcdata_crashinfo.kcdata_crashinfo.crashed_threadid") as? Int == 42)
625 func testReadThreadid() {
626 let buffer = NSMutableData(capacity:1000)!
628 var item = kcdata_item()
630 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
633 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
635 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
637 item.size = UInt32(MemoryLayout<UInt64>.size)
638 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
640 var payload : UInt64 = 42
641 buffer.append(&payload, length:MemoryLayout<UInt64>.size)
643 item.type = KCDATA_TYPE_BUFFER_END
646 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
648 guard let dict = try? self.parseBuffer(buffer)
649 else { XCTFail(); return; }
651 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.crashed_threadid") as? Int == 42)
655 func testRepeatedKey() {
656 // test a repeated item of the same key causes error
658 let buffer = NSMutableData(capacity:1000)!
660 var item = kcdata_item()
662 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
665 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
667 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
669 item.size = UInt32(MemoryLayout<UInt64>.size)
670 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
672 var payload : UInt64 = 42
673 buffer.append(&payload, length:MemoryLayout<UInt64>.size)
675 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
677 item.size = UInt32(MemoryLayout<UInt64>.size)
678 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
681 buffer.append(&payload, length:MemoryLayout<UInt64>.size)
683 item.type = KCDATA_TYPE_BUFFER_END
686 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
688 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
692 func testContainer() {
693 let buffer = NSMutableData(capacity:1000)!
695 var item = kcdata_item()
696 var payload64 : UInt64
697 var payload32 : UInt32
699 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
702 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
704 item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
706 item.size = UInt32(MemoryLayout<UInt32>.size)
707 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
708 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
709 buffer.append(&payload32, length:MemoryLayout<UInt32>.size)
711 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
713 item.size = UInt32(MemoryLayout<UInt64>.size)
714 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
716 buffer.append(&payload64, length:MemoryLayout<UInt64>.size)
718 item.type = UInt32(KCDATA_TYPE_CONTAINER_END)
720 item.size = UInt32(MemoryLayout<UInt32>.size)
721 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
722 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
723 buffer.append(&payload32, length:MemoryLayout<UInt32>.size)
726 item.type = KCDATA_TYPE_BUFFER_END
729 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
731 guard let dict = try? self.parseBuffer(buffer)
732 else { XCTFail(); return; }
734 XCTAssert(dict.value(forKeyPath: "kcdata_crashinfo.task_snapshots.0.crashed_threadid") as? Int == 42)
737 func testRepeatedContainer() {
738 //repeated container of same name and key shoudl fail
740 let buffer = NSMutableData(capacity:1000)!
742 var item = kcdata_item()
743 var payload64 : UInt64
744 var payload32 : UInt32
746 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
749 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
751 item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
753 item.size = UInt32(MemoryLayout<UInt32>.size)
754 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
755 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
756 buffer.append(&payload32, length:MemoryLayout<UInt32>.size)
758 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
760 item.size = UInt32(MemoryLayout<UInt64>.size)
761 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
763 buffer.append(&payload64, length:MemoryLayout<UInt64>.size)
765 item.type = UInt32(KCDATA_TYPE_CONTAINER_END)
767 item.size = UInt32(MemoryLayout<UInt32>.size)
768 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
769 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
770 buffer.append(&payload32, length:MemoryLayout<UInt32>.size)
773 item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
775 item.size = UInt32(MemoryLayout<UInt32>.size)
776 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
777 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
778 buffer.append(&payload32, length:MemoryLayout<UInt32>.size)
780 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
782 item.size = UInt32(MemoryLayout<UInt64>.size)
783 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
785 buffer.append(&payload64, length:MemoryLayout<UInt64>.size)
787 item.type = UInt32(KCDATA_TYPE_CONTAINER_END)
789 item.size = UInt32(MemoryLayout<UInt32>.size)
790 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
791 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
792 buffer.append(&payload32, length:MemoryLayout<UInt32>.size)
794 item.type = KCDATA_TYPE_BUFFER_END
797 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
799 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
803 func testContainerNoEnd() {
804 let buffer = NSMutableData(capacity:1000)!
806 var item = kcdata_item()
807 var payload64 : UInt64
808 var payload32 : UInt32
810 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
813 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
815 item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
817 item.size = UInt32(MemoryLayout<UInt32>.size)
818 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
819 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
820 buffer.append(&payload32, length:MemoryLayout<UInt32>.size)
822 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
824 item.size = UInt32(MemoryLayout<UInt64>.size)
825 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
827 buffer.append(&payload64, length:MemoryLayout<UInt64>.size)
829 item.type = KCDATA_TYPE_BUFFER_END
832 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
834 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
837 func testContainerNoEndNoEnd() {
838 let buffer = NSMutableData(capacity:1000)!
840 var item = kcdata_item()
841 var payload64 : UInt64
842 var payload32 : UInt32
844 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
847 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
849 item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
851 item.size = UInt32(MemoryLayout<UInt32>.size)
852 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
853 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
854 buffer.append(&payload32, length:MemoryLayout<UInt32>.size)
856 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
858 item.size = UInt32(MemoryLayout<UInt64>.size)
859 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
861 buffer.append(&payload64, length:MemoryLayout<UInt64>.size)
863 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
869 let buffer = NSMutableData(capacity:1000)!
871 var item = kcdata_item()
873 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
876 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
878 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
880 item.size = UInt32(MemoryLayout<UInt64>.size)
881 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
883 var payload : UInt64 = 42
884 buffer.append(&payload, length:MemoryLayout<UInt64>.size)
886 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
890 func testCrazySize() {
891 let buffer = NSMutableData(capacity:1000)!
893 var item = kcdata_item()
895 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
898 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
900 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
903 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
905 var payload : UInt64 = 42
906 buffer.append(&payload, length:MemoryLayout<UInt64>.size)
908 item.type = KCDATA_TYPE_BUFFER_END
911 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
913 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
916 func testReadRepeatedArray() {
917 // repeated arrays should be concatenated
920 let buffer = NSMutableData(capacity:1000)!
922 var item = kcdata_item()
924 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
927 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
929 item.type = UInt32(KCDATA_TYPE_ARRAY)
930 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
931 item.size = UInt32(n * MemoryLayout<UInt64>.size)
932 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
935 var payload : UInt64 = UInt64(i)
936 buffer.append(&payload, length:MemoryLayout<UInt64>.size)
939 item.type = UInt32(KCDATA_TYPE_ARRAY)
940 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
941 item.size = UInt32(n * MemoryLayout<UInt64>.size)
942 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
945 var payload : UInt64 = UInt64(i)
946 buffer.append(&payload, length:MemoryLayout<UInt64>.size)
949 item.type = KCDATA_TYPE_BUFFER_END
952 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
954 guard let dict = try? self.parseBuffer(buffer)
955 else { XCTFail(); return }
957 XCTAssert( 2*n == (dict.value(forKeyPath:"kcdata_crashinfo.crashed_threadid") as! [Any]).count)
959 let x = dict["kcdata_crashinfo"] as? NSDictionary
960 let y = x?["crashed_threadid"] as? NSArray
961 XCTAssert((y?[i]) as? Int == i % n)
965 func testReadThreadidArray(n : Int, pad : Int) {
966 let buffer = NSMutableData(capacity:1000)!
968 var item = kcdata_item()
970 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
973 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
975 item.type = UInt32(KCDATA_TYPE_ARRAY)
976 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
977 item.size = UInt32(n * MemoryLayout<UInt64>.size + pad)
978 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
981 var payload : UInt64 = UInt64(i)
982 buffer.append(&payload, length:MemoryLayout<UInt64>.size)
986 var payload : UInt8 = 0
987 buffer.append(&payload, length:1)
990 item.type = KCDATA_TYPE_BUFFER_END
993 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
995 guard let dict = try? self.parseBuffer(buffer)
996 else { XCTFail(); return; }
998 XCTAssert( n == (dict.value(forKeyPath:"kcdata_crashinfo.crashed_threadid") as! [Any]).count)
1001 let x = dict["kcdata_crashinfo"] as? NSDictionary
1002 let y = x?["crashed_threadid"] as? NSArray
1003 XCTAssert((y?[i]) as? Int == i)
1008 func testReadThreadidArray() {
1009 // test that we can correctly read old arrays with a variety of sizes and paddings
1010 self.testReadThreadidArray(n: 0, pad:0)
1013 self.testReadThreadidArray(n: n, pad:pad)
1018 func testReadThreadidArrayWrongSize1() {
1019 /// for old style arrays, if the element size is determined by the type. If the array of that size element at the given count doesn't fit, then parsing should fail
1023 let buffer = NSMutableData(capacity:1000)!
1025 var item = kcdata_item()
1027 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
1030 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1032 item.type = UInt32(KCDATA_TYPE_ARRAY)
1033 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
1034 item.size = UInt32(4)
1035 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1037 var payload : UInt32 = UInt32(42)
1038 buffer.append(&payload, length:MemoryLayout<UInt32>.size)
1040 item.type = KCDATA_TYPE_BUFFER_END
1043 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1045 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
1048 func testReadThreadidArrayWrongSize5() {
1049 /// if the count is bigger than the buffer, parsing will just fail
1053 let buffer = NSMutableData(capacity:1000)!
1055 var item = kcdata_item()
1057 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
1060 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1062 item.type = UInt32(KCDATA_TYPE_ARRAY)
1063 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
1064 item.size = UInt32(4)
1065 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1067 var payload : UInt32 = UInt32(42)
1068 buffer.append(&payload, length:MemoryLayout<UInt32>.size)
1070 item.type = KCDATA_TYPE_BUFFER_END
1073 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1075 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
1079 func testReadThreadidArrayPaddedSize() {
1080 // test that we can tolerate a little padding at the end of an array
1083 let buffer = NSMutableData(capacity:1000)!
1085 var item = kcdata_item()
1087 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
1090 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1092 item.type = UInt32(KCDATA_TYPE_ARRAY)
1093 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
1094 item.size = UInt32(n * MemoryLayout<UInt64>.size) + 1
1095 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1098 var payload : UInt64 = UInt64(i)
1099 buffer.append(&payload, length:MemoryLayout<UInt64>.size)
1101 var payload : UInt8 = 0
1102 buffer.append(&payload, length:1)
1104 item.type = KCDATA_TYPE_BUFFER_END
1107 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1109 guard let dict = try? self.parseBuffer(buffer)
1110 else { XCTFail(); return; }
1112 XCTAssert( n == (dict.value(forKeyPath:"kcdata_crashinfo.crashed_threadid") as! [Any]).count)
1114 let x = dict["kcdata_crashinfo"] as? NSDictionary
1115 let y = x?["crashed_threadid"] as? NSArray
1116 XCTAssert((y?[i]) as? Int == i)
1120 func testReadThreadidArrayPaddedSize15() {
1121 // test that we can tolerate a little padding at the end of an array
1124 let buffer = NSMutableData(capacity:1000)!
1126 var item = kcdata_item()
1128 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
1131 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1133 item.type = UInt32(KCDATA_TYPE_ARRAY)
1134 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
1135 item.size = UInt32(n * MemoryLayout<UInt64>.size) + 15
1136 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1139 var payload : UInt64 = UInt64(i)
1140 buffer.append(&payload, length:MemoryLayout<UInt64>.size)
1143 var payload : UInt8 = 0
1144 buffer.append(&payload, length:1)
1147 item.type = KCDATA_TYPE_BUFFER_END
1150 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1152 guard let dict = try? self.parseBuffer(buffer)
1153 else { XCTFail(); return; }
1155 XCTAssert( n == (dict.value(forKeyPath:"kcdata_crashinfo.crashed_threadid") as! [Any]).count)
1157 let x = dict["kcdata_crashinfo"] as? NSDictionary
1158 let y = x?["crashed_threadid"] as? NSArray
1159 XCTAssert((y?[i]) as? Int == i)
1164 func testReadThreadidWrongSize(size : UInt32) {
1165 let buffer = NSMutableData(capacity:1000)!
1167 var item = kcdata_item()
1169 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
1172 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1174 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
1177 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1179 var payload : UInt64 = 42
1180 buffer.append(&payload, length:Int(size))
1182 item.type = KCDATA_TYPE_BUFFER_END
1185 buffer.append(&item, length: MemoryLayout<kcdata_item>.size)
1187 guard let dict = try? self.parseBuffer(buffer)
1188 else { XCTFail(); return; }
1190 XCTAssert(dict.value(forKeyPath:"kcdata_crashinfo.crashed_threadid") == nil)
1193 func testReadThreadidWrongSize0() {
1194 self.testReadThreadidWrongSize(size: 0)
1197 func testReadThreadidWrongSize7() {
1198 self.testReadThreadidWrongSize(size: 7)
1201 func dataWithResource(_ name:String) -> NSData? {
1202 guard let filename = Bundle(for: self.classForCoder).path(forResource: name, ofType: nil)
1204 return NSData(contentsOfFile:filename)!
1207 func testSampleStackshot(_ name : String) {
1208 // check that we agree with sample file
1210 guard let sampledata = self.dataWithResource(name)
1211 else { XCTFail("failed to open bundle resource named " + name); return }
1212 var dict : NSDictionary?
1214 dict = try? self.parseBuffer(sampledata) as NSDictionary
1217 if let decoded = NSData(base64Encoded: sampledata as Data, options:.ignoreUnknownCharacters) {
1218 dict = try? self.parseBuffer(decoded) as NSDictionary
1223 if let decompressed = try? decompress(sampledata) {
1224 dict = try? self.parseBuffer(decompressed) as NSDictionary
1232 guard let plistdata = self.dataWithResource(name + ".plist.gz") ??
1233 self.dataWithResource(name + ".plist")
1234 else {XCTFail(); return}
1236 var opt_dict2 = try? PropertyListSerialization.propertyList(from: plistdata as Data, options: [], format: nil)
1237 if opt_dict2 == nil {
1238 opt_dict2 = try? PropertyListSerialization.propertyList(from:decompress(plistdata) as Data, options:[], format: nil)
1240 guard let dict2 = opt_dict2
1241 else { XCTFail(); return}
1243 XCTAssertEqual(dict, dict2 as! NSDictionary);
1245 //XCTAssert(dict == dict2 as? NSDictionary)
1247 // check that we agree with python
1251 let kcdatapy = Bundle(for: self.classForCoder).path(forResource: "kcdata.py", ofType: nil)
1253 let task = Process()
1254 task.launchPath = kcdatapy
1255 task.arguments = ["-p",
1256 Bundle(for:self.classForCoder).path(forResource: name, ofType: nil)!]
1258 task.standardOutput = pipe
1261 let data = pipe.fileHandleForReading.readDataToEndOfFile()
1263 guard let dict3 = try? PropertyListSerialization.propertyList(from:data, options:[], format: nil) as? NSDictionary
1264 else { XCTFail(); return }
1266 XCTAssert(dict == dict3)
1271 func testSampleStackshot() {
1272 self.testSampleStackshot("stackshot-sample")
1275 func testSampleStackshotOldArrays() {
1276 self.testSampleStackshot("stackshot-sample-old-arrays")
1279 func testSampleStackshotNewArrays() {
1280 self.testSampleStackshot("stackshot-sample-new-arrays")
1283 func testSampleDeltaStackshotOldArrays() {
1284 self.testSampleStackshot("delta-stackshot-sample-old-arrays")
1287 func testSampleDeltaStackshotNewArrays() {
1288 self.testSampleStackshot("delta-stackshot-sample-new-arrays")
1291 func testSampleCorpse() {
1292 self.testSampleStackshot("corpse-sample")
1295 func testSampleStackshotTailspin() {
1296 self.testSampleStackshot("stackshot-sample-tailspin")
1299 func testSampleStackshotTailspin2() {
1300 self.testSampleStackshot("stackshot-sample-tailspin-2")
1303 func testSampleExitReason() {
1304 self.testSampleStackshot("exitreason-sample")
1307 func testSampleThreadT() {
1308 self.testSampleStackshot("stackshot-sample-ths-thread-t")
1311 func testSampleCpuTimes() {
1312 self.testSampleStackshot("stackshot-sample-cputime")
1315 func testSampleDuration() {
1316 self.testSampleStackshot("stackshot-sample-duration")
1319 func testSampleNested() {
1320 self.testSampleStackshot("nested-sample")
1323 func testSampleTermWithReason() {
1324 self.testSampleStackshot("test-twr-sample")
1327 func testSampleCorpseTermWithReason() {
1328 self.testSampleStackshot("corpse-twr-sample")
1331 func testSampleCorpseTermWithReasonV2() {
1332 self.testSampleStackshot("corpse-twr-sample-v2")
1335 func testSampleCodesigningExitReason() {
1336 self.testSampleStackshot("exitreason-codesigning")
1339 func testSampleThreadGroups() {
1340 self.testSampleStackshot("stackshot-sample-thread-groups")
1343 func testSampleThreadGroupsFlags() {
1344 self.testSampleStackshot("stackshot-sample-thread-groups-flags")
1347 func testSampleCoalitions() {
1348 self.testSampleStackshot("stackshot-sample-coalitions")
1351 func testStackshotSharedcacheV2() {
1352 self.testSampleStackshot("stackshot-sample-sharedcachev2")
1355 func testStackshotFaultStats() {
1356 self.testSampleStackshot("stackshot-fault-stats")
1359 func testStackshotwithKCID() {
1360 self.testSampleStackshot("stackshot-with-kcid")
1363 func testXNUPostTestConfig() {
1364 self.testSampleStackshot("xnupost_testconfig-sample")
1367 func testStackshotWithWaitinfo() {
1368 self.testSampleStackshot("stackshot-with-waitinfo")
1371 func testStackshotWithThreadPolicy() {
1372 self.testSampleStackshot("stackshot-sample-thread-policy")
1375 func testDeltaStackshotWithThreadPolicy() {
1376 self.testSampleStackshot("stackshot-sample-delta-thread-policy")
1379 func testStackshotWithInstrsCycles() {
1380 self.testSampleStackshot("stackshot-sample-instrs-cycles")
1383 func testStackshotWithStacktop() {
1384 self.testSampleStackshot("stackshot-sample-stacktop")
1387 func testStackshotWithASID() {
1388 self.testSampleStackshot("stackshot-sample-asid")
1391 func testStackshotWithPageTables() {
1392 self.testSampleStackshot("stackshot-sample-asid-pagetable")
1395 func testStackshotCPUTimes() {
1396 self.testSampleStackshot("stackshot-sample-cpu-times")
1399 func testStackshotWithSharedCacheLayout() {
1400 self.testSampleStackshot("stackshot-with-shared-cache-layout")
1403 func testTrivial() {