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.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
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.IPath;
|
||||
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.
|
||||
};
|
||||
|
||||
ArrayList fileList;
|
||||
String[] files = null;
|
||||
boolean m_parsed = false;
|
||||
private Collection m_fileCollection = new ArrayList();
|
||||
private String[] m_fileNames = null;
|
||||
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 ArrayList m_parsedLineTableOffsets = new ArrayList();
|
||||
private int m_parsedLineTableSize = 0;
|
||||
|
||||
public DwarfReader(String file) throws IOException {
|
||||
super(file);
|
||||
|
@ -73,7 +79,11 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
|||
printEnabled = 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(
|
||||
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);
|
||||
if (data != null) {
|
||||
|
@ -91,7 +101,7 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
|||
|
||||
/* Read line table header:
|
||||
*
|
||||
* total_length: 4 bytes
|
||||
* total_length: 4 bytes (excluding itself)
|
||||
* version: 2
|
||||
* prologue length: 4
|
||||
* minimum_instruction_len: 1
|
||||
|
@ -101,6 +111,21 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
|||
* opcode_base: 1
|
||||
* 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"
|
||||
offset = offset + 14;
|
||||
int opcode_base = data[offset++];
|
||||
|
@ -155,53 +180,213 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if there are any line tables in .debug_line section that are
|
||||
* not referenced by any TAG_compile_units. If yes, add source files
|
||||
* 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;
|
||||
|
||||
int sectionSize = data.length;
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
parse(null);
|
||||
m_fileCollection.clear();
|
||||
|
||||
getSourceFilesFromDebugInfoSection();
|
||||
|
||||
getSourceFilesFromDebugLineSection();
|
||||
|
||||
m_parsed = true;
|
||||
|
||||
files = new String[fileList.size()];
|
||||
fileList.toArray(files);
|
||||
m_fileNames = new String[m_fileCollection.size()];
|
||||
m_fileCollection.toArray(m_fileNames);
|
||||
}
|
||||
|
||||
return files;
|
||||
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)
|
||||
{
|
||||
if (name == null || name.length() == 0)
|
||||
return;
|
||||
|
||||
if (name.charAt(0) == '<') // don't count the entry "<internal>" from GCCE compiler
|
||||
return;
|
||||
|
||||
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.
|
||||
// On Win32, if the file name has the full path except the drive letter,
|
||||
// add the driver letter.
|
||||
// Otherwise if the file name is not absolute, prepend the "dir".
|
||||
|
||||
if ( !pa.toFile().exists() && dir.length() > 0)
|
||||
{
|
||||
if (pa.isAbsolute())
|
||||
{
|
||||
if (pa.getDevice() == null && dir.charAt(1) == ':') // no drive letter
|
||||
fullName = dir.substring(0, 2) + name;
|
||||
}
|
||||
else
|
||||
fullName = dir + File.separatorChar + name;
|
||||
// For win32 only.
|
||||
// On Windows, there are cases where the source file itself has the full path
|
||||
// except the drive letter.
|
||||
if (m_onWindows && pa.isAbsolute() && pa.getDevice() == null) {
|
||||
// Try to get drive letter from comp_dir.
|
||||
if (dirPa.getDevice() != null)
|
||||
pa = pa.setDevice(dirPa.getDevice());
|
||||
else if (m_exeFileWin32Drive != null)
|
||||
// No drive from Dwarf data, which is also possible with RVCT or GCCE
|
||||
// compilers for ARM. A practically good solution is to assume
|
||||
// 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
|
||||
// option to locate the file manually...03/15/07
|
||||
pa = pa.setDevice(m_exeFileWin32Drive);
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (!m_fileCollection.contains(fullName))
|
||||
m_fileCollection.add(fullName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,6 +411,8 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
|
|||
return str;
|
||||
}
|
||||
|
||||
// Note this method modifies a data member
|
||||
//
|
||||
long read_unsigned_leb128(byte[] data, int offset) throws IOException {
|
||||
/* unsigned */
|
||||
long result = 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue