mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Fix problem extracting the list of source files.
This commit is contained in:
parent
56e73c7889
commit
0a66345786
1 changed files with 215 additions and 28 deletions
|
@ -15,11 +15,13 @@ package org.eclipse.cdt.utils.debug.dwarf;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.ISymbolReader;
|
import org.eclipse.cdt.core.ISymbolReader;
|
||||||
import org.eclipse.cdt.utils.debug.IDebugEntryRequestor;
|
import org.eclipse.cdt.utils.debug.IDebugEntryRequestor;
|
||||||
import org.eclipse.cdt.utils.elf.Elf;
|
import org.eclipse.cdt.utils.elf.Elf;
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
import org.eclipse.core.runtime.Path;
|
import org.eclipse.core.runtime.Path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,10 +39,14 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
||||||
DWARF_DEBUG_STR // this is optional. Some compilers don't generate it.
|
DWARF_DEBUG_STR // this is optional. Some compilers don't generate it.
|
||||||
};
|
};
|
||||||
|
|
||||||
ArrayList fileList;
|
private Collection m_fileCollection = new ArrayList();
|
||||||
String[] files = null;
|
private String[] m_fileNames = null;
|
||||||
boolean m_parsed = false;
|
private String m_exeFileWin32Drive; // Win32 drive of the exe file.
|
||||||
|
private boolean m_onWindows;
|
||||||
|
private boolean m_parsed = false;
|
||||||
private int m_leb128Size = 0;
|
private int m_leb128Size = 0;
|
||||||
|
private ArrayList m_parsedLineTableOffsets = new ArrayList();
|
||||||
|
private int m_parsedLineTableSize = 0;
|
||||||
|
|
||||||
public DwarfReader(String file) throws IOException {
|
public DwarfReader(String file) throws IOException {
|
||||||
super(file);
|
super(file);
|
||||||
|
@ -73,7 +79,11 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
||||||
printEnabled = false;
|
printEnabled = false;
|
||||||
|
|
||||||
m_parsed = false;
|
m_parsed = false;
|
||||||
fileList = new ArrayList();
|
|
||||||
|
Path pa = new Path(exe.getFilename());
|
||||||
|
m_exeFileWin32Drive = pa.getDevice();
|
||||||
|
|
||||||
|
m_onWindows = (File.separatorChar == '\\');
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -82,7 +92,7 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
||||||
*/
|
*/
|
||||||
void parseSourceInCULineInfo(
|
void parseSourceInCULineInfo(
|
||||||
String cuCompDir, // compilation directory of the CU
|
String cuCompDir, // compilation directory of the CU
|
||||||
int cuStmtList) // offste of the CU in the line table section
|
int cuStmtList) // offset of the CU line table in .debug_line section
|
||||||
{
|
{
|
||||||
byte[] data = (byte[]) dwarfSections.get(DWARF_DEBUG_LINE);
|
byte[] data = (byte[]) dwarfSections.get(DWARF_DEBUG_LINE);
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
|
@ -91,7 +101,7 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
||||||
|
|
||||||
/* Read line table header:
|
/* Read line table header:
|
||||||
*
|
*
|
||||||
* total_length: 4 bytes
|
* total_length: 4 bytes (excluding itself)
|
||||||
* version: 2
|
* version: 2
|
||||||
* prologue length: 4
|
* prologue length: 4
|
||||||
* minimum_instruction_len: 1
|
* minimum_instruction_len: 1
|
||||||
|
@ -101,6 +111,21 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
||||||
* opcode_base: 1
|
* opcode_base: 1
|
||||||
* standard_opcode_lengths: (value of opcode_base)
|
* standard_opcode_lengths: (value of opcode_base)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Remember the CU line tables we've parsed.
|
||||||
|
Integer cuOffset = new Integer(cuStmtList);
|
||||||
|
if (! m_parsedLineTableOffsets.contains(cuOffset)) {
|
||||||
|
m_parsedLineTableOffsets.add(cuOffset);
|
||||||
|
|
||||||
|
int length = read_4_bytes(data, offset) + 4;
|
||||||
|
m_parsedLineTableSize += length + 4;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Compiler like ARM RVCT may produce several CUs for the
|
||||||
|
// same source files.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip the following till "opcode_base"
|
// Skip the following till "opcode_base"
|
||||||
offset = offset + 14;
|
offset = offset + 14;
|
||||||
int opcode_base = data[offset++];
|
int opcode_base = data[offset++];
|
||||||
|
@ -155,53 +180,213 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getSourceFiles() {
|
/*
|
||||||
if (!m_parsed) {
|
* Check if there are any line tables in .debug_line section that are
|
||||||
parse(null);
|
* not referenced by any TAG_compile_units. If yes, add source files
|
||||||
m_parsed = true;
|
* in those table entries to our "m_fileCollection".
|
||||||
|
* If the compiler/linker is fully dwarf standard compliant, that should
|
||||||
|
* not happen. But that case does exist, hence this workaround.
|
||||||
|
* .................. LWang. 08/24/07
|
||||||
|
*/
|
||||||
|
private void getSourceFilesFromDebugLineSection()
|
||||||
|
{
|
||||||
|
byte[] data = (byte[]) dwarfSections.get(DWARF_DEBUG_LINE);
|
||||||
|
if (data == null)
|
||||||
|
return;
|
||||||
|
|
||||||
files = new String[fileList.size()];
|
int sectionSize = data.length;
|
||||||
fileList.toArray(files);
|
int minHeaderSize = 16;
|
||||||
|
|
||||||
|
// Check if there is data in .debug_line section that is not parsed
|
||||||
|
// yet by parseSourceInCULineInfo().
|
||||||
|
if (m_parsedLineTableSize >= sectionSize - minHeaderSize)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The .debug_line section contains a list of line tables
|
||||||
|
// for compile_units. We'll iterate through all line tables
|
||||||
|
// in the section.
|
||||||
|
/*
|
||||||
|
* Line table header for one compile_unit:
|
||||||
|
*
|
||||||
|
* total_length: 4 bytes (excluding itself)
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int lineTableStart = 0; // offset in the .debug_line section
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (lineTableStart < sectionSize - minHeaderSize) {
|
||||||
|
int offset = lineTableStart;
|
||||||
|
|
||||||
|
Integer currLineTableStart = new Integer(lineTableStart);
|
||||||
|
|
||||||
|
// Read length of the line table for one compile unit
|
||||||
|
// Note the length does not including the "length" field itself.
|
||||||
|
int tableLength = read_4_bytes(data, offset);
|
||||||
|
|
||||||
|
// Record start of next CU line table
|
||||||
|
lineTableStart += tableLength + 4;
|
||||||
|
|
||||||
|
// According to Dwarf standard, the "tableLength" should cover the
|
||||||
|
// the whole CU line table. But some compilers (e.g. ARM RVCT 2.2)
|
||||||
|
// produce extra padding (1 to 3 bytes) beyond that in order for
|
||||||
|
// "lineTableStart" to be aligned at multiple of 4. The padding
|
||||||
|
// bytes are beyond the "tableLength" and not indicated by
|
||||||
|
// any flag, which I believe is not Dwarf2 standard compliant.
|
||||||
|
// How to determine if that type of padding exists ?
|
||||||
|
// I don't have a 100% safe way. But following hacking seems
|
||||||
|
// good enough in practice.........08/26/07
|
||||||
|
if (lineTableStart < sectionSize - minHeaderSize &&
|
||||||
|
(lineTableStart & 0x3) != 0)
|
||||||
|
{
|
||||||
|
int ltLength = read_4_bytes(data, lineTableStart);
|
||||||
|
int dwarfVer = read_2_bytes(data, lineTableStart+4);
|
||||||
|
int minInstLengh = data[lineTableStart+4+2+4];
|
||||||
|
|
||||||
|
boolean dataValid =
|
||||||
|
ltLength > minHeaderSize &&
|
||||||
|
ltLength < 16*64*1024 && // One source file has that much line data ?
|
||||||
|
dwarfVer > 0 && dwarfVer < 4 && // ver 3 is still draft at present.
|
||||||
|
minInstLengh > 0 && minInstLengh <= 8;
|
||||||
|
|
||||||
|
if (! dataValid) // padding exists !
|
||||||
|
lineTableStart = (lineTableStart+3) & ~0x3;
|
||||||
}
|
}
|
||||||
|
|
||||||
return files;
|
if (m_parsedLineTableOffsets.contains(currLineTableStart))
|
||||||
|
// current line table has already been parsed, skip it.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Skip following fields till "opcode_base"
|
||||||
|
offset = offset + 14;
|
||||||
|
int opcode_base = data[offset++];
|
||||||
|
offset += opcode_base - 1;
|
||||||
|
|
||||||
|
// Read in directories.
|
||||||
|
//
|
||||||
|
ArrayList dirList = new ArrayList();
|
||||||
|
|
||||||
|
String str, fileName;
|
||||||
|
|
||||||
|
// first dir should be TAG_comp_dir from CU, which we don't have here.
|
||||||
|
dirList.add("");
|
||||||
|
|
||||||
|
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. Note "0" is reserved for compilation directory.
|
||||||
|
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();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getSourceFiles() {
|
||||||
|
if (!m_parsed) {
|
||||||
|
m_fileCollection.clear();
|
||||||
|
|
||||||
|
getSourceFilesFromDebugInfoSection();
|
||||||
|
|
||||||
|
getSourceFilesFromDebugLineSection();
|
||||||
|
|
||||||
|
m_parsed = true;
|
||||||
|
|
||||||
|
m_fileNames = new String[m_fileCollection.size()];
|
||||||
|
m_fileCollection.toArray(m_fileNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_fileNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get source file names from compile units (CU) in .debug_info section,
|
||||||
|
* which will also search line table for the CU in .debug_line section.
|
||||||
|
*
|
||||||
|
* The file names are stored in member "m_fileCollection".
|
||||||
|
*/
|
||||||
|
private void getSourceFilesFromDebugInfoSection() {
|
||||||
|
// This will parse the data in .debug_info section which
|
||||||
|
// will call this->processCompileUnit() to get source files.
|
||||||
|
parse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSourceFile(String dir, String name)
|
private void addSourceFile(String dir, String name)
|
||||||
{
|
{
|
||||||
if (name == null || name.length() == 0)
|
if (name == null || name.length() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (name.charAt(0) == '<') // don't count the entry "<internal>" from GCCE compiler
|
if (name.charAt(0) == '<') // don't count the entry "<internal>" from GCCE compiler
|
||||||
return;
|
return;
|
||||||
|
|
||||||
String fullName = name;
|
String fullName = name;
|
||||||
|
|
||||||
Path pa = new Path(name);
|
IPath dirPa = new Path(dir);
|
||||||
|
IPath pa = new Path(name);
|
||||||
|
|
||||||
|
// Combine dir & name if needed.
|
||||||
|
if (!pa.isAbsolute() && dir.length() > 0)
|
||||||
|
pa = dirPa.append(pa);
|
||||||
|
|
||||||
// Check to see if the file exists, if not, append the path information from the dir info.
|
// For win32 only.
|
||||||
// On Win32, if the file name has the full path except the drive letter,
|
// On Windows, there are cases where the source file itself has the full path
|
||||||
// add the driver letter.
|
// except the drive letter.
|
||||||
// Otherwise if the file name is not absolute, prepend the "dir".
|
if (m_onWindows && pa.isAbsolute() && pa.getDevice() == null) {
|
||||||
|
// Try to get drive letter from comp_dir.
|
||||||
if ( !pa.toFile().exists() && dir.length() > 0)
|
if (dirPa.getDevice() != null)
|
||||||
{
|
pa = pa.setDevice(dirPa.getDevice());
|
||||||
if (pa.isAbsolute())
|
else if (m_exeFileWin32Drive != null)
|
||||||
{
|
// No drive from Dwarf data, which is also possible with RVCT or GCCE
|
||||||
if (pa.getDevice() == null && dir.charAt(1) == ':') // no drive letter
|
// compilers for ARM. A practically good solution is to assume
|
||||||
fullName = dir.substring(0, 2) + name;
|
// drive of the exe file as the drive. Though it's not good in theory,
|
||||||
}
|
// it does not hurt when the assumption is wrong, as user still has the
|
||||||
else
|
// option to locate the file manually...03/15/07
|
||||||
fullName = dir + File.separatorChar + name;
|
pa = pa.setDevice(m_exeFileWin32Drive);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This convert the path to canonical path (but not necessarily absolute, which
|
// This convert the path to canonical path (but not necessarily absolute, which
|
||||||
// is different from java.io.File.getCanonicalPath()).
|
// is different from java.io.File.getCanonicalPath()).
|
||||||
pa = new Path(fullName);
|
|
||||||
fullName = pa.toOSString();
|
fullName = pa.toOSString();
|
||||||
|
|
||||||
if (!fileList.contains(fullName))
|
if (!m_fileCollection.contains(fullName))
|
||||||
fileList.add(fullName);
|
m_fileCollection.add(fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -226,6 +411,8 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note this method modifies a data member
|
||||||
|
//
|
||||||
long read_unsigned_leb128(byte[] data, int offset) throws IOException {
|
long read_unsigned_leb128(byte[] data, int offset) throws IOException {
|
||||||
/* unsigned */
|
/* unsigned */
|
||||||
long result = 0;
|
long result = 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue