2016-07-29 11 views
0

Solaris 11.3의 kstat library을 JNA를 사용하여 Java로 매핑하려고합니다. 필자는 구조의 대부분을 작동시킬 수 있었지만 지난 24 시간 동안 특히 어려운 노동 조합 내에서 노조와 싸우는 데 보냈습니다.JNA의 공용 구조체 내 구조체 매핑

kstat_data_lookup()을 사용하여 필요한 kstat_named 구조에 대한 포인터를 성공적으로 검색하고 있습니다. 내가 JNA이를 매핑 한

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

내 코드가 제대로이 C 구조의 데이터 (이름, DATA_TYPE, 그리고 노동 조합의 비 구조체 명)의 대부분은 검색 이 코드는 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 지정

저는 유망한 결과라고 생각하는 것을 포함하여 어디에서나 봤습니다. 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)'가 트릭을했습니다. –