Skip to content

Commit

Permalink
supported 64bit memory model on 64bit solaris.
Browse files Browse the repository at this point in the history
When the calling JVM is 64bit, /proc shows different contents, so we need a rather different code path for that.

git-svn-id: https://akuma.dev.java.net/svn/akuma/trunk/akuma@42 f4debed6-9561-0410-b0a4-b640bb5a59ad
  • Loading branch information
kohsuke committed Sep 17, 2009
1 parent 3b34e38 commit a5fce64
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 16 deletions.
17 changes: 17 additions & 0 deletions src/main/java/com/sun/akuma/CLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.sun.jna.StringArray;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import com.sun.jna.ptr.IntByReference;

/**
Expand Down Expand Up @@ -34,5 +35,21 @@ public interface CLibrary extends Library {

int sysctlnametomib(String name, Pointer mibp, IntByReference size);

public class FILE extends PointerType {
public FILE() {
}

public FILE(Pointer pointer) {
super(pointer);
}
}

// Additional C functions we need on Solaris 64bit to seek to a place above Long.MAX_VALUE
FILE fopen(String fileName, String mode);
int fseek(FILE file, long offset, int whence);
long ftell(FILE file);
int fread(Pointer buf, int size, int count, FILE file);
int fclose(FILE file);

public static final CLibrary LIBC = (CLibrary) Native.loadLibrary("c",CLibrary.class);
}
143 changes: 127 additions & 16 deletions src/main/java/com/sun/akuma/JavaVMArguments.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import java.util.*;
import static java.util.logging.Level.FINEST;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.logging.ConsoleHandler;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.File;
Expand All @@ -17,6 +19,7 @@
import java.io.DataInputStream;

import static com.sun.akuma.CLibrary.LIBC;
import com.sun.akuma.CLibrary.FILE;

/**
* List of arguments for Java VM and application.
Expand Down Expand Up @@ -102,6 +105,10 @@ private static int resolvePID(int pid) {
}

private static JavaVMArguments ofSolaris(int pid) throws IOException {
// /proc shows different contents based on the caller's memory model, so we need to know if we are 32 or 64.
// 32 JVMs are the norm, so err on the 32bit side.
boolean areWe64 = "64".equals(System.getProperty("sun.arch.data.model"));

pid = resolvePID(pid);
RandomAccessFile psinfo = new RandomAccessFile(new File("/proc/"+pid+"/psinfo"),"r");
try {
Expand Down Expand Up @@ -146,29 +153,86 @@ private static JavaVMArguments ofSolaris(int pid) throws IOException {
if(adjust(psinfo.readInt())!=pid)
throw new IOException("psinfo PID mismatch"); // sanity check

psinfo.seek(0xBC); // now jump to pr_argc
/* The following program computes the offset:
#include <stdio.h>
#include <sys/procfs.h>
int main() {
printf("psinfo_t = %d\n", sizeof(psinfo_t));
psinfo_t *x;
x = 0;
printf("%x\n", &(x->pr_argc));
}
*/

psinfo.seek(areWe64?0xEC:0xBC); // now jump to pr_argc
int argc = adjust(psinfo.readInt());
int argp = adjust(psinfo.readInt());

RandomAccessFile as = new RandomAccessFile(new File("/proc/"+pid+"/as"),"r");
try {
JavaVMArguments args = new JavaVMArguments();
for( int n=0; n<argc; n++ ) {
// read a pointer to one entry
as.seek(to64(argp+n*4));
int p = adjust(as.readInt());

args.add(readLine(as, p, "argv["+ n +"]"));
long argp = adjust(areWe64?psinfo.readLong():to64(psinfo.readInt()));
if(LOGGER.isLoggable(FINEST))
LOGGER.finest(String.format("argc=%d,argp=%X",argc,argp));

File asFile = new File("/proc/" + pid + "/as");
if (areWe64) {
// 32bit and 64bit basically does the same thing, but because the stream position
// is computed with signed long, doing 64bit seek to a position bigger than Long.MAX_VALUE
// requres some real hacking. Hence two different code path.
// (RandomAccessFile uses Java long for offset, so it just can't get to anywhere beyond Long.MAX_VALUE)
FILE fp = LIBC.fopen(asFile.getPath(),"r");
try {
JavaVMArguments args = new JavaVMArguments();
Memory m = new Memory(8);
for( int n=0; n<argc; n++ ) {
// read a pointer to one entry
seek64(fp,argp+n*8);
if(LOGGER.isLoggable(FINEST))
LOGGER.finest(String.format("Seeked to %X",LIBC.ftell(fp)));

m.setLong(0,0); // just to make sure failed read won't result in bogus value
LIBC.fread(m,1,8,fp);
long p = m.getLong(0);

args.add(readLine(fp, p, "argv["+ n +"]"));
}
return args;
} finally {
LIBC.fclose(fp);
}
} else {
RandomAccessFile as = new RandomAccessFile(asFile,"r");
try {
JavaVMArguments args = new JavaVMArguments();
for( int n=0; n<argc; n++ ) {
// read a pointer to one entry
as.seek(argp+n*4);
int p = adjust(as.readInt());

args.add(readLine(as, p, "argv["+ n +"]"));
}
return args;
} finally {
as.close();
}
return args;
} finally {
as.close();
}
} finally {
psinfo.close();
}
}

