modindex: getopt_long returns int not char (fix ppc64 bug)
[mit.git] / elfops_core.c
blob39fd4c330b1f130ae5b3ece5e9a6464c4d16b47e
1 #if defined(ELF32BIT)
3 #define PERBIT(x) x##32
4 #define ElfPERBIT(x) Elf32_##x
5 #define ELFPERBIT(x) ELF32_##x
6 /* 32-bit unsigned integer */
7 #define Elf32_Uint Elf32_Word
9 #elif defined(ELF64BIT)
11 #define PERBIT(x) x##64
12 #define ElfPERBIT(x) Elf64_##x
13 #define ELFPERBIT(x) ELF64_##x
14 /* 64-bit unsigned integer */
15 #define Elf64_Uint Elf64_Xword
17 #else
18 # error "Undefined ELF word length"
19 #endif
21 static void *PERBIT(get_section)(struct elf_file *module,
22 const char *secname,
23 ElfPERBIT(Shdr) **sechdr,
24 unsigned long *secsize)
26 void *data = module->data;
27 unsigned long len = module->len;
28 int conv = module->conv;
30 ElfPERBIT(Ehdr) *hdr;
31 ElfPERBIT(Shdr) *sechdrs;
32 ElfPERBIT(Off) e_shoff;
33 ElfPERBIT(Half) e_shnum, e_shstrndx;
34 ElfPERBIT(Off) secoffset;
36 const char *secnames;
37 unsigned int i;
39 if (len <= 0 || len < sizeof(*hdr))
40 return NULL;
42 hdr = data;
43 e_shoff = END(hdr->e_shoff, conv);
44 e_shnum = END(hdr->e_shnum, conv);
45 e_shstrndx = END(hdr->e_shstrndx, conv);
47 if (len < e_shoff + e_shnum * sizeof(sechdrs[0]))
48 return NULL;
50 sechdrs = data + e_shoff;
52 if (len < END(sechdrs[e_shstrndx].sh_offset, conv))
53 return NULL;
55 /* Find section by name; return header, pointer and size. */
56 secnames = data + END(sechdrs[e_shstrndx].sh_offset, conv);
57 for (i = 1; i < e_shnum; i++) {
58 if (streq(secnames + END(sechdrs[i].sh_name, conv), secname)) {
59 *secsize = END(sechdrs[i].sh_size, conv);
60 secoffset = END(sechdrs[i].sh_offset, conv);
61 if (sechdr)
62 *sechdr = sechdrs + i;
63 if (len < secoffset + *secsize)
64 return NULL;
65 return data + secoffset;
68 *secsize = 0;
69 return NULL;
72 /* Load the given section: NULL on error. */
73 static void *PERBIT(load_section)(struct elf_file *module,
74 const char *secname,
75 unsigned long *secsize)
77 return PERBIT(get_section)(module, secname, NULL, secsize);
80 static struct string_table *PERBIT(load_strings)(struct elf_file *module,
81 const char *secname,
82 struct string_table *tbl)
84 unsigned long size;
85 const char *strings;
87 strings = PERBIT(load_section)(module, secname, &size);
88 if (strings) {
89 /* Skip any zero padding. */
90 while (!strings[0]) {
91 strings++;
92 if (size-- <= 1)
93 return tbl;
95 for (; strings; strings = next_string(strings, &size))
96 tbl = NOFAIL(strtbl_add(strings, tbl));
98 return tbl;
101 static struct string_table *PERBIT(load_symbols)(struct elf_file *module)
103 struct PERBIT(kernel_symbol) *ksyms;
104 struct string_table *symtbl;
105 unsigned long i, size;
107 symtbl = NULL;
109 /* New-style: strings are in this section. */
110 symtbl = PERBIT(load_strings)(module, "__ksymtab_strings", symtbl);
111 if (symtbl) {
112 /* GPL symbols too */
113 return PERBIT(load_strings)(module, "__ksymtab_strings_gpl",
114 symtbl);
117 /* Old-style. */
118 ksyms = PERBIT(load_section)(module, "__ksymtab", &size);
119 for (i = 0; i < size / sizeof(struct PERBIT(kernel_symbol)); i++)
120 symtbl = NOFAIL(strtbl_add(ksyms[i].name, symtbl));
121 ksyms = PERBIT(load_section)(module, "__gpl_ksymtab", &size);
122 for (i = 0; i < size / sizeof(struct PERBIT(kernel_symbol)); i++)
123 symtbl = NOFAIL(strtbl_add(ksyms[i].name, symtbl));
125 return symtbl;
128 static char *PERBIT(get_aliases)(struct elf_file *module, unsigned long *size)
130 return PERBIT(load_section)(module, ".modalias", size);
133 static char *PERBIT(get_modinfo)(struct elf_file *module, unsigned long *size)
135 return PERBIT(load_section)(module, ".modinfo", size);
138 #ifndef STT_REGISTER
139 #define STT_REGISTER 13 /* Global register reserved to app. */
140 #endif
142 static struct string_table *PERBIT(load_dep_syms)(const char *pathname,
143 struct elf_file *module,
144 struct string_table **types)
146 unsigned int i;
147 unsigned long size;
148 char *strings;
149 ElfPERBIT(Sym) *syms;
150 ElfPERBIT(Ehdr) *hdr;
151 int handle_register_symbols;
152 struct string_table *names;
153 int conv;
155 names = NULL;
156 *types = NULL;
158 strings = PERBIT(load_section)(module, ".strtab", &size);
159 syms = PERBIT(load_section)(module, ".symtab", &size);
161 if (!strings || !syms) {
162 warn("Couldn't find symtab and strtab in module %s\n",
163 pathname);
164 return NULL;
167 hdr = module->data;
168 conv = module->conv;
170 handle_register_symbols =
171 (END(hdr->e_machine, conv) == EM_SPARC ||
172 END(hdr->e_machine, conv) == EM_SPARCV9);
174 for (i = 1; i < size / sizeof(syms[0]); i++) {
175 if (END(syms[i].st_shndx, conv) == SHN_UNDEF) {
176 /* Look for symbol */
177 const char *name;
178 int weak;
180 name = strings + END(syms[i].st_name, conv);
182 /* Not really undefined: sparc gcc 3.3 creates
183 U references when you have global asm
184 variables, to avoid anyone else misusing
185 them. */
186 if (handle_register_symbols
187 && (ELFPERBIT(ST_TYPE)(END(syms[i].st_info, conv))
188 == STT_REGISTER))
189 continue;
191 weak = (ELFPERBIT(ST_BIND)(END(syms[i].st_info, conv))
192 == STB_WEAK);
193 names = strtbl_add(name, names);
194 *types = strtbl_add(weak ? weak_sym : undef_sym, *types);
197 return names;
200 static void *PERBIT(deref_sym)(ElfPERBIT(Ehdr) *hdr,
201 ElfPERBIT(Shdr) *sechdrs,
202 ElfPERBIT(Sym) *sym,
203 unsigned int *secsize,
204 int conv)
206 /* In BSS? Happens for empty device tables on
207 * recent GCC versions. */
208 if (END(sechdrs[END(sym->st_shndx, conv)].sh_type,conv) == SHT_NOBITS)
209 return NULL;
211 if (secsize)
212 *secsize = END(sym->st_size, conv);
213 return (void *)hdr
214 + END(sechdrs[END(sym->st_shndx, conv)].sh_offset, conv)
215 + END(sym->st_value, conv);
218 /* FIXME: Check size, unless we end up using aliases anyway --RR */
219 static void PERBIT(fetch_tables)(struct elf_file *module,
220 struct module_tables *tables)
222 unsigned int i;
223 unsigned long size;
224 char *strings;
225 ElfPERBIT(Ehdr) *hdr;
226 ElfPERBIT(Sym) *syms;
227 ElfPERBIT(Shdr) *sechdrs;
228 int conv;
230 hdr = module->data;
231 conv = module->conv;
233 sechdrs = (void *)hdr + END(hdr->e_shoff, conv);
234 strings = PERBIT(load_section)(module, ".strtab", &size);
235 syms = PERBIT(load_section)(module, ".symtab", &size);
237 /* Don't warn again: we already have above */
238 if (!strings || !syms)
239 return;
241 tables->pci_table = NULL;
242 tables->usb_table = NULL;
243 tables->ccw_table = NULL;
244 tables->ieee1394_table = NULL;
245 tables->pnp_table = NULL;
246 tables->pnp_card_table = NULL;
247 tables->input_table = NULL;
248 tables->serio_table = NULL;
249 tables->of_table = NULL;
251 for (i = 0; i < size / sizeof(syms[0]); i++) {
252 char *name = strings + END(syms[i].st_name, conv);
254 if (!tables->pci_table && streq(name, "__mod_pci_device_table")) {
255 tables->pci_size = PERBIT(PCI_DEVICE_SIZE);
256 tables->pci_table = PERBIT(deref_sym)(hdr, sechdrs, &syms[i],
257 NULL, conv);
259 else if (!tables->usb_table && streq(name, "__mod_usb_device_table")) {
260 tables->usb_size = PERBIT(USB_DEVICE_SIZE);
261 tables->usb_table = PERBIT(deref_sym)(hdr, sechdrs, &syms[i],
262 NULL, conv);
264 else if (!tables->ccw_table && streq(name, "__mod_ccw_device_table")) {
265 tables->ccw_size = PERBIT(CCW_DEVICE_SIZE);
266 tables->ccw_table = PERBIT(deref_sym)(hdr, sechdrs, &syms[i],
267 NULL, conv);
269 else if (!tables->ieee1394_table && streq(name, "__mod_ieee1394_device_table")) {
270 tables->ieee1394_size = PERBIT(IEEE1394_DEVICE_SIZE);
271 tables->ieee1394_table = PERBIT(deref_sym)(hdr, sechdrs, &syms[i],
272 NULL, conv);
274 else if (!tables->pnp_table && streq(name, "__mod_pnp_device_table")) {
275 tables->pnp_size = PERBIT(PNP_DEVICE_SIZE);
276 tables->pnp_table = PERBIT(deref_sym)(hdr, sechdrs, &syms[i],
277 NULL, conv);
279 else if (!tables->pnp_card_table && streq(name, "__mod_pnp_card_device_table")) {
280 tables->pnp_card_size = PERBIT(PNP_CARD_DEVICE_SIZE);
281 tables->pnp_card_table = PERBIT(deref_sym)(hdr, sechdrs, &syms[i],
282 NULL, conv);
283 tables->pnp_card_offset = PERBIT(PNP_CARD_DEVICE_OFFSET);
285 else if (!tables->input_table && streq(name, "__mod_input_device_table")) {
286 tables->input_size = PERBIT(INPUT_DEVICE_SIZE);
287 tables->input_table = PERBIT(deref_sym)(hdr, sechdrs, &syms[i],
288 &tables->input_table_size,
289 conv);
291 else if (!tables->serio_table && streq(name, "__mod_serio_device_table")) {
292 tables->serio_size = PERBIT(SERIO_DEVICE_SIZE);
293 tables->serio_table = PERBIT(deref_sym)(hdr, sechdrs, &syms[i],
294 NULL, conv);
296 else if (!tables->of_table && streq(name, "__mod_of_device_table")) {
297 tables->of_size = PERBIT(OF_DEVICE_SIZE);
298 tables->of_table = PERBIT(deref_sym)(hdr, sechdrs, &syms[i],
299 NULL, conv);
305 * strip_section - tell the kernel to ignore the named section
307 static void PERBIT(strip_section)(struct elf_file *module, const char *secname)
309 void *p;
310 ElfPERBIT(Shdr) *sechdr;
311 unsigned long secsize;
313 p = PERBIT(get_section)(module, secname, &sechdr, &secsize);
314 if (p) {
315 ElfPERBIT(Uint) mask;
316 mask = ~((ElfPERBIT(Uint))SHF_ALLOC);
317 sechdr->sh_flags &= END(mask, module->conv);
321 static int PERBIT(dump_modversions)(struct elf_file *module)
323 unsigned long secsize;
324 struct PERBIT(modver_info) *info;
325 int n = 0;
327 info = module->ops->load_section(module, "__versions", &secsize);
328 if (!info)
329 return 0; /* not a kernel module */
330 if (secsize % sizeof(*info) != 0)
331 return -1; /* invalid section size */
333 for (n = 0; n < secsize / sizeof(*info); n++) {
334 #if defined(ELF32BIT)
335 printf("0x%08lx\t%s\n", (unsigned long)
336 #else /* defined(ELF64BIT) */
337 printf("0x%08llx\t%s\n", (unsigned long long)
338 #endif
339 END(info[n].crc, module->conv),
340 skip_dot(info[n].name));
342 return n;
345 struct module_ops PERBIT(mod_ops) = {
346 .load_section = PERBIT(load_section),
347 .load_symbols = PERBIT(load_symbols),
348 .load_dep_syms = PERBIT(load_dep_syms),
349 .fetch_tables = PERBIT(fetch_tables),
350 .get_aliases = PERBIT(get_aliases),
351 .get_modinfo = PERBIT(get_modinfo),
352 .strip_section = PERBIT(strip_section),
353 .dump_modvers = PERBIT(dump_modversions),
356 #undef PERBIT
357 #undef ElfPERBIT
358 #undef ELFPERBIT