summaryrefslogtreecommitdiff
path: root/utils/nwztools/database/nvp/nvptool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/nwztools/database/nvp/nvptool.cpp')
-rw-r--r--utils/nwztools/database/nvp/nvptool.cpp754
1 files changed, 754 insertions, 0 deletions
diff --git a/utils/nwztools/database/nvp/nvptool.cpp b/utils/nwztools/database/nvp/nvptool.cpp
new file mode 100644
index 0000000000..1371e93b87
--- /dev/null
+++ b/utils/nwztools/database/nvp/nvptool.cpp
@@ -0,0 +1,754 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2016 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <cstdio>
23#include <stdint.h>
24#include <cstdlib>
25#include <cstring>
26#include <getopt.h>
27#include <cstdarg>
28#include <string>
29#include <fstream>
30#include <elf.h>
31
32bool g_verbose = false;
33bool g_unsafe = false;
34
35uint8_t *read_file(const std::string& path, size_t& size)
36{
37 std::ifstream fin(path.c_str(), std::ios::binary);
38 if(!fin)
39 {
40 printf("Error: cannot open '%s'\n", path.c_str());
41 return 0;
42 }
43 fin.seekg(0, std::ios::end);
44 size = fin.tellg();
45 fin.seekg(0, std::ios::beg);
46 uint8_t *buf = new uint8_t[size];
47 fin.read((char *)buf, size);
48 return buf;
49}
50
51bool write_file(const std::string& path, uint8_t *buf, size_t size)
52{
53 std::ofstream fout(path.c_str(), std::ios::binary);
54 if(!fout)
55 {
56 printf("Error: cannot open '%s'\n", path.c_str());
57 return false;
58 }
59 fout.write((char *)buf, size);
60 fout.close();
61 return true;
62}
63
64/* ELF code */
65uint8_t *g_elf_buf;
66size_t g_elf_size;
67Elf32_Shdr *g_elf_symtab;
68Elf32_Shdr *g_elf_symtab_strtab;
69Elf32_Shdr *g_elf_shstrtab;
70
71Elf32_Ehdr *elf_ehdr()
72{
73 return (Elf32_Ehdr *)g_elf_buf;
74}
75
76#define NTH_SHDR_OFF(n) \
77 (elf_ehdr()->e_shoff + elf_ehdr()->e_shentsize * (n))
78
79Elf32_Shdr *elf_shdr(size_t index)
80{
81 if(index >= elf_ehdr()->e_shnum)
82 {
83 printf("Warning: section index is out of bounds\n");
84 return nullptr;
85 }
86 return (Elf32_Shdr *)(g_elf_buf + NTH_SHDR_OFF(index));
87}
88
89size_t elf_shnum()
90{
91 return elf_ehdr()->e_shnum;
92}
93
94const char *elf_get_str(Elf32_Shdr *strtab, Elf32_Word index)
95{
96 /* sanity checks */
97 if(strtab->sh_type != SHT_STRTAB)
98 {
99 printf("Warning: string access to a non-string-table section\n");
100 return nullptr;
101 }
102 if(strtab->sh_offset + strtab->sh_size > g_elf_size)
103 {
104 printf("Warning: string table section does not fit in the file\n");
105 return nullptr;
106 }
107 if(index >= strtab->sh_size)
108 {
109 printf("Warning: string access to string table is out of bounds\n");
110 return nullptr;
111 }
112 char *buf = (char *)(g_elf_buf + strtab->sh_offset);
113 if(buf[strtab->sh_size - 1] != 0)
114 {
115 printf("Warning: string table is not zero terminated\n");
116 return nullptr;
117 }
118 return buf + index;
119}
120
121const char *elf_get_section_name(size_t index)
122{
123 Elf32_Shdr *shdr = elf_shdr(index);
124 return shdr ? elf_get_str(g_elf_shstrtab, shdr->sh_name) : nullptr;
125}
126
127const char *elf_get_symbol_name(Elf32_Sym *sym)
128{
129 if(ELF32_ST_TYPE(sym->st_info) == STT_SECTION)
130 return elf_get_section_name(sym->st_shndx);
131 else
132 return elf_get_str(g_elf_symtab_strtab, sym->st_name);
133}
134
135Elf32_Sym *elf_get_symbol_by_name(const char *name)
136{
137 Elf32_Sym *sym = (Elf32_Sym *)(g_elf_buf + g_elf_symtab->sh_offset);
138 size_t nr_syms = g_elf_symtab->sh_size / sizeof(Elf32_Sym);
139 for(size_t i = 0; i < nr_syms; i++)
140 {
141 const char *s = elf_get_symbol_name(&sym[i]);
142 if(s != nullptr && strcmp(name, s) == 0)
143 return &sym[i];
144 }
145 return nullptr;
146}
147
148Elf32_Sym *elf_get_symbol_by_address(size_t shndx, Elf32_Word address)
149{
150 Elf32_Sym *sym = (Elf32_Sym *)(g_elf_buf + g_elf_symtab->sh_offset);
151 size_t nr_syms = g_elf_symtab->sh_size / sizeof(Elf32_Sym);
152 for(size_t i = 0; i < nr_syms; i++)
153 {
154 if(sym[i].st_shndx == shndx && sym[i].st_value == address)
155 return &sym[i];
156 }
157 return nullptr;
158}
159
160Elf32_Sym *elf_get_symbol_by_index(size_t index)
161{
162 Elf32_Sym *sym = (Elf32_Sym *)(g_elf_buf + g_elf_symtab->sh_offset);
163 size_t nr_syms = g_elf_symtab->sh_size / sizeof(Elf32_Sym);
164 if(index >= nr_syms)
165 return nullptr;
166 return &sym[index];
167}
168
169void *elf_get_section_ptr(size_t shndx, Elf32_Word address, size_t size)
170{
171 Elf32_Shdr *shdr = elf_shdr(shndx);
172 if(shdr == nullptr)
173 return nullptr;
174 if(address + size > shdr->sh_size)
175 return nullptr;
176 if(shdr->sh_offset + shdr->sh_size > g_elf_size)
177 return nullptr;
178 return g_elf_buf + shdr->sh_offset + address;
179}
180
181/* make sure the string has a final zero in the section, optionally check characters
182 * are printable */
183const char *elf_get_string_ptr_safe(size_t shndx, Elf32_Word offset, bool want_print = true)
184{
185 Elf32_Shdr *shdr = elf_shdr(shndx);
186 if(shdr == nullptr)
187 return nullptr;
188 /* address must be in the section */
189 if(offset >= shdr->sh_size)
190 return nullptr;
191 /* determine maximum size */
192 size_t max_sz = shdr->sh_size - offset;
193 const char *ptr = (const char *)(g_elf_buf + shdr->sh_offset + offset);
194 for(size_t i = 0; i < max_sz; i++)
195 {
196 if(ptr[i] == 0) /* found final 0, everything is fine */
197 return ptr;
198 if(want_print && !isprint(ptr[i]))
199 return nullptr;
200 }
201 return nullptr;
202}
203
204size_t elf_find_reloc_section(size_t shndx)
205{
206 /* find the relocation section */
207 for(size_t i = 0; i < elf_ehdr()->e_shnum; i++)
208 {
209 Elf32_Shdr *shdr = elf_shdr(i);
210 if(shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA)
211 continue;
212 if(shdr->sh_info != shndx)
213 continue;
214 return i;
215 }
216 return 0;
217}
218
219void *elf_get_symbol_ptr(Elf32_Sym *sym, size_t size)
220{
221 /* NOTE: also works for STT_SECTION since offset will be 0 */
222 return elf_get_section_ptr(sym->st_shndx, sym->st_value, size);
223}
224
225/* take the position of a 32-bit address in the section and apply relocation if
226 * any */
227void *elf_reloc_addr32(size_t shndx, Elf32_Word offset)
228{
229 /* read value */
230 uint32_t *val = (uint32_t *)elf_get_section_ptr(shndx, offset, 4);
231 if(val == nullptr)
232 return 0; /* invalid */
233 /* find reloc section if any */
234 size_t relshndx = elf_find_reloc_section(shndx);
235 if(relshndx == 0)
236 return g_elf_buf + *val; /* no relocation applies */
237 Elf32_Shdr *shdr = elf_shdr(relshndx);
238 /* find relocation that applies */
239 if(shdr->sh_type == SHT_RELA)
240 {
241 printf("Warning: unsupported RELA relocation type\n");
242 return 0;
243 }
244 Elf32_Rel *rel = (Elf32_Rel *)elf_get_section_ptr(relshndx, 0, shdr->sh_size);
245 if(rel == nullptr)
246 {
247 printf("Warning: invalid relocation section\n");
248 return 0;
249 }
250 size_t sym_count = shdr->sh_size / sizeof(Elf32_Rel);
251 for(size_t i = 0; i < sym_count; i++)
252 {
253 /* for relocatable files, r_offset is the offset in the section */
254 if(rel[i].r_offset != offset)
255 continue;
256 /* find symbol, ignore shdr->sh_link and assume it is g_elf_symtab
257 * since the file should have only one symbol table anyway */
258 Elf32_Sym *sym = elf_get_symbol_by_index(ELF32_R_SYM(rel[i].r_info));
259 /* found it! */
260 if(g_verbose)
261 {
262 printf("[section %zu (%s) offset %#x reloc val %#x type %d sym %d (%s)]\n",
263 shndx, elf_get_section_name(shndx), offset, *val,
264 ELF32_R_TYPE(rel[i].r_info), ELF32_R_SYM(rel[i].r_info),
265 sym ? elf_get_symbol_name(sym) : "<undef>");
266 }
267 /* apply reloc */
268 if(ELF32_R_TYPE(rel[i].r_info) == R_ARM_ABS32)
269 {
270 if(sym == nullptr)
271 {
272 printf("Warning: R_ARM_ABS32 reloc with invalid symbol reference\n");
273 return 0;
274 }
275 return *val + (uint8_t *)elf_get_symbol_ptr(sym, 0);
276 }
277 else
278 {
279 printf("Warning: unsupported relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
280 return 0;
281 }
282 }
283 /* no reloc applies */
284 if(g_verbose)
285 {
286 printf("[section %zu (%s) offset %#x no reloc found]\n", shndx,
287 elf_get_section_name(shndx), offset);
288 }
289 return g_elf_buf + *val; /* no relocation applies */
290}
291
292size_t elf_map_virt_addr(uint32_t address, Elf32_Word& out_off)
293{
294 /* for relocatable file, this is trivial */
295 for(size_t i = 0; i < elf_ehdr()->e_shnum; i++)
296 {
297 Elf32_Shdr *shdr = elf_shdr(i);
298 if(shdr->sh_offset <= address && address < shdr->sh_offset + shdr->sh_size)
299 {
300 out_off = address - shdr->sh_offset;
301 if(g_verbose)
302 {
303 printf("[map %#x to section %zi (%s) at %#x]\n", address, i,
304 elf_get_section_name(i), out_off);
305 }
306 return i;
307 }
308 }
309 return 0; /* section 0 is always invalid */
310}
311
312size_t elf_map_ptr(void *ptr, Elf32_Word& out_off)
313{
314 uint32_t addr = (uint32_t)((uint8_t *)ptr - g_elf_buf);
315 return elf_map_virt_addr(addr, out_off);
316}
317
318/* same as elf_reloc_addr32 but find section automatically from pointer */
319void *elf_reloc_addr32_ptr(uint32_t *val)
320{
321 Elf32_Word off;
322 size_t sec = elf_map_ptr((void *)val, off);
323 /* if it does not belong to any section, don't do anything */
324 if(sec == 0)
325 {
326 printf("Warning: reloc addr pointer not in any section\n");
327 return g_elf_buf + *val;
328 }
329 return elf_reloc_addr32(sec, off);
330}
331
332Elf32_Sym *elf_get_symbol_by_ptr(void *ptr)
333{
334 Elf32_Word off;
335 size_t sec = elf_map_ptr(ptr, off);
336 return sec ? elf_get_symbol_by_address(sec, off) : nullptr;
337}
338
339/* check if a string is safe */
340bool elf_is_str_ptr_safe(const char *str)
341{
342 Elf32_Word name_off;
343 /* find the section it belongs to */
344 size_t name_shndx = elf_map_ptr((void *)str, name_off);
345 if(name_shndx == 0)
346 return false;
347 /* check the string fit in the section */
348 return elf_get_string_ptr_safe(name_shndx, name_off) != nullptr;
349}
350
351bool elf_is_ptr_safe(void *ptr, size_t sz)
352{
353 Elf32_Word ptr_off;
354 /* find the section it belongs to */
355 size_t ptr_shndx = elf_map_ptr((void *)ptr, ptr_off);
356 if(ptr_shndx == 0)
357 return false;
358 /* check the string fit in the section */
359 return elf_get_section_ptr(ptr_shndx, ptr_off, sz) != nullptr;
360}
361
362bool elf_init()
363{
364 if(g_elf_size < sizeof(Elf32_Ehdr))
365 {
366 printf("Invalid ELF file: too small\n");
367 return false;
368 }
369 Elf32_Ehdr *ehdr = elf_ehdr();
370 if(ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
371 ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
372 ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
373 ehdr->e_ident[EI_MAG3] != ELFMAG3)
374 {
375 printf("Invalid ELF file: invalid ident\n");
376 return false;
377 }
378 /* we only support relocatable files */
379 if(ehdr->e_type != ET_REL)
380 {
381 printf("Unsupported ELF file: this is not a relocatable file\n");
382 return false;
383 }
384 if(ehdr->e_ident[EI_CLASS] != ELFCLASS32 || ehdr->e_machine != EM_ARM)
385 {
386 printf("Unsupported ELF file: this is not a 32-bit ARM ELF file\n");
387 return false;
388 }
389 /* go through sections */
390 if(ehdr->e_shoff == 0)
391 {
392 printf("Invalid ELF file: no sections\n");
393 return false;
394 }
395 if(ehdr->e_shentsize < sizeof(Elf32_Shdr))
396 {
397 printf("Invalid ELF file: section entry size too small\n");
398 return false;
399 }
400 if(NTH_SHDR_OFF(ehdr->e_shnum) > g_elf_size)
401 {
402 printf("Invalid ELF file: sections header does not fit in the file\n");
403 return false;
404 }
405 for(size_t i = 0; i < ehdr->e_shnum; i++)
406 {
407 Elf32_Shdr *shdr = (Elf32_Shdr *)(g_elf_buf + NTH_SHDR_OFF(i));
408 if(shdr->sh_type == SHT_SYMTAB)
409 g_elf_symtab = shdr;
410 }
411 /* handle symbol table */
412 if(g_elf_symtab)
413 {
414 if(g_elf_symtab->sh_offset + g_elf_symtab->sh_size > g_elf_size)
415 {
416 printf("Invalid ELF file: symtab does not file in the file\n");
417 return false;
418 }
419 g_elf_symtab_strtab = elf_shdr(g_elf_symtab->sh_link);
420 if(g_elf_symtab_strtab == nullptr)
421 {
422 printf("Invalid ELF file: symtab's strtab is not valid\n");
423 }
424 if(g_elf_symtab_strtab->sh_type != SHT_STRTAB)
425 {
426 printf("Invalid ELF file: symtab's strtab is not a string table\n");
427 return false;
428 }
429 }
430 /* handle section string table */
431 if(ehdr->e_shstrndx != SHN_UNDEF)
432 {
433 g_elf_shstrtab = elf_shdr(ehdr->e_shstrndx);
434 if(g_elf_shstrtab == nullptr)
435 {
436 printf("Invalid ELF file: section string table is invalid\n");
437 return false;
438 }
439 }
440
441 return true;
442}
443
444/* main code */
445
446void usage()
447{
448 printf("usage: nvptool [options] inputs...\n");
449 printf("options:\n");
450 printf(" -h/--help Display help\n");
451 printf(" -x/--extract Extract nvp map from icx_nvp_emmc.ko\n");
452 printf(" -o/--output Set output file\n");
453 printf(" -v/--verbose Enable debug output\n");
454 printf(" -u/--unsafe Perform potentially unsafe operations\n");
455 exit(1);
456}
457
458struct zone_info_v1_t
459{
460 uint32_t node;
461 uint32_t start;
462 uint32_t count;
463 uint32_t size;
464 uint32_t semaphore[4]; /* a 16-byte structure, useless for us */
465 uint32_t name; /* pointer to string */
466} __attribute__((packed));
467
468struct zone_info_v2_t
469{
470 uint32_t node;
471 uint32_t start;
472 uint32_t count;
473 uint32_t size;
474 uint32_t semaphore[3]; /* a 12-byte structure, useless for us */
475 uint32_t name; /* pointer to string */
476} __attribute__((packed));
477
478struct area_info_v1_t
479{
480 uint32_t type; /* 1 = large, 2 = small */
481 uint32_t zoneinfo; /* pointer to zone_info_t[] */
482 uint32_t zonecount;
483 uint32_t semaphore[4]; /* a 16-byte structure, useless for us */
484 uint32_t name; /* pointer to string */
485} __attribute__((packed));
486
487struct area_info_v2_t
488{
489 uint32_t type; /* 1 = large, 2 = small */
490 uint32_t zoneinfo; /* pointer to zone_info_t[] */
491 uint32_t zonecount;
492 uint32_t semaphore[3]; /* a 16-byte structure, useless for us */
493 uint32_t name; /* pointer to string */
494} __attribute__((packed));
495
496int guess_version(void *area_info_ptr)
497{
498 /* the "semaphore" part is always filled with zeroes, so simply check if there
499 * are 3 or 4 of them */
500 area_info_v1_t *ai_v1 = (area_info_v1_t *)area_info_ptr;
501 if(ai_v1->semaphore[3] == 0)
502 return 1; /* v1: semaphore has 4 fields */
503 else
504 return 2; /* v2: semaphore has 3 fields */
505}
506
507int do_extract(const char *output, int argc, char **argv)
508{
509 if(argc != 1)
510 {
511 printf("You need to specify exactly one input file to extract from.\n");
512 return 3;
513 }
514 FILE *fout = NULL;
515 if(output)
516 {
517 fout = fopen(output, "w");
518 if(fout == NULL)
519 {
520 printf("Cannot open output file '%s'\n", output);
521 return 4;
522 }
523 }
524 /* read elf file */
525 g_elf_buf = read_file(argv[0], g_elf_size);
526 if(g_elf_buf == nullptr)
527 {
528 printf("Cannot open input file '%s'\n", argv[0]);
529 return 1;
530 }
531 if(!elf_init())
532 {
533 printf("This is not a valid ELF file\n");
534 return 1;
535 }
536 if(g_elf_symtab == nullptr)
537 {
538 printf("This ELF file does not have a symbol table\n");
539 return 1;
540 }
541 /* look for symbol 'AreaInfo' */
542 Elf32_Sym *sym_AreaInfo = elf_get_symbol_by_name("AreaInfo");
543 if(sym_AreaInfo == nullptr)
544 {
545 printf("Cannot find symbol 'AreaInfo'\n");
546 return 1;
547 }
548 printf("AreaInfo:\n");
549 if(g_verbose)
550 {
551 printf("[%u bytes at address %#x in section %u (%s)]\n",
552 (unsigned)sym_AreaInfo->st_size, (unsigned)sym_AreaInfo->st_value,
553 (unsigned)sym_AreaInfo->st_shndx, elf_get_section_name(sym_AreaInfo->st_shndx));
554 }
555 /* guess version */
556 int ver = guess_version(elf_get_symbol_ptr(sym_AreaInfo, sizeof(area_info_v1_t)));
557 if(g_verbose)
558 printf("[guessed version: %d]\n", ver);
559 size_t sizeof_area_info = (ver == 1) ? sizeof(area_info_v1_t) : sizeof(area_info_v2_t);
560 size_t sizeof_zone_info = (ver == 1) ? sizeof(zone_info_v1_t) : sizeof(zone_info_v2_t);
561 /* sanity check AreaInfo */
562 size_t area_count = sym_AreaInfo->st_size / sizeof_area_info;
563 if(!g_unsafe && (sym_AreaInfo->st_size % sizeof_area_info) != 0)
564 {
565 printf("AreaInfo size (%u) is a not a multiple of area_info_t size (%zu).\n",
566 (unsigned)sym_AreaInfo->st_size, sizeof_area_info);
567 printf("Use unsafe option to override this check\n");
568 return 1;
569 }
570 area_info_v1_t *AreaInfo_v1 = (area_info_v1_t *)elf_get_symbol_ptr(sym_AreaInfo,
571 sym_AreaInfo->st_size);
572 area_info_v2_t *AreaInfo_v2 = (area_info_v2_t *)AreaInfo_v1;
573 if(AreaInfo_v1 == nullptr)
574 {
575 printf("Symbol does not point to a valid address\n");
576 return 1;
577 }
578 for(size_t i = 0; i < area_count; i++)
579 {
580 uint32_t type;
581 uint32_t *zoneinfo_ptr;
582 uint32_t zonecount;
583 uint32_t *name_ptr;
584
585 if(ver == 1)
586 {
587 type = AreaInfo_v1[i].type;
588 zoneinfo_ptr = &AreaInfo_v1[i].zoneinfo;
589 zonecount = AreaInfo_v1[i].zonecount;
590 name_ptr = &AreaInfo_v1[i].name;
591 }
592 else
593 {
594 type = AreaInfo_v2[i].type;
595 zoneinfo_ptr = &AreaInfo_v2[i].zoneinfo;
596 zonecount = AreaInfo_v2[i].zonecount;
597 name_ptr = &AreaInfo_v2[i].name;
598 }
599
600 if(g_verbose)
601 {
602 printf(" [type=%u info=%#x count=%u name=%#x]\n", type, *zoneinfo_ptr,
603 zonecount, *name_ptr);
604 }
605 /* translate name address */
606 const char *name = (const char *)elf_reloc_addr32_ptr(name_ptr);
607 if(name == nullptr || !elf_is_str_ptr_safe(name))
608 {
609 printf(" Entry name is not a string\n");
610 continue;
611 }
612 /* skip reserved entries */
613 if(*zoneinfo_ptr == 0)
614 {
615 printf(" %s\n", name);
616 continue;
617 }
618 /* relocate the zoneinfo pointer */
619 void *Zone = elf_reloc_addr32_ptr(zoneinfo_ptr);;
620 if(Zone == nullptr)
621 {
622 printf(" %s\n", name);
623 printf(" Zone info pointer is not valid\n");
624 continue;
625 }
626 /* in safe mode, make sure the zone info pointer is a symbol */
627 Elf32_Sym *zoneinfo_sym = elf_get_symbol_by_ptr((void *)Zone);
628 const char *zoneinfo_sym_name = "<no symbol>";
629 if(zoneinfo_sym)
630 zoneinfo_sym_name = elf_get_symbol_name(zoneinfo_sym);
631 printf(" %s (%s)\n", name, zoneinfo_sym_name);
632 if(!g_unsafe && !zoneinfo_sym)
633 {
634 printf(" Zone info pointer does not correspond to any symbol.\n");
635 printf(" Use unsafe option to override this check\n");
636 continue;
637 }
638 /* if we have the symbol, make sure the claimed size match */
639 if(!g_unsafe && zoneinfo_sym)
640 {
641 if(zoneinfo_sym->st_size != sizeof_zone_info * zonecount)
642 {
643 printf(" Zone info symbol size (%u) does not match expected size (%zu)\n",
644 (unsigned)zoneinfo_sym->st_size, sizeof_zone_info * zonecount);
645 printf(" Use unsafe option to override this check\n");
646 continue;
647 }
648 }
649 /* sanity check */
650 if(!elf_is_ptr_safe((void *)Zone, sizeof_zone_info * zonecount))
651 {
652 printf(" Zone info pointer is not valid\n");
653 continue;
654 }
655 /* read zone */
656 zone_info_v1_t *Zone_v1 = (zone_info_v1_t *)Zone;
657 zone_info_v2_t *Zone_v2 = (zone_info_v2_t *)Zone;
658 for(size_t j = 0; j < zonecount; j++)
659 {
660 uint32_t node, start, count, size;
661 uint32_t *name_ptr;
662
663 if(ver == 1)
664 {
665 node = Zone_v1[j].node;
666 start = Zone_v1[j].start;
667 count = Zone_v1[j].count;
668 size = Zone_v1[j].size;
669 name_ptr = &Zone_v1[j].name;
670 }
671 else
672 {
673 node = Zone_v2[j].node;
674 start = Zone_v2[j].start;
675 count = Zone_v2[j].count;
676 size = Zone_v2[j].size;
677 name_ptr = &Zone_v2[j].name;
678 }
679
680 if(g_verbose)
681 {
682 printf(" [node=%u start=%#x count=%u size=%u name=%#x]\n",
683 node, start, count, size, *name_ptr);
684 }
685 /* translate name address */
686 const char *name = (const char *)elf_reloc_addr32_ptr(name_ptr);
687 if(name == nullptr || !elf_is_str_ptr_safe(name))
688 {
689 printf(" Entry name is not a string\n");
690 continue;
691 }
692 printf(" %s: node %03u, size %u\n", name, node, size);
693 if(fout)
694 fprintf(fout, "%u,%u,%s\n", node, size, name);
695 }
696 }
697 if(fout)
698 fclose(fout);
699 /* success */
700 return 0;
701}
702
703int main(int argc, char **argv)
704{
705 const char *output = NULL;
706 bool extract = false;
707
708 if(argc <= 1)
709 usage();
710
711 while(1)
712 {
713 static struct option long_options[] =
714 {
715 {"help", no_argument, 0, 'h'},
716 {"extract", no_argument, 0, 'x'},
717 {"output", required_argument, 0, 'o'},
718 {"verbose", no_argument, 0, 'v'},
719 {"unsafe", no_argument, 0, 'u'},
720 {0, 0, 0, 0}
721 };
722
723 int c = getopt_long(argc, argv, "hxo:vu", long_options, NULL);
724 if(c == -1)
725 break;
726 switch(c)
727 {
728 case -1:
729 break;
730 case 'h':
731 usage();
732 break;
733 case 'o':
734 output = optarg;
735 break;
736 case 'x':
737 extract = true;
738 break;
739 case 'v':
740 g_verbose = true;
741 break;
742 case 'u':
743 g_unsafe = true;
744 break;
745 default:
746 abort();
747 }
748 }
749
750 if(extract)
751 return do_extract(output, argc - optind, argv + optind);
752 printf("You need to specify an operation. Run nvptool -h for help\n");
753 return 1;
754}