Makefile.ksplice: Rewrite ksplice-cow-check as a wrapper function.
[ksplice.git] / inspect.c
blob5c0244b76706fba5d0c5131a12c4a9031349861b
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 case KSPLICE_HOWTO_SYMBOL:
129 return "symbol";
130 default:
131 return "unknown";
135 void show_ksplice_reloc(struct supersect *ss,
136 const struct ksplice_reloc *kreloc)
138 struct supersect *khowto_ss;
139 const struct ksplice_reloc_howto *khowto =
140 read_pointer(ss, (void *const *)&kreloc->howto, &khowto_ss);
141 printf(" blank_addr: %s size: %x\n"
142 " type: %s\n"
143 " symbol: %s\n"
144 " insn_addend: %lx\n"
145 " target_addend: %lx\n"
146 " pcrel: %x dst_mask: %lx rightshift: %x signed_addend: %x\n"
147 "\n",
148 str_pointer(ss, (void *const *)&kreloc->blank_addr),
149 read_num(khowto_ss, &khowto->size),
150 str_howto_type(khowto),
151 str_ksplice_symbolp(ss, &kreloc->symbol),
152 read_num(ss, &kreloc->insn_addend),
153 read_num(ss, &kreloc->target_addend),
154 read_num(khowto_ss, &khowto->pcrel),
155 read_num(khowto_ss, &khowto->dst_mask),
156 read_num(khowto_ss, &khowto->rightshift),
157 read_num(khowto_ss, &khowto->signed_addend));
160 void show_ksplice_relocs(struct supersect *kreloc_ss)
162 const struct ksplice_reloc *kreloc;
163 for (kreloc = kreloc_ss->contents.data; (void *)kreloc <
164 kreloc_ss->contents.data + kreloc_ss->contents.size; kreloc++)
165 show_ksplice_reloc(kreloc_ss, kreloc);
168 void show_ksplice_section_flags(const struct ksplice_section *ksect)
170 printf(" flags:");
171 if (ksect->flags & KSPLICE_SECTION_RODATA)
172 printf(" rodata");
173 if (ksect->flags & KSPLICE_SECTION_TEXT)
174 printf(" text");
175 if (ksect->flags & KSPLICE_SECTION_DATA)
176 printf(" data");
177 printf("\n");
180 void show_ksplice_section(struct supersect *ss,
181 const struct ksplice_section *ksect)
183 printf(" symbol: %s\n"
184 " address: %s size: %lx\n",
185 str_ksplice_symbolp(ss, &ksect->symbol),
186 str_pointer(ss, (void *const *)&ksect->address),
187 read_num(ss, &ksect->size));
188 show_ksplice_section_flags(ksect);
189 printf("\n");
192 void show_ksplice_sections(struct supersect *ksect_ss)
194 struct ksplice_section *ksect;
195 for (ksect = ksect_ss->contents.data; (void *)ksect <
196 ksect_ss->contents.data + ksect_ss->contents.size; ksect++)
197 show_ksplice_section(ksect_ss, ksect);
200 const char *str_ksplice_patch_type(struct supersect *ss,
201 const struct ksplice_patch *kpatch)
203 const char *const *strp;
204 struct supersect *data_ss;
205 switch(kpatch->type) {
206 case KSPLICE_PATCH_TEXT:
207 return strprintf("text\n repladdr: %s", str_pointer
208 (ss, (void *const *)&kpatch->repladdr));
209 case KSPLICE_PATCH_DATA:
210 return strprintf("data\n size: %x", kpatch->size);
211 case KSPLICE_PATCH_EXPORT:
212 strp = read_pointer(ss, &kpatch->contents, &data_ss);
213 return strprintf("export\n newname: %s",
214 read_string(data_ss, strp));
215 default:
216 return "unknown";
220 void show_ksplice_patch(struct supersect *ss,
221 const struct ksplice_patch *kpatch)
223 printf(" type: %s\n"
224 " oldaddr: %s\n\n",
225 str_ksplice_patch_type(ss, kpatch),
226 str_pointer(ss, (void *const *)&kpatch->oldaddr));
229 void show_ksplice_patches(struct supersect *kpatch_ss)
231 const struct ksplice_patch *kpatch;
232 for (kpatch = kpatch_ss->contents.data; (void *)kpatch <
233 kpatch_ss->contents.data + kpatch_ss->contents.size; kpatch++)
234 show_ksplice_patch(kpatch_ss, kpatch);
237 void show_ksplice_call(struct supersect *ss, void *const *kcall)
239 printf("%s\n", str_pointer(ss, kcall));
242 void show_ksplice_calls(struct supersect *kcall_ss)
244 void *const *kcall;
245 for (kcall = kcall_ss->contents.data; (void *)kcall <
246 kcall_ss->contents.data + kcall_ss->contents.size; kcall++)
247 show_ksplice_call(kcall_ss, kcall);
250 void show_ksplice_system_map(struct supersect *ss,
251 const struct ksplice_system_map *smap)
253 printf("%s %s\n",
254 read_string(ss, &smap->label),
255 str_ulong_vec(ss, &smap->candidates, &smap->nr_candidates));
258 void show_ksplice_system_maps(struct supersect *smap_ss)
260 const struct ksplice_system_map *smap;
261 for (smap = smap_ss->contents.data;
262 (void *)smap < smap_ss->contents.data + smap_ss->contents.size;
263 smap++)
264 show_ksplice_system_map(smap_ss, smap);
267 struct inspect_section {
268 const char *prefix;
269 const char *header;
270 const char *notfound;
271 void (*show)(struct supersect *ss);
274 const struct inspect_section inspect_sections[] = {
276 .prefix = ".ksplice_init_relocs",
277 .header = "KSPLICE INIT RELOCATIONS",
278 .notfound = "No ksplice init relocations.\n",
279 .show = show_ksplice_relocs,
282 .prefix = ".ksplice_relocs",
283 .header = "KSPLICE RELOCATIONS",
284 .notfound = "No ksplice relocations.\n",
285 .show = show_ksplice_relocs,
288 .prefix = ".ksplice_sections",
289 .header = "KSPLICE SECTIONS",
290 .notfound = "No ksplice sections.\n",
291 .show = show_ksplice_sections,
294 .prefix = ".ksplice_patches",
295 .header = "KSPLICE PATCHES",
296 .notfound = "No ksplice patches.\n",
297 .show = show_ksplice_patches,
300 .prefix = ".ksplice_call",
301 .header = "KSPLICE CALLS",
302 .notfound = "No ksplice calls.\n",
303 .show = show_ksplice_calls,
306 .prefix = ".ksplice_system_map",
307 .header = "KSPLICE SYSTEM.MAP",
308 .notfound = "No ksplice System.map.\n",
309 .show = show_ksplice_system_maps,
311 }, *const inspect_sections_end = *(&inspect_sections + 1);
313 static void load_ksplice_reloc_offsets(struct superbfd *sbfd)
315 kreloc_section_hash_init(&ksplice_relocs);
317 asection *sect;
318 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
319 struct supersect *ss = fetch_supersect(sbfd, sect);
320 if (!strstarts(ss->name, ".ksplice_relocs") &&
321 !strstarts(ss->name, ".ksplice_init_relocs"))
322 continue;
323 struct ksplice_reloc *kreloc;
324 for (kreloc = ss->contents.data;
325 (void *)kreloc < ss->contents.data + ss->contents.size;
326 kreloc++) {
327 const struct ksplice_reloc_howto *khowto =
328 read_pointer(ss, (void *const *)&kreloc->howto,
329 NULL);
330 if (khowto->size == 0)
331 continue;
333 struct supersect *sym_ss;
334 const void *ptr =
335 read_pointer(ss, (void *const *)&kreloc->blank_addr,
336 &sym_ss);
337 char *key = strprintf("%p", ptr);
338 struct kreloc_section *ks, **ksp =
339 kreloc_section_hash_lookup(&ksplice_relocs, key,
340 TRUE);
341 free(key);
342 assert(*ksp == NULL);
343 ks = malloc(sizeof(*ks));
344 *ksp = ks;
345 ks->reloc = kreloc;
346 ks->ss = ss;
351 static void show_inspect_section(struct superbfd *sbfd,
352 const struct inspect_section *isect)
354 bool found = false;
355 asection *sect;
356 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
357 struct supersect *ss = fetch_supersect(sbfd, sect);
358 if (strstarts(ss->name, isect->prefix) &&
359 ss->contents.size != 0) {
360 printf("%s IN [%s]:\n", isect->header, sect->name);
361 found = true;
362 isect->show(ss);
365 if (!found)
366 printf("%s", isect->notfound);
367 printf("\n");
370 int main(int argc, char *argv[])
372 bfd *ibfd;
374 assert(argc >= 1);
375 bfd_init();
376 ibfd = bfd_openr(argv[1], NULL);
377 assert(ibfd);
379 char **matching;
380 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
382 struct superbfd *sbfd = fetch_superbfd(ibfd);
383 load_ksplice_reloc_offsets(sbfd);
384 const struct inspect_section *isect;
385 for (isect = inspect_sections; isect < inspect_sections_end; isect++)
386 show_inspect_section(sbfd, isect);
388 return 0;