A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 754 lines 23 kB view raw
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}