Hello,
I am trying to extract structure declaration from GNU/Linux kernel, basically this is the code I’m using for it (compiler arguments came from kernel compilation):
#!/usr/bin/env python3
import os
import pathlib
import shlex
import clang.cindex
CLANG_ARGS='-Wp,-MMD,drivers/scsi/aic7xxx/.aic79xx_osm.o.d -nostdinc -I./arch/x86/include -I./arch/x86/include/generated -I./include -I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/compiler-version.h -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -fmacro-prefix-map=./= -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Wno-format-security -std=gnu11 -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -fcf-protection=none -m64 -mno-80387 -mtune=generic -mno-red-zone -mcmodel=kernel -Wno-sign-compare -fno-asynchronous-unwind-tables -fno-jump-tables -fno-delete-null-pointer-checks -Wno-frame-address -Wno-address-of-packed-member -Wno-gnu-variable-sized-type-not-at-end -O2 -fstack-protector-strong -Wno-main -Wno-unused-but-set-variable -Wno-unused-const-variable -fno-stack-clash-protection -pg -mfentry -DCC_USING_FENTRY -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -Wcast-function-type -Wno-array-bounds -Wimplicit-fallthrough -fno-strict-overflow -fno-stack-check -Werror=date-time -Werror=incompatible-pointer-types -DKBUILD_MODFILE="drivers/scsi/aic7xxx/aic79xx" -DKBUILD_BASENAME="aic79xx_osm" -DKBUILD_MODNAME="aic79xx" -D__KBUILD_MODNAME=kmod_aic79xx'
def extract_structure(cursor):
print("{} {{".format(cursor.type.spelling))
for field in cursor.type.get_fields():
print("\t{} {};".format(field.type.spelling, field.spelling))
print("};\n---\n")
def main(filepath):
index = clang.cindex.Index.create()
tu = index.parse(filepath,
options=clang.cindex.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD,
args=shlex.split(CLANG_ARGS))
cursor = tu.cursor
for diag in tu.diagnostics:
print("[*] diagnotics: {}".format(diag))
for child in cursor.get_children():
if child.kind == clang.cindex.CursorKind.STRUCT_DECL:
extract_structure(child)
if __name__ == '__main__':
cwd = pathlib.Path.cwd()
os.chdir("/usr/src/linux-6.1.6")
main("./drivers/scsi/aic7xxx/aic79xx_osm.c")
os.chdir(cwd)
My issue is the unnamed structure and anonymous union. For example, for the file parsed (aic79xx_osm.c
), it produces this structure (first one in ./drivers/scsi/aic7xxx/aic79xx_osm.h
):
struct ahd_linux_device {
struct (unnamed struct at ./drivers/scsi/aic7xxx/aic79xx_osm.h:236:2) links;
int active;
int openings;
u_int qfrozen;
u_long commands_issued;
u_int tag_success_count;
ahd_linux_dev_flags flags;
struct timer_list timer;
u_int maxtags;
u_int tags_on_last_queuefull;
u_int last_queuefull_same_count;
u_int commands_since_idle_or_otag;
};
The original structure is that one below (comments removed):
struct ahd_linux_device {
TAILQ_ENTRY(ahd_linux_device) links;
int active;
int openings;
u_int qfrozen;
u_long commands_issued;
u_int tag_success_count;
#define AHD_TAG_SUCCESS_INTERVAL 50
ahd_linux_dev_flags flags;
struct timer_list timer;
u_int maxtags;
u_int tags_on_last_queuefull;
u_int last_queuefull_same_count;
#define AHD_LOCK_TAGS_COUNT 50
u_int commands_since_idle_or_otag;
#define AHD_OTAG_THRESH 500
};
TAILQ_ENTRY
is defined in ./drivers/scsi/aic7xxx/queue.h
as below:
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
So ideally I would like this result:
struct ahd_linux_device {
struct {
struct ahd_linux_device * tqe_next;
struct ahd_linux_device ** tqe_prev;
} links;
int active;
int openings;
[...]
};
Or if I can keep TAILQ_ENTRY
its still fine. But I have no idea of how I can achieved this. Is there way to do it ?