printk()-3-函数实现

基于msm-5.4


1. printk %ps格式打印调用路径

printk(*fmt, ...) //printk.c
    vprintk_func(fmt, args) //printk_safe.c
        vprintk_default(fmt, args) //printk.c 默认的, NMI/safe上下文是不同函数
            vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args) //printk.c
                vprintk_store(facility, level, dict, dictlen, fmt, args) //printk.c
                    vscnprintf(text, sizeof(textbuf), fmt, args) //lib/vsprintf.c
                        vsnprintf(buf, size, fmt, args) //lib/vsprintf.c
                            format_decode(fmt, &spec) //lib/vsprintf.c 此函数中解析格式控制字符串
                            case FORMAT_TYPE_PTR: //对于%ps打印,对应这个
                            pointer(fmt, str, end, va_arg(args, void *), spec); //vsprintf.c
                                case 'F':
                                case 'f':
                                case 'S':
                                case 's':
                                case 'B': //可以打印backtrace ####
                                    symbol_string(buf, end, ptr, spec, fmt); //vsprintf.c
                                        if (*fmt == 'B')
                                            sprint_backtrace(sym, value);
                                        else if (*fmt != 'f' && *fmt != 's')
                                            sprint_symbol(sym, value);
                                        else
                                            sprint_symbol_no_offset(sym, value) //kallsyms.c
                                                __sprint_symbol(buffer, address, 0, 0)
                                                    name = kallsyms_lookup(address, &size, &offset, &modname, buffer); //关键函数
                                                    if (!name) //符号名字若找不到就记录地址
                                                        return sprintf(buffer, "0x%lx", address - symbol_offset);
                                                    strcpy(buffer, name);
                                                    if (add_offset) //若要打印offset则打印offset和size
                                                        len += sprintf(buffer + len, "+%#lx/%#lx", offset, size);
                                                    if (modname) //若符号位于模块中还打印模块名
                                                        len += sprintf(buffer + len, " [%s]", modname);
                    log_output(facility, level, lflags, dict, dictlen, text, text_len);
                if (console_trylock_spinning()) //忙等获取控制台进行打印
                    console_unlock();
                wake_up_klogd() //唤醒 cat /dev/kmsg 和 syslog()

下面继续分析 kallsyms_lookup():

    kallsyms_lookup(addr, ...) //kallsyms.c
        if (is_ksym_addr(addr)) //判断 addr 属于内核地址范围 _stext<=addr<=_end
            pos = get_symbol_pos(addr, symbolsize, offset) //找到位置
            kallsyms_expand_symbol(get_symbol_offset(pos), namebuf, KSYM_NAME_LEN) //获取名字
            /* 若没找到看符号是否在模块中、是否在bpf镜像中、是否在ftrace中 */
            ret = module_address_lookup(addr, symbolsize, offset, modname, namebuf);
            if (!ret)
                ret = bpf_address_lookup(addr, symbolsize, offset, modname, namebuf);
            if (!ret)
                ret = ftrace_mod_address_lookup(addr, symbolsize, offset, modname, namebuf);

注: 这个msm-5.4内核的打印逻辑和 kernel-6.1 是一样的。

 

posted on 2026-03-13 18:15  Hello-World3  阅读(0)  评论(0)    收藏  举报

导航