17#include "opencsd/c_api/opencsd_c_api.h"
23class HardwareTraceConfig {
25 virtual ~HardwareTraceConfig() =
default;
28class ETMTraceConfig :
public HardwareTraceConfig {
33 ETMTraceConfig(
const Triple &TargetTriple, uint8_t TraceID)
35 ocsd_arch_version_t ArchVer = ARCH_UNKNOWN;
36 if (TargetTriple.isArmMClass()) {
37 unsigned ArchVersion = ARM::parseArchVersion(TargetTriple.getArchName());
40 else if (ArchVersion == 7)
44 ArchVer = ARCH_UNKNOWN;
47 Cfg.arch_ver = ArchVer;
48 Cfg.core_prof = profile_CortexM;
52 Cfg.reg_traceidr = TraceID;
56 if (Cfg.arch_ver == ARCH_UNKNOWN)
59 "OpenCSD: Unsupported processor architecture. Only Arm M-profile "
60 "(Cortex-M) with ETM support is currently supported.");
61 return Error::success();
66 dcd_tree_handle_t DcdTree = 0;
67 const object::Binary &
Binary;
68 const Triple &TargetTriple;
71 static ocsd_datapath_resp_t
72 processTrace(
const void *PContext,
const ocsd_trc_index_t ,
74 const ocsd_generic_trace_elem *Element) {
75 auto *Decoder =
static_cast<ETMDecoderImpl *
>(
const_cast<void *
>(PContext));
76 if (!Decoder || !Element)
77 return OCSD_RESP_FATAL_SYS_ERR;
80 if (Element->elem_type == OCSD_GEN_TRC_ELEM_INSTR_RANGE) {
81 uint64_t
Start = Element->st_addr;
82 uint64_t End = Element->en_addr;
88 Decoder->CurrentCallback->processInstructionRange(Start, End - 1);
91 return OCSD_RESP_CONT;
100 Error mapELFSegments(dcd_tree_handle_t DcdTree,
101 const object::Binary &SourceBin) {
102 SmallVector<ocsd_file_mem_region_t, 4> Regions;
103 auto ProcessHeaders = [&](
const auto &ElfFile) {
104 auto ProgramHeaders = ElfFile.program_headers();
108 for (
const auto &Phdr : *ProgramHeaders) {
111 ocsd_file_mem_region_t
Region{};
112 Region.start_address = (uint64_t)Phdr.p_vaddr;
113 Region.file_offset = (uint64_t)Phdr.p_offset;
114 Region.region_size = (uint64_t)Phdr.p_filesz;
115 Regions.push_back(Region);
120 if (
auto *O = dyn_cast<object::ELF32LEObjectFile>(&SourceBin))
121 ProcessHeaders(
O->getELFFile());
122 else if (
auto *O = dyn_cast<object::ELF64LEObjectFile>(&SourceBin))
123 ProcessHeaders(
O->getELFFile());
124 else if (
auto *O = dyn_cast<object::ELF32BEObjectFile>(&SourceBin))
125 ProcessHeaders(
O->getELFFile());
126 else if (
auto *O = dyn_cast<object::ELF64BEObjectFile>(&SourceBin))
127 ProcessHeaders(
O->getELFFile());
129 if (!Regions.empty()) {
130 std::string
Path = SourceBin.getFileName().str();
131 if (ocsd_dt_add_binfile_region_mem_acc(
132 DcdTree, Regions.data(), (uint32_t)Regions.size(),
133 OCSD_MEM_SPACE_ANY,
Path.c_str()) != 0) {
136 "OpenCSD: Failed to map ELF executable segments.");
139 return Error::success();
145 ETMDecoderImpl(
const object::Binary &Binary,
const Triple &Triple,
147 :
Binary(
Binary), TargetTriple(Triple), TraceID(TraceID) {}
149 ~ETMDecoderImpl()
override {
152 ocsd_destroy_dcd_tree(DcdTree);
158 DcdTree = ocsd_create_dcd_tree(OCSD_TRC_SRC_SINGLE, 0);
161 "Failed to create OpenCSD decoder tree.");
164 ETMTraceConfig Config(TargetTriple, TraceID);
165 if (Error
E = Config.validate())
169 OCSD_CREATE_FLG_FULL_DECODER | OCSD_OPFLG_CHK_RANGE_CONTINUE;
170 if (ocsd_dt_create_decoder(DcdTree, OCSD_BUILTIN_DCD_ETMV4I, Flags,
171 (
void *)&Config.Cfg, &Config.TraceID) != 0)
174 "OpenCSD: Failed to initialize the instruction decoder.");
177 if (Error
E = mapELFSegments(DcdTree, Binary))
182 ocsd_dt_set_gen_elem_outfn(DcdTree, processTrace,
this);
183 return Error::success();
186 Error processTrace(ArrayRef<uint8_t> TraceData,
187 Callback &TraceCallback)
override {
188 CurrentCallback = &TraceCallback;
190 ocsd_dt_process_data(DcdTree, OCSD_OP_RESET, 0, 0,
nullptr,
nullptr);
192 const uint8_t *DataPtr = TraceData.data();
193 uint32_t TotalSize = TraceData.size();
194 uint32_t Processed = 0;
197 while (Processed < TotalSize) {
198 uint32_t Consumed = 0;
199 uint32_t Remaining = TotalSize - Processed;
200 ocsd_datapath_resp_t Response =
201 ocsd_dt_process_data(DcdTree, OCSD_OP_DATA, Processed, Remaining,
202 DataPtr + Processed, &Consumed);
204 if (Response == OCSD_RESP_WAIT) {
206 ocsd_dt_process_data(DcdTree, OCSD_OP_FLUSH, 0, 0,
nullptr,
nullptr);
207 }
else if (Consumed == 0 && Processed < TotalSize) {
210 ocsd_dt_process_data(DcdTree, OCSD_OP_RESET, 0, 0,
nullptr,
nullptr);
213 Processed += Consumed;
216 if (Response >= OCSD_RESP_FATAL_INVALID_DATA)
218 "OpenCSD: Fatal decoding error.");
222 ocsd_dt_process_data(DcdTree, OCSD_OP_EOT, 0, 0,
nullptr,
nullptr);
223 return Error::success();
231 auto Decoder = std::make_unique<ETMDecoderImpl>(Binary, Triple, TraceID);
232 if (
Error E = Decoder->initialize())
234 return std::unique_ptr<ETMDecoder>(std::move(Decoder));
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines the SmallVector class.
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
static Expected< std::unique_ptr< ETMDecoder > > create(const object::Binary &Binary, const Triple &TargetTriple, uint8_t TraceID=0x10)
Tagged union holding either a T or a Error.
Triple - Helper class for working with autoconf configuration names.
void validate(const Triple &TT, const FeatureBitset &FeatureBits)
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.