1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <inttypes.h>
17 #include <libgen.h>
18 #include <signal.h>
19 #include <sys/mman.h>
20 #include <sys/prctl.h>
21 #include <sys/utsname.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <optional>
25 #include <set>
26 #include <string>
27 #include <unordered_map>
28 #include <unordered_set>
29 #include <vector>
30 
31 #include <android-base/file.h>
32 #include <android-base/logging.h>
33 #include <android-base/parseint.h>
34 #include <android-base/stringprintf.h>
35 #include <android-base/strings.h>
36 #include <android-base/unique_fd.h>
37 #if defined(__ANDROID__)
38 #include <android-base/properties.h>
39 #endif
40 
41 #include "IOEventLoop.h"
42 #include "MapRecordReader.h"
43 #include "OfflineUnwinder.h"
44 #include "RecordFilter.h"
45 #include "command.h"
46 #include "dso.h"
47 #include "environment.h"
48 #include "event_selection_set.h"
49 #include "event_type.h"
50 #include "read_elf.h"
51 #include "read_symbol_map.h"
52 #include "record.h"
53 #include "thread_tree.h"
54 #include "tracing.h"
55 #include "utils.h"
56 
57 namespace simpleperf {
58 namespace {
59 
60 using android::base::ParseUint;
61 using android::base::Realpath;
62 using android::base::StringAppendF;
63 
64 struct SymbolInfo {
65   Dso* dso;
66   const Symbol* symbol;
67   uint64_t vaddr_in_file;
68 };
69 
70 // The max size of records dumped by kernel is 65535, and dump stack size
71 // should be a multiply of 8, so MAX_DUMP_STACK_SIZE is 65528.
72 constexpr uint32_t MAX_DUMP_STACK_SIZE = 65528;
73 
74 // The max allowed pages in mapped buffer is decided by rlimit(RLIMIT_MEMLOCK).
75 // Here 1024 is a desired value for pages in mapped buffer. If mapped
76 // successfully, the buffer size = 1024 * 4K (page size) = 4M.
77 constexpr size_t DESIRED_PAGES_IN_MAPPED_BUFFER = 1024;
78 
79 // Currently, the record buffer size in user-space is set to match the kernel
80 // buffer size on a 8 core system. For system-wide recording, it is 8K pages *
81 // 4K page_size * 8 cores = 256MB. For non system-wide recording, it is 1K pages
82 // * 4K page_size * 8 cores = 64MB.
83 static constexpr size_t kRecordBufferSize = 64 * 1024 * 1024;
84 static constexpr size_t kSystemWideRecordBufferSize = 256 * 1024 * 1024;
85 
86 class MonitorCommand : public Command {
87  public:
MonitorCommand()88   MonitorCommand()
89       : Command("monitor", "monitor events and print their textual representations to stdout",
90                 // clang-format off
91 "Usage: simpleperf monitor [options]\n"
92 "       Gather sampling information and print the events on stdout.\n"
93 "       For precise recording, prefer the record command.\n"
94 "       Currently, only supports system-wide collection.\n"
95 "\n"
96 "Select monitored threads:\n"
97 "-a               System-wide collection. Use with --exclude-perf to exclude\n"
98 "                 samples for simpleperf process.\n"
99 "\n"
100 "Select monitored event types:\n"
101 "-e event1[:modifier1],event2[:modifier2],...\n"
102 "             Select a list of events to record. An event can be:\n"
103 "               1) an event name listed in `simpleperf list`;\n"
104 "               2) a raw PMU event in rN format. N is a hex number.\n"
105 "                  For example, r1b selects event number 0x1b.\n"
106 "             Modifiers can be added to define how the event should be\n"
107 "             monitored. Possible modifiers are:\n"
108 "                u - monitor user space events only\n"
109 "                k - monitor kernel space events only\n"
110 "\n"
111 "Select monitoring options:\n"
112 "-f freq      Set event sample frequency. It means recording at most [freq]\n"
113 "             samples every second. For non-tracepoint events, the default\n"
114 "             option is -f 4000. A -f/-c option affects all event types\n"
115 "             following it until meeting another -f/-c option. For example,\n"
116 "             for \"-f 1000 cpu-cycles -c 1 -e sched:sched_switch\", cpu-cycles\n"
117 "             has sample freq 1000, sched:sched_switch event has sample period 1.\n"
118 "-c count     Set event sample period. It means recording one sample when\n"
119 "             [count] events happen. For tracepoint events, the default option\n"
120 "             is -c 1.\n"
121 "--call-graph fp | dwarf[,<dump_stack_size>]\n"
122 "             Enable call graph recording. Use frame pointer or dwarf debug\n"
123 "             frame as the method to parse call graph in stack.\n"
124 "             Default is dwarf,65528.\n"
125 "-g           Same as '--call-graph dwarf'.\n"
126 "--duration time_in_sec  Monitor for time_in_sec seconds. Here time_in_sec"
127 "                        may be any positive floating point number.\n"
128 "--cpu-percent <percent>  Set the max percent of cpu time used for recording.\n"
129 "                         percent is in range [1-100], default is 25.\n"
130 "\n"
131 "Sample filter options:\n"
132 "--exclude-perf                Exclude samples for simpleperf process.\n"
133 RECORD_FILTER_OPTION_HELP_MSG
134 "\n"
135                 // clang-format on
136                 ),
137         system_wide_collection_(false),
138         fp_callchain_sampling_(false),
139         dwarf_callchain_sampling_(false),
140         dump_stack_size_in_dwarf_sampling_(MAX_DUMP_STACK_SIZE),
141         unwind_dwarf_callchain_(true),
142         duration_in_sec_(0),
143         event_selection_set_(false),
144         mmap_page_range_(std::make_pair(1, DESIRED_PAGES_IN_MAPPED_BUFFER)),
145         sample_record_count_(0),
146         last_record_timestamp_(0u),
147         record_filter_(thread_tree_) {
148     // If we run `adb shell simpleperf record xxx` and stop profiling by ctrl-c,
149     // adb closes sockets connecting simpleperf. After that, simpleperf will
150     // receive SIGPIPE when writing to stdout/stderr, which is a problem when we
151     // use '--app' option. So ignore SIGPIPE to finish properly.
152     signal(SIGPIPE, SIG_IGN);
153   }
154 
155   bool Run(const std::vector<std::string>& args);
156 
157  private:
158   bool ParseOptions(const std::vector<std::string>& args);
159   bool AdjustPerfEventLimit();
160   bool PrepareMonitoring();
161   bool DoMonitoring();
162   bool SetEventSelectionFlags();
163   bool DumpProcessMaps(pid_t pid, const std::unordered_set<pid_t>& tids);
164   void DumpSampleRecord(const SampleRecord& sr);
165   void DumpSampleCallchain(const SampleRecord& sr);
166   bool ProcessRecord(Record* record);
167   SymbolInfo GetSymbolInfo(uint32_t pid, uint32_t tid, uint64_t ip, bool in_kernel);
168   bool DumpMapsForRecord(Record* record);
169   void UpdateRecord(Record* record);
170   bool UnwindRecord(SampleRecord& r);
171 
172   uint64_t max_sample_freq_ = DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT;
173   size_t cpu_time_max_percent_ = 25;
174 
175   std::unique_ptr<SampleSpeed> sample_speed_;
176   bool system_wide_collection_;
177   bool fp_callchain_sampling_;
178   bool dwarf_callchain_sampling_;
179   uint32_t dump_stack_size_in_dwarf_sampling_;
180   bool unwind_dwarf_callchain_;
181   std::unique_ptr<OfflineUnwinder> offline_unwinder_;
182   double duration_in_sec_;
183   EventSelectionSet event_selection_set_;
184   std::pair<size_t, size_t> mmap_page_range_;
185   ThreadTree thread_tree_;
186   uint64_t sample_record_count_;
187   uint64_t last_record_timestamp_;  // used to insert Mmap2Records for JIT debug info
188   // In system wide recording, record if we have dumped map info for a process.
189   std::unordered_set<pid_t> dumped_processes_;
190   bool exclude_perf_ = false;
191   RecordFilter record_filter_;
192   std::unordered_map<uint64_t, std::string> event_names_;
193 
194   std::optional<MapRecordReader> map_record_reader_;
195 };
196 
Run(const std::vector<std::string> & args)197 bool MonitorCommand::Run(const std::vector<std::string>& args) {
198   ScopedCurrentArch scoped_arch(GetMachineArch());
199   if (!CheckPerfEventLimit()) {
200     return false;
201   }
202   AllowMoreOpenedFiles();
203 
204   if (!ParseOptions(args)) {
205     return false;
206   }
207   if (!AdjustPerfEventLimit()) {
208     return false;
209   }
210 
211   if (!PrepareMonitoring()) {
212     return false;
213   }
214   return DoMonitoring();
215 }
216 
PrepareMonitoring()217 bool MonitorCommand::PrepareMonitoring() {
218   // 1. Process options before opening perf event files.
219   if (!SetEventSelectionFlags()) {
220     return false;
221   }
222   if (unwind_dwarf_callchain_) {
223     offline_unwinder_ = OfflineUnwinder::Create(false);
224   }
225 
226   // 2. Add monitored targets.
227   if (system_wide_collection_) {
228     event_selection_set_.AddMonitoredThreads({-1});
229   } else {
230     LOG(ERROR) << "No threads to monitor. Try `simpleperf help monitor` for help";
231     return false;
232   }
233 
234   // 3. Open perf event files and create mapped buffers.
235   if (!event_selection_set_.OpenEventFiles({})) {
236     return false;
237   }
238   size_t record_buffer_size =
239       system_wide_collection_ ? kSystemWideRecordBufferSize : kRecordBufferSize;
240   if (!event_selection_set_.MmapEventFiles(mmap_page_range_.first, mmap_page_range_.second,
241                                            0 /* aux_buffer_size */, record_buffer_size,
242                                            false /* allow_cutting_samples */, exclude_perf_)) {
243     return false;
244   }
245   auto callback = std::bind(&MonitorCommand::ProcessRecord, this, std::placeholders::_1);
246   if (!event_selection_set_.PrepareToReadMmapEventData(callback)) {
247     return false;
248   }
249 
250   // Keep track of the event names per id.
251   event_names_ = event_selection_set_.GetEventNamesById();
252 
253   // Use first perf_event_attr and first event id to dump mmap and comm records.
254   EventAttrWithId dumping_attr_id = event_selection_set_.GetEventAttrWithId()[0];
255   map_record_reader_.emplace(*dumping_attr_id.attr, dumping_attr_id.ids[0],
256                              event_selection_set_.RecordNotExecutableMaps());
257   map_record_reader_->SetCallback([this](Record* r) { return ProcessRecord(r); });
258 
259   // 4. Load kallsyms, if possible.
260   std::string kallsyms;
261   if (LoadKernelSymbols(&kallsyms)) {
262     Dso::SetKallsyms(std::move(kallsyms));
263   }
264   map_record_reader_->ReadKernelMaps();
265 
266   // 5. Add read/signal/periodic Events.
267   IOEventLoop* loop = event_selection_set_.GetIOEventLoop();
268   auto exit_loop_callback = [loop]() { return loop->ExitLoop(); };
269   if (!loop->AddSignalEvents({SIGCHLD, SIGINT, SIGTERM}, exit_loop_callback)) {
270     return false;
271   }
272 
273   // Only add an event for SIGHUP if we didn't inherit SIG_IGN (e.g. from
274   // nohup).
275   if (!SignalIsIgnored(SIGHUP)) {
276     if (!loop->AddSignalEvent(SIGHUP, exit_loop_callback)) {
277       return false;
278     }
279   }
280 
281   if (duration_in_sec_ != 0) {
282     if (!loop->AddPeriodicEvent(SecondToTimeval(duration_in_sec_),
283                                 [loop]() { return loop->ExitLoop(); })) {
284       return false;
285     }
286   }
287   return true;
288 }
289 
DoMonitoring()290 bool MonitorCommand::DoMonitoring() {
291   if (!event_selection_set_.GetIOEventLoop()->RunLoop()) {
292     return false;
293   }
294   if (!event_selection_set_.FinishReadMmapEventData()) {
295     return false;
296   }
297   LOG(ERROR) << "Processed samples: " << sample_record_count_;
298   return true;
299 }
300 
GetMonitorCmdOptionFormats()301 inline const OptionFormatMap& GetMonitorCmdOptionFormats() {
302   static OptionFormatMap option_formats;
303   if (option_formats.empty()) {
304     option_formats = {
305         {"-a", {OptionValueType::NONE, OptionType::SINGLE, AppRunnerType::NOT_ALLOWED}},
306         {"-c", {OptionValueType::UINT, OptionType::ORDERED, AppRunnerType::ALLOWED}},
307         {"--call-graph", {OptionValueType::STRING, OptionType::ORDERED, AppRunnerType::ALLOWED}},
308         {"--cpu-percent", {OptionValueType::UINT, OptionType::SINGLE, AppRunnerType::ALLOWED}},
309         {"--duration", {OptionValueType::DOUBLE, OptionType::SINGLE, AppRunnerType::ALLOWED}},
310         {"-e", {OptionValueType::STRING, OptionType::ORDERED, AppRunnerType::ALLOWED}},
311         {"--exclude-perf", {OptionValueType::NONE, OptionType::SINGLE, AppRunnerType::ALLOWED}},
312         {"-f", {OptionValueType::UINT, OptionType::ORDERED, AppRunnerType::ALLOWED}},
313         {"-g", {OptionValueType::NONE, OptionType::ORDERED, AppRunnerType::ALLOWED}},
314         {"-t", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
315     };
316     const OptionFormatMap& record_filter_options = GetRecordFilterOptionFormats();
317     option_formats.insert(record_filter_options.begin(), record_filter_options.end());
318   }
319   return option_formats;
320 }
321 
ParseOptions(const std::vector<std::string> & args)322 bool MonitorCommand::ParseOptions(const std::vector<std::string>& args) {
323   OptionValueMap options;
324   std::vector<std::pair<OptionName, OptionValue>> ordered_options;
325 
326   if (!PreprocessOptions(args, GetMonitorCmdOptionFormats(), &options, &ordered_options, nullptr)) {
327     return false;
328   }
329 
330   // Process options.
331   system_wide_collection_ = options.PullBoolValue("-a");
332 
333   if (!options.PullUintValue("--cpu-percent", &cpu_time_max_percent_, 1, 100)) {
334     return false;
335   }
336 
337   if (!options.PullDoubleValue("--duration", &duration_in_sec_, 1e-9)) {
338     return false;
339   }
340 
341   exclude_perf_ = options.PullBoolValue("--exclude-perf");
342   if (!record_filter_.ParseOptions(options)) {
343     return false;
344   }
345 
346   CHECK(options.values.empty());
347 
348   // Process ordered options.
349   std::vector<size_t> wait_setting_speed_event_groups;
350 
351   for (const auto& pair : ordered_options) {
352     const OptionName& name = pair.first;
353     const OptionValue& value = pair.second;
354 
355     if (name == "-c" || name == "-f") {
356       if (value.uint_value < 1) {
357         LOG(ERROR) << "invalid " << name << ": " << value.uint_value;
358         return false;
359       }
360       if (name == "-c") {
361         sample_speed_.reset(new SampleSpeed(0, value.uint_value));
362       } else {
363         if (value.uint_value >= INT_MAX) {
364           LOG(ERROR) << "sample freq can't be bigger than INT_MAX: " << value.uint_value;
365           return false;
366         }
367         sample_speed_.reset(new SampleSpeed(value.uint_value, 0));
368       }
369 
370       for (auto groud_id : wait_setting_speed_event_groups) {
371         event_selection_set_.SetSampleSpeed(groud_id, *sample_speed_);
372       }
373       wait_setting_speed_event_groups.clear();
374 
375     } else if (name == "--call-graph") {
376       std::vector<std::string> strs = android::base::Split(*value.str_value, ",");
377       if (strs[0] == "fp") {
378         fp_callchain_sampling_ = true;
379         dwarf_callchain_sampling_ = false;
380       } else if (strs[0] == "dwarf") {
381         fp_callchain_sampling_ = false;
382         dwarf_callchain_sampling_ = true;
383         if (strs.size() > 1) {
384           uint64_t size;
385           if (!ParseUint(strs[1], &size)) {
386             LOG(ERROR) << "invalid dump stack size in --call-graph option: " << strs[1];
387             return false;
388           }
389           if ((size & 7) != 0) {
390             LOG(ERROR) << "dump stack size " << size << " is not 8-byte aligned.";
391             return false;
392           }
393           if (size >= MAX_DUMP_STACK_SIZE) {
394             LOG(ERROR) << "dump stack size " << size << " is bigger than max allowed size "
395                        << MAX_DUMP_STACK_SIZE << ".";
396             return false;
397           }
398           dump_stack_size_in_dwarf_sampling_ = static_cast<uint32_t>(size);
399         }
400       }
401 
402     } else if (name == "-e") {
403       std::vector<std::string> event_types = android::base::Split(*value.str_value, ",");
404       for (auto& event_type : event_types) {
405         size_t group_id;
406         if (!event_selection_set_.AddEventType(event_type, &group_id)) {
407           return false;
408         }
409         if (sample_speed_) {
410           event_selection_set_.SetSampleSpeed(group_id, *sample_speed_);
411         } else {
412           wait_setting_speed_event_groups.push_back(group_id);
413         }
414       }
415 
416     } else if (name == "-g") {
417       fp_callchain_sampling_ = false;
418       dwarf_callchain_sampling_ = true;
419     } else {
420       CHECK(false) << "unprocessed option: " << name;
421     }
422   }
423 
424   if (event_selection_set_.empty()) {
425     LOG(ERROR) << "No event to record. Use `-e` to specify which event should be monitored.";
426     return false;
427   }
428 
429   if (fp_callchain_sampling_) {
430     if (GetBuildArch() == ARCH_ARM) {
431       LOG(WARNING) << "`--callgraph fp` option doesn't work well on arm architecture, "
432                    << "consider using `-g` option or profiling on aarch64 architecture.";
433     }
434   }
435 
436   if (system_wide_collection_ && event_selection_set_.HasMonitoredTarget()) {
437     LOG(ERROR) << "Record system wide and existing processes/threads can't be "
438                   "used at the same time.";
439     return false;
440   }
441 
442   if (system_wide_collection_ && !IsRoot()) {
443     LOG(ERROR) << "System wide profiling needs root privilege.";
444     return false;
445   }
446   return true;
447 }
448 
AdjustPerfEventLimit()449 bool MonitorCommand::AdjustPerfEventLimit() {
450   bool set_prop = false;
451   // 1. Adjust max_sample_rate.
452   uint64_t cur_max_freq;
453   if (GetMaxSampleFrequency(&cur_max_freq) && cur_max_freq < max_sample_freq_ &&
454       !SetMaxSampleFrequency(max_sample_freq_)) {
455     set_prop = true;
456   }
457   // 2. Adjust perf_cpu_time_max_percent.
458   size_t cur_percent;
459   if (GetCpuTimeMaxPercent(&cur_percent) && cur_percent != cpu_time_max_percent_ &&
460       !SetCpuTimeMaxPercent(cpu_time_max_percent_)) {
461     set_prop = true;
462   }
463   // 3. Adjust perf_event_mlock_kb.
464   long cpus = sysconf(_SC_NPROCESSORS_CONF);
465   uint64_t mlock_kb = cpus * (mmap_page_range_.second + 1) * 4;
466 
467   uint64_t cur_mlock_kb;
468   if (GetPerfEventMlockKb(&cur_mlock_kb) && cur_mlock_kb < mlock_kb &&
469       !SetPerfEventMlockKb(mlock_kb)) {
470     set_prop = true;
471   }
472 
473   if (GetAndroidVersion() >= kAndroidVersionQ && set_prop) {
474     return SetPerfEventLimits(std::max(max_sample_freq_, cur_max_freq), cpu_time_max_percent_,
475                               std::max(mlock_kb, cur_mlock_kb));
476   }
477   return true;
478 }
479 
SetEventSelectionFlags()480 bool MonitorCommand::SetEventSelectionFlags() {
481   event_selection_set_.SampleIdAll();
482   event_selection_set_.WakeupPerSample();
483   if (fp_callchain_sampling_) {
484     event_selection_set_.EnableFpCallChainSampling();
485   } else if (dwarf_callchain_sampling_) {
486     if (!event_selection_set_.EnableDwarfCallChainSampling(dump_stack_size_in_dwarf_sampling_)) {
487       return false;
488     }
489   }
490   return true;
491 }
492 
ProcessRecord(Record * record)493 bool MonitorCommand::ProcessRecord(Record* record) {
494   UpdateRecord(record);
495   last_record_timestamp_ = std::max(last_record_timestamp_, record->Timestamp());
496   // In system wide recording, maps are dumped when they are needed by records.
497   if (system_wide_collection_ && !DumpMapsForRecord(record)) {
498     return false;
499   }
500   if (record->type() == PERF_RECORD_SAMPLE) {
501     auto& r = *static_cast<SampleRecord*>(record);
502 
503     // Record filter check should go after DumpMapsForRecord(). Otherwise, process/thread name
504     // filters don't work in system wide collection.
505     if (!record_filter_.Check(&r)) {
506       return true;
507     }
508 
509     // AdjustCallChainGeneratedByKernel() should go before UnwindRecord().
510     // Because we don't want to adjust callchains generated by dwarf unwinder.
511     if (fp_callchain_sampling_ || dwarf_callchain_sampling_) {
512       r.AdjustCallChainGeneratedByKernel();
513       if (!UnwindRecord(r)) {
514         return false;
515       }
516     }
517     DumpSampleRecord(r);
518     if (fp_callchain_sampling_ || dwarf_callchain_sampling_) {
519       DumpSampleCallchain(r);
520     }
521     sample_record_count_++;
522   } else {
523     // Other types of record are forwarded to the thread tree to build the
524     // representation of each processes (mmap, comm, etc).
525     thread_tree_.Update(*record);
526   }
527   return true;
528 }
529 
DumpSampleRecord(const SampleRecord & sr)530 void MonitorCommand::DumpSampleRecord(const SampleRecord& sr) {
531   std::string output("sample");
532   StringAppendF(&output, " name=%s", event_names_[sr.id_data.id].c_str());
533   StringAppendF(&output, " ip=%p", reinterpret_cast<void*>(sr.ip_data.ip));
534   SymbolInfo s = GetSymbolInfo(sr.tid_data.pid, sr.tid_data.tid, sr.ip_data.ip, sr.InKernel());
535   StringAppendF(&output, " symbol=%s (%s[+%" PRIx64 "])", s.symbol->DemangledName(),
536                 s.dso->Path().c_str(), s.vaddr_in_file);
537   StringAppendF(&output, " pid=%u tid=%u", sr.tid_data.pid, sr.tid_data.tid);
538   StringAppendF(&output, " cpu=%u", sr.cpu_data.cpu);
539   printf("%s\n", output.c_str());
540   fflush(stdout);
541 }
542 
DumpSampleCallchain(const SampleRecord & sr)543 void MonitorCommand::DumpSampleCallchain(const SampleRecord& sr) {
544   bool in_kernel = sr.InKernel();
545   if (sr.sample_type & PERF_SAMPLE_CALLCHAIN) {
546     for (size_t i = 0; i < sr.callchain_data.ip_nr; ++i) {
547       if (sr.callchain_data.ips[i] >= PERF_CONTEXT_MAX) {
548         if (sr.callchain_data.ips[i] == PERF_CONTEXT_USER) {
549           in_kernel = false;
550         }
551         continue;
552       }
553       SymbolInfo s =
554           GetSymbolInfo(sr.tid_data.pid, sr.tid_data.tid, sr.callchain_data.ips[i], in_kernel);
555       std::string output("sample callchain");
556       StringAppendF(&output, " %s (%s[+%" PRIx64 "])", s.symbol->DemangledName(),
557                     s.dso->Path().c_str(), s.vaddr_in_file);
558       printf("%s\n", output.c_str());
559     }
560     fflush(stdout);
561   }
562 }
563 
GetSymbolInfo(uint32_t pid,uint32_t tid,uint64_t ip,bool in_kernel)564 SymbolInfo MonitorCommand::GetSymbolInfo(uint32_t pid, uint32_t tid, uint64_t ip, bool in_kernel) {
565   ThreadEntry* thread = thread_tree_.FindThreadOrNew(pid, tid);
566   const MapEntry* map = thread_tree_.FindMap(thread, ip, in_kernel);
567   SymbolInfo info;
568   info.symbol = thread_tree_.FindSymbol(map, ip, &info.vaddr_in_file, &info.dso);
569   return info;
570 }
571 
DumpMapsForRecord(Record * record)572 bool MonitorCommand::DumpMapsForRecord(Record* record) {
573   if (record->type() == PERF_RECORD_SAMPLE) {
574     pid_t pid = static_cast<SampleRecord*>(record)->tid_data.pid;
575     if (dumped_processes_.find(pid) == dumped_processes_.end()) {
576       // Dump map info and all thread names for that process.
577       if (!map_record_reader_->ReadProcessMaps(pid, last_record_timestamp_)) {
578         return false;
579       }
580       dumped_processes_.insert(pid);
581     }
582   }
583   return true;
584 }
585 
UpdateRecord(Record * record)586 void MonitorCommand::UpdateRecord(Record* record) {
587   if (record->type() == PERF_RECORD_COMM) {
588     auto r = static_cast<CommRecord*>(record);
589     if (r->data->pid == r->data->tid) {
590       std::string s = GetCompleteProcessName(r->data->pid);
591       if (!s.empty()) {
592         r->SetCommandName(s);
593       }
594     }
595   }
596 }
597 
UnwindRecord(SampleRecord & r)598 bool MonitorCommand::UnwindRecord(SampleRecord& r) {
599   if ((r.sample_type & PERF_SAMPLE_CALLCHAIN) && (r.sample_type & PERF_SAMPLE_REGS_USER) &&
600       (r.regs_user_data.reg_mask != 0) && (r.sample_type & PERF_SAMPLE_STACK_USER) &&
601       (r.GetValidStackSize() > 0)) {
602     ThreadEntry* thread = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
603     RegSet regs(r.regs_user_data.abi, r.regs_user_data.reg_mask, r.regs_user_data.regs);
604     std::vector<uint64_t> ips;
605     std::vector<uint64_t> sps;
606     if (!offline_unwinder_->UnwindCallChain(*thread, regs, r.stack_user_data.data,
607                                             r.GetValidStackSize(), &ips, &sps)) {
608       return false;
609     }
610     r.ReplaceRegAndStackWithCallChain(ips);
611   }
612   return true;
613 }
614 }  // namespace
615 
RegisterMonitorCommand()616 void RegisterMonitorCommand() {
617   RegisterCommand("monitor", [] { return std::unique_ptr<Command>(new MonitorCommand()); });
618 }
619 
620 }  // namespace simpleperf
621