当前位置: 首页 > news >正文

Linux 内核函数kallsyms_lookup_name

文章目录

  • 一、API使用
  • 二、源码解析
    • 2.1 kallsyms_lookup_name
    • 2.2 kallsyms_expand_symbol
    • 2.3 kallsyms_sym_address
      • 2.3.1 x86_64
      • 2.3.2 arm64
      • 2.3.3 CONFIG_KALLSYMS_ABSOLUTE_PERCPU
  • 参考资料

一、API使用

kallsyms_lookup_name 是一个内核函数,用于通过符号名称查找相应的符号地址。它是内核符号查找机制的一部分,允许内核代码和模块在运行时动态地查找和访问内核符号。

只要符号存在于/proc/kallsyms 文件中,都可以通过kallsyms_lookup_name获取其符号的地址。

内核版本 2.6.33 - 5.7.0 该符号都是导出的:

# cat /proc/kallsyms | grep '\<kallsyms_lookup_name\>'
ffffffffb8558e90 T kallsyms_lookup_name

在 2.6.33 以下和 5.7.0 以上可以用 kprobe 来替代该函数,如下:

#include <linux/version.h>
#include <linux/kallsyms.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)#include <linux/kprobes.h>static unsigned long (*kallsyms_lookup_name_sym)(const char *name);static int _kallsyms_lookup_kprobe(struct kprobe *p, struct pt_regs *regs)
{return 0;
}unsigned long get_kallsyms_func(void)
{struct kprobe probe;int ret;unsigned long addr;memset(&probe, 0, sizeof(probe));probe.pre_handler = _kallsyms_lookup_kprobe;probe.symbol_name = "kallsyms_lookup_name";ret = register_kprobe(&probe);if (ret)return 0;addr = (unsigned long)probe.addr;unregister_kprobe(&probe);return addr;
}unsigned long generic_kallsyms_lookup_name(const char *name)
{/* singleton */if (!kallsyms_lookup_name_sym) {kallsyms_lookup_name_sym = (void *)get_kallsyms_func();if(!kallsyms_lookup_name_sym)return 0;}return kallsyms_lookup_name_sym(name);
}#elseunsigned long generic_kallsyms_lookup_name(const char *name)
{return kallsyms_lookup_name(name);
}#endif

这样generic_kallsyms_lookup_name在所有内核版本都可以完成kallsyms_lookup_name的功能。

二、源码解析

2.1 kallsyms_lookup_name

extern const unsigned long kallsyms_num_syms
__attribute__((weak, section(".rodata")));/* Lookup the address for this symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name)
{char namebuf[KSYM_NAME_LEN];unsigned long i;unsigned int off;for (i = 0, off = 0; i < kallsyms_num_syms; i++) {off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));if (strcmp(namebuf, name) == 0)return kallsyms_sym_address(i);}return module_kallsyms_lookup_name(name);
}
EXPORT_SYMBOL_GPL(kallsyms_lookup_name);

首先定义了一个名为 namebuf 的字符数组,用于存储扩展后的符号名称。KSYM_NAME_LEN 是一个常量,表示符号名称的最大长度。

接下来,函数通过一个循环来遍历符号表中的每个符号。kallsyms_num_syms 是一个表示符号表中符号数量的变量。

在循环中,使用 kallsyms_expand_symbol 函数对符号进行解压缩,将解压后的符号名称存储在 namebuf 中。

然后,函数将解压后的符号名称与传入的 name 进行比较。如果找到匹配的符号名称,函数返回相应符号的地址,即通过 kallsyms_sym_address 函数获取的地址。

如果循环结束后仍然没有找到匹配的符号,函数调用 module_kallsyms_lookup_name 函数,用于在内核模块中查找符号。

最后,通过 EXPORT_SYMBOL_GPL 宏,将 kallsyms_lookup_name 函数导出为内核符号,以便其他模块或代码可以引用和使用该函数。

2.2 kallsyms_expand_symbol

(1)

extern const u8 kallsyms_names[] __weak;extern const u8 kallsyms_token_table[] __weak;
extern const u16 kallsyms_token_index[] __weak;/** Expand a compressed symbol data into the resulting uncompressed string,* if uncompressed string is too long (>= maxlen), it will be truncated,* given the offset to where the symbol is in the compressed stream.*/
static unsigned int kallsyms_expand_symbol(unsigned int off,char *result, size_t maxlen)
{int len, skipped_first = 0;const u8 *tptr, *data;/* Get the compressed symbol length from the first symbol byte. */data = &kallsyms_names[off];len = *data;data++;/** Update the offset to return the offset for the next symbol on* the compressed stream.*/off += len + 1;/** For every byte on the compressed symbol data, copy the table* entry for that byte.*/while (len) {tptr = &kallsyms_token_table[kallsyms_token_index[*data]];data++;len--;while (*tptr) {if (skipped_first) {if (maxlen <= 1)goto tail;*result = *tptr;result++;maxlen--;} elseskipped_first = 1;tptr++;}}tail:if (maxlen)*result = '\0';/* Return to offset to the next symbol. */return off;
}

