this repo has no description
at fixPythonPipStalling 377 lines 9.5 kB view raw
1#include <stdio.h> 2#include <string.h> 3#include <sys/types.h> 4#include <dirent.h> 5#include <dlfcn.h> 6#include <stdbool.h> 7#include <stdlib.h> 8 9#include <mach/mach.h> 10 11#include <darling/emulation/common/simple.h> 12#include "xtracelib.h" 13#include "mach_trace.h" 14#include "bsd_trace.h" 15#include "xtrace/xtrace-mig-types.h" 16#include "tls.h" 17#include "string.h" 18 19#define XTRACE_MIG_DIR_PATH "/usr/lib/darling/xtrace-mig" 20 21static size_t subsystems_cnt = 0; 22static struct xtrace_mig_subsystem** subsystems = NULL; 23 24static mach_port_name_t host_port; 25 26extern "C" 27void xtrace_setup_mig_tracing(void) 28{ 29 // This runs before the syscall tracing is enabled, so we can 30 // freely use libSystem and make syscalls. 31 32 host_port = mach_host_self(); 33 34 DIR* xtrace_mig_dir = opendir(XTRACE_MIG_DIR_PATH); 35 if (xtrace_mig_dir == NULL) 36 { 37 perror("xtrace: failed to open " XTRACE_MIG_DIR_PATH); 38 return; 39 } 40 // Count the number of files, and allocate this many subsystem pointers; 41 for (struct dirent* dirent; (dirent = readdir(xtrace_mig_dir)) != NULL; subsystems_cnt++); 42 subsystems = (xtrace_mig_subsystem**)malloc(subsystems_cnt * sizeof(struct xtrace_mig_subsystem*)); 43 44 rewinddir(xtrace_mig_dir); 45 for (size_t i = 0; i < subsystems_cnt; i++) 46 { 47 struct dirent* dirent = readdir(xtrace_mig_dir); 48 if (dirent == NULL) 49 { 50 perror("xtrace: readdir"); 51 subsystems_cnt = i; 52 break; 53 } 54 if (dirent->d_type != DT_REG) 55 { 56 subsystems[i] = NULL; 57 continue; 58 } 59 size_t path_size = strlen(XTRACE_MIG_DIR_PATH) + 1 + strlen(dirent->d_name) + 1; 60 char path[path_size]; 61 strcpy(path, XTRACE_MIG_DIR_PATH "/"); 62 strcat(path, dirent->d_name); 63 64 void* dylib_handle = dlopen(path, RTLD_LOCAL); 65 if (dylib_handle == NULL) 66 { 67 xtrace_error("xtrace: failed to dlopen %s: %s\n", path, dlerror()); 68 subsystems[i] = NULL; 69 continue; 70 } 71 subsystems[i] = (struct xtrace_mig_subsystem*) dlsym(dylib_handle, "xtrace_mig_subsystem"); 72 if (subsystems[i] == NULL) 73 { 74 xtrace_error("xtrace: failed to dlsym(%s, \"xtrace_mig_subsystem\"): %s\n", path, dlerror()); 75 // Leave NULL subsystem in place and continue. 76 } 77 } 78 79 closedir(xtrace_mig_dir); 80} 81 82DEFINE_XTRACE_TLS_VAR(bool, is_first_arg, false, NULL); 83 84#define BEFORE if (!get_is_first_arg()) xtrace_string_append_c_string(log, ", ") 85#define AFTER set_is_first_arg(false) 86 87XTRACE_HIDDEN extern "C" 88void add_raw_arg(xtrace_string_t log, const char* format, ...) 89{ 90 va_list vl; 91 va_start(vl, format); 92 93 BEFORE; 94 xtrace_string_append_format_valist(log, format, vl); 95 AFTER; 96 97 va_end(vl); 98} 99 100XTRACE_HIDDEN extern "C" 101void add_num_arg(xtrace_string_t log, unsigned long long n) 102{ 103 BEFORE; 104 xtrace_string_append_format(log, "%llu", n); 105 AFTER; 106} 107 108XTRACE_HIDDEN extern "C" 109void add_ptr_arg(xtrace_string_t log, void* ptr) 110{ 111 BEFORE; 112 xtrace_string_append_format(log, "%p", ptr); 113 AFTER; 114} 115 116XTRACE_HIDDEN extern "C" 117void add_string_arg(xtrace_string_t log, const char* s) 118{ 119 BEFORE; 120 xtrace_print_string_literal(xtrace::String::to_cxx_ptr(log), s); 121 AFTER; 122} 123 124XTRACE_HIDDEN extern "C" 125void add_bytes_arg(xtrace_string_t log, const void* bytes, unsigned long cnt) 126{ 127 BEFORE; 128 const unsigned char* b = (const unsigned char*) bytes; 129 xtrace_string_append_c_string(log, "bytes "); 130 for (int i = 0; i < cnt; i++) 131 xtrace_string_append_format(log, "%x", b[i]); 132 AFTER; 133} 134 135XTRACE_HIDDEN extern "C" 136void add_return_code_arg(xtrace_string_t log, kern_return_t code) 137{ 138 BEFORE; 139 xtrace_print_kern_return(xtrace::String::to_cxx_ptr(log), code); 140 AFTER; 141} 142 143XTRACE_HIDDEN extern "C" 144void add_port_arg(xtrace_string_t log, mach_port_name_t port_name, mach_msg_type_name_t disposition) 145{ 146 BEFORE; 147 xtrace_string_append_format(log, "%s %u", xtrace_msg_type_to_str(disposition, 0), port_name); 148 AFTER; 149} 150 151XTRACE_HIDDEN extern "C" 152void add_ool_mem_arg(xtrace_string_t log, const void* ptr, unsigned long size) 153{ 154 BEFORE; 155 xtrace_string_append_format(log, "mem [%p; %lu]", ptr, size); 156 AFTER; 157} 158 159XTRACE_HIDDEN extern "C" 160void add_ool_ports_arg(xtrace_string_t log, const void* ptr, unsigned long cnt, mach_msg_type_name_t disposition) 161{ 162 BEFORE; 163 xtrace_string_append_format(log, "%s [%p; x%lu]", xtrace_msg_type_to_str(disposition, 0), ptr, cnt); 164 AFTER; 165} 166 167static unsigned long long read_integer(const void* ptr, unsigned int size) 168{ 169 switch (size / 8) 170 { 171 case 1: 172 return *(unsigned char*) ptr; 173 case sizeof(short): 174 return *(unsigned short*) ptr; 175 case sizeof(int): 176 return *(unsigned int*) ptr; 177/* 178 case sizeof(long): 179 return *(unsigned long*) ptr; 180*/ 181 case sizeof(long long): 182 return *(unsigned long long*) ptr; 183 default: 184 return -1; 185 } 186} 187 188XTRACE_HIDDEN extern "C" 189void add_struct_arg(xtrace_string_t log, const void* ptr, unsigned long cnt, unsigned long item_size) 190{ 191 BEFORE; 192 unsigned char* p = (unsigned char*) ptr; 193 xtrace_string_append_c_string(log, "{"); 194 for (unsigned long i = 0; i < cnt; i++) 195 { 196 if (i != 0) 197 xtrace_string_append_c_string(log, ", "); 198 xtrace_string_append_format(log, "%llu", read_integer((void*) p, item_size)); 199 p += item_size; 200 } 201 xtrace_string_append_c_string(log, "}"); 202 AFTER; 203} 204 205XTRACE_HIDDEN extern "C" 206void add_array_arg(xtrace_string_t log, const void* ptr, unsigned long cnt, unsigned long item_size) 207{ 208 BEFORE; 209 unsigned char* p = (unsigned char*) ptr; 210 xtrace_string_append_c_string(log, "["); 211 for (unsigned long i = 0; i < cnt; i++) 212 { 213 if (i != 0) 214 xtrace_string_append_c_string(log, ", "); 215 xtrace_string_append_format(log, "%llu", read_integer((void*) p, item_size)); 216 p += item_size; 217 } 218 xtrace_string_append_c_string(log, "]"); 219 AFTER; 220} 221 222XTRACE_HIDDEN extern "C" 223void set_return_code(xtrace_string_t log, kern_return_t code) 224{ 225 BEFORE; 226 xtrace_print_kern_return(xtrace::String::to_cxx_ptr(log), code); 227 AFTER; 228} 229 230#undef BEFORE 231#undef AFTER 232 233XTRACE_HIDDEN extern "C" 234const struct xtrace_mig_callbacks callbacks = { 235 .add_raw_arg = add_raw_arg, 236 .add_num_arg = add_num_arg, 237 .add_ptr_arg = add_ptr_arg, 238 .add_string_arg = add_string_arg, 239 .add_bytes_arg = add_bytes_arg, 240 .add_return_code_arg = add_return_code_arg, 241 .add_port_arg = add_port_arg, 242 .add_ool_mem_arg = add_ool_mem_arg, 243 .add_ool_ports_arg = add_ool_ports_arg, 244 .add_struct_arg = add_struct_arg, 245 .add_array_arg = add_array_arg, 246 .set_return_code = set_return_code, 247 // String Functions 248 .xtrace_string_construct = xtrace_string_construct, 249 .xtrace_string_destruct = xtrace_string_destruct, 250 .xtrace_string_clear = xtrace_string_clear, 251 .xtrace_string_c_str = xtrace_string_c_str, 252 // Logging Functions 253 .xtrace_log = xtrace_log 254}; 255 256static const struct xtrace_mig_routine_desc* find_routine(mach_msg_id_t id, const struct xtrace_mig_subsystem* s, int* out_is_reply) 257{ 258 if (s == NULL) 259 return NULL; 260 261 const struct xtrace_mig_routine_desc* r = NULL; 262 int is_reply; 263 264 if (s->base <= id && id < (s->base + s->routine_cnt)) 265 { 266 r = &s->routines[id - s->base]; 267 is_reply = 0; 268 } 269 else if (s->base + 100 <= id && id < (s->base + 100 + s->routine_cnt)) 270 { 271 r = &s->routines[id - (s->base + 100)]; 272 is_reply = 1; 273 } 274 275 if (r == NULL) 276 return NULL; 277 if (!r->present) 278 return NULL; 279 if (is_reply && !r->reply_present) 280 return NULL; 281 282 *out_is_reply = is_reply; 283 return r; 284} 285 286static int filter(const struct xtrace_mig_subsystem* s, mach_port_name_t request_port) 287{ 288 if (s == NULL) 289 return 0; 290 291 // mach_host.defs and job.defs use the same msgids, 292 // so use the request port to distinguish them. 293 if (request_port == bootstrap_port) 294 return strncmp(s->name, "job", 3) == 0; 295 if (request_port == host_port) 296 return strncmp(s->name, "host", 4) == 0; 297 298 return 1; 299} 300 301static int find_subsystem( 302 mach_msg_id_t id, 303 mach_port_name_t request_port, 304 int do_filter, 305 const struct xtrace_mig_subsystem** out_s, 306 const struct xtrace_mig_routine_desc** out_r, 307 int* out_is_reply 308) 309{ 310 // First, check if it matches any routine that has both a request and a reply. 311 // The reason for doing it like this is that many subsystems are actually 312 // "reply" and "forward" versions of other subsystems/routines, consisting only 313 // of simpleroutines; and we want to find the original ones if possible. 314 for (size_t i = 0; i < subsystems_cnt; i++) 315 { 316 if (do_filter && !filter(subsystems[i], request_port)) 317 continue; 318 319 const struct xtrace_mig_routine_desc* r = find_routine(id, subsystems[i], out_is_reply); 320 if (r != NULL && r->reply_present) 321 { 322 *out_s = subsystems[i]; 323 *out_r = r; 324 return 1; 325 } 326 } 327 328 // Now, just see if it matches anything. 329 for (size_t i = 0; i < subsystems_cnt; i++) 330 { 331 if (do_filter && !filter(subsystems[i], request_port)) 332 continue; 333 334 const struct xtrace_mig_routine_desc* r = find_routine(id, subsystems[i], out_is_reply); 335 if (r != NULL) 336 { 337 *out_s = subsystems[i]; 338 *out_r = r; 339 return 1; 340 } 341 } 342 343 return 0; 344} 345 346void xtrace_print_mig_message(xtrace::String* log, const mach_msg_header_t* message, mach_port_name_t request_port) 347{ 348 if (message == NULL) 349 return; 350 351 const struct xtrace_mig_subsystem* s; 352 const struct xtrace_mig_routine_desc* r; 353 int is_reply; 354 355 int res = find_subsystem(message->msgh_id, request_port, 1, &s, &r, &is_reply); 356 if (!res) 357 res = find_subsystem(message->msgh_id, request_port, 0, &s, &r, &is_reply); 358 if (!res) 359 return; 360 361 if (!is_reply) 362 log->append_format("%s::%s(", s->name, r->name); 363 else 364 { 365 xtrace_set_gray_color(log); 366 log->append_format("%s::%s() -> ", s->name, r->name); 367 xtrace_reset_color(log); 368 } 369 370 set_is_first_arg(true); 371 r->routine(message, is_reply, &callbacks); 372 373 if (!is_reply) 374 log->append(")"); 375 else 376 log->append(" "); 377}