Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 21 additions & 16 deletions tools/ctrace/src/decode/DwtPacketDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,15 @@ constexpr std::uint32_t kExceptionActionShift = 12U;
constexpr std::uint32_t kPmuOverflowMask = 0xffU;

constexpr std::uint8_t kArmv7MFullPcBytes = 4U;
constexpr std::uint8_t kArmv7MAddressOffsetBytes = 2U;
constexpr std::uint8_t kArmv8MMatchBytes = 1U;
constexpr std::uint32_t kArmv8MMatchValue = 1U;

/** @brief Returns whether a raw DWT address fragment width can be preserved. */
static bool isSupportedAddressOffsetSize(std::uint8_t size)
{
return size == 1U || size == 2U || size == 4U;
}

/** @brief Describes an invalid DWT event-counter payload. */
static std::string invalidEventCounterMessage(const DwtPayloadPacket& payload)
{
Expand Down Expand Up @@ -260,17 +265,17 @@ void DwtPacketDecoder::decodeDataTrace(const DwtPayloadPacket& payload, std::vec
output.push_back(std::move(match));
return;
}
const auto expectedSize = secondarySubtype ? kArmv7MAddressOffsetBytes : kArmv7MFullPcBytes;
if (payload.size != expectedSize) {
const auto supportedSize =
secondarySubtype ? isSupportedAddressOffsetSize(payload.size) : payload.size == kArmv7MFullPcBytes;
if (!supportedSize) {
auto flushed = flush(payload.quality, payload.tcyc);
output.insert(output.end(), std::make_move_iterator(flushed.begin()), std::make_move_iterator(flushed.end()));
TraceEvent error{TraceIssueEvent{
TraceIssueCode::UnsupportedDwtAddressPayload,
TraceIssueSeverity::Error,
"unsupported DWT " + std::string(secondarySubtype ? "address" : "PC or match") + " payload size " +
std::to_string(payload.size) +
"; the current ctrace-run format does not provide the "
"architecture and reconstruction data needed to decode it safely",
"unsupported DWT " + std::string(secondarySubtype ? "address offset" : "PC or match") +
" payload size " + std::to_string(payload.size) +
(secondarySubtype ? "; expected 1, 2, or 4 bytes" : "; expected a 4-byte PC or 1-byte match"),
std::nullopt,
std::nullopt,
}};
Expand All @@ -282,8 +287,8 @@ void DwtPacketDecoder::decodeDataTrace(const DwtPayloadPacket& payload, std::vec
return;
}
if (secondarySubtype) {
event.addressLo16 = payload.value;
event.hasAddressLo16 = true;
event.offset = DwtAddressOffset{payload.size, payload.value};
event.hasOffset = true;
} else {
event.pc = payload.value;
event.hasPc = true;
Expand Down Expand Up @@ -313,18 +318,18 @@ void DwtPacketDecoder::sendDataTraceEvent(std::uint32_t comparator, const Pendin
// The individual short-circuit permutations are an implementation detail;
// repeated and complementary fragments are covered as complete behaviors.
const auto repeatsFragmentKind = (pending->hasPc && event.hasPc) ||
(pending->hasAddressLo16 && event.hasAddressLo16) ||
(pending->hasOffset && event.hasOffset) ||
(pending->hasValue && event.hasValue);
if (!repeatsFragmentKind) {
pending->index = event.index;
pending->traceBusId = event.traceBusId;
pending->pc = event.hasPc ? event.pc : pending->pc;
pending->addressLo16 = event.hasAddressLo16 ? event.addressLo16 : pending->addressLo16;
pending->offset = event.hasOffset ? event.offset : pending->offset;
pending->value = event.hasValue ? event.value : pending->value;
pending->size = event.hasValue ? event.size : pending->size;
pending->isRead = event.hasValue ? event.isRead : pending->isRead;
pending->hasPc = pending->hasPc || event.hasPc;
pending->hasAddressLo16 = pending->hasAddressLo16 || event.hasAddressLo16;
pending->hasOffset = pending->hasOffset || event.hasOffset;
pending->hasValue = pending->hasValue || event.hasValue;
pending->quality.overflow = pending->quality.overflow || event.quality.overflow;
pending->quality.timestampReliable = pending->quality.timestampReliable && event.quality.timestampReliable;
Expand All @@ -351,14 +356,14 @@ void DwtPacketDecoder::flushPending(std::uint32_t comparator, const TraceQuality
pending->size,
pending->value,
pending->isRead ? AccessType::Read : AccessType::Write,
pending->hasAddressLo16 ? std::optional<std::uint32_t>(pending->addressLo16) : std::nullopt,
pending->hasOffset ? std::optional<DwtAddressOffset>(pending->offset) : std::nullopt,
pending->hasPc ? std::optional<std::uint32_t>(pending->pc) : std::nullopt,
});
}

DwtAddressTraceLocation location = DwtOffsetTraceLocation{pending->addressLo16};
if (pending->hasPc && pending->hasAddressLo16) {
location = DwtPcAndOffsetTraceLocation{pending->pc, pending->addressLo16};
DwtAddressTraceLocation location = DwtOffsetTraceLocation{pending->offset};
if (pending->hasPc && pending->hasOffset) {
location = DwtPcAndOffsetTraceLocation{pending->pc, pending->offset};
} else if (pending->hasPc) {
location = DwtPcTraceLocation{pending->pc};
}
Expand Down
4 changes: 2 additions & 2 deletions tools/ctrace/src/decode/DwtPacketDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ class DwtPacketDecoder {
std::uint64_t index = 0;
std::uint8_t traceBusId = 0U;
std::uint32_t pc = 0;
std::uint32_t addressLo16 = 0;
DwtAddressOffset offset;
std::uint32_t value = 0;
std::uint8_t size = 4;
bool isRead = false;
bool hasPc = false;
bool hasAddressLo16 = false;
bool hasOffset = false;
bool hasValue = false;
TraceQuality quality;
};
Expand Down
27 changes: 19 additions & 8 deletions tools/ctrace/src/model/TraceEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,24 @@ struct SoftwareTraceEvent {
std::uint32_t value = 0;
};

/** @brief Stores the raw address fragment and width carried by a DWT packet. */
struct DwtAddressOffset {
std::uint8_t size = 0;
std::uint32_t value = 0;
};

constexpr bool operator==(const DwtAddressOffset& left, const DwtAddressOffset& right)
{
return left.size == right.size && left.value == right.value;
}

/** @brief Contains a reconstructed DWT data access event. */
struct DwtDataTraceEvent {
std::uint32_t comparator = 0;
std::uint8_t size = 0;
std::uint32_t value = 0;
AccessType access = AccessType::Read;
std::optional<std::uint32_t> addressLo16 = std::nullopt;
std::optional<DwtAddressOffset> offset = std::nullopt;
std::optional<std::uint32_t> pc = std::nullopt;
};

Expand All @@ -75,15 +86,15 @@ struct DwtPcTraceLocation {
std::uint32_t pc;
};

/** @brief Identifies a DWT address event by its low address bits. */
/** @brief Identifies a DWT address event by its raw address fragment. */
struct DwtOffsetTraceLocation {
std::uint32_t addressLo16;
DwtAddressOffset offset;
};

/** @brief Identifies a DWT address event by program counter and address offset. */
struct DwtPcAndOffsetTraceLocation {
std::uint32_t pc;
std::uint32_t addressLo16;
DwtAddressOffset offset;
};

/** @brief Stores one of the supported DWT address location representations. */
Expand Down Expand Up @@ -112,14 +123,14 @@ inline std::optional<std::uint32_t> dwtAddressPc(const DwtAddressTraceEvent& eve
return std::nullopt;
}

/** @brief Returns the address offset carried by a DWT address event, if present. */
inline std::optional<std::uint32_t> dwtAddressOffset(const DwtAddressTraceEvent& event)
/** @brief Returns the raw address fragment carried by a DWT address event, if present. */
inline std::optional<DwtAddressOffset> dwtAddressOffset(const DwtAddressTraceEvent& event)
{
if (const auto* offset = std::get_if<DwtOffsetTraceLocation>(&event.location)) {
return offset->addressLo16;
return offset->offset;
}
if (const auto* combined = std::get_if<DwtPcAndOffsetTraceLocation>(&event.location)) {
return combined->addressLo16;
return combined->offset;
}
return std::nullopt;
}
Expand Down
6 changes: 3 additions & 3 deletions tools/ctrace/src/output/csv/CsvRowMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,16 @@ static CsvRow eventToCsvRow(const TraceEvent& event)
if (data->pc.has_value()) {
row[column(CsvColumn::Pc)] = hexValue(*data->pc, 4);
}
if (data->addressLo16.has_value()) {
row[column(CsvColumn::Offset)] = hexValue(*data->addressLo16, 2);
if (data->offset.has_value()) {
row[column(CsvColumn::Offset)] = hexValue(data->offset->value, data->offset->size);
}
} else if (const auto* address = traceEventPayload<DwtAddressTraceEvent>(event)) {
row[column(CsvColumn::Source)] = std::to_string(address->comparator);
if (const auto pc = dwtAddressPc(*address)) {
row[column(CsvColumn::Pc)] = hexValue(*pc, 4);
}
if (const auto offset = dwtAddressOffset(*address)) {
row[column(CsvColumn::Offset)] = hexValue(*offset, 2);
row[column(CsvColumn::Offset)] = hexValue(offset->value, offset->size);
}
} else if (const auto* match = traceEventPayload<DwtMatchTraceEvent>(event)) {
row[column(CsvColumn::Source)] = std::to_string(match->comparator);
Expand Down
52 changes: 40 additions & 12 deletions tools/ctrace/src/output/ctf/CtfEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <cstdint>
#include <filesystem>
#include <limits>
#include <optional>
#include <set>
#include <stdexcept>
#include <string>
Expand Down Expand Up @@ -111,6 +112,34 @@ static void writeVariantValue(CtfStreamWriter::Record& record, std::uint32_t dat
}
}

/** @brief Resolves the CTF representation of an optional raw DWT address offset. */
static const CtfSchema::DwtOffsetVariant& dwtOffsetVariant(const std::optional<DwtAddressOffset>& offset)
{
if (!offset.has_value()) {
return CtfSchema::DwtOffsetVariants.front();
}
const auto* variant = CtfSchema::dwtOffsetVariantForSize(offset->size);
if (variant == nullptr) {
throw std::runtime_error("CTF DWT address offset has an invalid SWO payload size");
}
return *variant;
}

/** @brief Writes an optional raw DWT address offset using its exact SWO width. */
static void writeDwtOffset(CtfStreamWriter::Record& record, const std::optional<DwtAddressOffset>& offset,
const CtfSchema::DwtOffsetVariant& variant)
{
record.writeU8(CtfSchema::value(variant.tag));
const auto value = offset.has_value() ? offset->value : 0U;
if (variant.byteSize == 1U) {
record.writeU8(static_cast<std::uint8_t>(value & 0xffU));
} else if (variant.byteSize == 2U) {
record.writeU16(static_cast<std::uint16_t>(value & 0xffffU));
} else {
record.writeU32(value);
}
}

CtfEncoder::CtfEncoder(CtfEncoderConfig config)
: m_config(std::move(config))
{
Expand Down Expand Up @@ -298,8 +327,9 @@ void CtfEncoder::writeDwtValueEvent(const TraceEvent& event, const DwtDataTraceE
reportDwtSizeMismatch(event, data, source);
const auto& variant = dwtValueVariant(source, data.comparator);
const auto hasPc = data.pc.has_value() ? 1U : 0U;
const auto hasAddress = data.addressLo16.has_value() ? 1U : 0U;
const auto payloadSize = 1U + 1U + 1U + variant.byteSize + 1U + hasPc * 4U + 1U + hasAddress * 2U + 1U + 4U;
const auto& offsetVariant = dwtOffsetVariant(data.offset);
const auto payloadSize =
1U + 1U + 1U + variant.byteSize + 1U + hasPc * 4U + 1U + offsetVariant.byteSize + 1U + 4U;
const auto eventTimestamp = allocateEventTimestamp(event.traceBusId);
const auto quality = computeSampleQuality(event);
m_stream.writeRecord(CtfSchema::value(CtfSchema::EventId::DwtValue), eventTimestamp, event.traceBusId, payloadSize,
Expand All @@ -314,10 +344,7 @@ void CtfEncoder::writeDwtValueEvent(const TraceEvent& event, const DwtDataTraceE
if (hasPc != 0U) {
record.writeU32(*data.pc);
}
record.writeU8(static_cast<std::uint8_t>(hasAddress));
if (hasAddress != 0U) {
record.writeU16(static_cast<std::uint16_t>(*data.addressLo16 & 0xffffU));
}
writeDwtOffset(record, data.offset, offsetVariant);
record.writeU8(quality.first);
record.writeU32(quality.second);
});
Expand Down Expand Up @@ -348,20 +375,21 @@ void CtfEncoder::reportDwtSizeMismatch(const TraceEvent& event, const DwtDataTra

void CtfEncoder::writeDwtAddrEvent(const TraceEvent& event, const DwtAddressTraceEvent& address)
{
constexpr auto payloadSize = 1U + 1U + 1U + 4U + 2U + 1U + 4U;
const auto eventTimestamp = allocateEventTimestamp(event.traceBusId);
const auto quality = computeSampleQuality(event);
const auto pc = dwtAddressPc(address);
const auto addressOffset = dwtAddressOffset(address);
const auto offset = dwtAddressOffset(address);
const auto& offsetVariant = dwtOffsetVariant(offset);
const auto hasPc = pc.has_value() ? 1U : 0U;
const auto hasAddress = addressOffset.has_value() ? 1U : 0U;
const auto payloadSize = 1U + 1U + hasPc * 4U + 1U + offsetVariant.byteSize + 1U + 4U;
m_stream.writeRecord(CtfSchema::value(CtfSchema::EventId::DwtAddress), eventTimestamp, event.traceBusId, payloadSize,
[&](CtfStreamWriter::Record& record) {
record.writeU8(static_cast<std::uint8_t>(address.comparator & 0xffU));
record.writeU8(static_cast<std::uint8_t>(hasPc));
record.writeU8(static_cast<std::uint8_t>(hasAddress));
record.writeU32(pc.value_or(0U));
record.writeU16(static_cast<std::uint16_t>(addressOffset.value_or(0U) & 0xffffU));
if (hasPc != 0U) {
record.writeU32(*pc);
}
writeDwtOffset(record, offset, offsetVariant);
record.writeU8(quality.first);
record.writeU32(quality.second);
});
Expand Down
34 changes: 27 additions & 7 deletions tools/ctrace/src/output/ctf/CtfMetadataWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,28 @@ static std::string ctfValueFields(const std::string_view& prefix)
return out.str();
}

/** @brief Generates the width-tagged TSDL field for a raw DWT address offset. */
static std::string ctfDwtOffsetFields()
{
std::ostringstream out;
out << " enum : uint8_t { ";
for (std::size_t index = 0; index < CtfSchema::DwtOffsetVariants.size(); ++index) {
const auto& variant = CtfSchema::DwtOffsetVariants[index];
if (index > 0U) {
out << ", ";
}
out << variant.name << " = " << static_cast<unsigned>(CtfSchema::value(variant.tag));
}
out << " } cmsis_dwt_offset_type;\n"
<< " variant <cmsis_dwt_offset_type> {\n";
for (const auto& variant : CtfSchema::DwtOffsetVariants) {
const auto type = variant.byteSize == 1U ? "uint8_t" : variant.byteSize == 2U ? "uint16_t" : "uint32_t";
out << " " << type << " " << variant.name << ";\n";
}
out << " } cmsis_dwt_offset;\n";
return out.str();
}

/** @brief Stores source labels and exception lanes emitted into CTF metadata. */
struct MetadataSymbols {
std::map<std::uint32_t, std::string> dwtValueTypes;
Expand Down Expand Up @@ -407,9 +429,8 @@ event {
)" << ctfValueFields("dwt")
<< R"( uint8_t cmsis_has_pc;
uint32_t cmsis_pc[cmsis_has_pc];
uint8_t cmsis_has_address_lo16;
uint16_t cmsis_address_lo16[cmsis_has_address_lo16];
uint8_t cmsis_sample_flags;
)" << ctfDwtOffsetFields()
<< R"( uint8_t cmsis_sample_flags;
uint32_t cmsis_overflow_count;
};
};
Expand All @@ -430,10 +451,9 @@ event {
fields := struct {
cmsis_dwt_comparator_t cmsis_dwt_comparator;
uint8_t cmsis_has_pc;
uint8_t cmsis_has_address_lo16;
uint32_t cmsis_pc;
uint16_t cmsis_address_lo16;
uint8_t cmsis_sample_flags;
uint32_t cmsis_pc[cmsis_has_pc];
)" << ctfDwtOffsetFields()
<< R"( uint8_t cmsis_sample_flags;
uint32_t cmsis_overflow_count;
};
};
Expand Down
Loading
Loading