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