001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.cnd.dwarfdump.reader;
043:
044: import java.io.RandomAccessFile;
045: import org.netbeans.modules.cnd.dwarfdump.FileMagic;
046: import org.netbeans.modules.cnd.dwarfdump.Magic;
047: import org.netbeans.modules.cnd.dwarfdump.dwarfconsts.ElfConstants;
048: import org.netbeans.modules.cnd.dwarfdump.elf.ElfHeader;
049: import org.netbeans.modules.cnd.dwarfdump.exception.WrongFileFormatException;
050: import org.netbeans.modules.cnd.dwarfdump.section.ElfSection;
051: import org.netbeans.modules.cnd.dwarfdump.elf.ProgramHeaderTable;
052: import org.netbeans.modules.cnd.dwarfdump.elf.SectionHeader;
053: import org.netbeans.modules.cnd.dwarfdump.section.StringTableSection;
054: import java.io.IOException;
055: import java.util.ArrayList;
056: import java.util.HashMap;
057: import java.util.List;
058: import org.netbeans.modules.cnd.dwarfdump.trace.TraceDwarf;
059:
060: /**
061: *
062: * @author ak119685
063: */
064: public class ElfReader extends ByteStreamReader {
065: private boolean isCoffFormat;
066: private boolean isMachoFormat;
067: private ElfHeader elfHeader = null;
068: private ProgramHeaderTable programHeaderTable;
069: private SectionHeader[] sectionHeadersTable;
070: private ElfSection[] sections = null;
071: private HashMap<String, Integer> sectionsMap = new HashMap<String, Integer>();
072: private StringTableSection stringTableSection = null;
073: private long shiftIvArchive = 0;
074: private long lengthIvArchive = 0;
075:
076: public ElfReader(String fname, RandomAccessFile reader,
077: Magic magic, long shift, long length) throws IOException {
078: super (fname, reader);
079: shiftIvArchive = shift;
080: lengthIvArchive = length;
081: if (!readHeader(magic)) {
082: return;
083: }
084: readProgramHeaderTable();
085: readSectionHeaderTable();
086:
087: sections = new ElfSection[sectionHeadersTable.length];
088:
089: // Before reading all sections need to read ElfStringTable section.
090: int elfStringTableIdx = elfHeader
091: .getELFStringTableSectionIndex();
092: if (!isCoffFormat && !isMachoFormat) {
093: stringTableSection = new StringTableSection(this ,
094: elfStringTableIdx);
095: }
096: sections[elfStringTableIdx] = stringTableSection;
097:
098: // Initialize Name-To-Idx map
099:
100: for (int i = 0; i < sections.length; i++) {
101: sectionsMap.put(getSectionName(i), i);
102: }
103: }
104:
105: public String getSectionName(int sectionIdx) {
106: if (!isCoffFormat && !isMachoFormat) {
107: if (stringTableSection == null) {
108: return ".shstrtab"; // NOI18N
109: }
110:
111: long nameOffset = sectionHeadersTable[sectionIdx].sh_name;
112: return stringTableSection.getString(nameOffset);
113: } else {
114: return sectionHeadersTable[sectionIdx].getSectionName();
115: }
116: }
117:
118: public boolean readHeader(Magic magic)
119: throws WrongFileFormatException, IOException {
120: elfHeader = new ElfHeader();
121: seek(shiftIvArchive);
122: byte[] bytes = new byte[16];
123: read(bytes);
124: switch (magic) {
125: case Elf:
126: readElfHeader(bytes);
127: return true;
128: case Coff:
129: readCoffHeader(shiftIvArchive);
130: return true;
131: case Exe:
132: readPeHeader(true);
133: return true;
134: case Pe:
135: readPeHeader(false);
136: return true;
137: case Macho:
138: return readMachoHeader();
139: }
140: throw new WrongFileFormatException(
141: "Not an ELF/PE/COFF/MACH-O file"); // NOI18N
142: }
143:
144: private void readElfHeader(byte[] bytes) throws IOException {
145: elfHeader.elfClass = bytes[4];
146: elfHeader.elfData = bytes[5];
147: elfHeader.elfVersion = bytes[6];
148: elfHeader.elfOs = bytes[7];
149: elfHeader.elfAbi = bytes[8];
150:
151: setDataEncoding(elfHeader.elfData);
152: setFileClass(elfHeader.elfClass);
153:
154: elfHeader.e_type = readShort();
155: elfHeader.e_machine = readShort();
156: elfHeader.e_version = readInt();
157: elfHeader.e_entry = read3264() + shiftIvArchive;
158: elfHeader.e_phoff = read3264() + shiftIvArchive;
159: elfHeader.e_shoff = read3264() + shiftIvArchive;
160: elfHeader.e_flags = readInt();
161: elfHeader.e_ehsize = readShort();
162: elfHeader.e_phentsize = readShort();
163: elfHeader.e_phnum = readShort();
164: elfHeader.e_shentsize = readShort();
165: elfHeader.e_shnum = readShort();
166: elfHeader.e_shstrndx = readShort();
167: }
168:
169: private void readPeHeader(boolean isExe) throws IOException {
170: elfHeader.elfData = LSB;
171: elfHeader.elfClass = ElfConstants.ELFCLASS32;
172: setDataEncoding(elfHeader.elfData);
173: setFileClass(elfHeader.elfClass);
174: int peOffset = 0;
175: if (isExe) {
176: seek(0x3c);
177: peOffset = readInt();
178: seek(peOffset);
179: byte[] bytes = new byte[4];
180: read(bytes);
181: if (!FileMagic.isPeMagic(bytes)) {
182: throw new WrongFileFormatException(
183: "Not an PE/COFF file"); // NOI18N
184: }
185: }
186: // skip PE magic
187: readCoffHeader(peOffset + 4);
188: }
189:
190: private void readCoffHeader(long shift) throws IOException {
191: isCoffFormat = true;
192: // Skip magic
193: seek(2 + shift);
194: elfHeader.elfData = LSB;
195: elfHeader.elfClass = ElfConstants.ELFCLASS32;
196: setDataEncoding(elfHeader.elfData);
197: setFileClass(elfHeader.elfClass);
198: elfHeader.e_shnum = readShort();
199: //skip time stump
200: readInt();
201: // read string table
202: long symbolTableOffset = shiftIvArchive + readInt();
203: int symbolTableEntries = readInt();
204: long stringTableOffset = symbolTableOffset + symbolTableEntries
205: * 18;
206: int stringTableLength = (int) (shiftIvArchive + lengthIvArchive - stringTableOffset);
207: long pointer = getFilePointer();
208: seek(stringTableOffset);
209: byte[] strings = new byte[stringTableLength];
210: read(strings);
211: stringTableSection = new StringTableSection(this , strings);
212: seek(pointer);
213: //
214: int optionalHeaderSize = readShort();
215: // flags
216: int flags = readShort();
217: if (optionalHeaderSize > 0) {
218: skipBytes(optionalHeaderSize);
219: }
220: elfHeader.e_shoff = getFilePointer();
221: }
222:
223: private boolean readMachoHeader() throws IOException {
224: isMachoFormat = true;
225: elfHeader.elfData = LSB;
226: elfHeader.elfClass = ElfConstants.ELFCLASS32;
227: setDataEncoding(elfHeader.elfData);
228: setFileClass(elfHeader.elfClass);
229: seek(shiftIvArchive);
230: boolean is64 = readByte() == (byte) 0xcf;
231: seek(shiftIvArchive + 16);
232: int ncmds = readInt();
233: int sizeOfCmds = readInt();
234: int flags = readInt();
235: if (is64) {
236: skipBytes(4);
237: }
238: List<SectionHeader> headers = new ArrayList<SectionHeader>();
239: for (int j = 0; j < ncmds; j++) {
240: int cmd = readInt();
241: int cmdSize = readInt();
242: if (TraceDwarf.TRACED) {
243: System.out.println("Load command: "
244: + LoadCommand.valueOf(cmd) + " (" + cmd + ")"); //NOI18N
245: }
246: if (LoadCommand.LC_SEGMENT.is(cmd)
247: || LoadCommand.LC_SEGMENT_64.is(cmd)) { //LC_SEGMENT LC_SEGMENT64
248: skipBytes(16);
249: if (is64) {
250: long vmAddr = readLong();
251: long vmSize = readLong();
252: long fileOff = readLong();
253: long fileSize = readLong();
254: } else {
255: int vmAddr = readInt();
256: int vmSize = readInt();
257: int fileOff = readInt();
258: int fileSize = readInt();
259: }
260: int vmMaxPort = readInt();
261: int vmInitPort = readInt();
262: int nSects = readInt();
263: int cmdFlags = readInt();
264: for (int i = 0; i < nSects; i++) {
265: SectionHeader h = readMachoSection(is64);
266: if (h != null) {
267: headers.add(h);
268: }
269: }
270: } else if (LoadCommand.LC_SYMTAB.is(cmd)) { //LC_SYMTAB
271: int symOffset = readInt();
272: int nsyms = readInt();
273: long strOffset = readInt() + shiftIvArchive;
274: int strSize = readInt();
275: // read string table
276: long pointer = getFilePointer();
277: seek(strOffset);
278: byte[] strings = new byte[strSize];
279: read(strings);
280: stringTableSection = new StringTableSection(this ,
281: strings);
282: seek(pointer);
283: } else {
284: skipBytes(cmdSize - 8);
285: }
286: }
287: if (TraceDwarf.TRACED && stringTableSection != null) {
288: stringTableSection.dump(System.out);
289: }
290: if (headers.size() == 0 || stringTableSection == null) {
291: if (isThereAnyLinkedObjectFiles(stringTableSection)) {
292: // we got situation when Mac's linker put dwarf information not in the executable file
293: // but just put links to object files instead
294: return false;
295: }
296: throw new WrongFileFormatException(
297: "Dwarf section not found in Mach-O file"); // NOI18N
298: }
299: sectionHeadersTable = new SectionHeader[headers.size()];
300: for (int i = 0; i < headers.size(); i++) {
301: sectionHeadersTable[i] = headers.get(i);
302: }
303: elfHeader.e_shstrndx = (short) (headers.size() - 1);
304: return true;
305: }
306:
307: private boolean isThereAnyLinkedObjectFiles(
308: StringTableSection stringTableSection) {
309: if (stringTableSection == null) {
310: return false;
311: }
312: int offset = 1;
313: while (offset < stringTableSection.getStringTable().length) {
314: String string = stringTableSection.getString(offset);
315: // XXX: find out how gdb determines object files link
316: // but this way would work 90% of times
317: if (string.length() > 2
318: && ".o".equals(string
319: .substring(string.length() - 2))) { //NOI18N
320: linkedObjectFiles.add(string);
321: }
322: offset += string.length() + 1;
323: }
324:
325: return linkedObjectFiles.size() > 0;
326: }
327:
328: private List<String> linkedObjectFiles = new ArrayList<String>();
329:
330: public List<String> getLinkedObjectFiles() {
331: return linkedObjectFiles;
332: }
333:
334: private SectionHeader readMachoSection(boolean is64)
335: throws IOException {
336: byte[] sectName = new byte[16];
337: read(sectName);
338: String section = getName(sectName, 0);
339: byte[] segName = new byte[16];
340: read(segName);
341: String segment = getName(segName, 0);
342: long addr;
343: long size;
344: if (is64) {
345: addr = readLong();
346: size = readLong();
347: } else {
348: addr = readInt();
349: size = readInt();
350: }
351: long offset = readInt() + shiftIvArchive;
352: int align = readInt();
353: int reloff = readInt();
354: int nreloc = readInt();
355: int segFlags = readInt();
356: readInt();
357: readInt();
358: if (is64) {
359: readInt();
360: }
361: if ("__DWARF".equals(segment)) {// NOI18N
362: SectionHeader h = new SectionHeader();
363: if (section.startsWith("__debug")) {// NOI18N
364: // convert to elf standard
365: section = "." + section.substring(2);// NOI18N
366: }
367: h.name = section;
368: h.sh_size = size;
369: h.sh_offset = offset;
370: h.sh_flags = segFlags;
371: return h;
372: } else if (TraceDwarf.TRACED) {
373: System.out.println("Segment,Section: " + segment + ","
374: + section); //NOI18N
375: }
376: return null;
377: }
378:
379: private String getName(byte[] stringtable, int offset) {
380: StringBuilder str = new StringBuilder();
381: for (int i = offset; i < stringtable.length; i++) {
382: if (stringtable[i] == 0) {
383: break;
384: }
385: str.append((char) stringtable[i]);
386: }
387: return str.toString();
388: }
389:
390: private void readProgramHeaderTable() {
391: // TODO: Add code
392: }
393:
394: private void readSectionHeaderTable() throws IOException {
395: long sectionHeaderOffset = elfHeader.getSectionHeaderOffset();
396:
397: if (sectionHeaderOffset > 0) {
398: seek(sectionHeaderOffset);
399: int sectionsNum = elfHeader.getNumberOfSectionHeaders();
400:
401: sectionHeadersTable = new SectionHeader[sectionsNum];
402:
403: for (int i = 0; i < sectionsNum; i++) {
404: if (isCoffFormat) {
405: sectionHeadersTable[i] = readCoffSectionHeader();
406: } else {
407: sectionHeadersTable[i] = readSectionHeader();
408: }
409: }
410: }
411: }
412:
413: private SectionHeader readSectionHeader() throws IOException {
414: SectionHeader h = new SectionHeader();
415:
416: h.sh_name = readInt();
417: h.sh_type = readInt();
418: h.sh_flags = read3264();
419: h.sh_addr = read3264();
420: h.sh_offset = read3264() + shiftIvArchive;
421: h.sh_size = read3264();
422: h.sh_link = readInt();
423: h.sh_info = readInt();
424: h.sh_addralign = read3264();
425: h.sh_entsize = read3264();
426:
427: return h;
428: }
429:
430: private SectionHeader readCoffSectionHeader() throws IOException {
431: SectionHeader h = new SectionHeader();
432:
433: byte[] bytes = new byte[8];
434: read(bytes);
435: String name = null;
436: if (bytes[0] == '/') {
437: int length = 0;
438: for (int j = 1; j < 8; j++) {
439: byte c = bytes[j];
440: if (c < '0') {
441: break;
442: }
443: length *= 10;
444: length += (c - '0');
445: }
446: name = stringTableSection.getString(length);
447: } else {
448: name = getName(bytes, 0);
449: }
450: h.name = name;
451: //System.out.println("Section: "+name);
452: int phisicalAddres = readInt();
453: int virtualAddres = readInt();
454: h.sh_size = readInt();
455: h.sh_offset = shiftIvArchive + readInt();
456: int relocationOffset = readInt();
457: int lineNumberOffset = readInt();
458: int mumberRelocations = readShort();
459: int mumberLineNumbers = readShort();
460: h.sh_flags = readInt();
461: return h;
462: }
463:
464: StringTableSection readStringTableSection(String sectionName)
465: throws IOException {
466: Integer sectionIdx = sectionsMap.get(sectionName);
467: return (sectionIdx == null) ? null
468: : readStringTableSection(sectionIdx);
469: }
470:
471: StringTableSection readStringTableSection(int sectionIdx)
472: throws IOException {
473: sections[sectionIdx] = new StringTableSection(this , sectionIdx);
474: return (StringTableSection) sections[sectionIdx];
475: }
476:
477: public ElfSection getSection(String sectionName) {
478: Integer sectionIdx = sectionsMap.get(sectionName);
479:
480: if (sectionIdx == null) {
481: return null;
482: }
483:
484: if (sections[sectionIdx] == null) {
485: sections[sectionIdx] = initSection(sectionIdx, sectionName);
486: }
487:
488: return sections[sectionIdx];
489: }
490:
491: ElfSection initSection(Integer sectionIdx, String sectionName) {
492: return null;
493: }
494:
495: public SectionHeader getSectionHeader(int sectionIdx) {
496: return sectionHeadersTable[sectionIdx];
497: }
498:
499: }
500:
501: enum LoadCommand {
502: UNKNOWN, LC_SEGMENT, LC_SYMTAB, LC_SYMSEG, LC_THREAD, LC_UNIXTHREAD, LC_LOADFVMLIB, LC_IDFVMLIB, LC_IDENT, LC_FVMFILE, LC_PREPAGE, LC_DYSYMTAB, LC_LOAD_DYLIB, LC_ID_DYLIB, LC_LOAD_DYLINKER, LC_ID_DYLINKER, LC_PREBOUND_DYLIB, LC_ROUTINES, LC_SUB_FRAMEWORK, LC_SUB_UMBRELLA, LC_SUB_CLIENT, LC_SUB_LIBRARY, LC_TWOLEVEL_HINTS, LC_PREBIND_CKSUM, LC_LOAD_WEAK_DYLIB, LC_SEGMENT_64, LC_ROUTINES_64, LC_UUID, UNDEFINED, LC_CODE_SIGNATURE;
503:
504: public boolean is(int value) {
505: return ordinal() == value;
506: }
507:
508: public static LoadCommand valueOf(int k) {
509: for (LoadCommand command : values()) {
510: if (command.is(k)) {
511: return command;
512: }
513: }
514: return UNKNOWN;
515: }
516: }
|