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