这篇文章会包含很多项目的源码阅读, 覆盖 elf 的解析, elf 的加载, elf 的链接, 一次说清楚. 并换一种风格, 只在代码关键地方做注释. 并不会直接总结一个 elf 包含了哪些信息, 然后去哪找云云, 只是纯粹的源码阅读的记录, 看看在实际生产中 elf 如何被使用的, 必要的地方做一些总结和提示, 仅仅如此, 这点您要做好心理准备.
所有注释, 总结, 补充说明都是我改过, 读过的, 放心食用.
编译完能跳转了, 但是还是有红线, 不理会.
这个我也写了, 实现的很乱, 各种历史的沉淀, 不好读, 就删了, 感兴趣可以自己看看, glibc/elf/rtld.c 中的 _dl_start 是入口函数.
编译也很快, 但是有红线, 推荐看网页版: 5faK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6W2L8r3W2^5K9i4u0Q4x3X3g2T1L8$3!0@1L8r3W2F1i4K6u0W2j5$3!0E0i4K6u0r3k6$3I4A6j5X3y4Q4x3V1k6Y4L8r3W2T1j5#2)9J5k6o6u0Q4x3X3f1K6x3W2)9J5c8Y4y4G2N6i4u0U0k6b7`.`.
不想编译 AOSP, 直接看网页版: c9dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7#2)9J5k6h3q4F1k6s2u0G2K9h3c8Q4x3X3g2U0L8$3#2Q4x3V1k6S2L8X3c8J5L8$3W2V1i4K6u0r3M7r3I4S2N6r3k6G2M7X3#2Q4x3V1k6K6N6i4m8W2M7Y4m8J5L8$3A6W2j5%4c8Q4x3V1k6Q4x3V1u0Q4x3V1k6S2L8X3c8J5L8$3W2V1i4K6u0V1L8r3q4@1k6i4y4@1i4K6u0V1M7X3g2D9k6h3q4K6k6g2)9K6b7h3u0A6L8$3&6A6j5#2)9J5c8W2)9J5b7H3`.`. 个人观点" 代码比 glibc 中的好读一万倍, 代码写的非常好, 看着很舒服.

elf 的解析 实现, 大而全, 很好读. 作为开胃菜, 让我们从这里开始.
找到 main 函数:
前边就是在处理输入的参数, 然后调用 process_file 解析, 传入的参数 argv[optind++] 是一个个文件名, 跟进去:
主要就是在根据魔数识别文件类型, 分发给对应处理函数, 我们继续跟入 process_object, 看看如何处理可执行文件的:
这是是核心"地图", 顺着这个函数我们可以找到任何一个想要的功能, 虽然代码排版很奇怪, 但逻辑很明了, 从上大小一点点解析, 好了, 接下来我们看看这些函数了, 他们会非常多.
其中一些工具函数(byte_get_little_endian, byte_put_little_endian 等), 我们不再看, 大致流程就是根据前 16 字节确定大小端, 32 位还是 64 位, 然后用已有结构体读取文件头, 下面贴一下 Elf32_External_Ehdr, Elf64_External_Ehdr, 也就是程序头的结构体:
保留了英文注释, 更原汁原味.
这个真是再熟悉不过了.
接着看看 get_32bit_section_headers, get_64bit_section_headers:
这一段就是根据之前读取的 ELF 文件头的记录的节头表偏移(e_shoff), 单个节头项大小(e_shentsize), 节头项总数(e_shnum)填充 filedata 的section_headers 字段, 节头表类似书的目录, 它记录了 ELF 文件中所有节(如代码段, 数据段, 符号表, 字符串表等)的关键信息(位置, 大小, 类型, 属性等), 后续解析文件内容时, 通过节头表就能快速定位到各个节的具体位置.
贴一下 Elf32_External_Shdr Elf64_External_Shdr, 节头表项:
依旧原汁原味.
将文件头的信息进行打印, 值得注意的是:
该来的还是来了, 一个非常长的函数
节头表中记录了一个个节以及他们对应的数据, 主要用于链接和调试, 告诉链接器如何把不同文件的节组合起来, 以及告诉调试器代码和数据在文件中的具体位置.
整体看下来就是对节头表的校验和打印后, 将信息存入 filedata 中, 值得一说的是, 每一个节头表项都有一个名字, 这个名字记录的是偏移, 在上边说的 e_shstrndx 中对应的 .shstrtab 节的字符串池中做偏移, 查找字符串.
其中调用了 get_elf_symbols, 解析符号表, 我们也来看看.
get_32bit_elf_symbols get_64bit_elf_symbols:
总结一下就是将符号表和扩展表的符号信息提取出来然后返回.
值得一提的是, 扩展表(.symtab_shndx 节)与符号表(.symtab 节), .symtab_shndx 节是 .symtab 节的辅助补充表, 核心作用是解决符号表中 节索引字段位数不足 的问题, ELF 符号表中每个符号都有 st_shndx 字段, 用于存储该符号所属的节索引, 当 st_shndx 溢出时就需要 .symtab_shndx 节来补充存储"超长节索引". 符号表与扩展表的关联通过节头的 sh_link 字段绑定, 扩展表的 sh_link 字段会存储其关联的符号表在节头表中的索引.
Elf32_External_Sym, Elf64_External_Sym, 符号表项结构体:
依旧贴出.
程序头表记录了一个个段, 他们描述了如何装载到内存中, 比如可执行代码段, 只读数据段, 可读写数据段等, 主要用于加载和运行, 告诉操作系统的加载器应该把文件的哪些部分映射到内存的哪个地址, 以及这些部分在内存中的访问权限.
解析和校验程序头表保存到 filedata 中, 都在代码中了, 我干了(狗头).
不管前面的校验直接看 get_32bit_program_headers get_64bit_program_headers:
朴实无华, 接着看一下 Elf32_External_Phdr Elf64_External_Phdr:
依旧贴出.
readelf 就到这吧, 如果全部记笔记要写很长, 删了很多, 整体读代码的方式大概就是这样, readelf.c 是一个非常全的 elf 解析.
总结一下读代码的流程: 首先跟着 process_object 找到你需要的功能对应的函数, 然后跟进去开读, 先把握整体, 在关心局部, 先 ai 注释, 在人工精读, 最后用自己的话总结一下. readelf 的代码整体看下来是非常好读, 质朴的 c 代码, 没有多少让人看不懂的工程化部分, 点赞. 好了开胃菜到此为止.
没有时间在为没读完 readelf 哀悼, 接下来映入眼帘的是 elf 的加载, 在 linux 系统中在运行一个 elf 时如何加载可执行文件或者 .so 文件
搞清楚这个函数就知道 linux 怎么加载 elf 的了.

总结一下核心就是 检查和加载, 只用到 ELF 文件头, 程序头表的 PT_LOAD 段, 读取要执行的 ELF 文件, 然后通过 ELF 头找到程序头表, 然后将 PT_LOAD 段加载到内存, 再移交控制权到其入口(有动态链接器, 会先进入动态链接器代码). 核心思想就这么点, 不过细节却有很多, 下面通过几个点讲一下:
首先看一下入参 struct linux_binprm:
可以看到这个结构体中包含了很多结构体, 不再一一贴出, 总结一下就是记录新程序的种种信息, 内存, 文件对象, 路径, 参数...
这段代码要摘出来单独说一下:
如果是动态链接 ELF, 这段的计算流程大概是这样(一个例子):
BSS 段专门用来存放未初始化的全局变量和静态变量, 它在程序加载时由操作系统自动清零. 他们存在于"缝隙"之中:
举个例子:
再来看一下加载动态链接器这个函数
可以看到这个就像是简化版的 load_elf_binary, 没有那么多需要处理的额外情况.
elf 的加载 大致就这样, 可以看到没什么神秘的地方, 尽管在读这段代码之前, 我一直觉得它很神秘, 还记得在 load_elf_binary 中我们将程序入口设置在了哪吗, 没错, 动态链接器, 如果一个 ELF 有动态链接器的话, 会先执行动态链接器的代码, 接下来我们看看动态链接器的实现. let's go.


不同的架构有不同的入口, 对应一段简短的汇编

