Only use COW hooks in diff mode.
[ksplice.git] / inspect.c
blobf2636182e6675f5eb491fc6a05c01a7a39e5885d
1 /* Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
2 * Tim Abbott <tabbott@mit.edu>,
3 * Jeffrey Brian Arnold <jbarnold@mit.edu>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
16 * 02110-1301, USA.
19 /* Always define KSPLICE_STANDALONE, even if you're using integrated Ksplice.
20 inspect won't compile without it. */
21 #define KSPLICE_STANDALONE
23 #define _GNU_SOURCE
24 #include "objcommon.h"
25 #include "kmodsrc/ksplice.h"
26 #include <stdio.h>
28 char *str_pointer(struct supersect *ss, void *const *addr);
30 struct kreloc_section {
31 struct supersect *ss;
32 const struct ksplice_reloc *reloc;
35 #define kreloc_section_init(ks) *(ks) = NULL
36 DEFINE_HASH_TYPE(struct kreloc_section *, kreloc_section_hash,
37 kreloc_section_hash_init, kreloc_section_hash_free,
38 kreloc_section_hash_lookup, kreloc_section_init);
39 struct kreloc_section_hash ksplice_relocs;
41 char *str_ulong_vec(struct supersect *ss, const unsigned long *const *datap,
42 const unsigned long *sizep)
44 struct supersect *data_ss;
45 const unsigned long *data =
46 read_pointer(ss, (void *const *)datap, &data_ss);
47 unsigned long size = read_num(ss, sizep);
49 char *buf = NULL;
50 size_t bufsize = 0;
51 FILE *fp = open_memstream(&buf, &bufsize);
52 fprintf(fp, "[ ");
53 size_t i;
54 for (i = 0; i < size; ++i)
55 fprintf(fp, "%lx ", read_num(data_ss, &data[i]));
56 fprintf(fp, "]");
57 fclose(fp);
58 return buf;
61 static const struct ksplice_reloc *
62 find_ksplice_reloc(struct supersect *ss, void *const *addr,
63 struct supersect **reloc_ss)
65 char *key = strprintf("%p", addr);
66 struct kreloc_section **ksp =
67 kreloc_section_hash_lookup(&ksplice_relocs, key, FALSE);
68 free(key);
69 if (ksp == NULL)
70 return NULL;
71 *reloc_ss = (*ksp)->ss;
72 return (*ksp)->reloc;
75 char *str_ksplice_symbol(struct supersect *ss,
76 const struct ksplice_symbol *ksymbol)
78 return strprintf("%s (%s)",
79 read_string(ss, &ksymbol->label),
80 read_string(ss, &ksymbol->name));
83 char *str_ksplice_symbolp(struct supersect *ptr_ss,
84 struct ksplice_symbol *const *ksymbolp)
86 asymbol *sym;
87 bfd_vma offset = read_reloc(ptr_ss, ksymbolp, sizeof(*ksymbolp), &sym);
88 if (bfd_is_const_section(sym->section))
89 return strprintf("*(%s)",
90 str_pointer(ptr_ss, (void *const *)ksymbolp));
91 struct supersect *ksymbol_ss = fetch_supersect(ptr_ss->parent,
92 sym->section);
93 return str_ksplice_symbol(ksymbol_ss, ksymbol_ss->contents.data +
94 sym->value + offset);
97 char *str_pointer(struct supersect *ss, void *const *addr)
99 asymbol *sym;
100 struct supersect *kreloc_ss;
101 const struct ksplice_reloc *kreloc =
102 find_ksplice_reloc(ss, addr, &kreloc_ss);
103 if (kreloc == NULL) {
104 bfd_vma offset = read_reloc(ss, addr, sizeof(*addr), &sym);
105 return strprintf("%s+%lx", sym->name, (unsigned long)offset);
106 } else {
107 return strprintf("[%s]+%lx",
108 str_ksplice_symbolp(kreloc_ss,
109 &kreloc->symbol),
110 kreloc->target_addend);
114 static const char *str_howto_type(const struct ksplice_reloc_howto *howto)
116 switch (howto->type) {
117 case KSPLICE_HOWTO_RELOC:
118 return "reloc";
119 case KSPLICE_HOWTO_RELOC_PATCH:
120 return "reloc(patch)";
121 case KSPLICE_HOWTO_TIME:
122 return "time";
123 case KSPLICE_HOWTO_DATE:
124 return "date";
125 case KSPLICE_HOWTO_BUG:
126 return "bug";
127 case KSPLICE_HOWTO_EXTABLE:
128 return "extable";
129 default:
130 return "unknown";
134 void show_ksplice_reloc(struct supersect *ss,
135 const struct ksplice_reloc *kreloc)
137 struct supersect *khowto_ss;
138 const struct ksplice_reloc_howto *khowto =
139 read_pointer(ss, (void *const *)&kreloc->howto, &khowto_ss);
140 printf(" blank_addr: %s size: %x\n"
141 " type: %s\n"
142 " symbol: %s\n"
143 " insn_addend: %lx\n"
144 " target_addend: %lx\n"
145 " pcrel: %x dst_mask: %lx rightshift: %x signed_addend: %x\n"
146 "\n",
147 str_pointer(ss, (void *const *)&kreloc->blank_addr),
148 read_num(khowto_ss, &khowto->size),
149 str_howto_type(khowto),
150 str_ksplice_symbolp(ss, &kreloc->symbol),
151 read_num(ss, &kreloc->insn_addend),
152 read_num(ss, &kreloc->target_addend),
153 read_num(khowto_ss, &khowto->pcrel),
154 read_num(khowto_ss, &khowto->dst_mask),
155 read_num(khowto_ss, &khowto->rightshift),
156 read_num(khowto_ss, &khowto->signed_addend));
159 void show_ksplice_relocs(struct supersect *kreloc_ss)
161 const struct ksplice_reloc *kreloc;
162 for (kreloc = kreloc_ss->contents.data; (void *)kreloc <
163 kreloc_ss->contents.data + kreloc_ss->contents.size; kreloc++)
164 show_ksplice_reloc(kreloc_ss, kreloc);
167 void show_ksplice_section_flags(const struct ksplice_section *ksect)
169 printf(" flags:");
170 if (ksect->flags & KSPLICE_SECTION_RODATA)
171 printf(" rodata");
172 if (ksect->flags & KSPLICE_SECTION_TEXT)
173 printf(" text");
174 if (ksect->flags & KSPLICE_SECTION_DATA)
175 printf(" data");
176 printf("\n");
179 void show_ksplice_section(struct supersect *ss,
180 const struct ksplice_section *ksect)
182 printf(" symbol: %s\n"
183 " address: %s size: %lx\n",
184 str_ksplice_symbolp(ss, &ksect->symbol),
185 str_pointer(ss, (void *const *)&ksect->address),
186 read_num(ss, &ksect->size));
187 show_ksplice_section_flags(ksect);
188 printf("\n");
191 void show_ksplice_sections(struct supersect *ksect_ss)
193 struct ksplice_section *ksect;
194 for (ksect = ksect_ss->contents.data; (void *)ksect <
195 ksect_ss->contents.data + ksect_ss->contents.size; ksect++)
196 show_ksplice_section(ksect_ss, ksect);
199 const char *str_ksplice_patch_type(struct supersect *ss,
200 const struct ksplice_patch *kpatch)
202 const unsigned short *line;
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_BUGLINE:
210 line = read_pointer(ss, &kpatch->contents, NULL);
211 return strprintf("bugline\n line: %hx", *line);
212 case KSPLICE_PATCH_DATA:
213 return strprintf("data\n size: %x", kpatch->size);
214 case KSPLICE_PATCH_EXPORT:
215 strp = read_pointer(ss, &kpatch->contents, &data_ss);
216 return strprintf("export\n newname: %s",
217 read_string(data_ss, strp));
218 default:
219 return "unknown";
223 void show_ksplice_patch(struct supersect *ss,
224 const struct ksplice_patch *kpatch)
226 printf(" type: %s\n"
227 " oldaddr: %s\n\n",
228 str_ksplice_patch_type(ss, kpatch),
229 str_pointer(ss, (void *const *)&kpatch->oldaddr));
232 void show_ksplice_patches(struct supersect *kpatch_ss)
234 const struct ksplice_patch *kpatch;
235 for (kpatch = kpatch_ss->contents.data; (void *)kpatch <
236 kpatch_ss->contents.data + kpatch_ss->contents.size; kpatch++)
237 show_ksplice_patch(kpatch_ss, kpatch);
240 void show_ksplice_call(struct supersect *ss, void *const *kcall)
242 printf("%s\n", str_pointer(ss, kcall));
245 void show_ksplice_calls(struct supersect *kcall_ss)
247 void *const *kcall;
248 for (kcall = kcall_ss->contents.data; (void *)kcall <
249 kcall_ss->contents.data + kcall_ss->contents.size; kcall++)
250 show_ksplice_call(kcall_ss, kcall);
253 void show_ksplice_system_map(struct supersect *ss,
254 const struct ksplice_system_map *smap)
256 printf("%s %s\n",
257 read_string(ss, &smap->label),
258 str_ulong_vec(ss, &smap->candidates, &smap->nr_candidates));
261 void show_ksplice_system_maps(struct supersect *smap_ss)
263 const struct ksplice_system_map *smap;
264 for (smap = smap_ss->contents.data;
265 (void *)smap < smap_ss->contents.data + smap_ss->contents.size;
266 smap++)
267 show_ksplice_system_map(smap_ss, smap);
270 struct inspect_section {
271 const char *prefix;
272 const char *header;
273 const char *notfound;
274 void (*show)(struct supersect *ss);
277 const struct inspect_section inspect_sections[] = {
279 .prefix = ".ksplice_init_relocs",
280 .header = "KSPLICE INIT RELOCATIONS",
281 .notfound = "No ksplice init relocations.\n",
282 .show = show_ksplice_relocs,
285 .prefix = ".ksplice_relocs",
286 .header = "KSPLICE RELOCATIONS",
287 .notfound = "No ksplice relocations.\n",
288 .show = show_ksplice_relocs,
291 .prefix = ".ksplice_sections",
292 .header = "KSPLICE SECTIONS",
293 .notfound = "No ksplice sections.\n",
294 .show = show_ksplice_sections,
297 .prefix = ".ksplice_patches",
298 .header = "KSPLICE PATCHES",
299 .notfound = "No ksplice patches.\n",
300 .show = show_ksplice_patches,
303 .prefix = ".ksplice_call",
304 .header = "KSPLICE CALLS",
305 .notfound = "No ksplice calls.\n",
306 .show = show_ksplice_calls,
309 .prefix = ".ksplice_system_map",
310 .header = "KSPLICE SYSTEM.MAP",
311 .notfound = "No ksplice System.map.\n",
312 .show = show_ksplice_system_maps,
314 }, *const inspect_sections_end = *(&inspect_sections + 1);
316 static void load_ksplice_reloc_offsets(struct superbfd *sbfd)
318 kreloc_section_hash_init(&ksplice_relocs);
320 asection *sect;
321 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
322 struct supersect *ss = fetch_supersect(sbfd, sect);
323 if (!starts_with(ss->name, ".ksplice_relocs") &&
324 !starts_with(ss->name, ".ksplice_init_relocs"))
325 continue;
326 struct ksplice_reloc *kreloc;
327 for (kreloc = ss->contents.data;
328 (void *)kreloc < ss->contents.data + ss->contents.size;
329 kreloc++) {
330 struct supersect *sym_ss;
331 const void *ptr =
332 read_pointer(ss, (void *const *)&kreloc->blank_addr,
333 &sym_ss);
334 char *key = strprintf("%p", ptr);
335 struct kreloc_section *ks, **ksp =
336 kreloc_section_hash_lookup(&ksplice_relocs, key,
337 TRUE);
338 free(key);
339 assert(*ksp == NULL);
340 ks = malloc(sizeof(*ks));
341 *ksp = ks;
342 ks->reloc = kreloc;
343 ks->ss = ss;
348 static void show_inspect_section(struct superbfd *sbfd,
349 const struct inspect_section *isect)
351 bool found = false;
352 asection *sect;
353 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
354 struct supersect *ss = fetch_supersect(sbfd, sect);
355 if (starts_with(ss->name, isect->prefix) &&
356 ss->contents.size != 0) {
357 printf("%s IN [%s]:\n", isect->header, sect->name);
358 found = true;
359 isect->show(ss);
362 if (!found)
363 printf("%s", isect->notfound);
364 printf("\n");
367 int main(int argc, char *argv[])
369 bfd *ibfd;
371 assert(argc >= 1);
372 bfd_init();
373 ibfd = bfd_openr(argv[1], NULL);
374 assert(ibfd);
376 char **matching;
377 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
379 struct superbfd *sbfd = fetch_superbfd(ibfd);
380 load_ksplice_reloc_offsets(sbfd);
381 const struct inspect_section *isect;
382 for (isect = inspect_sections; isect < inspect_sections_end; isect++)
383 show_inspect_section(sbfd, isect);
385 return 0;