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