summaryrefslogtreecommitdiff
path: root/simpleperf/cmd_report_sample.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/cmd_report_sample.cpp')
-rw-r--r--simpleperf/cmd_report_sample.cpp381
1 files changed, 242 insertions, 139 deletions
diff --git a/simpleperf/cmd_report_sample.cpp b/simpleperf/cmd_report_sample.cpp
index e133fb28..b547d3c9 100644
--- a/simpleperf/cmd_report_sample.cpp
+++ b/simpleperf/cmd_report_sample.cpp
@@ -21,22 +21,25 @@
#include <android-base/strings.h>
-#include "system/extras/simpleperf/report_sample.pb.h"
+#include "system/extras/simpleperf/cmd_report_sample.pb.h"
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include "OfflineUnwinder.h"
#include "command.h"
#include "event_attr.h"
#include "event_type.h"
#include "record_file.h"
+#include "report_utils.h"
#include "thread_tree.h"
#include "utils.h"
-namespace proto = simpleperf_report_proto;
-
+namespace simpleperf {
namespace {
+namespace proto = simpleperf_report_proto;
+
static const char PROT_FILE_MAGIC[] = "SIMPLEPERF";
static const uint16_t PROT_FILE_VERSION = 1u;
@@ -56,19 +59,66 @@ class ProtobufFileReader : public google::protobuf::io::CopyingInputStream {
public:
explicit ProtobufFileReader(FILE* in_fp) : in_fp_(in_fp) {}
- int Read(void* buffer, int size) override {
- return fread(buffer, 1, size, in_fp_);
- }
+ int Read(void* buffer, int size) override { return fread(buffer, 1, size, in_fp_); }
private:
FILE* in_fp_;
};
-struct CallEntry {
- Dso* dso;
- const Symbol* symbol;
- uint64_t vaddr_in_file;
-};
+static proto::Sample_CallChainEntry_ExecutionType ToProtoExecutionType(
+ CallChainExecutionType type) {
+ switch (type) {
+ case CallChainExecutionType::NATIVE_METHOD:
+ return proto::Sample_CallChainEntry_ExecutionType_NATIVE_METHOD;
+ case CallChainExecutionType::INTERPRETED_JVM_METHOD:
+ return proto::Sample_CallChainEntry_ExecutionType_INTERPRETED_JVM_METHOD;
+ case CallChainExecutionType::JIT_JVM_METHOD:
+ return proto::Sample_CallChainEntry_ExecutionType_JIT_JVM_METHOD;
+ case CallChainExecutionType::ART_METHOD:
+ return proto::Sample_CallChainEntry_ExecutionType_ART_METHOD;
+ }
+ CHECK(false) << "unexpected execution type";
+ return proto::Sample_CallChainEntry_ExecutionType_NATIVE_METHOD;
+}
+
+static const char* ProtoExecutionTypeToString(proto::Sample_CallChainEntry_ExecutionType type) {
+ switch (type) {
+ case proto::Sample_CallChainEntry_ExecutionType_NATIVE_METHOD:
+ return "native_method";
+ case proto::Sample_CallChainEntry_ExecutionType_INTERPRETED_JVM_METHOD:
+ return "interpreted_jvm_method";
+ case proto::Sample_CallChainEntry_ExecutionType_JIT_JVM_METHOD:
+ return "jit_jvm_method";
+ case proto::Sample_CallChainEntry_ExecutionType_ART_METHOD:
+ return "art_method";
+ }
+ CHECK(false) << "unexpected execution type: " << type;
+ return "";
+}
+
+static const char* ProtoUnwindingErrorCodeToString(
+ proto::Sample_UnwindingResult_ErrorCode error_code) {
+ switch (error_code) {
+ case proto::Sample_UnwindingResult::ERROR_NONE:
+ return "ERROR_NONE";
+ case proto::Sample_UnwindingResult::ERROR_UNKNOWN:
+ return "ERROR_UNKNOWN";
+ case proto::Sample_UnwindingResult::ERROR_NOT_ENOUGH_STACK:
+ return "ERROR_NOT_ENOUGH_STACK";
+ case proto::Sample_UnwindingResult::ERROR_MEMORY_INVALID:
+ return "ERROR_MEMORY_INVALID";
+ case proto::Sample_UnwindingResult::ERROR_UNWIND_INFO:
+ return "ERROR_UNWIND_INFO";
+ case proto::Sample_UnwindingResult::ERROR_INVALID_MAP:
+ return "ERROR_INVALID_MAP";
+ case proto::Sample_UnwindingResult::ERROR_MAX_FRAME_EXCEEDED:
+ return "ERROR_MAX_FRAME_EXCEEDED";
+ case proto::Sample_UnwindingResult::ERROR_REPEATED_FRAME:
+ return "ERROR_REPEATED_FRAME";
+ case proto::Sample_UnwindingResult::ERROR_INVALID_ELF:
+ return "ERROR_INVALID_ELF";
+ }
+}
class ReportSampleCommand : public Command {
public:
@@ -84,12 +134,14 @@ class ReportSampleCommand : public Command {
"-o report_file_name Set report file name. Default report file name is\n"
" report_sample.trace if --protobuf is used, otherwise\n"
" the report is written to stdout.\n"
-"--protobuf Use protobuf format in report_sample.proto to output samples.\n"
+"--proguard-mapping-file <file> Add proguard mapping file to de-obfuscate symbols.\n"
+"--protobuf Use protobuf format in cmd_report_sample.proto to output samples.\n"
" Need to set a report_file_name when using this option.\n"
"--show-callchain Print callchain samples.\n"
"--remove-unknown-kernel-symbols Remove kernel callchains when kernel symbols\n"
" are not available in perf.data.\n"
"--show-art-frames Show frames of internal methods in the ART Java interpreter.\n"
+"--show-execution-type Show execution type of a method\n"
"--symdir <dir> Look for files with symbols in a directory recursively.\n"
// clang-format on
),
@@ -103,7 +155,7 @@ class ReportSampleCommand : public Command {
trace_offcpu_(false),
remove_unknown_kernel_symbols_(false),
kernel_symbols_available_(false),
- show_art_frames_(false) {}
+ callchain_report_builder_(thread_tree_) {}
bool Run(const std::vector<std::string>& args) override;
@@ -116,14 +168,14 @@ class ReportSampleCommand : public Command {
void UpdateThreadName(uint32_t pid, uint32_t tid);
bool ProcessSampleRecord(const SampleRecord& r);
bool PrintSampleRecordInProtobuf(const SampleRecord& record,
- const std::vector<CallEntry>& entries);
- bool GetCallEntry(const ThreadEntry* thread, bool in_kernel, uint64_t ip, bool omit_unknown_dso,
- CallEntry* entry);
+ const std::vector<CallChainReportEntry>& entries);
+ void AddUnwindingResultInProtobuf(proto::Sample_UnwindingResult* proto_unwinding_result);
bool WriteRecordInProtobuf(proto::Record& proto_record);
bool PrintLostSituationInProtobuf();
bool PrintFileInfoInProtobuf();
bool PrintThreadInfoInProtobuf();
- bool PrintSampleRecord(const SampleRecord& record, const std::vector<CallEntry>& entries);
+ bool PrintSampleRecord(const SampleRecord& record,
+ const std::vector<CallChainReportEntry>& entries);
void PrintLostSituation();
std::string record_filename_;
@@ -141,9 +193,11 @@ class ReportSampleCommand : public Command {
std::vector<std::string> event_types_;
bool remove_unknown_kernel_symbols_;
bool kernel_symbols_available_;
- bool show_art_frames_;
+ bool show_execution_type_ = false;
+ CallChainReportBuilder callchain_report_builder_;
// map from <pid, tid> to thread name
std::map<uint64_t, const char*> thread_names_;
+ std::unique_ptr<UnwindingResultRecord> last_unwinding_result_;
};
bool ReportSampleCommand::Run(const std::vector<std::string>& args) {
@@ -191,10 +245,8 @@ bool ReportSampleCommand::Run(const std::vector<std::string>& args) {
return false;
}
protobuf_writer.reset(new ProtobufFileWriter(report_fp_));
- protobuf_os.reset(new google::protobuf::io::CopyingOutputStreamAdaptor(
- protobuf_writer.get()));
- protobuf_coded_os.reset(
- new google::protobuf::io::CodedOutputStream(protobuf_os.get()));
+ protobuf_os.reset(new google::protobuf::io::CopyingOutputStreamAdaptor(protobuf_writer.get()));
+ protobuf_coded_os.reset(new google::protobuf::io::CodedOutputStream(protobuf_os.get()));
coded_os_ = protobuf_coded_os.get();
}
@@ -203,9 +255,7 @@ bool ReportSampleCommand::Run(const std::vector<std::string>& args) {
return false;
}
if (!record_file_reader_->ReadDataSection(
- [this](std::unique_ptr<Record> record) {
- return ProcessRecord(std::move(record));
- })) {
+ [this](std::unique_ptr<Record> record) { return ProcessRecord(std::move(record)); })) {
return false;
}
@@ -237,42 +287,44 @@ bool ReportSampleCommand::Run(const std::vector<std::string>& args) {
}
bool ReportSampleCommand::ParseOptions(const std::vector<std::string>& args) {
- for (size_t i = 0; i < args.size(); ++i) {
- if (args[i] == "--dump-protobuf-report") {
- if (!NextArgumentOrError(args, &i)) {
- return false;
- }
- dump_protobuf_report_file_ = args[i];
- } else if (args[i] == "-i") {
- if (!NextArgumentOrError(args, &i)) {
- return false;
- }
- record_filename_ = args[i];
- } else if (args[i] == "-o") {
- if (!NextArgumentOrError(args, &i)) {
- return false;
- }
- report_filename_ = args[i];
- } else if (args[i] == "--protobuf") {
- use_protobuf_ = true;
- } else if (args[i] == "--show-callchain") {
- show_callchain_ = true;
- } else if (args[i] == "--remove-unknown-kernel-symbols") {
- remove_unknown_kernel_symbols_ = true;
- } else if (args[i] == "--show-art-frames") {
- show_art_frames_ = true;
- } else if (args[i] == "--symdir") {
- if (!NextArgumentOrError(args, &i)) {
- return false;
- }
- if (!Dso::AddSymbolDir(args[i])) {
- return false;
- }
- } else {
- ReportUnknownOption(args, i);
+ const OptionFormatMap option_formats = {
+ {"--dump-protobuf-report", {OptionValueType::STRING, OptionType::SINGLE}},
+ {"-i", {OptionValueType::STRING, OptionType::SINGLE}},
+ {"-o", {OptionValueType::STRING, OptionType::SINGLE}},
+ {"--proguard-mapping-file", {OptionValueType::STRING, OptionType::MULTIPLE}},
+ {"--protobuf", {OptionValueType::NONE, OptionType::SINGLE}},
+ {"--show-callchain", {OptionValueType::NONE, OptionType::SINGLE}},
+ {"--remove-unknown-kernel-symbols", {OptionValueType::NONE, OptionType::SINGLE}},
+ {"--show-art-frames", {OptionValueType::NONE, OptionType::SINGLE}},
+ {"--show-execution-type", {OptionValueType::NONE, OptionType::SINGLE}},
+ {"--symdir", {OptionValueType::STRING, OptionType::MULTIPLE}},
+ };
+ OptionValueMap options;
+ std::vector<std::pair<OptionName, OptionValue>> ordered_options;
+ if (!PreprocessOptions(args, option_formats, &options, &ordered_options, nullptr)) {
+ return false;
+ }
+ options.PullStringValue("--dump-protobuf-report", &dump_protobuf_report_file_);
+ options.PullStringValue("-i", &record_filename_);
+ options.PullStringValue("-o", &report_filename_);
+ for (const OptionValue& value : options.PullValues("--proguard-mapping-file")) {
+ if (!callchain_report_builder_.AddProguardMappingFile(*value.str_value)) {
+ return false;
+ }
+ }
+ use_protobuf_ = options.PullBoolValue("--protobuf");
+ show_callchain_ = options.PullBoolValue("--show-callchain");
+ remove_unknown_kernel_symbols_ = options.PullBoolValue("--remove-unknown-kernel-symbols");
+ if (options.PullBoolValue("--show-art-frames")) {
+ callchain_report_builder_.SetRemoveArtFrame(false);
+ }
+ show_execution_type_ = options.PullBoolValue("--show-execution-type");
+ for (const OptionValue& value : options.PullValues("--symdir")) {
+ if (!Dso::AddSymbolDir(*value.str_value)) {
return false;
}
}
+ CHECK(options.values.empty());
if (use_protobuf_ && report_filename_.empty()) {
report_filename_ = "report_sample.trace";
@@ -282,8 +334,7 @@ bool ReportSampleCommand::ParseOptions(const std::vector<std::string>& args) {
bool ReportSampleCommand::DumpProtobufReport(const std::string& filename) {
GOOGLE_PROTOBUF_VERIFY_VERSION;
- std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(filename.c_str(), "rb"),
- fclose);
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(filename.c_str(), "rb"), fclose);
if (fp == nullptr) {
PLOG(ERROR) << "failed to open " << filename;
return false;
@@ -343,8 +394,7 @@ bool ReportSampleCommand::DumpProtobufReport(const std::string& filename) {
FprintIndented(report_fp_, 1, "callchain:\n");
for (int i = 0; i < sample.callchain_size(); ++i) {
const proto::Sample_CallChainEntry& callchain = sample.callchain(i);
- FprintIndented(report_fp_, 2, "vaddr_in_file: %" PRIx64 "\n",
- callchain.vaddr_in_file());
+ FprintIndented(report_fp_, 2, "vaddr_in_file: %" PRIx64 "\n", callchain.vaddr_in_file());
FprintIndented(report_fp_, 2, "file_id: %u\n", callchain.file_id());
int32_t symbol_id = callchain.symbol_id();
FprintIndented(report_fp_, 2, "symbol_id: %d\n", symbol_id);
@@ -356,14 +406,25 @@ bool ReportSampleCommand::DumpProtobufReport(const std::string& filename) {
max_symbol_id_map[callchain.file_id()] =
std::max(max_symbol_id_map[callchain.file_id()], symbol_id);
}
+ if (callchain.has_execution_type()) {
+ FprintIndented(report_fp_, 2, "execution_type: %s\n",
+ ProtoExecutionTypeToString(callchain.execution_type()));
+ }
+ }
+ if (sample.has_unwinding_result()) {
+ FprintIndented(report_fp_, 1, "unwinding_result:\n");
+ FprintIndented(report_fp_, 2, "raw_error_code: %u\n",
+ sample.unwinding_result().raw_error_code());
+ FprintIndented(report_fp_, 2, "error_addr: 0x%" PRIx64 "\n",
+ sample.unwinding_result().error_addr());
+ FprintIndented(report_fp_, 2, "error_code: %s\n",
+ ProtoUnwindingErrorCodeToString(sample.unwinding_result().error_code()));
}
} else if (proto_record.has_lost()) {
auto& lost = proto_record.lost();
FprintIndented(report_fp_, 0, "lost_situation:\n");
- FprintIndented(report_fp_, 1, "sample_count: %" PRIu64 "\n",
- lost.sample_count());
- FprintIndented(report_fp_, 1, "lost_count: %" PRIu64 "\n",
- lost.lost_count());
+ FprintIndented(report_fp_, 1, "sample_count: %" PRIu64 "\n", lost.sample_count());
+ FprintIndented(report_fp_, 1, "lost_count: %" PRIu64 "\n", lost.lost_count());
} else if (proto_record.has_file()) {
auto& file = proto_record.file();
FprintIndented(report_fp_, 0, "file:\n");
@@ -376,8 +437,8 @@ bool ReportSampleCommand::DumpProtobufReport(const std::string& filename) {
FprintIndented(report_fp_, 1, "mangled_symbol: %s\n", file.mangled_symbol(i).c_str());
}
if (file.id() != files.size()) {
- LOG(ERROR) << "file id doesn't increase orderly, expected "
- << files.size() << ", really " << file.id();
+ LOG(ERROR) << "file id doesn't increase orderly, expected " << files.size() << ", really "
+ << file.id();
return false;
}
files.push_back(file.symbol_size());
@@ -404,13 +465,12 @@ bool ReportSampleCommand::DumpProtobufReport(const std::string& filename) {
}
for (auto pair : max_symbol_id_map) {
if (pair.first >= files.size()) {
- LOG(ERROR) << "file_id(" << pair.first << ") >= file count ("
- << files.size() << ")";
+ LOG(ERROR) << "file_id(" << pair.first << ") >= file count (" << files.size() << ")";
return false;
}
if (static_cast<uint32_t>(pair.second) >= files[pair.first]) {
- LOG(ERROR) << "symbol_id(" << pair.second << ") >= symbol count ("
- << files[pair.first] << ") in file_id( " << pair.first << ")";
+ LOG(ERROR) << "symbol_id(" << pair.second << ") >= symbol count (" << files[pair.first]
+ << ") in file_id( " << pair.first << ")";
return false;
}
}
@@ -464,13 +524,23 @@ bool ReportSampleCommand::PrintMetaInfo() {
bool ReportSampleCommand::ProcessRecord(std::unique_ptr<Record> record) {
thread_tree_.Update(*record);
- if (record->type() == PERF_RECORD_SAMPLE) {
- return ProcessSampleRecord(*static_cast<SampleRecord*>(record.get()));
- }
- if (record->type() == PERF_RECORD_LOST) {
- lost_count_ += static_cast<const LostRecord*>(record.get())->lost;
+ bool result = true;
+ switch (record->type()) {
+ case PERF_RECORD_SAMPLE: {
+ result = ProcessSampleRecord(*static_cast<SampleRecord*>(record.get()));
+ last_unwinding_result_.reset();
+ break;
+ }
+ case SIMPLE_PERF_RECORD_UNWINDING_RESULT: {
+ last_unwinding_result_.reset(static_cast<UnwindingResultRecord*>(record.release()));
+ break;
+ }
+ case PERF_RECORD_LOST: {
+ lost_count_ += static_cast<const LostRecord*>(record.get())->lost;
+ break;
+ }
}
- return true;
+ return result;
}
bool ReportSampleCommand::ProcessSampleRecord(const SampleRecord& r) {
@@ -488,34 +558,15 @@ bool ReportSampleCommand::ProcessSampleRecord(const SampleRecord& r) {
kernel_ip_count = std::min(kernel_ip_count, static_cast<size_t>(1u));
}
sample_count_++;
- std::vector<CallEntry> entries;
- bool near_java_method = false;
- auto is_entry_for_interpreter = [](const CallEntry& entry) {
- return android::base::EndsWith(entry.dso->Path(), "/libart.so");
- };
const ThreadEntry* thread = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
- for (size_t i = 0; i < ips.size(); ++i) {
- bool omit_unknown_dso = i > 0u;
- CallEntry entry;
- if (!GetCallEntry(thread, i < kernel_ip_count, ips[i], omit_unknown_dso, &entry)) {
+ std::vector<CallChainReportEntry> entries =
+ callchain_report_builder_.Build(thread, ips, kernel_ip_count);
+
+ for (size_t i = 1; i < entries.size(); i++) {
+ if (thread_tree_.IsUnknownDso(entries[i].dso)) {
+ entries.resize(i);
break;
}
- if (!show_art_frames_) {
- // Remove interpreter frames both before and after the Java frame.
- if (entry.dso->IsForJavaMethod()) {
- near_java_method = true;
- while (!entries.empty() && is_entry_for_interpreter(entries.back())) {
- entries.pop_back();
- }
- } else if (is_entry_for_interpreter(entry)) {
- if (near_java_method) {
- continue;
- }
- } else {
- near_java_method = false;
- }
- }
- entries.push_back(entry);
}
if (use_protobuf_) {
uint64_t key = (static_cast<uint64_t>(r.tid_data.pid) << 32) | r.tid_data.tid;
@@ -525,8 +576,8 @@ bool ReportSampleCommand::ProcessSampleRecord(const SampleRecord& r) {
return PrintSampleRecord(r, entries);
}
-bool ReportSampleCommand::PrintSampleRecordInProtobuf(const SampleRecord& r,
- const std::vector<CallEntry>& entries) {
+bool ReportSampleCommand::PrintSampleRecordInProtobuf(
+ const SampleRecord& r, const std::vector<CallChainReportEntry>& entries) {
proto::Record proto_record;
proto::Sample* sample = proto_record.mutable_sample();
sample->set_time(r.time_data.time);
@@ -534,7 +585,8 @@ bool ReportSampleCommand::PrintSampleRecordInProtobuf(const SampleRecord& r,
sample->set_thread_id(r.tid_data.tid);
sample->set_event_type_id(record_file_reader_->GetAttrIndexOfRecord(&r));
- for (const CallEntry& node : entries) {
+ bool complete_callchain = false;
+ for (const auto& node : entries) {
proto::Sample_CallChainEntry* callchain = sample->add_callchain();
uint32_t file_id;
if (!node.dso->GetDumpId(&file_id)) {
@@ -549,21 +601,82 @@ bool ReportSampleCommand::PrintSampleRecordInProtobuf(const SampleRecord& r,
callchain->set_vaddr_in_file(node.vaddr_in_file);
callchain->set_file_id(file_id);
callchain->set_symbol_id(symbol_id);
+ if (show_execution_type_) {
+ callchain->set_execution_type(ToProtoExecutionType(node.execution_type));
+ }
// Android studio wants a clear call chain end to notify whether a call chain is complete.
// For the main thread, the call chain ends at __libc_init in libc.so. For other threads,
// the call chain ends at __start_thread in libc.so.
// The call chain of the main thread can go beyond __libc_init, to _start (<= android O) or
// _start_main (> android O).
- if (node.dso->FileName() == "libc.so" &&
- (strcmp(node.symbol->Name(), "__libc_init") == 0 ||
- strcmp(node.symbol->Name(), "__start_thread") == 0)) {
+ if (node.dso->FileName() == "libc.so" && (strcmp(node.symbol->Name(), "__libc_init") == 0 ||
+ strcmp(node.symbol->Name(), "__start_thread") == 0)) {
+ complete_callchain = true;
break;
}
}
+ // No need to add unwinding result for callchains fixed by callchain joiner.
+ if (!complete_callchain && last_unwinding_result_) {
+ AddUnwindingResultInProtobuf(sample->mutable_unwinding_result());
+ }
return WriteRecordInProtobuf(proto_record);
}
+void ReportSampleCommand::AddUnwindingResultInProtobuf(
+ proto::Sample_UnwindingResult* proto_unwinding_result) {
+ const UnwindingResult& unwinding_result = last_unwinding_result_->unwinding_result;
+ proto_unwinding_result->set_raw_error_code(unwinding_result.error_code);
+ proto_unwinding_result->set_error_addr(unwinding_result.error_addr);
+ proto::Sample_UnwindingResult_ErrorCode error_code;
+ switch (unwinding_result.error_code) {
+ case UnwindStackErrorCode::ERROR_NONE:
+ error_code = proto::Sample_UnwindingResult::ERROR_NONE;
+ break;
+ case UnwindStackErrorCode::ERROR_MEMORY_INVALID: {
+ // We dumped stack data in range [stack_start, stack_end) for dwarf unwinding.
+ // If the failed-to-read memory addr is within [stack_end, stack_end + 128k], then
+ // probably we didn't dump enough stack data.
+ // 128k is a guess number. The size of stack used in one function layer is usually smaller
+ // than it. And using a bigger value is more likely to be false positive.
+ if (unwinding_result.error_addr >= unwinding_result.stack_end &&
+ unwinding_result.error_addr <= unwinding_result.stack_end + 128 * 1024) {
+ error_code = proto::Sample_UnwindingResult::ERROR_NOT_ENOUGH_STACK;
+ } else {
+ error_code = proto::Sample_UnwindingResult::ERROR_MEMORY_INVALID;
+ }
+ break;
+ }
+ case UnwindStackErrorCode::ERROR_UNWIND_INFO:
+ error_code = proto::Sample_UnwindingResult::ERROR_UNWIND_INFO;
+ break;
+ case UnwindStackErrorCode::ERROR_INVALID_MAP:
+ error_code = proto::Sample_UnwindingResult::ERROR_INVALID_MAP;
+ break;
+ case UnwindStackErrorCode::ERROR_MAX_FRAMES_EXCEEDED:
+ error_code = proto::Sample_UnwindingResult::ERROR_MAX_FRAME_EXCEEDED;
+ break;
+ case UnwindStackErrorCode::ERROR_REPEATED_FRAME:
+ error_code = proto::Sample_UnwindingResult::ERROR_REPEATED_FRAME;
+ break;
+ case UnwindStackErrorCode::ERROR_INVALID_ELF:
+ error_code = proto::Sample_UnwindingResult::ERROR_INVALID_ELF;
+ break;
+ case UnwindStackErrorCode::ERROR_UNSUPPORTED:
+ case UnwindStackErrorCode::ERROR_THREAD_DOES_NOT_EXIST:
+ case UnwindStackErrorCode::ERROR_THREAD_TIMEOUT:
+ case UnwindStackErrorCode::ERROR_SYSTEM_CALL:
+ // These error_codes shouldn't happen in simpleperf's use of libunwindstack.
+ error_code = proto::Sample_UnwindingResult::ERROR_UNKNOWN;
+ break;
+ default:
+ LOG(ERROR) << "unknown unwinding error code: " << unwinding_result.error_code;
+ error_code = proto::Sample_UnwindingResult::ERROR_UNKNOWN;
+ break;
+ }
+ proto_unwinding_result->set_error_code(error_code);
+}
+
bool ReportSampleCommand::WriteRecordInProtobuf(proto::Record& proto_record) {
coded_os_->WriteLittleEndian32(proto_record.ByteSize());
if (!proto_record.SerializeToCodedStream(coded_os_)) {
@@ -573,22 +686,6 @@ bool ReportSampleCommand::WriteRecordInProtobuf(proto::Record& proto_record) {
return true;
}
-bool ReportSampleCommand::GetCallEntry(const ThreadEntry* thread,
- bool in_kernel, uint64_t ip,
- bool omit_unknown_dso,
- CallEntry* entry) {
- const MapEntry* map = thread_tree_.FindMap(thread, ip, in_kernel);
- if (omit_unknown_dso && thread_tree_.IsUnknownDso(map->dso)) {
- return false;
- }
- entry->symbol = thread_tree_.FindSymbol(map, ip, &(entry->vaddr_in_file), &(entry->dso));
- // If we can't find symbol, use the dso shown in the map.
- if (entry->symbol == thread_tree_.UnknownSymbol()) {
- entry->dso = map->dso;
- }
- return true;
-}
-
bool ReportSampleCommand::PrintLostSituationInProtobuf() {
proto::Record proto_record;
proto::LostSituation* lost = proto_record.mutable_lost();
@@ -616,7 +713,7 @@ bool ReportSampleCommand::PrintFileInfoInProtobuf() {
proto::Record proto_record;
proto::File* file = proto_record.mutable_file();
file->set_id(file_id);
- file->set_path(dso->Path());
+ file->set_path(std::string{dso->GetReportPath()});
const std::vector<Symbol>& symbols = dso->GetSymbols();
std::vector<const Symbol*> dump_symbols;
for (const auto& sym : symbols) {
@@ -624,14 +721,11 @@ bool ReportSampleCommand::PrintFileInfoInProtobuf() {
dump_symbols.push_back(&sym);
}
}
- std::sort(dump_symbols.begin(), dump_symbols.end(),
- Symbol::CompareByDumpId);
+ std::sort(dump_symbols.begin(), dump_symbols.end(), Symbol::CompareByDumpId);
for (const auto& sym : dump_symbols) {
- std::string* symbol = file->add_symbol();
- *symbol = sym->DemangledName();
- std::string* mangled_symbol = file->add_mangled_symbol();
- *mangled_symbol = sym->Name();
+ file->add_symbol(sym->DemangledName());
+ file->add_mangled_symbol(sym->Name());
}
if (!WriteRecordInProtobuf(proto_record)) {
return false;
@@ -657,10 +751,10 @@ bool ReportSampleCommand::PrintThreadInfoInProtobuf() {
}
bool ReportSampleCommand::PrintSampleRecord(const SampleRecord& r,
- const std::vector<CallEntry>& entries) {
+ const std::vector<CallChainReportEntry>& entries) {
FprintIndented(report_fp_, 0, "sample:\n");
FprintIndented(report_fp_, 1, "event_type: %s\n",
- event_types_[record_file_reader_->GetAttrIndexOfRecord(&r)].c_str());
+ event_types_[record_file_reader_->GetAttrIndexOfRecord(&r)].data());
FprintIndented(report_fp_, 1, "time: %" PRIu64 "\n", r.time_data.time);
FprintIndented(report_fp_, 1, "event_count: %" PRIu64 "\n", r.period_data.period);
FprintIndented(report_fp_, 1, "thread_id: %d\n", r.tid_data.tid);
@@ -668,15 +762,23 @@ bool ReportSampleCommand::PrintSampleRecord(const SampleRecord& r,
FprintIndented(report_fp_, 1, "thread_name: %s\n", thread_name);
CHECK(!entries.empty());
FprintIndented(report_fp_, 1, "vaddr_in_file: %" PRIx64 "\n", entries[0].vaddr_in_file);
- FprintIndented(report_fp_, 1, "file: %s\n", entries[0].dso->Path().c_str());
+ FprintIndented(report_fp_, 1, "file: %s\n", entries[0].dso->GetReportPath().data());
FprintIndented(report_fp_, 1, "symbol: %s\n", entries[0].symbol->DemangledName());
+ if (show_execution_type_) {
+ FprintIndented(report_fp_, 1, "execution_type: %s\n",
+ ProtoExecutionTypeToString(ToProtoExecutionType(entries[0].execution_type)));
+ }
if (entries.size() > 1u) {
FprintIndented(report_fp_, 1, "callchain:\n");
for (size_t i = 1u; i < entries.size(); ++i) {
FprintIndented(report_fp_, 2, "vaddr_in_file: %" PRIx64 "\n", entries[i].vaddr_in_file);
- FprintIndented(report_fp_, 2, "file: %s\n", entries[i].dso->Path().c_str());
+ FprintIndented(report_fp_, 2, "file: %s\n", entries[i].dso->GetReportPath().data());
FprintIndented(report_fp_, 2, "symbol: %s\n", entries[i].symbol->DemangledName());
+ if (show_execution_type_) {
+ FprintIndented(report_fp_, 1, "execution_type: %s\n",
+ ProtoExecutionTypeToString(ToProtoExecutionType(entries[i].execution_type)));
+ }
}
}
return true;
@@ -691,7 +793,8 @@ void ReportSampleCommand::PrintLostSituation() {
} // namespace
void RegisterReportSampleCommand() {
- RegisterCommand("report-sample", [] {
- return std::unique_ptr<Command>(new ReportSampleCommand());
- });
+ RegisterCommand("report-sample",
+ [] { return std::unique_ptr<Command>(new ReportSampleCommand()); });
}
+
+} // namespace simpleperf