用于将压缩的符号数据展开为未压缩的字符串形式。

kallsyms_names数组保存每一个内核符号名字被压缩后的字节编码。存储的格式是 len + data,data是压缩后的字符编码。

函数的参数和功能如下:

off:指定符号在压缩流中的偏移量。
result:存储展开后的符号字符串的缓冲区。
maxlen:缓冲区的最大长度,用于避免字符串溢出。

函数首先从压缩流中获取符号的压缩长度,并将其存储在变量 len 中。然后,更新偏移量 off,使其指向下一个符号在压缩流中的位置。

接下来,函数开始解压缩符号数据。它逐字节遍历压缩的符号数据,根据每个字节在符号表中的索引,从符号表中获取相应的字符,并将其复制到结果缓冲区中。

在解压缩过程中,函数会跳过第一个字符,并将 skipped_first 设置为 1,这是为了处理一种特殊情况,即如果结果缓冲区的长度不足以容纳完整的符号,则只复制符号的一部分。

当解压缩完成后,函数检查剩余的缓冲区空间。如果缓冲区还有剩余空间,将在末尾添加空字符 ‘\0’,以确保结果字符串以 null 结尾。

最后,函数返回下一个符号在压缩流中的偏移量,以便在下次解压缩时使用。

(2)

extern const u8 kallsyms_token_table[] __weak;
extern const u16 kallsyms_token_index[] __weak;

kallsyms_token_table 和 kallsyms_token_index 数组在 Linux 内核的符号查找机制中用于符号展开过程。

这些数组的作用是提供压缩的符号数据与对应的未压缩字符之间的映射关系,以高效地将压缩的符号展开为原始的字符串形式。

以下是对这两个数组的简要说明:

kallsyms_token_table:该数组包含了用作压缩符号表示中的标记(token)的字符表。每个标记表示一系列在符号名称中常见的字符序列。数组中的条目被组织成一种能够高效查找标记索引的方式。

kallsyms_token_index:该数组用作对 kallsyms_token_table 的索引。它将压缩符号数据中的每个字节值映射到对应的标记表条目。在符号展开过程中,通过这个索引可以快速获取压缩数据中的字节对应的字符序列。

在符号展开过程中,kallsyms_expand_symbol 函数逐字节遍历压缩的符号数据。对于每个字节,它使用 kallsyms_token_index 数组获取对应的 kallsyms_token_table 中的索引。然后,从标记表中获取相应的字符序列,并将其复制到结果缓冲区中。

通过使用标记和索引,符号展开过程避免了在压缩的符号数据中多次存储重复的字符。相反,它使用较短的标记表示常见字符序列,从而实现了对符号名称的更高效压缩和解压缩。

kallsyms_token_table 和 kallsyms_token_index 数组在 Linux 内核中的符号压缩和展开机制中起着关键作用,通过优化符号名称的存储和查找,提高了效率。

