2016-07-29 30 views
0

Solaris 11.3のkstat libraryをJNAを使用してJavaにマップしようとしています。私は構造体のほとんどを動作させることができましたが、私は過去24時間を組合の中で特に困難な組合と戦って過ごしました。JNA内の共用体内の構造体のマッピング

kstat_data_lookup()を使用する必要があるkstat_named構造体へのポインタを正常に取得しています。私のコードは、適切に、この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)に対して正しく機能します。ただし、union内のstr構造に対応するデータ型がKSTAT_DATA_STRINGの場合、データを正しく取得するのに成功していません。

私はこのような入れ子構造をマッピングしています

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がsegfaultを引き起こしています)。私が試した:

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 

は、私も試してみた:

  • ではなく、構造体と共用体の両方でByReferenceの様々な組み合わせを使用してPointerタイプ
  • の種類としてKstatNamedStringを指定

私は有望な結果だと思ったことを含めて、どこでもGoogleで検索しましたhereしかし、何も動作していないようです。

私は何か簡単なものがないと確信しています。

答えて

1

Pointerタイプの代わりにKstatNamedStringを使用してください。

は、このようなあなたのポインタベースのコンストラクタを変更し

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

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

とシンプルPointer(その周り組合・ビットの必要性)はないようにstr構造体フィールドのaddrフィールドを変更します。

public Pointer /*UNION*/ addr; 

-Djna.dump_memory=trueであなたのJVMを実行して、文字列として新しく初期化Structureを印刷します。これは、JNAが構造体のメモリレイアウトをどのように解釈するか、およびネイティブメモリがどのように初期化されるかを示します。それはあなたが探している文字列を抽出する方法を決定するのに役立ちます(それがあると仮定して)。

ユニオンタイプを設定する前に、ユニオンread()メソッドを調整して、最初にタイプフィールド(Structure.readField("data_type")を使用)のみを読み取るようにすることもできます。

+0

ありがとうございます! 'super(p)'がやった。 –