在JNA

2016-07-29 83 views
0

映射一個工會內的構造,我試圖用JNA中的Solaris 11.3 kstat library映射到Java。儘管我已經設法使大部分結構能夠運作,但我在過去的24小時內與一個特別困難的工會內部結合聯盟進行了鬥爭。在JNA

我正在成功檢索指向kstat_named結構的指針,我需要使用kstat_data_lookup()。我的代碼可以正確獲取最大的收益的C結構數據(姓名,DATA_TYPE和工會的非結構構件):

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(對應於union中的str結構),那麼我無法正確檢索數據。

我制訂了嵌套結構是這樣的:

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的值在百萬以上,並試圖讀取字符串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
  • 在這兩個結構使用的ByReference各種組合和工會

我到處搜索了包括嘗試我認爲是有希望的結果here,但似乎沒有任何工作。

我敢肯定,我失去了一些東西簡單。

回答

1

使用KstatNamedString代替Pointer類型。

更改基於指針的構造是這樣的:

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

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

,改變str結構域的addr領域是一個簡單的Pointer(不需要周圍的工會位)。

public Pointer /*UNION*/ addr; 

-Djna.dump_memory=true運行你的JVM和打印您的新初始化Structure爲字符串。這將向您展示JNA如何解釋結構的內存佈局以及本機內存如何初始化。這應該有助於你確定如何提取你正在尋找的字符串(假設它在那裏)。

在設置聯合類型之前,您還可以調整聯合read()方法以最初只讀取類型字段(使用Structure.readField("data_type"))。

+0

謝謝! 'super(p)'做了訣竅。 –