/*
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.max.tele.debug.linux;
import java.io.*;
import java.nio.*;
import java.util.*;
import com.sun.max.lang.*;
import com.sun.max.tele.channel.*;
import com.sun.max.tele.channel.natives.*;
import com.sun.max.tele.debug.*;
import com.sun.max.tele.debug.unix.*;
import com.sun.max.util.*;
import com.sun.max.vm.hosted.*;
/**
* An implementation of {@link TeleChannelProtocol} for Linux that uses direct native method calls.
*
* Currently the Linux implementation does not use the {@link TeleChannelNatives} class owing to
* the requirement to invoke the underlying native methods in the same thread, which is handled in
* {@link LinuxTask}.
*/
public class LinuxNativeTeleChannelProtocol extends UnixNativeTeleChannelProtocolAdaptor implements LinuxTeleChannelProtocol {
public LinuxNativeTeleChannelProtocol() {
super(null);
}
private LinuxTask leaderTask;
private Map<Integer, LinuxTask> taskMap = new HashMap<Integer, LinuxTask>();
private LinuxTask task(long ltid) {
final int tid = (int) ltid;
LinuxTask result = taskMap.get(tid);
if (result == null) {
result = new LinuxTask(leaderTask, tid);
taskMap.put(tid, result);
}
return result;
}
@Override
public long create(String programFile, String[] commandLineArguments) {
final long commandLineArgumentsBuffer;
try {
commandLineArgumentsBuffer = createBufferAndAgent(programFile, commandLineArguments);
} catch (BootImageException ex) {
return -1;
}
leaderTask = LinuxTask.createChild(commandLineArgumentsBuffer, agent.port());
if (leaderTask == null) {
return -1;
}
return 1;
}
@Override
public int readBytes(long src, byte[] dst, int dstOffset, int length) {
return leaderTask.readBytes(src, dst, false, dstOffset, length);
}
@Override
public int readBytes(long src, ByteBuffer dst, int dstOffset, int length) {
if (dst.isDirect()) {
return leaderTask.readBytes(src, dst, true, dstOffset, length);
}
return leaderTask.readBytes(src, dst.array(), false, dst.arrayOffset() + dstOffset, length);
}
@Override
public int writeBytes(long dst, byte[] src, int srcOffset, int length) {
return leaderTask.writeBytes(dst, src, false, srcOffset, length);
}
@Override
public int writeBytes(long dst, ByteBuffer src, int srcOffset, int length) {
if (src.isDirect()) {
return leaderTask.writeBytes(dst, src, true, srcOffset, length);
}
return leaderTask.writeBytes(dst, src.array(), false, src.arrayOffset() + srcOffset, length);
}
@Override
public boolean gatherThreads(final Object teleDomain, final Object threadList, final long tlaList) {
final LinuxTeleVM teleVM = (teleDomain instanceof LinuxTeleProcess) ? (LinuxTeleVM) ((LinuxTeleProcess) teleDomain).vm() : null;
try {
if (teleVM != null) {
teleVM.handOverVMLock();
}
SingleThread.executeWithException(new Function<Void>() {
public Void call() throws IOException {
nativeGatherThreads(leaderTask.tgid(), teleDomain, threadList, tlaList);
return null;
}
});
} catch (Exception exception) {
exception.printStackTrace();
} finally {
if (teleVM != null) {
teleVM.handBackVMLock();
}
}
return false;
}
@Override
public boolean readRegisters(long threadId, byte[] integerRegisters, int integerRegistersSize, byte[] floatingPointRegisters, int floatingPointRegistersSize, byte[] stateRegisters,
int stateRegistersSize) {
return task(threadId).readRegisters(integerRegisters, floatingPointRegisters, stateRegisters);
}
@Override
public boolean setInstructionPointer(long threadId, long ip) {
return task(threadId).setInstructionPointer(ip);
}
@Override
public boolean singleStep(long threadId) {
return task(threadId).singleStep();
}
@Override
public boolean resumeAll() {
try {
leaderTask.resume(true);
return true;
} catch (OSExecutionRequestException ex) {
return false;
}
}
@Override
public boolean suspendAll() {
try {
leaderTask.suspend(true);
return true;
} catch (OSExecutionRequestException ex) {
return false;
}
}
@Override
public boolean resume(long threadId) {
return false;
}
@Override
public boolean suspend(long threadId) {
return false;
}
@Override
public int waitUntilStoppedAsInt() {
final ProcessState result = waitUntilStopped();
return result.ordinal();
}
@Override
public ProcessState waitUntilStopped() {
final ProcessState result = leaderTask.waitUntilStopped(true);
if (result != ProcessState.STOPPED) {
leaderTask.close();
}
return result;
}
@Override
public boolean kill() {
try {
leaderTask.kill();
return true;
} catch (OSExecutionRequestException ex) {
return false;
}
}
private static native void nativeGatherThreads(long pid, Object teleProcess, Object threadList, long tlaList);
}