blob: d80a66a95e2272ed79c2a7c173b85be5070eaf5e [file] [log] [blame]
// 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