(3)
符号数据通常是通过编译器和链接器生成的。这些符号数据包括函数名、变量名以及其他在编译和链接过程中产生的符号,然后保存在内核符号表(kernel symbol table)。

压缩的符号数据来源通常是内核符号表(kernel symbol table)。内核符号表包含了各种内核函数、变量和其他符号的信息,例如函数名、变量名以及其对应的地址等。

内核符号表中的符号信息通过特定的压缩算法进行压缩,以减小其大小并节省存储空间。

在编译内核时,可以选择启用内核符号表的生成。通过特定的编译选项,例如 CONFIG_KALLSYMS,可以将内核符号信息保留在编译后的内核镜像中。这样,在运行时,可以通过相应的机制(例如 /proc/kallsyms 文件)读取内核符号表,并将符号信息保存在内存中。

# cat /boot/config-4.19.90-23.8.v2101.ky10.x86_64 | grep CONFIG_KALLSYMS
CONFIG_KALLSYMS=y

压缩的符号数据是通过对内核符号表中的符号信息进行压缩算法处理而得到的。这样做的目的是减小符号数据的大小,节省内存空间和存储空间。在压缩过程中,符号的名称和其他相关信息被编码为压缩格式,以便在需要时进行解压缩并恢复出原始的符号信息。

关于符号数据的压缩,Linux内核中使用了一种简单的压缩算法,将符号数据进行压缩以节省内存空间。这种压缩算法使用了基于标记的方法,其中kallsyms_token_table和kallsyms_token_index数组用于解压缩过程。

在内核构建过程中,符号数据首先被收集,并将其压缩为一个压缩流。压缩的符号数据流中的每个字节都对应于kallsyms_token_table中的一个标记,或者表示一个特定的字符。通过解压缩过程,这些压缩的符号数据将被展开为原始的符号字符串。

kallsyms_expand_symbol 函数中的代码片段处理的就是这样的压缩的符号数据,通过解压缩算法和相关的表格,将其还原为未压缩的字符串形式,以便进行进一步的处理和使用。

备注:
具体的压缩过程在内核的构建脚本中实现,而不是在内核源码中:

// linux-4.19.90/scripts/kallsyms.c/* replace a given token in all the valid symbols. Use the sampled symbols* to update the counts */
static void compress_symbols(unsigned char *str, int idx)
{unsigned int i, len, size;unsigned char *p1, *p2;for (i = 0; i < table_cnt; i++) {len = table[i].len;p1 = table[i].sym;/* find the token on the symbol */p2 = find_token(p1, len, str);if (!p2) continue;/* decrease the counts for this symbol's tokens */forget_symbol(table[i].sym, len);size = len;do {*p2 = idx;p2++;size -= (p2 - p1);memmove(p2, p2 + 1, size);p1 = p2;len--;if (size < 2) break;/* find the token on the symbol */p2 = find_token(p1, size, str);} while (p2);table[i].len = len;/* increase the counts for this symbol's new tokens */learn_symbol(table[i].sym, len);}
}

随着内核的发展,可能会采用更为复杂的压缩算法,以提高压缩率和解压缩效率。例如,使用字典压缩算法,如LZ77或LZ78变种,通过建立符号字典并对重复的符号序列进行替换来实现压缩。这些算法通常会结合其他技术,如霍夫曼编码或算术编码,进一步提高压缩效果。

2.3 kallsyms_sym_address

extern const int kallsyms_offsets[] __weak;extern const unsigned long kallsyms_relative_base
__attribute__((weak, section(".rodata")));static unsigned long kallsyms_sym_address(int idx)
{if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))return kallsyms_addresses[idx];/* values are unsigned offsets if --absolute-percpu is not in effect */if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))return kallsyms_relative_base + (u32)kallsyms_offsets[idx];/* ...otherwise, positive offsets are absolute values */if (kallsyms_offsets[idx] >= 0)return kallsyms_offsets[idx];/* ...and negative offsets are relative to kallsyms_relative_base - 1 */return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
}

