/* * Copyright (c) 2010, 2011, 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.darwin; import java.io.*; import java.util.*; import com.sun.max.program.*; import com.sun.max.tele.*; import com.sun.max.tele.channel.iostream.*; import com.sun.max.tele.debug.*; import com.sun.max.tele.debug.darwin.DarwinMachO.LoadCommand; import com.sun.max.tele.debug.darwin.DarwinMachO.Segment64LoadCommand; import com.sun.max.tele.debug.darwin.DarwinMachO.ThreadLoadCommand; import com.sun.max.tele.util.*; import com.sun.max.unsafe.*; import com.sun.max.vm.hosted.*; /** * Core file handling for Darwin. Of course, it doesn't use ELF. Mach_O instead. * */ public class DarwinDumpTeleChannelProtocol extends TeleChannelDataIOProtocolAdaptor implements DarwinTeleChannelProtocol { protected int tlaSize; public boolean bigEndian; protected DarwinMachO machO; protected MaxVM teleVM; protected static final String HEAP_SYMBOL_NAME = "theHeap"; // defined in image.c, holds the base address of the boot heap private final List<Segment64LoadCommand> segmentList = new ArrayList<Segment64LoadCommand>(); private final List<ThreadLoadCommand> threadDataList = new ArrayList<ThreadLoadCommand>(); private DarwinDumpThreadAccess darwinDumpThreadAccess; public DarwinDumpTeleChannelProtocol(MaxVM teleVM, File vm, File dump) { this.teleVM = teleVM; try { // We need the tele library because we use it to access the OS-specific structs // that are embedded in the LC_THREAD segments of the dump file. Prototype.loadLibrary(TeleVM.TELE_LIBRARY_NAME); machO = new DarwinMachO(dump.getAbsolutePath()); processLoadCommands(machO.getLoadCommands()); } catch (Exception ex) { TeleError.unexpected("failed to open dump file: " + dump, ex); } } private void processLoadCommands(LoadCommand[] loadCommands) throws IOException { for (int i = 0; i < loadCommands.length; i++) { LoadCommand lc = loadCommands[i]; switch (lc.cmd) { case LoadCommand.LC_SEGMENT_64: segmentList.add((Segment64LoadCommand) lc); break; case LoadCommand.LC_THREAD: threadDataList.add((ThreadLoadCommand) lc); break; default: } } } @Override public int writeBytes(long dst, byte[] src, int srcOffset, int length) { Trace.line(2, "WARNING: Inspector trying to write to " + Long.toHexString(dst)); return length; } @Override public long create(String pathName, String[] commandLineArguments) { inappropriate("create"); return -1; } @Override public boolean attach(int id) { return true; } @Override public boolean detach() { return true; } @Override public int maxByteBufferSize() { return Integer.MAX_VALUE; } private Segment64LoadCommand findAddress(long addr) { final Address address = Address.fromLong(addr); for (Segment64LoadCommand slc : segmentList) { if (slc.filesize != 0) { final Address end = Address.fromLong(slc.vmaddr).plus(slc.vmsize); if (address.greaterEqual(Address.fromLong(slc.vmaddr)) && address.lessThan(end)) { return slc; } } } return null; } @Override public long getBootHeapStart() { final BootImage.Header header = teleVM.bootImage().header; final int bootHeapSize = header.codeSize + header.heapSize; for (Segment64LoadCommand slc : segmentList) { if (slc.filesize != 0 && slc.filesize == bootHeapSize) { return slc.vmaddr; } } TeleError.unexpected("failed to find the start of the boot heap"); return 0; } @Override public int readBytes(long src, byte[] dst, int dstOffset, int length) { final Segment64LoadCommand slc = findAddress(src); if (slc == null) { return 0; } try { machO.raf.seek(slc.fileoff + (src - slc.vmaddr)); return machO.raf.read(dst, dstOffset, length); } catch (IOException ex) { return 0; } } @Override public boolean initialize(int tlaSize, boolean bigEndian) { this.tlaSize = tlaSize; darwinDumpThreadAccess = new DarwinDumpThreadAccess(this, tlaSize, threadDataList); return true; } @Override public boolean readRegisters(long threadId, byte[] integerRegisters, int integerRegistersSize, byte[] floatingPointRegisters, int floatingPointRegistersSize, byte[] stateRegisters, int stateRegistersSize) { DarwinDumpThreadAccess.DarwinThreadInfo threadInfo = (DarwinDumpThreadAccess.DarwinThreadInfo) darwinDumpThreadAccess.getThreadInfo((int) threadId); System.arraycopy(threadInfo.integerRegisters, 0, integerRegisters, 0, integerRegisters.length); System.arraycopy(threadInfo.floatingPointRegisters, 0, floatingPointRegisters, 0, floatingPointRegisters.length); System.arraycopy(threadInfo.stateRegisters, 0, stateRegisters, 0, stateRegisters.length); return true; } @Override public boolean gatherThreads(Object teleProcessObject, Object threadList, long tlaList) { return darwinDumpThreadAccess.gatherThreads(teleProcessObject, threadList, tlaList); } @Override public int gatherThreads(long tlaList) { inappropriate("gatherThreads"); return 0; } @Override public int readThreads(int size, byte[] gatherThreadsData) { inappropriate("readThreads"); return 0; } @Override public boolean setInstructionPointer(long threadId, long ip) { inappropriate("setInstructionPointer"); return false; } @Override public boolean singleStep(long threadId) { inappropriate("setInstructionPointer"); return false; } @Override public boolean resumeAll() { inappropriate("resumeAll"); return false; } @Override public boolean suspendAll() { inappropriate("suspendAll"); return false; } @Override public boolean resume(long threadId) { inappropriate("resume"); return false; } @Override public boolean suspend(long threadId) { inappropriate("suspend"); return false; } @Override public int waitUntilStoppedAsInt() { inappropriate("waitUntilStoppedAsInt"); return 0; } @Override public boolean kill() { return true; } @Override public boolean activateWatchpoint(long start, long size, boolean after, boolean read, boolean write, boolean exec) { inappropriate("activateWatchpoint"); return false; } @Override public boolean deactivateWatchpoint(long start, long size) { inappropriate("deactivateWatchpoint"); return false; } @Override public long readWatchpointAddress() { inappropriate("readWatchpointAddress"); return 0; } @Override public int readWatchpointAccessCode() { inappropriate("readWatchpointAccessCode"); return 0; } @Override public int setTransportDebugLevel(int level) { return 0; } @Override public ProcessState waitUntilStopped() { inappropriate("waitUntilStoppedAsInt"); return null; } protected static void inappropriate(String methodName) { TeleError.unexpected("method: " + methodName + " should not be called in dump mode"); } protected static void unimplemented(String methodName) { TeleError.unimplemented("method: " + methodName); } }