1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #include <byteswap.h> |
3 | #include <stdbool.h> |
4 | #include <stdio.h> |
5 | #include <stdlib.h> |
6 | #include <stdarg.h> |
7 | #include <string.h> |
8 | #include <sys/types.h> |
9 | #include <sys/stat.h> |
10 | #include <sys/mman.h> |
11 | #include <fcntl.h> |
12 | #include <unistd.h> |
13 | #include <elf.h> |
14 | #include "../../include/linux/module_symbol.h" |
15 | |
16 | #include <list_types.h> |
17 | #include "elfconfig.h" |
18 | |
19 | /* On BSD-alike OSes elf.h defines these according to host's word size */ |
20 | #undef ELF_ST_BIND |
21 | #undef ELF_ST_TYPE |
22 | #undef ELF_R_SYM |
23 | #undef ELF_R_TYPE |
24 | |
25 | #if KERNEL_ELFCLASS == ELFCLASS32 |
26 | |
27 | #define Elf_Ehdr Elf32_Ehdr |
28 | #define Elf_Shdr Elf32_Shdr |
29 | #define Elf_Sym Elf32_Sym |
30 | #define Elf_Addr Elf32_Addr |
31 | #define Elf_Section Elf32_Half |
32 | #define ELF_ST_BIND ELF32_ST_BIND |
33 | #define ELF_ST_TYPE ELF32_ST_TYPE |
34 | |
35 | #define Elf_Rel Elf32_Rel |
36 | #define Elf_Rela Elf32_Rela |
37 | #define ELF_R_SYM ELF32_R_SYM |
38 | #define ELF_R_TYPE ELF32_R_TYPE |
39 | #else |
40 | |
41 | #define Elf_Ehdr Elf64_Ehdr |
42 | #define Elf_Shdr Elf64_Shdr |
43 | #define Elf_Sym Elf64_Sym |
44 | #define Elf_Addr Elf64_Addr |
45 | #define Elf_Section Elf64_Half |
46 | #define ELF_ST_BIND ELF64_ST_BIND |
47 | #define ELF_ST_TYPE ELF64_ST_TYPE |
48 | |
49 | #define Elf_Rel Elf64_Rel |
50 | #define Elf_Rela Elf64_Rela |
51 | #define ELF_R_SYM ELF64_R_SYM |
52 | #define ELF_R_TYPE ELF64_R_TYPE |
53 | #endif |
54 | |
55 | #define bswap(x) \ |
56 | ({ \ |
57 | _Static_assert(sizeof(x) == 1 || sizeof(x) == 2 || \ |
58 | sizeof(x) == 4 || sizeof(x) == 8, "bug"); \ |
59 | (typeof(x))(sizeof(x) == 2 ? bswap_16(x) : \ |
60 | sizeof(x) == 4 ? bswap_32(x) : \ |
61 | sizeof(x) == 8 ? bswap_64(x) : \ |
62 | x); \ |
63 | }) |
64 | |
65 | #define TO_NATIVE(x) \ |
66 | (target_is_big_endian == host_is_big_endian ? x : bswap(x)) |
67 | |
68 | #define __get_unaligned_t(type, ptr) ({ \ |
69 | const struct { type x; } __attribute__((__packed__)) *__pptr = \ |
70 | (typeof(__pptr))(ptr); \ |
71 | __pptr->x; \ |
72 | }) |
73 | |
74 | #define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr)) |
75 | |
76 | #define get_unaligned_native(ptr) \ |
77 | ({ \ |
78 | typeof(*(ptr)) _val = get_unaligned(ptr); \ |
79 | TO_NATIVE(_val); \ |
80 | }) |
81 | |
82 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) |
83 | |
84 | #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) |
85 | |
86 | struct buffer { |
87 | char *p; |
88 | int pos; |
89 | int size; |
90 | }; |
91 | |
92 | void __attribute__((format(printf, 2, 3))) |
93 | buf_printf(struct buffer *buf, const char *fmt, ...); |
94 | |
95 | void |
96 | buf_write(struct buffer *buf, const char *s, int len); |
97 | |
98 | /** |
99 | * struct module_alias - auto-generated MODULE_ALIAS() |
100 | * |
101 | * @node: linked to module::aliases |
102 | * @str: a string for MODULE_ALIAS() |
103 | */ |
104 | struct module_alias { |
105 | struct list_head node; |
106 | char str[]; |
107 | }; |
108 | |
109 | /** |
110 | * struct module - represent a module (vmlinux or *.ko) |
111 | * |
112 | * @dump_file: path to the .symvers file if loaded from a file |
113 | * @aliases: list head for module_aliases |
114 | * @no_trim_symbol: .no_trim_symbol section data |
115 | * @no_trim_symbol_len: length of the .no_trim_symbol section |
116 | */ |
117 | struct module { |
118 | struct list_head list; |
119 | struct list_head exported_symbols; |
120 | struct list_head unresolved_symbols; |
121 | const char *dump_file; |
122 | bool is_gpl_compatible; |
123 | bool is_vmlinux; |
124 | bool seen; |
125 | bool has_init; |
126 | bool has_cleanup; |
127 | char srcversion[25]; |
128 | // Missing namespace dependencies |
129 | struct list_head missing_namespaces; |
130 | // Actual imported namespaces |
131 | struct list_head imported_namespaces; |
132 | struct list_head aliases; |
133 | char *no_trim_symbol; |
134 | unsigned int no_trim_symbol_len; |
135 | char name[]; |
136 | }; |
137 | |
138 | struct elf_info { |
139 | size_t size; |
140 | Elf_Ehdr *hdr; |
141 | Elf_Shdr *sechdrs; |
142 | Elf_Sym *symtab_start; |
143 | Elf_Sym *symtab_stop; |
144 | unsigned int export_symbol_secndx; /* .export_symbol section */ |
145 | char *strtab; |
146 | char *modinfo; |
147 | unsigned int modinfo_len; |
148 | char *no_trim_symbol; |
149 | unsigned int no_trim_symbol_len; |
150 | |
151 | /* support for 32bit section numbers */ |
152 | |
153 | unsigned int num_sections; /* max_secindex + 1 */ |
154 | unsigned int secindex_strings; |
155 | /* if Nth symbol table entry has .st_shndx = SHN_XINDEX, |
156 | * take shndx from symtab_shndx_start[N] instead */ |
157 | Elf32_Word *symtab_shndx_start; |
158 | Elf32_Word *symtab_shndx_stop; |
159 | |
160 | struct symsearch *symsearch; |
161 | }; |
162 | |
163 | /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ |
164 | static inline unsigned int get_secindex(const struct elf_info *info, |
165 | const Elf_Sym *sym) |
166 | { |
167 | unsigned int index = sym->st_shndx; |
168 | |
169 | /* |
170 | * Elf{32,64}_Sym::st_shndx is 2 byte. Big section numbers are available |
171 | * in the .symtab_shndx section. |
172 | */ |
173 | if (index == SHN_XINDEX) |
174 | return info->symtab_shndx_start[sym - info->symtab_start]; |
175 | |
176 | /* |
177 | * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of |
178 | * the way to UINT_MAX-255..UINT_MAX, to avoid conflicting with real |
179 | * section indices. |
180 | */ |
181 | if (index >= SHN_LORESERVE && index <= SHN_HIRESERVE) |
182 | return index - SHN_HIRESERVE - 1; |
183 | |
184 | return index; |
185 | } |
186 | |
187 | /* |
188 | * If there's no name there, ignore it; likewise, ignore it if it's |
189 | * one of the magic symbols emitted used by current tools. |
190 | * |
191 | * Internal symbols created by tools should be ignored by modpost. |
192 | */ |
193 | static inline bool is_valid_name(struct elf_info *elf, Elf_Sym *sym) |
194 | { |
195 | const char *name = elf->strtab + sym->st_name; |
196 | |
197 | if (!name || !strlen(s: name)) |
198 | return false; |
199 | return !is_mapping_symbol(str: name); |
200 | } |
201 | |
202 | /* symsearch.c */ |
203 | void symsearch_init(struct elf_info *elf); |
204 | void symsearch_finish(struct elf_info *elf); |
205 | Elf_Sym *symsearch_find_nearest(struct elf_info *elf, Elf_Addr addr, |
206 | unsigned int secndx, bool allow_negative, |
207 | Elf_Addr min_distance); |
208 | |
209 | /* file2alias.c */ |
210 | void handle_moddevtable(struct module *mod, struct elf_info *info, |
211 | Elf_Sym *sym, const char *symname); |
212 | |
213 | /* sumversion.c */ |
214 | void get_src_version(const char *modname, char sum[], unsigned sumlen); |
215 | |
216 | /* from modpost.c */ |
217 | extern bool target_is_big_endian; |
218 | extern bool host_is_big_endian; |
219 | const char *get_basename(const char *path); |
220 | char *read_text_file(const char *filename); |
221 | char *get_line(char **stringp); |
222 | void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym); |
223 | |
224 | void __attribute__((format(printf, 2, 3))) |
225 | modpost_log(bool is_error, const char *fmt, ...); |
226 | |
227 | /* |
228 | * warn - show the given message, then let modpost continue running, still |
229 | * allowing modpost to exit successfully. This should be used when |
230 | * we still allow to generate vmlinux and modules. |
231 | * |
232 | * error - show the given message, then let modpost continue running, but fail |
233 | * in the end. This should be used when we should stop building vmlinux |
234 | * or modules, but we can continue running modpost to catch as many |
235 | * issues as possible. |
236 | * |
237 | * fatal - show the given message, and bail out immediately. This should be |
238 | * used when there is no point to continue running modpost. |
239 | */ |
240 | #define warn(fmt, args...) modpost_log(false, fmt, ##args) |
241 | #define error(fmt, args...) modpost_log(true, fmt, ##args) |
242 | #define fatal(fmt, args...) do { error(fmt, ##args); exit(1); } while (1) |
243 | |