用于在内核中获取符号地址的函数kallsyms_sym_address的实现。根据给定的索引idx,该函数返回对应符号的地址。

该函数的实现基于一些条件编译选项,包括CONFIG_KALLSYMS_BASE_RELATIVE和CONFIG_KALLSYMS_ABSOLUTE_PERCPU。这些选项根据内核的配置状态来确定符号地址的计算方式。

目前我接触的x86_64和arm64 都配置了CONFIG_KALLSYMS_BASE_RELATIVE编译选项。在启用CONFIG_KALLSYMS_BASE_RELATIVE选项时,符号地址以相对于基地址的偏移量形式存储,而不是绝对地址。kallsyms_relative_base表示这个基地址:

kallsyms_relative_base变量作为基地址,用于计算相对符号地址。
kallsyms_offsets 是一个数组,记录着每一个符号相对于kallsyms_relative_base变量的偏移量。

但是x86_64配置了CONFIG_KALLSYMS_ABSOLUTE_PERCPU选项,arm64没有配置CONFIG_KALLSYMS_ABSOLUTE_PERCPU选项。

CONFIG_KALLSYMS_ABSOLUTE_PERCPU 选项与 kallsyms 特性中的 per-CPU 符号处理相关。Per-CPU 符号是针对系统中每个 CPU 单独存在的特殊符号。这些符号通常用于存储特定于每个 CPU 的数据或状态。

当启用 CONFIG_KALLSYMS_ABSOLUTE_PERCPU 时,意味着在 kallsyms 机制中将 per-CPU 符号视为绝对值。正的 per-CPU 符号的偏移量被视为绝对地址,而负的偏移量被视为相对于特定基地址(kallsyms_relative_base - 1)的相对地址。

另一方面,当未启用 CONFIG_KALLSYMS_ABSOLUTE_PERCPU 时,per-CPU 符号被视为相对于基地址(kallsyms_relative_base)的无符号偏移量。基地址相对的方法可以更紧凑地存储 per-CPU 符号在符号表中的表示。

2.3.1 x86_64

# cat /etc/os-release
NAME="Kylin Linux Advanced Server"# uname -r
4.19.90-23.8.v2101.ky10.x86_64# lscpu
架构:                           x86_64
# cat /boot/config-4.19.90-23.8.v2101.ky10.x86_64 | grep CONFIG_KALLSYMS_BASE_RELATIVE
CONFIG_KALLSYMS_BASE_RELATIVE=y
# cat /boot/config-4.19.90-23.8.v2101.ky10.x86_64 | grep CONFIG_KALLSYMS_ABSOLUTE_PERCPU
CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y
static unsigned long kallsyms_sym_address(int idx)
{/* ...otherwise, positive offsets are absolute values */if (kallsyms_offsets[idx] >= 0)return kallsyms_offsets[idx];/* ...and negative offsets are relative to kallsyms_relative_base - 1 */return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
}

CONFIG_KALLSYMS_ABSOLUTE_PERCPU启用,表示偏移量包含正负值,函数根据正负值决定地址的计算方式。

如果偏移量kallsyms_offsets[idx]大于等于0,表示偏移量是绝对值,函数返回kallsyms_offsets[idx]作为地址。
正数:表示符号的地址是绝对地址,可以直接作为符号的地址使用。

如果偏移量kallsyms_offsets[idx]小于0,表示偏移量是相对于kallsyms_relative_base - 1的负值,函数返回kallsyms_relative_base - 1 - kallsyms_offsets[idx]作为地址。
负数:表示符号的地址是相对于 kallsyms_relative_base - 1 地址的偏移量。通过将偏移量从 kallsyms_relative_base - 1 中减去,可以计算出符号的实际地址。

CONFIG_KALLSYMS_ABSOLUTE_PERCPU用于控制符号地址在处理器特定数据区(per-CPU)时的解释方式。

