vyre_runtime/megakernel/protocol/codec/
debug_log.rs1use super::{debug, read_required_word, read_word_from_optional_words, validate_word_aligned};
2use super::{DebugRecord, ProtocolError};
3
4#[must_use]
6pub fn read_debug_log(debug_bytes: &[u8]) -> Vec<DebugRecord> {
7 try_read_debug_log(debug_bytes).unwrap_or_default()
8}
9
10pub fn read_debug_log_into(debug_bytes: &[u8], out: &mut Vec<DebugRecord>) {
14 if let Err(error) = try_read_debug_log_into(debug_bytes, out) {
18 panic!("vyre-runtime debug-log decode failed: {error}");
19 }
20}
21
22pub fn try_read_debug_log(debug_bytes: &[u8]) -> Result<Vec<DebugRecord>, ProtocolError> {
29 let mut records = Vec::new();
30 try_read_debug_log_into(debug_bytes, &mut records)?;
31 Ok(records)
32}
33
34pub fn try_read_debug_log_into(
43 debug_bytes: &[u8],
44 out: &mut Vec<DebugRecord>,
45) -> Result<(), ProtocolError> {
46 validate_word_aligned("debug_log", debug_bytes)?;
47 let cursor = read_required_word(
48 "debug_log",
49 debug_bytes,
50 debug_word_index(debug::CURSOR_WORD, "cursor word")?,
51 )?;
52 let record_words = debug_word_index(debug::RECORD_WORDS, "record word count")?;
53 let records_start = debug_word_index(debug::RECORDS_BASE, "records base word")?;
54 let total_word_capacity = debug_bytes.len() / 4;
55 if total_word_capacity < records_start {
56 return Err(ProtocolError::MissingWord {
57 buffer: "debug_log",
58 word_idx: records_start,
59 byte_len: debug_bytes.len(),
60 fix: "build debug-log bytes with encode_empty_debug_log",
61 });
62 }
63 let capacity_words = total_word_capacity - records_start;
64 let cursor = usize::try_from(cursor).map_err(|_| ProtocolError::ByteLengthOverflow {
65 buffer: "debug_log",
66 fix: "debug-log cursor does not fit host usize; keep protocol buffers within host addressable range",
67 })?;
68 if cursor > capacity_words {
69 return Err(ProtocolError::MissingWord {
70 buffer: "debug_log",
71 word_idx: records_start + cursor,
72 byte_len: debug_bytes.len(),
73 fix: "debug-log cursor must stay within the encoded record capacity",
74 });
75 }
76 let available = cursor;
77 if available % record_words != 0 {
78 return Err(ProtocolError::MissingWord {
79 buffer: "debug_log",
80 word_idx: records_start + available,
81 byte_len: debug_bytes.len(),
82 fix: "debug-log cursor must advance in whole PRINTF records",
83 });
84 }
85 let record_count = available / record_words;
86 out.clear();
87 try_reserve_record_capacity(out, record_count)?;
88 let words = bytemuck::try_cast_slice::<u8, u32>(debug_bytes).ok();
89 for i in 0..record_count {
90 let w = records_start + i * record_words;
91 out.push(DebugRecord {
92 fmt_id: read_word_from_optional_words(words, debug_bytes, w).ok_or(
93 ProtocolError::MissingWord {
94 buffer: "debug_log",
95 word_idx: w,
96 byte_len: debug_bytes.len(),
97 fix: "decode only debug-log buffers produced by the matching megakernel protocol encoder",
98 })?,
99 args: [
100 read_word_from_optional_words(words, debug_bytes, w + 1).ok_or(
101 ProtocolError::MissingWord {
102 buffer: "debug_log",
103 word_idx: w + 1,
104 byte_len: debug_bytes.len(),
105 fix: "decode only debug-log buffers produced by the matching megakernel protocol encoder",
106 })?,
107 read_word_from_optional_words(words, debug_bytes, w + 2).ok_or(
108 ProtocolError::MissingWord {
109 buffer: "debug_log",
110 word_idx: w + 2,
111 byte_len: debug_bytes.len(),
112 fix: "decode only debug-log buffers produced by the matching megakernel protocol encoder",
113 })?,
114 read_word_from_optional_words(words, debug_bytes, w + 3).ok_or(
115 ProtocolError::MissingWord {
116 buffer: "debug_log",
117 word_idx: w + 3,
118 byte_len: debug_bytes.len(),
119 fix: "decode only debug-log buffers produced by the matching megakernel protocol encoder",
120 })?,
121 ],
122 });
123 }
124 Ok(())
125}
126
127fn debug_word_index(word: u32, label: &'static str) -> Result<usize, ProtocolError> {
128 usize::try_from(word).map_err(|_| ProtocolError::ByteLengthOverflow {
129 buffer: "debug_log",
130 fix: match label {
131 "cursor word" => "debug-log cursor word cannot fit host usize",
132 "record word count" => "debug-log record word count cannot fit host usize",
133 "records base word" => "debug-log records base word cannot fit host usize",
134 _ => "debug-log word index cannot fit host usize",
135 },
136 })
137}
138
139fn try_reserve_record_capacity(
140 out: &mut Vec<DebugRecord>,
141 target_capacity: usize,
142) -> Result<(), ProtocolError> {
143 vyre_foundation::allocation::try_reserve_vec_to_capacity(out, target_capacity).map_err(|_| {
144 ProtocolError::ByteLengthOverflow {
145 buffer: "debug_log",
146 fix: "host debug-log decode could not reserve output records; reduce debug-log capacity or decode into a reused scratch vector",
147 }
148 })
149}