]> git.saurik.com Git - apple/system_cmds.git/blob - msa/Printing.hpp
3ebb0a458c48094ac9a93629c4e66dd09f0f865b
[apple/system_cmds.git] / msa / Printing.hpp
1 //
2 // MessagePrinting.h
3 // msa
4 //
5 // Created by James McIlree on 2/5/14.
6 // Copyright (c) 2014 Apple. All rights reserved.
7 //
8
9 #ifndef __msa__MessagePrinting__
10 #define __msa__MessagePrinting__
11
12 char* print_mach_msg_header(char*, char*, const Globals&);
13 char* print_thread_set_voucher_header(char* buf, char* buf_end, const Globals& globals);
14 const char* qos_to_string(uint32_t qos);
15 const char* qos_to_short_string(uint32_t qos);
16 const char* role_to_string(uint32_t role);
17 const char* role_to_short_string(uint32_t role);
18 void print_base_empty(PrintBuffer& buffer, const Globals& globals, uintptr_t event_index, const char* type, bool should_newline);
19
20 template <typename SIZE>
21 void print_base(PrintBuffer& buffer,
22 const Globals& globals,
23 AbsTime timestamp,
24 const MachineThread<SIZE>* thread,
25 const KDEvent<SIZE>& event,
26 uintptr_t event_index,
27 const char* type,
28 bool should_newline)
29 {
30 // Base Header is... (32)
31 //
32 // Time(µS) Type Thread ThreadVoucher AppType Process ;;
33 // 123456789abcdef0 1234567890123456789012 1234567890 123456789abcdef0 12345678901234567 123456789012345678901234 12
34 // 14.11 mach_msg_send 18FB voucher-133 AdaptiveDaemon TextEdit (231) ;;
35 // 18.11 mach_msg_recv 18FB 0 InteractiveDaemon configd (19981) ;;
36
37 // Base Header is... (64)
38 //
39 // Time(µS) Type Thread ThreadVoucher AppType Process ;;
40 // 123456789abcdef0 1234567890123456789012 1234567890 123456789abcdef0 12345678901234567 123456789012345678901234 12
41 // 14.11 mach_msg_send 18FB voucher-133 AdaptiveDaemon TextEdit (231) ;;
42 // 18.11 mach_msg_recv 18FB 0 InteractiveDaemon configd (19981) ;;
43
44 //
45 // [Index]
46 //
47 if (globals.should_print_event_index()) {
48 buffer.printf("%8llu ", (uint64_t)event_index);
49 }
50
51 //
52 // Time
53 //
54 if (globals.should_print_mach_absolute_timestamps()) {
55 if (globals.beginning_of_time().value() == 0)
56 buffer.printf("%16llX ", (timestamp - globals.beginning_of_time()).value());
57 else
58 buffer.printf("%16llu ", (timestamp - globals.beginning_of_time()).value());
59 } else {
60 NanoTime ntime = (timestamp - globals.beginning_of_time()).nano_time(globals.timebase());
61 buffer.printf("%16.2f ", (double)ntime.value() / 1000.0);
62 }
63
64 //
65 // beg/end/---
66 //
67 buffer.printf("%3s ", event.is_func_start() ? "beg" : (event.is_func_end() ? "end" : "---"));
68
69 //
70 // Type Code, Thread
71 //
72
73 // This assert doesn't handle utf8...
74 ASSERT(strlen(type) <= 22, "Sanity");
75 if (SIZE::is_64_bit)
76 buffer.printf("%22s %10llX ", type, (uint64_t)thread->tid());
77 else
78 buffer.printf("%22s %10llX ", type, (uint64_t)thread->tid());
79
80 //
81 // ThreadVoucher
82 //
83 auto thread_voucher = (thread) ? thread->voucher(timestamp) : &Machine<SIZE>::UnsetVoucher;
84
85 if (thread_voucher->is_unset()) {
86 buffer.printf("%16s ", "-");
87 } else if (thread_voucher->is_null()) {
88 buffer.printf("%16s ", "0");
89 } else {
90 char voucher_id[32];
91 snprintf(voucher_id, sizeof(voucher_id), "voucher-%u", thread_voucher->id());
92 buffer.printf("%16s ", voucher_id);
93 }
94
95 //
96 // AppType
97 //
98 const char* apptype_string = nullptr;
99 switch (thread->process().apptype()) {
100 case -1:
101 apptype_string = "-";
102 break;
103 case TASK_APPTYPE_NONE:
104 apptype_string = "None";
105 break;
106 case TASK_APPTYPE_DAEMON_INTERACTIVE:
107 apptype_string = "InteractiveDaemon";
108 break;
109 case TASK_APPTYPE_DAEMON_STANDARD:
110 apptype_string = "StandardDaemon";
111 break;
112 case TASK_APPTYPE_DAEMON_ADAPTIVE:
113 apptype_string = "AdaptiveDaemon";
114 break;
115 case TASK_APPTYPE_DAEMON_BACKGROUND:
116 apptype_string = "BackgroundDaemon";
117 break;
118 case TASK_APPTYPE_APP_DEFAULT:
119 apptype_string = "App";
120 break;
121 case TASK_APPTYPE_APP_TAL:
122 apptype_string = "TALApp";
123 break;
124 default:
125 apptype_string = "???";
126 break;
127 }
128 buffer.printf("%17s ", apptype_string);
129
130 //
131 // Process
132 //
133 char process_name[32];
134
135 // Should not ever fail, but...
136 if (thread) {
137 const MachineProcess<SIZE>& process = thread->process();
138 snprintf(process_name, sizeof(process_name), "%s (%d)", process.name(), process.pid());
139 } else {
140 snprintf(process_name, sizeof(process_name), "???");
141 }
142
143 if (should_newline)
144 buffer.printf("%24s ;;\n", process_name);
145 else
146 buffer.printf("%24s ;; ", process_name);
147 }
148
149 template <typename SIZE>
150 void print_mach_msg(PrintBuffer& buffer,
151 const Globals& globals,
152 const Machine<SIZE>& machine,
153 const KDEvent<SIZE>& event,
154 uintptr_t event_index,
155 bool is_send,
156 const MachineMachMsg<SIZE>* mach_msg)
157 {
158 // Mach Msg Header is... (32)
159 //
160 // ;; Message From/To MsgID MsgVoucher DeliveryTime FLAGS
161 // 12 123456789012345678901234567 123456789ab 123456789abcdef0 1234567890123 ...
162 // ;; -> configd (19981) 55 - - ONEWAY, IMP-DONATING
163 // ;; <- TextEdit (231) 55 voucher-133 120080 VOUCHER-PROVIDED-BY-KERNEL, VOUCHER-REFUSED
164
165 // Mach Msg Header is... (64)
166 //
167 // ;; Message From/To MsgID MsgVoucher DeliveryTime FLAGS
168 // 12 123456789012345678901234567 123456789ab 123456789abcdef0 1234567890123 ...
169 // ;; -> configd (19981) 55 - - ONEWAY, IMP-DONATING
170 // ;; <- TextEdit (231) 55 voucher-133 120080 VOUCHER-PROVIDED-BY-KERNEL, VOUCHER-REFUSED
171
172 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event, event_index, is_send ? "mach_msg_send" : "mach_msg_recv", false);
173
174 //
175 // Message From/To
176 //
177 {
178 char from_to_name[32];
179 const MachineThread<SIZE>* from_to_thread = NULL;
180 const char* from_to_direction;
181
182 if (is_send) {
183 from_to_direction = "->";
184 if (mach_msg->has_receiver())
185 from_to_thread = machine.thread(mach_msg->recv_tid(), mach_msg->recv_time());
186 } else {
187 from_to_direction = "<-";
188 if (mach_msg->has_sender())
189 from_to_thread = machine.thread(mach_msg->send_tid(), mach_msg->send_time());
190 }
191
192 if (from_to_thread) {
193 const MachineProcess<SIZE>& from_to_process = from_to_thread->process();
194 snprintf(from_to_name, sizeof(from_to_name), "%s %s (%d)", from_to_direction, from_to_process.name(), from_to_process.pid());
195 } else {
196 // (???) is a trigraph, break up by escaping one of the ?
197 snprintf(from_to_name, sizeof(from_to_name), "%s ??? (??\?)", from_to_direction);
198 }
199
200 buffer.printf("%-27s ", from_to_name);
201 }
202
203 //
204 // MsgID
205 //
206
207 char msg_id[32];
208 snprintf(msg_id, sizeof(msg_id), "msg-%u", mach_msg->id());
209 buffer.printf("%11s ", msg_id);
210
211 //
212 // MsgVoucher
213 //
214 // We want to differentiate between sending a NULL voucher and not having msgh_bits set.
215 // We will show a NULL voucher as 0, but if msgh_bits says no voucher was sent, we will show "-"
216 //
217
218 MachineVoucher<SIZE>* msg_voucher = (is_send) ? mach_msg->send_voucher() : mach_msg->recv_voucher();
219
220 if (msg_voucher->is_unset()) {
221 buffer.printf("%16s ", "-");
222 } else if (msg_voucher->is_null()) {
223 buffer.printf("%16s ", "0");
224 } else {
225 char voucher_id[32];
226 snprintf(voucher_id, sizeof(voucher_id), "voucher-%u", msg_voucher->id());
227 buffer.printf("%16s ", voucher_id);
228 }
229
230 //
231 // DeliveryTime
232 //
233
234 if (!is_send) {
235 if (mach_msg->has_sender()) {
236 NanoTime ntime = (mach_msg->recv_time() - mach_msg->send_time()).nano_time(globals.timebase());
237 buffer.printf("%13.2f ", (double)ntime.value() / 1000.0);
238 } else {
239 buffer.printf("%13s ", "?");
240 }
241 } else {
242 buffer.printf("%13s ", "-");
243 }
244
245 //
246 // FLAGS
247 //
248 const char* separator = "";
249
250 if (is_send) {
251 if (!MACH_MSGH_BITS_HAS_LOCAL(mach_msg->send_msgh_bits())) {
252 buffer.printf("%sONEWAY", separator);
253 separator = ", ";
254 }
255
256 if (MACH_MSGH_BITS_RAISED_IMPORTANCE(mach_msg->send_msgh_bits())) {
257 buffer.printf("%sMSGH_BITS_RAISED_IMPORTANCE", separator);
258 separator = ", ";
259 }
260
261 if (MACH_MSGH_BITS_HOLDS_IMPORTANCE_ASSERTION(mach_msg->send_msgh_bits())) {
262 buffer.printf("%sMSGH_BITS_HOLDS_IMPORTANCE_ASSERTION", separator);
263 separator = ", ";
264 }
265 } else {
266 if (mach_msg->is_voucher_refused()) {
267 // FIX ME!
268 // Need to test this... Can we tell if a voucher was refused without the
269 // send voucher?
270 //
271 if (mach_msg->has_non_null_send_voucher() || mach_msg->has_non_null_recv_voucher()) {
272 buffer.printf("%sVOUCHER-REFUSED", separator);
273 }
274
275 separator = ", ";
276 }
277 if (MACH_MSGH_BITS_RAISED_IMPORTANCE(mach_msg->recv_msgh_bits())) {
278 buffer.printf("%sMSGH_BITS_RAISED_IMPORTANCE", separator);
279 separator = ", ";
280 }
281
282 if (MACH_MSGH_BITS_HOLDS_IMPORTANCE_ASSERTION(mach_msg->recv_msgh_bits())) {
283 buffer.printf("%sMSGH_BITS_HOLDS_IMPORTANCE_ASSERTION", separator);
284 separator = ", ";
285 }
286 }
287
288 //
289 // MsgVoucher transformation
290 //
291 {
292 char transformed_voucher[32];
293
294 if (mach_msg->has_sender() && mach_msg->has_receiver()) {
295 auto send_voucher = mach_msg->send_voucher();
296 auto recv_voucher = mach_msg->recv_voucher();
297
298 if (send_voucher != recv_voucher) {
299 auto changed_voucher = (is_send) ? recv_voucher : send_voucher;
300 auto changed_tense = (is_send) ? "becomes" : "was";
301
302 if (changed_voucher->is_unset()) {
303 snprintf(transformed_voucher, sizeof(transformed_voucher), "(%s -)", changed_tense);
304 } else if (changed_voucher->is_null()) {
305 snprintf(transformed_voucher, sizeof(transformed_voucher), "(%s 0)", changed_tense);
306 } else {
307 snprintf(transformed_voucher, sizeof(transformed_voucher), "(%s voucher-%u)", changed_tense, changed_voucher->id());
308 }
309
310 buffer.printf("%sVOUCHER_CHANGED %s", separator, transformed_voucher);
311 }
312 }
313 }
314
315 buffer.printf("\n");
316 }
317
318 template <typename SIZE>
319 void print_boost(PrintBuffer& buffer,
320 const Globals& globals,
321 const Machine<SIZE>& machine,
322 const KDEvent<SIZE>& event,
323 uintptr_t event_index,
324 pid_t boost_receiver_pid,
325 bool is_boost)
326 {
327
328 // Base Header is... (32)
329 //
330 // ;;
331 // 12
332 // ;; BOOST foobard (338)
333
334 // Base Header is... (64)
335 //
336 // ;;
337 // 12
338 // ;; BOOST foobard (338)
339
340
341 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event, event_index, is_boost ? "boost" : "unboost", false);
342
343 //
344 // Boost target
345 //
346
347 const MachineProcess<SIZE>* target = machine.process(boost_receiver_pid, event.timestamp());
348 const char* target_name;
349
350 if (target) {
351 target_name = target->name();
352 } else {
353 target_name = "???";
354 }
355
356 const char* action = is_boost ? "BOOST" : "UNBOOST";
357
358 buffer.printf("%s %s (%d)\n", action, target_name, boost_receiver_pid);
359 }
360
361 template <typename SIZE>
362 void print_impdelv(PrintBuffer& buffer,
363 const Globals& globals,
364 const Machine<SIZE>& machine,
365 const KDEvent<SIZE>& event,
366 uintptr_t event_index,
367 pid_t sender_pid,
368 uint32_t importance_delivery_result)
369 {
370 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event, event_index, "importance_delivered", false);
371
372 //
373 // Importance sender
374 //
375 const char* sender_name = "???";
376 if (const MachineProcess<SIZE>* sender = machine.process(sender_pid, event.timestamp())) {
377 sender_name = sender->name();
378 }
379
380 // 0: BOOST NOT APPLIED
381 // 1: BOOST EXTERNALIZED
382 // 2: LIVE_IMPORTANCE_LINKAGE!
383
384 switch (importance_delivery_result) {
385 case 0:
386 buffer.printf("importance from %s (%d) was not applied\n", sender_name, sender_pid);
387 break;
388 case 1:
389 buffer.printf("importance from %s (%d) was externalized\n", sender_name, sender_pid);
390 break;
391 case 2:
392 buffer.printf("linked to %s (%d)'s live importance chain\n", sender_name, sender_pid);
393 break;
394
395 default:
396 ASSERT(false, "Unknown importance delivery result value");
397 buffer.printf("Unknown importance delivery result value\n");
398 break;
399 }
400 }
401
402 template <typename SIZE>
403 void print_generic(PrintBuffer& buffer,
404 const Globals& globals,
405 const Machine<SIZE>& machine,
406 const KDEvent<SIZE>& event,
407 uintptr_t event_index,
408 const char* type)
409 {
410 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event, event_index, type, true);
411 }
412
413 template <typename SIZE>
414 void print_importance_assert(PrintBuffer& buffer,
415 const Globals& globals,
416 const Machine<SIZE>& machine,
417 const KDEvent<SIZE>& event,
418 uintptr_t event_index,
419 const char* type,
420 std::unordered_map<pid_t, std::pair<uint32_t, uint32_t>>& task_importance)
421 {
422 // All callers must have the following trace event data:
423 //
424 // ignored, target_pid, internal_count, external_count
425
426 // First check if anything changed
427 pid_t target_pid = (pid_t)event.arg2();
428 if (target_pid < 1)
429 return;
430
431 bool must_print = false;
432 auto it = task_importance.find(target_pid);
433 if (it == task_importance.end()) {
434 it = task_importance.emplace(target_pid, std::pair<uint32_t, uint32_t>(0, 0)).first;
435 // The very first time we see data for an app, we always want to print it.
436 must_print = true;
437 }
438
439 auto old_importance = it->second;
440 auto new_importance = std::pair<uint32_t, uint32_t>((uint32_t)event.arg3(), (uint32_t)event.arg4());
441 if (must_print || old_importance != new_importance) {
442 const MachineThread<SIZE>* event_thread = machine.thread(event.tid(), event.timestamp());
443 print_base(buffer, globals, event.timestamp(), event_thread, event, event_index, type, false);
444
445 const MachineProcess<SIZE>* target = machine.process(target_pid, event.timestamp());
446 const char* target_name;
447
448 if (target) {
449 target_name = target->name();
450 } else {
451 target_name = "???";
452 }
453
454 int internal_delta = new_importance.first - old_importance.first;
455 int external_delta = new_importance.second - old_importance.second;
456
457 char internal_sign = internal_delta >= 0 ? '+' : '-';
458 char external_sign = external_delta >= 0 ? '+' : '-';
459
460 char internal_changed_buf[32];
461 char external_changed_buf[32];
462
463 if (internal_delta != 0) {
464 snprintf(internal_changed_buf, sizeof(internal_changed_buf), " (%c%u)", internal_sign, abs(internal_delta));
465 } else {
466 internal_changed_buf[0] = 0;
467 }
468
469 if (external_delta != 0) {
470 snprintf(external_changed_buf, sizeof(external_changed_buf), " (%c%u)", external_sign, abs(external_delta));
471 } else {
472 external_changed_buf[0] = 0;
473 }
474
475 buffer.printf("%s (%d) internal: %u%s external: %u%s\n",
476 target_name, target_pid,
477 new_importance.first, internal_changed_buf,
478 new_importance.second, external_changed_buf);
479
480 it->second = new_importance;
481 }
482 }
483
484 template <typename SIZE>
485 void print_watchport_importance_transfer(PrintBuffer& buffer,
486 const Globals& globals,
487 const Machine<SIZE>& machine,
488 const KDEvent<SIZE>& event,
489 uintptr_t event_index)
490 {
491 // event data is
492 //
493 // proc_selfpid(), pid, boost, released_pid, 0);
494
495 // Did any importance transfer?
496 if (event.arg3() == 0)
497 return;
498
499 // Do we have a valid pid?
500 pid_t dest_pid = (pid_t)event.arg2();
501 if (dest_pid < 1)
502 return;
503
504 const MachineThread<SIZE>* event_thread = machine.thread(event.tid(), event.timestamp());
505 print_base(buffer, globals, event.timestamp(), event_thread, event, event_index, "importance_watchport", false);
506
507 const char* dest_name;
508 if (const MachineProcess<SIZE>* dest = machine.process(dest_pid, event.timestamp())) {
509 dest_name = dest->name();
510 } else {
511 dest_name = "???";
512 }
513
514 buffer.printf("%s (%d) receives %d importance via watchport\n",
515 dest_name, dest_pid, (int)event.arg3());
516 }
517
518 template <typename SIZE>
519 void print_importance_send_failed(PrintBuffer& buffer,
520 const Globals& globals,
521 const Machine<SIZE>& machine,
522 const KDEvent<SIZE>& event,
523 uintptr_t event_index)
524 {
525 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event, event_index, "impsend", false);
526
527 //
528 // Currently, the IMP_MSG_SEND trace data is not accurate.
529 //
530
531 buffer.printf("Backed out importance (may be resent) - TIMED_OUT, NO_BUFFER, or SEND_INTERRUPTED\n");
532 }
533
534 #if 0
535
536 template <typename SIZE>
537 void print_trequested_task(PrintBuffer& buffer,
538 const Globals& globals,
539 const Machine<SIZE>& machine,
540 const KDEvent<SIZE>& event,
541 uintptr_t event_index,
542 pid_t pid,
543 struct task_requested_policy new_task_requested,
544 struct task_requested_policy original_task_requested)
545 {
546 // Many of these events would print nothing, we want to make sure there is something to print first.
547
548 char description[512];
549 char* cursor = description;
550 char* cursor_end = cursor + sizeof(description);
551 uint32_t description_count = 0;
552
553 if (new_task_requested.t_role != original_task_requested.t_role) {
554 const char* role = "???";
555 switch (new_task_requested.t_role) {
556 // This is seen when apps are terminating
557 case TASK_UNSPECIFIED:
558 role = "unspecified";
559 break;
560
561 case TASK_FOREGROUND_APPLICATION:
562 role = "foreground";
563 break;
564
565 case TASK_BACKGROUND_APPLICATION:
566 role = "background";
567 break;
568
569 case TASK_CONTROL_APPLICATION:
570 role = "control-application";
571 break;
572
573 case TASK_GRAPHICS_SERVER:
574 role = "graphics-server";
575 break;
576
577 case TASK_THROTTLE_APPLICATION:
578 role = "throttle-application";
579 break;
580
581 case TASK_NONUI_APPLICATION:
582 role = "nonui-application";
583 break;
584
585 case TASK_DEFAULT_APPLICATION:
586 role = "default-application";
587 break;
588
589 default:
590 ASSERT(false, "Unexpected app role");
591 break;
592 }
593 cursor += snprintf(cursor, cursor_end - cursor, "%sROLE:%s", description_count++ == 0 ? "" : ", ", role);
594 GUARANTEE(cursor < cursor_end);
595 }
596
597 if (new_task_requested.int_darwinbg != original_task_requested.int_darwinbg) {
598 cursor += snprintf(cursor, cursor_end - cursor, "%s%sINT_DARWINBG", description_count++ == 0 ? "" : ", ", new_task_requested.int_darwinbg ? "" : "!");
599 GUARANTEE(cursor < cursor_end);
600 }
601
602 if (new_task_requested.ext_darwinbg != original_task_requested.ext_darwinbg) {
603 cursor += snprintf(cursor, cursor_end - cursor, "%s%sEXT_DARWINBG", description_count++ == 0 ? "" : ", ", new_task_requested.ext_darwinbg ? "" : "!");
604 GUARANTEE(cursor < cursor_end);
605 }
606
607 if (new_task_requested.t_int_gpu_deny != original_task_requested.t_int_gpu_deny) {
608 cursor += snprintf(cursor, cursor_end - cursor, "%sINT_GPU_DENY", description_count++ == 0 ? "" : ", ");
609 GUARANTEE(cursor < cursor_end);
610 }
611
612 if (new_task_requested.t_ext_gpu_deny != original_task_requested.t_ext_gpu_deny) {
613 cursor += snprintf(cursor, cursor_end - cursor, "%sEXT_GPU_DENY", description_count++ == 0 ? "" : ", ");
614 GUARANTEE(cursor < cursor_end);
615 }
616
617 if (new_task_requested.t_tal_enabled != original_task_requested.t_tal_enabled) {
618 cursor += snprintf(cursor, cursor_end - cursor, "%sTAL_ENABLED", description_count++ == 0 ? "" : ", ");
619 GUARANTEE(cursor < cursor_end);
620 }
621
622 if (new_task_requested.t_sfi_managed != original_task_requested.t_sfi_managed) {
623 cursor += snprintf(cursor, cursor_end - cursor, "%sSFI_MANAGED", description_count++ == 0 ? "" : ", ");
624 GUARANTEE(cursor < cursor_end);
625 }
626
627 if (new_task_requested.t_sup_active != original_task_requested.t_sup_active) {
628 cursor += snprintf(cursor, cursor_end - cursor, "%sAPPNAP", description_count++ == 0 ? "" : ", ");
629 GUARANTEE(cursor < cursor_end);
630 }
631
632 if (new_task_requested.t_base_latency_qos != original_task_requested.t_base_latency_qos) {
633 cursor += snprintf(cursor, cursor_end - cursor, "%sBASE_LATENCY_QOS:%s", description_count++ == 0 ? "" : ", ", qos_to_string(new_task_requested.t_base_latency_qos));
634 GUARANTEE(cursor < cursor_end);
635 }
636
637 if (new_task_requested.t_over_latency_qos != original_task_requested.t_over_latency_qos) {
638 cursor += snprintf(cursor, cursor_end - cursor, "%sOVERRIDE_LATENCY_QOS:%s", description_count++ == 0 ? "" : ", ", qos_to_string(new_task_requested.t_over_latency_qos));
639 GUARANTEE(cursor < cursor_end);
640 }
641
642 if (new_task_requested.t_base_through_qos != original_task_requested.t_base_through_qos) {
643 cursor += snprintf(cursor, cursor_end - cursor, "%sBASE_THROUGHPUT_QOS:%s", description_count++ == 0 ? "" : ", ", qos_to_string(new_task_requested.t_base_through_qos));
644 GUARANTEE(cursor < cursor_end);
645 }
646
647 if (new_task_requested.t_over_through_qos != original_task_requested.t_over_through_qos) {
648 cursor += snprintf(cursor, cursor_end - cursor, "%sOVERRIDE_THROUGHPUT_QOS:%s", description_count++ == 0 ? "" : ", ", qos_to_string(new_task_requested.t_over_through_qos));
649 GUARANTEE(cursor < cursor_end);
650 }
651
652 if (new_task_requested.t_qos_clamp != original_task_requested.t_qos_clamp) {
653 cursor += snprintf(cursor, cursor_end - cursor, "%sQOS_CLAMP:%s", description_count++ == 0 ? "" : ", ", qos_to_string(new_task_requested.t_qos_clamp));
654 GUARANTEE(cursor < cursor_end);
655 }
656
657 if (description_count) {
658 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event_index, "task_trequested", false);
659
660 ASSERT(pid != -1, "Sanity");
661
662 const char* target_name;
663 if (const MachineProcess<SIZE>* target = machine.process(pid, event.timestamp())) {
664 target_name = target->name();
665 } else {
666 target_name = "???";
667 }
668
669 buffer.printf("%s (%d) requests %s\n", target_name, pid, description);
670 }
671 }
672
673 struct task_requested_policy {
674 /* Task and thread policy (inherited) */
675 uint64_t int_darwinbg :1, /* marked as darwinbg via setpriority */
676 ext_darwinbg :1,
677 int_iotier :2, /* IO throttle tier */
678 ext_iotier :2,
679 int_iopassive :1, /* should IOs cause lower tiers to be throttled */
680 ext_iopassive :1,
681 bg_iotier :2, /* what IO throttle tier should apply to me when I'm darwinbg? (pushed to threads) */
682 terminated :1, /* all throttles should be removed for quick exit or SIGTERM handling */
683
684 /* Thread only policy */
685 th_pidbind_bg :1, /* thread only: task i'm bound to is marked 'watchbg' */
686 th_workq_bg :1, /* thread only: currently running a background priority workqueue */
687 thrp_qos :3, /* thread only: thread qos class */
688 thrp_qos_relprio :4, /* thread only: thread qos relative priority (store as inverse, -10 -> 0xA) */
689 thrp_qos_override :3, /* thread only: thread qos class override */
690
691 /* Task only policy */
692 t_apptype :3, /* What apptype did launchd tell us this was (inherited) */
693 t_boosted :1, /* Has a non-zero importance assertion count */
694 t_int_gpu_deny :1, /* don't allow access to GPU */
695 t_ext_gpu_deny :1,
696 t_role :3, /* task's system role */
697 t_tal_enabled :1, /* TAL mode is enabled */
698 t_base_latency_qos :3, /* Timer latency QoS */
699 t_over_latency_qos :3, /* Timer latency QoS override */
700 t_base_through_qos :3, /* Computation throughput QoS */
701 t_over_through_qos :3, /* Computation throughput QoS override */
702 t_sfi_managed :1, /* SFI Managed task */
703 t_qos_clamp :3, /* task qos clamp */
704
705 /* Task only: suppression policies (non-embedded only) */
706 t_sup_active :1, /* Suppression is on */
707 t_sup_lowpri_cpu :1, /* Wants low priority CPU (MAXPRI_THROTTLE) */
708 t_sup_timer :3, /* Wanted timer throttling QoS tier */
709 t_sup_disk :1, /* Wants disk throttling */
710 t_sup_cpu_limit :1, /* Wants CPU limit (not hooked up yet)*/
711 t_sup_suspend :1, /* Wants to be suspended */
712 t_sup_throughput :3, /* Wants throughput QoS tier */
713 t_sup_cpu :1, /* Wants suppressed CPU priority (MAXPRI_SUPPRESSED) */
714 t_sup_bg_sockets :1, /* Wants background sockets */
715
716 reserved :2;
717 };
718 #endif
719
720 template <typename SIZE>
721 void print_appnap(PrintBuffer& buffer,
722 const Globals& globals,
723 const Machine<SIZE>& machine,
724 const KDEvent<SIZE>& event,
725 uintptr_t event_index,
726 bool is_appnap_active,
727 std::unordered_map<pid_t, bool>& task_appnap_state,
728 std::unordered_map<pid_t, TaskRequestedPolicy>& task_requested_state)
729 {
730 //
731 // event args are:
732 //
733 // self_pid, audit_token_pid_from_task(task), trequested_0(task, NULL), trequested_1(task, NULL)
734 //
735 auto pid = (pid_t)event.arg2();
736 auto trequested_0 = event.arg3();
737 auto trequested_1 = event.arg4();
738 auto task_requested = (SIZE::is_64_bit) ? TaskRequestedPolicy(trequested_0) : TaskRequestedPolicy((Kernel32::ptr_t)trequested_0, (Kernel32::ptr_t)trequested_1);
739 auto should_print = false;
740
741 ASSERT(pid != -1, "Sanity");
742
743 // If the appnap state changed, we want to print this event.
744 auto appnap_it = task_appnap_state.find(pid);
745 if (appnap_it == task_appnap_state.end()) {
746 should_print = true;
747 task_appnap_state.emplace(pid, is_appnap_active);
748 } else {
749 if (appnap_it->second != is_appnap_active) {
750 should_print = true;
751 appnap_it->second = is_appnap_active;
752 }
753 }
754
755 // If the task_requested state changed, we want to print this event.
756 auto requested_it = task_requested_state.find(pid);
757 if (requested_it == task_requested_state.end()) {
758 should_print = true;
759 task_requested_state.emplace(pid, task_requested);
760 } else {
761 if (requested_it->second != task_requested) {
762 should_print = true;
763 requested_it->second = task_requested;
764 }
765 }
766
767 if (should_print) {
768 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event, event_index, "imp_supression", false);
769
770 const char* name;
771 if (auto target = machine.process(pid, event.timestamp())) {
772 name = target->name();
773 } else {
774 name = "???";
775 }
776 buffer.printf("%s (%d) AppNap is %s\n", name, pid, is_appnap_active ? "ON" : "OFF");
777 print_trequested_task(buffer, globals, machine, event, event_index, pid, task_requested);
778 }
779 }
780
781 template <typename SIZE>
782 void print_trequested_task(PrintBuffer& buffer,
783 const Globals& globals,
784 const Machine<SIZE>& machine,
785 const KDEvent<SIZE>& event,
786 uintptr_t event_index,
787 pid_t pid,
788 TaskRequestedPolicy task_requested)
789 {
790
791 ASSERT(pid != -1, "Sanity");
792 const char* target_name;
793 if (const MachineProcess<SIZE>* target = machine.process(pid, event.timestamp())) {
794 target_name = target->name();
795 } else {
796 target_name = "???";
797 }
798
799 struct task_requested_policy trp = task_requested.as_struct();
800
801 print_base_empty(buffer, globals, event_index, "task_trequested", false);
802 buffer.printf("%s (%d) requests%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
803 target_name, pid,
804 trp.int_darwinbg ? " IntDBG" : "",
805 trp.ext_darwinbg ? " ExtDBG" : "",
806 trp.int_iopassive ? " IntIOPass" : "",
807 trp.ext_iopassive ? " ExtIOPass" : "",
808 trp.terminated ? " Term" : "",
809 trp.t_boosted ? " Boost" : "",
810 trp.t_int_gpu_deny ? " IntDenyGPU" : "",
811 trp.t_ext_gpu_deny ? " ExtDenyGPU" : "",
812 trp.t_tal_enabled ? " TAL" : "",
813 trp.t_sfi_managed ? " SFI" : "",
814 // Below here is AppNap only...
815 trp.t_sup_active ? " AppNap" : "",
816 trp.t_sup_lowpri_cpu ? " SupLowPriCPU" : "",
817 trp.t_sup_disk ? " SupDisk" : "",
818 trp.t_sup_cpu_limit ? " SupCPULim" : "",
819 trp.t_sup_suspend ? " SupSusp" : "",
820 trp.t_sup_cpu ? " SupCPU" : "",
821 trp.t_sup_bg_sockets ? " SupBGSck" : "");
822
823 print_base_empty(buffer, globals, event_index, "task_trequested", false);
824 buffer.printf("%s (%d) requests QOS (SupTHR/SupTMR/LAT/OVERLAT/THR/OVERTHR/CLAMP) %s/%s/%s/%s/%s/%s/%s int_IOTier:%d ext_IOTier:%d bg_IOTier:%d\n",
825 target_name, pid,
826 qos_to_string(trp.t_sup_throughput),
827 qos_to_string(trp.t_sup_timer),
828 qos_to_string(trp.t_base_latency_qos),
829 qos_to_string(trp.t_over_latency_qos),
830 qos_to_string(trp.t_base_through_qos),
831 qos_to_string(trp.t_over_through_qos),
832 qos_to_string(trp.t_qos_clamp),
833 trp.int_iotier,
834 trp.ext_iotier,
835 trp.bg_iotier);
836 }
837
838 template <typename SIZE>
839 void print_trequested_thread(PrintBuffer& buffer,
840 const Globals& globals,
841 const Machine<SIZE>& machine,
842 const KDEvent<SIZE>& event,
843 uintptr_t event_index,
844 const MachineThread<SIZE>* thread,
845 struct task_requested_policy new_thread_requested,
846 struct task_requested_policy original_thread_requested)
847 {
848 ASSERT(thread, "Sanity");
849
850 // Many of these events would print nothing, we want to make sure there is something to print first.
851
852 char description[512];
853 char* cursor = description;
854 char* cursor_end = cursor + sizeof(description);
855 uint32_t description_count = 0;
856
857 if (new_thread_requested.int_darwinbg != original_thread_requested.int_darwinbg) {
858 cursor += snprintf(cursor, cursor_end - cursor, "%sINT_DARWINBG", description_count++ == 0 ? "" : ", ");
859 GUARANTEE(cursor < cursor_end);
860 }
861
862 if (new_thread_requested.ext_darwinbg != original_thread_requested.ext_darwinbg) {
863 cursor += snprintf(cursor, cursor_end - cursor, "%sEXT_DARWINBG", description_count++ == 0 ? "" : ", ");
864 GUARANTEE(cursor < cursor_end);
865 }
866
867 if (new_thread_requested.th_pidbind_bg != original_thread_requested.th_pidbind_bg) {
868 cursor += snprintf(cursor, cursor_end - cursor, "%sPIDBIND_BG", description_count++ == 0 ? "" : ", ");
869 GUARANTEE(cursor < cursor_end);
870 }
871
872 if (new_thread_requested.th_workq_bg != original_thread_requested.th_workq_bg) {
873 cursor += snprintf(cursor, cursor_end - cursor, "%sWORKQ_BG", description_count++ == 0 ? "" : ", ");
874 GUARANTEE(cursor < cursor_end);
875 }
876
877 if (new_thread_requested.thrp_qos != original_thread_requested.thrp_qos) {
878 cursor += snprintf(cursor, cursor_end - cursor, "%sTHREAD_QOS:%s", description_count++ == 0 ? "" : ", ", qos_to_string(new_thread_requested.thrp_qos));
879 GUARANTEE(cursor < cursor_end);
880 }
881
882 if (new_thread_requested.thrp_qos_relprio != original_thread_requested.thrp_qos_relprio) {
883 cursor += snprintf(cursor, cursor_end - cursor, "%sTHREAD_QOS_RELATIVE_PRIORITY:%d", description_count++ == 0 ? "" : ", ", -new_thread_requested.thrp_qos_relprio);
884 GUARANTEE(cursor < cursor_end);
885 }
886
887 if (new_thread_requested.thrp_qos_override != original_thread_requested.thrp_qos_override) {
888 cursor += snprintf(cursor, cursor_end - cursor, "%sTHREAD_OVERRIDE_QOS:%s", description_count++ == 0 ? "" : ", ", qos_to_string(new_thread_requested.thrp_qos_override));
889 GUARANTEE(cursor < cursor_end);
890 }
891
892 if (description_count) {
893 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event_index, "thread_trequested", false);
894 ASSERT(thread->process().pid() != -1, "Sanity");
895 buffer.printf("%s (%d) %llX requests %s\n", thread->process().name(), thread->process().pid(), (uint64_t)thread->tid(), description);
896 }
897 }
898
899 template <typename SIZE>
900 void print_teffective_task(PrintBuffer& buffer,
901 const Globals& globals,
902 const Machine<SIZE>& machine,
903 const KDEvent<SIZE>& event,
904 uintptr_t event_index,
905 pid_t pid,
906 TaskEffectivePolicy task_effective)
907 {
908 ASSERT(pid != -1, "Sanity");
909 const char* target_name;
910 if (const MachineProcess<SIZE>* target = machine.process(pid, event.timestamp())) {
911 target_name = target->name();
912 } else {
913 target_name = "???";
914 }
915
916 struct task_effective_policy tep = task_effective.as_struct();
917
918 print_base_empty(buffer, globals, event_index, "task_teffective", false);
919 buffer.printf("%s (%d) is%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
920 target_name, pid,
921 tep.darwinbg ? " DarwinBG" : "",
922 tep.t_sup_active ? " AppNap" : "",
923 tep.lowpri_cpu ? " LowPri" : "",
924 tep.io_passive ? " IOPass" : "",
925 tep.all_sockets_bg ? " ASckBG" : "",
926 tep.new_sockets_bg ? " NSckBG" : "",
927 tep.terminated ? " Term" : "",
928 tep.qos_ui_is_urgent ? " QOSUiIsUrg" : "",
929 tep.t_gpu_deny ? " GPUDeny" : "",
930 tep.t_suspended ? " SupSusp" : "",
931 tep.t_watchers_bg ? " WchrsBG" : "",
932 tep.t_suppressed_cpu ? " SupCPU" : "",
933 tep.t_sfi_managed ? " SFI" : "",
934 tep.t_live_donor ? " LiveImpDnr" : "");
935
936 print_base_empty(buffer, globals, event_index, "task_teffective", false);
937 buffer.printf("%s (%d) is Role:%s LAT/THR/CLAMP/CEIL:%s/%s/%s/%s IOTier:%d BG_IOTier:%d\n",
938 target_name, pid,
939 role_to_string(tep.t_role),
940 qos_to_string(tep.t_latency_qos),
941 qos_to_string(tep.t_through_qos),
942 qos_to_string(tep.t_qos_clamp),
943 qos_to_string(tep.t_qos_ceiling),
944 tep.io_tier,
945 tep.bg_iotier);
946 }
947
948 template <typename SIZE>
949 void print_teffective_thread(PrintBuffer& buffer,
950 const Globals& globals,
951 const Machine<SIZE>& machine,
952 const KDEvent<SIZE>& event,
953 uintptr_t event_index,
954 const MachineThread<SIZE>* thread,
955 TaskEffectivePolicy thread_effective)
956 {
957 ASSERT(thread, "Sanity");
958
959 const char* target_name = thread->process().name();
960
961 struct task_effective_policy tep = thread_effective.as_struct();
962
963 print_base_empty(buffer, globals, event_index, "thread_teffective", false);
964 buffer.printf("%s (%d) %llX is%s%s%s%s%s%s%s%s\n",
965 target_name, thread->process().pid(), (uint64_t)thread->tid(),
966 tep.darwinbg ? " DarwinBG" : "",
967 tep.t_sup_active ? " AppNap" : "",
968 tep.lowpri_cpu ? " LowPri" : "",
969 tep.io_passive ? " IOPass" : "",
970 tep.all_sockets_bg ? " ASckBG" : "",
971 tep.new_sockets_bg ? " NSckBG" : "",
972 tep.terminated ? " Term" : "",
973 tep.qos_ui_is_urgent ? " QOSUiIsUrg" : "");
974
975 print_base_empty(buffer, globals, event_index, "thread_teffective", false);
976 buffer.printf("%s (%d) %llX is QOS:%s QOS_relprio:%d\n",
977 target_name, thread->process().pid(), (uint64_t)thread->tid(),
978 qos_to_string(tep.thep_qos),
979 tep.thep_qos_relprio);
980 }
981
982 template <typename SIZE>
983 void print_importance_apptype(PrintBuffer& buffer,
984 const Globals& globals,
985 const Machine<SIZE>& machine,
986 const KDEvent<SIZE>& event,
987 uintptr_t event_index)
988 {
989 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event, event_index, "set_apptype", false);
990
991 //
992 // trace args are:
993 //
994 // selfpid, targetpid, trequested(targetpid, NULL), is_importance_receiver
995
996 //
997 // QoS clamp
998 //
999 // Can only be determined on K64, the bits needed are trimmed off in
1000 // K32 tracepoints.
1001
1002 char qos_clamp[32];
1003 qos_clamp[0] = 0;
1004 if (SIZE::is_64_bit) {
1005 uint32_t qos_level = (event.arg3() & POLICY_REQ_QOS_CLAMP_MASK) >> POLICY_REQ_QOS_CLAMP_SHIFT;
1006 if (qos_level != THREAD_QOS_UNSPECIFIED) {
1007 snprintf(qos_clamp, sizeof(qos_clamp), ", clamped to %s", qos_to_string(qos_level));
1008 }
1009 }
1010
1011 pid_t target_pid = (pid_t)event.arg2();
1012 const char* target_name;
1013
1014 if (target_pid != -1 ) {
1015 if (const MachineProcess<SIZE>* target = machine.process(target_pid, event.timestamp())) {
1016 target_name = target->name();
1017 } else {
1018 target_name = "???";
1019 }
1020 } else {
1021 target_name = "NULL-Task";
1022 }
1023
1024 const char* apptype = "???";
1025 switch (event.dbg_code()) {
1026 case TASK_APPTYPE_NONE:
1027 apptype = "None";
1028 break;
1029 case TASK_APPTYPE_DAEMON_INTERACTIVE:
1030 apptype = "InteractiveDaemon";
1031 break;
1032 case TASK_APPTYPE_DAEMON_STANDARD:
1033 apptype = "StandardDaemon";
1034 break;
1035 case TASK_APPTYPE_DAEMON_ADAPTIVE:
1036 apptype = "AdaptiveDaemon";
1037 break;
1038 case TASK_APPTYPE_DAEMON_BACKGROUND:
1039 apptype = "BackgroundDaemon";
1040 break;
1041 case TASK_APPTYPE_APP_DEFAULT:
1042 apptype = "App";
1043 break;
1044 case TASK_APPTYPE_APP_TAL:
1045 apptype = "TALApp";
1046 break;
1047 default:
1048 break;
1049 }
1050
1051 const char* imp_recv = "";
1052 if (event.arg4()) {
1053 imp_recv = ", receives importance";
1054 }
1055 buffer.printf("Set %s (%d) to %s%s%s\n", target_name, target_pid, apptype, imp_recv, qos_clamp);
1056 }
1057
1058 template <typename SIZE>
1059 void print_importance_update_task(PrintBuffer& buffer,
1060 const Globals& globals,
1061 const Machine<SIZE>& machine,
1062 const KDEvent<SIZE>& event,
1063 uintptr_t event_index,
1064 const char* type,
1065 std::unordered_map<pid_t, std::pair<TaskEffectivePolicy, uint32_t>>& task_effective_state)
1066 {
1067 //
1068 // event args are:
1069 //
1070 // targetpid, teffective_0(task, NULL), teffective_1(task, NULL), tpriority(task, THREAD_NULL)
1071 //
1072 auto pid = (pid_t)event.arg1();
1073 auto teffective_0 = event.arg2();
1074 auto teffective_1 = event.arg3();
1075 auto priority = (uint32_t)event.arg4();
1076 auto task_effective_policy = (SIZE::is_64_bit) ? TaskEffectivePolicy(teffective_0) : TaskEffectivePolicy((Kernel32::ptr_t)teffective_0, (Kernel32::ptr_t)teffective_1);
1077 auto state = std::pair<TaskEffectivePolicy, uint32_t>(task_effective_policy, priority);
1078 auto should_print = false;
1079
1080 ASSERT(pid != -1, "Sanity");
1081
1082 // Verify that some state changed before printing.
1083 auto it = task_effective_state.find(pid);
1084 if (it == task_effective_state.end()) {
1085 should_print = true;
1086 task_effective_state.emplace(pid, state);
1087 } else {
1088 if (it->second != state) {
1089 should_print = true;
1090 it->second = state;
1091 }
1092 }
1093
1094 if (should_print) {
1095 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event, event_index, type, false);
1096
1097 const char* name;
1098 if (auto target = machine.process(pid, event.timestamp())) {
1099 name = target->name();
1100 } else {
1101 name = "???";
1102 }
1103
1104 buffer.printf("%s (%d) base priority is %d\n", name, pid, priority);
1105
1106 print_teffective_task(buffer, globals, machine, event, event_index, pid, task_effective_policy);
1107 }
1108 }
1109
1110 template <typename SIZE>
1111 void print_importance_update_thread(PrintBuffer& buffer,
1112 const Globals& globals,
1113 const Machine<SIZE>& machine,
1114 const KDEvent<SIZE>& event,
1115 uintptr_t event_index,
1116 const char* type,
1117 std::unordered_map<typename SIZE::ptr_t, std::pair<TaskEffectivePolicy, uint32_t>>& thread_effective_state)
1118 {
1119 //
1120 // event args are:
1121 //
1122 // targettid, teffective_0(task, thread), teffective_1(task, thread), tpriority(task, thread)
1123 //
1124
1125 if (const MachineThread<SIZE>* thread = machine.thread(event.arg1(), event.timestamp())) {
1126 auto pid = thread->process().pid();
1127 auto teffective_0 = event.arg2();
1128 auto teffective_1 = event.arg3();
1129 auto priority = (uint32_t)event.arg4();
1130 auto thread_effective_policy = (SIZE::is_64_bit) ? TaskEffectivePolicy(teffective_1) : TaskEffectivePolicy((Kernel32::ptr_t)teffective_0, (Kernel32::ptr_t)teffective_1);
1131 auto state = std::pair<TaskEffectivePolicy, uint32_t>(thread_effective_policy, priority);
1132 auto should_print = false;
1133
1134 // Verify that some state changed before printing.
1135 auto it = thread_effective_state.find(thread->tid());
1136 if (it == thread_effective_state.end()) {
1137 should_print = true;
1138 thread_effective_state.emplace(thread->tid(), state);
1139 } else {
1140 if (it->second != state) {
1141 should_print = true;
1142 it->second = state;
1143 }
1144 }
1145
1146 if (should_print) {
1147 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event, event_index, type, false);
1148 buffer.printf("%s (%d) %llX base priority is %d\n", thread->process().name(), pid, (uint64_t)thread->tid(), priority);
1149
1150 print_teffective_thread(buffer, globals, machine, event, event_index, thread, thread_effective_policy);
1151 }
1152 }
1153 }
1154
1155 template <typename SIZE>
1156 void print_fork(PrintBuffer& buffer,
1157 const Globals& globals,
1158 const Machine<SIZE>& machine,
1159 const KDEvent<SIZE>& event,
1160 uintptr_t event_index,
1161 const MachineProcess<SIZE>& child_process)
1162 {
1163 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event, event_index, "fork", false);
1164
1165 //
1166 // Other process
1167 //
1168
1169 buffer.printf("Create %s (%d)\n", child_process.name(), child_process.pid());
1170 }
1171
1172 template <typename SIZE>
1173 void print_exit(PrintBuffer& buffer,
1174 const Globals& globals,
1175 const KDEvent<SIZE>& event,
1176 const MachineThread<SIZE>* thread,
1177 uintptr_t event_index)
1178 {
1179 ASSERT(thread, "Sanity");
1180
1181 print_base(buffer, globals, event.timestamp(), thread, event, event_index, "exit", false);
1182
1183 //
1184 // exit code
1185 //
1186
1187 int exit_status = thread->process().exit_status();
1188
1189 if (WIFEXITED(exit_status)) {
1190 buffer.printf("returned %d\n", WEXITSTATUS(exit_status));
1191 } else if (WIFSIGNALED(exit_status)) {
1192 buffer.printf("SIGNAL: %s\n", strsignal(WTERMSIG(exit_status)));
1193 } else {
1194 buffer.printf("Unhandled exit status %x\n", (uint32_t)exit_status);
1195 }
1196 }
1197
1198 template <typename SIZE>
1199 void print_voucher(PrintBuffer& buffer,
1200 const Globals& globals,
1201 const Machine<SIZE>& machine,
1202 const KDEvent<SIZE>& event,
1203 uintptr_t event_index,
1204 const char* type,
1205 const MachineVoucher<SIZE>* voucher,
1206 bool is_create)
1207 {
1208 print_base(buffer, globals, event.timestamp(), machine.thread(event.tid(), event.timestamp()), event, event_index, type, false);
1209
1210 //
1211 // Calculate lifetime
1212 //
1213
1214 char lifetime[32];
1215 AbsInterval timespan = voucher->timespan();
1216
1217 //
1218 // Voucher created before the trace starts will have a starting time
1219 // of 0; Vouchers that are still alive will have a max of UINT64_MAX.
1220 //
1221 if (timespan.location() == AbsTime(0) || timespan.max() == AbsTime(UINT64_MAX)) {
1222 snprintf(lifetime, sizeof(lifetime), "???");
1223 } else {
1224 NanoTime t1 = timespan.length().nano_time(globals.timebase());
1225 snprintf(lifetime, sizeof(lifetime), "%0.2f", (double)t1.value() / NANOSECONDS_PER_MICROSECOND);
1226 }
1227
1228
1229 //
1230 // Voucher addr
1231 //
1232 if (is_create) {
1233 buffer.printf("Create voucher-%u @ %llX, lifetime will be %s µs, now %u vouchers\n", voucher->id(), (uint64_t)voucher->address(), lifetime, (uint32_t)event.arg3());
1234 } else {
1235 buffer.printf("Destroy voucher-%u @ %llX, lifetime was %s µs, now %u vouchers\n", voucher->id(), (uint64_t)voucher->address(), lifetime, (uint32_t)event.arg3());
1236 }
1237 }
1238
1239 template <typename SIZE>
1240 void print_voucher_contents(PrintBuffer& buffer,
1241 const Globals& globals,
1242 const Machine<SIZE>& machine,
1243 const KDEvent<SIZE>& event,
1244 uintptr_t event_index,
1245 const MachineVoucher<SIZE>* voucher)
1246 {
1247 const uint8_t* bytes = voucher->content_bytes();
1248 uint32_t bytes_required = voucher->content_size();
1249
1250 ASSERT(bytes_required, "Printing empty voucher");
1251
1252 unsigned int used_size = 0;
1253 mach_voucher_attr_recipe_t recipe = NULL;
1254 while (bytes_required > used_size) {
1255 recipe = (mach_voucher_attr_recipe_t)&bytes[used_size];
1256
1257 switch (recipe->key) {
1258 case MACH_VOUCHER_ATTR_KEY_NONE:
1259 ASSERT(false, "No key in recipe");
1260 break;
1261
1262 case MACH_VOUCHER_ATTR_KEY_ATM:
1263 print_base_empty(buffer, globals, event_index, "voucher_create", false);
1264 buffer.printf(" voucher-%u | ATM ID %llu\n", voucher->id(), *(uint64_t *)(uintptr_t)recipe->content);
1265 break;
1266
1267 case MACH_VOUCHER_ATTR_KEY_IMPORTANCE:
1268 print_base_empty(buffer, globals, event_index, "voucher_create", false);
1269 buffer.printf(" voucher-%u | %s\n", voucher->id(), (char *)recipe->content);
1270 break;
1271
1272 case MACH_VOUCHER_ATTR_KEY_BANK:
1273 // Spacing and newline is different because that is how BANK formats it :-(
1274 print_base_empty(buffer, globals, event_index, "voucher_create", false);
1275 buffer.printf(" voucher-%u |%s", voucher->id(), (char *)recipe->content);
1276 break;
1277
1278 case MACH_VOUCHER_ATTR_KEY_USER_DATA:
1279 for (uint32_t offset=0; offset<recipe->content_size; offset += 16) {
1280 uint8_t* data = ((uint8_t*)recipe->content) + offset;
1281 size_t data_remaining = std::min(recipe->content_size - offset, (uint32_t)16);
1282
1283 print_base_empty(buffer, globals, event_index, "voucher_create", false);
1284 buffer.printf(" voucher-%u | UserData: %04u ", voucher->id(), offset);
1285
1286 // 16 * 3 == 48, 16 chars to spare
1287 char hex_buffer[64];
1288 // Hex data.
1289 for (uint32_t cursor = 0; cursor<data_remaining; cursor++) {
1290 char* hex_buffer_tmp = &hex_buffer[cursor * 3];
1291 size_t hex_buffer_tmp_size = sizeof(hex_buffer) - cursor * 3;
1292 snprintf(hex_buffer_tmp, hex_buffer_tmp_size, "%02x ", data[cursor]);
1293 }
1294
1295 char ascii_buffer[24];
1296 for (uint32_t cursor = 0; cursor<data_remaining; cursor++) {
1297 if (isprint(data[cursor]))
1298 ascii_buffer[cursor] = data[cursor];
1299 else
1300 ascii_buffer[cursor] = '.';
1301 }
1302 ascii_buffer[data_remaining] = 0;
1303
1304 buffer.printf("%-48s %-16s\n", hex_buffer, ascii_buffer);
1305 }
1306 break;
1307
1308 default:
1309 print_base_empty(buffer, globals, event_index, "voucher_create", false);
1310 buffer.printf(" voucher-%u | UNKNOWN key-%u command-%u size-%u\n", voucher->id(), recipe->key, recipe->command, recipe->content_size);
1311 break;
1312 }
1313
1314 used_size += sizeof(mach_voucher_attr_recipe_data_t) + recipe->content_size;
1315 }
1316 }
1317
1318 #endif /* defined(__msa__MessagePrinting__) */