在内核中,有一些符号(如变量或函数)可以在每个处理器的特定数据区中有不同的副本。这是为了提高性能和并发性。这些符号在每个处理器的数据区中的地址可能是相对于某个基地址而不是绝对地址。

当启用了CONFIG_KALLSYMS_ABSOLUTE_PERCPU选项时,表示偏移值中的正数偏移是绝对地址,而负数偏移是相对于基地址的偏移量。这意味着符号在每个处理器的数据区中具有不同的绝对地址。

当启用CONFIG_KALLSYMS_ABSOLUTE_PERCPU配置选项时,表示每个处理器特定数据区(per-CPU)的符号具有独立的绝对地址。这意味着每个处理器的符号地址不是相对于共享基地址的,而是每个处理器都有自己独特的绝对地址。

2.3.2 arm64

# cat /etc/os-release
NAME="Kylin Linux Advanced Server"# uname -r
4.19.90-24.4.v2101.ky10.aarch64# lscpu
架构:                           aarch64
# cat /boot/config-4.19.90-24.4.v2101.ky10.aarch64 | grep CONFIG_KALLSYMS_BASE_RELATIVE
CONFIG_KALLSYMS_BASE_RELATIVE=y
# cat /boot/config-4.19.90-24.4.v2101.ky10.aarch64 | grep CONFIG_KALLSYMS_ABSOLUTE_PERCPU

没有CONFIG_KALLSYMS_ABSOLUTE_PERCPU选项。

当未启用CONFIG_KALLSYMS_ABSOLUTE_PERCPU选项时,每个处理器特定数据区的符号通常表示为相对于共享基地址的偏移量。通过偏移量与基地址相加,内核可以计算出实际的每个处理器特定数据区中的符号地址。这种方法通过避免为每个处理器存储单独的绝对地址,节省了内存。

static unsigned long kallsyms_sym_address(int idx)
{/* values are unsigned offsets if --absolute-percpu is not in effect */if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))return kallsyms_relative_base + (u32)kallsyms_offsets[idx];

如果CONFIG_KALLSYMS_ABSOLUTE_PERCPU未启用,表示偏移量是无符号的,函数返回kallsyms_relative_base + (u32)kallsyms_offsets[idx],其中kallsyms_relative_base是一个基地址,kallsyms_offsets是一个无符号偏移量数组。

函数通过将基地址(kallsyms_relative_base)与无符号偏移值(kallsyms_offsets[idx])相加来计算相对地址。

2.3.3 CONFIG_KALLSYMS_ABSOLUTE_PERCPU

在内核中启用CONFIG_KALLSYMS_ABSOLUTE_PERCPU选项对性能的影响:

符号查找效率提高: 启用CONFIG_KALLSYMS_ABSOLUTE_PERCPU选项后,每个处理器特定数据区的符号都有自己的绝对地址,而不是相对于基地址的偏移量。这意味着符号查找可以更快速和直接地进行,因为不再需要计算相对地址。这可能会提高符号查找的效率,特别是在需要频繁访问处理器特定数据区的情况下。

内存占用增加: 启用CONFIG_KALLSYMS_ABSOLUTE_PERCPU选项会导致每个处理器特定数据区的符号都需要独立的绝对地址。相对于使用相对地址来表示,这可能会增加内存的占用量,因为需要为每个处理器存储独立的地址。如果系统中有大量的处理器或大量的处理器特定数据区符号,这种额外的内存开销可能是显著的。

启动时间延长: 内核在启动时需要解析符号表并建立符号地址的映射关系。启用CONFIG_KALLSYMS_ABSOLUTE_PERCPU选项后,需要额外的工作来处理每个处理器特定数据区的符号地址。这可能会导致启动时间延长,特别是在有大量处理器或处理器特定数据区符号的系统中。

