Never inline init_symbol_arrays, to avoid conflicting stack garbage.
[ksplice.git] / inspect.c
blob3246f2131a9d208ac76e04b1ee1486d1a70d25e0
1 /* Copyright (C) 2008-2009 Ksplice, Inc.
2 * Authors: Anders Kaseorg, Tim Abbott, Jeff Arnold
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
15 * 02110-1301, USA.
18 /* Always define KSPLICE_STANDALONE, even if you're using integrated Ksplice.
19 inspect won't compile without it. */
20 #define KSPLICE_STANDALONE
22 #define _GNU_SOURCE
23 #include "objcommon.h"
24 #include "kmodsrc/ksplice.h"
25 #include <stdio.h>
27 char *str_pointer(struct supersect *ss, void *const *addr);
29 struct kreloc_section {
30 struct supersect *ss;
31 const struct ksplice_reloc *reloc;
34 #define kreloc_section_init(ks) *(ks) = NULL
35 DEFINE_HASH_TYPE(struct kreloc_section *, kreloc_section_hash,
36 kreloc_section_hash_init, kreloc_section_hash_free,
37 kreloc_section_hash_lookup, kreloc_section_init);
38 struct kreloc_section_hash ksplice_relocs;
40 char *str_ulong_vec(struct supersect *ss, const unsigned long *const *datap,
41 const unsigned long *sizep)
43 struct supersect *data_ss;
44 const unsigned long *data =
45 read_pointer(ss, (void *const *)datap, &data_ss);
46 unsigned long size = read_num(ss, sizep);
48 char *buf = NULL;
49 size_t bufsize = 0;
50 FILE *fp = open_memstream(&buf, &bufsize);
51 fprintf(fp, "[ ");
52 size_t i;
53 for (i = 0; i < size; ++i)
54 fprintf(fp, "%lx ", read_num(data_ss, &data[i]));
55 fprintf(fp, "]");
56 fclose(fp);
57 return buf;
60 static const struct ksplice_reloc *
61 find_ksplice_reloc(struct supersect *ss, void *const *addr,
62 struct supersect **reloc_ss)
64 char *key = strprintf("%p", addr);
65 struct kreloc_section **ksp =
66 kreloc_section_hash_lookup(&ksplice_relocs, key, FALSE);
67 free(key);
68 if (ksp == NULL)
69 return NULL;
70 *reloc_ss = (*ksp)->ss;
71 return (*ksp)->reloc;
74 char *str_ksplice_symbol(struct supersect *ss,
75 const struct ksplice_symbol *ksymbol)
77 return strprintf("%s (%s)",
78 read_string(ss, &ksymbol->label),
79 read_string(ss, &ksymbol->name));
82 char *str_ksplice_symbolp(struct supersect *ptr_ss,
83 struct ksplice_symbol *const *ksymbolp)
85 asymbol *sym;
86 bfd_vma offset = read_reloc(ptr_ss, ksymbolp, sizeof(*ksymbolp), &sym);
87 if (bfd_is_const_section(sym->section))
88 return strprintf("*(%s)",
89 str_pointer(ptr_ss, (void *const *)ksymbolp));
90 struct supersect *ksymbol_ss = fetch_supersect(ptr_ss->parent,
91 sym->section);
92 return str_ksplice_symbol(ksymbol_ss, ksymbol_ss->contents.data +
93 sym->value + offset);
96 char *str_pointer(struct supersect *ss, void *const *addr)
98 asymbol *sym;
99 struct supersect *kreloc_ss;
100 const struct ksplice_reloc *kreloc =
101 find_ksplice_reloc(ss, addr, &kreloc_ss);
102 if (kreloc == NULL) {
103 bfd_vma offset = read_reloc(ss, addr, sizeof(*addr), &sym);
104 return strprintf("%s+%lx", sym->name, (unsigned long)offset);
105 } else {
106 return strprintf("[%s]+%lx",
107 str_ksplice_symbolp(kreloc_ss,
108 &kreloc->symbol),
109 kreloc->target_addend);
113 static const char *str_howto_type(const struct ksplice_reloc_howto *howto)
115 switch (howto->type) {
116 case KSPLICE_HOWTO_RELOC:
117 return "reloc";
118 case KSPLICE_HOWTO_RELOC_PATCH:
119 return "reloc(patch)";
120 case KSPLICE_HOWTO_TIME:
121 return "time";
122 case KSPLICE_HOWTO_DATE:
123 return "date";
124 case KSPLICE_HOWTO_BUG:
125 return "bug";
126 case KSPLICE_HOWTO_EXTABLE:
127 return "extable";
128 default:
129 return "unknown";
133 void show_ksplice_reloc(struct supersect *ss,
134 const struct ksplice_reloc *kreloc)
136 struct supersect *khowto_ss;
137 const struct ksplice_reloc_howto *khowto =
138 read_pointer(ss, (void *const *)&kreloc->howto, &khowto_ss);
139 printf(" blank_addr: %s size: %x\n"
140 " type: %s\n"
141 " symbol: %s\n"
142 " insn_addend: %lx\n"
143 " target_addend: %lx\n"
144 " pcrel: %x dst_mask: %lx rightshift: %x signed_addend: %x\n"
145 "\n",
146 str_pointer(ss, (void *const *)&kreloc->blank_addr),
147 read_num(khowto_ss, &khowto->size),
148 str_howto_type(khowto),
149 str_ksplice_symbolp(ss, &kreloc->symbol),
150 read_num(ss, &kreloc->insn_addend),
151 read_num(ss, &kreloc->target_addend),
152 read_num(khowto_ss, &khowto->pcrel),
153 read_num(khowto_ss, &khowto->dst_mask),
154 read_num(khowto_ss, &khowto->rightshift),
155 read_num(khowto_ss, &khowto->signed_addend));
158 void show_ksplice_relocs(struct supersect *kreloc_ss)
160 const struct ksplice_reloc *kreloc;
161 for (kreloc = kreloc_ss->contents.data; (void *)kreloc <
162 kreloc_ss->contents.data + kreloc_ss->contents.size; kreloc++)
163 show_ksplice_reloc(kreloc_ss, kreloc);
166 void show_ksplice_section_flags(const struct ksplice_section *ksect)
168 printf(" flags:");
169 if (ksect->flags & KSPLICE_SECTION_RODATA)
170 printf(" rodata");
171 if (ksect->flags & KSPLICE_SECTION_TEXT)
172 printf(" text");
173 if (ksect->flags & KSPLICE_SECTION_DATA)
174 printf(" data");
175 printf("\n");
178 void show_ksplice_section(struct supersect *ss,
179 const struct ksplice_section *ksect)
181 printf(" symbol: %s\n"
182 " address: %s size: %lx\n",
183 str_ksplice_symbolp(ss, &ksect->symbol),
184 str_pointer(ss, (void *const *)&ksect->address),
185 read_num(ss, &ksect->size));
186 show_ksplice_section_flags(ksect);
187 printf("\n");
190 void show_ksplice_sections(struct supersect *ksect_ss)
192 struct ksplice_section *ksect;
193 for (ksect = ksect_ss->contents.data; (void *)ksect <
194 ksect_ss->contents.data + ksect_ss->contents.size; ksect++)
195 show_ksplice_section(ksect_ss, ksect);
198 const char *str_ksplice_patch_type(struct supersect *ss,
199 const struct ksplice_patch *kpatch)
201 const char *const *strp;
202 struct supersect *data_ss;
203 switch(kpatch->type) {
204 case KSPLICE_PATCH_TEXT:
205 return strprintf("text\n repladdr: %s", str_pointer
206 (ss, (void *const *)&kpatch->repladdr));
207 case KSPLICE_PATCH_DATA:
208 return strprintf("data\n size: %x", kpatch->size);
209 case KSPLICE_PATCH_EXPORT:
210 strp = read_pointer(ss, &kpatch->contents, &data_ss);
211 return strprintf("export\n newname: %s",
212 read_string(data_ss, strp));
213 default:
214 return "unknown";
218 void show_ksplice_patch(struct supersect *ss,
219 const struct ksplice_patch *kpatch)
221 printf(" type: %s\n"
222 " oldaddr: %s\n\n",
223 str_ksplice_patch_type(ss, kpatch),
224 str_pointer(ss, (void *const *)&kpatch->oldaddr));
227 void show_ksplice_patches(struct supersect *kpatch_ss)
229 const struct ksplice_patch *kpatch;
230 for (kpatch = kpatch_ss->contents.data; (void *)kpatch <
231 kpatch_ss->contents.data + kpatch_ss->contents.size; kpatch++)
232 show_ksplice_patch(kpatch_ss, kpatch);
235 void show_ksplice_call(struct supersect *ss, void *const *kcall)
237 printf("%s\n", str_pointer(ss, kcall));
240 void show_ksplice_calls(struct supersect *kcall_ss)
242 void *const *kcall;
243 for (kcall = kcall_ss->contents.data; (void *)kcall <
244 kcall_ss->contents.data + kcall_ss->contents.size; kcall++)
245 show_ksplice_call(kcall_ss, kcall);
248 void show_ksplice_system_map(struct supersect *ss,
249 const struct ksplice_system_map *smap)
251 printf("%s %s\n",
252 read_string(ss, &smap->label),
253 str_ulong_vec(ss, &smap->candidates, &smap->nr_candidates));
256 void show_ksplice_system_maps(struct supersect *smap_ss)
258 const struct ksplice_system_map *smap;
259 for (smap = smap_ss->contents.data;
260 (void *)smap < smap_ss->contents.data + smap_ss->contents.size;
261 smap++)
262 show_ksplice_system_map(smap_ss, smap);
265 struct inspect_section {
266 const char *prefix;
267 const char *header;
268 const char *notfound;
269 void (*show)(struct supersect *ss);
272 const struct inspect_section inspect_sections[] = {
274 .prefix = ".ksplice_init_relocs",
275 .header = "KSPLICE INIT RELOCATIONS",
276 .notfound = "No ksplice init relocations.\n",
277 .show = show_ksplice_relocs,
280 .prefix = ".ksplice_relocs",
281 .header = "KSPLICE RELOCATIONS",
282 .notfound = "No ksplice relocations.\n",
283 .show = show_ksplice_relocs,
286 .prefix = ".ksplice_sections",
287 .header = "KSPLICE SECTIONS",
288 .notfound = "No ksplice sections.\n",
289 .show = show_ksplice_sections,
292 .prefix = ".ksplice_patches",
293 .header = "KSPLICE PATCHES",
294 .notfound = "No ksplice patches.\n",
295 .show = show_ksplice_patches,
298 .prefix = ".ksplice_call",
299 .header = "KSPLICE CALLS",
300 .notfound = "No ksplice calls.\n",
301 .show = show_ksplice_calls,
304 .prefix = ".ksplice_system_map",
305 .header = "KSPLICE SYSTEM.MAP",
306 .notfound = "No ksplice System.map.\n",
307 .show = show_ksplice_system_maps,
309 }, *const inspect_sections_end = *(&inspect_sections + 1);
311 static void load_ksplice_reloc_offsets(struct superbfd *sbfd)
313 kreloc_section_hash_init(&ksplice_relocs);
315 asection *sect;
316 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
317 struct supersect *ss = fetch_supersect(sbfd, sect);
318 if (!strstarts(ss->name, ".ksplice_relocs") &&
319 !strstarts(ss->name, ".ksplice_init_relocs"))
320 continue;
321 struct ksplice_reloc *kreloc;
322 for (kreloc = ss->contents.data;
323 (void *)kreloc < ss->contents.data + ss->contents.size;
324 kreloc++) {
325 struct supersect *sym_ss;
326 const void *ptr =
327 read_pointer(ss, (void *const *)&kreloc->blank_addr,
328 &sym_ss);
329 char *key = strprintf("%p", ptr);
330 struct kreloc_section *ks, **ksp =
331 kreloc_section_hash_lookup(&ksplice_relocs, key,
332 TRUE);
333 free(key);
334 assert(*ksp == NULL);
335 ks = malloc(sizeof(*ks));
336 *ksp = ks;
337 ks->reloc = kreloc;
338 ks->ss = ss;
343 static void show_inspect_section(struct superbfd *sbfd,
344 const struct inspect_section *isect)
346 bool found = false;
347 asection *sect;
348 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
349 struct supersect *ss = fetch_supersect(sbfd, sect);
350 if (strstarts(ss->name, isect->prefix) &&
351 ss->contents.size != 0) {
352 printf("%s IN [%s]:\n", isect->header, sect->name);
353 found = true;
354 isect->show(ss);
357 if (!found)
358 printf("%s", isect->notfound);
359 printf("\n");
362 int main(int argc, char *argv[])
364 bfd *ibfd;
366 assert(argc >= 1);
367 bfd_init();
368 ibfd = bfd_openr(argv[1], NULL);
369 assert(ibfd);
371 char **matching;
372 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
374 struct superbfd *sbfd = fetch_superbfd(ibfd);
375 load_ksplice_reloc_offsets(sbfd);
376 const struct inspect_section *isect;
377 for (isect = inspect_sections; isect < inspect_sections_end; isect++)
378 show_inspect_section(sbfd, isect);
380 return 0;