Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 92ad13eab97badcef932d6d68fa6a5c3a9631db8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*******************************************************************************
 * Copyright (c) 2009 Red Hat, Inc.
 * 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:
 *    Elliott Baron <ebaron@redhat.com> - initial API and implementation
 *    Alena Laskavaia - Bug 482947 - Valgrind Message API's: get rid of launch dependency
 *******************************************************************************/
package org.eclipse.linuxtools.internal.valgrind.core;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.model.IPersistableSourceLocator;
import org.eclipse.debug.core.model.ISourceLocator;
import org.eclipse.debug.core.sourcelookup.IPersistableSourceLocator2;
import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
import org.eclipse.linuxtools.valgrind.core.CommandLineConstants;
import org.eclipse.linuxtools.valgrind.core.IValgrindMessage;
import org.eclipse.linuxtools.valgrind.core.ValgrindParserUtils;

/**
 * Parser for paring valgrind generic output into array of hierarchical messages
 */
public class ValgrindCoreParser {
    private static final String AT = "at"; //$NON-NLS-1$
    private static final String BY = "by"; //$NON-NLS-1$

    private List<IValgrindMessage> messages;
    private int pid;
    private ILaunch launch;
    private ISourceLocator locator;

    /**
     * When using this method make sure locator passed to this method can
     * outlive disposal of launch object if it was derived from it, use
     * {@link #copyLaunchSourceLocator(ILaunch)} if needed
     *
     * @param inputFile
     *            - file to parse
     * @param launch
     *            - launch object, can be null
     * @param locator
     *            - source locator
     * @throws IOException if file is not found or error reading it
     */
    public ValgrindCoreParser(File inputFile, ILaunch launch, ISourceLocator locator) throws IOException {
        this.launch = launch;
        this.locator = locator;
        // keep track of nested messages and their corresponding indents
        Stack<IValgrindMessage> messageStack = new Stack<>();
        Stack<Integer> indentStack = new Stack<>();
        messages = new ArrayList<>();

        try (BufferedReader br = new BufferedReader(new FileReader(inputFile))) {
            pid = ValgrindParserUtils.parsePID(inputFile.getName(), CommandLineConstants.LOG_PREFIX);
            String line;
            while ((line = br.readLine()) != null) {
                // remove PID string
                // might encounter warnings also #325130
                // fixed #423371 - handle timestamp (e.g. ==00:00:00:01.175 52756728==)
                line = line.replaceFirst("==([\\d:\\.]+\\s)?\\d+==|\\*\\*\\d+\\*\\*", ""); //$NON-NLS-1$ //$NON-NLS-2$

                int indent;
                for (indent = 0; indent < line.length()
                && line.charAt(indent) == ' '; indent++){}

                line = line.trim();
                if (!line.isEmpty()) {
                    /*
                     * indent == 1 -> top level message
                     * indent > 1 -> child message
                     * indent == 0 -> should not occur
                     */
                    if (indent == 1) {
                        // top-level message, clear stacks
                        IValgrindMessage message = getMessage(null, line);
                        messages.add(message);
                        messageStack.clear();
                        messageStack.push(message);
                        indentStack.clear();
                        indentStack.push(indent);
                    } else if (indent > 1) {
                        /**
                         * We assume that an indented child message has a
                         * parent, but this may not be the case.
                         * See BZ #360225
                         */
                        if (indentStack.isEmpty()) {
                            // pretend this is a top level message
                            IValgrindMessage message = getMessage(null, line);
                            messages.add(message);
                            messageStack.clear();
                            messageStack.push(message);
                            indentStack.clear();
                            indentStack.push(1);
                        } else {
                            // find this message's parent
                            while (indent <= indentStack.peek()) {
                                messageStack.pop();
                                indentStack.pop();
                            }

                            messageStack.push(getMessage(messageStack.peek(), line));
                            indentStack.push(indent);
                        }
                    }
                }
            }
        }
    }

    private IValgrindMessage getMessage(IValgrindMessage message, String line) {
        if (line.startsWith(AT) || line.startsWith(BY)) {
            Object[] parsed = ValgrindParserUtils.parseFilename(line);
            String filename = (String) parsed[0];
            int lineNo = (Integer) parsed[1];
            return new ValgrindStackFrame(message, line, launch, locator, filename, lineNo);
        }
        return new ValgrindError(message, line, launch, pid);
    }

    /**
     * Return messages from paring
     * @return all parsed messages
     *
     */
    public IValgrindMessage[] getMessages() {
        return messages.toArray(new IValgrindMessage[messages.size()]);
    }

    /**
     * Constructor
     * @param inputFile - file to parse
     * @param launch - launch object can be null
     * @throws IOException if cannot open file
     */
    public ValgrindCoreParser(File inputFile, ILaunch launch) throws IOException {
        this(inputFile, launch, copyLaunchSourceLocator(launch));
    }

    /**
     * Return a safe source locator from launch object which won't be disposed if launch object is disposed
     * @param launch - launch object
     * @return source locator
     *
     */
    public static ISourceLocator copyLaunchSourceLocator(ILaunch launch) {
        if (launch == null)
            return null;
        ISourceLocator sourceLocator = launch.getSourceLocator();
        ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration();
        // sourceLocator from launch object will be disposed when launch is
        // gone,
        // since we want to use it later we need to create a copy of it
        if (sourceLocator instanceof ISourceLookupDirector) {
            try {
                ISourceLookupDirector director = (ISourceLookupDirector) sourceLocator;

                String id = director.getId();
                String memento = director.getMemento();
                IPersistableSourceLocator sourceLocatorCopy = DebugPlugin.getDefault().getLaunchManager()
                        .newSourceLocator(id);
                if (sourceLocatorCopy instanceof IPersistableSourceLocator2) {
                    ((IPersistableSourceLocator2) sourceLocatorCopy).initializeFromMemento(memento,
                            launchConfiguration);
                } else
                    sourceLocatorCopy.initializeFromMemento(memento);
                return sourceLocatorCopy;
            } catch (CoreException e) {
                // ignore
            }
        }
        return sourceLocator;
    }
}

Back to the top