| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #pragma once |
| |
| #include <string> |
| #include <unordered_set> |
| #include <vector> |
| |
| #include "garnet/lib/debugger_utils/build_ids.h" |
| #include "garnet/lib/debugger_utils/elf_reader.h" |
| #include "garnet/lib/debugger_utils/elf_symtab.h" |
| #include "garnet/lib/debugger_utils/ktrace_reader.h" |
| #include "garnet/lib/debugger_utils/load_maps.h" |
| |
| #include "third_party/processor-trace/libipt/include/intel-pt.h" |
| |
| #include "third_party/simple-pt/symtab.h" |
| |
| namespace intel_processor_trace { |
| |
| // Parameters needed to drive the decoder. |
| |
| struct DecoderConfig { |
| // Path to the kernel ELF file. |
| std::string kernel_file_name; |
| |
| // Ideally this should come from sideband data, but it can be manually |
| // specified. |
| uint64_t kernel_cr3 = pt_asid_no_cr3; |
| |
| // Path to the raw processor trace dump. |
| // This file is produced by the "ipt" program. |
| std::string pt_file_name; |
| |
| // Path to a text file containing a mapping of "id" values and their |
| // corresponding PT dump files. |
| // The format of each line is "id /path/to/pt-file". |
| // "id" is either a cpu number for cpu-based tracing, or thread id for |
| // thread-based tracing; in decimal. |
| std::string pt_list_file_name; |
| |
| // Path to needed ktrace data. |
| // This file is produced by the "ipt" program. |
| std::string ktrace_file_name; |
| |
| // Optional additional files passed on the command line. |
| std::vector<std::string> elf_file_names; |
| |
| // Path to the "ids.txt" files from the build. |
| std::vector<std::string> ids_file_names; |
| |
| // Path to file containing linker map output. |
| std::vector<std::string> map_file_names; |
| }; |
| |
| struct Process { |
| Process(zx_koid_t p, uint64_t c, uint64_t start, uint64_t end); |
| zx_koid_t pid; |
| uint64_t cr3; |
| // The time, in units ktrace uses, when the process was live. |
| // An end time of zero means "unknown". |
| uint64_t start_time, end_time; |
| }; |
| |
| struct PtFile { |
| PtFile(uint64_t i, const std::string& f); |
| |
| // The id of the cpu we are processing. Cpus are numbered 0...N. |
| static constexpr uint64_t kIdUnset = ~(uint64_t)0; |
| |
| uint64_t id; |
| std::string file; |
| }; |
| |
| using SymbolTable = simple_pt::SymbolTable; |
| using Symbol = simple_pt::Symbol; |
| using LoadMap = debugger_utils::LoadMap; |
| using BuildId = debugger_utils::BuildId; |
| |
| class DecoderState { |
| public: |
| static std::unique_ptr<DecoderState> Create(const DecoderConfig& config); |
| |
| ~DecoderState(); |
| |
| const Process* LookupProcessByPid(zx_koid_t pid); |
| const Process* LookupProcessByCr3(uint64_t cr3); |
| |
| const LoadMap* LookupMapEntry(zx_koid_t pid, uint64_t addr); |
| |
| const BuildId* LookupBuildId(const std::string& bid); |
| |
| std::string LookupFile(const std::string& file); |
| |
| const SymbolTable* FindSymbolTable(uint64_t cr3, uint64_t pc); |
| const Symbol* FindSymbol(uint64_t cr3, uint64_t pc, |
| const SymbolTable** out_symtab); |
| const char* FindPcFileName(uint64_t cr3, uint64_t pc); |
| |
| bool SeenCr3(uint64_t cr3); |
| |
| uint64_t kernel_cr3() const { return kernel_cr3_; } |
| void set_kernel_cr3(uint64_t cr3) { kernel_cr3_ = cr3; } |
| |
| const pt_config& config() const { return config_; } |
| void set_nom_freq(uint8_t nom_freq) { config_.nom_freq = nom_freq; } |
| void set_family(uint32_t family) { config_.cpu.family = family; } |
| void set_model(uint32_t model) { config_.cpu.model = model; } |
| void set_stepping(uint32_t stepping) { config_.cpu.stepping = stepping; } |
| |
| bool AllocDecoder(const std::string& pt_file); |
| void FreeDecoder(); |
| pt_insn_decoder* decoder() const { return decoder_; } |
| |
| const std::vector<Process>& processes() const { return processes_; } |
| |
| const std::vector<PtFile>& pt_files() const { return pt_files_; } |
| |
| const std::unordered_set<uint64_t>& unknown_cr3s() const { |
| return unknown_cr3s_; |
| } |
| |
| private: |
| DecoderState(); |
| |
| bool AllocImage(const std::string& name); |
| |
| bool ReadKtraceFile(const std::string& file); |
| bool ReadMapFile(const std::string& file); |
| bool ReadIdsFile(const std::string& file); |
| bool ReadPtListFile(const std::string& file); |
| |
| void AddSymtab(std::unique_ptr<SymbolTable> symtab); |
| bool ReadElf(const std::string& file, uint64_t base, uint64_t cr3, |
| uint64_t file_off, uint64_t map_len); |
| bool ReadKernelElf(const std::string& file, uint64_t cr3); |
| |
| void SetKernelCr3(uint64_t cr3) { kernel_cr3_ = cr3; } |
| |
| static int ReadMemCallback(uint8_t* buffer, size_t size, |
| const struct pt_asid* asid, uint64_t addr, |
| void* context); |
| |
| static int ProcessKtraceRecord(debugger_utils::KtraceRecord* rec, void* arg); |
| |
| bool AddProcess(zx_koid_t pid, uint64_t cr3, uint64_t start_time); |
| bool MarkProcessExited(zx_koid_t pid, uint64_t end_time); |
| |
| void AddPtFile(const std::string& file_dir, uint64_t id, |
| const std::string& path); |
| |
| pt_config config_; |
| pt_image* image_; |
| pt_insn_decoder* decoder_; |
| |
| uint64_t kernel_cr3_; |
| |
| std::vector<Process> processes_; |
| debugger_utils::LoadMapTable load_maps_; |
| debugger_utils::BuildIdTable build_ids_; |
| std::vector<PtFile> pt_files_; |
| |
| // List of cr3 values seen that we don't have processes for. |
| // This helps printers explain the results to human readers. |
| std::unordered_set<uint64_t> unknown_cr3s_; |
| |
| std::vector<std::unique_ptr<SymbolTable>> symtabs_; |
| }; |
| |
| } // namespace intel_processor_trace |