在 bionic/linker/arch/arm64/begin.S:
搜索 __linker_init 找到 bionic/linker/linker_main.cpp:
代码虽然简短, 但事却不少, 初始化 TCB, 计算基地址, 重定位自身...我们调重点看.
通过程序头表中的 PT_PHDR 段计算链接器基地址(linker_addr)和加载偏移(load_bias):
获取程序头表中的动态段, 解析重定位符号, 我们分别看看三个处理函数.
RELR 格式的重定位有两种模式: 单一项 / 位图项, 单一项不用说, 对单个地址重定位, 位图项是用来将相近的一段基址重定位, 以上一个单一项的偏移为基地址, 然后用当前取出来的值作为位图, 比特位为 0 位代表不需要重定位, 为 1 代表需要重定位.
可以看到, 逻辑写的非常清晰, 好代码, 我们在看看 apply_relr_reloc:
还记得 load_bias, 在上边计算的: load_bias = 程序头表实际内存地址 - 程序头表的虚拟地址(p_vaddr), 也就是地址的内存偏移, 在 RELR 重定位中得到的值 offset 是预计的虚拟地址, 就像 p_vaddr, 需要加上 load_bias 后才是真实内存地址, 然后将这个地址存的值在加上 load_bias 完成重定位.
这里要讲一下 IFUNC 机制, Indirect Function, 即间接函数. 运行时动态选择函数实现, 也就是添加了一个中间层, 为兼容性和优化创造了条件.
回到 __linker_init 接着往下看, 来到了 prelink_image 函数
整体看下来, 主要是就是在遍历解析动态段的信息, 先找到动态段位置, 然后遍历, 保存信息, 然后在做一些校验.
额外说明 ARM64 MTE: MTE 通过给内存地址和指针添加 "标签", 并在内存访问时验证标签匹配性, 实现对非法内存访问的实时检测, 将物理内存按 16 字节划分, 每个 16 字节块分配一个 5 位的 "内存标签", 64 位虚拟地址的高 8 位(bit 56-63)中预留 5 位作为 "指针标签", 用于存储对应内存块的标签值.
还有哈希表, 这个也要介绍一下, 传统哈希表(DT_HASH)和 GNU 哈希表(DT_GNU_HASH)都是用于"根据符号名快速找到对应的符号地址"这一问题, 当程序调用外部函数或者访问全局变量时, 需要通过符号名在符号表中找到对应的内存地址, 哈希表的作用就是将符号名映射为哈希值, 通过哈希表快速定位符号在符号表中的位置, 避免线性遍历符号表.
回到 __linker_init 接着往下看, 来到了 link_image 函数
这个只是一个包装方法, 实际是调用 relocate 方法处理, 跟入 relocate:
总结一下就是根据重定位项不同的类型做重定位处理, 计算重定位值写会目标地址, 与上边的 apply_relr_reloc 中的处理逻辑其实很类似.
到此完成了链接器的重定位.
回到主线, 再看 __linker_init_post_relocation
可以看到做了很多的初始化, 感兴趣可以自己看一下, 我们跟入 linker_main, 看后续如何处理目标程序,
加载并链接目标可执行文件, 算是最核心的部分, 也是最后一部分, 坐稳发车.
读下来和动态链接器的最大的区别就是是否加载依赖库是吧, 剩下的重定位逻辑基本一致, 初始化也差不多, 我们重点分析一下加载依赖库部分.
把大象装进冰箱分为哪几步?
前边的几步好说, 但是 Step 5-7 工作机制要举个例子讲一下.
这就是库重定位, 链接的逻辑.
回过头, 我们在看一下是如何加载库到内存的.
通过名称判断当前命名空间及其链接的命名空间中是否已加载该库, 如果未加载就调用 load_library 加载, 如果已经加载就复用, 总结来说就是这样.
再看 load_library
解析要加载库的 ELF 文件, 做一些校验, 得到它的 soinfo, 然后将它依赖库加入加载任务列表. 至于怎么解析的 ELF, 这里就不再看了, 已经读过太多遍了.
到此为止, 旅途结束.
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.301.tar.xz
tar xvf linux-5.9.6.tar.xz
sudo apt install -y llvm clang clang++ lld git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison
bear -- make CC=clang CXX=clang++ LLVM=1 defconfig -j$(nproc)
bear -- make CC=clang CXX=clang++ LLVM=1 -j$(nproc)
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.301.tar.xz
tar xvf linux-5.9.6.tar.xz
sudo apt install -y llvm clang clang++ lld git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison
bear -- make CC=clang CXX=clang++ LLVM=1 defconfig -j$(nproc)
bear -- make CC=clang CXX=clang++ LLVM=1 -j$(nproc)
git clone git://sourceware.org/git/binutils-gdb.git
cd ~/binutils-gdb
sudo apt install -y build-essential flex bison texinfo libncurses5-dev python3-dev
mkdir build && cd build
../configure CC=clang CXX=clang++ --disable-gdb --disable-werror
bear -- make -j$(nproc)
git clone git://sourceware.org/git/binutils-gdb.git
cd ~/binutils-gdb
sudo apt install -y build-essential flex bison texinfo libncurses5-dev python3-dev
mkdir build && cd build
../configure CC=clang CXX=clang++ --disable-gdb --disable-werror
bear -- make -j$(nproc)
注释
int
main (int argc, char ** argv)
{
int err;
#ifdef HAVE_LC_MESSAGES
setlocale (LC_MESSAGES, "");
#endif
setlocale (LC_CTYPE, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
expandargv (&argc, &argv);
parse_args (& cmdline, argc, argv);
if (optind < (argc - 1))
show_name = true;
else if (optind >= argc)
{
do_checks = true;
warn (_("Nothing to do.\n"));
usage (stderr);
}
err = false;
while (optind < argc)
if (! process_file (argv[optind++]))
err = true;
free (cmdline.dump_sects);
free (dump_ctf_symtab_name);
free (dump_ctf_strtab_name);
free (dump_ctf_parent_name);
return err ? EXIT_FAILURE : EXIT_SUCCESS;
}
注释
int
main (int argc, char ** argv)
{
int err;
#ifdef HAVE_LC_MESSAGES
setlocale (LC_MESSAGES, "");
#endif
setlocale (LC_CTYPE, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
expandargv (&argc, &argv);
parse_args (& cmdline, argc, argv);
if (optind < (argc - 1))
show_name = true;
else if (optind >= argc)
{
do_checks = true;
warn (_("Nothing to do.\n"));
usage (stderr);
}
err = false;
while (optind < argc)
if (! process_file (argv[optind++]))
err = true;
free (cmdline.dump_sects);
free (dump_ctf_symtab_name);
free (dump_ctf_strtab_name);
free (dump_ctf_parent_name);
return err ? EXIT_FAILURE : EXIT_SUCCESS;
}
static bool
process_file (char * file_name)
{
Filedata * filedata = NULL;
struct stat statbuf;
char armag[SARMAG];
bool ret = true;
if (stat (file_name, &statbuf) < 0)
{
if (errno == ENOENT)
error (_("'%s': No such file\n"), file_name);
else
error (_("Could not locate '%s'. System error message: %s\n"),
file_name, strerror (errno));
return false;
}
if (! S_ISREG (statbuf.st_mode))
{
error (_("'%s' is not an ordinary file\n"), file_name);
return false;
}
filedata = calloc (1, sizeof * filedata);
if (filedata == NULL)
{
error (_("Out of memory allocating file data structure\n"));
return false;
}
filedata->file_name = file_name;
filedata->handle = fopen (file_name, "rb");
if (filedata->handle == NULL)
{
error (_("Input file '%s' is not readable.\n"), file_name);
free (filedata);
return false;
}
if (fread (armag, SARMAG, 1, filedata->handle) != 1)
{
error (_("%s: Failed to read file's magic number\n"), file_name);
fclose (filedata->handle);
free (filedata);
return false;
}
filedata->file_size = statbuf.st_size;
filedata->is_separate = false;
if (memcmp (armag, ARMAG, SARMAG) == 0)
{
if (! process_archive (filedata, false))
ret = false;
}
else if (memcmp (armag, ARMAGT, SARMAG) == 0)
{
if ( ! process_archive (filedata, true))
ret = false;
}
else
{
if (do_archive_index && !check_all)
error (_("File %s is not an archive so its index cannot be displayed.\n"),
file_name);
rewind (filedata->handle);
filedata->archive_file_size = filedata->archive_file_offset = 0;
if (! process_object (filedata))
ret = false;
}
close_debug_file (filedata);
free (ba_cache.strtab);
ba_cache.strtab = NULL;
free (ba_cache.symtab);
ba_cache.symtab = NULL;
ba_cache.filedata = NULL;
return ret;
}
static bool
process_file (char * file_name)
{
Filedata * filedata = NULL;
struct stat statbuf;
char armag[SARMAG];
bool ret = true;
if (stat (file_name, &statbuf) < 0)
{
if (errno == ENOENT)
error (_("'%s': No such file\n"), file_name);
else
error (_("Could not locate '%s'. System error message: %s\n"),
file_name, strerror (errno));
return false;
}
if (! S_ISREG (statbuf.st_mode))
{
error (_("'%s' is not an ordinary file\n"), file_name);
return false;
}
filedata = calloc (1, sizeof * filedata);
if (filedata == NULL)
{
error (_("Out of memory allocating file data structure\n"));
return false;
}
filedata->file_name = file_name;
filedata->handle = fopen (file_name, "rb");
if (filedata->handle == NULL)
{
error (_("Input file '%s' is not readable.\n"), file_name);
free (filedata);
return false;
}
if (fread (armag, SARMAG, 1, filedata->handle) != 1)
{
error (_("%s: Failed to read file's magic number\n"), file_name);
fclose (filedata->handle);
free (filedata);
return false;
}
filedata->file_size = statbuf.st_size;
filedata->is_separate = false;
if (memcmp (armag, ARMAG, SARMAG) == 0)
{
if (! process_archive (filedata, false))
ret = false;
}
else if (memcmp (armag, ARMAGT, SARMAG) == 0)
{
if ( ! process_archive (filedata, true))
ret = false;
}
else
{
if (do_archive_index && !check_all)
error (_("File %s is not an archive so its index cannot be displayed.\n"),
file_name);
rewind (filedata->handle);
filedata->archive_file_size = filedata->archive_file_offset = 0;
if (! process_object (filedata))
ret = false;
}
close_debug_file (filedata);
free (ba_cache.strtab);
ba_cache.strtab = NULL;
free (ba_cache.symtab);
ba_cache.symtab = NULL;
ba_cache.filedata = NULL;
return ret;
}
static bool
process_object (Filedata * filedata)
{
bool have_separate_files;
unsigned int i;
bool res;
if (! get_file_header (filedata))
{
error (_("%s: Failed to read file header\n"), filedata->file_name);
return false;
}
for (i = ARRAY_SIZE (filedata->version_info); i--;)
filedata->version_info[i] = 0;
for (i = ARRAY_SIZE (filedata->dynamic_info); i--;)
filedata->dynamic_info[i] = 0;
filedata->dynamic_info_DT_GNU_HASH = 0;
filedata->dynamic_info_DT_MIPS_XHASH = 0;
if (show_name)
printf (_("\nFile: %s\n"), filedata->file_name);
initialise_dump_sects (filedata);
get_section_headers (filedata, true);
if (! process_file_header (filedata))
{
res = false;
goto out;
}
free (filedata->section_headers);
filedata->section_headers = NULL;
if (! process_section_headers (filedata))
{
do_unwind = do_version = do_dump = do_arch = false;
if (! do_using_dynamic)
do_syms = do_dyn_syms = do_reloc = false;
}
if (! process_section_groups (filedata))
do_unwind = false;
process_program_headers (filedata);
res = process_dynamic_section (filedata);
if (! process_relocs (filedata))
res = false;
if (! process_unwind (filedata))
res = false;
if (! process_symbol_table (filedata))
res = false;
if (! process_lto_symbol_tables (filedata))
res = false;
if (! process_syminfo (filedata))
res = false;
if (! process_version_sections (filedata))
res = false;
if (might_need_separate_debug_info (filedata))
have_separate_files = load_separate_debug_files (filedata, filedata->file_name);
else
have_separate_files = false;
if (! process_section_contents (filedata))
res = false;
if (! process_got_section_contents (filedata))
res = false;
if (have_separate_files)
{
separate_info * d;
for (d = first_separate_info; d != NULL; d = d->next)
{
initialise_dump_sects (d->handle);
if (process_links && ! process_file_header (d->handle))
res = false;
else if (! process_section_headers (d->handle))
res = false;
else if (! process_section_contents (d->handle))
res = false;
else if (process_links)
{
if (! process_section_groups (d->handle))
res = false;
process_program_headers (d->handle);
if (! process_dynamic_section (d->handle))
res = false;
if (! process_relocs (d->handle))
res = false;
if (! process_unwind (d->handle))
res = false;
if (! process_symbol_table (d->handle))
res = false;
if (! process_lto_symbol_tables (d->handle))
res = false;
if (! process_syminfo (d->handle))
res = false;
if (! process_version_sections (d->handle))
res = false;
if (! process_notes (d->handle))
res = false;
}
}
}
if (! process_notes (filedata))
res = false;
if (! process_gnu_liblist (filedata))
res = false;
if (! process_arch_specific (filedata))
res = false;
out:
free_filedata (filedata);
free_debug_memory ();
return res;
}
static bool
process_object (Filedata * filedata)
{
bool have_separate_files;
unsigned int i;
bool res;
if (! get_file_header (filedata))
{
error (_("%s: Failed to read file header\n"), filedata->file_name);
return false;
}
for (i = ARRAY_SIZE (filedata->version_info); i--;)
filedata->version_info[i] = 0;
for (i = ARRAY_SIZE (filedata->dynamic_info); i--;)
filedata->dynamic_info[i] = 0;
filedata->dynamic_info_DT_GNU_HASH = 0;
filedata->dynamic_info_DT_MIPS_XHASH = 0;
if (show_name)
printf (_("\nFile: %s\n"), filedata->file_name);
initialise_dump_sects (filedata);
get_section_headers (filedata, true);
if (! process_file_header (filedata))
{
res = false;
goto out;
}
free (filedata->section_headers);
filedata->section_headers = NULL;
if (! process_section_headers (filedata))
{
do_unwind = do_version = do_dump = do_arch = false;
if (! do_using_dynamic)
do_syms = do_dyn_syms = do_reloc = false;
}
if (! process_section_groups (filedata))
do_unwind = false;
process_program_headers (filedata);
res = process_dynamic_section (filedata);
if (! process_relocs (filedata))
res = false;
if (! process_unwind (filedata))
res = false;
if (! process_symbol_table (filedata))
res = false;
if (! process_lto_symbol_tables (filedata))
res = false;
if (! process_syminfo (filedata))
res = false;
if (! process_version_sections (filedata))
res = false;
if (might_need_separate_debug_info (filedata))
have_separate_files = load_separate_debug_files (filedata, filedata->file_name);
else
have_separate_files = false;
if (! process_section_contents (filedata))
res = false;
if (! process_got_section_contents (filedata))
res = false;
if (have_separate_files)
{
separate_info * d;
for (d = first_separate_info; d != NULL; d = d->next)
{
initialise_dump_sects (d->handle);
if (process_links && ! process_file_header (d->handle))
res = false;
else if (! process_section_headers (d->handle))
res = false;
else if (! process_section_contents (d->handle))
res = false;
else if (process_links)
{
if (! process_section_groups (d->handle))
res = false;
process_program_headers (d->handle);
if (! process_dynamic_section (d->handle))
res = false;
if (! process_relocs (d->handle))
res = false;
if (! process_unwind (d->handle))
res = false;
if (! process_symbol_table (d->handle))
res = false;
if (! process_lto_symbol_tables (d->handle))
res = false;
if (! process_syminfo (d->handle))
res = false;
if (! process_version_sections (d->handle))
res = false;
if (! process_notes (d->handle))
res = false;
}
}
}
if (! process_notes (filedata))
res = false;
if (! process_gnu_liblist (filedata))
res = false;
if (! process_arch_specific (filedata))
res = false;
out:
free_filedata (filedata);
free_debug_memory ();
return res;
}
static bool
get_file_header (Filedata * filedata)
{
if (fread (filedata->file_header.e_ident, EI_NIDENT, 1, filedata->handle) != 1)
return false;
switch (filedata->file_header.e_ident[EI_DATA])
{
default:
case ELFDATANONE:
case ELFDATA2LSB:
byte_get = byte_get_little_endian;
byte_put = byte_put_little_endian;
break;
case ELFDATA2MSB:
byte_get = byte_get_big_endian;
byte_put = byte_put_big_endian;
break;
}
is_32bit_elf = (filedata->file_header.e_ident[EI_CLASS] != ELFCLASS64);
if (is_32bit_elf)
{
Elf32_External_Ehdr ehdr32;
if (fread (ehdr32.e_type, sizeof (ehdr32) - EI_NIDENT, 1, filedata->handle) != 1)
return false;
filedata->file_header.e_type = BYTE_GET (ehdr32.e_type);
filedata->file_header.e_machine = BYTE_GET (ehdr32.e_machine);
filedata->file_header.e_version = BYTE_GET (ehdr32.e_version);
filedata->file_header.e_entry = BYTE_GET (ehdr32.e_entry);
filedata->file_header.e_phoff = BYTE_GET (ehdr32.e_phoff);
filedata->file_header.e_shoff = BYTE_GET (ehdr32.e_shoff);
filedata->file_header.e_flags = BYTE_GET (ehdr32.e_flags);
filedata->file_header.e_ehsize = BYTE_GET (ehdr32.e_ehsize);
filedata->file_header.e_phentsize = BYTE_GET (ehdr32.e_phentsize);
filedata->file_header.e_phnum = BYTE_GET (ehdr32.e_phnum);
filedata->file_header.e_shentsize = BYTE_GET (ehdr32.e_shentsize);
filedata->file_header.e_shnum = BYTE_GET (ehdr32.e_shnum);
filedata->file_header.e_shstrndx = BYTE_GET (ehdr32.e_shstrndx);
}
else
{
Elf64_External_Ehdr ehdr64;
if (fread (ehdr64.e_type, sizeof (ehdr64) - EI_NIDENT, 1, filedata->handle) != 1)
return false;
filedata->file_header.e_type = BYTE_GET (ehdr64.e_type);
filedata->file_header.e_machine = BYTE_GET (ehdr64.e_machine);
filedata->file_header.e_version = BYTE_GET (ehdr64.e_version);
filedata->file_header.e_entry = BYTE_GET (ehdr64.e_entry);
filedata->file_header.e_phoff = BYTE_GET (ehdr64.e_phoff);
filedata->file_header.e_shoff = BYTE_GET (ehdr64.e_shoff);
filedata->file_header.e_flags = BYTE_GET (ehdr64.e_flags);
filedata->file_header.e_ehsize = BYTE_GET (ehdr64.e_ehsize);
filedata->file_header.e_phentsize = BYTE_GET (ehdr64.e_phentsize);
filedata->file_header.e_phnum = BYTE_GET (ehdr64.e_phnum);
filedata->file_header.e_shentsize = BYTE_GET (ehdr64.e_shentsize);
filedata->file_header.e_shnum = BYTE_GET (ehdr64.e_shnum);
filedata->file_header.e_shstrndx = BYTE_GET (ehdr64.e_shstrndx);
}
return true;
}
static bool
get_file_header (Filedata * filedata)
{
if (fread (filedata->file_header.e_ident, EI_NIDENT, 1, filedata->handle) != 1)
return false;
switch (filedata->file_header.e_ident[EI_DATA])
{
default:
case ELFDATANONE:
case ELFDATA2LSB:
byte_get = byte_get_little_endian;
byte_put = byte_put_little_endian;
break;
case ELFDATA2MSB:
byte_get = byte_get_big_endian;
byte_put = byte_put_big_endian;
break;
}
is_32bit_elf = (filedata->file_header.e_ident[EI_CLASS] != ELFCLASS64);
if (is_32bit_elf)
{
Elf32_External_Ehdr ehdr32;
if (fread (ehdr32.e_type, sizeof (ehdr32) - EI_NIDENT, 1, filedata->handle) != 1)
return false;
filedata->file_header.e_type = BYTE_GET (ehdr32.e_type);
filedata->file_header.e_machine = BYTE_GET (ehdr32.e_machine);
filedata->file_header.e_version = BYTE_GET (ehdr32.e_version);
filedata->file_header.e_entry = BYTE_GET (ehdr32.e_entry);
filedata->file_header.e_phoff = BYTE_GET (ehdr32.e_phoff);
filedata->file_header.e_shoff = BYTE_GET (ehdr32.e_shoff);
filedata->file_header.e_flags = BYTE_GET (ehdr32.e_flags);
filedata->file_header.e_ehsize = BYTE_GET (ehdr32.e_ehsize);
filedata->file_header.e_phentsize = BYTE_GET (ehdr32.e_phentsize);
filedata->file_header.e_phnum = BYTE_GET (ehdr32.e_phnum);
filedata->file_header.e_shentsize = BYTE_GET (ehdr32.e_shentsize);
filedata->file_header.e_shnum = BYTE_GET (ehdr32.e_shnum);
filedata->file_header.e_shstrndx = BYTE_GET (ehdr32.e_shstrndx);
}
else
{
Elf64_External_Ehdr ehdr64;
if (fread (ehdr64.e_type, sizeof (ehdr64) - EI_NIDENT, 1, filedata->handle) != 1)
return false;
filedata->file_header.e_type = BYTE_GET (ehdr64.e_type);
filedata->file_header.e_machine = BYTE_GET (ehdr64.e_machine);
filedata->file_header.e_version = BYTE_GET (ehdr64.e_version);
filedata->file_header.e_entry = BYTE_GET (ehdr64.e_entry);
filedata->file_header.e_phoff = BYTE_GET (ehdr64.e_phoff);
filedata->file_header.e_shoff = BYTE_GET (ehdr64.e_shoff);
filedata->file_header.e_flags = BYTE_GET (ehdr64.e_flags);
filedata->file_header.e_ehsize = BYTE_GET (ehdr64.e_ehsize);
filedata->file_header.e_phentsize = BYTE_GET (ehdr64.e_phentsize);
filedata->file_header.e_phnum = BYTE_GET (ehdr64.e_phnum);
filedata->file_header.e_shentsize = BYTE_GET (ehdr64.e_shentsize);
filedata->file_header.e_shnum = BYTE_GET (ehdr64.e_shnum);
filedata->file_header.e_shstrndx = BYTE_GET (ehdr64.e_shstrndx);
}
return true;
}
typedef struct {
unsigned char e_ident[16];
unsigned char e_type[2];
unsigned char e_machine[2];
unsigned char e_version[4];
unsigned char e_entry[4];
unsigned char e_phoff[4];
unsigned char e_shoff[4];
unsigned char e_flags[4];
unsigned char e_ehsize[2];
unsigned char e_phentsize[2];
unsigned char e_phnum[2];
unsigned char e_shentsize[2];
unsigned char e_shnum[2];
unsigned char e_shstrndx[2];
} Elf32_External_Ehdr;
typedef struct {
unsigned char e_ident[16];
unsigned char e_type[2];
unsigned char e_machine[2];
unsigned char e_version[4];
unsigned char e_entry[8];
unsigned char e_phoff[8];
unsigned char e_shoff[8];
unsigned char e_flags[4];
unsigned char e_ehsize[2];
unsigned char e_phentsize[2];
unsigned char e_phnum[2];
unsigned char e_shentsize[2];
unsigned char e_shnum[2];
unsigned char e_shstrndx[2];
} Elf64_External_Ehdr;
typedef struct {
unsigned char e_ident[16];
unsigned char e_type[2];
unsigned char e_machine[2];
unsigned char e_version[4];
unsigned char e_entry[4];
unsigned char e_phoff[4];
unsigned char e_shoff[4];
unsigned char e_flags[4];
unsigned char e_ehsize[2];
unsigned char e_phentsize[2];
unsigned char e_phnum[2];
unsigned char e_shentsize[2];
unsigned char e_shnum[2];
unsigned char e_shstrndx[2];
} Elf32_External_Ehdr;
typedef struct {
unsigned char e_ident[16];
unsigned char e_type[2];
unsigned char e_machine[2];
unsigned char e_version[4];
unsigned char e_entry[8];
unsigned char e_phoff[8];
unsigned char e_shoff[8];
unsigned char e_flags[4];
unsigned char e_ehsize[2];
unsigned char e_phentsize[2];
unsigned char e_phnum[2];
unsigned char e_shentsize[2];
unsigned char e_shnum[2];
unsigned char e_shstrndx[2];
} Elf64_External_Ehdr;
static bool
get_section_headers (Filedata *filedata, bool probe)
{
if (filedata->section_headers != NULL)
return true;
if (is_32bit_elf)
return get_32bit_section_headers (filedata, probe);
else
return get_64bit_section_headers (filedata, probe);
}
static bool
get_section_headers (Filedata *filedata, bool probe)
{
if (filedata->section_headers != NULL)
return true;
if (is_32bit_elf)
return get_32bit_section_headers (filedata, probe);
else
return get_64bit_section_headers (filedata, probe);
}
static bool
get_32bit_section_headers (Filedata * filedata, bool probe)
{
Elf32_External_Shdr * shdrs;
Elf_Internal_Shdr * internal;
unsigned int i;
unsigned int size = filedata->file_header.e_shentsize;
unsigned int num = probe ? 1 : filedata->file_header.e_shnum;
if (size == 0 || num == 0)
return false;
if (filedata->file_header.e_shoff == 0)
return false;
if (size < sizeof * shdrs)
{
if (! probe)
error (_("The e_shentsize field in the ELF header is less than the size of an ELF section header\n"));
return false;
}
if (!probe && size > sizeof * shdrs)
warn (_("The e_shentsize field in the ELF header is larger than the size of an ELF section header\n"));
shdrs = (Elf32_External_Shdr *) get_data (NULL, filedata, filedata->file_header.e_shoff,
size, num,
probe ? NULL : _("section headers"));
if (shdrs == NULL)
return false;
filedata->section_headers = (Elf_Internal_Shdr *)
cmalloc (num, sizeof (Elf_Internal_Shdr));
if (filedata->section_headers == NULL)
{
if (!probe)
error (_("Out of memory reading %u section headers\n"), num);
free (shdrs);
return false;
}
for (i = 0, internal = filedata->section_headers;
i < num;
i++, internal++)
{
internal->sh_name = BYTE_GET (shdrs[i].sh_name);
internal->sh_type = BYTE_GET (shdrs[i].sh_type);
internal->sh_flags = BYTE_GET (shdrs[i].sh_flags);
internal->sh_addr = BYTE_GET (shdrs[i].sh_addr);
internal->sh_offset = BYTE_GET (shdrs[i].sh_offset);
internal->sh_size = BYTE_GET (shdrs[i].sh_size);
internal->sh_link = BYTE_GET (shdrs[i].sh_link);
internal->sh_info = BYTE_GET (shdrs[i].sh_info);
internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign);
internal->sh_entsize = BYTE_GET (shdrs[i].sh_entsize);
if (!probe && internal->sh_link > num)
warn (_("Section %u has an out of range sh_link value of %u\n"), i, internal->sh_link);
if (!probe && internal->sh_flags & SHF_INFO_LINK && internal->sh_info > num)
warn (_("Section %u has an out of range sh_info value of %u\n"), i, internal->sh_info);
}
free (shdrs);
return true;
}
static bool
get_64bit_section_headers (Filedata * filedata, bool probe)
{
Elf64_External_Shdr * shdrs;
Elf_Internal_Shdr * internal;
unsigned int i;
unsigned int size = filedata->file_header.e_shentsize;
unsigned int num = probe ? 1 : filedata->file_header.e_shnum;
if (size == 0 || num == 0)
return false;
if (filedata->file_header.e_shoff == 0)
return false;
if (size < sizeof * shdrs)
{
if (! probe)
error (_("The e_shentsize field in the ELF header is less than the size of an ELF section header\n"));
return false;
}
if (! probe && size > sizeof * shdrs)
warn (_("The e_shentsize field in the ELF header is larger than the size of an ELF section header\n"));
shdrs = (Elf64_External_Shdr *) get_data (NULL, filedata,
filedata->file_header.e_shoff,
size, num,
probe ? NULL : _("section headers"));
if (shdrs == NULL)
return false;
filedata->section_headers = (Elf_Internal_Shdr *)
cmalloc (num, sizeof (Elf_Internal_Shdr));
if (filedata->section_headers == NULL)
{
if (! probe)
error (_("Out of memory reading %u section headers\n"), num);
free (shdrs);
return false;
}
for (i = 0, internal = filedata->section_headers;
i < num;
i++, internal++)
{
internal->sh_name = BYTE_GET (shdrs[i].sh_name);
internal->sh_type = BYTE_GET (shdrs[i].sh_type);
internal->sh_flags = BYTE_GET (shdrs[i].sh_flags);
internal->sh_addr = BYTE_GET (shdrs[i].sh_addr);
internal->sh_size = BYTE_GET (shdrs[i].sh_size);
internal->sh_entsize = BYTE_GET (shdrs[i].sh_entsize);
internal->sh_link = BYTE_GET (shdrs[i].sh_link);
internal->sh_info = BYTE_GET (shdrs[i].sh_info);
internal->sh_offset = BYTE_GET (shdrs[i].sh_offset);
internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign);
if (!probe && internal->sh_link > num)
warn (_("Section %u has an out of range sh_link value of %u\n"), i, internal->sh_link);
if (!probe && internal->sh_flags & SHF_INFO_LINK && internal->sh_info > num)
warn (_("Section %u has an out of range sh_info value of %u\n"), i, internal->sh_info);
}
free (shdrs);
return true;
}
static bool
get_32bit_section_headers (Filedata * filedata, bool probe)
{
Elf32_External_Shdr * shdrs;
Elf_Internal_Shdr * internal;
unsigned int i;
unsigned int size = filedata->file_header.e_shentsize;
unsigned int num = probe ? 1 : filedata->file_header.e_shnum;
if (size == 0 || num == 0)
return false;
if (filedata->file_header.e_shoff == 0)
return false;
if (size < sizeof * shdrs)
{
if (! probe)
error (_("The e_shentsize field in the ELF header is less than the size of an ELF section header\n"));
return false;
}
if (!probe && size > sizeof * shdrs)
warn (_("The e_shentsize field in the ELF header is larger than the size of an ELF section header\n"));
shdrs = (Elf32_External_Shdr *) get_data (NULL, filedata, filedata->file_header.e_shoff,
size, num,
probe ? NULL : _("section headers"));
if (shdrs == NULL)
return false;
filedata->section_headers = (Elf_Internal_Shdr *)
cmalloc (num, sizeof (Elf_Internal_Shdr));
if (filedata->section_headers == NULL)
{
if (!probe)
error (_("Out of memory reading %u section headers\n"), num);
free (shdrs);
return false;
}
for (i = 0, internal = filedata->section_headers;
i < num;
i++, internal++)
{
internal->sh_name = BYTE_GET (shdrs[i].sh_name);
internal->sh_type = BYTE_GET (shdrs[i].sh_type);
internal->sh_flags = BYTE_GET (shdrs[i].sh_flags);
internal->sh_addr = BYTE_GET (shdrs[i].sh_addr);
internal->sh_offset = BYTE_GET (shdrs[i].sh_offset);
internal->sh_size = BYTE_GET (shdrs[i].sh_size);
internal->sh_link = BYTE_GET (shdrs[i].sh_link);
internal->sh_info = BYTE_GET (shdrs[i].sh_info);
internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign);
internal->sh_entsize = BYTE_GET (shdrs[i].sh_entsize);
if (!probe && internal->sh_link > num)
warn (_("Section %u has an out of range sh_link value of %u\n"), i, internal->sh_link);
if (!probe && internal->sh_flags & SHF_INFO_LINK && internal->sh_info > num)
warn (_("Section %u has an out of range sh_info value of %u\n"), i, internal->sh_info);
}
free (shdrs);
return true;
}
static bool
get_64bit_section_headers (Filedata * filedata, bool probe)
{
Elf64_External_Shdr * shdrs;
Elf_Internal_Shdr * internal;
unsigned int i;
unsigned int size = filedata->file_header.e_shentsize;
unsigned int num = probe ? 1 : filedata->file_header.e_shnum;
if (size == 0 || num == 0)
return false;
if (filedata->file_header.e_shoff == 0)
return false;
if (size < sizeof * shdrs)
{
if (! probe)
error (_("The e_shentsize field in the ELF header is less than the size of an ELF section header\n"));
return false;
}
if (! probe && size > sizeof * shdrs)
warn (_("The e_shentsize field in the ELF header is larger than the size of an ELF section header\n"));
shdrs = (Elf64_External_Shdr *) get_data (NULL, filedata,
filedata->file_header.e_shoff,
size, num,
probe ? NULL : _("section headers"));
if (shdrs == NULL)
return false;
filedata->section_headers = (Elf_Internal_Shdr *)
cmalloc (num, sizeof (Elf_Internal_Shdr));
if (filedata->section_headers == NULL)
{
if (! probe)
error (_("Out of memory reading %u section headers\n"), num);
free (shdrs);
return false;
}
for (i = 0, internal = filedata->section_headers;
i < num;
i++, internal++)
{
internal->sh_name = BYTE_GET (shdrs[i].sh_name);
internal->sh_type = BYTE_GET (shdrs[i].sh_type);
internal->sh_flags = BYTE_GET (shdrs[i].sh_flags);
internal->sh_addr = BYTE_GET (shdrs[i].sh_addr);
internal->sh_size = BYTE_GET (shdrs[i].sh_size);
internal->sh_entsize = BYTE_GET (shdrs[i].sh_entsize);
internal->sh_link = BYTE_GET (shdrs[i].sh_link);
internal->sh_info = BYTE_GET (shdrs[i].sh_info);
internal->sh_offset = BYTE_GET (shdrs[i].sh_offset);
internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign);
if (!probe && internal->sh_link > num)
warn (_("Section %u has an out of range sh_link value of %u\n"), i, internal->sh_link);
if (!probe && internal->sh_flags & SHF_INFO_LINK && internal->sh_info > num)
warn (_("Section %u has an out of range sh_info value of %u\n"), i, internal->sh_info);
}
free (shdrs);
return true;
}
typedef struct {
unsigned char sh_name[4];
unsigned char sh_type[4];
unsigned char sh_flags[4];
unsigned char sh_addr[4];
unsigned char sh_offset[4];
unsigned char sh_size[4];
unsigned char sh_link[4];
unsigned char sh_info[4];
unsigned char sh_addralign[4];
unsigned char sh_entsize[4];
} Elf32_External_Shdr;
typedef struct {
unsigned char sh_name[4];
unsigned char sh_type[4];
unsigned char sh_flags[8];
unsigned char sh_addr[8];
unsigned char sh_offset[8];
unsigned char sh_size[8];
unsigned char sh_link[4];
unsigned char sh_info[4];
unsigned char sh_addralign[8];
unsigned char sh_entsize[8];
} Elf64_External_Shdr;
typedef struct {
unsigned char sh_name[4];
unsigned char sh_type[4];
unsigned char sh_flags[4];
unsigned char sh_addr[4];
unsigned char sh_offset[4];
unsigned char sh_size[4];
unsigned char sh_link[4];
unsigned char sh_info[4];
unsigned char sh_addralign[4];
unsigned char sh_entsize[4];
} Elf32_External_Shdr;
typedef struct {
unsigned char sh_name[4];
unsigned char sh_type[4];
unsigned char sh_flags[8];
unsigned char sh_addr[8];
unsigned char sh_offset[8];
unsigned char sh_size[8];
unsigned char sh_link[4];
unsigned char sh_info[4];
unsigned char sh_addralign[8];
unsigned char sh_entsize[8];
} Elf64_External_Shdr;
static bool
process_file_header (Filedata * filedata)
{
Elf_Internal_Ehdr * header = & filedata->file_header;
if (! check_magic_number (filedata, header))
return false;
if (! filedata->is_separate)
init_dwarf_by_elf_machine_code (header->e_machine);
if (do_header)
{
unsigned i;
if (filedata->is_separate)
printf (_("ELF Header in linked file '%s':\n"),
printable_string (filedata->file_name, 0));
else
printf (_("ELF Header:\n"));
printf (_(" Magic: "));
for (i = 0; i < EI_NIDENT; i++)
printf ("%2.2x ", header->e_ident[i]);
printf ("\n");
printf (_(" Class: %s\n"),
get_elf_class (header->e_ident[EI_CLASS]));
printf (_(" Data: %s\n"),
get_data_encoding (header->e_ident[EI_DATA]));
printf (_(" Version: %d%s\n"),
header->e_ident[EI_VERSION],
(header->e_ident[EI_VERSION] == EV_CURRENT
? _(" (current)")
: (header->e_ident[EI_VERSION] != EV_NONE
? _(" <unknown>")
: "")));
printf (_(" OS/ABI: %s\n"),
get_osabi_name (filedata, header->e_ident[EI_OSABI]));
printf (_(" ABI Version: %d\n"),
header->e_ident[EI_ABIVERSION]);
printf (_(" Type: %s\n"),
get_file_type (filedata));
printf (_(" Machine: %s\n"),
get_machine_name (header->e_machine));
printf (_(" Version: 0x%lx\n"),
header->e_version);
printf (_(" Entry point address: "));
print_vma (header->e_entry, PREFIX_HEX);
printf (_("\n Start of program headers: "));
print_vma (header->e_phoff, DEC);
printf (_(" (bytes into file)\n Start of section headers: "));
print_vma (header->e_shoff, DEC);
printf (_(" (bytes into file)\n"));
printf (_(" Flags: 0x%lx%s\n"),
header->e_flags,
get_machine_flags (filedata, header->e_flags, header->e_machine));
printf (_(" Size of this header: %u (bytes)\n"),
header->e_ehsize);
printf (_(" Size of program headers: %u (bytes)\n"),
header->e_phentsize);
printf (_(" Number of program headers: %u"),
header->e_phnum);
if (filedata->section_headers != NULL
&& header->e_phnum == PN_XNUM
&& filedata->section_headers[0].sh_info != 0)
printf (" (%u)", filedata->section_headers[0].sh_info);
putc ('\n', stdout);
printf (_(" Size of section headers: %u (bytes)\n"),
header->e_shentsize);
printf (_(" Number of section headers: %u"),
header->e_shnum);
if (filedata->section_headers != NULL && header->e_shnum == SHN_UNDEF)
{
header->e_shnum = filedata->section_headers[0].sh_size;
printf (" (%u)", header->e_shnum);
}
putc ('\n', stdout);
printf (_(" Section header string table index: %u"),
header->e_shstrndx);
if (filedata->section_headers != NULL
&& header->e_shstrndx == (SHN_XINDEX & 0xffff))
{
header->e_shstrndx = filedata->section_headers[0].sh_link;
printf (" (%u)", header->e_shstrndx);
}
if (header->e_shstrndx != SHN_UNDEF
&& header->e_shstrndx >= header->e_shnum)
{
header->e_shstrndx = SHN_UNDEF;
printf (_(" <corrupt: out of range>"));
}
putc ('\n', stdout);
}
if (filedata->section_headers != NULL)
{
if (header->e_phnum == PN_XNUM
&& filedata->section_headers[0].sh_info != 0)
{
free (filedata->program_headers);
filedata->program_headers = NULL;
header->e_phnum = filedata->section_headers[0].sh_info;
}
if (header->e_shnum == SHN_UNDEF)
header->e_shnum = filedata->section_headers[0].sh_size;
if (header->e_shstrndx == (SHN_XINDEX & 0xffff))
header->e_shstrndx = filedata->section_headers[0].sh_link;
if (header->e_shstrndx >= header->e_shnum)
header->e_shstrndx = SHN_UNDEF;
}
return true;
}
static bool
process_file_header (Filedata * filedata)
{
Elf_Internal_Ehdr * header = & filedata->file_header;
if (! check_magic_number (filedata, header))
return false;
if (! filedata->is_separate)
init_dwarf_by_elf_machine_code (header->e_machine);
if (do_header)
{
unsigned i;
if (filedata->is_separate)
printf (_("ELF Header in linked file '%s':\n"),
printable_string (filedata->file_name, 0));
else
printf (_("ELF Header:\n"));
printf (_(" Magic: "));
for (i = 0; i < EI_NIDENT; i++)
printf ("%2.2x ", header->e_ident[i]);
printf ("\n");
printf (_(" Class: %s\n"),
get_elf_class (header->e_ident[EI_CLASS]));
printf (_(" Data: %s\n"),
get_data_encoding (header->e_ident[EI_DATA]));
printf (_(" Version: %d%s\n"),
header->e_ident[EI_VERSION],
(header->e_ident[EI_VERSION] == EV_CURRENT
? _(" (current)")
: (header->e_ident[EI_VERSION] != EV_NONE
? _(" <unknown>")
: "")));
printf (_(" OS/ABI: %s\n"),
get_osabi_name (filedata, header->e_ident[EI_OSABI]));
printf (_(" ABI Version: %d\n"),
header->e_ident[EI_ABIVERSION]);
printf (_(" Type: %s\n"),
get_file_type (filedata));
printf (_(" Machine: %s\n"),
get_machine_name (header->e_machine));
printf (_(" Version: 0x%lx\n"),
header->e_version);
printf (_(" Entry point address: "));
print_vma (header->e_entry, PREFIX_HEX);
printf (_("\n Start of program headers: "));
print_vma (header->e_phoff, DEC);
printf (_(" (bytes into file)\n Start of section headers: "));
print_vma (header->e_shoff, DEC);
printf (_(" (bytes into file)\n"));
printf (_(" Flags: 0x%lx%s\n"),
header->e_flags,
get_machine_flags (filedata, header->e_flags, header->e_machine));
printf (_(" Size of this header: %u (bytes)\n"),
header->e_ehsize);
printf (_(" Size of program headers: %u (bytes)\n"),
header->e_phentsize);
printf (_(" Number of program headers: %u"),
header->e_phnum);
if (filedata->section_headers != NULL
&& header->e_phnum == PN_XNUM
&& filedata->section_headers[0].sh_info != 0)
printf (" (%u)", filedata->section_headers[0].sh_info);
putc ('\n', stdout);
printf (_(" Size of section headers: %u (bytes)\n"),
header->e_shentsize);
printf (_(" Number of section headers: %u"),
header->e_shnum);
if (filedata->section_headers != NULL && header->e_shnum == SHN_UNDEF)
{
header->e_shnum = filedata->section_headers[0].sh_size;
printf (" (%u)", header->e_shnum);
}
putc ('\n', stdout);
printf (_(" Section header string table index: %u"),
header->e_shstrndx);
if (filedata->section_headers != NULL
&& header->e_shstrndx == (SHN_XINDEX & 0xffff))
{
header->e_shstrndx = filedata->section_headers[0].sh_link;
printf (" (%u)", header->e_shstrndx);
}
if (header->e_shstrndx != SHN_UNDEF
&& header->e_shstrndx >= header->e_shnum)
{
header->e_shstrndx = SHN_UNDEF;
printf (_(" <corrupt: out of range>"));
}
putc ('\n', stdout);
}
if (filedata->section_headers != NULL)
{
if (header->e_phnum == PN_XNUM
&& filedata->section_headers[0].sh_info != 0)
{
free (filedata->program_headers);
filedata->program_headers = NULL;
header->e_phnum = filedata->section_headers[0].sh_info;
}
if (header->e_shnum == SHN_UNDEF)
header->e_shnum = filedata->section_headers[0].sh_size;
if (header->e_shstrndx == (SHN_XINDEX & 0xffff))
header->e_shstrndx = filedata->section_headers[0].sh_link;
if (header->e_shstrndx >= header->e_shnum)
header->e_shstrndx = SHN_UNDEF;
}
return true;
}
static bool
process_section_headers (Filedata * filedata)
{
if (!get_section_headers (filedata, false))
return false;
if (filedata->string_table == NULL
&& filedata->file_header.e_shstrndx != SHN_UNDEF
&& filedata->file_header.e_shstrndx < filedata->file_header.e_shnum)
{
section = filedata->section_headers + filedata->file_header.e_shstrndx;
if (section->sh_size != 0)
{
filedata->string_table = (char *) get_data (NULL, filedata, section->sh_offset,
1, section->sh_size,
_("string table"));
filedata->string_table_length = filedata->string_table != NULL ? section->sh_size : 0;
}
}
eh_addr_size = is_32bit_elf ? 4 : 8;
switch (filedata->file_header.e_machine)
{
case EM_MIPS:
case EM_MIPS_RS3_LE:
if ((filedata->file_header.e_flags & EF_MIPS_ABI) == EF_MIPS_ABI_EABI64
&& find_section (filedata, ".gcc_compiled_long32") == NULL)
eh_addr_size = 8;
break;
case EM_H8_300:
case EM_H8_300H:
switch (filedata->file_header.e_flags & EF_H8_MACH)
{
case E_H8_MACH_H8300:
case E_H8_MACH_H8300HN:
case E_H8_MACH_H8300SN:
case E_H8_MACH_H8300SXN:
eh_addr_size = 2;
break;
case E_H8_MACH_H8300H:
case E_H8_MACH_H8300S:
case E_H8_MACH_H8300SX:
eh_addr_size = 4;
break;
}
break;
case EM_M32C_OLD:
case EM_M32C:
switch (filedata->file_header.e_flags & EF_M32C_CPU_MASK)
{
case EF_M32C_CPU_M16C:
eh_addr_size = 2;
break;
}
break;
}
#define CHECK_ENTSIZE_VALUES(section, i, size32, size64) \
do \
{ \
uint64_t expected_entsize = is_32bit_elf ? size32 : size64; \
if (section->sh_entsize != expected_entsize) \
{ \
error (_("Section %d has invalid sh_entsize of %" PRIx64 "\n"), \
i, section->sh_entsize); \
error (_("(Using the expected size of %" PRIx64 " for the rest of this dump)\n"), \
expected_entsize); \
section->sh_entsize = expected_entsize; \
} \
} \
while (0)
#define CHECK_ENTSIZE(section, i, type) \
CHECK_ENTSIZE_VALUES (section, i, sizeof (Elf32_External_##type), \
sizeof (Elf64_External_##type))
for (i = 0, section = filedata->section_headers;
i < filedata->file_header.e_shnum;
i++, section++)
{
const char *name = printable_section_name (filedata, section);
switch (section->sh_type)
{
case SHT_DYNSYM:
if (filedata->dynamic_symbols != NULL)
{
error (_("File contains multiple dynamic symbol tables\n"));
continue;
}
CHECK_ENTSIZE (section, i, Sym);
filedata->dynamic_symbols
= get_elf_symbols (filedata, section, &filedata->num_dynamic_syms);
filedata->dynamic_symtab_section = section;
break;
case SHT_STRTAB:
if (streq (name, ".dynstr"))
{
if (filedata->dynamic_strings != NULL)
{
error (_("File contains multiple dynamic string tables\n"));
continue;
}
filedata->dynamic_strings
= (char *) get_data (NULL, filedata, section->sh_offset,
1, section->sh_size, _("dynamic strings"));
filedata->dynamic_strings_length
= filedata->dynamic_strings == NULL ? 0 : section->sh_size;
filedata->dynamic_strtab_section = section;
}
break;
case SHT_SYMTAB_SHNDX:
{
elf_section_list * entry = xmalloc (sizeof * entry);
entry->hdr = section;
entry->next = filedata->symtab_shndx_list;
filedata->symtab_shndx_list = entry;
}
break;
case SHT_SYMTAB:
CHECK_ENTSIZE (section, i, Sym);
break;
case SHT_GROUP:
CHECK_ENTSIZE_VALUES (section, i, GRP_ENTRY_SIZE, GRP_ENTRY_SIZE);
break;
case SHT_REL:
CHECK_ENTSIZE (section, i, Rel);
if (do_checks && section->sh_size == 0)
warn (_("Section '%s': zero-sized relocation section\n"), name);
break;
case SHT_RELA:
CHECK_ENTSIZE (section, i, Rela);
if (do_checks && section->sh_size == 0)
warn (_("Section '%s': zero-sized relocation section\n"), name);
break;
case SHT_RELR:
CHECK_ENTSIZE (section, i, Relr);
break;
case SHT_NOTE:
case SHT_PROGBITS:
case SHT_GNU_SFRAME:
if (do_checks && section->sh_size == 0)
warn (_("Section '%s': has a size of zero - is this intended ?\n"), name);
break;
default:
break;
}
if ((do_debugging || do_debug_info || do_debug_abbrevs
|| do_debug_lines || do_debug_pubnames || do_debug_pubtypes
|| do_debug_aranges || do_debug_frames || do_debug_macinfo
|| do_debug_str || do_debug_str_offsets || do_debug_loc
|| do_debug_ranges
|| do_debug_addr || do_debug_cu_index || do_debug_links)
&& (startswith (name, ".debug_")
|| startswith (name, ".zdebug_")))
{
if (name[1] == 'z')
name += sizeof (".zdebug_") - 1;
else
name += sizeof (".debug_") - 1;
if (do_debugging
|| (do_debug_info && startswith (name, "info"))
|| (do_debug_info && startswith (name, "types"))
|| (do_debug_abbrevs && startswith (name, "abbrev"))
|| (do_debug_lines && strcmp (name, "line") == 0)
|| (do_debug_lines && startswith (name, "line."))
|| (do_debug_pubnames && startswith (name, "pubnames"))
|| (do_debug_pubtypes && startswith (name, "pubtypes"))
|| (do_debug_pubnames && startswith (name, "gnu_pubnames"))
|| (do_debug_pubtypes && startswith (name, "gnu_pubtypes"))
|| (do_debug_aranges && startswith (name, "aranges"))
|| (do_debug_ranges && startswith (name, "ranges"))
|| (do_debug_ranges && startswith (name, "rnglists"))
|| (do_debug_frames && startswith (name, "frame"))
|| (do_debug_macinfo && startswith (name, "macinfo"))
|| (do_debug_macinfo && startswith (name, "macro"))
|| (do_debug_str && startswith (name, "str"))
|| (do_debug_links && startswith (name, "sup"))
|| (do_debug_str_offsets && startswith (name, "str_offsets"))
|| (do_debug_loc && startswith (name, "loc"))
|| (do_debug_loc && startswith (name, "loclists"))
|| (do_debug_addr && startswith (name, "addr"))
|| (do_debug_cu_index && startswith (name, "cu_index"))
|| (do_debug_cu_index && startswith (name, "tu_index"))
)
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
}
else if ((do_debugging || do_debug_info)
&& startswith (name, ".gnu.linkonce.wi."))
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
else if (do_debug_frames && streq (name, ".eh_frame"))
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
else if (do_debug_frames && streq (name, ".eh_frame_hdr"))
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
else if (do_gdb_index && (streq (name, ".gdb_index")
|| streq (name, ".debug_names")))
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
else if ((do_debugging || do_trace_info || do_trace_abbrevs
|| do_trace_aranges)
&& startswith (name, ".trace_"))
{
name += sizeof (".trace_") - 1;
if (do_debugging
|| (do_trace_info && streq (name, "info"))
|| (do_trace_abbrevs && streq (name, "abbrev"))
|| (do_trace_aranges && streq (name, "aranges"))
)
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
}
else if ((do_debugging || do_debug_links)
&& (startswith (name, ".gnu_debuglink")
|| startswith (name, ".gnu_debugaltlink")))
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
}
if (! do_sections)
return true;
if (filedata->is_separate && ! process_links)
return true;
if (filedata->is_separate)
printf (_("\nSection Headers in linked file '%s':\n"),
printable_string (filedata->file_name, 0));
else if (filedata->file_header.e_shnum > 1)
printf (_("\nSection Headers:\n"));
else
printf (_("\nSection Header:\n"));
if (is_32bit_elf)
{
if (do_section_details)
{
printf (_(" [Nr] Name\n"));
printf (_(" Type Addr Off Size ES Lk Inf Al\n"));
}
else
printf
(_(" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n"));
}
else if (do_wide)
{
if (do_section_details)
{
printf (_(" [Nr] Name\n"));
printf (_(" Type Address Off Size ES Lk Inf Al\n"));
}
else
printf
(_(" [Nr] Name Type Address Off Size ES Flg Lk Inf Al\n"));
}
else
{
if (do_section_details)
{
printf (_(" [Nr] Name\n"));
printf (_(" Type Address Offset Link\n"));
printf (_(" Size EntSize Info Align\n"));
}
else
{
printf (_(" [Nr] Name Type Address Offset\n"));
printf (_(" Size EntSize Flags Link Info Align\n"));
}
}
if (do_section_details)
printf (_(" Flags\n"));
for (i = 0, section = filedata->section_headers;
i < filedata->file_header.e_shnum;
i++, section++)
{
switch (section->sh_type)
{
case SHT_REL:
case SHT_RELR:
case SHT_RELA:
if (section->sh_link == 0
&& (filedata->file_header.e_type == ET_EXEC
|| filedata->file_header.e_type == ET_DYN))
break;
case SHT_SYMTAB_SHNDX:
case SHT_GROUP:
case SHT_HASH:
case SHT_GNU_HASH:
case SHT_GNU_versym:
if (section->sh_link == 0
|| section->sh_link >= filedata->file_header.e_shnum
|| (filedata->section_headers[section->sh_link].sh_type != SHT_SYMTAB
&& filedata->section_headers[section->sh_link].sh_type != SHT_DYNSYM))
warn (_("[%2u]: Link field (%u) should index a symtab section.\n"),
i, section->sh_link);
break;
case SHT_DYNAMIC:
case SHT_SYMTAB:
case SHT_DYNSYM:
case SHT_GNU_verneed:
case SHT_GNU_verdef:
case SHT_GNU_LIBLIST:
if (section->sh_link == 0
|| section->sh_link >= filedata->file_header.e_shnum
|| filedata->section_headers[section->sh_link].sh_type != SHT_STRTAB)
warn (_("[%2u]: Link field (%u) should index a string section.\n"),
i, section->sh_link);
break;
case SHT_INIT_ARRAY:
case SHT_FINI_ARRAY:
case SHT_PREINIT_ARRAY:
if (section->sh_type < SHT_LOOS && section->sh_link != 0)
warn (_("[%2u]: Unexpected value (%u) in link field.\n"),
i, section->sh_link);
break;
default:
#if 0
#endif
break;
}
switch (section->sh_type)
{
case SHT_REL:
case SHT_RELA:
if (section->sh_info == 0
&& (filedata->file_header.e_type == ET_EXEC
|| filedata->file_header.e_type == ET_DYN))
break;
if (section->sh_info == 0
|| section->sh_info >= filedata->file_header.e_shnum
|| (filedata->section_headers[section->sh_info].sh_type != SHT_PROGBITS
&& filedata->section_headers[section->sh_info].sh_type != SHT_NOBITS
&& filedata->section_headers[section->sh_info].sh_type != SHT_NOTE
&& filedata->section_headers[section->sh_info].sh_type != SHT_INIT_ARRAY
&& filedata->section_headers[section->sh_info].sh_type != SHT_FINI_ARRAY
&& filedata->section_headers[section->sh_info].sh_type != SHT_PREINIT_ARRAY
&& filedata->section_headers[section->sh_info].sh_type < SHT_LOOS))
warn (_("[%2u]: Info field (%u) should index a relocatable section.\n"),
i, section->sh_info);
break;
case SHT_DYNAMIC:
case SHT_HASH:
case SHT_SYMTAB_SHNDX:
case SHT_INIT_ARRAY:
case SHT_FINI_ARRAY:
case SHT_PREINIT_ARRAY:
if (section->sh_info != 0)
warn (_("[%2u]: Unexpected value (%u) in info field.\n"),
i, section->sh_info);
break;
case SHT_GROUP:
case SHT_SYMTAB:
case SHT_DYNSYM:
break;
default:
if (section->sh_type == SHT_NOBITS)
;
else if (section->sh_flags & SHF_INFO_LINK)
{
if (section->sh_info < 1 || section->sh_info >= filedata->file_header.e_shnum)
warn (_("[%2u]: Expected link to another section in info field"), i);
}
else if (section->sh_type < SHT_LOOS
&& (section->sh_flags & SHF_GNU_MBIND) == 0
&& section->sh_info != 0)
warn (_("[%2u]: Unexpected value (%u) in info field.\n"),
i, section->sh_info);
break;
}
if (section->sh_size > filedata->file_size
&& section->sh_type != SHT_NOBITS
&& section->sh_type != SHT_NULL
&& section->sh_type < SHT_LOOS)
warn (_("Size of section %u is larger than the entire file!\n"), i);
printf (" [%2u] ", i);
if (do_section_details)
printf ("%s\n ", printable_section_name (filedata, section));
else
print_symbol_name (-17, printable_section_name (filedata, section));
printf (do_wide ? " %-15s " : " %-15.15s ",
get_section_type_name (filedata, section->sh_type));
if (is_32bit_elf)
{
const char * link_too_big = NULL;
print_vma (section->sh_addr, LONG_HEX);
printf ( " %6.6lx %6.6lx %2.2lx",
(unsigned long) section->sh_offset,
(unsigned long) section->sh_size,
(unsigned long) section->sh_entsize);
if (do_section_details)
fputs (" ", stdout);
else
printf (" %3s ", get_elf_section_flags (filedata, section->sh_flags));
if (section->sh_link >= filedata->file_header.e_shnum)
{
link_too_big = "";
switch (filedata->file_header.e_machine)
{
case EM_386:
case EM_IAMCU:
case EM_X86_64:
case EM_L1OM:
case EM_K1OM:
case EM_OLD_SPARCV9:
case EM_SPARC32PLUS:
case EM_SPARCV9:
case EM_SPARC:
if (section->sh_link == (SHN_BEFORE & 0xffff))
link_too_big = "BEFORE";
else if (section->sh_link == (SHN_AFTER & 0xffff))
link_too_big = "AFTER";
break;
default:
break;
}
}
if (do_section_details)
{
if (link_too_big != NULL && * link_too_big)
printf ("<%s> ", link_too_big);
else
printf ("%2u ", section->sh_link);
printf ("%3u %2lu\n", section->sh_info,
(unsigned long) section->sh_addralign);
}
else
printf ("%2u %3u %2lu\n",
section->sh_link,
section->sh_info,
(unsigned long) section->sh_addralign);
if (link_too_big && ! * link_too_big)
warn (_("section %u: sh_link value of %u is larger than the number of sections\n"),
i, section->sh_link);
}
else if (do_wide)
{
print_vma (section->sh_addr, LONG_HEX);
if ((long) section->sh_offset == section->sh_offset)
printf (" %6.6lx", (unsigned long) section->sh_offset);
else
{
putchar (' ');
print_vma (section->sh_offset, LONG_HEX);
}
if ((unsigned long) section->sh_size == section->sh_size)
printf (" %6.6lx", (unsigned long) section->sh_size);
else
{
putchar (' ');
print_vma (section->sh_size, LONG_HEX);
}
if ((unsigned long) section->sh_entsize == section->sh_entsize)
printf (" %2.2lx", (unsigned long) section->sh_entsize);
else
{
putchar (' ');
print_vma (section->sh_entsize, LONG_HEX);
}
if (do_section_details)
fputs (" ", stdout);
else
printf (" %3s ", get_elf_section_flags (filedata, section->sh_flags));
printf ("%2u %3u ", section->sh_link, section->sh_info);
if ((unsigned long) section->sh_addralign == section->sh_addralign)
printf ("%2lu\n", (unsigned long) section->sh_addralign);
else
{
print_vma (section->sh_addralign, DEC);
putchar ('\n');
}
}
else if (do_section_details)
{
putchar (' ');
print_vma (section->sh_addr, LONG_HEX);
if ((long) section->sh_offset == section->sh_offset)
printf (" %16.16lx", (unsigned long) section->sh_offset);
else
{
printf (" ");
print_vma (section->sh_offset, LONG_HEX);
}
printf (" %u\n ", section->sh_link);
print_vma (section->sh_size, LONG_HEX);
putchar (' ');
print_vma (section->sh_entsize, LONG_HEX);
printf (" %-16u %lu\n",
section->sh_info,
(unsigned long) section->sh_addralign);
}
else
{
putchar (' ');
print_vma (section->sh_addr, LONG_HEX);
if ((long) section->sh_offset == section->sh_offset)
printf (" %8.8lx", (unsigned long) section->sh_offset);
else
{
printf (" ");
print_vma (section->sh_offset, LONG_HEX);
}
printf ("\n ");
print_vma (section->sh_size, LONG_HEX);
printf (" ");
print_vma (section->sh_entsize, LONG_HEX);
printf (" %3s ", get_elf_section_flags (filedata, section->sh_flags));
printf (" %2u %3u %lu\n",
section->sh_link,
section->sh_info,
(unsigned long) section->sh_addralign);
}
if (do_section_details)
{
printf (" %s\n", get_elf_section_flags (filedata, section->sh_flags));
if ((section->sh_flags & SHF_COMPRESSED) != 0)
{
unsigned char buf[24];
assert (sizeof (buf) >= sizeof (Elf64_External_Chdr));
if (get_data (&buf, filedata, section->sh_offset, 1,
sizeof (buf), _("compression header")))
{
Elf_Internal_Chdr chdr;
if (get_compression_header (&chdr, buf, sizeof (buf)) == 0)
printf (_(" [<corrupt>]\n"));
else
{
if (chdr.ch_type == ch_compress_zlib)
printf (" ZLIB, ");
else if (chdr.ch_type == ch_compress_zstd)
printf (" ZSTD, ");
else
printf (_(" [<unknown>: 0x%x], "),
chdr.ch_type);
print_vma (chdr.ch_size, LONG_HEX);
printf (", %lu\n", (unsigned long) chdr.ch_addralign);
}
}
}
}
}
return true;
}
static bool
process_section_headers (Filedata * filedata)
{
if (!get_section_headers (filedata, false))
return false;
if (filedata->string_table == NULL
&& filedata->file_header.e_shstrndx != SHN_UNDEF
&& filedata->file_header.e_shstrndx < filedata->file_header.e_shnum)
{
section = filedata->section_headers + filedata->file_header.e_shstrndx;
if (section->sh_size != 0)
{
filedata->string_table = (char *) get_data (NULL, filedata, section->sh_offset,
1, section->sh_size,
_("string table"));
filedata->string_table_length = filedata->string_table != NULL ? section->sh_size : 0;
}
}
eh_addr_size = is_32bit_elf ? 4 : 8;
switch (filedata->file_header.e_machine)
{
case EM_MIPS:
case EM_MIPS_RS3_LE:
if ((filedata->file_header.e_flags & EF_MIPS_ABI) == EF_MIPS_ABI_EABI64
&& find_section (filedata, ".gcc_compiled_long32") == NULL)
eh_addr_size = 8;
break;
case EM_H8_300:
case EM_H8_300H:
switch (filedata->file_header.e_flags & EF_H8_MACH)
{
case E_H8_MACH_H8300:
case E_H8_MACH_H8300HN:
case E_H8_MACH_H8300SN:
case E_H8_MACH_H8300SXN:
eh_addr_size = 2;
break;
case E_H8_MACH_H8300H:
case E_H8_MACH_H8300S:
case E_H8_MACH_H8300SX:
eh_addr_size = 4;
break;
}
break;
case EM_M32C_OLD:
case EM_M32C:
switch (filedata->file_header.e_flags & EF_M32C_CPU_MASK)
{
case EF_M32C_CPU_M16C:
eh_addr_size = 2;
break;
}
break;
}
#define CHECK_ENTSIZE_VALUES(section, i, size32, size64) \
do \
{ \
uint64_t expected_entsize = is_32bit_elf ? size32 : size64; \
if (section->sh_entsize != expected_entsize) \
{ \
error (_("Section %d has invalid sh_entsize of %" PRIx64 "\n"), \
i, section->sh_entsize); \
error (_("(Using the expected size of %" PRIx64 " for the rest of this dump)\n"), \
expected_entsize); \
section->sh_entsize = expected_entsize; \
} \
} \
while (0)
#define CHECK_ENTSIZE(section, i, type) \
CHECK_ENTSIZE_VALUES (section, i, sizeof (Elf32_External_##type), \
sizeof (Elf64_External_##type))
for (i = 0, section = filedata->section_headers;
i < filedata->file_header.e_shnum;
i++, section++)
{
const char *name = printable_section_name (filedata, section);
switch (section->sh_type)
{
case SHT_DYNSYM:
if (filedata->dynamic_symbols != NULL)
{
error (_("File contains multiple dynamic symbol tables\n"));
continue;
}
CHECK_ENTSIZE (section, i, Sym);
filedata->dynamic_symbols
= get_elf_symbols (filedata, section, &filedata->num_dynamic_syms);
filedata->dynamic_symtab_section = section;
break;
case SHT_STRTAB:
if (streq (name, ".dynstr"))
{
if (filedata->dynamic_strings != NULL)
{
error (_("File contains multiple dynamic string tables\n"));
continue;
}
filedata->dynamic_strings
= (char *) get_data (NULL, filedata, section->sh_offset,
1, section->sh_size, _("dynamic strings"));
filedata->dynamic_strings_length
= filedata->dynamic_strings == NULL ? 0 : section->sh_size;
filedata->dynamic_strtab_section = section;
}
break;
case SHT_SYMTAB_SHNDX:
{
elf_section_list * entry = xmalloc (sizeof * entry);
entry->hdr = section;
entry->next = filedata->symtab_shndx_list;
filedata->symtab_shndx_list = entry;
}
break;
case SHT_SYMTAB:
CHECK_ENTSIZE (section, i, Sym);
break;
case SHT_GROUP:
CHECK_ENTSIZE_VALUES (section, i, GRP_ENTRY_SIZE, GRP_ENTRY_SIZE);
break;
case SHT_REL:
CHECK_ENTSIZE (section, i, Rel);
if (do_checks && section->sh_size == 0)
warn (_("Section '%s': zero-sized relocation section\n"), name);
break;
case SHT_RELA:
CHECK_ENTSIZE (section, i, Rela);
if (do_checks && section->sh_size == 0)
warn (_("Section '%s': zero-sized relocation section\n"), name);
break;
case SHT_RELR:
CHECK_ENTSIZE (section, i, Relr);
break;
case SHT_NOTE:
case SHT_PROGBITS:
case SHT_GNU_SFRAME:
if (do_checks && section->sh_size == 0)
warn (_("Section '%s': has a size of zero - is this intended ?\n"), name);
break;
default:
break;
}
if ((do_debugging || do_debug_info || do_debug_abbrevs
|| do_debug_lines || do_debug_pubnames || do_debug_pubtypes
|| do_debug_aranges || do_debug_frames || do_debug_macinfo
|| do_debug_str || do_debug_str_offsets || do_debug_loc
|| do_debug_ranges
|| do_debug_addr || do_debug_cu_index || do_debug_links)
&& (startswith (name, ".debug_")
|| startswith (name, ".zdebug_")))
{
if (name[1] == 'z')
name += sizeof (".zdebug_") - 1;
else
name += sizeof (".debug_") - 1;
if (do_debugging
|| (do_debug_info && startswith (name, "info"))
|| (do_debug_info && startswith (name, "types"))
|| (do_debug_abbrevs && startswith (name, "abbrev"))
|| (do_debug_lines && strcmp (name, "line") == 0)
|| (do_debug_lines && startswith (name, "line."))
|| (do_debug_pubnames && startswith (name, "pubnames"))
|| (do_debug_pubtypes && startswith (name, "pubtypes"))
|| (do_debug_pubnames && startswith (name, "gnu_pubnames"))
|| (do_debug_pubtypes && startswith (name, "gnu_pubtypes"))
|| (do_debug_aranges && startswith (name, "aranges"))
|| (do_debug_ranges && startswith (name, "ranges"))
|| (do_debug_ranges && startswith (name, "rnglists"))
|| (do_debug_frames && startswith (name, "frame"))
|| (do_debug_macinfo && startswith (name, "macinfo"))
|| (do_debug_macinfo && startswith (name, "macro"))
|| (do_debug_str && startswith (name, "str"))
|| (do_debug_links && startswith (name, "sup"))
|| (do_debug_str_offsets && startswith (name, "str_offsets"))
|| (do_debug_loc && startswith (name, "loc"))
|| (do_debug_loc && startswith (name, "loclists"))
|| (do_debug_addr && startswith (name, "addr"))
|| (do_debug_cu_index && startswith (name, "cu_index"))
|| (do_debug_cu_index && startswith (name, "tu_index"))
)
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
}
else if ((do_debugging || do_debug_info)
&& startswith (name, ".gnu.linkonce.wi."))
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
else if (do_debug_frames && streq (name, ".eh_frame"))
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
else if (do_debug_frames && streq (name, ".eh_frame_hdr"))
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
else if (do_gdb_index && (streq (name, ".gdb_index")
|| streq (name, ".debug_names")))
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
else if ((do_debugging || do_trace_info || do_trace_abbrevs
|| do_trace_aranges)
&& startswith (name, ".trace_"))
{
name += sizeof (".trace_") - 1;
if (do_debugging
|| (do_trace_info && streq (name, "info"))
|| (do_trace_abbrevs && streq (name, "abbrev"))
|| (do_trace_aranges && streq (name, "aranges"))
)
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
}
else if ((do_debugging || do_debug_links)
&& (startswith (name, ".gnu_debuglink")
|| startswith (name, ".gnu_debugaltlink")))
request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP);
}
if (! do_sections)
return true;
if (filedata->is_separate && ! process_links)
return true;
if (filedata->is_separate)
printf (_("\nSection Headers in linked file '%s':\n"),
printable_string (filedata->file_name, 0));
else if (filedata->file_header.e_shnum > 1)
printf (_("\nSection Headers:\n"));
else
printf (_("\nSection Header:\n"));
if (is_32bit_elf)
{
if (do_section_details)
{
printf (_(" [Nr] Name\n"));
printf (_(" Type Addr Off Size ES Lk Inf Al\n"));
}
else
printf
(_(" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n"));
}
else if (do_wide)
{
if (do_section_details)
{
printf (_(" [Nr] Name\n"));
printf (_(" Type Address Off Size ES Lk Inf Al\n"));
}
else
printf
(_(" [Nr] Name Type Address Off Size ES Flg Lk Inf Al\n"));
}
else
{
if (do_section_details)
{
printf (_(" [Nr] Name\n"));
printf (_(" Type Address Offset Link\n"));
printf (_(" Size EntSize Info Align\n"));
}
else
{
printf (_(" [Nr] Name Type Address Offset\n"));
printf (_(" Size EntSize Flags Link Info Align\n"));
}
}
if (do_section_details)
printf (_(" Flags\n"));
for (i = 0, section = filedata->section_headers;
i < filedata->file_header.e_shnum;
i++, section++)
{
switch (section->sh_type)
{
case SHT_REL:
case SHT_RELR:
case SHT_RELA:
if (section->sh_link == 0
&& (filedata->file_header.e_type == ET_EXEC
|| filedata->file_header.e_type == ET_DYN))
break;
case SHT_SYMTAB_SHNDX:
case SHT_GROUP:
case SHT_HASH:
case SHT_GNU_HASH:
case SHT_GNU_versym:
if (section->sh_link == 0
|| section->sh_link >= filedata->file_header.e_shnum
|| (filedata->section_headers[section->sh_link].sh_type != SHT_SYMTAB
&& filedata->section_headers[section->sh_link].sh_type != SHT_DYNSYM))
warn (_("[%2u]: Link field (%u) should index a symtab section.\n"),
i, section->sh_link);
break;
case SHT_DYNAMIC:
case SHT_SYMTAB:
case SHT_DYNSYM:
case SHT_GNU_verneed:
case SHT_GNU_verdef:
case SHT_GNU_LIBLIST:
if (section->sh_link == 0
|| section->sh_link >= filedata->file_header.e_shnum
|| filedata->section_headers[section->sh_link].sh_type != SHT_STRTAB)
warn (_("[%2u]: Link field (%u) should index a string section.\n"),
i, section->sh_link);
break;
case SHT_INIT_ARRAY:
case SHT_FINI_ARRAY:
case SHT_PREINIT_ARRAY:
if (section->sh_type < SHT_LOOS && section->sh_link != 0)
warn (_("[%2u]: Unexpected value (%u) in link field.\n"),
i, section->sh_link);
break;
default:
#if 0
#endif
break;
}
switch (section->sh_type)
{
case SHT_REL:
case SHT_RELA:
if (section->sh_info == 0
&& (filedata->file_header.e_type == ET_EXEC
|| filedata->file_header.e_type == ET_DYN))
break;
if (section->sh_info == 0
|| section->sh_info >= filedata->file_header.e_shnum
|| (filedata->section_headers[section->sh_info].sh_type != SHT_PROGBITS
&& filedata->section_headers[section->sh_info].sh_type != SHT_NOBITS
&& filedata->section_headers[section->sh_info].sh_type != SHT_NOTE
&& filedata->section_headers[section->sh_info].sh_type != SHT_INIT_ARRAY
&& filedata->section_headers[section->sh_info].sh_type != SHT_FINI_ARRAY
&& filedata->section_headers[section->sh_info].sh_type != SHT_PREINIT_ARRAY
&& filedata->section_headers[section->sh_info].sh_type < SHT_LOOS))
warn (_("[%2u]: Info field (%u) should index a relocatable section.\n"),
i, section->sh_info);
break;
case SHT_DYNAMIC:
case SHT_HASH:
case SHT_SYMTAB_SHNDX:
case SHT_INIT_ARRAY:
case SHT_FINI_ARRAY:
case SHT_PREINIT_ARRAY:
if (section->sh_info != 0)
warn (_("[%2u]: Unexpected value (%u) in info field.\n"),
i, section->sh_info);
break;
case SHT_GROUP:
case SHT_SYMTAB:
case SHT_DYNSYM:
break;
default:
if (section->sh_type == SHT_NOBITS)
;
else if (section->sh_flags & SHF_INFO_LINK)
{
if (section->sh_info < 1 || section->sh_info >= filedata->file_header.e_shnum)
warn (_("[%2u]: Expected link to another section in info field"), i);
}
else if (section->sh_type < SHT_LOOS
&& (section->sh_flags & SHF_GNU_MBIND) == 0
&& section->sh_info != 0)
warn (_("[%2u]: Unexpected value (%u) in info field.\n"),
i, section->sh_info);
break;
}
if (section->sh_size > filedata->file_size
&& section->sh_type != SHT_NOBITS
&& section->sh_type != SHT_NULL
&& section->sh_type < SHT_LOOS)
warn (_("Size of section %u is larger than the entire file!\n"), i);
printf (" [%2u] ", i);
if (do_section_details)
printf ("%s\n ", printable_section_name (filedata, section));
else
print_symbol_name (-17, printable_section_name (filedata, section));
printf (do_wide ? " %-15s " : " %-15.15s ",
get_section_type_name (filedata, section->sh_type));
if (is_32bit_elf)
{
const char * link_too_big = NULL;
print_vma (section->sh_addr, LONG_HEX);
printf ( " %6.6lx %6.6lx %2.2lx",
(unsigned long) section->sh_offset,
(unsigned long) section->sh_size,
(unsigned long) section->sh_entsize);
if (do_section_details)
fputs (" ", stdout);
else
printf (" %3s ", get_elf_section_flags (filedata, section->sh_flags));
if (section->sh_link >= filedata->file_header.e_shnum)
{
link_too_big = "";
switch (filedata->file_header.e_machine)
{
case EM_386:
case EM_IAMCU:
case EM_X86_64:
case EM_L1OM:
case EM_K1OM:
case EM_OLD_SPARCV9:
case EM_SPARC32PLUS:
case EM_SPARCV9:
case EM_SPARC:
if (section->sh_link == (SHN_BEFORE & 0xffff))
link_too_big = "BEFORE";
else if (section->sh_link == (SHN_AFTER & 0xffff))
link_too_big = "AFTER";
break;
default:
break;
}
}
if (do_section_details)
{
if (link_too_big != NULL && * link_too_big)
printf ("<%s> ", link_too_big);
else
printf ("%2u ", section->sh_link);
printf ("%3u %2lu\n", section->sh_info,
(unsigned long) section->sh_addralign);
}
else
printf ("%2u %3u %2lu\n",
section->sh_link,
section->sh_info,
(unsigned long) section->sh_addralign);
if (link_too_big && ! * link_too_big)
warn (_("section %u: sh_link value of %u is larger than the number of sections\n"),
i, section->sh_link);
}
else if (do_wide)
{
print_vma (section->sh_addr, LONG_HEX);
if ((long) section->sh_offset == section->sh_offset)
printf (" %6.6lx", (unsigned long) section->sh_offset);
else
{
putchar (' ');
print_vma (section->sh_offset, LONG_HEX);
}
if ((unsigned long) section->sh_size == section->sh_size)
printf (" %6.6lx", (unsigned long) section->sh_size);
else
{
putchar (' ');
print_vma (section->sh_size, LONG_HEX);
}
if ((unsigned long) section->sh_entsize == section->sh_entsize)
printf (" %2.2lx", (unsigned long) section->sh_entsize);
else
{
putchar (' ');
print_vma (section->sh_entsize, LONG_HEX);
}
if (do_section_details)
fputs (" ", stdout);
else
printf (" %3s ", get_elf_section_flags (filedata, section->sh_flags));
printf ("%2u %3u ", section->sh_link, section->sh_info);
if ((unsigned long) section->sh_addralign == section->sh_addralign)
printf ("%2lu\n", (unsigned long) section->sh_addralign);
else
{
print_vma (section->sh_addralign, DEC);
putchar ('\n');
}
}
else if (do_section_details)
{
putchar (' ');
print_vma (section->sh_addr, LONG_HEX);
if ((long) section->sh_offset == section->sh_offset)
printf (" %16.16lx", (unsigned long) section->sh_offset);
else
{
printf (" ");
print_vma (section->sh_offset, LONG_HEX);
}
printf (" %u\n ", section->sh_link);
print_vma (section->sh_size, LONG_HEX);
putchar (' ');
print_vma (section->sh_entsize, LONG_HEX);
printf (" %-16u %lu\n",
section->sh_info,
(unsigned long) section->sh_addralign);
}
else
{
putchar (' ');
print_vma (section->sh_addr, LONG_HEX);
if ((long) section->sh_offset == section->sh_offset)
printf (" %8.8lx", (unsigned long) section->sh_offset);
else
{
printf (" ");
print_vma (section->sh_offset, LONG_HEX);
}
printf ("\n ");
print_vma (section->sh_size, LONG_HEX);
printf (" ");
print_vma (section->sh_entsize, LONG_HEX);
printf (" %3s ", get_elf_section_flags (filedata, section->sh_flags));
printf (" %2u %3u %lu\n",
section->sh_link,
section->sh_info,
(unsigned long) section->sh_addralign);
}
if (do_section_details)
{
printf (" %s\n", get_elf_section_flags (filedata, section->sh_flags));
if ((section->sh_flags & SHF_COMPRESSED) != 0)
{
unsigned char buf[24];
assert (sizeof (buf) >= sizeof (Elf64_External_Chdr));
if (get_data (&buf, filedata, section->sh_offset, 1,
sizeof (buf), _("compression header")))
{
Elf_Internal_Chdr chdr;
if (get_compression_header (&chdr, buf, sizeof (buf)) == 0)
printf (_(" [<corrupt>]\n"));
else
{
if (chdr.ch_type == ch_compress_zlib)
printf (" ZLIB, ");
else if (chdr.ch_type == ch_compress_zstd)
printf (" ZSTD, ");
else
printf (_(" [<unknown>: 0x%x], "),
chdr.ch_type);
print_vma (chdr.ch_size, LONG_HEX);
printf (", %lu\n", (unsigned long) chdr.ch_addralign);
}
}
}
}
}
return true;
}
static Elf_Internal_Sym *
get_elf_symbols (Filedata *filedata,
Elf_Internal_Shdr *section,
uint64_t *num_syms_return)
{
if (is_32bit_elf)
return get_32bit_elf_symbols (filedata, section, num_syms_return);
else
return get_64bit_elf_symbols (filedata, section, num_syms_return);
}
static Elf_Internal_Sym *
get_elf_symbols (Filedata *filedata,
Elf_Internal_Shdr *section,
uint64_t *num_syms_return)
{
if (is_32bit_elf)
return get_32bit_elf_symbols (filedata, section, num_syms_return);
else
return get_64bit_elf_symbols (filedata, section, num_syms_return);
}
static Elf_Internal_Sym *
get_32bit_elf_symbols (Filedata *filedata,
Elf_Internal_Shdr *section,
uint64_t *num_syms_return)
{
uint64_t number = 0;
Elf32_External_Sym * esyms = NULL;
Elf_External_Sym_Shndx * shndx = NULL;
Elf_Internal_Sym * isyms = NULL;
Elf_Internal_Sym * psym;
unsigned int j;
elf_section_list * entry;
if (section->sh_size == 0)
{
if (num_syms_return != NULL)
* num_syms_return = 0;
return NULL;
}
if (section->sh_entsize == 0 || section->sh_entsize > section->sh_size)
{
error (_("Section %s has an invalid sh_entsize of %#" PRIx64 "\n"),
printable_section_name (filedata, section),
section->sh_entsize);
goto exit_point;
}
if (section->sh_size > filedata->file_size)
{
error (_("Section %s has an invalid sh_size of %#" PRIx64 "\n"),
printable_section_name (filedata, section),
section->sh_size);
goto exit_point;
}
number = section->sh_size / section->sh_entsize;
if (number * sizeof (Elf32_External_Sym) > section->sh_size + 1)
{
error (_("Size (%#" PRIx64 ") of section %s "
"is not a multiple of its sh_entsize (%#" PRIx64 ")\n"),
section->sh_size,
printable_section_name (filedata, section),
section->sh_entsize);
goto exit_point;
}
esyms = (Elf32_External_Sym *) get_data (NULL, filedata, section->sh_offset, 1,
section->sh_size, _("symbols"));
if (esyms == NULL)
goto exit_point;
shndx = NULL;
for (entry = filedata->symtab_shndx_list; entry != NULL; entry = entry->next)
{
if (entry->hdr->sh_link != (size_t) (section - filedata->section_headers))
continue;
if (shndx != NULL)
{
error (_("Multiple symbol table index sections associated with the same symbol section\n"));
free (shndx);
}
shndx = (Elf_External_Sym_Shndx *) get_data (NULL, filedata,
entry->hdr->sh_offset,
1, entry->hdr->sh_size,
_("symbol table section indices"));
if (shndx == NULL)
goto exit_point;
if (entry->hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number)
{
error (_("Index section %s has an sh_size of %#" PRIx64 " - expected %#" PRIx64 "\n"),
printable_section_name (filedata, entry->hdr),
entry->hdr->sh_size,
section->sh_size);
goto exit_point;
}
}
isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym));
if (isyms == NULL)
{
error (_("Out of memory reading %" PRIu64 " symbols\n"), number);
goto exit_point;
}
for (j = 0, psym = isyms; j < number; j++, psym++)
{
psym->st_name = BYTE_GET (esyms[j].st_name);
psym->st_value = BYTE_GET (esyms[j].st_value);
psym->st_size = BYTE_GET (esyms[j].st_size);
psym->st_shndx = BYTE_GET (esyms[j].st_shndx);
if (psym->st_shndx == (SHN_XINDEX & 0xffff) && shndx != NULL)
psym->st_shndx
= byte_get ((unsigned char *) &shndx[j], sizeof (shndx[j]));
else if (psym->st_shndx >= (SHN_LORESERVE & 0xffff))
psym->st_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff);
psym->st_info = BYTE_GET (esyms[j].st_info);
psym->st_other = BYTE_GET (esyms[j].st_other);
}
exit_point:
free (shndx);
free (esyms);
if (num_syms_return != NULL)
* num_syms_return = isyms == NULL ? 0 : number;
return isyms;
}
static Elf_Internal_Sym *
get_64bit_elf_symbols (Filedata *filedata,
Elf_Internal_Shdr *section,
uint64_t *num_syms_return)
{
uint64_t number = 0;
Elf64_External_Sym * esyms = NULL;
Elf_External_Sym_Shndx * shndx = NULL;
Elf_Internal_Sym * isyms = NULL;
Elf_Internal_Sym * psym;
unsigned int j;
elf_section_list * entry;
if (section->sh_size == 0)
{
if (num_syms_return != NULL)
* num_syms_return = 0;
return NULL;
}
if (section->sh_entsize == 0 || section->sh_entsize > section->sh_size)
{
error (_("Section %s has an invalid sh_entsize of %#" PRIx64 "\n"),
printable_section_name (filedata, section),
section->sh_entsize);
goto exit_point;
}
if (section->sh_size > filedata->file_size)
{
error (_("Section %s has an invalid sh_size of %#" PRIx64 "\n"),
printable_section_name (filedata, section),
section->sh_size);
goto exit_point;
}
number = section->sh_size / section->sh_entsize;
if (number * sizeof (Elf64_External_Sym) > section->sh_size + 1)
{
error (_("Size (%#" PRIx64 ") of section %s "
"is not a multiple of its sh_entsize (%#" PRIx64 ")\n"),
section->sh_size,
printable_section_name (filedata, section),
section->sh_entsize);
goto exit_point;
}
esyms = (Elf64_External_Sym *) get_data (NULL, filedata, section->sh_offset, 1,
section->sh_size, _("symbols"));
if (!esyms)
goto exit_point;
shndx = NULL;
for (entry = filedata->symtab_shndx_list; entry != NULL; entry = entry->next)
{
if (entry->hdr->sh_link != (size_t) (section - filedata->section_headers))
continue;
if (shndx != NULL)
{
error (_("Multiple symbol table index sections associated with the same symbol section\n"));
free (shndx);
}
shndx = (Elf_External_Sym_Shndx *) get_data (NULL, filedata,
entry->hdr->sh_offset,
1, entry->hdr->sh_size,
_("symbol table section indices"));
if (shndx == NULL)
goto exit_point;
if (entry->hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number)
{
error (_("Index section %s has an sh_size of %#" PRIx64 " - expected %#" PRIx64 "\n"),
printable_section_name (filedata, entry->hdr),
entry->hdr->sh_size,
section->sh_size);
goto exit_point;
}
}
isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym));
if (isyms == NULL)
{
error (_("Out of memory reading %" PRIu64 " symbols\n"), number);
goto exit_point;
}
for (j = 0, psym = isyms; j < number; j++, psym++)
{
psym->st_name = BYTE_GET (esyms[j].st_name);
psym->st_info = BYTE_GET (esyms[j].st_info);
psym->st_other = BYTE_GET (esyms[j].st_other);
psym->st_shndx = BYTE_GET (esyms[j].st_shndx);
if (psym->st_shndx == (SHN_XINDEX & 0xffff) && shndx != NULL)
psym->st_shndx
= byte_get ((unsigned char *) &shndx[j], sizeof (shndx[j]));
else if (psym->st_shndx >= (SHN_LORESERVE & 0xffff))
psym->st_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff);
psym->st_value = BYTE_GET (esyms[j].st_value);
psym->st_size = BYTE_GET (esyms[j].st_size);
}
exit_point:
free (shndx);
free (esyms);
if (num_syms_return != NULL)
* num_syms_return = isyms == NULL ? 0 : number;
return isyms;
}
static Elf_Internal_Sym *
get_32bit_elf_symbols (Filedata *filedata,
Elf_Internal_Shdr *section,
uint64_t *num_syms_return)
{
uint64_t number = 0;
Elf32_External_Sym * esyms = NULL;
Elf_External_Sym_Shndx * shndx = NULL;
Elf_Internal_Sym * isyms = NULL;
Elf_Internal_Sym * psym;
unsigned int j;
elf_section_list * entry;
if (section->sh_size == 0)
{
if (num_syms_return != NULL)
* num_syms_return = 0;
return NULL;
}
if (section->sh_entsize == 0 || section->sh_entsize > section->sh_size)
{
error (_("Section %s has an invalid sh_entsize of %#" PRIx64 "\n"),
printable_section_name (filedata, section),
section->sh_entsize);
goto exit_point;
}
if (section->sh_size > filedata->file_size)
{
error (_("Section %s has an invalid sh_size of %#" PRIx64 "\n"),
printable_section_name (filedata, section),
section->sh_size);
goto exit_point;
}
number = section->sh_size / section->sh_entsize;
if (number * sizeof (Elf32_External_Sym) > section->sh_size + 1)
{
error (_("Size (%#" PRIx64 ") of section %s "
"is not a multiple of its sh_entsize (%#" PRIx64 ")\n"),
section->sh_size,
printable_section_name (filedata, section),
section->sh_entsize);
goto exit_point;
}
esyms = (Elf32_External_Sym *) get_data (NULL, filedata, section->sh_offset, 1,
section->sh_size, _("symbols"));
if (esyms == NULL)
goto exit_point;
shndx = NULL;
for (entry = filedata->symtab_shndx_list; entry != NULL; entry = entry->next)
{
if (entry->hdr->sh_link != (size_t) (section - filedata->section_headers))
continue;
if (shndx != NULL)
{
error (_("Multiple symbol table index sections associated with the same symbol section\n"));
free (shndx);
}
shndx = (Elf_External_Sym_Shndx *) get_data (NULL, filedata,
entry->hdr->sh_offset,
1, entry->hdr->sh_size,
_("symbol table section indices"));
if (shndx == NULL)
goto exit_point;
if (entry->hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number)
{
error (_("Index section %s has an sh_size of %#" PRIx64 " - expected %#" PRIx64 "\n"),
printable_section_name (filedata, entry->hdr),
entry->hdr->sh_size,
section->sh_size);
goto exit_point;
}
}
isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym));
if (isyms == NULL)
{
error (_("Out of memory reading %" PRIu64 " symbols\n"), number);
goto exit_point;
}
for (j = 0, psym = isyms; j < number; j++, psym++)
{
psym->st_name = BYTE_GET (esyms[j].st_name);
psym->st_value = BYTE_GET (esyms[j].st_value);
psym->st_size = BYTE_GET (esyms[j].st_size);
psym->st_shndx = BYTE_GET (esyms[j].st_shndx);
if (psym->st_shndx == (SHN_XINDEX & 0xffff) && shndx != NULL)
psym->st_shndx
= byte_get ((unsigned char *) &shndx[j], sizeof (shndx[j]));
else if (psym->st_shndx >= (SHN_LORESERVE & 0xffff))
psym->st_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff);
psym->st_info = BYTE_GET (esyms[j].st_info);
psym->st_other = BYTE_GET (esyms[j].st_other);
}
exit_point:
free (shndx);
free (esyms);
if (num_syms_return != NULL)
* num_syms_return = isyms == NULL ? 0 : number;
return isyms;
}
static Elf_Internal_Sym *
get_64bit_elf_symbols (Filedata *filedata,
Elf_Internal_Shdr *section,
uint64_t *num_syms_return)
{
uint64_t number = 0;
Elf64_External_Sym * esyms = NULL;
Elf_External_Sym_Shndx * shndx = NULL;
Elf_Internal_Sym * isyms = NULL;
Elf_Internal_Sym * psym;
unsigned int j;
elf_section_list * entry;
if (section->sh_size == 0)
{
if (num_syms_return != NULL)
* num_syms_return = 0;
return NULL;
}
if (section->sh_entsize == 0 || section->sh_entsize > section->sh_size)
{
error (_("Section %s has an invalid sh_entsize of %#" PRIx64 "\n"),
printable_section_name (filedata, section),
section->sh_entsize);
goto exit_point;
}
if (section->sh_size > filedata->file_size)
{
error (_("Section %s has an invalid sh_size of %#" PRIx64 "\n"),
printable_section_name (filedata, section),
section->sh_size);
goto exit_point;
}
number = section->sh_size / section->sh_entsize;
if (number * sizeof (Elf64_External_Sym) > section->sh_size + 1)
{
error (_("Size (%#" PRIx64 ") of section %s "
"is not a multiple of its sh_entsize (%#" PRIx64 ")\n"),
section->sh_size,
printable_section_name (filedata, section),
section->sh_entsize);
goto exit_point;
}
esyms = (Elf64_External_Sym *) get_data (NULL, filedata, section->sh_offset, 1,
section->sh_size, _("symbols"));
if (!esyms)
goto exit_point;
shndx = NULL;
for (entry = filedata->symtab_shndx_list; entry != NULL; entry = entry->next)
{
if (entry->hdr->sh_link != (size_t) (section - filedata->section_headers))
continue;
if (shndx != NULL)
{
error (_("Multiple symbol table index sections associated with the same symbol section\n"));
free (shndx);
}
shndx = (Elf_External_Sym_Shndx *) get_data (NULL, filedata,
entry->hdr->sh_offset,
1, entry->hdr->sh_size,
_("symbol table section indices"));
if (shndx == NULL)
goto exit_point;
if (entry->hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number)
{
error (_("Index section %s has an sh_size of %#" PRIx64 " - expected %#" PRIx64 "\n"),
printable_section_name (filedata, entry->hdr),
entry->hdr->sh_size,
section->sh_size);
goto exit_point;
}
}
isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym));
if (isyms == NULL)
{
error (_("Out of memory reading %" PRIu64 " symbols\n"), number);
goto exit_point;
}
for (j = 0, psym = isyms; j < number; j++, psym++)
{
psym->st_name = BYTE_GET (esyms[j].st_name);
psym->st_info = BYTE_GET (esyms[j].st_info);
psym->st_other = BYTE_GET (esyms[j].st_other);
psym->st_shndx = BYTE_GET (esyms[j].st_shndx);
if (psym->st_shndx == (SHN_XINDEX & 0xffff) && shndx != NULL)
psym->st_shndx
= byte_get ((unsigned char *) &shndx[j], sizeof (shndx[j]));
else if (psym->st_shndx >= (SHN_LORESERVE & 0xffff))
psym->st_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff);
psym->st_value = BYTE_GET (esyms[j].st_value);
psym->st_size = BYTE_GET (esyms[j].st_size);
}
exit_point:
free (shndx);
free (esyms);
if (num_syms_return != NULL)
* num_syms_return = isyms == NULL ? 0 : number;
return isyms;
}
typedef struct {
unsigned char st_name[4];
unsigned char st_value[4];
unsigned char st_size[4];
unsigned char st_info[1];
unsigned char st_other[1];
unsigned char st_shndx[2];
} Elf32_External_Sym;
typedef struct {
unsigned char st_name[4];
unsigned char st_info[1];
unsigned char st_other[1];
unsigned char st_shndx[2];
unsigned char st_value[8];
unsigned char st_size[8];
} Elf64_External_Sym;
typedef struct {
unsigned char st_name[4];
unsigned char st_value[4];
unsigned char st_size[4];
unsigned char st_info[1];
unsigned char st_other[1];
unsigned char st_shndx[2];
} Elf32_External_Sym;
typedef struct {
unsigned char st_name[4];
unsigned char st_info[1];
unsigned char st_other[1];
unsigned char st_shndx[2];
unsigned char st_value[8];
unsigned char st_size[8];
} Elf64_External_Sym;
static void
process_program_headers (Filedata * filedata)
{
Elf_Internal_Phdr * segment;
unsigned int i;
Elf_Internal_Phdr * previous_load = NULL;
if (do_segments && !do_header)
{
if (filedata->is_separate)
printf ("\nIn linked file '%s' the ELF file type is %s\n",
printable_string (filedata->file_name, 0),
get_file_type (filedata));
else
printf (_("\nElf file type is %s\n"), get_file_type (filedata));
printf (_("Entry point 0x%" PRIx64 "\n"),
filedata->file_header.e_entry);
printf (ngettext ("There is %d program header,"
" starting at offset %" PRIu64 "\n",
"There are %d program headers,"
" starting at offset %" PRIu64 "\n",
filedata->file_header.e_phnum),
filedata->file_header.e_phnum,
filedata->file_header.e_phoff);
}
if (! get_program_headers (filedata))
goto no_headers;
if (do_segments)
{
if (filedata->file_header.e_phnum > 1)
printf (_("\nProgram Headers:\n"));
else
printf (_("\nProgram Headers:\n"));
if (is_32bit_elf)
printf
(_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n"));
else if (do_wide)
printf
(_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n"));
else
{
printf
(_(" Type Offset VirtAddr PhysAddr\n"));
printf
(_(" FileSiz MemSiz Flags Align\n"));
}
}
uint64_t dynamic_addr = 0;
uint64_t dynamic_size = 0;
for (i = 0, segment = filedata->program_headers;
i < filedata->file_header.e_phnum;
i++, segment++)
{
if (do_segments)
{
printf (" %-14.14s ", get_segment_type (filedata, segment->p_type));
if (is_32bit_elf)
{
printf ("0x%6.6lx ", (unsigned long) segment->p_offset);
printf ("0x%8.8lx ", (unsigned long) segment->p_vaddr);
printf ("0x%8.8lx ", (unsigned long) segment->p_paddr);
printf ("0x%5.5lx ", (unsigned long) segment->p_filesz);
printf ("0x%5.5lx ", (unsigned long) segment->p_memsz);
printf ("%c%c%c ",
(segment->p_flags & PF_R ? 'R' : ' '),
(segment->p_flags & PF_W ? 'W' : ' '),
(segment->p_flags & PF_X ? 'E' : ' '));
printf ("%#lx", (unsigned long) segment->p_align);
}
else if (do_wide)
{
if ((unsigned long) segment->p_offset == segment->p_offset)
printf ("0x%6.6lx ", (unsigned long) segment->p_offset);
else
{
print_vma (segment->p_offset, FULL_HEX);
putchar (' ');
}
print_vma (segment->p_vaddr, FULL_HEX);
putchar (' ');
print_vma (segment->p_paddr, FULL_HEX);
putchar (' ');
if ((unsigned long) segment->p_filesz == segment->p_filesz)
printf ("0x%6.6lx ", (unsigned long) segment->p_filesz);
else
{
print_vma (segment->p_filesz, FULL_HEX);
putchar (' ');
}
if ((unsigned long) segment->p_memsz == segment->p_memsz)
printf ("0x%6.6lx", (unsigned long) segment->p_memsz);
else
{
print_vma (segment->p_memsz, FULL_HEX);
}
printf (" %c%c%c ",
(segment->p_flags & PF_R ? 'R' : ' '),
(segment->p_flags & PF_W ? 'W' : ' '),
(segment->p_flags & PF_X ? 'E' : ' '));
if ((unsigned long) segment->p_align == segment->p_align)
printf ("%#lx", (unsigned long) segment->p_align);
else
{
print_vma (segment->p_align, PREFIX_HEX);
}
}
else
{
print_vma (segment->p_offset, FULL_HEX);
putchar (' ');
print_vma (segment->p_vaddr, FULL_HEX);
putchar (' ');
print_vma (segment->p_paddr, FULL_HEX);
printf ("\n ");
print_vma (segment->p_filesz, FULL_HEX);
putchar (' ');
print_vma (segment->p_memsz, FULL_HEX);
printf (" %c%c%c ",
(segment->p_flags & PF_R ? 'R' : ' '),
(segment->p_flags & PF_W ? 'W' : ' '),
(segment->p_flags & PF_X ? 'E' : ' '));
print_vma (segment->p_align, PREFIX_HEX);
}
putc ('\n', stdout);
}
switch (segment->p_type)
{
case PT_LOAD:
#if 0 /* 不校验 PT_LOAD 段的顺序
虽然 ELF 标准要求 PT_LOAD 段按虚拟地址递增排序, 但部分程序
会使用非有序段, 因此禁用该校验以兼容实际场景 */
if (previous_load
&& previous_load->p_vaddr > segment->p_vaddr)
error (_("LOAD segments must be sorted in order of increasing VirtAddr\n"));
#endif
if (segment->p_memsz < segment->p_filesz)
error (_("the segment's file size is larger than its memory size\n"));
previous_load = segment;
break;
case PT_PHDR:
if (i > 0 && previous_load != NULL)
error (_("the PHDR segment must occur before any LOAD segment\n"));
if (filedata->file_header.e_machine != EM_PARISC)
{
unsigned int j;
for (j = 1; j < filedata->file_header.e_phnum; j++)
{
Elf_Internal_Phdr *load = filedata->program_headers + j;
if (load->p_type == PT_LOAD
&& load->p_offset <= segment->p_offset
&& (load->p_offset + load->p_filesz
>= segment->p_offset + segment->p_filesz)
&& load->p_vaddr <= segment->p_vaddr
&& (load->p_vaddr + load->p_filesz
>= segment->p_vaddr + segment->p_filesz))
break;
}
if (j == filedata->file_header.e_phnum)
error (_("the PHDR segment is not covered by a LOAD segment\n"));
}
break;
case PT_DYNAMIC:
if (dynamic_addr)
error (_("more than one dynamic segment\n"));
dynamic_addr = segment->p_offset;
dynamic_size = segment->p_filesz;
if (filedata->section_headers != NULL)
{
Elf_Internal_Shdr * sec;
sec = find_section (filedata, ".dynamic");
if (sec == NULL || sec->sh_size == 0)
{
if (!is_ia64_vms (filedata))
error (_("no .dynamic section in the dynamic segment\n"));
break;
}
if (sec->sh_type == SHT_NOBITS)
{
dynamic_addr = 0;
dynamic_size = 0;
break;
}
dynamic_addr = sec->sh_offset;
dynamic_size = sec->sh_size;
if (do_checks
&& (dynamic_addr != segment->p_offset
|| dynamic_size != segment->p_filesz))
warn (_("\
the .dynamic section is not the same as the dynamic segment\n"));
}
if (dynamic_addr > filedata->file_size
|| (dynamic_size > filedata->file_size - dynamic_addr))
{
error (_("the dynamic segment offset + size exceeds the size of the file\n"));
dynamic_addr = 0;
dynamic_size = 0;
}
break;
case PT_INTERP:
if (segment->p_offset >= filedata->file_size
|| segment->p_filesz > filedata->file_size - segment->p_offset
|| segment->p_filesz - 1 >= (size_t) -2
|| fseek64 (filedata->handle,
filedata->archive_file_offset + segment->p_offset,
SEEK_SET))
error (_("Unable to find program interpreter name\n"));
else
{
size_t len = segment->p_filesz;
free (filedata->program_interpreter);
filedata->program_interpreter = xmalloc (len + 1);
len = fread (filedata->program_interpreter, 1, len,
filedata->handle);
filedata->program_interpreter[len] = 0;
if (do_segments)
printf (_(" [Requesting program interpreter: %s]\n"),
printable_string (filedata->program_interpreter, 0));
}
break;
}
}
if (do_segments
&& filedata->section_headers != NULL
&& filedata->string_table != NULL)
{
printf (_("\n Section to Segment mapping:\n"));
printf (_(" Segment Sections...\n"));
for (i = 0; i < filedata->file_header.e_phnum; i++)
{
unsigned int j;
Elf_Internal_Shdr * section;
segment = filedata->program_headers + i;
section = filedata->section_headers + 1;
printf (" %2.2d ", i);
for (j = 1; j < filedata->file_header.e_shnum; j++, section++)
{
if (!ELF_TBSS_SPECIAL (section, segment)
&& ELF_SECTION_IN_SEGMENT_STRICT (section, segment))
printf ("%s ", printable_section_name (filedata, section));
}
putc ('\n',stdout);
}
}
filedata->dynamic_addr = dynamic_addr;
filedata->dynamic_size = dynamic_size ? dynamic_size : 1;
return;
no_headers:
filedata->dynamic_addr = 0;
filedata->dynamic_size = 1;
}
static void
process_program_headers (Filedata * filedata)
{
Elf_Internal_Phdr * segment;
unsigned int i;
Elf_Internal_Phdr * previous_load = NULL;
if (do_segments && !do_header)
{
if (filedata->is_separate)
printf ("\nIn linked file '%s' the ELF file type is %s\n",
printable_string (filedata->file_name, 0),
get_file_type (filedata));
else
printf (_("\nElf file type is %s\n"), get_file_type (filedata));
printf (_("Entry point 0x%" PRIx64 "\n"),
filedata->file_header.e_entry);
printf (ngettext ("There is %d program header,"
" starting at offset %" PRIu64 "\n",
"There are %d program headers,"
" starting at offset %" PRIu64 "\n",
filedata->file_header.e_phnum),
filedata->file_header.e_phnum,
filedata->file_header.e_phoff);
}
if (! get_program_headers (filedata))
goto no_headers;
if (do_segments)
{
if (filedata->file_header.e_phnum > 1)
printf (_("\nProgram Headers:\n"));
else
printf (_("\nProgram Headers:\n"));
if (is_32bit_elf)
printf
(_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n"));
else if (do_wide)
printf
(_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n"));
else
{
printf
(_(" Type Offset VirtAddr PhysAddr\n"));
printf
(_(" FileSiz MemSiz Flags Align\n"));
}
}
uint64_t dynamic_addr = 0;
uint64_t dynamic_size = 0;
for (i = 0, segment = filedata->program_headers;
i < filedata->file_header.e_phnum;
i++, segment++)
{
if (do_segments)
{
printf (" %-14.14s ", get_segment_type (filedata, segment->p_type));
if (is_32bit_elf)
{
printf ("0x%6.6lx ", (unsigned long) segment->p_offset);
printf ("0x%8.8lx ", (unsigned long) segment->p_vaddr);
printf ("0x%8.8lx ", (unsigned long) segment->p_paddr);
printf ("0x%5.5lx ", (unsigned long) segment->p_filesz);
printf ("0x%5.5lx ", (unsigned long) segment->p_memsz);
printf ("%c%c%c ",
(segment->p_flags & PF_R ? 'R' : ' '),
(segment->p_flags & PF_W ? 'W' : ' '),
(segment->p_flags & PF_X ? 'E' : ' '));
printf ("%#lx", (unsigned long) segment->p_align);
}
else if (do_wide)
{
if ((unsigned long) segment->p_offset == segment->p_offset)
printf ("0x%6.6lx ", (unsigned long) segment->p_offset);
else
{
print_vma (segment->p_offset, FULL_HEX);
putchar (' ');
}
print_vma (segment->p_vaddr, FULL_HEX);
putchar (' ');
print_vma (segment->p_paddr, FULL_HEX);
putchar (' ');
if ((unsigned long) segment->p_filesz == segment->p_filesz)
printf ("0x%6.6lx ", (unsigned long) segment->p_filesz);
else
{
print_vma (segment->p_filesz, FULL_HEX);
putchar (' ');
}
if ((unsigned long) segment->p_memsz == segment->p_memsz)
printf ("0x%6.6lx", (unsigned long) segment->p_memsz);
else
{
print_vma (segment->p_memsz, FULL_HEX);
}
printf (" %c%c%c ",
(segment->p_flags & PF_R ? 'R' : ' '),
(segment->p_flags & PF_W ? 'W' : ' '),
(segment->p_flags & PF_X ? 'E' : ' '));
if ((unsigned long) segment->p_align == segment->p_align)
printf ("%#lx", (unsigned long) segment->p_align);
else
{
print_vma (segment->p_align, PREFIX_HEX);
}
}
else
{
print_vma (segment->p_offset, FULL_HEX);
putchar (' ');
print_vma (segment->p_vaddr, FULL_HEX);
putchar (' ');
print_vma (segment->p_paddr, FULL_HEX);
printf ("\n ");
print_vma (segment->p_filesz, FULL_HEX);
putchar (' ');
print_vma (segment->p_memsz, FULL_HEX);
printf (" %c%c%c ",
(segment->p_flags & PF_R ? 'R' : ' '),
(segment->p_flags & PF_W ? 'W' : ' '),
(segment->p_flags & PF_X ? 'E' : ' '));
print_vma (segment->p_align, PREFIX_HEX);
}
putc ('\n', stdout);
}
switch (segment->p_type)
{
case PT_LOAD:
#if 0 /* 不校验 PT_LOAD 段的顺序
虽然 ELF 标准要求 PT_LOAD 段按虚拟地址递增排序, 但部分程序
会使用非有序段, 因此禁用该校验以兼容实际场景 */
if (previous_load
&& previous_load->p_vaddr > segment->p_vaddr)
error (_("LOAD segments must be sorted in order of increasing VirtAddr\n"));
#endif
if (segment->p_memsz < segment->p_filesz)
error (_("the segment's file size is larger than its memory size\n"));
previous_load = segment;
break;
case PT_PHDR:
if (i > 0 && previous_load != NULL)
error (_("the PHDR segment must occur before any LOAD segment\n"));
if (filedata->file_header.e_machine != EM_PARISC)
{
unsigned int j;
for (j = 1; j < filedata->file_header.e_phnum; j++)
{
Elf_Internal_Phdr *load = filedata->program_headers + j;
if (load->p_type == PT_LOAD
&& load->p_offset <= segment->p_offset
&& (load->p_offset + load->p_filesz
>= segment->p_offset + segment->p_filesz)
&& load->p_vaddr <= segment->p_vaddr
&& (load->p_vaddr + load->p_filesz
>= segment->p_vaddr + segment->p_filesz))
break;
}
if (j == filedata->file_header.e_phnum)
error (_("the PHDR segment is not covered by a LOAD segment\n"));
}
break;
case PT_DYNAMIC:
if (dynamic_addr)
error (_("more than one dynamic segment\n"));
dynamic_addr = segment->p_offset;
dynamic_size = segment->p_filesz;
if (filedata->section_headers != NULL)
{
Elf_Internal_Shdr * sec;
sec = find_section (filedata, ".dynamic");
if (sec == NULL || sec->sh_size == 0)
{
if (!is_ia64_vms (filedata))
error (_("no .dynamic section in the dynamic segment\n"));
break;
}
if (sec->sh_type == SHT_NOBITS)
{
dynamic_addr = 0;
dynamic_size = 0;
break;
}
dynamic_addr = sec->sh_offset;
dynamic_size = sec->sh_size;
if (do_checks
&& (dynamic_addr != segment->p_offset
|| dynamic_size != segment->p_filesz))
warn (_("\
the .dynamic section is not the same as the dynamic segment\n"));
}
if (dynamic_addr > filedata->file_size
|| (dynamic_size > filedata->file_size - dynamic_addr))
{
error (_("the dynamic segment offset + size exceeds the size of the file\n"));
dynamic_addr = 0;
dynamic_size = 0;
}
break;
case PT_INTERP:
if (segment->p_offset >= filedata->file_size
|| segment->p_filesz > filedata->file_size - segment->p_offset
|| segment->p_filesz - 1 >= (size_t) -2
|| fseek64 (filedata->handle,
filedata->archive_file_offset + segment->p_offset,
SEEK_SET))
error (_("Unable to find program interpreter name\n"));
else
{
size_t len = segment->p_filesz;
free (filedata->program_interpreter);
filedata->program_interpreter = xmalloc (len + 1);
len = fread (filedata->program_interpreter, 1, len,
filedata->handle);
filedata->program_interpreter[len] = 0;
if (do_segments)
printf (_(" [Requesting program interpreter: %s]\n"),
printable_string (filedata->program_interpreter, 0));
}
break;
}
}
if (do_segments
&& filedata->section_headers != NULL
&& filedata->string_table != NULL)
{
printf (_("\n Section to Segment mapping:\n"));
printf (_(" Segment Sections...\n"));
for (i = 0; i < filedata->file_header.e_phnum; i++)
{
unsigned int j;
Elf_Internal_Shdr * section;
segment = filedata->program_headers + i;
section = filedata->section_headers + 1;
printf (" %2.2d ", i);
for (j = 1; j < filedata->file_header.e_shnum; j++, section++)
{
if (!ELF_TBSS_SPECIAL (section, segment)
&& ELF_SECTION_IN_SEGMENT_STRICT (section, segment))
printf ("%s ", printable_section_name (filedata, section));
}
putc ('\n',stdout);
}
}
filedata->dynamic_addr = dynamic_addr;
filedata->dynamic_size = dynamic_size ? dynamic_size : 1;
return;
no_headers:
filedata->dynamic_addr = 0;
filedata->dynamic_size = 1;
}
static bool
get_program_headers (Filedata * filedata)
{
Elf_Internal_Phdr * phdrs;
if (filedata->program_headers != NULL)
return true;
if (filedata->file_header.e_phnum
* (is_32bit_elf ? sizeof (Elf32_External_Phdr) : sizeof (Elf64_External_Phdr))
>= filedata->file_size)
{
error (_("Too many program headers - %#x - the file is not that big\n"),
filedata->file_header.e_phnum);
return false;
}
phdrs = (Elf_Internal_Phdr *) cmalloc (filedata->file_header.e_phnum,
sizeof (Elf_Internal_Phdr));
if (phdrs == NULL)
{
error (_("Out of memory reading %u program headers\n"),
filedata->file_header.e_phnum);
return false;
}
if (is_32bit_elf
? get_32bit_program_headers (filedata, phdrs)
: get_64bit_program_headers (filedata, phdrs))
{
filedata->program_headers = phdrs;
return true;
}
free (phdrs);
return false;
}
static bool
get_program_headers (Filedata * filedata)
{
Elf_Internal_Phdr * phdrs;
if (filedata->program_headers != NULL)
return true;
if (filedata->file_header.e_phnum
* (is_32bit_elf ? sizeof (Elf32_External_Phdr) : sizeof (Elf64_External_Phdr))
>= filedata->file_size)
{
error (_("Too many program headers - %#x - the file is not that big\n"),
filedata->file_header.e_phnum);
return false;
}
phdrs = (Elf_Internal_Phdr *) cmalloc (filedata->file_header.e_phnum,
sizeof (Elf_Internal_Phdr));
if (phdrs == NULL)
{
error (_("Out of memory reading %u program headers\n"),
filedata->file_header.e_phnum);
return false;
}
if (is_32bit_elf
? get_32bit_program_headers (filedata, phdrs)
: get_64bit_program_headers (filedata, phdrs))
{
filedata->program_headers = phdrs;
return true;
}
free (phdrs);
return false;
}
static bool
get_32bit_program_headers (Filedata * filedata, Elf_Internal_Phdr * pheaders)
{
Elf32_External_Phdr * phdrs;
Elf32_External_Phdr * external;
Elf_Internal_Phdr * internal;
unsigned int i;
unsigned int size = filedata->file_header.e_phentsize;
unsigned int num = filedata->file_header.e_phnum;
if (size == 0 || num == 0)
return false;
if (size < sizeof * phdrs)
{
error (_("The e_phentsize field in the ELF header is less than the size of an ELF program header\n"));
return false;
}
if (size > sizeof * phdrs)
warn (_("The e_phentsize field in the ELF header is larger than the size of an ELF program header\n"));
phdrs = (Elf32_External_Phdr *) get_data (NULL, filedata, filedata->file_header.e_phoff,
size, num, _("program headers"));
if (phdrs == NULL)
return false;
for (i = 0, internal = pheaders, external = phdrs;
i < filedata->file_header.e_phnum;
i++, internal++, external++)
{
internal->p_type = BYTE_GET (external->p_type);
internal->p_offset = BYTE_GET (external->p_offset);
internal->p_vaddr = BYTE_GET (external->p_vaddr);
internal->p_paddr = BYTE_GET (external->p_paddr);
internal->p_filesz = BYTE_GET (external->p_filesz);
internal->p_memsz = BYTE_GET (external->p_memsz);
internal->p_flags = BYTE_GET (external->p_flags);
internal->p_align = BYTE_GET (external->p_align);
}
free (phdrs);
return true;
}
static bool
get_64bit_program_headers (Filedata * filedata, Elf_Internal_Phdr * pheaders)
{
Elf64_External_Phdr * phdrs;
Elf64_External_Phdr * external;
Elf_Internal_Phdr * internal;
unsigned int i;
unsigned int size = filedata->file_header.e_phentsize;
unsigned int num = filedata->file_header.e_phnum;
if (size == 0 || num == 0)
return false;
if (size < sizeof * phdrs)
{
error (_("The e_phentsize field in the ELF header is less than the size of an ELF program header\n"));
return false;
}
if (size > sizeof * phdrs)
warn (_("The e_phentsize field in the ELF header is larger than the size of an ELF program header\n"));
phdrs = (Elf64_External_Phdr *) get_data (NULL, filedata, filedata->file_header.e_phoff,
size, num, _("program headers"));
if (!phdrs)
return false;
for (i = 0, internal = pheaders, external = phdrs;
i < filedata->file_header.e_phnum;
i++, internal++, external++)
{
internal->p_type = BYTE_GET (external->p_type);
internal->p_flags = BYTE_GET (external->p_flags);
internal->p_offset = BYTE_GET (external->p_offset);
internal->p_vaddr = BYTE_GET (external->p_vaddr);
internal->p_paddr = BYTE_GET (external->p_paddr);
internal->p_filesz = BYTE_GET (external->p_filesz);
internal->p_memsz = BYTE_GET (external->p_memsz);
internal->p_align = BYTE_GET (external->p_align);
}
free (phdrs);
return true;
}
static bool
get_32bit_program_headers (Filedata * filedata, Elf_Internal_Phdr * pheaders)
{
Elf32_External_Phdr * phdrs;
Elf32_External_Phdr * external;
Elf_Internal_Phdr * internal;
unsigned int i;
unsigned int size = filedata->file_header.e_phentsize;
unsigned int num = filedata->file_header.e_phnum;
if (size == 0 || num == 0)
return false;
if (size < sizeof * phdrs)
{
error (_("The e_phentsize field in the ELF header is less than the size of an ELF program header\n"));
return false;
}
if (size > sizeof * phdrs)
warn (_("The e_phentsize field in the ELF header is larger than the size of an ELF program header\n"));
phdrs = (Elf32_External_Phdr *) get_data (NULL, filedata, filedata->file_header.e_phoff,
size, num, _("program headers"));
if (phdrs == NULL)
return false;
for (i = 0, internal = pheaders, external = phdrs;
i < filedata->file_header.e_phnum;
i++, internal++, external++)
{
internal->p_type = BYTE_GET (external->p_type);
internal->p_offset = BYTE_GET (external->p_offset);
internal->p_vaddr = BYTE_GET (external->p_vaddr);
internal->p_paddr = BYTE_GET (external->p_paddr);
internal->p_filesz = BYTE_GET (external->p_filesz);
internal->p_memsz = BYTE_GET (external->p_memsz);
internal->p_flags = BYTE_GET (external->p_flags);
internal->p_align = BYTE_GET (external->p_align);
}
free (phdrs);
return true;
}
static bool
get_64bit_program_headers (Filedata * filedata, Elf_Internal_Phdr * pheaders)
{
Elf64_External_Phdr * phdrs;
Elf64_External_Phdr * external;
Elf_Internal_Phdr * internal;
unsigned int i;
unsigned int size = filedata->file_header.e_phentsize;
unsigned int num = filedata->file_header.e_phnum;
if (size == 0 || num == 0)
return false;
if (size < sizeof * phdrs)
{
error (_("The e_phentsize field in the ELF header is less than the size of an ELF program header\n"));
return false;
}
if (size > sizeof * phdrs)
warn (_("The e_phentsize field in the ELF header is larger than the size of an ELF program header\n"));
phdrs = (Elf64_External_Phdr *) get_data (NULL, filedata, filedata->file_header.e_phoff,
size, num, _("program headers"));
if (!phdrs)
return false;
for (i = 0, internal = pheaders, external = phdrs;
i < filedata->file_header.e_phnum;
i++, internal++, external++)
{
internal->p_type = BYTE_GET (external->p_type);
internal->p_flags = BYTE_GET (external->p_flags);
internal->p_offset = BYTE_GET (external->p_offset);
internal->p_vaddr = BYTE_GET (external->p_vaddr);
internal->p_paddr = BYTE_GET (external->p_paddr);
internal->p_filesz = BYTE_GET (external->p_filesz);
internal->p_memsz = BYTE_GET (external->p_memsz);
internal->p_align = BYTE_GET (external->p_align);
}
free (phdrs);
return true;
}
typedef struct {
unsigned char p_type[4];
unsigned char p_offset[4];
unsigned char p_vaddr[4];
unsigned char p_paddr[4];
unsigned char p_filesz[4];
unsigned char p_memsz[4];
unsigned char p_flags[4];
unsigned char p_align[4];
} Elf32_External_Phdr;
typedef struct {
unsigned char p_type[4];
unsigned char p_flags[4];
unsigned char p_offset[8];
unsigned char p_vaddr[8];
unsigned char p_paddr[8];
unsigned char p_filesz[8];
unsigned char p_memsz[8];
unsigned char p_align[8];
} Elf64_External_Phdr;
typedef struct {
unsigned char p_type[4];
unsigned char p_offset[4];
unsigned char p_vaddr[4];
unsigned char p_paddr[4];
unsigned char p_filesz[4];
unsigned char p_memsz[4];
unsigned char p_flags[4];
unsigned char p_align[4];
} Elf32_External_Phdr;
typedef struct {
unsigned char p_type[4];
unsigned char p_flags[4];
unsigned char p_offset[8];
unsigned char p_vaddr[8];
unsigned char p_paddr[8];
unsigned char p_filesz[8];
unsigned char p_memsz[8];
unsigned char p_align[8];
} Elf64_External_Phdr;
static int load_elf_binary(struct linux_binprm *bprm)
{
struct file *interpreter = NULL;
unsigned long load_addr = 0, load_bias = 0;
int load_addr_set = 0;
unsigned long error;
struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL;
unsigned long elf_bss, elf_brk;
int bss_prot = 0;
int retval, i;
unsigned long elf_entry;
unsigned long interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc __maybe_unused = 0;
int executable_stack = EXSTACK_DEFAULT;
struct {
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
} *loc;
struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE;
struct pt_regs *regs;
loc = kmalloc(sizeof(*loc), GFP_KERNEL);
if (!loc) {
retval = -ENOMEM;
goto out_ret;
}
loc->elf_ex = *((struct elfhdr *)bprm->buf);
retval = -ENOEXEC;
if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out;
if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN)
goto out;
if (!elf_check_arch(&loc->elf_ex))
goto out;
if (elf_check_fdpic(&loc->elf_ex))
goto out;
if (!bprm->file->f_op->mmap)
goto out;
elf_phdata = load_elf_phdrs(&loc->elf_ex, bprm->file);
if (!elf_phdata)
goto out;
elf_ppnt = elf_phdata;
for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
char *elf_interpreter;
loff_t pos;
if (elf_ppnt->p_type != PT_INTERP)
continue;
retval = -ENOEXEC;
if (elf_ppnt->p_filesz > PATH_MAX || elf_ppnt->p_filesz < 2)
goto out_free_ph;
retval = -ENOMEM;
elf_interpreter = kmalloc(elf_ppnt->p_filesz, GFP_KERNEL);
if (!elf_interpreter)
goto out_free_ph;
pos = elf_ppnt->p_offset;
retval = kernel_read(bprm->file, elf_interpreter,
elf_ppnt->p_filesz, &pos);
if (retval != elf_ppnt->p_filesz) {
if (retval >= 0)
retval = -EIO;
goto out_free_interp;
}
retval = -ENOEXEC;
if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0')
goto out_free_interp;
interpreter = open_exec(elf_interpreter);
kfree(elf_interpreter);
retval = PTR_ERR(interpreter);
if (IS_ERR(interpreter))
goto out_free_ph;
would_dump(bprm, interpreter);
pos = 0;
retval = kernel_read(interpreter, &loc->interp_elf_ex,
sizeof(loc->interp_elf_ex), &pos);
if (retval != sizeof(loc->interp_elf_ex)) {
if (retval >= 0)
retval = -EIO;
goto out_free_dentry;
}
break;
out_free_interp:
kfree(elf_interpreter);
goto out_free_ph;
}
elf_ppnt = elf_phdata;
for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++)
switch (elf_ppnt->p_type) {
case PT_GNU_STACK:
if (elf_ppnt->p_flags & PF_X)
executable_stack = EXSTACK_ENABLE_X;
else
executable_stack = EXSTACK_DISABLE_X;
break;
case PT_LOPROC ... PT_HIPROC:
retval = arch_elf_pt_proc(&loc->elf_ex, elf_ppnt,
bprm->file, false,
&arch_state);
if (retval)
goto out_free_dentry;
break;
}
if (interpreter) {
retval = -ELIBBAD;
if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out_free_dentry;
if (!elf_check_arch(&loc->interp_elf_ex) ||
elf_check_fdpic(&loc->interp_elf_ex))
goto out_free_dentry;
interp_elf_phdata = load_elf_phdrs(&loc->interp_elf_ex,
interpreter);
if (!interp_elf_phdata)
goto out_free_dentry;
elf_ppnt = interp_elf_phdata;
for (i = 0; i < loc->interp_elf_ex.e_phnum; i++, elf_ppnt++)
switch (elf_ppnt->p_type) {
case PT_LOPROC ... PT_HIPROC:
retval = arch_elf_pt_proc(&loc->interp_elf_ex,
elf_ppnt, interpreter,
true, &arch_state);
if (retval)
goto out_free_dentry;
break;
}
}
retval = arch_check_elf(&loc->elf_ex,
!!interpreter, &loc->interp_elf_ex,
&arch_state);
if (retval)
goto out_free_dentry;
retval = flush_old_exec(bprm);
if (retval)
goto out_free_dentry;
SET_PERSONALITY2(loc->elf_ex, &arch_state);
if (elf_read_implies_exec(loc->elf_ex, executable_stack))
current->personality |= READ_IMPLIES_EXEC;
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
current->flags |= PF_RANDOMIZE;
setup_new_exec(bprm);
install_exec_creds(bprm);
retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
executable_stack);
if (retval < 0)
goto out_free_dentry;
elf_bss = 0;
elf_brk = 0;
start_code = ~0UL;
end_code = 0;
start_data = 0;
end_data = 0;
for(i = 0, elf_ppnt = elf_phdata;
i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot, elf_flags;
unsigned long k, vaddr;
unsigned long total_size = 0;
if (elf_ppnt->p_type != PT_LOAD)
continue;
if (unlikely (elf_brk > elf_bss)) {
unsigned long nbyte;
retval = set_brk(elf_bss + load_bias,
elf_brk + load_bias,
bss_prot);
if (retval)
goto out_free_dentry;
nbyte = ELF_PAGEOFFSET(elf_bss);
if (nbyte) {
nbyte = ELF_MIN_ALIGN - nbyte;
if (nbyte > elf_brk - elf_bss)
nbyte = elf_brk - elf_bss;
if (clear_user((void __user *)elf_bss +
load_bias, nbyte)) {
}
}
}
elf_prot = make_prot(elf_ppnt->p_flags);
elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
vaddr = elf_ppnt->p_vaddr;
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
elf_flags |= MAP_FIXED;
} else if (loc->elf_ex.e_type == ET_DYN) {
if (interpreter) {
load_bias = ELF_ET_DYN_BASE;
if (current->flags & PF_RANDOMIZE)
load_bias += arch_mmap_rnd();
elf_flags |= MAP_FIXED;
} else
load_bias = 0;
load_bias = ELF_PAGESTART(load_bias - vaddr);
total_size = total_mapping_size(elf_phdata,
loc->elf_ex.e_phnum);
if (!total_size) {
retval = -EINVAL;
goto out_free_dentry;
}
}
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
elf_prot, elf_flags, total_size);
if (BAD_ADDR(error)) {
retval = IS_ERR((void *)error) ?
PTR_ERR((void*)error) : -EINVAL;
goto out_free_dentry;
}
if (!load_addr_set) {
load_addr_set = 1;
load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);
if (loc->elf_ex.e_type == ET_DYN) {
load_bias += error -
ELF_PAGESTART(load_bias + vaddr);
load_addr += load_bias;
reloc_func_desc = load_bias;
}
}
k = elf_ppnt->p_vaddr;
if (k < start_code)
start_code = k;
if (start_data < k)
start_data = k;
if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz ||
elf_ppnt->p_memsz > TASK_SIZE ||
TASK_SIZE - elf_ppnt->p_memsz < k) {
retval = -EINVAL;
goto out_free_dentry;
}
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
if (k > elf_bss)
elf_bss = k;
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
end_code = k;
if (end_data < k)
end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
if (k > elf_brk) {
bss_prot = elf_prot;
elf_brk = k;
}
}
loc->elf_ex.e_entry += load_bias;
elf_bss += load_bias;
elf_brk += load_bias;
start_code += load_bias;
end_code += load_bias;
start_data += load_bias;
end_data += load_bias;
retval = set_brk(elf_bss, elf_brk, bss_prot);
if (retval)
goto out_free_dentry;
if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) {
retval = -EFAULT;
goto out_free_dentry;
}
if (interpreter) {
unsigned long interp_map_addr = 0;
elf_entry = load_elf_interp(&loc->interp_elf_ex,
interpreter,
&interp_map_addr,
load_bias, interp_elf_phdata);
if (!IS_ERR((void *)elf_entry)) {
interp_load_addr = elf_entry;
elf_entry += loc->interp_elf_ex.e_entry;
}
if (BAD_ADDR(elf_entry)) {
retval = IS_ERR((void *)elf_entry) ?
(int)elf_entry : -EINVAL;
goto out_free_dentry;
}
reloc_func_desc = interp_load_addr;
allow_write_access(interpreter);
fput(interpreter);
} else {
elf_entry = loc->elf_ex.e_entry;
if (BAD_ADDR(elf_entry)) {
retval = -EINVAL;
goto out_free_dentry;
}
}
kfree(interp_elf_phdata);
kfree(elf_phdata);
set_binfmt(&elf_format);
#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
retval = arch_setup_additional_pages(bprm, !!interpreter);
if (retval < 0)
goto out;
#endif
retval = create_elf_tables(bprm, &loc->elf_ex,
load_addr, interp_load_addr);
if (retval < 0)
goto out;
current->mm->end_code = end_code;
current->mm->start_code = start_code;
current->mm->start_data = start_data;
current->mm->end_data = end_data;
current->mm->start_stack = bprm->p;
if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) {
if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) &&
loc->elf_ex.e_type == ET_DYN && !interpreter)
current->mm->brk = current->mm->start_brk =
ELF_ET_DYN_BASE;
current->mm->brk = current->mm->start_brk =
arch_randomize_brk(current->mm);
#ifdef compat_brk_randomized
current->brk_randomized = 1;
#endif
}
if (current->personality & MMAP_PAGE_ZERO) {
error = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, 0);
}
regs = current_pt_regs();
#ifdef ELF_PLAT_INIT
ELF_PLAT_INIT(regs, reloc_func_desc);
#endif
finalize_exec(bprm);
start_thread(regs, elf_entry, bprm->p);
retval = 0;
out:
kfree(loc);
out_ret:
return retval;
out_free_dentry:
kfree(interp_elf_phdata);
allow_write_access(interpreter);
if (interpreter)
fput(interpreter);
out_free_ph:
kfree(elf_phdata);
goto out;
}
static int load_elf_binary(struct linux_binprm *bprm)
{
struct file *interpreter = NULL;
unsigned long load_addr = 0, load_bias = 0;
int load_addr_set = 0;
unsigned long error;
struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL;
unsigned long elf_bss, elf_brk;
int bss_prot = 0;
int retval, i;
unsigned long elf_entry;
unsigned long interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc __maybe_unused = 0;
int executable_stack = EXSTACK_DEFAULT;
struct {
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
} *loc;
struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE;
struct pt_regs *regs;
loc = kmalloc(sizeof(*loc), GFP_KERNEL);
if (!loc) {
retval = -ENOMEM;
goto out_ret;
}
loc->elf_ex = *((struct elfhdr *)bprm->buf);
retval = -ENOEXEC;
if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out;
if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN)
goto out;
if (!elf_check_arch(&loc->elf_ex))
goto out;
if (elf_check_fdpic(&loc->elf_ex))
goto out;
if (!bprm->file->f_op->mmap)
goto out;
elf_phdata = load_elf_phdrs(&loc->elf_ex, bprm->file);
if (!elf_phdata)
goto out;
elf_ppnt = elf_phdata;
for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
char *elf_interpreter;
loff_t pos;
if (elf_ppnt->p_type != PT_INTERP)
continue;
retval = -ENOEXEC;
if (elf_ppnt->p_filesz > PATH_MAX || elf_ppnt->p_filesz < 2)
goto out_free_ph;
retval = -ENOMEM;
elf_interpreter = kmalloc(elf_ppnt->p_filesz, GFP_KERNEL);
if (!elf_interpreter)
goto out_free_ph;
pos = elf_ppnt->p_offset;
retval = kernel_read(bprm->file, elf_interpreter,
elf_ppnt->p_filesz, &pos);
if (retval != elf_ppnt->p_filesz) {
if (retval >= 0)
retval = -EIO;
goto out_free_interp;
}
retval = -ENOEXEC;
if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0')
goto out_free_interp;
interpreter = open_exec(elf_interpreter);
kfree(elf_interpreter);
retval = PTR_ERR(interpreter);
if (IS_ERR(interpreter))
goto out_free_ph;
would_dump(bprm, interpreter);
pos = 0;
retval = kernel_read(interpreter, &loc->interp_elf_ex,
sizeof(loc->interp_elf_ex), &pos);
if (retval != sizeof(loc->interp_elf_ex)) {
if (retval >= 0)
retval = -EIO;
goto out_free_dentry;
}
break;
out_free_interp:
kfree(elf_interpreter);
goto out_free_ph;
}
elf_ppnt = elf_phdata;
for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++)
switch (elf_ppnt->p_type) {
case PT_GNU_STACK:
if (elf_ppnt->p_flags & PF_X)
executable_stack = EXSTACK_ENABLE_X;
else
executable_stack = EXSTACK_DISABLE_X;
break;
case PT_LOPROC ... PT_HIPROC:
retval = arch_elf_pt_proc(&loc->elf_ex, elf_ppnt,
bprm->file, false,
&arch_state);
if (retval)
goto out_free_dentry;
break;
}
if (interpreter) {
retval = -ELIBBAD;
if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out_free_dentry;
if (!elf_check_arch(&loc->interp_elf_ex) ||
elf_check_fdpic(&loc->interp_elf_ex))
goto out_free_dentry;
interp_elf_phdata = load_elf_phdrs(&loc->interp_elf_ex,
interpreter);
if (!interp_elf_phdata)
goto out_free_dentry;
elf_ppnt = interp_elf_phdata;
for (i = 0; i < loc->interp_elf_ex.e_phnum; i++, elf_ppnt++)
switch (elf_ppnt->p_type) {
case PT_LOPROC ... PT_HIPROC:
retval = arch_elf_pt_proc(&loc->interp_elf_ex,
elf_ppnt, interpreter,
true, &arch_state);
if (retval)
goto out_free_dentry;
break;
}
}
retval = arch_check_elf(&loc->elf_ex,
!!interpreter, &loc->interp_elf_ex,
&arch_state);
if (retval)
goto out_free_dentry;
retval = flush_old_exec(bprm);
if (retval)
goto out_free_dentry;
SET_PERSONALITY2(loc->elf_ex, &arch_state);
if (elf_read_implies_exec(loc->elf_ex, executable_stack))
current->personality |= READ_IMPLIES_EXEC;
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
current->flags |= PF_RANDOMIZE;
setup_new_exec(bprm);
install_exec_creds(bprm);
retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
executable_stack);
if (retval < 0)
goto out_free_dentry;
elf_bss = 0;
elf_brk = 0;
start_code = ~0UL;
end_code = 0;
start_data = 0;
end_data = 0;
for(i = 0, elf_ppnt = elf_phdata;
i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot, elf_flags;
unsigned long k, vaddr;
unsigned long total_size = 0;
if (elf_ppnt->p_type != PT_LOAD)
continue;
if (unlikely (elf_brk > elf_bss)) {
unsigned long nbyte;
retval = set_brk(elf_bss + load_bias,
elf_brk + load_bias,
bss_prot);
if (retval)
goto out_free_dentry;
nbyte = ELF_PAGEOFFSET(elf_bss);
if (nbyte) {
nbyte = ELF_MIN_ALIGN - nbyte;
if (nbyte > elf_brk - elf_bss)
nbyte = elf_brk - elf_bss;
if (clear_user((void __user *)elf_bss +
load_bias, nbyte)) {
}
}
}
elf_prot = make_prot(elf_ppnt->p_flags);
elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
vaddr = elf_ppnt->p_vaddr;
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
elf_flags |= MAP_FIXED;
} else if (loc->elf_ex.e_type == ET_DYN) {
if (interpreter) {
load_bias = ELF_ET_DYN_BASE;
if (current->flags & PF_RANDOMIZE)
load_bias += arch_mmap_rnd();
elf_flags |= MAP_FIXED;
} else
load_bias = 0;
load_bias = ELF_PAGESTART(load_bias - vaddr);
total_size = total_mapping_size(elf_phdata,
loc->elf_ex.e_phnum);
if (!total_size) {
retval = -EINVAL;
goto out_free_dentry;
}
}
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
elf_prot, elf_flags, total_size);
if (BAD_ADDR(error)) {
retval = IS_ERR((void *)error) ?
PTR_ERR((void*)error) : -EINVAL;
goto out_free_dentry;
}
if (!load_addr_set) {
load_addr_set = 1;
load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);
if (loc->elf_ex.e_type == ET_DYN) {
load_bias += error -
ELF_PAGESTART(load_bias + vaddr);
load_addr += load_bias;
reloc_func_desc = load_bias;
}
}
k = elf_ppnt->p_vaddr;
if (k < start_code)
start_code = k;
if (start_data < k)
start_data = k;
if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz ||
elf_ppnt->p_memsz > TASK_SIZE ||
TASK_SIZE - elf_ppnt->p_memsz < k) {
retval = -EINVAL;
goto out_free_dentry;
}
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
if (k > elf_bss)
elf_bss = k;
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
end_code = k;
if (end_data < k)
end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2025-12-2 18:34
被nothing233编辑
,原因: 增加流程图