系统补丁制作

  1. 补丁的用途
  1. 紧急现网bug 修复
  2. 测试问题验证
  3. 定制化功能

等等

2,补丁实现机制:  

1、系统启动 

系统启动时需要加载系统软件和配置文件。如果指定了下次启动的补丁文件,还需加载补丁文件。系统启动的场景一般如下 :

对设备指定升级后的补丁文件。

可以在设备升级的同时指定之前未安装过的补丁文件,当设备升级完成后,补丁也会立即生效。

2、补丁文件 

补丁是一种与设备系统软件兼容的软件,用于解决设备系统软件少量且急需解决的问题。在设备的运行过程中,有时需要对设备系统软件进行一些适应性和排错性的修改,如改正系统中存在的缺陷、优化某功能以适应业务需求等。

补丁通常以补丁文件的形式发布,一个补丁文件可能包含一个或多个补丁,不同的补丁具有不同的功能。当补丁文件被用户从存储器加载到内存补丁区中时,补丁文件中的补丁将被分配一个在此内存补丁区中唯一的单元序号,用于标志、管理和操作各补丁。

5、补丁分类 

根据补丁生效对业务运行的影响,补丁分成热补丁和冷补丁:

1、热补丁HP(Hot Patch):

补丁生效不中断业务,不影响业务运行,同时可以降低设备升级成本,避免升级风险。

2、冷补丁CP(Cold Patch):

要使补丁生效需要复位单板或重启设备,影响业务的运行。

根据补丁间的依赖关系,补丁可分为增量型补丁和非增量型补丁。

3、增量型补丁:

是指对在其前面的补丁有依赖性的补丁。一个新的补丁文件必须包含前一个补丁文件中的所有补丁信息。用户可以在不卸载原补丁文件的情况下直接安装新的补丁文件。

4、非增量型补丁:

只允许当前系统安装一个补丁文件。如果用户安装完补丁之后希望重新安装另一个补丁文件,则需要先卸载当前的补丁文件,然后再重新安装并运行新的补丁文件。

6、补丁状态 

每个补丁都有自身的状态,只有在用户命令行的干预下才能发生切换。补丁状态详细信息如下:

1、空闲状态(Idle)

此时,补丁文件存储在设备的存储器中,但文件中的补丁还没有被加载到内存补丁区中。当用户将补丁从存储器中加载到内存补丁区后,补丁的状态将被设置为去激活。

2、去激活状态(Deactive)

当补丁被加载到内存补丁区中或激活的补丁被停止运行时,补丁就处于去激活状态。

用户可以对去激活状态的补丁进行以下两种操作:

卸载此补丁,使补丁从内存补丁区中被删除。临时运行此补丁,使补丁的状态变为激活状态。

3、激活状态(Active)

当补丁被存储在内存补丁区中,且被临时运行时,补丁就处于激活状态。当单板被复位后,此单板上在复位前处于激活状态的补丁仍然恢复为激活状态。只有当整机复位后,复位前处于激活状态的补丁将会处于去激活状态。

用户可以对激活状态的补丁进行以下3种操作:

卸载此补丁,使补丁从内存补丁区中被删除。停止运行此补丁,使补丁的状态变为去激活状态。永久运行此补丁,使补丁的状态变为运行状态。

4、运行状态(Running)

当补丁被存储在内存补丁区中,且被永久运行时,补丁就处于运行状态。当单板或整机被复位后,在复位前处于运行状态的补丁将保持运行状态。

用户可以卸载处于运行状态的补丁,使补丁从内存补丁区中被删除。

         

7、补丁安装 

为设备安装补丁也是设备升级的一种方式。补丁安装方式有以下两种:

一般均采用不中断业务的方式,在设备运行过程中直接加载运行补丁,这也是热补丁的优势。

另外一种方式是指定系统下次启动的补丁文件,这种方式需要设备重启之后补丁才能生效。一般用于设备升级的同时安装补丁文件。

 

3,操作系统内核热补丁原理:

Kpatch基于ftrace实现内核函数的替换,类似于ftrace的动态探测点。利用mcount机制,在内核编译时在每个函数入口保留数个字节,然后在打补丁时将“被替换函数”入口保留的字节替换为跳转指令,跳转到Kpatch的相关流程中,最终进入“新函数”的执行流程,实现函数级别的执行流程在线替换。具体而言如下图:

 

       

 

4,Linux 补丁模块加载机制

 

5,VxWorks 补丁模块加载机制

