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;
043:
044: import java.io.File;
045: import java.io.FileNotFoundException;
046: import java.io.IOException;
047: import java.io.RandomAccessFile;
048: import java.util.ArrayList;
049: import java.util.LinkedList;
050: import java.util.List;
051: import org.netbeans.modules.cnd.dwarfdump.dwarfconsts.SECTIONS;
052: import org.netbeans.modules.cnd.dwarfdump.exception.WrongFileFormatException;
053: import org.netbeans.modules.cnd.dwarfdump.reader.DwarfReader;
054: import org.netbeans.modules.cnd.dwarfdump.section.DwarfDebugInfoSection;
055: import org.netbeans.modules.cnd.dwarfdump.section.ElfSection;
056: import org.netbeans.modules.cnd.dwarfdump.trace.TraceDwarf;
057:
058: /**
059: *
060: * @author ak119685
061: */
062: public class Dwarf {
063: private DwarfReader dwarfReader;
064: private List<MemberHeader> offsets;
065: private FileMagic magic;
066: private String fileName;
067:
068: enum Mode {
069: Normal, Archive, MachoLOF
070: };
071:
072: private final Mode mode;
073:
074: public Dwarf(String objFileName) throws FileNotFoundException,
075: WrongFileFormatException, IOException {
076: if (TraceDwarf.TRACED) {
077: System.out.println("\n**** Dwarfing " + objFileName + "\n"); //NOI18N
078: }
079: fileName = objFileName;
080: magic = new FileMagic(objFileName);
081: if (magic.getMagic() == Magic.Arch) {
082: // support archives
083: skipFirstHeader(magic.getReader());
084: offsets = getObjectTable(magic.getReader());
085: if (offsets.size() == 0) {
086: throw new WrongFileFormatException("Not an ELF file"); // NOI18N
087: }
088: mode = Mode.Archive;
089: } else {
090: dwarfReader = new DwarfReader(objFileName, magic
091: .getReader(), magic.getMagic(), 0, magic
092: .getReader().length());
093: if (dwarfReader.getLinkedObjectFiles().size() > 0) {
094: // Mach-O left dwarf info in linked object files
095: mode = Mode.MachoLOF;
096: } else {
097: mode = Mode.Normal;
098: }
099:
100: }
101: }
102:
103: private void skipFirstHeader(RandomAccessFile reader)
104: throws IOException {
105: reader.seek(8);
106: byte[] next = new byte[60];
107: reader.readFully(next);
108: int length = 0;
109: for (int i = 0; i < 10; i++) {
110: byte c = next[i + 48];
111: if (c == ' ') {
112: break;
113: }
114: length *= 10;
115: length += (c - '0');
116: }
117: // Skip first header
118: reader.skipBytes(length);
119: }
120:
121: private List<MemberHeader> getObjectTable(RandomAccessFile reader)
122: throws IOException {
123: byte[] next = new byte[60];
124: ArrayList<MemberHeader> offsetsList = new ArrayList<MemberHeader>();
125: while (true) {
126: if (reader.getFilePointer() + 60 >= reader.length()) {
127: break;
128: }
129: reader.readFully(next);
130: int length = readNumber(next, 48);
131: int nameLength = 0;
132: //System.out.println(new String(next, 0, 16));
133: if (next[0] == '/' && next[1] == '/') {
134: // skip long name section;
135: reader.skipBytes(length);
136: continue;
137: } else if (next[0] == '#' && next[1] == '1'
138: && next[2] == '/') {
139: nameLength = readNumber(next, 3);
140: reader.skipBytes(nameLength);
141: } else if (next[0] == '\n') {
142: break;
143: }
144: long pointer = reader.getFilePointer();
145: byte[] bytes = new byte[8];
146: reader.readFully(bytes);
147: if (FileMagic.isElfMagic(bytes)
148: || FileMagic.isCoffMagic(bytes)
149: || FileMagic.isMachoMagic(bytes)) {
150: offsetsList.add(new MemberHeader(pointer, length));
151: }
152: reader.skipBytes(length - 8 - nameLength);
153: if (length % 2 == 1) {
154: reader.skipBytes(1);
155: }
156: }
157: return offsetsList;
158: }
159:
160: private int readNumber(final byte[] next, int shift) {
161: int length = 0;
162: for (int i = 0; i < 10; i++) {
163: byte c = next[i + shift];
164: if (c == ' ') {
165: break;
166: }
167: length *= 10;
168: length += (c - '0');
169: }
170: return length;
171: }
172:
173: public void dispose() {
174: if (magic != null) {
175: try {
176: magic.getReader().close();
177: } catch (IOException ex) {
178: //ex.printStackTrace();
179: }
180: magic = null;
181: }
182: }
183:
184: public CompilationUnit getCompilationUnit(String srcFileFullName)
185: throws IOException {
186: for (CompilationUnit unit : getCompilationUnits()) {
187: // TODO: remove hack
188:
189: String srcFileName = srcFileFullName
190: .substring(srcFileFullName
191: .lastIndexOf(File.separatorChar));
192: String unitFileName = unit.getSourceFileFullName();
193: unitFileName = unitFileName.substring(unitFileName
194: .lastIndexOf(File.separatorChar));
195:
196: if (unitFileName.equals(srcFileName)) {
197: //if (unit.getSourceFileFullName().equals(srcFileFullName)) {
198: return unit;
199: }
200: }
201:
202: return null;
203: }
204:
205: public ElfSection getSection(String sectionName) {
206: return dwarfReader.getSection(sectionName);
207: }
208:
209: public String getFileName() {
210: return fileName;
211: }
212:
213: public List<CompilationUnit> getCompilationUnits()
214: throws IOException {
215: if (mode == Mode.Archive) {
216: return getArchiveCompilationUnits(magic.getReader());
217: } else if (mode == Mode.Normal) {
218: return getFileCompilationUnits();
219: } else {// mode = Mode.MachoLOF
220: return getMachoLOFCompilationUnits();
221: }
222: }
223:
224: private List<CompilationUnit> getFileCompilationUnits()
225: throws IOException {
226: DwarfDebugInfoSection debugInfo = (DwarfDebugInfoSection) dwarfReader
227: .getSection(SECTIONS.DEBUG_INFO);
228: List<CompilationUnit> result = null;
229: if (debugInfo != null) {
230: result = debugInfo.getCompilationUnits();
231: } else {
232: result = new LinkedList<CompilationUnit>();
233: }
234: return result;
235: }
236:
237: private List<CompilationUnit> getMachoLOFCompilationUnits()
238: throws IOException {
239: List<CompilationUnit> result = new LinkedList<CompilationUnit>();
240: for (String string : dwarfReader.getLinkedObjectFiles()) {
241: Dwarf gimli = new Dwarf(string);
242: result.addAll(gimli.getCompilationUnits());
243: }
244: return result;
245: }
246:
247: private List<CompilationUnit> getArchiveCompilationUnits(
248: RandomAccessFile reader) throws IOException {
249: List<CompilationUnit> result = new LinkedList<CompilationUnit>();
250: for (MemberHeader member : offsets) {
251: long shiftIvArchive = member.getOffset();
252: int length = member.getLength();
253: reader.seek(shiftIvArchive);
254: byte[] bytes = new byte[8];
255: reader.readFully(bytes);
256: if (FileMagic.isElfMagic(bytes)) {
257: dwarfReader = new DwarfReader(fileName, reader,
258: Magic.Elf, shiftIvArchive, length);
259: } else if (FileMagic.isCoffMagic(bytes)) {
260: dwarfReader = new DwarfReader(fileName, reader,
261: Magic.Coff, shiftIvArchive, length);
262: } else if (FileMagic.isMachoMagic(bytes)) {
263: dwarfReader = new DwarfReader(fileName, reader,
264: Magic.Macho, shiftIvArchive, length);
265: }
266: result.addAll(getFileCompilationUnits());
267: }
268: return result;
269: }
270: }
|