2

JNA を使用して、Solaris 11.3のkstat ライブラリを Javaにマップしようとしています。ほとんどの構造を機能させることができましたが、過去 24 時間、特に困難な構造内の構造内の結合との戦いに費やしました。

kstat_data_lookup()kstat_namedを使用して、必要な構造へのポインターを正常に取得しています。私のコードは、この C 構造体のほとんどのデータ (name、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 の場合、これは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値は数百万で、文字列を読み取ろうとする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

私も試しました:

  • KstatNamedStringタイプの代わりにタイプとしてPointer指定する
  • ByReference構造体と共用体の両方でのさまざまな組み合わせの使用

ここで有望な結果だと思ったことを試すなど、どこでもグーグル検索しましたが、何もうまくいかないようです。

私は単純なものが欠けていると確信しています。

4

1 に答える 1