Skip to main content

cc_teec/
teec_trace.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2025-2026 KylinSoft Co., Ltd. <https://www.kylinos.cn/>
3// See LICENSES for license details.
4
5#![allow(unused_variables)]
6
7use std::ffi::CStr;
8
9use libc::{c_char, c_int, size_t};
10
11pub const TRACE_ERROR: c_int = 1;
12pub const TRACE_INFO: c_int = 2;
13pub const TRACE_DEBUG: c_int = 3;
14pub const TRACE_FLOW: c_int = 4;
15
16fn get_thread_id() -> i32 {
17    unsafe { libc::syscall(libc::SYS_gettid) as i32 }
18}
19
20/// 判断字节是否为可打印ASCII字符(32-126)
21#[allow(dead_code)]
22fn is_printable_ascii(byte: u8) -> bool {
23    (32..=126).contains(&byte)
24}
25
26/// 将日志级别常量转换为对应的字符串表示
27fn get_level_string(level: c_int) -> &'static str {
28    match level {
29        TRACE_ERROR => "ERR",
30        TRACE_INFO => "INF",
31        TRACE_DEBUG => "DBG",
32        TRACE_FLOW => "FLW",
33        _ => "",
34    }
35}
36
37// TODO: 实现 log_to_file 函数,当定义了 TEEC_LOG_FILE 时,
38// 在函数最后调用 log_to_file 函数将信息写入日志中
39
40/// 格式化输出日志信息到标准输出,格式为:
41/// 级别 \[线程ID\] 前缀:函数名:行号: 消息
42///
43/// # 参数
44/// - function: 函数名(可为null)
45/// - line: 行号(<=0时忽略函数信息)
46/// - level: 日志级别
47/// - prefix: 模块前缀
48/// - message: 日志消息
49///
50/// # 返回值
51/// - 成功时返回输出的字节数,失败时返回-1
52#[expect(clippy::not_unsafe_ptr_arg_deref)]
53#[unsafe(no_mangle)]
54pub extern "C" fn rust_dprintf(
55    function: *const c_char,
56    line: c_int,
57    level: c_int,
58    prefix: *const c_char,
59    message: *const c_char,
60) -> c_int {
61    if prefix.is_null() || message.is_null() {
62        return -1;
63    }
64
65    let msg = {
66        // SAFETY: 已经检查 message 不为空
67        let c_str = unsafe { CStr::from_ptr(message) };
68        match c_str.to_str() {
69            Ok(s) => s,
70            Err(_) => return -1,
71        }
72    };
73
74    let output = if !function.is_null() && line > 0 {
75        // SAFETY: 已经检查 function 不为空
76        // 使用 unwrap_or 提供有意义的默认值,避免静默失败
77        let function_str = unsafe { CStr::from_ptr(function) }
78            .to_str()
79            .unwrap_or("<invalid_utf8>");
80
81        // SAFETY: 已经检查 prefix 不为空
82        let prefix_str = unsafe { CStr::from_ptr(prefix) }
83            .to_str()
84            .unwrap_or("<invalid_utf8>");
85        let thread_id = get_thread_id();
86        let level_str = get_level_string(level);
87
88        format!("{level_str} [{thread_id}] {prefix_str}:{function_str}:{line}: {msg}\n")
89    } else {
90        format!("{msg}\n")
91    };
92
93    print!("{output}");
94
95    output.len() as c_int
96}
97
98/// 十六进制dump函数,用于调试级别3和4
99///
100/// 以十六进制和 ASCII 形式输出内存缓冲区内容,格式类似 hexdump -C
101/// 每行显示 16 字节,左侧为十六进制,右侧为可打印 ASCII 字符
102///
103/// # 参数
104/// - bname: 缓冲区名称,显示在输出开头
105/// - buffer: 待dump的内存缓冲区起始地址
106/// - blen: 缓冲区长度
107#[cfg(any(feature = "debug_level_3", feature = "debug_level_4"))]
108#[expect(clippy::not_unsafe_ptr_arg_deref)]
109#[unsafe(no_mangle)]
110pub extern "C" fn dump_buffer(bname: *const c_char, buffer: *const u8, blen: size_t) {
111    if bname.is_null() || buffer.is_null() || blen == 0 {
112        return;
113    }
114
115    // SAFETY: 已经检查 bname 不为空
116    // 使用 unwrap_or 提供有意义的默认值,便于识别编码问题
117    let bname_str = unsafe { CStr::from_ptr(bname) }
118        .to_str()
119        .unwrap_or("<invalid_utf8>");
120
121    eprintln!("#### {bname_str}");
122
123    // SAFETY: 创建缓冲区切片,已经检查 buffer 不为空且 blen 指定了有效长度
124    let buffer_slice = unsafe { std::slice::from_raw_parts(buffer, blen) };
125    let mut offset = 0;
126
127    while offset < buffer_slice.len() {
128        // 打印十六进制部分(每字节两位十六进制数)
129        for i in 0..16 {
130            if offset + i < buffer_slice.len() {
131                eprint!("{:02x} ", buffer_slice[offset + i]);
132            } else {
133                eprint!("   "); // 填充空格保持对齐
134            }
135
136            if i == 7 {
137                eprint!(" "); // 在8字节后添加额外空格
138            }
139        }
140
141        eprint!(" |");
142
143        // 打印 ASCII
144        for i in 0..16 {
145            if offset + i < buffer_slice.len() {
146                let byte = buffer_slice[offset + i];
147                if is_printable_ascii(byte) {
148                    eprint!("{}", byte as char);
149                } else {
150                    eprint!("."); // 不可打印字符显示为.
151                }
152            }
153        }
154
155        eprintln!("|");
156
157        offset += 16;
158    }
159}
160
161/// dump_buffer 的空实现,用于未启用调试特性时
162///
163/// 保持相同的函数签名但函数体为空,避免链接错误
164#[cfg(not(any(feature = "debug_level_3", feature = "debug_level_4")))]
165#[unsafe(no_mangle)]
166pub extern "C" fn dump_buffer(_bname: *const c_char, _buffer: *const u8, _blen: size_t) {
167    // 空操作,仅在启用 debug_level_3 或 debug_level_4 时才有实际功能
168}
169
170#[cfg(test)]
171mod teec_trace_tests {
172    use super::*;
173    use std::ffi::CString;
174
175    fn make_c_string_with_ptr(s: &str) -> (CString, *const c_char) {
176        let cstr = CString::new(s).expect("Failed to create CString");
177        let ptr = cstr.as_ptr();
178        (cstr, ptr)
179    }
180
181    #[test]
182    fn test_is_printable_ascii() {
183        // 测试各种边界情况
184        assert!(is_printable_ascii(b'A'));
185        assert!(is_printable_ascii(b'z'));
186        assert!(is_printable_ascii(b' '));
187        assert!(is_printable_ascii(b'~'));
188
189        assert!(!is_printable_ascii(0));
190        assert!(!is_printable_ascii(31));
191        assert!(!is_printable_ascii(127));
192        assert!(!is_printable_ascii(128));
193        assert!(!is_printable_ascii(255));
194    }
195
196    #[test]
197    fn test_get_level_string() {
198        // 测试所有预定义的日志级别
199        assert_eq!(get_level_string(TRACE_ERROR), "ERR");
200        assert_eq!(get_level_string(TRACE_INFO), "INF");
201        assert_eq!(get_level_string(TRACE_DEBUG), "DBG");
202        assert_eq!(get_level_string(TRACE_FLOW), "FLW");
203        assert_eq!(get_level_string(0), ""); // 未知级别
204        assert_eq!(get_level_string(999), ""); // 无效级别
205    }
206
207    #[test]
208    fn test_rust_dprintf_valid_input() {
209        let function = Some("test_function");
210        let line = 42;
211        let level = TRACE_INFO;
212        let prefix = "mylib";
213        let message = "This is a test message";
214
215        let (function_cstr, function_ptr) = if let Some(func) = function {
216            make_c_string_with_ptr(func)
217        } else {
218            // 空字符串永远不会失败,使用 expect 提供清晰的错误信息
219            let cstr = CString::new("").expect("Empty string should always create CString");
220            (cstr, std::ptr::null())
221        };
222
223        let (prefix_cstr, prefix_ptr) = make_c_string_with_ptr(prefix);
224        let (message_cstr, message_ptr) = make_c_string_with_ptr(message);
225
226        let result = rust_dprintf(function_ptr, line, level, prefix_ptr, message_ptr);
227
228        assert!(result > 0);
229    }
230
231    #[test]
232    fn test_rust_dprintf_different_levels() {
233        for (level, _expected_prefix) in [
234            (TRACE_ERROR, "ERR"),
235            (TRACE_INFO, "INF"),
236            (TRACE_DEBUG, "DBG"),
237            (TRACE_FLOW, "FLW"),
238        ] {
239            let function = Some("func");
240            let line = 1;
241            let prefix = "prefix";
242            let message = "message";
243
244            let (function_cstr, function_ptr) = if let Some(func) = function {
245                make_c_string_with_ptr(func)
246            } else {
247                // 空字符串永远不会失败,使用 expect 提供清晰的错误信息
248                let cstr = CString::new("").expect("Empty string should always create CString");
249                (cstr, std::ptr::null())
250            };
251
252            let (prefix_cstr, prefix_ptr) = make_c_string_with_ptr(prefix);
253            let (message_cstr, message_ptr) = make_c_string_with_ptr(message);
254
255            let result = rust_dprintf(function_ptr, line, level, prefix_ptr, message_ptr);
256
257            assert!(result > 0);
258        }
259    }
260
261    #[test]
262    fn test_rust_dprintf_no_function_info() {
263        let level = TRACE_INFO;
264        let prefix = "prefix";
265        let message = "simple message";
266
267        let (prefix_cstr, prefix_ptr) = make_c_string_with_ptr(prefix);
268        let (message_cstr, message_ptr) = make_c_string_with_ptr(message);
269
270        let result = rust_dprintf(std::ptr::null(), 0, level, prefix_ptr, message_ptr);
271
272        // 当 function 为 null 时,输出格式应该只有消息和换行
273        // 返回值应该是消息长度加换行符
274        assert_eq!(result, (message.len() + 1) as i32); // +1 为换行符
275    }
276
277    #[test]
278    fn test_rust_dprintf_null_pointers() {
279        // 测试空指针处理
280        let (prefix_cstr, prefix_ptr) = make_c_string_with_ptr("prefix");
281        let result = rust_dprintf(
282            std::ptr::null(),
283            0,
284            TRACE_INFO,
285            prefix_ptr,
286            std::ptr::null(),
287        );
288        assert_eq!(result, -1);
289
290        let (message_cstr, message_ptr) = make_c_string_with_ptr("message");
291        let result = rust_dprintf(
292            std::ptr::null(),
293            0,
294            TRACE_INFO,
295            std::ptr::null(),
296            message_ptr,
297        );
298        assert_eq!(result, -1);
299
300        let result = rust_dprintf(
301            std::ptr::null(),
302            0,
303            TRACE_INFO,
304            std::ptr::null(),
305            std::ptr::null(),
306        );
307        assert_eq!(result, -1);
308    }
309
310    #[test]
311    fn test_rust_dprintf_invalid_utf8() {
312        // 测试无效 UTF-8 输入的处理
313        let invalid_utf8 = b"valid\xFFpart\0";
314        let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(invalid_utf8) };
315        let ptr = cstr.as_ptr();
316
317        let (prefix_cstr, prefix_ptr) = make_c_string_with_ptr("prefix");
318        let result = rust_dprintf(std::ptr::null(), 0, TRACE_INFO, prefix_ptr, ptr);
319
320        // 应该返回 -1,因为 UTF-8 转换失败
321        assert_eq!(result, -1);
322    }
323
324    #[test]
325    fn test_thread_id_positive() {
326        // 线程 ID 应该是正数
327        let thread_id = get_thread_id();
328        assert!(thread_id > 0);
329    }
330
331    #[test]
332    fn test_integration_style() {
333        // 模拟实际使用场景
334        let test_cases = vec![
335            (
336                Some("connect"),
337                101,
338                TRACE_ERROR,
339                "network",
340                "Connection failed",
341            ),
342            (
343                Some("process"),
344                205,
345                TRACE_INFO,
346                "worker",
347                "Processing item",
348            ),
349            (
350                Some("validate"),
351                42,
352                TRACE_DEBUG,
353                "parser",
354                "Validating input",
355            ),
356            (Some("loop"), 15, TRACE_FLOW, "main", "Iteration complete"),
357        ];
358
359        for (func, line, level, prefix, msg) in test_cases {
360            let (function_cstr, function_ptr) = if let Some(f) = func {
361                make_c_string_with_ptr(f)
362            } else {
363                // 空字符串永远不会失败,使用 expect 提供清晰的错误信息
364                let cstr = CString::new("").expect("Empty string should always create CString");
365                (cstr, std::ptr::null())
366            };
367
368            let (prefix_cstr, prefix_ptr) = make_c_string_with_ptr(prefix);
369            let (message_cstr, message_ptr) = make_c_string_with_ptr(msg);
370
371            let result = rust_dprintf(function_ptr, line, level, prefix_ptr, message_ptr);
372
373            // 基本验证:函数应成功执行
374            assert!(
375                result > 0,
376                "Failed for case: {:?}",
377                (func, line, level, prefix, msg)
378            );
379        }
380    }
381
382    #[test]
383    fn test_performance_no_panics() {
384        // 确保多次调用不会 panic
385        let (prefix_cstr, prefix_ptr) = make_c_string_with_ptr("perf");
386        let (message_cstr, message_ptr) = make_c_string_with_ptr("test");
387
388        for _ in 0..1000 {
389            let result = rust_dprintf(std::ptr::null(), 0, TRACE_INFO, prefix_ptr, message_ptr);
390            assert!(result >= 0);
391        }
392    }
393
394    // 测试 dump_buffer 的条件编译
395    #[test]
396    fn test_dump_buffer_exists() {
397        // 验证dump_buffer函数存在且可调用
398        let buffer = b"Hello, World!";
399        let (name_cstr, name_ptr) = make_c_string_with_ptr("test_buffer");
400
401        // 安全调用,只是验证接口存在
402        dump_buffer(name_ptr, buffer.as_ptr(), buffer.len());
403
404        // 测试空指针和零长度
405        dump_buffer(std::ptr::null(), std::ptr::null(), 0);
406        dump_buffer(name_ptr, std::ptr::null(), 10);
407        dump_buffer(std::ptr::null(), buffer.as_ptr(), buffer.len());
408    }
409
410    #[test]
411    fn test_dump_buffer_edge_cases() {
412        // 测试 dump_buffer 的边界情况
413        let buffer: [u8; 0] = [];
414        let (name_cstr, name_ptr) = make_c_string_with_ptr("empty");
415
416        dump_buffer(name_ptr, buffer.as_ptr(), buffer.len());
417
418        let small_buffer = b"short";
419        let (name2_cstr, name2_ptr) = make_c_string_with_ptr("small");
420
421        dump_buffer(name2_ptr, small_buffer.as_ptr(), small_buffer.len());
422
423        let non_printable = [0u8, 1, 2, 3, 128, 255, 10, 13];
424        let (name3_cstr, name3_ptr) = make_c_string_with_ptr("non_printable");
425
426        dump_buffer(name3_ptr, non_printable.as_ptr(), non_printable.len());
427    }
428}
429
430#[cfg(all(test, any(feature = "debug_level_3", feature = "debug_level_4")))]
431mod dump_buffer_tests {
432    use super::*;
433    use std::ffi::CString;
434
435    // 测试辅助函数
436    fn make_c_string_with_ptr(s: &str) -> (CString, *const c_char) {
437        let cstr = CString::new(s).expect("Failed to create CString");
438        let ptr = cstr.as_ptr();
439        (cstr, ptr)
440    }
441
442    #[test]
443    fn test_dump_buffer_output() {
444        // 测试实际的dump_buffer输出格式(仅在启用相关特性时)
445        let buffer = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%";
446        let (name_cstr, name_ptr) = make_c_string_with_ptr("hex_dump_test");
447
448        // 这个测试主要确保函数不 panic
449        dump_buffer(name_ptr, buffer.as_ptr(), buffer.len());
450    }
451
452    #[test]
453    fn test_dump_buffer_exact_format() {
454        // 测试精确的格式输出
455        let buffer = vec![
456            // 第一行:可打印ASCII
457            b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D',
458            b'E', b'F', // 第二行:混合内容
459            0x00, 0x7F, 0x80, 0xFF, 32, 126, 10, 13, 255, 1, 2, 3, b'X', b'Y', b'Z', 0,
460        ];
461
462        let (name_cstr, name_ptr) = make_c_string_with_ptr("exact_format_test");
463
464        // 这个测试主要确保函数不 panic
465        dump_buffer(name_ptr, buffer.as_ptr(), buffer.len());
466    }
467}