Update copyright information.
[ksplice.git] / inspect.c
blobf5bc7fb1e8636a4b8e6a47271945da67f470b942
1 /* Copyright (C) 2008 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 unsigned short *line;
202 const char *const *strp;
203 struct supersect *data_ss;
204 switch(kpatch->type) {
205 case KSPLICE_PATCH_TEXT:
206 return strprintf("text\n repladdr: %s", str_pointer
207 (ss, (void *const *)&kpatch->repladdr));
208 case KSPLICE_PATCH_BUGLINE:
209 line = read_pointer(ss, &kpatch->contents, NULL);
210 return strprintf("bugline\n line: %hx", *line);
211 case KSPLICE_PATCH_DATA:
212 return strprintf("data\n size: %x", kpatch->size);
213 case KSPLICE_PATCH_EXPORT:
214 strp = read_pointer(ss, &kpatch->contents, &data_ss);
215 return strprintf("export\n newname: %s",
216 read_string(data_ss, strp));
217 default:
218 return "unknown";
222 void show_ksplice_patch(struct supersect *ss,
223 const struct ksplice_patch *kpatch)
225 printf(" type: %s\n"
226 " oldaddr: %s\n\n",
227 str_ksplice_patch_type(ss, kpatch),
228 str_pointer(ss, (void *const *)&kpatch->oldaddr));
231 void show_ksplice_patches(struct supersect *kpatch_ss)
233 const struct ksplice_patch *kpatch;
234 for (kpatch = kpatch_ss->contents.data; (void *)kpatch <
235 kpatch_ss->contents.data + kpatch_ss->contents.size; kpatch++)
236 show_ksplice_patch(kpatch_ss, kpatch);
239 void show_ksplice_call(struct supersect *ss, void *const *kcall)
241 printf("%s\n", str_pointer(ss, kcall));
244 void show_ksplice_calls(struct supersect *kcall_ss)
246 void *const *kcall;
247 for (kcall = kcall_ss->contents.data; (void *)kcall <
248 kcall_ss->contents.data + kcall_ss->contents.size; kcall++)
249 show_ksplice_call(kcall_ss, kcall);
252 void show_ksplice_system_map(struct supersect *ss,
253 const struct ksplice_system_map *smap)
255 printf("%s %s\n",
256 read_string(ss, &smap->label),
257 str_ulong_vec(ss, &smap->candidates, &smap->nr_candidates));
260 void show_ksplice_system_maps(struct supersect *smap_ss)
262 const struct ksplice_system_map *smap;
263 for (smap = smap_ss->contents.data;
264 (void *)smap < smap_ss->contents.data + smap_ss->contents.size;
265 smap++)
266 show_ksplice_system_map(smap_ss, smap);
269 struct inspect_section {
270 const char *prefix;
271 const char *header;
272 const char *notfound;
273 void (*show)(struct supersect *ss);
276 const struct inspect_section inspect_sections[] = {
278 .prefix = ".ksplice_init_relocs",
279 .header = "KSPLICE INIT RELOCATIONS",
280 .notfound = "No ksplice init relocations.\n",
281 .show = show_ksplice_relocs,
284 .prefix = ".ksplice_relocs",
285 .header = "KSPLICE RELOCATIONS",
286 .notfound = "No ksplice relocations.\n",
287 .show = show_ksplice_relocs,
290 .prefix = ".ksplice_sections",
291 .header = "KSPLICE SECTIONS",
292 .notfound = "No ksplice sections.\n",
293 .show = show_ksplice_sections,
296 .prefix = ".ksplice_patches",
297 .header = "KSPLICE PATCHES",
298 .notfound = "No ksplice patches.\n",
299 .show = show_ksplice_patches,
302 .prefix = ".ksplice_call",
303 .header = "KSPLICE CALLS",
304 .notfound = "No ksplice calls.\n",
305 .show = show_ksplice_calls,
308 .prefix = ".ksplice_system_map",
309 .header = "KSPLICE SYSTEM.MAP",
310 .notfound = "No ksplice System.map.\n",
311 .show = show_ksplice_system_maps,
313 }, *const inspect_sections_end = *(&inspect_sections + 1);
315 static void load_ksplice_reloc_offsets(struct superbfd *sbfd)
317 kreloc_section_hash_init(&ksplice_relocs);
319 asection *sect;
320 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
321 struct supersect *ss = fetch_supersect(sbfd, sect);
322 if (!starts_with(ss->name, ".ksplice_relocs") &&
323 !starts_with(ss->name, ".ksplice_init_relocs"))
324 continue;
325 struct ksplice_reloc *kreloc;
326 for (kreloc = ss->contents.data;
327 (void *)kreloc < ss->contents.data + ss->contents.size;
328 kreloc++) {
329 struct supersect *sym_ss;
330 const void *ptr =
331 read_pointer(ss, (void *const *)&kreloc->blank_addr,
332 &sym_ss);
333 char *key = strprintf("%p", ptr);
334 struct kreloc_section *ks, **ksp =
335 kreloc_section_hash_lookup(&ksplice_relocs, key,
336 TRUE);
337 free(key);
338 assert(*ksp == NULL);
339 ks = malloc(sizeof(*ks));
340 *ksp = ks;
341 ks->reloc = kreloc;
342 ks->ss = ss;
347 static void show_inspect_section(struct superbfd *sbfd,
348 const struct inspect_section *isect)
350 bool found = false;
351 asection *sect;
352 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
353 struct supersect *ss = fetch_supersect(sbfd, sect);
354 if (starts_with(ss->name, isect->prefix) &&
355 ss->contents.size != 0) {
356 printf("%s IN [%s]:\n", isect->header, sect->name);
357 found = true;
358 isect->show(ss);
361 if (!found)
362 printf("%s", isect->notfound);
363 printf("\n");
366 int main(int argc, char *argv[])
368 bfd *ibfd;
370 assert(argc >= 1);
371 bfd_init();
372 ibfd = bfd_openr(argv[1], NULL);
373 assert(ibfd);
375 char **matching;
376 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
378 struct superbfd *sbfd = fetch_superbfd(ibfd);
379 load_ksplice_reloc_offsets(sbfd);
380 const struct inspect_section *isect;
381 for (isect = inspect_sections; isect < inspect_sections_end; isect++)
382 show_inspect_section(sbfd, isect);
384 return 0;