1
/*******************************************************************************
2
* Copyright (c) 2009 STMicroelectronics.
3
* All rights reserved. This program and the accompanying materials
4
* are made available under the terms of the Eclipse Public License v1.0
5
* which accompanies this distribution, and is available at
6
* http://www.eclipse.org/legal/epl-v10.html
9
* Xavier Raynaud <xavier.raynaud@st.com> - initial API and implementation
10
*******************************************************************************/
11
package org.eclipse.linuxtools.internal.gcov.parser;
13
import java.io.BufferedInputStream;
14
import java.io.DataInput;
15
import java.io.DataInputStream;
17
import java.io.FileInputStream;
18
import java.io.FileNotFoundException;
19
import java.io.IOException;
20
import java.io.InputStream;
21
import java.io.InputStreamReader;
22
import java.io.LineNumberReader;
23
import java.io.PrintStream;
24
import java.io.Serializable;
25
import java.util.ArrayList;
26
import java.util.HashMap;
27
import java.util.LinkedList;
28
import java.util.List;
31
import org.eclipse.cdt.core.IBinaryParser.IBinaryObject;
32
import org.eclipse.core.resources.IProject;
33
import org.eclipse.core.runtime.CoreException;
34
import org.eclipse.core.runtime.IPath;
35
import org.eclipse.core.runtime.IStatus;
36
import org.eclipse.core.runtime.Path;
37
import org.eclipse.core.runtime.Status;
38
import org.eclipse.linuxtools.binutils.utils.STSymbolManager;
39
import org.eclipse.linuxtools.gcov.Activator;
40
import org.eclipse.linuxtools.internal.gcov.model.CovFileTreeElement;
41
import org.eclipse.linuxtools.internal.gcov.model.CovFolderTreeElement;
42
import org.eclipse.linuxtools.internal.gcov.model.CovFunctionTreeElement;
43
import org.eclipse.linuxtools.internal.gcov.model.CovRootTreeElement;
44
import org.eclipse.swt.SWT;
45
import org.eclipse.swt.widgets.FileDialog;
46
import org.eclipse.swt.widgets.Shell;
47
import org.eclipse.ui.PlatformUI;
50
* @author Xavier Raynaud <xavier.raynaud@st.com>
53
public class CovManager implements Serializable {
58
private static final long serialVersionUID = 5582066617970911413L;
60
private final String binaryPath;
62
private final ArrayList<Folder> allFolders = new ArrayList<Folder>();
63
private final ArrayList<SourceFile> allSrcs = new ArrayList<SourceFile>();
64
private final ArrayList<GcnoFunction> allFnctns = new ArrayList<GcnoFunction>();
65
private final HashMap<String, SourceFile> sourceMap = new HashMap<String, SourceFile>();
66
private long nbrPgmRuns = 0;
68
private CovRootTreeElement rootNode;
69
private IProject project;
74
* @param project the project that will be used to get the path to run commands
76
public CovManager(String binaryPath, IProject project) {
77
this.binaryPath = binaryPath;
78
this.project = project;
85
public CovManager(String binaryPath) {
86
this(binaryPath, null);
90
* parse coverage files, execute resolve graph algorithm, process counts for functions,
92
* @param List of coverage files paths
93
* @throws CoreException, IOException, InterruptedException
96
public void processCovFiles(List<String> covFilesPaths, String initialGcda) throws CoreException, IOException, InterruptedException {
97
GcdaRecordsParser daRcrd = null;
100
Map<File, File> sourcePath = new HashMap<File, File>();
102
if (initialGcda != null) {
103
File initialGcdaFile = new File(initialGcda).getAbsoluteFile();
104
for (String s : covFilesPaths) {
105
File gcda = new File(s).getAbsoluteFile();
106
if (gcda.getName().equals(initialGcdaFile.getName()) && !gcda.equals(initialGcdaFile)) {
107
if (!sourcePath.isEmpty()) {
108
// hum... another file has the same name...
109
// sorry, we have to clean sourcePath
113
addSourceLookup(sourcePath, initialGcdaFile, gcda);
121
for (String gcdaPath: covFilesPaths) {
122
String gcnoPath = gcdaPath.replace(".gcda", ".gcno");
124
traceFile = OpenTraceFileStream(gcnoPath, ".gcno", sourcePath);
125
if (traceFile == null) return;
126
GcnoRecordsParser noRcrd = new GcnoRecordsParser(sourceMap, allSrcs);
127
noRcrd.parseData(traceFile);
129
// add new functions parsed to AllSrcs array
130
for (GcnoFunction f: noRcrd.getFnctns()) {
134
//close the input stream
135
if(traceFile.getClass() == DataInputStream.class)
136
((DataInputStream)traceFile).close();
139
traceFile = OpenTraceFileStream(gcdaPath, ".gcda", sourcePath);
140
if (traceFile == null) return;
141
if (noRcrd.getFnctns().isEmpty()){
142
String message = gcnoPath + " doesn't contain any function:\n";
143
Status status = new Status(Status.ERROR, Activator.PLUGIN_ID, message);
144
throw new CoreException(status);
146
daRcrd = new GcdaRecordsParser(noRcrd.getFnctns());
147
daRcrd.parseGcdaRecord(traceFile);
149
//close the input stream
150
if(traceFile.getClass() == DataInputStream.class)
151
((DataInputStream)traceFile).close();
154
// to fill the view title
156
nbrPgmRuns = daRcrd.getObjSmryNbrPgmRuns();
157
/* process counts from data parsed */
159
// solve graph for each function
160
for (GcnoFunction gf : allFnctns) {
161
gf.solveGraphFnctn();
165
for (SourceFile sourceFile: allSrcs) {
166
sourceFile.createLines();
170
for (GcnoFunction gf : allFnctns) {
171
gf.addLineCounts(allSrcs);
175
for (SourceFile sf: allSrcs) {
176
sf.accumulateLineCounts();
179
/* compute counts by folder*/
181
// make the folders list
182
for (SourceFile sf : allSrcs) {
183
File srcFile = new File (sf.getName());
184
String folderName = srcFile.getParent();
185
if (folderName == null) folderName = "?";
186
Folder folder = null;
187
for (Folder f: allFolders) {
188
if (f.getPath().equals(folderName))
192
folder = new Folder(folderName);
193
allFolders.add(folder);
195
folder.addSrcFiles(sf);
198
// assign sourcesList for each folder
199
for (Folder f : allFolders) {
200
f.accumulateSourcesCounts();
206
* fill the model by count results
207
* @throws CoreException, IOException, InterruptedException
210
public void fillGcovView() {
211
// process counts for summary level
212
int summaryTotal = 0, summaryInstrumented = 0, summaryExecuted = 0;
213
for (Folder f : allFolders) {
214
summaryTotal+=f.getNumLines();
215
summaryInstrumented+=f.getLinesInstrumented();
216
summaryExecuted+=f.getLinesExecuted();
219
// fill rootNode model: the entry of the contentProvider
220
rootNode = new CovRootTreeElement("Summary", summaryTotal,summaryExecuted,
221
summaryInstrumented);
222
IBinaryObject binaryObject = STSymbolManager.sharedInstance.getBinaryObject(new Path(binaryPath));
224
for (Folder fldr : allFolders) {
225
String folderLocation = fldr.getPath();
226
CovFolderTreeElement fldrTreeElem = new CovFolderTreeElement(
227
rootNode, folderLocation, fldr.getNumLines(), fldr.getLinesExecuted(),
228
fldr.getLinesInstrumented());
229
rootNode.addChild(fldrTreeElem);
231
for (SourceFile src : fldr.getSrcFiles()) {
232
CovFileTreeElement srcTreeElem = new CovFileTreeElement(
233
fldrTreeElem, src.getName(), src.getNumLines(), src
234
.getLinesExecuted(), src.getLinesInstrumented());
235
fldrTreeElem.addChild(srcTreeElem);
237
for (GcnoFunction fnctn : src.getFnctns()) {
238
String name = fnctn.getName();
239
name = STSymbolManager.sharedInstance.demangle(binaryObject, name, project);;
240
srcTreeElem.addChild(new CovFunctionTreeElement(
241
srcTreeElem, name, fnctn.getSrcFile(), fnctn
242
.getFirstLineNmbr(), fnctn.getCvrge()
243
.getLinesExecuted(), fnctn.getCvrge()
244
.getLinesInstrumented()));
250
// transform String path to stream
251
private DataInput OpenTraceFileStream(String filePath, String extension, Map<File, File> sourcePath) throws FileNotFoundException{
252
File f = new File(filePath).getAbsoluteFile();
253
String filename = f.getName();
254
if (f.isFile() && f.canRead()) {
255
FileInputStream fis = new FileInputStream(f);
256
InputStream inputStream = new BufferedInputStream(fis);
257
return new DataInputStream(inputStream);
262
if ("".equals(postfix)) postfix = f.getName();
263
else postfix = f.getName() + File.separator + postfix;
264
f = f.getParentFile();
266
dir = sourcePath.get(f);
268
} while (dir == null);
271
f = new File(dir, postfix);
272
if (f.isFile() && f.canRead()) {
273
return OpenTraceFileStream(f.getAbsolutePath(), extension, sourcePath);
278
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
279
FileDialog fg = new FileDialog(shell, SWT.OPEN);
280
fg.setFilterExtensions(new String[] {"*" + extension, "*.*", "*"});
281
fg.setFileName(filename);
282
fg.setText(filePath + " not found. Please enter location of " + filename);
283
String s = fg.open();
284
if (s == null) return null;
286
f = new File(s).getAbsoluteFile();
287
addSourceLookup(sourcePath, f, new File(filePath).getAbsoluteFile());
288
if (f.isFile() && f.canRead()) {
289
FileInputStream fis = new FileInputStream(f);
290
InputStream inputStream = new BufferedInputStream(fis);
291
return new DataInputStream(inputStream);
299
public ArrayList<SourceFile> getAllSrcs() {
303
public ArrayList<GcnoFunction> getAllFnctns() {
307
public CovRootTreeElement getRootNode() {
311
public String getBinaryPath() {
315
public SourceFile getSourceFile(String sourcePath){
316
return sourceMap.get(sourcePath);
319
public long getNbrPgmRuns() {
324
* Retrieve a list containing gcda paths from a binary file
326
* @throws CoreException
327
* @throws IOException
328
* @throws InterruptedException
330
public List<String> getGCDALocations() throws CoreException, IOException, InterruptedException
332
IBinaryObject binaryObject = STSymbolManager.sharedInstance.getBinaryObject(new Path(binaryPath));
333
String binaryPath = binaryObject.getPath().toOSString();
334
List<String> l = new LinkedList<String>();
335
String cpu = binaryObject.getCPU();
337
if ("sh".equals(cpu)) {
338
String stringsTool = "sh4strings";
339
p = getStringsProcess(stringsTool, binaryPath);
340
if ( p == null) p = getStringsProcess("sh4-linux-strings", binaryPath);
341
} else if ("stxp70".equals(cpu)) {
342
String stringsTool = "stxp70v3-strings";
343
p = getStringsProcess(stringsTool, binaryPath);
344
} else if ("st200".equals(cpu)){
345
String stringsTool = cpu + "strings";
346
p = getStringsProcess(stringsTool, binaryPath);
348
String stringsTool = "strings";
349
p = getStringsProcess(stringsTool, binaryPath);
352
Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR,
353
"An error occured during analysis: unable to retrieve gcov data", new IOException());
354
Activator.getDefault().getLog().log(status);
357
ThreadConsumer t = new ThreadConsumer(p, l);
365
private Process getStringsProcess(String stringsTool, String binaryPath) {
367
Process p = Runtime.getRuntime().exec(new String[] {stringsTool, binaryPath });
369
} catch (Exception _) {
376
private static final class ThreadConsumer extends Thread
378
private final Process p;
379
private final List<String> list;
380
ThreadConsumer(Process p, List<String> files)
390
populateGCDAFiles(p.getInputStream());
391
} catch (Exception _) {
395
private void populateGCDAFiles(InputStream s) throws IOException
397
InputStreamReader isr = new InputStreamReader(s);
398
LineNumberReader lnr = new LineNumberReader(isr);
400
while ((line =lnr.readLine()) != null) {
401
if (line.endsWith(".gcda"))
403
// absolute .gcda filepaths retrieved using the "strings" tool may
404
// be prefixed by random printable characters so strip leading
405
// characters until the filepath starts with "X:/", "X:\", "/" or "\"
406
// FIXME: need a more robust mechanism to locate .gcda files [Bugzilla 329710]
407
while ((line.length() > 6) && !line.matches("^([A-Za-z]:)?[/\\\\].*")) {
408
line = line.substring(1);
410
IPath p = new Path(line);
411
String filename = p.toString();
414
if (!list.contains(filename)) list.add(filename);
420
public void dumpProcessCovFilesResult(PrintStream ps) throws FileNotFoundException {
421
ps.println("Parse gcda and gcno files done, resolve graph algorithm executed, now display results");
422
ps.println("- PRINT FUNCTIONS ARRAY : ");
423
for (int i = 0; i < allFnctns.size(); i++) {
424
ps.println("-- FUNCTION " +i);
425
ps.println(" name = " + allFnctns.get(i).getName());
426
ps.println(" instrumentd lines = " + allFnctns.get(i).getCvrge().getLinesInstrumented());
427
ps.println(" executed lines = "+ allFnctns.get(i).getCvrge().getLinesExecuted());
429
ps.println("- PRINT SRCS ARRAY : ");
430
for (int i = 0; i < allSrcs.size(); i++) {
431
ps.println("-- FILE " + i);
432
ps.println(" name = " + allSrcs.get(i).getName());
433
ps.println(" total lines = " + allSrcs.get(i).getNumLines());
434
ps.println(" instrumentd lines = "+ allSrcs.get(i).getLinesInstrumented());
435
ps.println(" executed lines = "+ allSrcs.get(i).getLinesExecuted());
441
* @return the sourceMap
443
public HashMap<String, SourceFile> getSourceMap() {
448
private void addSourceLookup(Map<File, File> map, File hostPath, File compilerPath) {
449
while (hostPath.getName().equals(compilerPath.getName())) {
450
hostPath = hostPath.getParentFile();
451
compilerPath = compilerPath.getParentFile();
453
map.put(compilerPath, hostPath);