1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.compatibility.common.util; 18 19 import java.io.File; 20 import java.io.IOException; 21 import java.io.RandomAccessFile; 22 import java.util.ArrayList; 23 import java.util.HashMap; 24 import java.util.List; 25 import java.util.Map; 26 27 /** 28 * A poor man's implementation of the readelf command. This program is designed to parse ELF 29 * (Executable and Linkable Format) files. 30 */ 31 // ToDo: consolidate with com.android.compatibility.common.util 32 public class ReadElf implements AutoCloseable { 33 /** The magic values for the ELF identification. */ 34 private static final byte[] ELFMAG = { 35 (byte) 0x7F, (byte) 'E', (byte) 'L', (byte) 'F', 36 }; 37 38 private static final int EI_NIDENT = 16; 39 40 private static final int EI_CLASS = 4; 41 private static final int EI_DATA = 5; 42 43 public static final int ET_DYN = 3; 44 public static final int EM_386 = 3; 45 public static final int EM_MIPS = 8; 46 public static final int EM_ARM = 40; 47 public static final int EM_X86_64 = 62; 48 // http://en.wikipedia.org/wiki/Qualcomm_Hexagon 49 public static final int EM_QDSP6 = 164; 50 public static final int EM_AARCH64 = 183; 51 52 public static final String ARCH_ARM = "arm"; 53 public static final String ARCH_X86 = "x86"; 54 public static final String ARCH_MIPS = "mips"; 55 public static final String ARCH_UNKNOWN = "unknown"; 56 private static final String RODATA = ".rodata"; 57 58 private static final int ELFCLASS32 = 1; 59 private static final int ELFCLASS64 = 2; 60 61 private static final int ELFDATA2LSB = 1; 62 private static final int ELFDATA2MSB = 2; 63 64 private static final int EV_CURRENT = 1; 65 66 private static final long PT_LOAD = 1; 67 68 // https://en.wikipedia.org/wiki/Executable_and_Linkable_Format 69 private static final int SHT_PROGBITS = 1; 70 private static final int SHT_SYMTAB = 2; 71 private static final int SHT_STRTAB = 3; 72 private static final int SHT_DYNAMIC = 6; 73 private static final int SHT_DYNSYM = 11; 74 private static final int SHT_GNU_VERDEF = 0x6ffffffd; 75 private static final int SHT_GNU_VERNEED = 0x6ffffffe; 76 private static final int SHT_GNU_VERSYM = 0x6fffffff; 77 78 public static class Symbol { 79 public static final int STB_LOCAL = 0; 80 public static final int STB_GLOBAL = 1; 81 public static final int STB_WEAK = 2; 82 public static final int STB_LOPROC = 13; 83 public static final int STB_HIPROC = 15; 84 85 public static final int STT_NOTYPE = 0; 86 public static final int STT_OBJECT = 1; 87 public static final int STT_FUNC = 2; 88 public static final int STT_SECTION = 3; 89 public static final int STT_FILE = 4; 90 public static final int STT_COMMON = 5; 91 public static final int STT_TLS = 6; 92 93 public static final int SHN_UNDEF = 0; 94 public static final int SHN_ABS = 0xfff1; 95 96 public final String name; 97 public final int bind; 98 public final int type; 99 public final int shndx; 100 public final long value; 101 public final long size; 102 public final int other; 103 104 public VerNeed mVerNeed; 105 public VerDef mVerDef; 106 Symbol(String name, int st_info, int st_shndx, long st_value, long st_size, int st_other)107 Symbol(String name, int st_info, int st_shndx, long st_value, long st_size, int st_other) { 108 this.name = name; 109 this.bind = (st_info >> 4) & 0x0F; 110 this.type = st_info & 0x0F; 111 this.shndx = st_shndx; 112 this.value = st_value; 113 this.size = st_size; 114 this.other = st_other; 115 } 116 117 @Override toString()118 public String toString() { 119 return String.format( 120 "%s, %s, %s, %s, %s, %s", 121 name, 122 toBind(), 123 toType(), 124 toShndx(), 125 getExternalLibFileName(), 126 getExternalLibName()); 127 } 128 toBind()129 public String toBind() { 130 switch (bind) { 131 case STB_LOCAL: 132 return "LOCAL"; 133 case STB_GLOBAL: 134 return "GLOBAL"; 135 case STB_WEAK: 136 return "WEAK"; 137 } 138 return "STB_??? (" + bind + ")"; 139 } 140 toType()141 public String toType() { 142 switch (type) { 143 case STT_NOTYPE: 144 return "NOTYPE"; 145 case STT_OBJECT: 146 return "OBJECT"; 147 case STT_FUNC: 148 return "FUNC"; 149 case STT_SECTION: 150 return "SECTION"; 151 case STT_FILE: 152 return "FILE"; 153 case STT_COMMON: 154 return "COMMON"; 155 case STT_TLS: 156 return "TLS"; 157 } 158 return "STT_??? (" + type + ")"; 159 } 160 toShndx()161 public String toShndx() { 162 switch (shndx) { 163 case SHN_ABS: 164 return "ABS"; 165 case SHN_UNDEF: 166 return "UND"; 167 } 168 return String.valueOf(shndx); 169 } 170 171 // if a symbol is not define locally isGlobalUnd()172 public boolean isGlobalUnd() { 173 return (bind != STB_LOCAL && shndx == SHN_UNDEF); 174 } 175 176 // if a symbol is extern isExtern()177 public boolean isExtern() { 178 return (bind != STB_LOCAL && shndx != SHN_UNDEF); 179 } 180 getExternalLibFileName()181 public String getExternalLibFileName() { 182 if (mVerNeed != null) { 183 return mVerNeed.vn_file_name; 184 } 185 return null; 186 } 187 getExternalLibName()188 public String getExternalLibName() { 189 if (mVerNeed != null) { 190 return mVerNeed.vn_vernaux[0].vna_lib_name; 191 } 192 return null; 193 } 194 getExternalLibVer()195 public int getExternalLibVer() { 196 if (mVerNeed != null) { 197 return mVerNeed.vn_vernaux[0].vna_other; 198 } 199 return -1; 200 } 201 getVerDefLibName()202 public String getVerDefLibName() { 203 if (mVerDef != null) { 204 return mVerDef.vd_verdaux[0].vda_lib_name; 205 } 206 return null; 207 } 208 getVerDefVersion()209 public int getVerDefVersion() { 210 if (mVerDef != null) { 211 return mVerDef.vd_version; 212 } 213 return -1; 214 } 215 } 216 217 public static class SecHeader { 218 public final long sh_name; 219 public final long sh_type; 220 public final long sh_flags; 221 public final long sh_addr; 222 public final long sh_offset; 223 public final long sh_size; 224 public final long sh_link; 225 public final long sh_info; 226 public final long sh_addralign; 227 public final long sh_entsize; 228 SecHeader( long name, long type, long flags, long addr, long offset, long size, long link, long info, long addralign, long entsize)229 SecHeader( 230 long name, 231 long type, 232 long flags, 233 long addr, 234 long offset, 235 long size, 236 long link, 237 long info, 238 long addralign, 239 long entsize) { 240 this.sh_name = name; 241 this.sh_type = type; 242 this.sh_flags = flags; 243 this.sh_addr = addr; 244 this.sh_offset = offset; 245 this.sh_size = size; 246 this.sh_link = link; 247 this.sh_info = info; 248 this.sh_addralign = addralign; 249 this.sh_entsize = entsize; 250 } 251 252 @Override toString()253 public String toString() { 254 return String.format( 255 "%d, %d, %d, %d, %d, %d, %d, %d, %d, %d", 256 this.sh_name, 257 this.sh_type, 258 this.sh_flags, 259 this.sh_addr, 260 this.sh_offset, 261 this.sh_size, 262 this.sh_link, 263 this.sh_info, 264 this.sh_addralign, 265 this.sh_entsize); 266 } 267 } 268 269 public static class VerNeed { 270 public final int vn_version; 271 public final int vn_cnt; 272 public final long vn_file; 273 public final long vn_aux; 274 public final long vn_next; 275 public String vn_file_name; 276 public VerNAux[] vn_vernaux; 277 VerNeed(String file_name, String lib_name, int ndx)278 VerNeed(String file_name, String lib_name, int ndx) { 279 this.vn_file_name = file_name.toLowerCase(); 280 this.vn_vernaux = new VerNAux[1]; 281 this.vn_vernaux[0] = new VerNAux(lib_name, ndx); 282 283 this.vn_version = 0; 284 this.vn_cnt = 0; 285 this.vn_file = 0; 286 this.vn_aux = 0; 287 this.vn_next = 0; 288 } 289 VerNeed(int ver, int cnt, long file, long aux, long next)290 VerNeed(int ver, int cnt, long file, long aux, long next) { 291 this.vn_version = ver; 292 this.vn_cnt = cnt; 293 this.vn_file = file; 294 this.vn_aux = aux; 295 this.vn_next = next; 296 } 297 298 @Override toString()299 public String toString() { 300 String vernauxStr = ""; 301 for (int i = 0; i < this.vn_cnt; i++) { 302 vernauxStr += String.format(" %s\n", this.vn_vernaux[i].toString()); 303 } 304 return String.format( 305 "%s, %d, %d, %d, %d, %d \n%s", 306 this.vn_file_name, 307 this.vn_version, 308 this.vn_cnt, 309 this.vn_file, 310 this.vn_aux, 311 this.vn_next, 312 vernauxStr); 313 } 314 } 315 316 public static class VerNAux { 317 public final long vna_hash; 318 public final int vna_flags; 319 public final int vna_other; 320 public final long vna_name; 321 public final long vna_next; 322 public String vna_lib_name; 323 VerNAux(String lib_name, int ndx)324 VerNAux(String lib_name, int ndx) { 325 this.vna_lib_name = lib_name; 326 327 this.vna_hash = 0; 328 this.vna_flags = 0; 329 this.vna_other = ndx; 330 this.vna_name = 0; 331 this.vna_next = 0; 332 } 333 VerNAux(long hash, int flags, int other, long name, long next)334 VerNAux(long hash, int flags, int other, long name, long next) { 335 this.vna_hash = hash; 336 this.vna_flags = flags; 337 this.vna_other = other; 338 this.vna_name = name; 339 this.vna_next = next; 340 } 341 342 @Override toString()343 public String toString() { 344 return String.format( 345 "%s, %d, %d, %d, %d, %d", 346 this.vna_lib_name, 347 this.vna_hash, 348 this.vna_flags, 349 this.vna_other, 350 this.vna_name, 351 this.vna_next); 352 } 353 } 354 355 public static class VerDef { 356 public final int vd_version; 357 public final int vd_flags; 358 public final int vd_ndx; 359 public final int vd_cnt; 360 public final long vd_hash; 361 public final long vd_aux; 362 public final long vd_next; 363 public VerDAux[] vd_verdaux; 364 VerDef(String lib_name)365 VerDef(String lib_name) { 366 this.vd_verdaux = new VerDAux[1]; 367 this.vd_verdaux[0] = new VerDAux(lib_name); 368 369 this.vd_version = 0; 370 this.vd_flags = 0; 371 this.vd_ndx = 0; 372 this.vd_cnt = 0; 373 this.vd_hash = 0; 374 this.vd_aux = 0; 375 this.vd_next = 0; 376 } 377 VerDef(int ver, int flags, int ndx, int cnt, long hash, long aux, long next)378 VerDef(int ver, int flags, int ndx, int cnt, long hash, long aux, long next) { 379 this.vd_version = ver; 380 this.vd_flags = flags; 381 this.vd_ndx = ndx; 382 this.vd_cnt = cnt; 383 this.vd_hash = hash; 384 this.vd_aux = aux; 385 this.vd_next = next; 386 } 387 388 @Override toString()389 public String toString() { 390 String vStr = ""; 391 for (int i = 0; i < this.vd_cnt; i++) { 392 vStr += String.format(" %s\n", this.vd_verdaux[i].toString()); 393 } 394 return String.format( 395 "%s, %d, %d, %d, %d, %d \n%s", 396 this.vd_verdaux[0].vda_lib_name, 397 this.vd_version, 398 this.vd_flags, 399 this.vd_ndx, 400 this.vd_cnt, 401 this.vd_hash, 402 vStr); 403 } 404 } 405 406 public static class VerDAux { 407 public final long vda_name; 408 public final long vda_next; 409 public String vda_lib_name; 410 VerDAux(String lib_name)411 VerDAux(String lib_name) { 412 this.vda_lib_name = lib_name.toLowerCase(); 413 414 this.vda_name = 0; 415 this.vda_next = 0; 416 } 417 VerDAux(long name, long next)418 VerDAux(long name, long next) { 419 this.vda_name = name; 420 this.vda_next = next; 421 } 422 423 @Override toString()424 public String toString() { 425 return String.format("%s, %d, %d", this.vda_lib_name, this.vda_name, this.vda_next); 426 } 427 } 428 429 // Dynamic Section Entry 430 public static class DynamicEntry { 431 private static final int DT_NEEDED = 1; 432 public final long mTag; 433 public final long mValue; 434 DynamicEntry(long tag, long value)435 DynamicEntry(long tag, long value) { 436 mTag = tag; 437 mValue = value; 438 } 439 isNeeded()440 public boolean isNeeded() { 441 if (mTag == DT_NEEDED) { 442 return true; 443 } else { 444 // System.err.println(String.format("Not Needed: %d, %d", mTag, mValue)); 445 return false; 446 } 447 } 448 getValue()449 public long getValue() { 450 return mValue; 451 } 452 453 @Override toString()454 public String toString() { 455 return String.format("%d, %d", this.mTag, this.mValue); 456 } 457 } 458 459 private final String mPath; 460 private final RandomAccessFile mFile; 461 private final byte[] mBuffer = new byte[512]; 462 private int mEndian; 463 private boolean mIsDynamic; 464 private boolean mIsPIE; 465 private int mType; 466 private int mAddrSize; 467 private int mMachine; 468 469 /** Symbol Table offset */ 470 private long mSymTabOffset; 471 472 /** Symbol Table size */ 473 private long mSymTabSize; 474 475 /** Symbol entry count */ 476 private int mSymEntCnt; 477 478 /** Dynamic Symbol Table offset */ 479 private long mDynSymOffset; 480 481 /** Dynamic Symbol Table size */ 482 private long mDynSymSize; 483 484 /** Dynamic entry count */ 485 private int mDynSymEntCnt; 486 487 /** Section Header String Table offset */ 488 private long mShStrTabOffset; 489 490 /** Section Header String Table size */ 491 private long mShStrTabSize; 492 493 /** String Table offset */ 494 private long mStrTabOffset; 495 496 /** String Table size */ 497 private long mStrTabSize; 498 499 /** Dynamic String Table offset */ 500 private long mDynStrOffset; 501 502 /** Dynamic String Table size */ 503 private long mDynStrSize; 504 505 /** Dynamic Table offset */ 506 private long mDynamicTabOffset; 507 508 /** Dynamic Table size */ 509 private long mDynamicTabSize; 510 511 /** Version Symbols Table offset */ 512 private long mVerSymTabOffset; 513 514 /** Version Symbols Table size */ 515 private long mVerSymTabSize; 516 517 /** Version Needs Table offset */ 518 private long mVerNeedTabOffset; 519 520 /** Version Definition Table size */ 521 private long mVerNeedTabSize; 522 523 private int mVerNeedEntryCnt; 524 525 /** Version Definition Table offset */ 526 private long mVerDefTabOffset; 527 528 /** Version Needs Table size */ 529 private long mVerDefTabSize; 530 531 private int mVerDefEntryCnt; 532 533 /** Symbol Table symbol names */ 534 private Map<String, Symbol> mSymbols; 535 536 /** Symbol Table symbol array */ 537 private Symbol[] mSymArr; 538 539 /** Dynamic Symbol Table symbol names */ 540 private Map<String, Symbol> mDynamicSymbols; 541 542 /** Dynamic Symbol Table symbol array */ 543 private Symbol[] mDynSymArr; 544 545 /** Version Symbols Table */ 546 private int[] mVerSym; 547 548 /** Version Needed Table */ 549 private VerNeed[] mVerNeedArr; 550 551 /** Version Definition Table */ 552 private VerDef[] mVerDefArr; 553 554 /** Dynamic Table */ 555 private List<DynamicEntry> mDynamicArr; 556 557 /** Rodata offset */ 558 private boolean mHasRodata; 559 560 /** Rodata offset */ 561 private long mRodataOffset; 562 563 /** Rodata size */ 564 private int mRodataSize; 565 566 /** Rodata String List */ 567 private List<String> mRoStrings; 568 569 /** Rodata byte[] */ 570 private byte[] mRoData; 571 read(File file)572 public static ReadElf read(File file) throws IOException { 573 return new ReadElf(file); 574 } 575 main(String[] args)576 public static void main(String[] args) throws IOException { 577 for (String arg : args) { 578 ReadElf elf = ReadElf.read(new File(arg)); 579 elf.getDynamicSymbol("x"); 580 elf.getSymbol("x"); 581 582 Symbol[] symArr; 583 System.out.println("===Symbol==="); 584 symArr = elf.getSymArr(); 585 for (int i = 0; i < symArr.length; i++) { 586 System.out.println(String.format("%8x: %s", i, symArr[i].toString())); 587 } 588 System.out.println("===Dynamic Symbol==="); 589 symArr = elf.getDynSymArr(); 590 for (int i = 0; i < symArr.length; i++) { 591 if (elf.mVerNeedEntryCnt > 0) { 592 System.out.println( 593 String.format( 594 "%8x: %s, %s, %s - %d", 595 i, 596 symArr[i].toString(), 597 symArr[i].getExternalLibName(), 598 symArr[i].getExternalLibFileName(), 599 symArr[i].getExternalLibVer())); 600 } else { 601 System.out.println( 602 String.format( 603 "%8x: %s, %s - %d", 604 i, 605 symArr[i].toString(), 606 symArr[i].getVerDefLibName(), 607 symArr[i].getVerDefVersion())); 608 } 609 } 610 611 System.out.println("===Dynamic Dependencies==="); 612 for (String DynDepEntry : elf.getDynamicDependencies()) { 613 System.out.println(DynDepEntry); 614 } 615 616 System.out.println("===Strings in Read Only(.rodata) section==="); 617 for (String roStr : elf.getRoStrings()) { 618 System.out.println(roStr); 619 } 620 621 elf.close(); 622 } 623 } 624 isElf(File file)625 public static boolean isElf(File file) { 626 try { 627 if (file.length() < EI_NIDENT) { 628 throw new IllegalArgumentException( 629 "Too small to be an ELF file: " + file.getCanonicalPath()); 630 } 631 632 RandomAccessFile raFile = new RandomAccessFile(file, "r"); 633 byte[] buffer = new byte[512]; 634 raFile.seek(0); 635 raFile.readFully(buffer, 0, EI_NIDENT); 636 if (buffer[0] != ELFMAG[0] 637 || buffer[1] != ELFMAG[1] 638 || buffer[2] != ELFMAG[2] 639 || buffer[3] != ELFMAG[3]) { 640 throw new IllegalArgumentException("Invalid ELF file: " + file.getCanonicalPath()); 641 } 642 raFile.close(); 643 ; 644 return true; 645 } catch (Exception e) { 646 return false; 647 } 648 } 649 getBits()650 public int getBits() { 651 if (mMachine == EM_386 652 || mMachine == EM_MIPS 653 || mMachine == EM_ARM 654 || mMachine == EM_QDSP6) { 655 return 32; 656 } else if (mMachine == EM_AARCH64 || mMachine == EM_X86_64) { 657 return 64; 658 } else { 659 return -1; 660 } 661 } 662 getArchitecture()663 public String getArchitecture() { 664 if (mMachine == EM_ARM || mMachine == EM_AARCH64) { 665 return ARCH_ARM; 666 } else if (mMachine == EM_386 || mMachine == EM_X86_64) { 667 return ARCH_X86; 668 } else if (mMachine == EM_MIPS) { 669 return ARCH_MIPS; 670 } else { 671 return ARCH_UNKNOWN; 672 } 673 } 674 getSymbols()675 public Map<String, Symbol> getSymbols() throws IOException { 676 if (mSymbols == null) { 677 getSymbol(""); 678 } 679 return mSymbols; 680 } 681 getSymArr()682 public Symbol[] getSymArr() throws IOException { 683 if (mSymArr == null) { 684 getSymbol(""); 685 } 686 return mSymArr; 687 } 688 getDynamicSymbols()689 public Map<String, Symbol> getDynamicSymbols() throws IOException { 690 if (mDynamicSymbols == null) { 691 getDynamicSymbol(""); 692 } 693 return mDynamicSymbols; 694 } 695 getDynSymArr()696 public Symbol[] getDynSymArr() throws IOException { 697 if (mDynSymArr == null) { 698 getDynamicSymbol(""); 699 } 700 return mDynSymArr; 701 } 702 isDynamic()703 public boolean isDynamic() { 704 return mIsDynamic; 705 } 706 getType()707 public int getType() { 708 return mType; 709 } 710 isPIE()711 public boolean isPIE() { 712 return mIsPIE; 713 } 714 ReadElf(File file)715 private ReadElf(File file) throws IOException { 716 mHasRodata = false; 717 mRoData = null; 718 mPath = file.getPath(); 719 mFile = new RandomAccessFile(file, "r"); 720 721 if (mFile.length() < EI_NIDENT) { 722 throw new IllegalArgumentException("Too small to be an ELF file: " + file); 723 } 724 725 readHeader(); 726 } 727 728 @Override close()729 public void close() { 730 try { 731 mFile.close(); 732 } catch (IOException ignored) { 733 } 734 } 735 736 @Override finalize()737 protected void finalize() throws Throwable { 738 try { 739 close(); 740 } finally { 741 super.finalize(); 742 } 743 } 744 readHeader()745 private void readHeader() throws IOException { 746 mFile.seek(0); 747 mFile.readFully(mBuffer, 0, EI_NIDENT); 748 749 if (mBuffer[0] != ELFMAG[0] 750 || mBuffer[1] != ELFMAG[1] 751 || mBuffer[2] != ELFMAG[2] 752 || mBuffer[3] != ELFMAG[3]) { 753 throw new IllegalArgumentException("Invalid ELF file: " + mPath); 754 } 755 756 int elfClass = mBuffer[EI_CLASS]; 757 if (elfClass == ELFCLASS32) { 758 mAddrSize = 4; 759 } else if (elfClass == ELFCLASS64) { 760 mAddrSize = 8; 761 } else { 762 throw new IOException("Invalid ELF EI_CLASS: " + elfClass + ": " + mPath); 763 } 764 765 mEndian = mBuffer[EI_DATA]; 766 if (mEndian == ELFDATA2LSB) { 767 } else if (mEndian == ELFDATA2MSB) { 768 throw new IOException("Unsupported ELFDATA2MSB file: " + mPath); 769 } else { 770 throw new IOException("Invalid ELF EI_DATA: " + mEndian + ": " + mPath); 771 } 772 773 mType = readHalf(); 774 775 int e_machine = readHalf(); 776 if (e_machine != EM_386 777 && e_machine != EM_X86_64 778 && e_machine != EM_AARCH64 779 && e_machine != EM_ARM 780 && e_machine != EM_MIPS 781 && e_machine != EM_QDSP6) { 782 throw new IOException("Invalid ELF e_machine: " + e_machine + ": " + mPath); 783 } 784 785 // AbiTest relies on us rejecting any unsupported combinations. 786 if ((e_machine == EM_386 && elfClass != ELFCLASS32) 787 || (e_machine == EM_X86_64 && elfClass != ELFCLASS64) 788 || (e_machine == EM_AARCH64 && elfClass != ELFCLASS64) 789 || (e_machine == EM_ARM && elfClass != ELFCLASS32) 790 || (e_machine == EM_QDSP6 && elfClass != ELFCLASS32)) { 791 throw new IOException( 792 "Invalid e_machine/EI_CLASS ELF combination: " 793 + e_machine 794 + "/" 795 + elfClass 796 + ": " 797 + mPath); 798 } 799 800 mMachine = e_machine; 801 long e_version = readWord(); 802 if (e_version != EV_CURRENT) { 803 throw new IOException("Invalid e_version: " + e_version + ": " + mPath); 804 } 805 806 long e_entry = readAddr(); 807 808 long ph_off = readOff(); 809 long sh_off = readOff(); 810 811 long e_flags = readWord(); 812 int e_ehsize = readHalf(); 813 int e_phentsize = readHalf(); 814 int e_phnum = readHalf(); 815 int e_shentsize = readHalf(); 816 int e_shnum = readHalf(); 817 int e_shstrndx = readHalf(); 818 819 readSectionHeaders(sh_off, e_shnum, e_shentsize, e_shstrndx); 820 readProgramHeaders(ph_off, e_phnum, e_phentsize); 821 } 822 readSectionHeaders(long sh_off, int e_shnum, int e_shentsize, int e_shstrndx)823 private void readSectionHeaders(long sh_off, int e_shnum, int e_shentsize, int e_shstrndx) 824 throws IOException { 825 // Read the Section Header String Table offset first. 826 { 827 mFile.seek(sh_off + e_shstrndx * e_shentsize); 828 829 long sh_name = readWord(); 830 long sh_type = readWord(); 831 long sh_flags = readX(mAddrSize); 832 long sh_addr = readAddr(); 833 long sh_offset = readOff(); 834 long sh_size = readX(mAddrSize); 835 // ... 836 837 if (sh_type == SHT_STRTAB) { 838 mShStrTabOffset = sh_offset; 839 mShStrTabSize = sh_size; 840 } 841 } 842 843 for (int i = 0; i < e_shnum; ++i) { 844 // Don't bother to re-read the Section Header StrTab. 845 if (i == e_shstrndx) { 846 continue; 847 } 848 849 mFile.seek(sh_off + i * e_shentsize); 850 851 long sh_name = readWord(); 852 long sh_type = readWord(); 853 long sh_flags = readX(mAddrSize); 854 long sh_addr = readAddr(); 855 long sh_offset = readOff(); 856 long sh_size = readX(mAddrSize); 857 long sh_link = readWord(); 858 long sh_info = readWord(); 859 long sh_addralign = readX(mAddrSize); 860 ; 861 long sh_entsize = readX(mAddrSize); 862 ; 863 864 if (sh_type == SHT_SYMTAB || sh_type == SHT_DYNSYM) { 865 final String symTabName = readShStrTabEntry(sh_name); 866 if (".symtab".equals(symTabName)) { 867 mSymTabOffset = sh_offset; 868 mSymTabSize = sh_size; 869 mSymEntCnt = (int) (sh_size / sh_entsize); 870 } else if (".dynsym".equals(symTabName)) { 871 mDynSymOffset = sh_offset; 872 mDynSymSize = sh_size; 873 mDynSymEntCnt = (int) (sh_size / sh_entsize); 874 } 875 System.out.println( 876 String.format( 877 "%s, %d, %d, %d, %d, %d", 878 symTabName, sh_offset, sh_size, sh_link, sh_info, sh_entsize)); 879 } else if (sh_type == SHT_STRTAB) { 880 final String strTabName = readShStrTabEntry(sh_name); 881 if (".strtab".equals(strTabName)) { 882 mStrTabOffset = sh_offset; 883 mStrTabSize = sh_size; 884 System.out.println( 885 String.format( 886 "%s, %d, %d, %d, %d", 887 strTabName, sh_offset, sh_size, sh_link, sh_info)); 888 } else if (".dynstr".equals(strTabName)) { 889 mDynStrOffset = sh_offset; 890 mDynStrSize = sh_size; 891 System.out.println( 892 String.format( 893 "%s, %d, %d, %d, %d", 894 strTabName, sh_offset, sh_size, sh_link, sh_info)); 895 } 896 } else if (sh_type == SHT_DYNAMIC) { 897 mIsDynamic = true; 898 final String strTabName = readShStrTabEntry(sh_name); 899 mDynamicTabOffset = sh_offset; 900 mDynamicTabSize = sh_size; 901 System.out.println( 902 String.format( 903 "%s, %d, %d, %d, %d", 904 strTabName, sh_offset, sh_size, sh_link, sh_info)); 905 } else if (sh_type == SHT_GNU_VERSYM) { 906 final String strTabName = readShStrTabEntry(sh_name); 907 if (".gnu.version".equals(strTabName)) { 908 mVerSymTabOffset = sh_offset; 909 mVerSymTabSize = sh_size; 910 } 911 System.out.println( 912 String.format( 913 "%s, %d, %d, %d, %d", 914 strTabName, sh_offset, sh_size, sh_link, sh_info)); 915 } else if (sh_type == SHT_GNU_VERNEED) { 916 final String strTabName = readShStrTabEntry(sh_name); 917 if (".gnu.version_r".equals(strTabName)) { 918 mVerNeedTabOffset = sh_offset; 919 mVerNeedTabSize = sh_size; 920 mVerNeedEntryCnt = (int) sh_info; 921 } 922 System.out.println( 923 String.format( 924 "%s, %d, %d, %d, %d", 925 strTabName, sh_offset, sh_size, sh_link, sh_info)); 926 } else if (sh_type == SHT_GNU_VERDEF) { 927 final String strTabName = readShStrTabEntry(sh_name); 928 if (".gnu.version_d".equals(strTabName)) { 929 mVerDefTabOffset = sh_offset; 930 mVerDefTabSize = sh_size; 931 mVerDefEntryCnt = (int) sh_info; 932 } 933 System.out.println( 934 String.format( 935 "%s, %d, %d, %d, %d", 936 strTabName, sh_offset, sh_size, sh_link, sh_info)); 937 } else if (sh_type == SHT_PROGBITS) { 938 final String strTabName = readShStrTabEntry(sh_name); 939 if (".rodata".equals(strTabName)) { 940 mHasRodata = true; 941 mRodataOffset = sh_offset; 942 mRodataSize = (int) sh_size; 943 } 944 System.out.println( 945 String.format( 946 "%s, %d, %d, %d, %d", 947 strTabName, sh_offset, sh_size, sh_link, sh_info)); 948 } 949 } 950 } 951 readProgramHeaders(long ph_off, int e_phnum, int e_phentsize)952 private void readProgramHeaders(long ph_off, int e_phnum, int e_phentsize) throws IOException { 953 for (int i = 0; i < e_phnum; ++i) { 954 mFile.seek(ph_off + i * e_phentsize); 955 956 long p_type = readWord(); 957 if (p_type == PT_LOAD) { 958 if (mAddrSize == 8) { 959 // Only in Elf64_phdr; in Elf32_phdr p_flags is at the end. 960 long p_flags = readWord(); 961 } 962 long p_offset = readOff(); 963 long p_vaddr = readAddr(); 964 // ... 965 966 if (p_vaddr == 0) { 967 mIsPIE = true; 968 } 969 } 970 } 971 } 972 readSymbolTable( Symbol[] symArr, boolean isDynSym, long symStrOffset, long symStrSize, long tableOffset, long tableSize)973 private HashMap<String, Symbol> readSymbolTable( 974 Symbol[] symArr, 975 boolean isDynSym, 976 long symStrOffset, 977 long symStrSize, 978 long tableOffset, 979 long tableSize) 980 throws IOException { 981 HashMap<String, Symbol> result = new HashMap<String, Symbol>(); 982 mFile.seek(tableOffset); 983 int i = 0; 984 while (mFile.getFilePointer() < tableOffset + tableSize) { 985 long st_name = readWord(); 986 int st_info; 987 int st_shndx; 988 long st_value; 989 long st_size; 990 int st_other; 991 if (mAddrSize == 8) { 992 st_info = readByte(); 993 st_other = readByte(); 994 st_shndx = readHalf(); 995 st_value = readAddr(); 996 st_size = readX(mAddrSize); 997 } else { 998 st_value = readAddr(); 999 st_size = readWord(); 1000 st_info = readByte(); 1001 st_other = readByte(); 1002 st_shndx = readHalf(); 1003 } 1004 1005 String symName; 1006 if (st_name == 0) { 1007 symName = ""; 1008 } else { 1009 symName = readStrTabEntry(symStrOffset, symStrSize, st_name); 1010 } 1011 1012 Symbol sym = new Symbol(symName, st_info, st_shndx, st_value, st_size, st_other); 1013 if (!symName.equals("")) { 1014 result.put(symName, sym); 1015 } 1016 if (isDynSym) { 1017 if (mVerNeedEntryCnt > 0) { 1018 if (sym.type == Symbol.STT_NOTYPE) { 1019 sym.mVerNeed = mVerNeedArr[0]; 1020 } else { 1021 sym.mVerNeed = getVerNeed(mVerSym[i]); 1022 } 1023 } else if (mVerDefEntryCnt > 0) { 1024 sym.mVerDef = mVerDefArr[mVerSym[i]]; 1025 } 1026 } 1027 symArr[i] = sym; 1028 i++; 1029 } 1030 System.out.println( 1031 String.format( 1032 "Info readSymbolTable: %s, isDynSym %b, symbol# %d", 1033 mPath, isDynSym, symArr.length)); 1034 return result; 1035 } 1036 readShStrTabEntry(long strOffset)1037 private String readShStrTabEntry(long strOffset) throws IOException { 1038 if (mShStrTabOffset == 0 || strOffset < 0 || strOffset >= mShStrTabSize) { 1039 return null; 1040 } 1041 return readString(mShStrTabOffset + strOffset); 1042 } 1043 readStrTabEntry(long tableOffset, long tableSize, long strOffset)1044 private String readStrTabEntry(long tableOffset, long tableSize, long strOffset) 1045 throws IOException { 1046 if (tableOffset == 0 || strOffset < 0 || strOffset >= tableSize) { 1047 return null; 1048 } 1049 return readString(tableOffset + strOffset); 1050 } 1051 readDynStrTabEntry(long strOffset)1052 private String readDynStrTabEntry(long strOffset) throws IOException { 1053 if (mDynStrOffset == 0 || strOffset < 0 || strOffset >= mDynStrSize) { 1054 return null; 1055 } 1056 return readString(mDynStrOffset + strOffset); 1057 } 1058 getVerSym()1059 private int[] getVerSym() throws IOException { 1060 if (mVerSym == null) { 1061 mFile.seek(mVerSymTabOffset); 1062 int cnt = (int) mVerSymTabSize / 2; 1063 mVerSym = new int[cnt]; 1064 for (int i = 0; i < cnt; i++) { 1065 mVerSym[i] = readHalf(); 1066 //System.out.println(String.format("%d, %d", i, mVerSym[i])); 1067 } 1068 } 1069 return mVerSym; 1070 } 1071 getVerNeed(int ndx)1072 public VerNeed getVerNeed(int ndx) throws IOException { 1073 // vna_other Contains version index unique for the file which is used in the version symbol table. 1074 if (ndx < 2) { 1075 return this.mVerNeedArr[ndx]; 1076 } 1077 1078 for (int i = 2; i < this.mVerNeedEntryCnt + 2; i++) { 1079 for (int j = 0; j < this.mVerNeedArr[i].vn_cnt; j++) { 1080 if (this.mVerNeedArr[i].vn_vernaux[j].vna_other == ndx) { 1081 return this.mVerNeedArr[i]; 1082 } 1083 } 1084 } 1085 System.out.println(String.format("no VerNeed found: %d", ndx)); 1086 return null; 1087 } 1088 getVerNeedArr()1089 private VerNeed[] getVerNeedArr() throws IOException { 1090 if (mVerNeedArr == null) { 1091 mVerNeedArr = new VerNeed[mVerNeedEntryCnt + 2]; 1092 1093 // SHT_GNU_versym 0: local 1094 mVerNeedArr[0] = new VerNeed("*local*", "*local*", 0); 1095 // HT_GNU_versym 1: global 1096 mVerNeedArr[1] = new VerNeed("*global*", "*global*", 1); 1097 1098 long idx = mVerNeedTabOffset; 1099 for (int i = 2; i < mVerNeedEntryCnt + 2; i++) { 1100 mFile.seek(idx); 1101 mVerNeedArr[i] = 1102 new VerNeed(readHalf(), readHalf(), readWord(), readWord(), readWord()); 1103 mVerNeedArr[i].vn_file_name = readDynStrTabEntry(mVerNeedArr[i].vn_file).toLowerCase(); 1104 1105 mVerNeedArr[i].vn_vernaux = new VerNAux[mVerNeedArr[i].vn_cnt]; 1106 long idxAux = idx + mVerNeedArr[i].vn_aux; 1107 for (int j = 0; j < mVerNeedArr[i].vn_cnt; j++) { 1108 mFile.seek(idxAux); 1109 mVerNeedArr[i].vn_vernaux[j] = 1110 new VerNAux(readWord(), readHalf(), readHalf(), readWord(), readWord()); 1111 mVerNeedArr[i].vn_vernaux[j].vna_lib_name = 1112 readDynStrTabEntry(mVerNeedArr[i].vn_vernaux[j].vna_name); 1113 idxAux += mVerNeedArr[i].vn_vernaux[j].vna_next; 1114 } 1115 idx += mVerNeedArr[i].vn_next; 1116 System.out.println(mVerNeedArr[i]); 1117 } 1118 } 1119 1120 return mVerNeedArr; 1121 } 1122 getVerDef()1123 private VerDef[] getVerDef() throws IOException { 1124 if (mVerDefArr == null) { 1125 mVerDefArr = new VerDef[mVerDefEntryCnt + 2]; 1126 1127 // SHT_GNU_versym 0: local 1128 mVerDefArr[0] = new VerDef("*local*"); 1129 // HT_GNU_versym 1: global 1130 mVerDefArr[1] = new VerDef("*global*"); 1131 1132 long idx = mVerDefTabOffset; 1133 for (int i = 2; i < mVerDefEntryCnt + 2; i++) { 1134 mFile.seek(idx); 1135 mVerDefArr[i] = 1136 new VerDef( 1137 readHalf(), 1138 readHalf(), 1139 readHalf(), 1140 readHalf(), 1141 readWord(), 1142 readWord(), 1143 readWord()); 1144 1145 mVerDefArr[i].vd_verdaux = new VerDAux[mVerDefArr[i].vd_cnt]; 1146 long idxAux = idx + mVerDefArr[i].vd_aux; 1147 for (int j = 0; j < mVerDefArr[i].vd_cnt; j++) { 1148 mFile.seek(idxAux); 1149 mVerDefArr[i].vd_verdaux[j] = new VerDAux(readWord(), readWord()); 1150 mVerDefArr[i].vd_verdaux[j].vda_lib_name = 1151 readDynStrTabEntry(mVerDefArr[i].vd_verdaux[j].vda_name).toLowerCase(); 1152 idxAux += mVerDefArr[i].vd_verdaux[j].vda_next; 1153 } 1154 idx += mVerDefArr[i].vd_next; 1155 System.out.println(mVerDefArr[i]); 1156 } 1157 } 1158 return mVerDefArr; 1159 } 1160 readHalf()1161 private int readHalf() throws IOException { 1162 return (int) readX(2); 1163 } 1164 readWord()1165 private long readWord() throws IOException { 1166 return readX(4); 1167 } 1168 readOff()1169 private long readOff() throws IOException { 1170 return readX(mAddrSize); 1171 } 1172 readAddr()1173 private long readAddr() throws IOException { 1174 return readX(mAddrSize); 1175 } 1176 readX(int byteCount)1177 private long readX(int byteCount) throws IOException { 1178 mFile.readFully(mBuffer, 0, byteCount); 1179 1180 int answer = 0; 1181 if (mEndian == ELFDATA2LSB) { 1182 for (int i = byteCount - 1; i >= 0; i--) { 1183 answer = (answer << 8) | (mBuffer[i] & 0xff); 1184 } 1185 } else { 1186 final int N = byteCount - 1; 1187 for (int i = 0; i <= N; ++i) { 1188 answer = (answer << 8) | (mBuffer[i] & 0xff); 1189 } 1190 } 1191 1192 return answer; 1193 } 1194 readString(long offset)1195 private String readString(long offset) throws IOException { 1196 long originalOffset = mFile.getFilePointer(); 1197 mFile.seek(offset); 1198 mFile.readFully(mBuffer, 0, (int) Math.min(mBuffer.length, mFile.length() - offset)); 1199 mFile.seek(originalOffset); 1200 1201 for (int i = 0; i < mBuffer.length; ++i) { 1202 if (mBuffer[i] == 0) { 1203 return new String(mBuffer, 0, i); 1204 } 1205 } 1206 1207 return null; 1208 } 1209 readByte()1210 private int readByte() throws IOException { 1211 return mFile.read() & 0xff; 1212 } 1213 getSymbol(String name)1214 public Symbol getSymbol(String name) { 1215 if (mSymbols == null) { 1216 try { 1217 mSymArr = new Symbol[mSymEntCnt]; 1218 mSymbols = 1219 readSymbolTable( 1220 mSymArr, 1221 false, 1222 mStrTabOffset, 1223 mStrTabSize, 1224 mSymTabOffset, 1225 mSymTabSize); 1226 } catch (IOException e) { 1227 return null; 1228 } 1229 } 1230 return mSymbols.get(name); 1231 } 1232 getDynamicSymbol(String name)1233 public Symbol getDynamicSymbol(String name) throws IOException { 1234 if (mDynamicSymbols == null) { 1235 try { 1236 int[] verSmyArr = this.getVerSym(); 1237 VerNeed[] verNeedArr = this.getVerNeedArr(); 1238 VerDef[] verDefArr = this.getVerDef(); 1239 mDynSymArr = new Symbol[mDynSymEntCnt]; 1240 mDynamicSymbols = 1241 readSymbolTable( 1242 mDynSymArr, 1243 true, 1244 mDynStrOffset, 1245 mDynStrSize, 1246 mDynSymOffset, 1247 mDynSymSize); 1248 } catch (IOException e) { 1249 return null; 1250 } 1251 } 1252 return mDynamicSymbols.get(name); 1253 } 1254 1255 // Get Dynamic Linking Dependency List getDynamicDependencies()1256 public List<String> getDynamicDependencies() throws IOException { 1257 List<String> result = new ArrayList<>(); 1258 for (DynamicEntry entry : getDynamicList()) { 1259 if (entry.isNeeded()) { 1260 result.add(readDynStr(entry.getValue())); 1261 } 1262 } 1263 return result; 1264 } 1265 getDynamicList()1266 private List<DynamicEntry> getDynamicList() throws IOException { 1267 if (mDynamicArr == null) { 1268 int entryNo = 0; 1269 mDynamicArr = new ArrayList<>(); 1270 mFile.seek(mDynamicTabOffset); 1271 System.out.println( 1272 String.format( 1273 "mDynamicTabOffset 0x%x, mDynamicTabSize %d", 1274 mDynamicTabOffset, mDynamicTabSize)); 1275 while (true) { 1276 long tag = readX(mAddrSize); 1277 long value = readX(mAddrSize); 1278 // System.out.println(String.format("%d: 0x%x, %d", entryNo, tag, value)); 1279 mDynamicArr.add(new DynamicEntry(tag, value)); 1280 if (tag == 0) { 1281 break; 1282 } 1283 entryNo++; 1284 } 1285 } 1286 return mDynamicArr; 1287 } 1288 readDynStr(long strOffset)1289 private String readDynStr(long strOffset) throws IOException { 1290 int offset = (int) (strOffset & 0xFFFFFFFF); 1291 if (mDynStrOffset == 0 || offset < 0 || offset >= mDynStrSize) { 1292 System.err.println( 1293 String.format( 1294 "err mDynStrOffset: %d, mDynStrSize: %d, offset: %d", 1295 mDynStrOffset, mDynStrSize, offset)); 1296 return String.format("%d", offset); 1297 } 1298 return readString(mDynStrOffset + offset); 1299 } 1300 1301 /** 1302 * Gets a list of string from .rodata section 1303 * 1304 * @return a String list .rodata section 1305 */ getRoStrings()1306 public List<String> getRoStrings() throws IOException { 1307 if (mRoStrings == null) { 1308 mRoStrings = new ArrayList<>(); 1309 byte[] byteArr = getRoData(); 1310 if (byteArr != null) { 1311 int strOffset = 0; 1312 for (int i = 0; i < mRodataSize; i++) { 1313 if (byteArr[i] == 0) { 1314 // skip null string 1315 if (i != strOffset) { 1316 String str = new String(byteArr, strOffset, i - strOffset); 1317 mRoStrings.add(str); 1318 } 1319 strOffset = i + 1; 1320 } 1321 } 1322 } 1323 } 1324 return mRoStrings; 1325 } 1326 1327 /** 1328 * Gets .rodata section 1329 * 1330 * @return byte [] of .rodata or null if there is none 1331 */ getRoData()1332 public byte[] getRoData() throws IOException { 1333 if (mHasRodata && mRoData == null) { 1334 mRoData = new byte[mRodataSize]; 1335 mFile.seek(mRodataOffset); 1336 mFile.readFully(mRoData); 1337 } 1338 1339 return mRoData; 1340 } 1341 } 1342