在JNA

时间:2016-07-29 20:20:29

标签: struct solaris jna unions kstat

我正在尝试使用JNA将Solaris 11.3中的kstat library映射到Java。虽然我已经设法使大多数结构工作,但我花了最后24小时与一个特别困难的工会内部结合工作。

我使用kstat_data_lookup()成功检索了指向kstat_named结构的指针。我的代码正确地检索了这个C结构中的大部分数据(联合的name,data_type和非struct成员):

typedef struct kstat_named {
   char    name[KSTAT_STRLEN];    /* name of counter */
   uchar_t data_type;             /* data type */
   union {
            charc[16];            /* enough for 128-bit ints */
            struct {
               union {
                   char *ptr;    /* NULL-terminated string */
               } addr;
               uint32_t len;     /* length of string */
            } str;
            int32_t   i32;
            uint32_t  ui32;
            int64_t   i64;
            uint64_t  ui64;

  /* These structure members are obsolete */

            int32_t   l;
            uint32_t  ul;
            int64_t   ll;
            uint64_t  ull;
         } value;                /* value of counter */
} kstat_named_t;

我在JNA中将其映射如下:

class KstatNamed extends Structure {
    public static class UNION extends Union {
        public byte[] charc = new byte[16]; // enough for 128-bit ints
        public Pointer str; // KstatNamedString
        public int i32;
        public int ui32;
        public long i64;
        public long ui64;
    }

    public byte[] name = new byte[KSTAT_STRLEN]; // name of counter
    public byte data_type; // data type
    public UNION value; // value of counter

    public KstatNamed() {
        super();
    }

    public KstatNamed(Pointer p) {
        super();
        this.useMemory(p);
        this.read();
    }

    @Override
    public void read() {
        super.read();
        switch (data_type) {
        case KSTAT_DATA_CHAR:
            value.setType(byte[].class);
            break;
        case KSTAT_DATA_STRING:
            value.setType(Pointer.class);
            break;
        case KSTAT_DATA_INT32:
        case KSTAT_DATA_UINT32:
            value.setType(int.class);
            break;
        case KSTAT_DATA_INT64:
        case KSTAT_DATA_UINT64:
            value.setType(long.class);
            break;
        default:
            break;
        }
        value.read();
    }

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList(new String[] { "name", "data_type", "value" });
    }
}

此代码适用于int32类型(KSTAT_DATA_INT32)。但是,当数据类型为KSTAT_DATA_STRING(对应str内的union结构时,我无法正确检索数据。

我已经映射了这样的嵌套结构:

class KstatNamedString extends Structure {
    public static class UNION extends Union {
        public Pointer ptr; // NULL-terminated string
    }

    public UNION addr;
    public int len; // length of string

    public KstatNamedString() {
        super();
    }

    public KstatNamedString(Pointer p) {
        super();
        this.useMemory(p);
        this.read();
    }

    @Override
    public void read() {
        super.read();
        addr.setType(Pointer.class);
        addr.read();
    }

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList(new String[] { "addr", "len" });
    }
}

最终我试图复制这个C宏的行为:

#define KSTAT_NAMED_STR_PTR(knptr) ((knptr)->value.str.addr.ptr)

我尝试了多种尝试访问上述结构的不同方法,但它似乎永远不会读取正确的数据(len值是数百万并尝试读取字符串{{1导致segfault)。我试过了:

ptr

我也试过了:

  • 指定Pointer p = LibKstat.INSTANCE.kstat_data_lookup(ksp, name); KstatNamed data = new KstatNamed(p); KstatNamedString str = new KstatNamedString(data.value.str); return str.addr.ptr.getString(0); // <--- Segfault on C side 作为类型而不是KstatNamedString类型
  • 在结构和联盟中使用Pointer的各种组合

我到处搜索,包括尝试我认为有希望的结果here,但似乎没有任何效果。

我确定我错过了一些简单的事情。

1 个答案:

答案 0 :(得分:1)

使用KstatNamedString代替Pointer类型。

更改基于指针的构造函数,如下所示:

public KstatNamed(Pointer p) {
    super(p);
    this.read();
}

public KstatNamedString(Pointer p) {
    super(p);
    this.read();
}

并将addr struct字段的str字段更改为简单的Pointer(不需要围绕它的union位)。

public Pointer /*UNION*/ addr;

使用-Djna.dump_memory=true运行您的JVM,并将新初始化的Structure打印为字符串。这将向您展示JNA如何解释结构的内存布局,以及如何初始化本机内存。这应该可以帮助您确定如何提取您正在寻找的字符串(假设它在那里)。

在设置联合类型之前,您还可以调整union read()方法,以便最初只读取类型字段(使用Structure.readField("data_type"))。