代码复杂性增加: 启用CONFIG_KALLSYMS_ABSOLUTE_PERCPU选项会引入对处理器特定数据区符号的维护和处理的复杂性。需要确保每个处理器的符号地址在正确的位置,并且符号查找和解释逻辑需要处理符号地址的绝对性和相对性。这可能增加内核代码的复杂性和维护成本。

参考资料

Linux 4.19.90

https://blog.csdn.net/weixin_38878510/article/details/113264807

相关文章:

Linux 内核函数kallsyms_lookup_name

文章目录 一、API使用二、源码解析2.1 kallsyms_lookup_name2.2 kallsyms_expand_symbol2.3 kallsyms_sym_address2.3.1 x86_642.3.2 arm642.3.3 CONFIG_KALLSYMS_ABSOLUTE_PERCPU 参考资料 一、API使用 kallsyms_lookup_name 是一个内核函数&#xff0c;用于通过符号名称查找…...

强化学习在游戏AI中的应用与挑战

文章目录 1. 强化学习简介2. 强化学习在游戏AI中的应用2.1 游戏智能体训练2.2 游戏AI决策2.3 游戏测试和优化 3. 强化学习在游戏AI中的挑战3.1 探索与利用的平衡3.2 多样性的应对 4. 解决方法与展望4.1 深度强化学习4.2 奖励设计和函数逼近 5. 总结 &#x1f389;欢迎来到AIGC人…...

6 Python的异常处理

概述 在上一节&#xff0c;我们介绍了Python的面向对象编程&#xff0c;包括&#xff1a;类的定义、类的使用、类变量、实例变量、实例方法、类方法、静态方法、类的运算符重载、继承等内容。在这一节中&#xff0c;我们将介绍Python的异常处理。异常是指程序在运行过程中出现的…...

【跨语言通讯】

传统的跨语言通讯方案&#xff1a; 基于SOAP消息格式的WebService 基于JSON消息格式的RESTful 服务 主要弊端&#xff1a; XML体积太大&#xff0c;解析性能极差 JSON体积相对较小&#xff0c;解析相对较快&#xff0c;但表达能力较弱 如今比较流行的跨语言通讯方案&…...

Android 基础知识

一、Activity 1、onSaveInstanceState(),onRestoreInstanceState的调用时机 onSaveInstanceState 调用时机 从最近应用中选择运行其他程序时 但用户按下Home键时 屏幕方向切换时 按下电源案件时 从当前activity启动一个新的activity时 onRestorInstanceState调用时机 只…...

Linux常用命令_帮助命令、用户管理命令、压缩解压命令

文章目录 1. 帮助命令1.1 帮助命令:man1.2 帮助命令:help1.3 其他帮助命令 2. 用户管理命令2.1 用户管理命令: useradd2.2 用户管理命令: passwd2.3 用户管理命令: who2.4 用户管理命令: w 3. 压缩解压命令3.1 压缩解压命令: gzip3.2 压缩解压命令: gunzip3.3 压缩解压命令: ta…...

解决 KylinOS “Could not get lock /var/lib/dpkg/lock”错误

最近,我遇到了 “Could not get lock /var/lib/dpkg/lock”的错误,我既不能安装任何软件包,也不能更新系统。此错误也与“Could not get lock /var/lib/apt/lists/lock”错误密切相关。以下是 Ubuntu 20.04 上的一些样本输出。 Reading package lists… Done E: Could not…...

PHP pdf 自动填写表单

一、下载github上的项目&#xff0c;地址 二、下载pdftk 地址 // 转化PDF模板 pdftk modele.pdf output modele2.pdf# 填充pdf文件中的表单 require(fpdm.php); $fields array(name > My name,address > My address,city > My city,phone > My phone nu…...

Win2016Server绑定多网卡实现负载均衡

一、服务器端&#xff1a; 1、输入ncpa.cpl打开网络连接&#xff0c;对要绑定的网卡勾掉IPV4&#xff0c;IPV4地址选择自动 2、输入servermanager.exe&#xff0c;打开服务器管理器 3、在 [本地服务器] 中&#xff0c;点后边的 “已禁用” &#xff0c;在 [适配器和接口] 小窗口…...

