一种残膜回收机防缠绕挑膜装置的制 一种秧草收获机用电力驱动行走机构

一种Linux系统上动态链接库可视化依赖树的生成方法与流程

2023-01-06 03:28:19 来源:中国专利 TAG:
一种linux系统上动态链接库可视化依赖树的生成方法
技术领域
:1.本专利申请属于依赖树生成
技术领域
:,更具体地说,是涉及一种linux系统上动态链接库可视化依赖树的生成方法。
背景技术
::2.应用兼容性是国内外操作系统厂商重点攻克的难题之一,是影响应用生态的关键因素。红帽、欧拉等服务器操作系统通过包的依赖关系划分,给出了系统上一些核心组件的重要性定义。麒麟桌面操作系统在统型工作中,为了能全面准确的定义系统中依赖库与应用程序的影响关系,除了借鉴红帽等发行版的核心组件定义思想外,还从依赖库的被依赖层次、被引用计数、abi兼容率等多个维度去分析操作系统重要核心组件。3.本发明开发的工具就是统型依赖库工作中的一个重要参考维度,我们考虑应用程序的依赖关系通常包括编译依赖和运行时依赖,应用程序的兼容主要从api和abi的维度去进行分析。本发明开发了一套操作系统依赖库树形结构生成工具,可视化的标示出所有动态库的依赖层级关系与引用频次。4.考虑到需要解析的库文件数量很大,使用mmap将磁盘文件映射到虚拟内存,程序可以采用指针的方式读写操作内存,完成对于依赖库文件的解析操作,避免频繁的i/o操作。5.与本专利申请最接近的现有技术是:一种软件包依赖关系检测方法,专利号:cn114327473a。6.该技术指出,在软件安装过程中,常常会面临软件依赖的问题。通常情况下,安装时检测某版本软件依赖,会单独去检索这个版本的软件依赖包,如果还有依赖,就继续往下检索。当检索到没有依赖后,倒着把软件包进行安装,即可顺利完成所有软件和依赖的安装。这种做法存在一个无法解决的问题,即当往下检索时,可能会出现后面的软件包依赖前面的软件包的情况,从而形成死锁。7.软件包依赖分析的现有方法包括基于集合分析的方法、基于分层图分析的方法等,其中效果较好的分层图分析方法的大致思路为:针对指定操作系统构建分层图,针对用户给定的某个软件,在图中查找依赖关系,最后将依赖关系进行导出。8.该专利虽然也是分析操作系统中的依赖关系,但是它分析的维度是软件包,在生成的有向图中标示出包的依赖关系,无法计算动态库的被引用次数。这个专利接收输入是一组软件包,根据生成的有向关系依次安装各个软件包,与本发明的想要解决的问题场景不符。9.为了能全面准确的定义系统中依赖库与应用程序的影响关系,在统型工作中提供新的维度去分析操作系统重要核心组件。本发明开发了一套操作系统依赖库树形结构生成工具,可视化的标示出所有动态库的依赖层级关系与引用频次。技术实现要素:10.本发明需要解决的技术问题是提供一种linux系统上动态链接库可视化依赖树的生成方法,可以可视化地标示出所有动态库的依赖层级关系与引用频次,直观性更好。11.为了解决上述问题,本发明所采用的技术方案是:一种linux系统上动态链接库可视化依赖树的生成方法,包括如下步骤:s1、编写脚本程序,执行脚本程序中的generate_input函数,生成c程序的输入文件result.output,输入文件result.output存储有应用程序的依赖库合集;s2、将输入文件result.output输入二进制执行程序elf_parser进行分析,生成c程序的输出文件library.dot;s3、执行脚本程序中的handle_output函数,解析输出文件library.dot,从而给树状图加上各个依赖库的引用计数,生成可视化图像,最终得以画出依赖树结构图。12.本发明技术方案的进一步改进在于:步骤s1中,脚本程序为shell脚本程序。13.本发明技术方案的进一步改进在于:步骤s2中,二进制执行程序elf_parser执行如下分析:s21、解析并检测输入文件result.output合法后,将输入文件result.output中所有依赖库的库名、初始绝对路径libpath、当前层级level存入consumed队列;否则执行步骤s28;s22、循环解析consumed队列:遍历consumed队列中的内容,判断consumed队列是否为空,若consumed队列不为空,执行步骤s23,否则执行步骤s27;s23、当前依赖库的初始绝对路径libpath存在的情况下,加载该依赖库,并判断该依赖库是否为64位的elf文件,若是64位的elf文件,执行步骤s24,否则返回步骤s22;s24、解析elf文件中的dt_needed字段,dt_needed字段用以表示依赖库上声明的依赖项,在初始绝对路径libpath的基础上,找到这个依赖库在系统中的最终绝对路径newpath,将该依赖库的当前层级level的数值加一,表示依赖库加深了一个层次,层次越深表明依赖库越重要;并将该依赖库的最终绝对路径newpath与新的当前层级level一起存入consumed队列;同时记录该依赖库的被引用次数,将被引用次数加一,存入counthash哈希表;libpath和newpath都是变量名,libpath和newpath都是指绝对路径,只不过是名称不一样,实际操作中,先判断libpath是否存在,若libpath存在,newpath是在libpath存在情况下找到的最终绝对路径结果。14.s25、调取用于保存依赖库的层次信息的levelhash表,判断是否需要将初始绝对路径libpath和新的当前层级level插入levelhash表中,若需要,执行步骤s26,否则执行步骤s27;这里需要补充说明:levelhash表中保存的是层次信息,层次越深表明这个库越重要;counthash哈希保存的是对这个依赖库的引用计数,也就是被引用次数,两张表记录不同的信息。15.s26、将初始绝对路径libpath和新的当前层级level存入levelhash表,并保存.dot结构的文件(也就是将缓存中的数据写到输出文件library.dot予以保存),然后返回步骤s22;s27、遍历counthash哈希表,将库名与被引用次数写到输出文件count.record;s28、结束程序。16.本发明技术方案的进一步改进在于:步骤s23中,当前依赖库的绝对路径libpath存在,加载该依赖库,是指:调用mmap映射到内存空间以弹出consumed队列;判断该依赖库是否为64位的elf文件,是指:解析elf文件头结构e_ident[16]的数据,若e_ident[16]的第五个字节等于2,则该依赖库是64位的elf文件,反之则不是。[0017]本发明技术方案的进一步改进在于:步骤s24中,二进制执行程序elf_parser还可以解析单个依赖库。[0018]本发明技术方案的进一步改进在于:对于单个依赖库,通过-l参数添加一个elf文件(比如解析绝对路径)来解析单个依赖库。这里需要补充说明:-l参数只是为了解析单个库,跟s24的newpath类型其实是一样的,但不是一个内容。举例说明,如果这个程序加ꢀ‑l参数,就表示只解析一个库;如果这个程序后面接的是文件名,解析的就是文件中保存的所有依赖库的信息,算是单个库与多个库的不同解析方式,当然如果文件中只保存一个库的路径信息,其实效果跟ꢀ‑l参数加库名是一样的。[0019]本发明技术方案的进一步改进在于:步骤s25中,判断是否需要将初始绝对路径libpath和新的当前层级level插入levelhash表,是指:如果levelhash表中不存在依赖库的层级记录或者levelhash表中该依赖库保存的层级低于待插入的依赖库的层级level,则将初始绝对路径libpath和新的当前层级level存入levelhash表中,否则忽略这个待插入的依赖库。[0020]本发明技术方案的进一步改进在于:步骤s3中,执行脚本程序中的handle_output函数,通过去重、替换操作,将依赖库的引用计数加到.dot结构的文件中,最后利用dot工具生成树状图结构。[0021]本发明技术方案的进一步改进在于:去重为awk去重,替换为sed替换。[0022]由于采用了上述技术方案,本发明取得的有益效果是:该发明在操作系统统型依赖库中得以应用,可以绘画出操作系统出所有应用程序依赖库的层级关系,结合该可视化树以及引用关系记录文件,引用次数记录文件,引用层级记录文件等,为操作系统依赖库的统型提供了有效的参考依据。[0023]本专利特点如下:(1)shell脚本与c程序协同工作,创造性的将操作系统的依赖库关系生成dot格式文件,从而生成可视化的结构树。[0024](2)通过mmap映射到内存文件,glob机制与可执行文件elf库实现对系统中所有库的解析,以内存访问的形式解析elf格式信息,获取依赖库清单,避免了大量的i/o操作。[0025]当前的工具如readelf、libtree等,只能通过文本方式显示出某一个应用或者动态库的所有依赖关系,这种方式无法直观地看出依赖层次关系,而且得到的信息很有局限性。本发明则不然,根据输入参数的不同,本发明可以解析某一个库的依赖树,也可以绘画出操作系统中所有应用程序的依赖树,更加直观清晰。[0026]本发明提出的一种linux系统上动态链接库的可视化依赖树生成方法,通过程序解析elf文件,将依赖关系保存到dot格式文件中,并结合脚本的方式,将引用次数加到数据节点中,从而实现了可视化树形结构的生成。附图说明[0027]图1为本发明的方案框架图;图2为本发明生成的依赖结构图;图3为本发明的方案实施流程图;图4为本发明生成的操作系统中所有依赖树结构的局部图。具体实施方式[0028]下面结合实施例对本发明做进一步详细说明。[0029]首先介绍一下缩略语和关键术语定义。[0030]统型依赖库:操作系统为了引导外部生态建立,最大程度帮助应用程序提高兼容性,提出的对操作系统上依赖库的层次划分思想。最核心的一级库在操作系统主版本间接口保持稳定,二级库在操作系统主版本内接口保持稳定。应用程序通过对自身依赖库的分析与统型组件分级对照,可以明确应用程序在操作系统上的兼容性。[0031]elf:目标文件常常按照特定格式来组织,在linux下,它是elf格式(executablelinkableformat,可执行可链接格式),可执行二进制文件、目标代码文件、共享库文件和coredump文件都属于elf文件。[0032]静态库与动态库:linux操作系统上的库有两种:静态库(.a)和动态库(.so)。所谓静态、动态是指链接。在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行时被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。[0033]虚拟内存:一种性能优越的内存管理技术。它为程序提供了看似巨大的内存空间,使得一个较大的程序能够运行在较小的内存空间中;同时又为每个进程提供了独立的虚拟地址空间,既简化了内存管理,也保护了每个进程的地址空间。[0034]mmap:本质是一种进程虚拟内存的映射方法,可以将一个文件、一段物理内存或者其它对象映射到进程的虚拟内存地址空间。实现这样的映射关系后,进程就可以采用指针的方式来读写操作这一段内存,进而完成对文件的操作。[0035]引用频次:通过本次发明程序,计算操作系统上动态库被其他库的直接与间接引用次数。[0036]引用层次:通过本次发明程序,计算各个动态库在操作系统上被其他库依赖的最深层次。[0037]abi兼容率:通过abi-dumper等开源工具分析某个库包在不同版本的接口、参数等信息,生成的兼容率百分比。[0038]绝对路径:绝对路径就是文件的真正存在的路径,是指从硬盘的根目录开始,进行一级级目录指向文件。比如ꢀ“/usr/lib/x86_64-linux-gnu/libc.so.6”;或者/home/xunli/test/desktop-qt像这样的从/开始,没有.或者..这样的路径,就是绝对路径。本发明的申请文件里面强调绝对路径,是为了强调使用方法,让用户勿使用相对路径。[0039]本发明中涉及到初始绝对路径、最终绝对路径以及解析绝对路径,分别是绝对路径的三种表现形式,其中初始绝对路径是基础,在初始绝对路径存在的基础上,找到最终绝result.output。[0053]2.重要部件是解析依赖库并生成依赖关系层次的c程序,该程序的ꢀ‑l参数是单个库的测试验证场景,上面已经给过说明,不再赘述。下面重点描述接收文件名作为传入参数的场景:2.1elf_parser程序检测输入文件result.output是否合法,合法后,遍历输入文件result.output中所有依赖库,如果确实为elf格式的文件,将输入文件result.output中所有依赖库保存到队列consumed中,consumed中包括各依赖库的库名、初始绝对路径libpath、当前层级level等,作为初始化第一层级的依赖库,接下来会执行步骤2.2中循环解析consumed队列的过程,直到consumed队列清空,循环终止,结束循环,执行2.7;2.2循环解析consumed队列:遍历consumed队列中的内容,如果consumed队列不为空,进入步骤2.3-步骤2.6中的循环。[0054]2.3调用函数parse_lib_link解析这些输入文件result.output。[0055](1)函数parse_lib_link接受两个参数,第一个参数是依赖库在系统中的初始绝对路径libpath,第二个参数是当前层级level。[0056](2)首先判断当前依赖库的初始绝对路径libpath是否存在,如果初始绝对路径libpath存在,加载该依赖库,调用mmap映射到内存空间以弹出consumed队列,解析elf头结构e_ident[16]的数据,以判断该依赖库是否为64位的elf文件,如果是有效的64位elf文件,进入下一步解析,否则的话跳过这个依赖库回到循环开头,继续解析文件中后面的依赖库。[0057]简单介绍一下elf头结构:typedefstruct{ꢀꢀꢀꢀunsignedchare_ident[ei_nident];ꢀꢀꢀꢀuint16_tꢀꢀꢀꢀꢀꢀe_type;ꢀꢀꢀꢀuint16_tꢀꢀꢀꢀꢀꢀe_machine;ꢀꢀꢀꢀuint32_tꢀꢀꢀꢀꢀꢀe_version;ꢀꢀꢀꢀelf64_addrꢀꢀꢀꢀe_entry;ꢀꢀꢀꢀelf64_offꢀꢀꢀꢀꢀe_phoff;ꢀꢀꢀꢀelf64_offꢀꢀꢀꢀꢀe_shoff;ꢀꢀꢀꢀuint32_tꢀꢀꢀꢀꢀꢀe_flags;ꢀꢀꢀꢀuint16_tꢀꢀꢀꢀꢀꢀe_ehsize;ꢀꢀꢀꢀuint16_tꢀꢀꢀꢀꢀꢀe_phentsize;ꢀꢀꢀꢀuint16_tꢀꢀꢀꢀꢀꢀe_phnum;ꢀꢀꢀꢀuint16_tꢀꢀꢀꢀꢀꢀe_shentsize;ꢀꢀꢀꢀuint16_tꢀꢀꢀꢀꢀꢀe_shnum;ꢀꢀꢀꢀuint16_tꢀꢀꢀꢀꢀꢀe_shstrndx;}elf64_ehdr;结构体最开头是16个字节的e_ident,其中包含用以表示elf文件的字符,以及其他一些与机器无关的信息。本发明主要解析前五个字节,开头的4个字节值固定不变,为0x7f和elf三个字符。第五个字节表示当前这个elf文件是32位字节还是64位字节,本发明只处理64位字节的格式,如果检测到e_ident[16]的第五个字节不等于2,也就是e_ident[4]不等于2,自动退出程序。若e_ident[4]等于2,则证明该依赖库是64位的elf文件,继续执行下面的步骤。[0058]这个数据结构还包含了许多其他信息,能告诉人们节头表(sectionheadertable)在文件中什么位置。通过节头表可知,e_shoff表示sectionheadertable的偏移量,e_shstrndx表示sectionheaderstringtableindex,节头字符串表索引,有这些信息就能读取节头表了。[0059]2.4本发明的重点是找到elf文件依赖的依赖库的名称,也就是节头表中section名称为.dynamic和.dynstr的节点,如果d_tag为dt_needed,表明就是我们需要找的动态依赖库。不过这时候获取的还只是简单的名称,比如libxcb.so.1,为了能进一步检测这些依赖库所依赖的库,我们需要根据名称来找到它在系统中的最终绝对路径newpath,也就是ꢀ“/usr/lib/x86_64-linux-gnu/libxcb.so.1”这样的信息。本发明通过glob模式匹配机制,找到该依赖库在系统中的最终绝对路径newpath,将当前层级level数值加一,表示依赖库加深了一个层次,后续需要进一步解析的。并将依赖库的最终绝对路径newpath与新的当前层级level一起加入consumed队列,等待后续解析。[0060]需要说明的是,libpath和newpath都是绝对路径的变量名,libpath和newpath都代表的是绝对路径,只不过是名称不一样,newpath是在libpath存在情况下找到的最终绝对路径的结果,所以需要先判断libpath是否存在。[0061]libpath比如:/usr/lib/x86_64-linux-gnu/。[0062]newpath比如:/lib/x86_64-linux-gnu/libgraphite2.so.3。[0063]这里需要结合上文的-l参数继续补充说明:-l参数是小写的数字l,不是字母i。这个-l参数只是为了解析单个库,跟上文的newpath类型其实是一样的,但不是一个内容。如果这个程序加ꢀ‑l,就表示只解析一个库;如果这个程序后面接的是文件名,解析的就是文件中保存的所有依赖库的信息,这样算是单个库与多个库的不同解析方式,当然如果文件中只保存一个库的路径信息,其实效果跟ꢀ‑l参数加库名是一样的。[0064]通过-l参数添加一个elf文件的解析绝对路径来解析单个依赖库,此处的解析绝对路径既不是libpath也不是newpath,而是本发明可以接受的一个参数,这个参数是指向一个可执行程序或者动态库的用于解析的绝对路径,可以称之为解析绝对路径。[0065]还需要记录正在解析的这个库的被引用次数,解析到这个库,就说明有其他库依赖到它,所以将该库的被引用次数(也可以叫引用计数)加一,存入counthash哈希表。[0066]2.5同时调取用于保存依赖库的层次信息的levelhash表,判断是否需要将初始绝对路径libpath和新的当前层级level的信息插入levelhash表,如果levelhash表中不存在库或者levelhash表中保存的层级低于待插入的层级level,将初始绝对路径libpath和新的当前层级level存入levelhash表,这是为了避免引用层级最深的记录被冲掉。[0067]对于每个依赖库,只保留层级最深的记录。在程序初始运行时,所有依赖库的初始层级都为1,所以如果不存在初始层级的记录就直接插入;如果发现这个记录已经存在了,就需要对比两个依赖库的level大小,如果levelhash表中该依赖库的层级低于待插入的依赖库的层级level,则将初始绝对路径libpath和新的当前层级level存入levelhash表中,否则忽略这个待插入的依赖库。[0068]补充说明:levelhash表中保存的是层次信息,层次越深表明这个库越重要;counthash哈希表保存的是对这个依赖库的引用计数,也就是被引用次数,两张表levelhash表、counthash哈希表记录的信息不同。[0069]2.6在插入levelhash表时,说明当前依赖库的调用层级在当前时间节点是最深的,所以这里的predepend是最靠近根部的依赖,此时生成ꢀ“lib1”ꢀ‑》ꢀ“lib2”ꢀ格式的记录,保存到缓存中,待写入dot格式文件,完成将缓存中的数据写到输出文件library.dot予以保存这一步骤。[0070]完成一个依赖库的操作,接下来继续下一个依赖库,直到consumed队列为空,结束循环。[0071]2.7遍历counthash哈希表,将库名与被引用次数(也可以叫引用计数)写到文件count.record,并将缓存中的数据写到文件library.dot。[0072]2.8至此,程序结束。[0073]在步骤s3中,脚本处理解析程序的输出文件,通过awk去重、sed替换等操作,将依赖库的被引用次数(也叫引用计数)加到.dot文件中,最后利用dot工具生成树状图结构。[0074]本发明的实施场景是在操作系统统型依赖库中得以应用,由于整个系统生成树结构很庞大,截取其中一个片段,如图4。图4是生成的操作系统中所有依赖树结构的局部图,表现的是samba这一模块依赖树以及对应各个库的引用频次。graphviz是一个画图软件,其中的dot工具可以用于绘制流程图。dot工具可以根据dot语言代码生成gif、png、svg、pdf、postscript格式的图片文件。结合该可视化树以及引用关系记录文件,引用次数记录文件,引用层级记录文件等,为操作系统依赖库的统型提供了有效的参考依据。[0075]本发明的优势是:1.结合shell脚本,c程序解析与dot工具实现可视化依赖树结构的生成。[0076]2.通过mmap映射、glob机制与elf库实现对系统中所有库的解析。[0077]因此,本发明通过程序解析elf文件,将依赖层次关系保存到dot格式文件中,并结合脚本的方式,将引用次数加到数据节点中,从而实现了可视化树形结构的生成。当前第1页12当前第1页12
再多了解一些

本文用于创业者技术爱好者查询,仅供学习研究,如用于商业用途,请联系技术所有人。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

相关文献