/*
* Copyright (c) 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;
import java.io.*;
import java.util.*;
import com.sun.max.tele.MaxPlatform.OS;
import com.sun.max.tele.*;
import com.sun.max.tele.method.*;
import com.sun.max.tele.reference.*;
import com.sun.max.unsafe.*;
/**
* Provides access to native functions defined in shared libraries loaded into the VM.
*/
public class TeleNativeLibraries {
private static class TargetVMLibInfo {
private RemoteReference reference;
private TeleVM vm;
protected TargetVMLibInfo(TeleVM vm, RemoteReference teleNativeLibraryReference) {
this.vm = vm;
this.reference = teleNativeLibraryReference;
}
TeleNativeLibrary getTeleNativeLibrary(TeleNativeLibrary oldTeleNativeLibrary) {
TeleNativeLibrary result;
if (oldTeleNativeLibrary == null) {
String libPath;
final Pointer pathAsCString = vm.fields().DynamicLinker$LibInfo_pathAsCString.readWord(reference).asPointer();
OS os = vm.platform().getOS();
if (pathAsCString.isNotZero()) {
libPath = stringFromCString(vm, pathAsCString);
} else {
// this is mainHandle
libPath = new File(vm.bootImageFile().getParent(), os.libjvmName() + "." + os.libSuffix()).getAbsolutePath();
}
result = TeleNativeLibrary.create(vm, os, libPath);
} else {
result = oldTeleNativeLibrary;
}
// These values may change between calls to this method, although once set they are constant.
final Pointer sentinelAsCString = vm.fields().DynamicLinker$LibInfo_sentinelAsCString.readWord(reference).asPointer();
String sentinel = sentinelAsCString.isZero() ? null : stringFromCString(vm, sentinelAsCString);
final Address sentinelAddress = vm.fields().DynamicLinker$LibInfo_sentinelAddress.readWord(reference).asAddress();
result.setSentinel(sentinel, sentinelAddress);
return result;
}
private static String stringFromCString(TeleVM vm, Pointer cString) {
byte[] bytes = new byte[1024];
int index = 0;
while (true) {
byte b = vm.memoryIO().readByte(cString, index);
if (b == 0) {
break;
}
bytes[index++] = b;
}
return new String(bytes, 0, index);
}
}
private final static ArrayList<TeleNativeLibrary> libs = new ArrayList<TeleNativeLibrary>();
public final static List<TeleNativeLibrary> libs() {
return libs;
}
/**
* Add any new libraries since last refresh. It is possible that a sentinel value has appeared
* since the last refresh, so we check that.
* @param vm
*/
public static void update(TeleVM vm) throws Exception {
int length = vm.fields().DynamicLinker_libInfoIndex.readInt(vm);
RemoteReference libInfoArrayReference = vm.fields().DynamicLinker_libInfoArray.readRemoteReference(vm);
for (int index = 0; index < length; index++) {
boolean newLib = index >= libs.size();
if (newLib || libs.get(index).base().isZero()) {
RemoteReference libInfoReference = libInfoArrayReference.readArrayAsRemoteReference(index);
TargetVMLibInfo targetVMLibInfo = new TargetVMLibInfo(vm, libInfoReference);
TeleNativeLibrary teleNativeLibrary = processLibrary(targetVMLibInfo, newLib ? null : libs.get(index));
if (index >= libs.size()) {
libs.add(teleNativeLibrary);
}
}
}
}
/**
* Read the symbols from the library using OS-specific object format.
* If we know the sentinel symbol's address, then gather all the native functions.
* @param targetVMLibInfo
* @param oldTeleNativeLibrary null if new library else existing TeleNativeLibrary
* @return associated TeleNativeLibrary
* @throws Exception
*/
private static TeleNativeLibrary processLibrary(TargetVMLibInfo targetVMLibInfo, TeleNativeLibrary oldTeleNativeLibrary) throws Exception {
TeleNativeLibrary teleNativeLibrary = targetVMLibInfo.getTeleNativeLibrary(oldTeleNativeLibrary);
teleNativeLibrary.gatherFunctions();
return teleNativeLibrary;
}
}