使用动态加载目标模块的方式有很多好处,比如可以在不破坏原来的环境下增加调试定位功能,相当于给系统打“补丁”,不需要编译原来的代码(甚至可以不用原来的代码)而只需要关注正在调试的代码,这样能减少编译时间和减少映像的加载量。

  实现目标模块的动态加载有很多种方法,如在主机环境的界面上通过在目标模块上单击鼠标右键,选择“Download 文件名”;也可以通过wShell和GDB命令行窗口实现。本文通过tshell下使用ld()、loadModule()、loadModuleAt()中一个函数来实现,当然在代码中也可以自如地调用它们。

  ld命令是由用户接口子程序库usrLib提供的一个加载命令。使用ld的前提是在config.h中定义INCLUDE_LOADER。这样,在usrRoot()函数中就会自动调用加载模块初始化函数moduleLibInit();同时,根据CPU类型,自动决定目标模块的格式。如果CPU是MIPS、PPC、ARM、I80X86、COLDFIRE、SIMSPARCSOLARIS、SH等,加载的目标模块格式是elf类型,就会调用loadElfInit();如果CPU是I960、AM29XXX等,加载的目标模块的格式则是coff类型,就会调用loadCoffInit()函数。

  在ARM和PPC下,Tornado编译器生成的.o或.out都是elf类型,打开目标文件都会看到文件头有ELF(45,4C,46)标记。这时可以通过ftp工具把它加载到文件系统(如使用copy命令加载到RAM盘)中,再调用ld()或loadModule()函数加载到内存中运行。

  ld的函数原型是:MODULE_ID ld( int syms, BOOL noAbort, char *name )。参数syms决定目标文件的符号怎么处理:0,添加全局符号到系统符号表中;1,添加全局和局部符号到系统符号表中;-1,符号不添加到系统符号表中。一般选1,便于在shell下使用其中的符号。参数noAbort表明是否可以忽略加载期间出现的错误,为TRUE则忽略,FALSE则不忽略。name则为加载的文件名,包含文件路径。注意:ld是一条shell命令,也就是它是为在shell下调用而设计的一个函数,所以尽量不要用在代码内部,因为在之后的vxworks版本中直接调用ld可能会不支持。

  loadModule的函数原型是:MODULE_ID loadModule( int fd, int loadFlag )。fd为文件描述符号,需要先打开文件获取fd;参数loadFlag含义有LOAD_NO_SYMBOLS(2)、LOAD_LOCAL_SYMBOLS(4)、LOAD_GLOBAL_SYMBOLS(8)、LOAD_ALL_SYMBOLS(0xC)三种。

  假如已经将需要加载的文件demo.o放到ram盘中,则加载到内存中的方式有以下几种:

(1)-> ld(1,0,”/tffs0/demo.o”)

(2)-> ld </tffs0/demo.o

(3)-> fd = open(“/tffs0/demo.o”,O_RDONLY);

  -> loadModule(fd,0xC);

  ->close(fd);

加载函数返回的是MODULE_ID,这是该加载模块的标识,使用卸载unldByModuleId时可以模块ID。查看加载模块的具体信息的函数是moduleShow()。

  对于某些应用,使用ld或loadModule会出现以下错误:

Relocation value does not fit in 24 bits.

ld error: error loading file (errno = 0x3d0001).

这个问题主要在内存空间大于32M,当往目标机上downloading编译好的模块时出现。

原因:

  VxWorks和GNU/Wind River(diab)compiler要遵循EABI(Embedded Application Binary Interface),这是PowerPC架构的一个标准。这个标准对函数的调用是branching而不是jumping,而branching在 PowerPC架构下面是限制在32M以内的。(The PowerPC relative branch instruction is limited to jumps between +/- 32MB (24 bits = +/- 4M instructions, 4 bytes per instruction = +/- 32MB) of the current instruction. If an instruction cannot be resolved within a 24 bit range, it will print out the error above.)

一般来说,如果通过主机往目标机download,是不会出现这个问题的,因为这个时候的目标文件(比如.out文件)是download到了 WDB POOL里面,而WDB POOL是紧挨着VxWorks映像的,所以只要WDB POOL有足够大的空间就不会出现上述问题。

 而通过目标机download(比如tshell)时,目标文件是download到系统内存池的最后,这个时候如果你的内存大于32M,就会出现上述问题。

  为了规避这个问题,可以使用长跳转来完成函数的调用。可以通过在C/C++ compiler下加入编译选项解决。对于GNU,该选项是-mlongcall;对于diab,该选项是-Xcode-absolute-far

  当然也可以使用loadModuleAt()解决这个问题,将目标模块加载到指定地址,使所需要的函数在跳转地址以内。其原型是:MODULE_ID loadModuleAt( int fd, int loadFlag, void **ppText, void **ppData, void **ppBss)。ppText、ppData、ppBss分别是加载后的text段、data段和bss段所指向的地址。假如加载demo.o到1M空间处(保证这个空间没有被占用):

-> fd = open(“/tffs0/demo.o”,O_RDONLY);

