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(x : AnyObject) -> uuid_t {
30 return uuid_t(UInt8(a[0] as! Int),
48 func nsuuid2array(uuid : NSUUID) -> [Int] {
50 let ptr = UnsafeMutablePointer<UInt8>.alloc(16)
52 defer { ptr.dealloc(16) }
54 uuid.getUUIDBytes(ptr)
56 ret.append(Int(ptr[i]))
61 func decompress(data:NSData) throws -> NSData {
62 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)
64 let bufsize : Int = 1000
65 let buffer = UnsafeMutablePointer<UInt8>.alloc(bufsize)
66 defer { buffer.dealloc(bufsize) }
67 let output = NSMutableData()
68 stream.next_out = buffer
69 stream.avail_out = UInt32(bufsize)
70 stream.next_in = UnsafeMutablePointer(data.bytes)
71 stream.avail_in = UInt32(data.length)
72 inflateInit2_(&stream, 16+MAX_WBITS, ZLIB_VERSION, Int32(sizeof(z_stream)))
75 let z = inflate(&stream, Z_NO_FLUSH);
76 if (z == Z_OK || z == Z_STREAM_END) {
77 output.appendBytes(buffer, length: bufsize - Int(stream.avail_out))
78 stream.avail_out = UInt32(bufsize)
79 stream.next_out = buffer
80 if (z == Z_STREAM_END) {
84 throw NSError(domain: "zlib", code: Int(z), userInfo: nil)
91 class Tests: XCTestCase {
93 override func setUp() {
95 continueAfterFailure = false
98 override func tearDown() {
99 // Put teardown code here. This method is called after the invocation of each test method in the class.
103 func parseBuffer(buffer:NSData) throws -> NSDictionary {
105 guard let dict = parseKCDataBuffer(UnsafeMutablePointer(buffer.bytes), UInt32(buffer.length), &error)
107 XCTAssert(error != nil)
113 func testPaddingFlags(pad : Int) {
114 let buffer = NSMutableData(capacity:1000)!
116 var item = kcdata_item()
118 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
121 buffer.appendBytes(&item, length: sizeof(kcdata_item))
123 item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
124 item.flags = UInt64(pad)
125 item.size = UInt32(sizeof(dyld_uuid_info_32))
126 buffer.appendBytes(&item, length: sizeof(kcdata_item))
128 let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
130 var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
131 buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32))
133 item.type = KCDATA_TYPE_BUFFER_END
136 buffer.appendBytes(&item, length: sizeof(kcdata_item))
138 guard let dict = try? self.parseBuffer(buffer)
139 else { XCTFail(); return; }
141 var uuidarray = nsuuid2array(uuid)
143 uuidarray.removeLast()
146 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42)
147 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == uuidarray)
150 func testPaddingFlags() {
156 func testBootArgs() {
157 let s = "hello, I am some boot args"
159 let buffer = NSMutableData(capacity:1000)!
161 var item = kcdata_item()
163 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
166 buffer.appendBytes(&item, length: sizeof(kcdata_item))
168 item.type = UInt32(STACKSHOT_KCTYPE_BOOTARGS)
170 item.size = UInt32(s.utf8.count + 1)
171 buffer.appendBytes(&item, length: sizeof(kcdata_item))
172 s.nulTerminatedUTF8.withUnsafeBufferPointer({
173 buffer.appendBytes($0.baseAddress, length:s.utf8.count + 1)
176 item.type = KCDATA_TYPE_BUFFER_END
179 buffer.appendBytes(&item, length: sizeof(kcdata_item))
181 guard let dict = try? self.parseBuffer(buffer) else { XCTFail(); return; }
182 XCTAssert(dict["kcdata_crashinfo"]?["boot_args"] == s)
185 func testBootArgsMissingNul() {
186 let s = "hello, I am some boot args"
188 let buffer = NSMutableData(capacity:1000)!
190 var item = kcdata_item()
192 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
195 buffer.appendBytes(&item, length: sizeof(kcdata_item))
197 item.type = UInt32(STACKSHOT_KCTYPE_BOOTARGS)
199 item.size = UInt32(s.utf8.count)
200 buffer.appendBytes(&item, length: sizeof(kcdata_item))
201 s.nulTerminatedUTF8.withUnsafeBufferPointer({
202 buffer.appendBytes($0.baseAddress, length:s.utf8.count)
205 item.type = KCDATA_TYPE_BUFFER_END
208 buffer.appendBytes(&item, length: sizeof(kcdata_item))
210 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
213 func testLoadInfo() {
214 let buffer = NSMutableData(capacity:1000)!
216 var item = kcdata_item()
218 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
221 buffer.appendBytes(&item, length: sizeof(kcdata_item))
223 item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
225 item.size = UInt32(sizeof(dyld_uuid_info_32))
226 buffer.appendBytes(&item, length: sizeof(kcdata_item))
228 let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
230 var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
231 buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32))
233 item.type = KCDATA_TYPE_BUFFER_END
236 buffer.appendBytes(&item, length: sizeof(kcdata_item))
238 guard let dict = try? self.parseBuffer(buffer)
239 else { XCTFail(); return; }
241 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42)
242 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == nsuuid2array(uuid))
245 func testLoadInfoWrongSize() {
246 // test what happens when a struct size is short
248 let buffer = NSMutableData(capacity:1000)!
250 var item = kcdata_item()
252 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
255 buffer.appendBytes(&item, length: sizeof(kcdata_item))
257 item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
259 item.size = UInt32(sizeof(dyld_uuid_info_32)) - 1
260 buffer.appendBytes(&item, length: sizeof(kcdata_item))
262 let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
264 var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
265 buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32) - 1)
267 item.type = KCDATA_TYPE_BUFFER_END
270 buffer.appendBytes(&item, length: sizeof(kcdata_item))
272 guard let dict = try? self.parseBuffer(buffer)
273 else { XCTFail(); return; }
274 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42)
275 var uuidarray = nsuuid2array(uuid)
276 uuidarray.removeLast()
277 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == uuidarray)
280 func testLoadInfoWayWrongSize() {
281 // test what happens when a struct size is short
283 let buffer = NSMutableData(capacity:1000)!
285 var item = kcdata_item()
287 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
290 buffer.appendBytes(&item, length: sizeof(kcdata_item))
292 item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
294 item.size = UInt32(sizeof(dyld_uuid_info_32)) - 16
295 buffer.appendBytes(&item, length: sizeof(kcdata_item))
297 let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
299 var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
300 buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32) - 16)
302 item.type = KCDATA_TYPE_BUFFER_END
305 buffer.appendBytes(&item, length: sizeof(kcdata_item))
307 guard let dict = try? self.parseBuffer(buffer)
308 else { XCTFail(); return; }
309 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42)
310 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == nil)
313 func testLoadInfoPreposterousWrongSize() {
314 // test what happens when a struct size is short
316 let buffer = NSMutableData(capacity:1000)!
318 var item = kcdata_item()
320 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
323 buffer.appendBytes(&item, length: sizeof(kcdata_item))
325 item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
327 item.size = UInt32(1)
328 buffer.appendBytes(&item, length: sizeof(kcdata_item))
330 var payload = UInt8(42)
331 buffer.appendBytes(&payload, length:1)
333 item.type = KCDATA_TYPE_BUFFER_END
336 buffer.appendBytes(&item, length: sizeof(kcdata_item))
338 guard let dict = try? self.parseBuffer(buffer)
339 else { XCTFail(); return; }
340 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == nil)
341 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == nil)
345 func testNewArray(n : Int, pad : Int) {
346 let buffer = NSMutableData(capacity:1000)!
347 var item = kcdata_item()
349 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
352 buffer.appendBytes(&item, length: sizeof(kcdata_item))
354 item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0) + UInt32(pad)
355 item.flags = UInt64(STACKSHOT_KCTYPE_DONATING_PIDS) << 32 | UInt64(n)
356 item.size = UInt32(n * sizeof(UInt32) + pad)
357 buffer.appendBytes(&item, length: sizeof(kcdata_item))
360 var payload = UInt32(42 * i)
361 buffer.appendBytes(&payload, length:sizeof(UInt32))
365 var payload = UInt8(42-i)
366 buffer.appendBytes(&payload, length:sizeof(UInt8))
369 item.type = KCDATA_TYPE_BUFFER_END
372 buffer.appendBytes(&item, length: sizeof(kcdata_item))
374 guard let dict = try? self.parseBuffer(buffer)
375 else { XCTFail(); return; }
376 XCTAssert(dict["kcdata_crashinfo"]?["donating_pids"]??.count == n)
378 let x = dict["kcdata_crashinfo"] as? NSDictionary
379 let y = x?["donating_pids"] as? NSArray
380 XCTAssert((y?[i]) as? NSObject == 42 * i)
384 func testNewArrays() {
385 self.testNewArray(0,pad:0)
388 self.testNewArray(i, pad:pad)
394 func testArrayLoadInfo(n : Int) {
395 let buffer = NSMutableData(capacity:1000)!
396 var item = kcdata_item()
398 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
401 buffer.appendBytes(&item, length: sizeof(kcdata_item))
403 item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
404 item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
405 item.size = UInt32(n * sizeof(dyld_uuid_info_32))
406 buffer.appendBytes(&item, length: sizeof(kcdata_item))
408 let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
412 var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid))
414 buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32))
417 item.type = KCDATA_TYPE_BUFFER_END
420 buffer.appendBytes(&item, length: sizeof(kcdata_item))
422 guard let dict = try? self.parseBuffer(buffer)
423 else { XCTFail(); return; }
424 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n)
426 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == 42+i)
427 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == nsuuid2array(uuid))
431 func testArrayLoadInfo() {
437 func testArrayLoadInfoWrongSize() {
438 // test what happens when array element sizes are too short
442 let buffer = NSMutableData(capacity:1000)!
443 var item = kcdata_item()
445 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
448 buffer.appendBytes(&item, length: sizeof(kcdata_item))
450 item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
451 item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
452 item.size = UInt32(n * (sizeof(dyld_uuid_info_32) - wrong))
453 buffer.appendBytes(&item, length: sizeof(kcdata_item))
455 let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
458 var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid))
459 buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32)-wrong)
462 item.type = KCDATA_TYPE_BUFFER_END
465 buffer.appendBytes(&item, length: sizeof(kcdata_item))
467 var uuidarray = nsuuid2array(uuid)
468 uuidarray.removeLast()
470 guard let dict = try? self.parseBuffer(buffer)
471 else { XCTFail(); return; }
472 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n)
474 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == 42+i)
475 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == uuidarray)
480 func testArrayLoadInfoWayWrongSize() {
481 // test what happens when array element sizes are too short
485 let buffer = NSMutableData(capacity:1000)!
486 var item = kcdata_item()
488 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
491 buffer.appendBytes(&item, length: sizeof(kcdata_item))
493 item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
494 item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
495 item.size = UInt32(n * (sizeof(dyld_uuid_info_32) - wrong))
496 buffer.appendBytes(&item, length: sizeof(kcdata_item))
498 let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
501 var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid))
502 buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32)-wrong)
505 item.type = KCDATA_TYPE_BUFFER_END
508 buffer.appendBytes(&item, length: sizeof(kcdata_item))
510 guard let dict = try? self.parseBuffer(buffer)
511 else { XCTFail(); return; }
512 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n)
514 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == 42+i)
515 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == nil)
519 func testArrayLoadInfoPreposterouslyWrongSize() {
520 // test what happens when array element sizes are too short
524 let buffer = NSMutableData(capacity:1000)!
525 var item = kcdata_item()
527 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
530 buffer.appendBytes(&item, length: sizeof(kcdata_item))
532 item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
533 item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
534 item.size = UInt32(n * (sizeof(dyld_uuid_info_32) - wrong))
535 buffer.appendBytes(&item, length: sizeof(kcdata_item))
538 var payload = UInt8(42*i)
539 buffer.appendBytes(&payload, length:1)
542 item.type = KCDATA_TYPE_BUFFER_END
545 buffer.appendBytes(&item, length: sizeof(kcdata_item))
547 guard let dict = try? self.parseBuffer(buffer)
548 else { XCTFail(); return; }
549 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n)
551 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == nil)
552 XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == nil)
558 let buffer = NSMutableData(capacity:1000)!
560 var item = kcdata_item()
562 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
565 buffer.appendBytes(&item, length: sizeof(kcdata_item))
567 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
569 item.size = UInt32(sizeof(UInt64))
570 buffer.appendBytes(&item, length: sizeof(kcdata_item))
572 var payload : UInt64 = 42
573 buffer.appendBytes(&payload, length:sizeof(UInt64))
575 item.type = KCDATA_TYPE_BUFFER_END
578 buffer.appendBytes(&item, length: sizeof(kcdata_item))
580 let buffer2 = NSMutableData(capacity:1000)!
582 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
585 buffer2.appendBytes(&item, length: sizeof(kcdata_item))
587 item.type = UInt32(KCDATA_TYPE_NESTED_KCDATA)
589 item.size = UInt32(buffer.length)
590 buffer2.appendBytes(&item, length: sizeof(kcdata_item))
591 buffer2.appendData(buffer)
593 item.type = KCDATA_TYPE_BUFFER_END
596 buffer2.appendBytes(&item, length: sizeof(kcdata_item))
598 guard let dict2 = try? self.parseBuffer(buffer2)
599 else { XCTFail(); return; }
601 XCTAssert(dict2["kcdata_crashinfo"]?["kcdata_crashinfo"]??["crashed_threadid"] == 42)
605 func testReadThreadid() {
606 let buffer = NSMutableData(capacity:1000)!
608 var item = kcdata_item()
610 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
613 buffer.appendBytes(&item, length: sizeof(kcdata_item))
615 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
617 item.size = UInt32(sizeof(UInt64))
618 buffer.appendBytes(&item, length: sizeof(kcdata_item))
620 var payload : UInt64 = 42
621 buffer.appendBytes(&payload, length:sizeof(UInt64))
623 item.type = KCDATA_TYPE_BUFFER_END
626 buffer.appendBytes(&item, length: sizeof(kcdata_item))
628 guard let dict = try? self.parseBuffer(buffer)
629 else { XCTFail(); return; }
631 XCTAssert(dict["kcdata_crashinfo"]!["crashed_threadid"] == 42)
635 func testRepeatedKey() {
636 // test a repeated item of the same key causes error
638 let buffer = NSMutableData(capacity:1000)!
640 var item = kcdata_item()
642 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
645 buffer.appendBytes(&item, length: sizeof(kcdata_item))
647 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
649 item.size = UInt32(sizeof(UInt64))
650 buffer.appendBytes(&item, length: sizeof(kcdata_item))
652 var payload : UInt64 = 42
653 buffer.appendBytes(&payload, length:sizeof(UInt64))
655 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
657 item.size = UInt32(sizeof(UInt64))
658 buffer.appendBytes(&item, length: sizeof(kcdata_item))
661 buffer.appendBytes(&payload, length:sizeof(UInt64))
663 item.type = KCDATA_TYPE_BUFFER_END
666 buffer.appendBytes(&item, length: sizeof(kcdata_item))
668 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
672 func testContainer() {
673 let buffer = NSMutableData(capacity:1000)!
675 var item = kcdata_item()
676 var payload64 : UInt64
677 var payload32 : UInt32
679 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
682 buffer.appendBytes(&item, length: sizeof(kcdata_item))
684 item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
686 item.size = UInt32(sizeof(UInt32))
687 buffer.appendBytes(&item, length: sizeof(kcdata_item))
688 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
689 buffer.appendBytes(&payload32, length:sizeof(UInt32))
691 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
693 item.size = UInt32(sizeof(UInt64))
694 buffer.appendBytes(&item, length: sizeof(kcdata_item))
696 buffer.appendBytes(&payload64, length:sizeof(UInt64))
698 item.type = UInt32(KCDATA_TYPE_CONTAINER_END)
700 item.size = UInt32(sizeof(UInt32))
701 buffer.appendBytes(&item, length: sizeof(kcdata_item))
702 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
703 buffer.appendBytes(&payload32, length:sizeof(UInt32))
706 item.type = KCDATA_TYPE_BUFFER_END
709 buffer.appendBytes(&item, length: sizeof(kcdata_item))
711 guard let dict = try? self.parseBuffer(buffer)
712 else { XCTFail(); return; }
714 XCTAssert(dict["kcdata_crashinfo"]?["task_snapshots"]??["0"]??["crashed_threadid"] == 42)
718 func testRepeatedContainer() {
719 //repeated container of same name and key shoudl fail
721 let buffer = NSMutableData(capacity:1000)!
723 var item = kcdata_item()
724 var payload64 : UInt64
725 var payload32 : UInt32
727 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
730 buffer.appendBytes(&item, length: sizeof(kcdata_item))
732 item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
734 item.size = UInt32(sizeof(UInt32))
735 buffer.appendBytes(&item, length: sizeof(kcdata_item))
736 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
737 buffer.appendBytes(&payload32, length:sizeof(UInt32))
739 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
741 item.size = UInt32(sizeof(UInt64))
742 buffer.appendBytes(&item, length: sizeof(kcdata_item))
744 buffer.appendBytes(&payload64, length:sizeof(UInt64))
746 item.type = UInt32(KCDATA_TYPE_CONTAINER_END)
748 item.size = UInt32(sizeof(UInt32))
749 buffer.appendBytes(&item, length: sizeof(kcdata_item))
750 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
751 buffer.appendBytes(&payload32, length:sizeof(UInt32))
754 item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
756 item.size = UInt32(sizeof(UInt32))
757 buffer.appendBytes(&item, length: sizeof(kcdata_item))
758 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
759 buffer.appendBytes(&payload32, length:sizeof(UInt32))
761 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
763 item.size = UInt32(sizeof(UInt64))
764 buffer.appendBytes(&item, length: sizeof(kcdata_item))
766 buffer.appendBytes(&payload64, length:sizeof(UInt64))
768 item.type = UInt32(KCDATA_TYPE_CONTAINER_END)
770 item.size = UInt32(sizeof(UInt32))
771 buffer.appendBytes(&item, length: sizeof(kcdata_item))
772 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
773 buffer.appendBytes(&payload32, length:sizeof(UInt32))
775 item.type = KCDATA_TYPE_BUFFER_END
778 buffer.appendBytes(&item, length: sizeof(kcdata_item))
780 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
784 func testContainerNoEnd() {
785 let buffer = NSMutableData(capacity:1000)!
787 var item = kcdata_item()
788 var payload64 : UInt64
789 var payload32 : UInt32
791 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
794 buffer.appendBytes(&item, length: sizeof(kcdata_item))
796 item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
798 item.size = UInt32(sizeof(UInt32))
799 buffer.appendBytes(&item, length: sizeof(kcdata_item))
800 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
801 buffer.appendBytes(&payload32, length:sizeof(UInt32))
803 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
805 item.size = UInt32(sizeof(UInt64))
806 buffer.appendBytes(&item, length: sizeof(kcdata_item))
808 buffer.appendBytes(&payload64, length:sizeof(UInt64))
810 item.type = KCDATA_TYPE_BUFFER_END
813 buffer.appendBytes(&item, length: sizeof(kcdata_item))
815 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
818 func testContainerNoEndNoEnd() {
819 let buffer = NSMutableData(capacity:1000)!
821 var item = kcdata_item()
822 var payload64 : UInt64
823 var payload32 : UInt32
825 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
828 buffer.appendBytes(&item, length: sizeof(kcdata_item))
830 item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
832 item.size = UInt32(sizeof(UInt32))
833 buffer.appendBytes(&item, length: sizeof(kcdata_item))
834 payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
835 buffer.appendBytes(&payload32, length:sizeof(UInt32))
837 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
839 item.size = UInt32(sizeof(UInt64))
840 buffer.appendBytes(&item, length: sizeof(kcdata_item))
842 buffer.appendBytes(&payload64, length:sizeof(UInt64))
844 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
850 let buffer = NSMutableData(capacity:1000)!
852 var item = kcdata_item()
854 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
857 buffer.appendBytes(&item, length: sizeof(kcdata_item))
859 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
861 item.size = UInt32(sizeof(UInt64))
862 buffer.appendBytes(&item, length: sizeof(kcdata_item))
864 var payload : UInt64 = 42
865 buffer.appendBytes(&payload, length:sizeof(UInt64))
867 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
871 func testCrazySize() {
872 let buffer = NSMutableData(capacity:1000)!
874 var item = kcdata_item()
876 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
879 buffer.appendBytes(&item, length: sizeof(kcdata_item))
881 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
884 buffer.appendBytes(&item, length: sizeof(kcdata_item))
886 var payload : UInt64 = 42
887 buffer.appendBytes(&payload, length:sizeof(UInt64))
889 item.type = KCDATA_TYPE_BUFFER_END
892 buffer.appendBytes(&item, length: sizeof(kcdata_item))
894 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
897 func testReadRepeatedArray() {
898 // repeated arrays should be concatenated
901 let buffer = NSMutableData(capacity:1000)!
903 var item = kcdata_item()
905 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
908 buffer.appendBytes(&item, length: sizeof(kcdata_item))
910 item.type = UInt32(KCDATA_TYPE_ARRAY)
911 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
912 item.size = UInt32(n * sizeof(UInt64))
913 buffer.appendBytes(&item, length: sizeof(kcdata_item))
916 var payload : UInt64 = UInt64(i)
917 buffer.appendBytes(&payload, length:sizeof(UInt64))
920 item.type = UInt32(KCDATA_TYPE_ARRAY)
921 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
922 item.size = UInt32(n * sizeof(UInt64))
923 buffer.appendBytes(&item, length: sizeof(kcdata_item))
926 var payload : UInt64 = UInt64(i)
927 buffer.appendBytes(&payload, length:sizeof(UInt64))
930 item.type = KCDATA_TYPE_BUFFER_END
933 buffer.appendBytes(&item, length: sizeof(kcdata_item))
935 guard let dict = try? self.parseBuffer(buffer)
936 else { XCTFail(); return }
938 XCTAssert( 2*n == dict["kcdata_crashinfo"]!["crashed_threadid"]!!.count)
940 let x = dict["kcdata_crashinfo"] as? NSDictionary
941 let y = x?["crashed_threadid"] as? NSArray
942 XCTAssert((y?[i]) as? NSObject == i % n)
946 func testReadThreadidArray(n : Int, pad : Int) {
947 let buffer = NSMutableData(capacity:1000)!
949 var item = kcdata_item()
951 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
954 buffer.appendBytes(&item, length: sizeof(kcdata_item))
956 item.type = UInt32(KCDATA_TYPE_ARRAY)
957 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
958 item.size = UInt32(n * sizeof(UInt64) + pad)
959 buffer.appendBytes(&item, length: sizeof(kcdata_item))
962 var payload : UInt64 = UInt64(i)
963 buffer.appendBytes(&payload, length:sizeof(UInt64))
967 var payload : UInt8 = 0
968 buffer.appendBytes(&payload, length:1)
971 item.type = KCDATA_TYPE_BUFFER_END
974 buffer.appendBytes(&item, length: sizeof(kcdata_item))
976 guard let dict = try? self.parseBuffer(buffer)
977 else { XCTFail(); return; }
979 XCTAssert( n == dict["kcdata_crashinfo"]?["crashed_threadid"]??.count)
981 let x = dict["kcdata_crashinfo"] as? NSDictionary
982 let y = x?["crashed_threadid"] as? NSArray
983 XCTAssert((y?[i]) as? NSObject == i)
988 func testReadThreadidArray() {
989 // test that we can correctly read old arrays with a variety of sizes and paddings
990 self.testReadThreadidArray(0, pad:0)
993 self.testReadThreadidArray(n, pad:pad)
998 func testReadThreadidArrayWrongSize1() {
999 /// 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
1003 let buffer = NSMutableData(capacity:1000)!
1005 var item = kcdata_item()
1007 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
1010 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1012 item.type = UInt32(KCDATA_TYPE_ARRAY)
1013 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
1014 item.size = UInt32(4)
1015 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1017 var payload : UInt32 = UInt32(42)
1018 buffer.appendBytes(&payload, length:sizeof(UInt32))
1020 item.type = KCDATA_TYPE_BUFFER_END
1023 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1025 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
1028 func testReadThreadidArrayWrongSize5() {
1029 /// if the count is bigger than the buffer, parsing will just fail
1033 let buffer = NSMutableData(capacity:1000)!
1035 var item = kcdata_item()
1037 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
1040 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1042 item.type = UInt32(KCDATA_TYPE_ARRAY)
1043 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
1044 item.size = UInt32(4)
1045 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1047 var payload : UInt32 = UInt32(42)
1048 buffer.appendBytes(&payload, length:sizeof(UInt32))
1050 item.type = KCDATA_TYPE_BUFFER_END
1053 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1055 XCTAssert( (try? self.parseBuffer(buffer)) == nil )
1059 func testReadThreadidArrayPaddedSize() {
1060 // test that we can tolerate a little padding at the end of an array
1063 let buffer = NSMutableData(capacity:1000)!
1065 var item = kcdata_item()
1067 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
1070 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1072 item.type = UInt32(KCDATA_TYPE_ARRAY)
1073 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
1074 item.size = UInt32(n * sizeof(UInt64)) + 1
1075 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1078 var payload : UInt64 = UInt64(i)
1079 buffer.appendBytes(&payload, length:sizeof(UInt64))
1081 var payload : UInt8 = 0
1082 buffer.appendBytes(&payload, length:1)
1084 item.type = KCDATA_TYPE_BUFFER_END
1087 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1089 guard let dict = try? self.parseBuffer(buffer)
1090 else { XCTFail(); return; }
1092 XCTAssert( n == dict["kcdata_crashinfo"]?["crashed_threadid"]??.count)
1094 let x = dict["kcdata_crashinfo"] as? NSDictionary
1095 let y = x?["crashed_threadid"] as? NSArray
1096 XCTAssert((y?[i]) as? NSObject == i)
1100 func testReadThreadidArrayPaddedSize15() {
1101 // test that we can tolerate a little padding at the end of an array
1104 let buffer = NSMutableData(capacity:1000)!
1106 var item = kcdata_item()
1108 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
1111 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1113 item.type = UInt32(KCDATA_TYPE_ARRAY)
1114 item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
1115 item.size = UInt32(n * sizeof(UInt64)) + 15
1116 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1119 var payload : UInt64 = UInt64(i)
1120 buffer.appendBytes(&payload, length:sizeof(UInt64))
1124 var payload : UInt8 = 0
1125 buffer.appendBytes(&payload, length:1)
1128 item.type = KCDATA_TYPE_BUFFER_END
1131 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1133 guard let dict = try? self.parseBuffer(buffer)
1134 else { XCTFail(); return; }
1136 XCTAssert( n == dict["kcdata_crashinfo"]?["crashed_threadid"]??.count)
1138 let x = dict["kcdata_crashinfo"] as? NSDictionary
1139 let y = x?["crashed_threadid"] as? NSArray
1140 XCTAssert((y?[i]) as? NSObject == i)
1145 func testReadThreadidWrongSize(size : UInt32) {
1146 let buffer = NSMutableData(capacity:1000)!
1148 var item = kcdata_item()
1150 item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
1153 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1155 item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
1158 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1160 var payload : UInt64 = 42
1161 buffer.appendBytes(&payload, length:Int(size))
1163 item.type = KCDATA_TYPE_BUFFER_END
1166 buffer.appendBytes(&item, length: sizeof(kcdata_item))
1168 guard let dict = try? self.parseBuffer(buffer)
1169 else { XCTFail(); return; }
1171 XCTAssert(dict["kcdata_crashinfo"]?["crashed_threadid"] == nil)
1174 func testReadThreadidWrongSize0() {
1175 self.testReadThreadidWrongSize(0)
1178 func testReadThreadidWrongSize7() {
1179 self.testReadThreadidWrongSize(7)
1182 func dataWithResource(name:String) -> NSData? {
1183 guard let filename = NSBundle(forClass: self.classForCoder).pathForResource(name, ofType: nil)
1185 return NSData(contentsOfFile:filename)!
1188 func testSampleStackshot(name : String) {
1189 // check that we agree with sample file
1191 guard let sampledata = self.dataWithResource(name)
1192 else { XCTFail(); return }
1193 var dict : NSDictionary?
1195 dict = try? self.parseBuffer(sampledata)
1198 if let decoded = NSData(base64EncodedData: sampledata, options:.IgnoreUnknownCharacters) {
1199 dict = try? self.parseBuffer(decoded)
1204 if let decompressed = try? decompress(sampledata) {
1205 dict = try? self.parseBuffer(decompressed)
1213 guard let plistdata = self.dataWithResource(name + ".plist.gz") ??
1214 self.dataWithResource(name + ".plist")
1215 else {XCTFail(); return}
1217 var dict2 = try? NSPropertyListSerialization.propertyListWithData(plistdata, options: NSPropertyListReadOptions.Immutable, format: nil)
1219 dict2 = try? NSPropertyListSerialization.propertyListWithData(decompress(plistdata), options: .Immutable, format: nil)
1222 XCTAssert(dict2 != nil)
1224 XCTAssert(dict == dict2 as? NSDictionary)
1226 // check that we agree with python
1230 let kcdatapy = NSBundle(forClass: self.classForCoder).pathForResource("kcdata.py", ofType: nil)
1233 task.launchPath = kcdatapy
1234 task.arguments = ["-p",
1235 NSBundle(forClass:self.classForCoder).pathForResource(name, ofType: nil)!]
1237 task.standardOutput = pipe
1240 let data = pipe.fileHandleForReading.readDataToEndOfFile()
1242 guard let dict3 = try? NSPropertyListSerialization.propertyListWithData(data, options: .Immutable, format: nil) as? NSDictionary
1243 else { XCTFail(); return }
1245 XCTAssert(dict == dict3)
1250 func testSampleStackshot() {
1251 self.testSampleStackshot("stackshot-sample")
1254 func testSampleStackshotOldArrays() {
1255 self.testSampleStackshot("stackshot-sample-old-arrays")
1258 func testSampleStackshotNewArrays() {
1259 self.testSampleStackshot("stackshot-sample-new-arrays")
1262 func testSampleDeltaStackshotOldArrays() {
1263 self.testSampleStackshot("delta-stackshot-sample-old-arrays")
1266 func testSampleDeltaStackshotNewArrays() {
1267 self.testSampleStackshot("delta-stackshot-sample-new-arrays")
1270 func testSampleCorpse() {
1271 self.testSampleStackshot("corpse-sample")
1274 func testSampleStackshotTailspin() {
1275 self.testSampleStackshot("stackshot-sample-tailspin")
1278 func testSampleStackshotTailspin2() {
1279 self.testSampleStackshot("stackshot-sample-tailspin-2")
1282 func testSampleExitReason() {
1283 self.testSampleStackshot("exitreason-sample")
1286 func testSampleThreadT() {
1287 self.testSampleStackshot("stackshot-sample-ths-thread-t")
1290 func testSampleCpuTimes() {
1291 self.testSampleStackshot("stackshot-sample-cputime")
1294 func testSampleDuration() {
1295 self.testSampleStackshot("stackshot-sample-duration")
1298 func testSampleNested() {
1299 self.testSampleStackshot("nested-sample")
1302 func testSampleTermWithReason() {
1303 self.testSampleStackshot("test-twr-sample")
1306 func testSampleCorpseTermWithReason() {
1307 self.testSampleStackshot("corpse-twr-sample")
1310 func testSampleCorpseTermWithReasonV2() {
1311 self.testSampleStackshot("corpse-twr-sample-v2")
1314 func testSampleCodesigningExitReason() {
1315 self.testSampleStackshot("exitreason-codesigning")
1318 func testStackshotSharedcacheV2() {
1319 self.testSampleStackshot("stackshot-sample-sharedcachev2")
1322 func testStackshotFaultStats() {
1323 self.testSampleStackshot("stackshot-fault-stats")
1326 func testStackshotwithKCID() {
1327 self.testSampleStackshot("stackshot-with-kcid")
1330 func testXNUPostTestConfig() {
1331 self.testSampleStackshot("xnupost_testconfig-sample")
1334 func testTrivial() {