From 65b8437bdabd701484e2cbee3e498928174a4488 Mon Sep 17 00:00:00 2001 From: Ken Ryall Date: Wed, 3 May 2006 22:32:12 +0000 Subject: [PATCH] Added support for extracting the list of source files from ELF-DWARF. --- .../eclipse/cdt/utils/debug/dwarf/Dwarf.java | 18 +- .../cdt/utils/debug/dwarf/DwarfReader.java | 288 ++++++++++++++++++ .../utils/org/eclipse/cdt/utils/elf/Elf.java | 23 ++ .../cdt/utils/elf/parser/ElfBinaryObject.java | 7 + 4 files changed, 331 insertions(+), 5 deletions(-) create mode 100644 core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/debug/dwarf/DwarfReader.java diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/debug/dwarf/Dwarf.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/debug/dwarf/Dwarf.java index 8543fbc7f00..2b659911dd7 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/debug/dwarf/Dwarf.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/debug/dwarf/Dwarf.java @@ -163,6 +163,8 @@ public class Dwarf { CompileUnit currentCU; + boolean printEnabled = true; + public Dwarf(String file) throws IOException { Elf exe = new Elf(file); init(exe); @@ -340,15 +342,18 @@ public class Dwarf { header.abbreviationOffset = read_4_bytes(data, offset + 6); header.addressSize = data[offset + 10]; - System.out.println("Compilation Unit @ " + Long.toHexString(offset)); //$NON-NLS-1$ - System.out.println(header); + if (printEnabled) { + System.out.println("Compilation Unit @ " + Long.toHexString(offset)); //$NON-NLS-1$ + System.out.println(header); + } // read the abbrev section. InputStream in = new ByteArrayInputStream(data, offset + 11, length); Map abbrevs = parseDebugAbbreviation(header); parseDebugInfoEntry(requestor, in, abbrevs, header); - System.out.println(); + if (printEnabled) + System.out.println(); } } catch (IOException e) { e.printStackTrace(); @@ -562,10 +567,13 @@ public class Dwarf { void processDebugInfoEntry(IDebugEntryRequestor requestor, AbbreviationEntry entry, List list) { int len = list.size(); int tag = (int) entry.tag; - System.out.println("Abbrev Number " + entry.code); //$NON-NLS-1$ + if (printEnabled) + System.out.println("Abbrev Number " + entry.code); //$NON-NLS-1$ + for (int i = 0; i < len; i++) { AttributeValue av = (AttributeValue) list.get(i); - System.out.println(av); + if (printEnabled) + System.out.println(av); // We are only interrested in certain tags. switch (tag) { case DwarfConstants.DW_TAG_array_type : diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/debug/dwarf/DwarfReader.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/debug/dwarf/DwarfReader.java new file mode 100644 index 00000000000..4ae30a7bdad --- /dev/null +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/debug/dwarf/DwarfReader.java @@ -0,0 +1,288 @@ +/******************************************************************************* + * Copyright (c) 2006 Nokia and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Nokia - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.utils.debug.dwarf; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.core.ISymbolReader; +import org.eclipse.cdt.utils.debug.IDebugEntryRequestor; +import org.eclipse.cdt.utils.elf.Elf; +import org.eclipse.core.runtime.Path; + +/** + * Light-weight parser of Dwarf2 data which is intended for getting only + * source files that contribute to the given executable. + */ +public class DwarfReader extends Dwarf implements ISymbolReader { + + // These are sections that must be parsed to get the source file list. + final static String[] DWARF_SectionsToParse = + { + DWARF_DEBUG_INFO, + DWARF_DEBUG_LINE, + DWARF_DEBUG_ABBREV, + DWARF_DEBUG_STR + }; + + ArrayList fileList; + String[] files = null; + boolean m_parsed = false; + private int m_leb128Size = 0; + + public DwarfReader(String file) throws IOException { + super(file); + } + + public DwarfReader(Elf exe) throws IOException { + super(exe); + } + + // Override parent. + // + public void init(Elf exe) throws IOException { + Elf.ELFhdr header = exe.getELFhdr(); + isLE = header.e_ident[Elf.ELFhdr.EI_DATA] == Elf.ELFhdr.ELFDATA2LSB; + + Elf.Section[] sections = exe.getSections(); + + // Read in sections (and only the sections) we care about. + // + for (int i = 0; i < sections.length; i++) { + String name = sections[i].toString(); + for (int j = 0; j < DWARF_SectionsToParse.length; j++) { + if (name.equals(DWARF_SectionsToParse[j])) { + dwarfSections.put(DWARF_SectionsToParse[j], sections[i].loadSectionData()); + } + } + } + + if (dwarfSections.size() < DWARF_SectionsToParse.length) + throw new IOException("No enough Dwarf data."); + + // Don't print during parsing. + printEnabled = false; + + m_parsed = false; + fileList = new ArrayList(); + } + + /* + * Parse line table data of a compilation unit to get names of all source files + * that contribute to the compilation unit. + */ + void parseSourceInCULineInfo( + String cuCompDir, // compilation directory of the CU + int cuStmtList) // offste of the CU in the line table section + { + byte[] data = (byte[]) dwarfSections.get(DWARF_DEBUG_LINE); + if (data != null) { + try { + int offset = cuStmtList; + + /* Read line table header: + * + * total_length: 4 bytes + * version: 2 + * prologue length: 4 + * minimum_instruction_len: 1 + * default_is_stmt: 1 + * line_base: 1 + * line_range: 1 + * opcode_base: 1 + * standard_opcode_lengths: (value of opcode_base) + */ + // Skip the following till "opcode_base" + offset = offset + 14; + int opcode_base = data[offset++]; + offset += opcode_base - 1; + + // Read in directories. + // + ArrayList dirList = new ArrayList(); + + // Put the compilation directory of the CU as the first dir + dirList.add(cuCompDir); + + String str, fileName; + + while (true) { + str = readString(data, offset); + if (str.length() == 0) + break; + dirList.add(str); + offset += str.length()+1; + } + offset++; + + // Read file names + // + long leb128; + while (true) { + fileName = readString(data, offset); + if (fileName.length() == 0) // no more file entry + break; + offset += fileName.length()+1; + + // dir index + leb128 = read_unsigned_leb128(data, offset); + offset += m_leb128Size; + + addSourceFile((String)dirList.get((int)leb128), fileName); + + // Skip the followings + // + // modification time + leb128 = read_unsigned_leb128(data, offset); + offset += m_leb128Size; + + // file size in bytes + leb128 = read_unsigned_leb128(data, offset); + offset += m_leb128Size; + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public String[] getSourceFiles() { + if (!m_parsed) { + parse(null); + m_parsed = true; + + files = new String[fileList.size()]; + fileList.toArray(files); + } + + return files; + } + + private void addSourceFile(String dir, String name) + { + if (name == null) + return; + if (name.charAt(0) == '<') // don't count the entry "" from GCCE compiler + return; + + String fullName = name; + + Path pa = new Path(name); + if (! pa.isAbsolute() && dir.length() > 0) + fullName = dir + File.separatorChar + name; + + // This convert the path to canonical path (but not necessarily absolute, which + // is different from java.io.File.getCanonicalPath()). + pa = new Path(fullName); + fullName = pa.toOSString(); + + if (!fileList.contains(fullName)) + fileList.add(fullName); + } + + /** + * Read a null-ended string from the given "data" stream starting at the given "offset". + * data : IN, byte stream + * offset: IN, offset in the stream + */ + String readString(byte[] data, int offset) + { + String str; + + StringBuffer sb = new StringBuffer(); + for (; offset < data.length; offset++) { + byte c = data[offset]; + if (c == 0) { + break; + } + sb.append((char) c); + } + + str = sb.toString(); + return str; + } + + long read_unsigned_leb128(byte[] data, int offset) throws IOException { + /* unsigned */ + long result = 0; + int shift = 0; + short b; + + m_leb128Size = 0; + while (true) { + b = (short) data[offset]; + if (b == -1) + break; //throw new IOException("no more data"); + m_leb128Size++; + result |= ((long) (b & 0x7f) << shift); + if ((b & 0x80) == 0) { + break; + } + shift += 7; + } + + return result; + } + + // Override parent: only handle TAG_Compile_Unit. + void processDebugInfoEntry(IDebugEntryRequestor requestor, AbbreviationEntry entry, List list) { + int len = list.size(); + int tag = (int) entry.tag; + for (int i = 0; i < len; i++) { + switch (tag) { + case DwarfConstants.DW_TAG_compile_unit : + processCompileUnit(requestor, list); + break; + default: + break; + } + } + } + + // Override parent. + // Just get the file name of the CU. + // Argument "requestor" is ignored. + void processCompileUnit(IDebugEntryRequestor requestor, List list) { + + String cuName, cuCompDir; + int stmtList = -1; + + cuName = cuCompDir = ""; + + for (int i = 0; i < list.size(); i++) { + AttributeValue av = (AttributeValue)list.get(i); + try { + int name = (int)av.attribute.name; + switch(name) { + case DwarfConstants.DW_AT_name: + cuName = (String)av.value; + break; + case DwarfConstants.DW_AT_comp_dir: + cuCompDir = (String)av.value; + break; + case DwarfConstants.DW_AT_stmt_list: + stmtList = ((Number)av.value).intValue(); + break; + default: + break; + } + } catch (ClassCastException e) { + } + } + + addSourceFile(cuCompDir, cuName); + if (stmtList > -1) // this CU has "stmt_list" attribute + parseSourceInCULineInfo(cuCompDir, stmtList); + } +} diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/Elf.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/Elf.java index c002db4cef5..58d1c48484c 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/Elf.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/Elf.java @@ -19,11 +19,16 @@ import java.util.Comparator; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.IAddress; import org.eclipse.cdt.core.IAddressFactory; +import org.eclipse.cdt.core.ISymbolReader; import org.eclipse.cdt.utils.Addr32; import org.eclipse.cdt.utils.Addr32Factory; import org.eclipse.cdt.utils.Addr64; import org.eclipse.cdt.utils.Addr64Factory; import org.eclipse.cdt.utils.ERandomAccessFile; +import org.eclipse.cdt.utils.coff.Coff.SectionHeader; +import org.eclipse.cdt.utils.coff.PE.Attribute; +import org.eclipse.cdt.utils.debug.dwarf.DwarfReader; +import org.eclipse.cdt.utils.debug.stabs.StabsReader; // test checkin public class Elf { @@ -1141,4 +1146,22 @@ public class Elf { } return result; } + + private ISymbolReader createDwarfReader() { + DwarfReader reader = null; + // Check if Dwarf data exists + try { + reader = new DwarfReader(this); + } catch (IOException e) { + // No Dwarf data in the Elf. + } + return reader; + } + + public ISymbolReader getSymbolReader() { + ISymbolReader reader = null; + reader = createDwarfReader(); + return reader; + } + } diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/ElfBinaryObject.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/ElfBinaryObject.java index 0103c9643a1..a8ec4b6533e 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/ElfBinaryObject.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/ElfBinaryObject.java @@ -19,6 +19,7 @@ import java.util.List; import org.eclipse.cdt.core.IAddressFactory; import org.eclipse.cdt.core.IBinaryParser; +import org.eclipse.cdt.core.ISymbolReader; import org.eclipse.cdt.core.IBinaryParser.IBinaryFile; import org.eclipse.cdt.core.IBinaryParser.ISymbol; import org.eclipse.cdt.utils.AR; @@ -183,6 +184,12 @@ public class ElfBinaryObject extends BinaryObjectAdapter { } catch (IOException e) { } } + if (adapter.equals(ISymbolReader.class)) { + Elf elf = (Elf)getAdapter(Elf.class); + if (elf != null) { + return elf.getSymbolReader(); + } + } return super.getAdapter(adapter); }