summaryrefslogtreecommitdiff
path: root/utils/nwztools/database/nvp/nvptool.cpp
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2016-11-11 15:40:56 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2016-11-11 16:07:14 +0100
commit44bb2856a59be53ef5ede154a39c54a59b1cc6d0 (patch)
treece343ecff309d6d0172ea56946a9ce679329b250 /utils/nwztools/database/nvp/nvptool.cpp
parent19de536ce2f3c8066ca5be9b570f72e5c1e88342 (diff)
downloadrockbox-44bb2856a59be53ef5ede154a39c54a59b1cc6d0.tar.gz
rockbox-44bb2856a59be53ef5ede154a39c54a59b1cc6d0.zip
nwztools/database: add database of information on Sony NWZ linux players
There must be an evil genius in Sony's Walkman division. Someone who made sure that each model is close enough to the previous one so that little code is needed but different enough so that an educated guess is not enough. Each linux-based Sony player has a model ID (mid) which is a 32-bit integer. I was able to extract a list of all model IDs and the correspoding name of the player (see README). This gives us 1) a nice list of all players (because NWZ-A729 vs NWZ-A729B, really Sony?) 2) an easy way to find the name of player programatically. It seems that the lower 8-bit of the model ID gives the storage size but don't bet your life on it. The remaining bytes seem to follow some kind of pattern but there are exceptions. From this list, I was able to build a list of all Sony's series (up to quite recent one). The only safe way to build that is by hand, with a list of series, each series having a list of model IDs. The notion of series is very important because all models in a series share the same firmware. A very important concept on Sony's players is the NVP, an area of the flash that stores data associated with keys. The README contains more information but basically this is where is record the model ID, the destination, the boot flags, the firmware upgrade flags, the boot image, the DRM keys, and a lot of other stuff. Of course Sony decided to slightly tweak the index of the keys regularly over time which means that each series has a potentially different map, and we need this map to talk to the NVP driver. Fortunately, Sony distributes the kernel for all its players and they contain a kernel header with this information. I wrote a script to unpack kernel sources and parse this header, producing a bunch of nw-*.txt files, included in this commit. This map is very specific though: it maps Sony's 3-letter names (bti) to indexes (1). This is not very useful without the decription (bti = boot image) and its size (262144). This information is harder to come by, and is only stored in one place: if icx_nvp_emmc.ko drivers, found on the device. Fortunately, Sony distributes a number of firmware upgrade, that contain the rootfs, than once extracted contain this driver. The driver is a standard ELF files with symbols. I wrote a parsing tool (nvptool) that is able to extract this information from the drivers. Using that, I produced a bunch of nodes-nw*.txt files. A reasonable assumption is that nodes meaning and size do not change over time (bti is always the boot image and is always 262144 bytes), so by merging a few of those file, we can get a complete picture (note that some nodes that existed in older player do not exists anymore so we really need to merge several ones from different generations). The advantage of storing all this information in plain text files, is that it now makes it easy to parse it and produce whatever format we want to use it. I wrote a python script that parses all this mess and produces a C file and header with all this information (nwz_db.{c,h}). Change-Id: Id790581ddd527d64418fe9e4e4df8e0546117b80
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}