1
/*******************************************************************************
2
* Copyright (c) 2008, 2010 Ericsson and others.
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
* Ericsson - Initial API and implementation
10
*******************************************************************************/
12
package org.eclipse.cdt.dsf.mi.service.command.output;
14
import java.util.ArrayList;
15
import java.util.List;
16
import java.util.regex.Matcher;
17
import java.util.regex.Pattern;
19
import org.eclipse.cdt.dsf.concurrent.Immutable;
22
* GDB/MI thread group parsing.
24
* The description field can be different depending on the target we are connected to.
26
* -list-thread-groups --available:
27
* ^done,groups=[{id="161",type="process",description="name: JIM_InstallerProcess, type 555481, locked: N, system: N, state: Idle"},
28
* {id="162",type="process",description="name: JIM_TcpSetupHandlerProcess, type 555505, locked: N, system: N, state: Idle"},
29
* {id="165",type="process",description="name: JUnitProcess2_PT, type 1094608, locked: N, system: N, state: Idle"},
30
* {id="166",type="process",description="name: JUnitProcess_PT, type 1094605, locked: N, system: N, state: Idle"}]
32
* {id="3602",type="process",description="/usr/sbin/dhcdbd --system",user="root"}
34
* -list-thread-groups:
35
* ^done,groups=[{id="162",type="process",pid="162"}]
37
* -list-thread-groups GROUPID, in the case of a running thread or a stopped thread:
38
* ^done,threads=[{id="1",target-id="Thread 162.32942",details="JUnitProcess_PT (Ready) 1030373359 44441",frame={level="0",addr="0x00000000",func="??",args=[]},state="stopped"}]
39
* ^done,threads=[{id="1",target-id="Thread 162.32942",details="JUnitProcess_PT Idle 981333916 42692",state="running"}]
41
* As of GDB 7.1, a new 'core' output field has been added. This field is a list
42
* of integers, each identifying a core that one thread of the group is running on.
43
* This field may be absent if such information is not available.
46
* ^done,groups=[{id="12779",type="process",pid="12779",cores=["3"]}]
48
* -list-thread-groups 12779
49
* ^done,threads=[{id="10",
50
* target-id="Thread 0xb3d58ba0 (LWP 12876)",
51
* frame={level="0",addr="0xb7e21b88",func="clone",args=[],from="/lib/libc.so.6"},
55
* target-id="Thread 0xb755fba0 (LWP 12811)",
56
* frame={level="0",addr="0xffffe410",func="__kernel_vsyscall",args=[]},
60
* target-id="Thread 0xb7d60ba0 (LWP 12810)",
61
* frame={level="0",addr="0xffffe410",func="__kernel_vsyscall",args=[]},
65
* target-id="Thread 0xb7d616b0 (LWP 12779)",
66
* frame={level="0",addr="0x08048609",func="main",args=[],file="../src/NonStop.cpp",fullname="/local/runtime-TestDSF/NonStop/src/NonStop.cpp",line="44"},
70
* As of GDB 7.1, the --recurse option has been added and causes a different output
72
* -list-thread-groups --recurse 1
73
* ^done,groups=[{id="12779",
78
* target-id="Thread 0xb3d58ba0 (LWP 12876)",
79
* frame={level="0",addr="0xb7e21b88",func="clone",args=[],from="/lib/libc.so.6"},
83
* target-id="Thread 0xb755fba0 (LWP 12811)",
84
* frame={level="0",addr="0xffffe410",func="__kernel_vsyscall",args=[]},
88
* target-id="Thread 0xb7d60ba0 (LWP 12810)",
89
* frame={level="0",addr="0xffffe410",func="__kernel_vsyscall",args=[]},
93
* target-id="Thread 0xb7d616b0 (LWP 12779)",
94
* frame={level="0",addr="0x08048609",func="main",args=[],file="../src/NonStop.cpp",fullname="/local/runtime-TestDSF/NonStop/src/NonStop.cpp",line="44"},
100
* Example of outputs by version on Linux
104
* (when no inferior is running)
105
* -list-thread-groups
108
* (with an inferior running)
109
* -list-thread-groups
110
* ^done,groups=[{id="19386",type="process",pid="19386"}]
112
* -list-thread-groups 19386
113
* ^done,threads=[{id="1",target-id="process 19386",frame={level="0",addr="0x08048618",func="main",args=[],file="a.cc",fullname="/local/lmckhou/testing/a.cc",line="9"},state="stopped"}]
115
* -list-thread-groups --available
116
* ^done,groups=[{id="19371",type="process",description="gdb.7.0 -i mi testing/a.out",user="lmckhou"},{id="19386",type="process",description="/local/lmckhou/testing/a.out",user="lmckhou"},{id="19413",type="process",description="sleep 5",user="lmckhou"}]
120
* (when no inferior is running)
121
* -list-thread-groups
122
* ^done,groups=[{id="0",type="process",pid="0"}]
124
* (with an inferior running)
125
* -list-thread-groups
126
* ^done,groups=[{id="19424",type="process",pid="19424",cores=["3"]}]
128
* -list-thread-groups 19424
129
* ^done,threads=[{id="1",target-id="process 19424",frame={level="0",addr="0x08048618",func="main",args=[],file="a.cc",fullname="/local/lmckhou/testing/a.cc",line="9"},state="stopped",core="3"}]
131
* -list-thread-groups --available
132
* ^done,groups=[{id="19418",type="process",description="gdb.7.1 -i mi testing/a.out",user="lmckhou"},{id="19424",type="process",description="/local/lmckhou/testing/a.out",user="lmckhou"},{id="19438",type="process",description="sleep 5",user="lmckhou"}]
136
* (when no inferior is running)
137
* -list-thread-groups
138
* ^done,groups=[{id="i1",type="process",executable="/local/lmckhou/testing/a.out"}]
140
* (with an inferior running)
141
* -list-thread-groups
142
* ^done,groups=[{id="i1",type="process",pid="19451",executable="/local/lmckhou/testing/a.out",cores=["2"]}]
144
* -list-thread-groups i1
145
* ^done,threads=[{id="1",target-id="process 19451",frame={level="0",addr="0x08048618",func="main",args=[],file="a.cc",fullname="/local/lmckhou/testing/a.cc",line="9"},state="stopped",core="2"}]
147
* -list-thread-groups --available
148
* ^done,groups=[{id="19445",type="process",description="gdb.7.2 -i mi testing/a.out",user="lmckhou"},{id="19451",type="process",description="/local/lmckhou/testing/a.out",user="lmckhou"},{id="19462",type="process",description="sleep 5",user="lmckhou"}]
153
public class MIListThreadGroupsInfo extends MIInfo {
156
* @noextend This interface is not intended to be extended by clients.
157
* @noimplement This interface is not intended to be implemented by clients.
159
public interface IThreadGroupInfo {
163
String getDesciption();
171
String getExecutable();
175
private static class ThreadGroupInfo implements IThreadGroupInfo {
176
final String fGroupId;
177
final String fDescription;
182
final String[] fCores;
183
final String fExecutable;
185
public ThreadGroupInfo(String id, String description, String type, String pid,
186
String user, String[] cores, String exec) {
188
fDescription = description;
196
fName = parseName(fDescription);
199
private static String parseName(String desc) {
200
String name = ""; //$NON-NLS-1$
202
// Find the string "name: " followed by the smallest set of characters that
203
// is followed by a comma, or by the end of the line.
204
Pattern pattern = Pattern.compile("name: (.*?)(, |$)", Pattern.MULTILINE); //$NON-NLS-1$
205
Matcher matcher = pattern.matcher(desc);
206
if (matcher.find()) {
207
name = matcher.group(1);
209
// If we didn't get the form "name: " then we expect to have the form
210
// "/usr/sbin/dhcdbd --system"
211
name = desc.split("\\s", 2)[0]; //$NON-NLS-1$
217
public String getGroupId() { return fGroupId; }
218
public String getPid() { return fPid; }
220
public String getName() { return fName; }
222
public String getDesciption() { return fDescription; }
223
public String[] getCores() { return fCores; }
224
public String getUser() { return fUser; }
226
public String getType() { return fType; }
227
public String getExecutable() { return fExecutable; }
231
private IThreadGroupInfo[] fGroupList;
232
private MIThreadInfoInfo fThreadInfo;
234
public MIListThreadGroupsInfo(MIOutput out) {
239
public IThreadGroupInfo[] getGroupList() { return fGroupList; }
240
public MIThreadInfoInfo getThreadInfo() { return fThreadInfo; }
242
private void parse() {
244
MIOutput out = getMIOutput();
245
MIResultRecord rr = out.getMIResultRecord();
247
MIResult[] results = rr.getMIResults();
248
for (int i = 0; i < results.length; i++) {
249
String var = results[i].getVariable();
250
if (var.equals("groups")) { //$NON-NLS-1$
251
MIValue val = results[i].getMIValue();
252
if (val instanceof MIList) {
253
parseGroups((MIList)val);
255
} else if (var.equals("threads")) { //$NON-NLS-1$
256
// Re-use the MIThreadInfoInfo parsing
257
fThreadInfo = new MIThreadInfoInfo(out);
262
if (fGroupList == null) {
263
fGroupList = new IThreadGroupInfo[0];
265
if (fThreadInfo == null) {
266
fThreadInfo = new MIThreadInfoInfo(null);
270
private void parseGroups(MIList list) {
271
MIValue[] values = list.getMIValues();
272
fGroupList = new IThreadGroupInfo[values.length];
273
for (int i = 0; i < values.length; i++) {
274
MIResult[] results = ((MITuple)values[i]).getMIResults();
275
String id, desc, type, pid, exec, user;
276
id = desc = type = pid = exec = user = "";//$NON-NLS-1$
278
String[] cores = null;
280
for (MIResult result : results) {
281
String var = result.getVariable();
282
if (var.equals("id")) { //$NON-NLS-1$
283
MIValue value = result.getMIValue();
284
if (value instanceof MIConst) {
285
String str = ((MIConst)value).getCString();
288
} else if (var.equals("description")) { //$NON-NLS-1$
289
MIValue value = result.getMIValue();
290
if (value instanceof MIConst) {
291
String str = ((MIConst)value).getCString();
294
} else if (var.equals("type")) { //$NON-NLS-1$
295
MIValue value = result.getMIValue();
296
if (value instanceof MIConst) {
297
String str = ((MIConst)value).getCString();
300
} else if (var.equals("pid")) { //$NON-NLS-1$
301
MIValue value = result.getMIValue();
302
if (value instanceof MIConst) {
303
String str = ((MIConst)value).getCString();
306
} else if (var.equals("user")) { //$NON-NLS-1$
307
MIValue value = result.getMIValue();
308
if (value instanceof MIConst) {
309
String str = ((MIConst)value).getCString();
312
} else if (var.equals("cores")) { //$NON-NLS-1$
313
// Staring with GDB 7.1
314
MIValue value = result.getMIValue();
315
if (value instanceof MIList) {
316
cores = parseCores((MIList)value);
318
} else if (var.equals("executable")) { //$NON-NLS-1$
319
// Staring with GDB 7.2
320
MIValue value = result.getMIValue();
321
if (value instanceof MIConst) {
322
String str = ((MIConst)value).getCString();
327
// In the case of -list-thread-groups --available, the pid field is not present, but the
328
// pid is used as the main id. To know we are in this case, we check that we have
329
// a description, that only happens for -list-thread-groups --available
330
// We must check this because with GDB 7.2, there will be no pid field as a result
331
// of -list-thread-groups, if no process is actually running yet.
332
if (pid.equals("") && !desc.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$
335
fGroupList[i] = new ThreadGroupInfo(id, desc, type, pid, user, cores, exec);
339
private String[] parseCores(MIList list) {
340
List<String> cores = new ArrayList<String>();
342
MIValue[] values = list.getMIValues();
343
for (int i = 0; i < values.length; i++) {
344
if (values[i] instanceof MIConst) {
345
cores.add(((MIConst)values[i]).getCString());
348
return cores.toArray(new String[cores.size()]);