2016-07-29 2 views
0

Я пытаюсь сопоставить kstat library в Solaris 11.3 с Java, используя JNA. В то время как мне удалось заставить большинство структур работать, я провел последние 24 часа, сражаясь с особенно сложным объединением в рамках структуры внутри профсоюза.Сопоставление структуры внутри объединения в JNA

Я успешно получаю указатель на структуру kstat_named Мне нужно использовать kstat_data_lookup(). Мой код правильно извлекает большую часть данных (имя, DATA_TYPE и без STRUCT членов союза) в этой C структуру:

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; 

Я отображенная это в ЮНЕ следующим образом:

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 в обеих структурах и профсоюзы

Я повсюду гугл, включая попытку того, что, по моему мнению, было многообещающим результатом here, но ничего не работает.

Уверен, что я пропустил что-то простое.

ответ

1

Используйте KstatNamedString вместо Pointer.

Изменение указателя на основе конструкторов, как это:

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

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

и изменить addr поле поля str STRUCT чтобы быть простым Pointer (нет необходимости союзных бит вокруг него).

public Pointer /*UNION*/ addr; 

Запустите JVM с -Djna.dump_memory=true и распечатать заново инициализирован Structure в виде строки. Это покажет вам, как JNA интерпретирует макет памяти структуры и как инициализируется исходная память. Это должно помочь вам определить, как извлечь строку, которую вы ищете (при условии, что она есть).

Вы также можете настроить свой союз read(), чтобы сначала прочитать только поле типа (используя Structure.readField("data_type")) перед установкой типа объединения.

+0

Спасибо! 'super (p)' сделал трюк. –

Смежные вопросы