/******************************************************************************* * Copyright (c) 2008, 2010 Ericsson and others. * 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: * Ericsson - Initial API and implementation * Wind River Systems - refactored to match pattern in package * John Dallaway - GDB 7.x getOsId() pattern match too restrictive (Bug 325552) *******************************************************************************/ package org.eclipse.cdt.dsf.mi.service.command.output; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.cdt.dsf.concurrent.Immutable; /** * GDB/MI Thread tuple parsing. * * @since 1.1 */ @Immutable public class MIThread { /** @since 4.1 */ public final static String MI_THREAD_STATE_RUNNING = "running"; //$NON-NLS-1$ /** @since 4.1 */ public final static String MI_THREAD_STATE_STOPPED = "stopped"; //$NON-NLS-1$ final private String fThreadId; final private String fTargetId; final private String fOsId; final private String fParentId; final private MIFrame fTopFrame; final private String fDetails; final private String fState; final private String fCore; private MIThread(String threadId, String targetId, String osId, String parentId, MIFrame topFrame, String details, String state, String core) { fThreadId = threadId; fTargetId = targetId; fOsId = osId; fParentId = parentId; fTopFrame = topFrame; fDetails = details; fState = state; fCore = core; } public String getThreadId() { return fThreadId; } public String getTargetId() { return fTargetId; } public String getOsId() { return fOsId; } public String getParentId() { return fParentId; } public MIFrame getTopFrame() { return fTopFrame; } public String getDetails() { return fDetails; } public String getState() { return fState; } /** * Available since GDB 7.1 * @since 4.0 */ public String getCore() { return fCore; } public static MIThread parse(MITuple tuple) { MIResult[] results = tuple.getMIResults(); String threadId = null; String targetId = null; String osId = null; String parentId = null; MIFrame topFrame = null; String state = null; String details = null; String core = null; for (int j = 0; j < results.length; j++) { MIResult result = results[j]; String var = result.getVariable(); if (var.equals("id")) { //$NON-NLS-1$ MIValue val = results[j].getMIValue(); if (val instanceof MIConst) { threadId = ((MIConst) val).getCString().trim(); } } else if (var.equals("target-id")) { //$NON-NLS-1$ MIValue val = results[j].getMIValue(); if (val instanceof MIConst) { targetId = ((MIConst) val).getCString().trim(); osId = parseOsId(targetId); parentId = parseParentId(targetId); } } else if (var.equals("frame")) { //$NON-NLS-1$ MITuple val = (MITuple)results[j].getMIValue(); topFrame = new MIFrame(val); } else if (var.equals("state")) { //$NON-NLS-1$ MIValue val = results[j].getMIValue(); if (val instanceof MIConst) { state = ((MIConst) val).getCString().trim(); } } else if (var.equals("details")) { //$NON-NLS-1$ MIValue val = results[j].getMIValue(); if (val instanceof MIConst) { details = ((MIConst) val).getCString().trim(); } } else if (var.equals("core")) { //$NON-NLS-1$ MIValue val = results[j].getMIValue(); if (val instanceof MIConst) { core = ((MIConst) val).getCString().trim(); } } } return new MIThread(threadId, targetId, osId, parentId, topFrame, details, state, core); } // Note that windows gdbs returns lower case "thread" , so the matcher needs to be case-insensitive. private static Pattern fgOsIdPattern1 = Pattern.compile("([Tt][Hh][Rr][Ee][Aa][Dd]\\s*)(0x[0-9a-fA-F]+|-?\\d+)(\\s*\\([Ll][Ww][Pp]\\s*)(\\d*)", 0); //$NON-NLS-1$ private static Pattern fgOsIdPattern2 = Pattern.compile("[Tt][Hh][Rr][Ee][Aa][Dd]\\s*\\d+\\.(\\d+)", 0); //$NON-NLS-1$ private static Pattern fgOsIdPattern3 = Pattern.compile("[Tt][Hh][Rr][Ee][Aa][Dd]\\s*(\\S+)", 0); //$NON-NLS-1$ static String parseOsId(String str) { // General format: // "Thread 0xb7c8ab90 (LWP 7010)" // ^^^^ // "Thread 162.32942" // ^^^^^ // "thread abc123" // ^^^^^^ // PLEASE UPDATE MIThreadTests.java IF YOU TWEAK THIS CODE Matcher matcher = fgOsIdPattern1.matcher(str); if (matcher.find()) { return matcher.group(4); } matcher = fgOsIdPattern2.matcher(str); if (matcher.find()) { return matcher.group(1); } matcher = fgOsIdPattern3.matcher(str); if (matcher.find()) { return matcher.group(1); } return null; } private static Pattern fgIdPattern = Pattern.compile("[Tt][Hh][Rr][Ee][Aa][Dd]\\s*(\\d+)\\.\\d+", 0); //$NON-NLS-1$ /** * This is used to parse the same ID fed to {@link #parseOsId(String)}. The * difference is that we return the first portion when the ID is in format * "Thread pppp.tttt". If the ID is not in that format, we return null. */ static String parseParentId(String str) { // General format: // "Thread 162.32942" // ^^^ // PLEASE UPDATE MIThreadTests.java IF YOU TWEAK THIS CODE Matcher matcher = fgIdPattern.matcher(str); if (matcher.find()) { return matcher.group(1); } return null; } }