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(); 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 dict2 = try? PropertyListSerialization.propertyList(from: plistdata as Data, options: [], format: nil)
1238 dict2 = try? PropertyListSerialization.propertyList(from:decompress(plistdata) as Data, options:[], format: nil)
1241 XCTAssert(dict2 != nil)
1243 XCTAssert(dict == dict2 as? NSDictionary)
1245 // check that we agree with python
1249 let kcdatapy = Bundle(for: self.classForCoder).path(forResource: "kcdata.py", ofType: nil)
1251 let task = Process()
1252 task.launchPath = kcdatapy
1253 task.arguments = ["-p",
1254 Bundle(for:self.classForCoder).path(forResource: name, ofType: nil)!]
1256 task.standardOutput = pipe
1259 let data = pipe.fileHandleForReading.readDataToEndOfFile()
1261 guard let dict3 = try? PropertyListSerialization.propertyList(from:data, options:[], format: nil) as? NSDictionary
1262 else { XCTFail(); return }
1264 XCTAssert(dict == dict3)
1269 func testSampleStackshot() {
1270 self.testSampleStackshot("stackshot-sample")
1273 func testSampleStackshotOldArrays() {
1274 self.testSampleStackshot("stackshot-sample-old-arrays")
1277 func testSampleStackshotNewArrays() {
1278 self.testSampleStackshot("stackshot-sample-new-arrays")
1281 func testSampleDeltaStackshotOldArrays() {
1282 self.testSampleStackshot("delta-stackshot-sample-old-arrays")
1285 func testSampleDeltaStackshotNewArrays() {
1286 self.testSampleStackshot("delta-stackshot-sample-new-arrays")
1289 func testSampleCorpse() {
1290 self.testSampleStackshot("corpse-sample")
1293 func testSampleStackshotTailspin() {
1294 self.testSampleStackshot("stackshot-sample-tailspin")
1297 func testSampleStackshotTailspin2() {
1298 self.testSampleStackshot("stackshot-sample-tailspin-2")
1301 func testSampleExitReason() {
1302 self.testSampleStackshot("exitreason-sample")
1305 func testSampleThreadT() {
1306 self.testSampleStackshot("stackshot-sample-ths-thread-t")
1309 func testSampleCpuTimes() {
1310 self.testSampleStackshot("stackshot-sample-cputime")
1313 func testSampleDuration() {
1314 self.testSampleStackshot("stackshot-sample-duration")
1317 func testSampleNested() {
1318 self.testSampleStackshot("nested-sample")
1321 func testSampleTermWithReason() {
1322 self.testSampleStackshot("test-twr-sample")
1325 func testSampleCorpseTermWithReason() {
1326 self.testSampleStackshot("corpse-twr-sample")
1329 func testSampleCorpseTermWithReasonV2() {
1330 self.testSampleStackshot("corpse-twr-sample-v2")
1333 func testSampleCodesigningExitReason() {
1334 self.testSampleStackshot("exitreason-codesigning")
1337 func testSampleThreadGroups() {
1338 self.testSampleStackshot("stackshot-sample-thread-groups")
1341 func testSampleThreadGroupsFlags() {
1342 self.testSampleStackshot("stackshot-sample-thread-groups-flags")
1345 func testSampleCoalitions() {
1346 self.testSampleStackshot("stackshot-sample-coalitions")
1349 func testStackshotSharedcacheV2() {
1350 self.testSampleStackshot("stackshot-sample-sharedcachev2")
1353 func testStackshotFaultStats() {
1354 self.testSampleStackshot("stackshot-fault-stats")
1357 func testStackshotwithKCID() {
1358 self.testSampleStackshot("stackshot-with-kcid")
1361 func testXNUPostTestConfig() {
1362 self.testSampleStackshot("xnupost_testconfig-sample")
1365 func testStackshotWithWaitinfo() {
1366 self.testSampleStackshot("stackshot-with-waitinfo")
1369 func testStackshotWithThreadPolicy() {
1370 self.testSampleStackshot("stackshot-sample-thread-policy")
1373 func testStackshotWithInstrsCycles() {
1374 self.testSampleStackshot("stackshot-sample-instrs-cycles")
1377 func testTrivial() {