2016-07-29 36 views
0

Ich versuche, die kstat library in Solaris 11.3 zu Java mit JNA zuordnen. Während ich es geschafft habe, dass die meisten Strukturen funktionieren, habe ich die letzten 24 Stunden damit verbracht, mit einer besonders schwierigen Gewerkschaft innerhalb einer Struktur innerhalb einer Gewerkschaft zu kämpfen.Mapping einer Struktur in einer Union in JNA

Ich bin erfolgreich abrufen einen Zeiger auf eine kstat_named Struktur, die ich brauche kstat_data_lookup(). Mein Code richtig ruft die meisten Daten (Name, data_type und Nicht-struct Mitglieder der Vereinigung) in dieser C-Struktur:

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; 

ich dies in JNA zugeordnet haben, wie folgt:

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" }); 
    } 
} 

Dieser Code funktioniert ordnungsgemäß für Int32-Typen (KSTAT_DATA_INT32). Wenn der Datentyp jedoch KSTAT_DATA_STRING ist, was der Struktur str in union entspricht, habe ich keinen Erfolg beim ordnungsgemäßen Abrufen der Daten.

Ich habe die verschachtelte Struktur wie folgt abgebildet:

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" }); 
    } 
} 

Letztlich Ich versuche, das Verhalten dieses C Makro zu replizieren: Der Versuch, mehrere verschiedene Methoden der

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

Ich habe versucht, Zugriff auf die obige Struktur, aber es scheint nie die richtigen Daten zu lesen (der len Wert ist in den Millionen und versucht, die Zeichenfolge ptr zu lesen, verursacht Segfault). Ich habe versucht:

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 

Ich habe auch versucht:

  • Angabe KstatNamedString als Typ anstelle des Pointer Typ
  • Mit verschiedenen Kombinationen von ByReference sowohl in den Strukturen und den Gewerkschaften

Ich habe überall gegooglet, einschließlich zu versuchen, was ich für ein vielversprechendes Ergebnis hielt here, aber nichts scheint zu funktionieren.

Ich bin sicher, ich vermisse etwas Einfaches.

Antwort

1

Verwenden Sie KstatNamedString anstelle von Pointer Typ.

Ihre Zeiger-basierte ändern Konstrukteurs wie folgt aus:

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

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

und das addr Feld des str struct Feld ändern ein einfaches Pointer (keine Notwendigkeit für die Union Bits um ihn herum) zu sein.

public Pointer /*UNION*/ addr; 

Führen Sie Ihre JVM mit -Djna.dump_memory=true und drucken Sie Ihre neu initialisiert Structure als String zurück. Das zeigt Ihnen, wie JNA das Speicherlayout der Struktur interpretiert und wie der native Speicher initialisiert wird. Das sollte Ihnen helfen zu bestimmen, wie Sie die gesuchte Zeichenfolge extrahieren (vorausgesetzt, sie ist da).

Sie können die union-Methode read() auch so einstellen, dass zunächst nur das Feld type (unter Verwendung von Structure.readField("data_type")) gelesen wird, bevor der Union-Typ festgelegt wird.

+0

Danke! 'super (p)' hat es geschafft. –