微软宣布在 Excel 中使用 Python:结合了 Python 的强大功能和 Excel 的灵活性。

文章目录 Excel 中的 Python 有何独特之处&#xff1f;1. Excel 中的 Python 是为分析师构建的。高级可视化机器学习、预测分析和预测数据清理 2. Excel 中的 Python 通过 Anaconda 展示了最好的 Python 分析功能。3. Excel 中的 Python 在 Microsoft 云上安全运行&#xff0c;…...

学习心得03:OpenCV

数学真是不可思议&#xff0c;不管什么东西&#xff0c;都能用数学来处理。OpenCV以前也接触过&#xff0c;这次是系统学习一下。 颜色模型 RGB&#xff0c;YUV&#xff0c;HSV&#xff0c;Lab&#xff0c;GRAY 颜色转换cvtColor()/convertTo()&#xff0c;通道分离split()&…...

ubuntu学习(五)----读取文件以及光标的移动

1、读取文件函数原型介绍 ssize_t read(int fd,void*buf,size_t count) 参数说明&#xff1a; fd: 是文件描述符 buf:为读出数据的缓冲区&#xff1b; count: 为每次读取的字节数&#xff08;是请求读取的字节数&#xff0c;读上来的数据保存在缓冲区buf中&#xff0c;同时文…...

Python 数据分析——matplotlib 快速绘图

matplotlib采用面向对象的技术来实现&#xff0c;因此组成图表的各个元素都是对象&#xff0c;在编写较大的应用程序时通过面向对象的方式使用matplotlib将更加有效。但是使用这种面向对象的调用接口进行绘图比较烦琐&#xff0c;因此matplotlib还提供了快速绘图的pyplot模块。…...

uniapp小程序位置信息配置

uniapp 小程序获取当前位置信息报错 报错信息&#xff1a; getLocation:fail the api need to be declared in the requiredPrivateInfos field in app.json/ext.json 需要在manifest.json配置文件中进行配置&#xff1a;...

《基于 Vue 组件库 的 Webpack5 配置》1.模式 Mode 和 vue-loader

一定要配置 模式 Mode&#xff0c;这里有个小知识点&#xff0c;环境变量 process.env.NODE_ENV module.exports {mode: production,// process.env.NODE_ENV 或 development, }一定要配置 vue-loader Vue Loader v15 现在需要配合一个 webpack 插件才能正确使用&#xff1b; …...

01.sqlite3学习——数据库概述

目录 重点概述总结 数据库标准介绍 什么是数据库&#xff1f; 数据库是如何存储数据的&#xff1f; 数据库是如何管理数据的&#xff1f; 数据库系统结构 常见关系型数据库管理系统 关系型数据库相关知识点 数据库与文件存储数据对比 重点概述总结 数据库可以理解为操…...

视频集中存储/云存储平台EasyCVR国标GB28181协议接入的报文交互数据包分析

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频汇聚融合管理…...

容器技术,1. Docker,2. Kubernetes(K8s):

目录 容器技术 1. Docker&#xff1a; 2. Kubernetes&#xff08;K8s&#xff09;&#xff1a; Docker和Kubernetes 容器的主要应用场景有哪些&#xff1f; 容器技术 有效的将单个操作系统的资源划分到孤立的组中&#xff0c;以便更好的在孤立的组之间平衡有冲突的资源使…...

Jtti :sql server怎么备份数据库?

在 SQL Server 中备份数据库是一项重要的操作&#xff0c;它可以确保你的数据在意外情况下得以恢复。以下是在 SQL Server 中备份数据库的基本步骤&#xff1a; 使用 SQL Server Management Studio (SSMS) 进行备份&#xff1a; 打开 SQL Server Management Studio(SSMS)并连接…...

Stable Diffusion 系列教程 | 打破模型壁垒