/**
* Seek to the specified position. This method handles offset bigger than {@link Long#MAX_VALUE} correctly.
*
* @param upos
* This value is interpreted as unsigned 64bit integer (even though it's typed 'long')
*/
private static void seek64(FILE fp, long upos) {
LIBC.fseek(fp,0,0); // start at the beginning
while(upos<0) {
long chunk = Long.MAX_VALUE;
upos -= chunk;
LIBC.fseek(fp,chunk,1);
}
LIBC.fseek(fp,upos,1);
}

/**
* {@link DataInputStream} reads a value in big-endian, so
* convert it to the correct value on little-endian systems.
Expand All @@ -180,6 +244,20 @@ private static int adjust(int i) {
return i;
}

private static long adjust(long i) {
if(IS_LITTLE_ENDIAN)
return (i<<56)
| ((i<<40) & 0x00FF000000000000L)
| ((i<<24) & 0x0000FF0000000000L)
| ((i<< 8) & 0x000000FF00000000L)
| ((i>> 8) & 0x00000000FF000000L)
| ((i>>24) & 0x0000000000FF0000L)
| ((i>>40) & 0x000000000000FF00L)
| (i>>56);
else
return i;
}

/**
* int to long conversion with zero-padding.
*/
Expand All @@ -189,7 +267,7 @@ private static long to64(int i) {

private static String readLine(RandomAccessFile as, int p, String prefix) throws IOException {
if(LOGGER.isLoggable(FINEST))
LOGGER.finest("Reading "+prefix+" at "+p);
LOGGER.finest(String.format("Reading %s at %X",prefix,p));

as.seek(to64(p));
ByteArrayOutputStream buf = new ByteArrayOutputStream();
Expand All @@ -206,6 +284,30 @@ private static String readLine(RandomAccessFile as, int p, String prefix) throws
return line;
}

private static String readLine(FILE as, long p, String prefix) throws IOException {
if(LOGGER.isLoggable(FINEST))
LOGGER.finest(String.format("Reading %s at %X",prefix,p));

seek64(as,p);
Memory m = new Memory(1);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
int i=0;
while(true) {
if(LIBC.fread(m,1,1,as)==0) break;
byte b = m.getByte(0);
if(b==0) break;

if((++i)%100==0 && LOGGER.isLoggable(FINEST))
LOGGER.finest(prefix +" is so far "+buf.toString());

buf.write(b);
}
String line = buf.toString();
if(LOGGER.isLoggable(FINEST))
LOGGER.finest(prefix+" was "+line);
return line;
}

/**
* Reads the entire file.
*/
Expand Down Expand Up @@ -362,6 +464,15 @@ void skip0() {
private static final Logger LOGGER = Logger.getLogger(JavaVMArguments.class.getName());

public static void main(String[] args) throws IOException {
// dump the process model of the caller
System.out.println("sun.arch.data.model="+System.getProperty("sun.arch.data.model"));
System.out.println("sun.cpu.endian="+System.getProperty("sun.cpu.endian"));

LOGGER.setLevel(Level.ALL);
ConsoleHandler handler = new ConsoleHandler();
handler.setLevel(Level.ALL);
LOGGER.addHandler(handler);

if (args.length==0)
System.out.println(current());
else {
Expand Down

0 comments on commit a5fce64

Please sign in to comment.