-> pText = 0x100000; pData = pBss = 0xffffffff; /* (LD_NO_ADDRESS) */

-> loadModuleAt( fd, 8, &pText, &pData, &pBss);close(fd);

  加载完成后,在shell下就可以执行最新的目标文件中的函数了。如果函数以前有的,按照最后加载的函数为准。可见,加载的目标模块都经过重定位、符号解析和添加的过程。

  如果目标模块中使用的全局变量或函数在本模块和以前的程序中都没有定义,则加载时会出现类似undefined symbol的错误。

  有时候从主机上下载的目标模块中的函数符号不会出现在目标机的shell中,反过来也一样,目标机的shell中生成的符号对主机wShell也不可见。出现这种情况的主要原因是目标机和主机的符号没有同步化,需要在编译映像时定义INCLUDE_SYM_TBL_SYNC.

6,实现细节

一,设备端补丁生效

第一种方案:

  1. kpatch 基于ftrace 实现内核函数的替换,类似于ftrace 的动态探测点,利用mcount 机制,在内核编译时在每个函数入口保留数个字节
  2. ftrace : function trace . 最早主要用于记录内核函数运行轨迹,随桌功能的逐渐增加, 演变成了一个跟踪框架。 
  3. 当内核CONFIG_FUNCTION_TRACER 打开时,编译时会增加-pg 编译选项
  4. gcc 4.6 新增加了-pg -m fentry支持, 这样可以在函数的最开始插入一条调用fentry 的指令
  5. 补丁去除时,自动代码区全部恢复为空指令 nop
  6.  

第二种方案:

  1. 使用传统方式,保存要打补丁函数的入口指令(一般为链表),改为跳转指令,添转到新函数入口
  2. 补丁去除时,从链表获取旧的函数的入口指令恢复

二 ,主机侧补丁制作:

  1.  头文件管理
  2.  补丁代码编写,拷贝代码到补丁制作文件夹
  3.  补丁源文件中增加补丁的构造函数,析构函数 用于模块 初始化和卸载

 (可以完成任务创建,资源初始化等工作)

  1.  编译补丁代码,生成操作系统可加载的文件
  2.  打包加头补丁文件 ,携带版本,大小 ,crc校验,描述等信息

三, 配套版本补丁的管理:

补丁文件只能在指定的大包版本范围上生效。

 

四, 补丁命令行

  1. 设置下次启动生效的补丁文件
  2. 动态生效热补丁文件
  3. 显示补丁信息
  4. 卸载补丁

五, 补丁缺陷

  1. 数据结构,全局数据
  2. 函数参数
  3. 硬件初始化函数

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一款不错的补丁制作工具 [+] 支持补丁模式:   - 文件偏移。   - 虚拟地址(VA)。   - 相对虚拟地址(RVA)。   [+] 支持32位 和 64位的 PE 文件(EXE,DLL)。   [+] 支持多文件偏移补丁。   [+] 支持多文件 S&R 补丁。   [+] 支持高级 S&R 补丁。   [+] 支持 Windows 检查。   [+] 支持附加文件(文件安装程序)。   [+] 支持注册表补丁。   [+] 支持修补后恢复原始文件日期和时间。   [+] 支持文件大小、CRC32、MD5 哈希值检查。   [+] 支持滚动文字与透明边缘。   [+] 支持 XM、V2M、MOD、IT、S3M、MTM、UMX、MID、SID、SPC、YM、FTC、FLC、SQT、PT1、PT2、PT3、PSG、PSC、PSM、YM、GTR、STP 和 ASC 模块。   [+] 支持 PNG、JPG、BMP 皮肤(SKN)。   [+] 支持大多数的字体,包括:TTF、FON、OTF、WOFF、FNT。   [+] 支持 Windows 光标和动态光标(CUR、ANI)。   [+] 支持 Windows 图标(ICO)。   [+] 支持注册表补丁中的占位符。   [+] 支持保存/加载项目。   [+] 支持目标文件自动检测(从文件路径或注册表)。   [+] 支持 UPX 或外部打包器与命令。   [+] 支持 NFO(补丁/加载器需要 NFO 运行)。   [+] 全功能皮肤生成器。   [+] 皮肤转换器。   加载器选项:   [+] 支持 32 位和 64 位的加载器。   [+] 支持特定 RVA 补丁(多字节)。   [+] 支持搜索和替换(多字节)。   [+] 注册表补丁。   [+] 支持特定路径目标自动检测(使用宏)。   从特定注册表项。   [+] 支持修补加载的 DLL 模块。   [+] 支持修补现有进程。   [+] 支持文件检查(CRC32、文件大小和 MD5)。   [+] 添加设置调试权限。   [+] 添加等待第一个窗口。   [+] 支持静默加载器。   [+] 定时加载器延迟(毫秒)和超时(秒)选项。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值