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.util.HashMap;
045: import java.util.List;
046: import java.util.Map;
047: import org.netbeans.modules.cnd.dwarfdump.dwarf.DwarfAbbriviationTable;
048: import org.netbeans.modules.cnd.dwarfdump.dwarf.DwarfAbbriviationTableEntry;
049: import org.netbeans.modules.cnd.dwarfdump.dwarf.DwarfEntry;
050: import org.netbeans.modules.cnd.dwarfdump.dwarf.DwarfMacinfoTable;
051: import org.netbeans.modules.cnd.dwarfdump.dwarf.DwarfNameLookupTable;
052: import org.netbeans.modules.cnd.dwarfdump.dwarf.DwarfStatementList;
053: import org.netbeans.modules.cnd.dwarfdump.dwarfconsts.ATTR;
054: import org.netbeans.modules.cnd.dwarfdump.dwarfconsts.SECTIONS;
055: import org.netbeans.modules.cnd.dwarfdump.dwarfconsts.TAG;
056: import org.netbeans.modules.cnd.dwarfdump.reader.DwarfReader;
057: import org.netbeans.modules.cnd.dwarfdump.section.DwarfAbbriviationTableSection;
058: import org.netbeans.modules.cnd.dwarfdump.section.DwarfAttribute;
059: import org.netbeans.modules.cnd.dwarfdump.section.DwarfLineInfoSection;
060: import org.netbeans.modules.cnd.dwarfdump.section.DwarfMacroInfoSection;
061: import org.netbeans.modules.cnd.dwarfdump.section.DwarfNameLookupTableSection;
062: import java.io.File;
063: import java.io.IOException;
064: import java.io.PrintStream;
065: import java.util.ArrayList;
066: import org.netbeans.modules.cnd.dwarfdump.dwarfconsts.ElfConstants;
067:
068: /**
069: *
070: * @author ak119685
071: */
072: public class CompilationUnit {
073: private DwarfReader reader;
074:
075: public long debugInfoSectionOffset;
076: public long unit_offset;
077: public long unit_length;
078: public long unit_total_length;
079: public int version;
080: public long debug_abbrev_offset;
081: public long info_offset;
082: public byte address_size;
083: public DwarfEntry root = null;
084:
085: private DwarfAbbriviationTable abbr_table = null;
086: private DwarfStatementList statement_list = null;
087: private DwarfMacinfoTable macrosTable = null;
088: private DwarfNameLookupTable pubnamesTable = null;
089: private long debugInfoOffset;
090:
091: private Map<Long, Long> specifications = new HashMap<Long, Long>();
092: private Map<Long, DwarfEntry> entries = new HashMap<Long, DwarfEntry>();
093:
094: /** Creates a new instance of CompilationUnit */
095: public CompilationUnit(DwarfReader reader, long sectionOffset,
096: long unitOffset) throws IOException {
097: this .reader = reader;
098: this .debugInfoSectionOffset = sectionOffset;
099: this .unit_offset = unitOffset;
100: readCompilationUnitHeader();
101: root = getDebugInfo(false);
102: }
103:
104: public String getProducer() {
105: return (String) root.getAttributeValue(ATTR.DW_AT_producer);
106: }
107:
108: public String getCompilationDir() {
109: return (String) root.getAttributeValue(ATTR.DW_AT_comp_dir);
110: }
111:
112: public String getSourceFileName() {
113: return (String) root.getAttributeValue(ATTR.DW_AT_name);
114: }
115:
116: public String getCommandLine() {
117: Object cl = root.getAttributeValue(ATTR.DW_AT_SUN_command_line);
118: return (cl == null) ? null : (String) cl;
119: }
120:
121: public String getSourceFileFullName() {
122: String result = null;
123:
124: try {
125: String dir = getCompilationDir();
126: String name = getSourceFileName();
127: if (name != null) {
128: if (dir != null) {
129: if (name.startsWith("/")) { // NOI18N
130: result = new File(name).getCanonicalPath();
131: } else {
132: result = new File(dir + File.separator + name)
133: .getCanonicalPath();
134: }
135: } else {
136: result = new File(name).getCanonicalPath();
137: }
138: }
139: } catch (IOException ex) {
140: ex.printStackTrace();
141: }
142:
143: return result;
144: }
145:
146: public String getSourceFileAbsolutePath() {
147: String result = null;
148:
149: String dir = getCompilationDir();
150: String name = getSourceFileName();
151: if (dir != null) {
152: if (name.startsWith("/")) { // NOI18N
153: result = new File(name).getAbsolutePath();
154: } else {
155: result = new File(dir + File.separator + name)
156: .getAbsolutePath();
157: }
158: } else {
159: result = new File(name).getAbsolutePath();
160: }
161:
162: return result;
163: }
164:
165: public String getSourceLanguage() {
166: if (root != null) {
167: Object lang = root.getAttributeValue(ATTR.DW_AT_language);
168: if (lang != null) {
169: return lang.toString();
170: }
171: }
172: return null;
173: }
174:
175: public String getType(DwarfEntry entry) {
176: TAG entryKind = entry.getKind();
177:
178: if (entryKind.equals(TAG.DW_TAG_unspecified_parameters)) {
179: return "null"; // NOI18N
180: }
181:
182: Integer typeRef = (Integer) entry
183: .getAttributeValue(ATTR.DW_AT_type);
184:
185: if (typeRef == null) {
186: return "void"; // NOI18N
187: }
188:
189: DwarfEntry typeEntry = getEntry(typeRef);
190: TAG kind = typeEntry.getKind();
191:
192: if (kind.equals(TAG.DW_TAG_base_type)) {
193: String name = typeEntry.getName();
194:
195: // TODO: Is it OK?
196: if (name.equals("long unsigned int")) { // NOI18N
197: name = "unsigned long"; // NOI18N
198: } else if (name.equals("long int")) { // NOI18N
199: name = "long"; // NOI18N
200: }
201:
202: return name;
203: }
204:
205: if (kind.equals(TAG.DW_TAG_structure_type)
206: || kind.equals(TAG.DW_TAG_enumeration_type)
207: || kind.equals(TAG.DW_TAG_union_type)
208: || kind.equals(TAG.DW_TAG_typedef)
209: || kind.equals(TAG.DW_TAG_class_type)) {
210: return typeEntry.getName();
211: }
212:
213: if (kind.equals(TAG.DW_TAG_const_type)) {
214: // TODO: Check algorithm!
215:
216: Object atType = typeEntry
217: .getAttributeValue(ATTR.DW_AT_type);
218:
219: if (atType == null) {
220: return "const void"; // NOI18N
221: }
222:
223: if (atType instanceof Integer) {
224: Integer constTypeRef = (Integer) typeEntry
225: .getAttributeValue(ATTR.DW_AT_type);
226:
227: DwarfEntry refTypeEntry = getEntry(constTypeRef);
228: typeEntry.getKind();
229: if (refTypeEntry.getKind().equals(
230: TAG.DW_TAG_reference_type)
231: || refTypeEntry.getKind().equals(
232: TAG.DW_TAG_array_type)) {
233: return getType(typeEntry);
234: } else {
235: if (refTypeEntry.getKind() == TAG.DW_TAG_pointer_type) {
236: return getType(typeEntry) + " const"; // NOI18N
237: } else {
238: return "const " + getType(typeEntry); // NOI18N
239: }
240: }
241: }
242:
243: // return "const " + getType(typeEntry); // NOI18N
244:
245: }
246:
247: if (kind.equals(TAG.DW_TAG_reference_type)) {
248: return getType(typeEntry) + "&"; // NOI18N
249: }
250:
251: if (kind.equals(TAG.DW_TAG_array_type)) {
252: return getType(typeEntry) + "[]"; // NOI18N
253: }
254:
255: if (kind.equals(TAG.DW_TAG_pointer_type)
256: || kind.equals(TAG.DW_TAG_ptr_to_member_type)) {
257: return getType(typeEntry) + "*"; // NOI18N
258: }
259:
260: if (kind.equals(TAG.DW_TAG_subroutine_type)) {
261: return getType(typeEntry);
262: }
263:
264: if (kind.equals(TAG.DW_TAG_volatile_type)) {
265: return getType(typeEntry);
266: }
267:
268: if (kind.equals(TAG.DW_TAG_union_type)) {
269: return getType(typeEntry);
270: }
271:
272: return "<" + kind + ">"; // NOI18N
273: }
274:
275: public DwarfEntry getEntry(long sectionOffset) {
276: //return entryLookup(getDebugInfo(true), sectionOffset);
277: DwarfEntry entry = entries.get(sectionOffset);
278:
279: if (entry == null) {
280: entry = entryLookup(getDebugInfo(true), sectionOffset);
281: entries.put(sectionOffset, entry);
282: }
283:
284: return entry;
285: }
286:
287: public DwarfEntry getDefinition(DwarfEntry entry) {
288: Long ref = specifications.get(entry.getRefference());
289: if (ref != null) {
290: return getEntry(ref);
291: }
292: return null;
293: }
294:
295: private DwarfEntry entryLookup(DwarfEntry entry, long refference) {
296: if (entry == null) {
297: return null;
298: }
299:
300: if (entry.getRefference() == refference) {
301: return entry;
302: }
303:
304: for (DwarfEntry child : entry.getChildren()) {
305: DwarfEntry res = entryLookup(child, refference);
306: if (res != null) {
307: return res;
308: }
309: }
310:
311: return null;
312: }
313:
314: public DwarfEntry getRoot() {
315: return root;
316: }
317:
318: public DwarfEntry getTypedefFor(Integer typeRef) {
319: // TODO: Rewrite not to iterate every time.
320:
321: for (DwarfEntry entry : getDebugInfo(true).getChildren()) {
322: if (entry.getKind().equals(TAG.DW_TAG_typedef)) {
323: Object entryTypeRef = entry
324: .getAttributeValue(ATTR.DW_AT_type);
325: if (entryTypeRef != null
326: && ((Integer) entryTypeRef).equals(typeRef)) {
327: return entry;
328: }
329: }
330: }
331:
332: return null;
333: }
334:
335: /**
336: * unit_length represents the length of the .debug_info contribution for
337: * this compilation unit, not including the length field itself. So this
338: * method returns unit_length + sizeof(unit_length field). I.e. 4 or 4 + 8.
339: * @return the total bytes number occupied by this CU.
340: */
341:
342: public long getUnitTotalLength() {
343: return unit_total_length;
344: }
345:
346: private void readCompilationUnitHeader() throws IOException {
347: reader.seek(debugInfoSectionOffset + unit_offset);
348:
349: unit_length = reader.readDWlen();
350: // The total length of this CU is unit_lenght + sizeof(unit_lenght field).
351:
352: long pos = reader.getFilePointer();
353: unit_total_length = unit_length + pos
354: - (debugInfoSectionOffset + unit_offset);
355:
356: version = reader.readShort();
357: debug_abbrev_offset = reader.read3264();
358: address_size = (byte) (0xff & reader.readByte());
359:
360: // GNU writes debug info using 32-bit mode even in elf64
361: // It's a hack. Check if we have a meaningful address_size.
362: // If not and we are in 64-bit mode => try to fallback into 32-bit mode.
363: if (address_size != 4 && address_size != 8 && reader.is64Bit()) {
364: reader.setFileClass(ElfConstants.ELFCLASS32);
365: reader.seek(reader.getFilePointer() - 9);
366: debug_abbrev_offset = reader.read3264();
367: address_size = (byte) (0xff & reader.readByte());
368: }
369:
370: debugInfoOffset = reader.getFilePointer();
371:
372: reader.setAddressSize(address_size);
373:
374: DwarfAbbriviationTableSection abbrSection = (DwarfAbbriviationTableSection) reader
375: .getSection(SECTIONS.DEBUG_ABBREV);
376: abbr_table = abbrSection
377: .getAbbriviationTable(debug_abbrev_offset);
378: }
379:
380: public DwarfStatementList getStatementList() {
381: if (statement_list == null) {
382: initStatementList();
383: }
384:
385: return statement_list;
386: }
387:
388: public DwarfMacinfoTable getMacrosTable() {
389: if (macrosTable == null) {
390: initMacrosTable();
391: }
392:
393: return macrosTable;
394: }
395:
396: private DwarfNameLookupTable getPubnamesTable() {
397: if (pubnamesTable == null) {
398: initPubnamesTable();
399: }
400:
401: return pubnamesTable;
402: }
403:
404: private DwarfEntry getDebugInfo(boolean readChildren) {
405: if (root == null
406: || (readChildren && root.getChildren().size() == 0)) {
407: try {
408: //getPubnamesTable();
409: long currPos = reader.getFilePointer();
410: reader.seek(debugInfoOffset);
411: root = readEntry(0, readChildren);
412: reader.seek(currPos);
413:
414: if (readChildren) {
415: setSpecializations(root);
416: }
417:
418: } catch (IOException ex) {
419: ex.printStackTrace();
420: }
421: }
422:
423: return root;
424: }
425:
426: private void setSpecializations(DwarfEntry entry) {
427: Object o = entry.getAttributeValue(ATTR.DW_AT_specification);
428:
429: if (o instanceof Integer) {
430: specifications.put(new Long(((Integer) o).intValue()),
431: entry.getRefference());
432: }
433:
434: for (DwarfEntry child : entry.getChildren()) {
435: setSpecializations(child);
436: }
437: }
438:
439: private DwarfEntry readEntry(int level, boolean readChildren)
440: throws IOException {
441: long refference = reader.getFilePointer()
442: - debugInfoSectionOffset - unit_offset;
443: long idx = reader.readUnsignedLEB128();
444:
445: if (idx == 0) {
446: return null;
447: }
448:
449: DwarfAbbriviationTableEntry abbreviationEntry = abbr_table
450: .getEntry(idx);
451:
452: if (abbreviationEntry == null) {
453: return null;
454: }
455:
456: DwarfEntry entry = new DwarfEntry(this , abbreviationEntry,
457: refference, level);
458: entries.put(refference, entry);
459:
460: for (int i = 0; i < abbreviationEntry.getAttributesCount(); i++) {
461: DwarfAttribute attr = abbreviationEntry.getAttribute(i);
462: entry.addValue(reader.readAttrValue(attr));
463: }
464:
465: if (readChildren == true && entry.hasChildren()) {
466: DwarfEntry child;
467: while ((child = readEntry(level + 1, true)) != null) {
468: entry.addChild(child);
469: }
470: }
471:
472: return entry;
473: }
474:
475: private void initStatementList() {
476: DwarfLineInfoSection lineInfoSection = (DwarfLineInfoSection) reader
477: .getSection(SECTIONS.DEBUG_LINE);
478:
479: if (root == null) {
480: return;
481: }
482:
483: Number statementListOffset = (Number) root
484: .getAttributeValue(ATTR.DW_AT_stmt_list);
485: if (statementListOffset != null) {
486: statement_list = lineInfoSection
487: .getStatementList(statementListOffset.longValue());
488: }
489: }
490:
491: private void initMacrosTable() {
492: DwarfMacroInfoSection macroInfoSection = (DwarfMacroInfoSection) reader
493: .getSection(SECTIONS.DEBUG_MACINFO); // NOI18N
494:
495: if (macroInfoSection == null) {
496: return;
497: }
498:
499: Integer macroInfoOffset = (Integer) root
500: .getAttributeValue(ATTR.DW_AT_macro_info);
501:
502: if (macroInfoOffset == null) {
503: return;
504: }
505:
506: macrosTable = macroInfoSection.getMacinfoTable(macroInfoOffset);
507: }
508:
509: private void initPubnamesTable() {
510: DwarfNameLookupTableSection dwarfNameLookupTableSection = (DwarfNameLookupTableSection) reader
511: .getSection(SECTIONS.DEBUG_PUBNAMES);
512:
513: if (dwarfNameLookupTableSection != null) {
514: pubnamesTable = dwarfNameLookupTableSection
515: .getNameLookupTableFor(unit_offset);
516: }
517: }
518:
519: public List<DwarfEntry> getDeclarations() {
520: return getDeclarations(true);
521: }
522:
523: public List<DwarfEntry> getEntries() {
524: // Read pubnames section first
525: getPubnamesTable();
526: return getDebugInfo(true).getChildren();
527: }
528:
529: /**
530: * Used to get a list of declarations defined/used in this CU.
531: * @param limitedToFile <code>true</code> means return declarations defined in the current source file only
532: * @return returns a list of declarations defined/used in this CU.
533: */
534: public List<DwarfEntry> getDeclarations(boolean limitedToFile) {
535: boolean reportExcluded = false;
536: int fileEntryIdx = 0;
537:
538: // make sure that pubnames table has been read ...
539: getPubnamesTable();
540:
541: ArrayList<DwarfEntry> result = new ArrayList<DwarfEntry>();
542:
543: if (limitedToFile) {
544: fileEntryIdx = getStatementList().getFileEntryIdx(
545: getSourceFileName());
546: }
547:
548: for (DwarfEntry child : getEntries()) {
549: if ((!limitedToFile)
550: || (limitedToFile && child
551: .isEntryDefinedInFile(fileEntryIdx))) {
552: // TODO: Check algorythm
553: // Do not add definitions that have DW_AT_abstract_origin attribute.
554: // Do not add entries that's names start with _GLOBAL__F | _GLOBAL__I | _GLOBAL__D
555:
556: if (!child.hasAbastractOrigin()) {
557: String qname = child.getQualifiedName();
558: if (qname != null && !qname.startsWith("_GLOBAL__")) { // NOI18N
559: result.add(child);
560: } else if (reportExcluded) {
561: System.out.println("Exclude declaration: "
562: + child.getDeclaration()); // NOI18N
563: }
564: }
565: }
566: }
567:
568: return result;
569: }
570:
571: public void dump(PrintStream out) {
572: if (root == null) {
573: out.println("*** No compilation units for "
574: + reader.getFileName()); // NOI18N
575: return;
576: }
577:
578: out.println("*** " + getSourceFileFullName() + " ***"); // NOI18N
579: out.println(" Compilation Unit @ offset "
580: + Long.toHexString(unit_offset) + ":"); // NOI18N
581: out.println(" Length: " + unit_length); // NOI18N
582: out.println(" Version: " + version); // NOI18N
583: out.println(" Abbrev Offset: " + debug_abbrev_offset); // NOI18N
584: out.println(" Pointer Size: " + address_size); // NOI18N
585:
586: /*
587: * getPubnamesTable() will not only set pubnamesTable (if not set yet)
588: * but also setup qualified names from appropriate pubnames table.
589: */
590:
591: getPubnamesTable();
592:
593: getDebugInfo(true).dump(out);
594: DwarfStatementList stList = getStatementList();
595: if (stList != null) {
596: stList.dump(out);
597: }
598:
599: // Still pubnamesTable could be null (if not present for this
600: // Compilation Unit)
601:
602: if (pubnamesTable != null) {
603: pubnamesTable.dump(out);
604: }
605:
606: DwarfMacinfoTable macinfoTable = getMacrosTable();
607: if (macinfoTable != null) {
608: macinfoTable.dump(out);
609: }
610:
611: out.println();
612: }
613:
614: }
|