目录 1.模型基本分类 1.1 CheckPoint 大模型/底模型/主模型 1.2 VAE美化模型/变分自编码器 1.3 HyperNetwork 超网络 1.4 embeddings&#xff08;/Textual Inversion&#xff09; 嵌入式向量 1.5 loRa 低秩适应模型 2. 下载途径和渠道 2.1 C站 2.1.1 如何筛选到自己需…...

Cypress 做 e2e 测试,如何在获得某个 checkbox 后先判断它是否被 check 然后再更改它的状态?

比如如果这个 checkbox 已经被 check 了&#xff0c;就不做操作&#xff0c;否则将它 check。 我们假设这个 checkbox 的 data-testid 属性是 VendorCodeCheckbox-0-test-id。Cypress 的代码如下&#xff1a; cy.getByTestId(VendorCodeCheckbox-0-test-id).shadow().find([r…...

基于PIC单片机温度-脉搏-DS18B20温度-液晶12864显示(proteus仿真+源程序)

一、系统方案 1、上电初始化液晶第一行显示脉搏&#xff0c;第二行显示温度&#xff0c;第三行显示模式&#xff0c;第四行显示强度&#xff1b;按下K1按键可以选择模式&#xff0c;催眼模式或治疗模式。 2、治疗模块下&#xff0c;可以通过K2、K3修改强度。 二、硬件设计 原理…...

【C++进阶(一)】STL大法以及string的使用

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; STL标准库 1. 前言2. STL库的版本以及缺陷3. ST…...

leetcode做题笔记99. 恢复二叉搜索树

给你二叉搜索树的根节点 root &#xff0c;该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下&#xff0c;恢复这棵树 。 思路一&#xff1a;模拟题意 int midOrder(struct TreeNode **pre, struct TreeNode **err1, struct TreeNode **err2, struct TreeNo…...

24 | 紧跟时代步伐:微服务模式下API测试要怎么做?

微服务架构&#xff08;Microservice Architecture&#xff09; 微服务是一种架构风格。在微服务架构下&#xff0c;一个大型复杂软件系统不再由一个单体组成&#xff0c;而是由一系列相互独立的微服务组成。其中&#xff0c;各个微服务运行在自己的进程中&#xff0c;开发和部…...

【论文阅读】POIROT:关联攻击行为与内核审计记录以寻找网络威胁(CCS-2019)

POIROT: Aligning Attack Behavior with Kernel Audit Records for Cyber Threat Hunting CCS-2019 伊利诺伊大学芝加哥分校、密歇根大学迪尔伯恩分校 Milajerdi S M, Eshete B, Gjomemo R, et al. Poirot: Aligning attack behavior with kernel audit records for cyber thre…...

K8S cluster with multi-masters on Azure VM

拓扑参考&#xff1a; 在 Azure VM 实例上部署 KubeSphere 基础模板 需要修改 IP 地址和 VM Image的可以在模板中修改。 {"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#","contentVersion": &q…...

初阶c语言:趣味扫雷游戏

目录 前言 制作菜单 构建游戏选择框架 实现游戏功能 模块化编程&#xff1a;查看前节三子棋的内容 初始化雷区 ​编辑 优化棋盘 随机埋入地雷 点击后的决策 实现此功能代码 game&#xff08;&#xff09;&#xff1b;的安排 前言 《扫雷》是一款大众类的益智小游戏&…...

JVM——内存模型

1.java内存模型 1.1 原子性 1.2 问题分析 这里与局部变量自增不同&#xff0c;局部变量调用iinc是在局部变量表槽位上进行自增。 静态变量是在操作数栈自增。 这里的主内存和工作内存时再JMM里的说法。 因为操作系统是时间片切换的多个线程轮流使用CPU. 1.3解决方法 JMM中…...

java八股文面试[JVM]——元空间

JAVA8为什么要增加元空间 为什么要移除永久代&#xff1f; 知识来源&#xff1a; 【2023年面试】JVM8为什么要增加元空间_哔哩哔哩_bilibili...