brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.3 KiB · 371a146 Raw
316 lines · cpp
1//===-- Genealogy.cpp -------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include <Availability.h>10#include <dlfcn.h>11#include <string>12#include <uuid/uuid.h>13 14#include "DNBDefs.h"15#include "Genealogy.h"16#include "GenealogySPI.h"17#include "MachThreadList.h"18 19/// Constructor20 21Genealogy::Genealogy()22    : m_os_activity_diagnostic_for_pid(nullptr),23      m_os_activity_iterate_processes(nullptr),24      m_os_activity_iterate_breadcrumbs(nullptr),25      m_os_activity_iterate_messages(nullptr),26      m_os_activity_iterate_activities(nullptr), m_os_trace_get_type(nullptr),27      m_os_trace_copy_formatted_message(nullptr),28      m_os_activity_for_thread(nullptr), m_os_activity_for_task_thread(nullptr),29      m_thread_activities(), m_process_executable_infos(),30      m_diagnosticd_call_timed_out(false) {31  m_os_activity_diagnostic_for_pid =32      (bool (*)(pid_t, os_activity_t, uint32_t, os_diagnostic_block_t))dlsym(33          RTLD_DEFAULT, "os_activity_diagnostic_for_pid");34  m_os_activity_iterate_processes =35      (void (*)(os_activity_process_list_t, bool (^)(os_activity_process_t)))36          dlsym(RTLD_DEFAULT, "os_activity_iterate_processes");37  m_os_activity_iterate_breadcrumbs =38      (void (*)(os_activity_process_t, bool (^)(os_activity_breadcrumb_t)))39          dlsym(RTLD_DEFAULT, "os_activity_iterate_breadcrumbs");40  m_os_activity_iterate_messages = (void (*)(41      os_trace_message_list_t, os_activity_process_t,42      bool (^)(os_trace_message_t)))dlsym(RTLD_DEFAULT,43                                          "os_activity_iterate_messages");44  m_os_activity_iterate_activities = (void (*)(45      os_activity_list_t, os_activity_process_t,46      bool (^)(os_activity_entry_t)))dlsym(RTLD_DEFAULT,47                                           "os_activity_iterate_activities");48  m_os_trace_get_type =49      (uint8_t(*)(os_trace_message_t))dlsym(RTLD_DEFAULT, "os_trace_get_type");50  m_os_trace_copy_formatted_message = (char *(*)(os_trace_message_t))dlsym(51      RTLD_DEFAULT, "os_trace_copy_formatted_message");52  m_os_activity_for_thread =53      (os_activity_t(*)(os_activity_process_t, uint64_t))dlsym(54          RTLD_DEFAULT, "os_activity_for_thread");55  m_os_activity_for_task_thread = (os_activity_t(*)(task_t, uint64_t))dlsym(56      RTLD_DEFAULT, "os_activity_for_task_thread");57  m_os_activity_messages_for_thread = (os_trace_message_list_t(*)(58      os_activity_process_t process, os_activity_t activity,59      uint64_t thread_id))dlsym(RTLD_DEFAULT,60                                "os_activity_messages_for_thread");61}62 63Genealogy::ThreadActivitySP64Genealogy::GetGenealogyInfoForThread(pid_t pid, nub_thread_t tid,65                                     const MachThreadList &thread_list,66                                     task_t task, bool &timed_out) {67  ThreadActivitySP activity;68  //69  // if we've timed out trying to get the activities, don't try again at this70  // process stop.71  // (else we'll need to hit the timeout for every thread we're asked about.)72  // We'll try again at the next public stop.73 74  if (m_thread_activities.size() == 0 && !m_diagnosticd_call_timed_out) {75    GetActivities(pid, thread_list, task);76  }77  std::map<nub_thread_t, ThreadActivitySP>::const_iterator search;78  search = m_thread_activities.find(tid);79  if (search != m_thread_activities.end()) {80    activity = search->second;81  }82  timed_out = m_diagnosticd_call_timed_out;83  return activity;84}85 86void Genealogy::Clear() {87  m_thread_activities.clear();88  m_diagnosticd_call_timed_out = false;89}90 91void Genealogy::GetActivities(pid_t pid, const MachThreadList &thread_list,92                              task_t task) {93  if (m_os_activity_diagnostic_for_pid != nullptr &&94      m_os_activity_iterate_processes != nullptr &&95      m_os_activity_iterate_breadcrumbs != nullptr &&96      m_os_activity_iterate_messages != nullptr &&97      m_os_activity_iterate_activities != nullptr &&98      m_os_trace_get_type != nullptr &&99      m_os_trace_copy_formatted_message != nullptr &&100      (m_os_activity_for_thread != nullptr ||101       m_os_activity_for_task_thread != nullptr)) {102    __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);103    __block BreadcrumbList breadcrumbs;104    __block ActivityList activities;105    __block MessageList messages;106    __block std::map<nub_thread_t, uint64_t> thread_activity_mapping;107 108    os_activity_diagnostic_flag_t flags =109        OS_ACTIVITY_DIAGNOSTIC_ALL_ACTIVITIES |110        OS_ACTIVITY_DIAGNOSTIC_PROCESS_ONLY;111    if (m_os_activity_diagnostic_for_pid(112            pid, 0, flags, ^(os_activity_process_list_t processes, int error) {113              if (error == 0) {114                m_os_activity_iterate_processes(processes, ^bool(115                                                    os_activity_process_t116                                                        process_info) {117                  if (pid == process_info->pid) {118                    // Collect all the Breadcrumbs119                    m_os_activity_iterate_breadcrumbs(120                        process_info,121                        ^bool(os_activity_breadcrumb_t breadcrumb) {122                          Breadcrumb bc;123                          bc.breadcrumb_id = breadcrumb->breadcrumb_id;124                          bc.activity_id = breadcrumb->activity_id;125                          bc.timestamp = breadcrumb->timestamp;126                          if (breadcrumb->name)127                            bc.name = breadcrumb->name;128                          breadcrumbs.push_back(bc);129                          return true;130                        });131 132                    // Collect all the Activities133                    m_os_activity_iterate_activities(134                        process_info->activities, process_info,135                        ^bool(os_activity_entry_t activity) {136                          Activity ac;137                          ac.activity_start = activity->activity_start;138                          ac.activity_id = activity->activity_id;139                          ac.parent_id = activity->parent_id;140                          if (activity->activity_name)141                            ac.activity_name = activity->activity_name;142                          if (activity->reason)143                            ac.reason = activity->reason;144                          activities.push_back(ac);145                          return true;146                        });147 148                    // Collect all the Messages -- messages not associated with149                    // any thread150                    m_os_activity_iterate_messages(151                        process_info->messages, process_info,152                        ^bool(os_trace_message_t trace_msg) {153                          Message msg;154                          msg.timestamp = trace_msg->timestamp;155                          msg.trace_id = trace_msg->trace_id;156                          msg.thread = trace_msg->thread;157                          msg.type = m_os_trace_get_type(trace_msg);158                          msg.activity_id = 0;159                          if (trace_msg->image_uuid && trace_msg->image_path) {160                            ProcessExecutableInfoSP process_info_sp(161                                new ProcessExecutableInfo());162                            uuid_copy(process_info_sp->image_uuid,163                                      trace_msg->image_uuid);164                            process_info_sp->image_path = trace_msg->image_path;165                            msg.process_info_index =166                                AddProcessExecutableInfo(process_info_sp);167                          }168                          const char *message_text =169                              m_os_trace_copy_formatted_message(trace_msg);170                          if (message_text)171                            msg.message = message_text;172                          messages.push_back(msg);173                          return true;174                        });175 176                    // Discover which activities are said to be running on177                    // threads currently178                    const nub_size_t num_threads = thread_list.NumThreads();179                    for (nub_size_t i = 0; i < num_threads; ++i) {180                      nub_thread_t thread_id = thread_list.ThreadIDAtIndex(i);181                      os_activity_t act = 0;182                      if (m_os_activity_for_task_thread != nullptr) {183                        act = m_os_activity_for_task_thread(task, thread_id);184                      } else if (m_os_activity_for_thread != nullptr) {185                        act = m_os_activity_for_thread(process_info, thread_id);186                      }187                      if (act != 0)188                        thread_activity_mapping[thread_id] = act;189                    }190 191                    // Collect all Messages -- messages associated with a thread192 193                    // When there's no genealogy information, an early version194                    // of os_activity_messages_for_thread195                    // can crash in rare circumstances.  Check to see if this196                    // process has any activities before197                    // making the call to get messages.198                    if (process_info->activities != nullptr &&199                        thread_activity_mapping.size() > 0) {200                      std::map<nub_thread_t, uint64_t>::const_iterator iter;201                      for (iter = thread_activity_mapping.begin();202                           iter != thread_activity_mapping.end(); ++iter) {203                        nub_thread_t thread_id = iter->first;204                        os_activity_t act = iter->second;205                        os_trace_message_list_t this_thread_messages =206                            m_os_activity_messages_for_thread(process_info, act,207                                                              thread_id);208                        m_os_activity_iterate_messages(209                            this_thread_messages, process_info,210                            ^bool(os_trace_message_t trace_msg) {211                              Message msg;212                              msg.timestamp = trace_msg->timestamp;213                              msg.trace_id = trace_msg->trace_id;214                              msg.thread = trace_msg->thread;215                              msg.type = m_os_trace_get_type(trace_msg);216                              msg.activity_id = act;217                              if (trace_msg->image_uuid &&218                                  trace_msg->image_path) {219                                ProcessExecutableInfoSP process_info_sp(220                                    new ProcessExecutableInfo());221                                uuid_copy(process_info_sp->image_uuid,222                                          trace_msg->image_uuid);223                                process_info_sp->image_path =224                                    trace_msg->image_path;225                                msg.process_info_index =226                                    AddProcessExecutableInfo(process_info_sp);227                              }228                              const char *message_text =229                                  m_os_trace_copy_formatted_message(trace_msg);230                              if (message_text)231                                msg.message = message_text;232                              messages.push_back(msg);233                              return true;234                            });235                      }236                    }237                  }238                  return true;239                });240              }241              dispatch_semaphore_signal(semaphore);242            }) == true) {243      // Wait for the diagnosticd xpc calls to all finish up -- or half a second244      // to elapse.245      dispatch_time_t timeout =246          dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2);247      bool success = dispatch_semaphore_wait(semaphore, timeout) == 0;248      if (!success) {249        m_diagnosticd_call_timed_out = true;250        return;251      }252    }253 254    // breadcrumbs, activities, and messages have all now been filled in.255 256    std::map<nub_thread_t, uint64_t>::const_iterator iter;257    for (iter = thread_activity_mapping.begin();258         iter != thread_activity_mapping.end(); ++iter) {259      nub_thread_t thread_id = iter->first;260      uint64_t activity_id = iter->second;261      ActivityList::const_iterator activity_search;262      for (activity_search = activities.begin();263           activity_search != activities.end(); ++activity_search) {264        if (activity_search->activity_id == activity_id) {265          ThreadActivitySP thread_activity_sp(new ThreadActivity());266          thread_activity_sp->current_activity = *activity_search;267 268          BreadcrumbList::const_iterator breadcrumb_search;269          for (breadcrumb_search = breadcrumbs.begin();270               breadcrumb_search != breadcrumbs.end(); ++breadcrumb_search) {271            if (breadcrumb_search->activity_id == activity_id) {272              thread_activity_sp->breadcrumbs.push_back(*breadcrumb_search);273            }274          }275          MessageList::const_iterator message_search;276          for (message_search = messages.begin();277               message_search != messages.end(); ++message_search) {278            if (message_search->thread == thread_id) {279              thread_activity_sp->messages.push_back(*message_search);280            }281          }282 283          m_thread_activities[thread_id] = thread_activity_sp;284          break;285        }286      }287    }288  }289}290 291uint32_t292Genealogy::AddProcessExecutableInfo(ProcessExecutableInfoSP process_exe_info) {293  const uint32_t info_size =294      static_cast<uint32_t>(m_process_executable_infos.size());295  for (uint32_t idx = 0; idx < info_size; ++idx) {296    if (uuid_compare(m_process_executable_infos[idx]->image_uuid,297                     process_exe_info->image_uuid) == 0) {298      return idx + 1;299    }300  }301  m_process_executable_infos.push_back(process_exe_info);302  return info_size + 1;303}304 305Genealogy::ProcessExecutableInfoSP306Genealogy::GetProcessExecutableInfosAtIndex(size_t idx) {307  ProcessExecutableInfoSP info_sp;308  if (idx > 0) {309    idx--;310    if (idx <= m_process_executable_infos.size()) {311      info_sp = m_process_executable_infos[idx];312    }313  }314  return info_sp;315}316