.\" Man page for pahole .\" Arnaldo Carvalho de Melo, 2009 .\" Licensed under version 2 of the GNU General Public License. .TH pahole 1 "January 16, 2020" "dwarves" "dwarves" .\" .SH "نام (NAME)" pahole \- نمایش و دستکاری چیدمان ساختار داده و چاپ خوانای داده‌های خام .SH "خلاصه دستور (SYNOPSIS)" \fBpahole\fR [\fIoptions\fR] \fIfiles\fR .SH "توضیحات (DESCRIPTION)" دستور .B pahole چیدمان ساختارهای داده کدگذاری‌شده در قالب‌های اطلاعات دیباگ را نمایش می‌دهد؛ قالب‌های DWARF، CTF و BTF پشتیبانی می‌شوند. .PP این ابزار از جمله برای این موارد مفید است: بهینه‌سازی ساختارهای داده مهم از طریق کاهش اندازه آن‌ها، پی بردن به اینکه چه فیلدی در یک آفست مشخص از ابتدای ساختار داده قرار گرفته است، بررسی تغییرات ABI و به طور کلی درک یک پایگاه‌کد جدید که باید با آن کار کنید. .PP این ابزار همچنین از این چیدمان‌های ساختاری برای چاپ خوانای داده‌های ارائه‌شده به ورودی استاندارد خود استفاده می‌کند، به عنوان مثال: .PP .nf $ pahole --header elf64_hdr --prettify /lib/modules/5.8.0-rc6+/build/vmlinux { .e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .e_type = 2, .e_machine = 62, .e_version = 1, .e_entry = 16777216, .e_phoff = 64, .e_shoff = 604653784, .e_flags = 0, .e_ehsize = 64, .e_phentsize = 56, .e_phnum = 5, .e_shentsize = 64, .e_shnum = 80, .e_shstrndx = 79, }, $ .fi برای نمونه‌ها و مستندات بیشتر بخش «چاپ خوانا (PRETTY PRINTING)» را ببینید. .PP فایل‌ها باید اطلاعات دیباگ مرتبط را داشته باشند. این اطلاعات ممکن است در خود فایل، در بخش‌های ELF، یا در فایلی جداگانه باشد. .PP یک راه برای داشتن این اطلاعات، مشخص کردن گزینه \fB\-g\fR برای کامپایلر در هنگام ساخت است. هنگامی که این کار انجام شود، اطلاعات در یک بخش ELF ذخیره خواهند شد. برای قالب اطلاعات دیباگ DWARF، این کار بخش ELF با نام \fB.debug_info\fR را (در میان بخش‌های دیگر) اضافه می‌کند. برای CTF، این اطلاعات فقط در یک بخش ELF با نام \fB.SUNW_ctf\fR یافت می‌شود. اطلاعات BTF دست‌کم در بخش ELF با نام \fB.BTF\fR و ممکن است در بخش \fB.BTF.ext\fR نیز ارائه شود. .PP بسته‌های \fBdebuginfo\fR که در بیشتر توزیع‌های لینوکس در دسترس هستند نیز توسط \fBpahole\fR پشتیبانی می‌شوند، جایی که اطلاعات دیباگ در فایلی جداگانه در دسترس است. .PP به طور پیش‌فرض، \fBpahole\fR چیدمان تمام structهای نام‌گذاری‌شده در فایل‌های مشخص‌شده را نمایش می‌دهد. .PP اگر فایلی مشخص نشود، بررسی می‌کند که آیا مسیر /sys/kernel/btf/vmlinux موجود است یا خیر، و با استفاده از اطلاعات BTF موجود در آن درباره هسته در حال اجرا عمل می‌کند، یعنی این دستور کار می‌کند: .PP .nf $ pahole list_head struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ .fi امکان تغییر مسیر فایل /sys/kernel/btf/vmlinux با تنظیم متغیر محیطی PAHOLE_VMLINUX_BTF_FILENAME وجود دارد. این کار ممکن است برای آزمایش، اسکریپت‌نویسی در هنگام استفاده از یک BTF متفاوت برای vmlinux مفید باشد. همچنین در آزمون‌های پس‌رفت pahole استفاده می‌شود. .PP اگر BTF وجود نداشته باشد و هیچ فایلی ارسال نشود، آن‌گاه یک vmlinux مطابق با build-id هسته در حال اجرا در مکان‌های معمول، از جمله جایی که بسته‌های debuginfo هسته آن را قرار می‌دهند، جستجو خواهد شد تا به جای آن اطلاعات DWARF بررسی شود. .PP برای پیشنهادهای بیشتر در مورد نحوه استفاده، بخش «مثال‌ها (EXAMPLES)» را ببینید. .PP همچنین هر آنچه را که به ورودی استاندارد آن داده شود، بر اساس نوع مشخص‌شده، به صورت خوانا چاپ می‌کند؛ بخش مثال‌ها را ببینید. .PP از گزینه --count برای تعیین تعداد رکوردهایی که باید چاپ خوانا شوند استفاده کنید. .SH "گزینه‌ها (OPTIONS)" برنامه pahole از گزینه‌های زیر پشتیبانی می‌کند. .TP .B \-C, \-\-class_name=CLASS_NAMES فقط نمایش همین کلاس‌ها. این مقدار می‌تواند یک لیست جداشده با کاما از نام‌های کلاس یا نشانی‌های URL فایل باشد (مانند: file://class_list.txt) .TP .B \-c, \-\-cacheline_size=SIZE تنظیم اندازه cacheline بر حسب SIZE بایت. .TP .B \-\-sort مرتب‌سازی خروجی بر اساس نام نوع؛ شاید در آینده امکان مرتب‌سازی بر اساس معیارهای دیگر نیز اضافه شود. .PP این گزینه بیشتر به این دلیل مورد نیاز است که خروجی چاپ خوانا از BTF و DWARF در هنگام استفاده از چندین thread برای بارگذاری داده‌های DWARF قابل مقایسه باشد، زیرا در آن شرایط ترتیبی که انواع در واحدهای کامپایل (CUs) پردازش می‌شوند قطعی نیست. .TP .B \-\-compile تولید کد قابل کامپایل، با تمام تعاریف برای همه نوع‌ها، مانند: .PP .nf $ pahole --compile > vmlinux.h .fi .PP یک هدر تولید می‌کند که می‌تواند در یک فایل منبع C گنجانده شده و ساخته شود. در مثال ارائه‌شده، در صورت وجود از اطلاعات BTF استفاده می‌کند، در غیر این صورت به دنبال یک فایل DWARF مطابق با build-id هسته در حال اجرا می‌گردد. .TP .B \-\-skip_emitting_atomic_typedefs در هنگام استفاده با گزینه‌هایی مانند --compile، عبارت 'typedef _Atomic int atomic_int' و موارد مشابه را درج نمی‌کند. اگر کامپایلر این‌ها را از قبل فراهم می‌کند از این گزینه استفاده کنید؛ از حدود سال ۲۰۲۲ با gcc 12.2.1 این موارد در DWARF کدگذاری نمی‌شوند، بنابراین برای تولید کد قابل کامپایل باید آن typedefها را برای انواع اتمیک استفاده‌شده در ساختارهای داده‌ای که از اطلاعات دیباگ استخراج می‌شوند صادر کنیم. .TP .B \-\-count=COUNT چاپ خوانای نخستین COUNT رکورد از ورودی. .TP .B \-\-skip=COUNT نادیده گرفتن COUNT رکورد از ورودی. .TP .B \-E, \-\-expand_types گسترش اعضای کلاس. برای یافتن اینکه یک آفست از ابتدای یک struct در کدام عضو از structهای درونی قرار دارد مفید است. .TP .B \-F, \-\-format_path امکان مشخص کردن فهرستی از قالب‌های دیباگ به ترتیب اولویت برای بررسی. در حال حاضر این شامل "btf"، "ctf" و "dwarf" است. مسیر قالب پیش‌فرض استفاده‌شده معادل "-F dwarf,btf,ctf" است. .TP .B \-\-hashbits=BITS امکان مشخص کردن تعداد بیت‌ها برای بارگذار قالب دیباگ. تاکنون تنها موردی که تحت تأثیر قرار گرفته "dwarf" است، پیش‌فرض کنونی آن ۱۵ و حداکثر آن در حال حاضر ۲۱ بیت است. می‌توانید آن را تغییر دهید تا ببینید آیا با تکامل هسته و نیاز به بارگذاری انواع و توابع بیشتر، کارایی بهبود می‌یابد یا خیر. .TP .B \-\-hex چاپ آفست‌ها و اندازه‌ها در مبنای شانزده (هگزادسیمال). .TP .B \-r, \-\-rel_offset نمایش آفست‌های نسبی اعضا در structهای درونی. .TP .B \-p, \-\-expand_pointers گسترش اعضای اشاره‌گر کلاس. .TP .B \-R, \-\-reorganize سازمان‌دهی مجدد struct، تنزل رتبه و ترکیب bitfieldها، و جابجایی اعضا برای حذف حفره‌های تراز (alignment holes) و padding. .TP .B \-S, \-\-show_reorg_steps نمایش چیدمان struct در هر مرحله از سازمان‌دهی مجدد. .TP .B \-i, \-\-contains=CLASS_NAME نمایش کلاس‌هایی که شامل CLASS_NAME هستند. .TP .B \-\-contains_enumerator=ENUMERATOR_NAME نمایش شمارشی (enumeration) که شامل ENUMERATOR_NAME است. .PP .nf $ pahole --contains_enumerator S_VERSION enum file_time_flags { S_ATIME = 1, S_MTIME = 2, S_CTIME = 4, S_VERSION = 8, } $ .fi .TP .B \-a, \-\-anon_include شامل کردن کلاس‌های ناشناس (anonymous). .TP .B \-A, \-\-nested_anon_include شامل کردن کلاس‌های ناشناس تو در تو (درون structهای دیگر). .TP .B \-B, \-\-bit_holes=NR_HOLES تنها نمایش structهایی که دست‌کم NR_HOLES حفره بیتی دارند. .TP .B \-d, \-\-recursive حالت بازگشتی، بر چندین فلگ دیگر نیز تأثیر می‌گذارد. .TP .B \-D, \-\-decl_exclude=PREFIX مستثنی کردن کلاس‌های اعلان‌شده در فایل‌های دارای پیشوند PREFIX. .TP .B \-f, \-\-find_pointers_to=CLASS_NAME یافتن اشاره‌گرها به CLASS_NAME. .TP .B \-H, \-\-holes=NR_HOLES تنها نمایش structهایی با دست‌کم NR_HOLES حفره. .TP .B \-\-padding=SIZE_PADDING تنها نمایش structهایی با SIZE_PADDING بایت padding در انتهای آن. .TP .B \-\-padding_ge=SIZE_PADDING تنها نمایش structهایی با دست‌کم SIZE_PADDING بایت padding در انتهای آن. .TP .B \-I, \-\-show_decl_info نمایش فایل و شماره خطی که تگ‌ها در آن تعریف شده‌اند، در صورتی که در اطلاعات دیباگ موجود باشد. .TP .B \-\-skip_encoding_btf_vars به طور پیش‌فرض، متغیرهای VAR فقط برای متغیرهای percpu کدگذاری می‌شوند. در صورت مشخص شدن، این گزینه از کدگذاری هرگونه متغیر VAR جلوگیری می‌کند. توجه داشته باشید که این گزینه می‌تواند توسط ویژگی "global_var" لغو شود. .TP .B \-\-skip_encoding_btf_decl_tag عدم کدگذاری تگ‌های اعلان (decl tags) در BTF. .TP .B \-\-skip_encoding_btf_enum64 عدم کدگذاری enum64 در BTF. .TP .B \-\-skip_encoding_btf_type_tag عدم کدگذاری تگ‌های نوع (type tags) در BTF. .TP .B \-\-skip_encoding_btf_inconsistent_proto عدم کدگذاری توابعی با چندین پیش‌نمونه (prototype) ناسازگار یا استفاده غیرمنتظره از رجیسترها برای پارامترهای آن‌ها، به طوری که رجیسترهای استفاده‌شده با قراردادهای فراخوانی همخوانی ندارند. .TP .B \-j, \-\-jobs=N اجرای N وظیفه به صورت موازی. در صورت مشخص نشدن آرگومان، به صورت پیش‌فرض تعداد پردازنده‌های آنلاین به علاوه ۱۰٪ در نظر گرفته می‌شود (مشابه سیستم ساخت 'ninja'). .TP .B \-J, \-\-btf_encode کدگذاری اطلاعات BTF از روی DWARF، که در فرآیند ساخت هسته لینوکس هنگام فعال بودن CONFIG_DEBUG_INFO_BTF=y استفاده می‌شود و در لینوکس ۵.۲ معرفی شد. برای پیاده‌سازی ویژگی‌هایی مانند BPF CO-RE (یک بار کامپایل - همه‌جا اجرا) به کار می‌رود. ببینید: \fIhttps://nakryiko.com/posts/bpf-portability-and-co-re\fR .TP .B \-\-btf_encode_detached=FILENAME همانند گزینه -J/--btf_encode، اما ذخیره اطلاعات خام BTF در یک فایل جداگانه. .TP .B \-\-btf_encode_force نادیده گرفتن نمادهایی که هنگام کدگذاری BTF نامعتبر تشخیص داده می‌شوند. .TP .B \-\-btf_base=PATH مسیر فایل پایه BTF، به عنوان مثال vmlinux در هنگام کدگذاری اطلاعات BTF ماژول هسته. این مسیر ممکن است در هنگام درخواست برای /sys/kernel/btf/MODULE استنتاج شود و به صورت خودکار روی "/sys/kernel/btf/vmlinux" تنظیم گردد. .TP .B \-\-btf_gen_floats اجازه تولید مدخل‌های BTF_KIND_FLOAT در سیستم‌هایی که اطلاعات DWARF فایل vmlinux دارای انواع ممیز شناور (float) است. .TP .B \-\-btf_gen_optimized تولید BTF برای توابع دارای پسوندهای مرتبط با بهینه‌سازی (مانند isra. و constprop.). .TP .B \-\-btf_gen_all اجازه استفاده از تمام قابلیت‌های BTF پشتیبانی‌شده توسط pahole. .TP .B \-\-btf_features=FEATURE_LIST کدگذاری BTF با استفاده از لیست ویژگی‌های مشخص‌شده، یا تعیین 'default' برای همه ویژگی‌های استاندارد پشتیبانی‌شده. این گزینه می‌تواند به عنوان جایگزینی برای استفاده از چندین گزینه مرتبط با BTF به کار رود، و 'default' نشان‌دهنده مجموعه استانداردی از ویژگی‌های BTF است که برای تولید BTF هسته استفاده می‌شوند، بنابراین به عنوان یک میانبر برای آزمایش آخرین مجموعه ویژگی‌های استاندارد مفید است. با این حال ساخت‌های هسته به جای 'default' ویژگی‌های خاص را مشخص خواهند کرد تا اطمینان حاصل شود که ویژگی‌های مورد نظر صرف‌نظر از نسخه pahole و مجموعه پیش‌فرض مربوطه فعال هستند. ویژگی‌های استاندارد پشتیبانی‌شده عبارتند از: .nf encode_force Ignore invalid symbols when encoding BTF; for example if a symbol has an invalid name, it will be ignored and BTF encoding will continue. var Encode percpu variables using BTF_KIND_VAR in BTF. float Encode floating-point types in BTF. decl_tag Encode declaration tags using BTF_KIND_DECL_TAG. type_tag Encode type tags using BTF_KIND_TYPE_TAG. enum64 Encode enum64 values with BTF_KIND_ENUM64. optimized_func Encode representations of optimized functions with suffixes like ".isra.0". consistent_func Avoid encoding inconsistent static functions. These occur when a parameter is optimized out in some CUs and not others, or when the same function name has inconsistent BTF descriptions in different CUs. .fi ویژگی‌های غیر استاندارد پشتیبانی‌شده (که در 'default' فعال نیستند): .nf attributes Allow generation of decl_tags and type_tags with kind_flag = 1. These tags can be used to encode arbitrary compiler attributes in BTF, but are backward incompatible. decl_tag_kfuncs Inject a BTF_KIND_DECL_TAG for each discovered kfunc. distilled_base For split BTF, generate a distilled version of the associated base BTF to support later relocation of split BTF with a possibly changed base, storing it in a .BTF.base ELF section. global_var Encode all global variables using BTF_KIND_VAR in BTF. .fi بنابراین به عنوان مثال، مشخص کردن \-\-btf_encode=var,enum64 منجر به کدگذاری BTF خواهد شد که (علاوه بر کدگذاری اطلاعات پایه BTF) شامل متغیرها و مقادیر enum64 نیز خواهد بود. اگر بخواهید یک ویژگی اضافی به مجموعه ویژگی‌های استاندارد بیفزایید، می‌توان از پیشوند '+' استفاده کرد، یعنی: \-\-btf_features=+reproducible_build تمام ویژگی‌های پیش‌فرض را به علاوه ویژگی اضافی 'reproducible_build' اضافه می‌کند. .TP .B \-\-btf_features_strict مشابه \-\-btf_features در بالا، اما در صورت برخورد با یک ویژگی ناشناخته، pahole خارج خواهد شد. .TP .B \-\-supported_btf_features نمایش مجموعه ویژگی‌های BTF پشتیبانی‌شده توسط گزینه \-\-btf_features و خروج. برای بررسی اینکه کدام ویژگی‌ها پشتیبانی می‌شوند مفید است، چرا که \-\-btf_features در صورت تعیین ویژگی ناشناخته خطایی صادر نمی‌کند. .TP .B \-\-running_kernel_vmlinux, جستجو برای یک vmlinux مطابق با build-id هسته در حال اجرا (از /sys/kernel/notes)، که ممکن است از یک سرور debuginfo دریافت شود. .TP .B \-l, \-\-show_first_biggest_size_base_type_member نمایش نخستین عضو نوع پایه‌ای (base_type) با بزرگ‌ترین اندازه. .TP .B \-m, \-\-nr_methods نمایش تعداد متدهای تمام کلاس‌ها، یعنی تعداد توابعی که آرگومان‌هایی از نوع اشاره‌گر به یک کلاس مشخص دارند. .PP برای به دست آوردن تعداد متدها برای یک کلاس خاص، لطفاً استفاده کنید: .PP .nf $ pahole --nr_methods | grep -w sock sock 1005 $ .fi .PP در مثال بالا از اطلاعات BTF موجود در /sys/kernel/btf/vmlinux استفاده شده است. .TP .B \-M, \-\-show_only_data_members تنها نمایش اعضایی که در چیدمان کلاس فضا اشغال می‌کنند. متدهای ++C نمایش داده نخواهند شد. .TP .B \-n, \-\-nr_members نمایش تعداد اعضا. .TP .B \-N, \-\-class_name_len نمایش اندازه کلاس‌ها. .TP .B \-O, \-\-dwarf_offset=OFFSET نمایش تگ با DWARF OFFSET مشخص. .TP .B \-P, \-\-packable تنها نمایش structهایی که دارای حفره‌هایی هستند که با سازمان‌دهی مجدد اعضا قابل بسته‌بندی و پر شدن هستند، به عنوان مثال هنگام استفاده از گزینه \fB\-\-reorganize\fR. .TP .B \-P, \-\-with_flexible_array تنها نمایش structهایی که دارای یک آرایه انعطاف‌پذیر (flexible array) هستند. .TP .B \-P, \-\-with_embedded_flexible_array تنها نمایش structهایی که دارای یک آرایه انعطاف‌پذیر توکار هستند، یعنی struct درونی که دارای آرایه‌های انعطاف‌پذیر است، یک آرایه انعطاف‌پذیر «در وسط». .TP .B \-q, \-\-quiet نمایش خروجی کوتاه‌تر و آرام‌تر. .TP .B \-s, \-\-sizes نمایش اندازه کلاس‌ها. .TP .B \-t, \-\-separator=SEP استفاده از SEP به عنوان جداکننده فیلدها. .TP .B \-T, \-\-nr_definitions نمایش اینکه struct چند بار تعریف شده است. .TP .B \-u, \-\-defined_in نمایش واحدهای کامپایلی (CUs) که CLASS_NAME (-C) در آن‌ها تعریف شده است. .TP .B \-\-flat_arrays تخت کردن آرایه‌ها، به طوری که array[10][2] تبدیل به array[20] شود. برای آزمودن و مقایسه خروجی‌های هر دو کدگذاری CTF/BTF و DWARF برای یک باینری یکسان مفید است. .TP .B \-\-suppress_aligned_attribute حذف نشانگرهای تراز اجباری، تا بتوان خروجی BTF یا CTF را (که فاقد این اطلاعات هستند) با خروجی DWARF نسخه ۵ یا بالاتر مقایسه کرد. .TP .B \-\-suppress_force_paddings حذف padding اجباری bitfield در انتهای structها، زیرا این امر به قابلیتی مانند DW_AT_alignment در DWARF نیاز دارد، تا بتوان خروجی BTF یا CTF را که فاقد این اطلاعات هستند مقایسه نمود. .TP .B \-\-suppress_packed حذف خروجی استنتاج __attribute__((__packed__))، تا بتوان خروجی BTF یا CTF را مقایسه کرد؛ الگوریتم استنتاج از مواردی مانند DW_AT_alignment استفاده می‌کند، بنابراین تا زمان بهبود آن برای استنتاج این مورد در BTF نیز، امکان غیرفعال کردن این خروجی فراهم شده است. .TP .B \-\-fixup_silly_bitfields تبدیل bitfieldهای نامناسب مانند "int foo:32" به شکل ساده "int foo". .TP .B \-V, \-\-verbose نمایش توضیحات با جزئیات کامل. .TP .B \-\-ptr_table_stats چاپ آمارهای مربوط به ساختارهای داده ptr_table، که برای نگهداری تمام انواع، تگ‌ها و ساختارهای داده توابع استفاده می‌شوند، به منظور تنظیم بهینگی توسعه چنین جداولی برای یک فایل vmlinux متداول در سال ۲۰۲۱. .TP .B \-w, \-\-word_size=WORD_SIZE تغییر اندازه کلمه معماری به WORD_SIZE. .TP .B \-x, \-\-exclude=PREFIX مستثنی کردن کلاس‌های دارای پیشوند PREFIX. .TP .B \-X, \-\-cu_exclude=PREFIX مستثنی کردن واحدهای کامپایل دارای پیشوند PREFIX. .TP .B \-\-lang=languages فقط پردازش واحدهای کامپایلی که از کد منبع نوشته‌شده به زبان‌های مشخص ایجاد شده‌اند. .PP زبان‌های پشتیبانی‌شده: .PP .nf ada83, ada95, asm, bliss, c, c89, c99, c11, c++, c++03, c++11, c++14, cobol74, cobol85, d, dylan, fortran77, fortran90, fortran95, fortran03, fortran08, go, haskell, java, julia, modula2, modula3, objc, objc++, ocaml, opencl, pascal83, pli, python, renderscript, rust, swift, upc .fi .PP برای نمونه، هسته لینوکس در حدود سال ۲۰۲۲ با 'c89' نوشته شده است، از آن در فیلترها استفاده کنید. .TP .B \-\-lang_exclude=languages عدم پردازش واحدهای کامپایلی که از کد منبع نوشته‌شده به زبان‌های مشخص ایجاد شده‌اند. .PP به عنوان مثال، برای نادیده گرفتن واحدهای کامپایل نوشته‌شده به زبان Rust، استفاده کنید از: .PP .nf pahole -j --btf_encode --lang_exclude rust .fi .PP این کار همچنین با تنظیم متغیر محیطی PAHOLE_LANG_EXCLUDE با همان لیست زبان‌ها قابل انجام است؛ برای نمونه، دستور زیر معادل عبارت بالا است: .PP .nf export PAHOLE_LANG_EXCLUDE=rust pahole -j --btf_encode .fi .PP به این معنا که در هر دو حالت، واحدهای کامپایل 'rust' نادیده گرفته خواهند شد. .PP این قابلیت برای اسکریپت‌ها مناسب است چرا که روشی برای درخواست این استثناء برای pahole و pfunct بدون نیاز به استفاده از lang_exclude-- در تمام فراخوانی‌ها فراهم می‌سازد، فقط کافیست آن متغیر محیطی تنظیم شود. .TP .B \-y, \-\-prefix_filter=PREFIX شامل کردن کلاس‌های دارای پیشوند PREFIX. .TP .B \-z, \-\-hole_size_ge=HOLE_SIZE تنها نمایش structهایی با دست‌کم یک حفره بزرگ‌تر یا مساوی با HOLE_SIZE. .TP .B \-\-structs تنها نمایش structها؛ تمام فیلترهای دیگر نیز اعمال می‌شوند، یعنی برای نمایش فقط اندازه‌های همه structها می‌توانید --structs را با --sizes ترکیب کنید، و غیره. .TP .B \-\-packed تنها نمایش structهای فشرده (packed)؛ تمام فیلترهای دیگر نیز اعمال می‌شوند، یعنی برای نمایش فقط اندازه‌های تمام structهای packed می‌توانید --packed را با --sizes ترکیب کنید، و غیره. .TP .B \-\-unions تنها نمایش unionها؛ تمام فیلترهای دیگر اعمال می‌شوند، یعنی برای نمایش فقط اندازه‌های همه unionها می‌توانید --union را با --sizes ترکیب کنید، و غیره. .TP .B \-\-version نمایش نسخه سنتی به صورت رشته‌ای، مانند: "v1.18". .TP .B \-\-numeric_version نمایش نسخه به صورت صرفاً عددی، مناسب برای استفاده در Makefileها و اسکریپت‌هایی که می‌خواهند بدانند آیا نسخه نصب‌شده قابلیت خاصی دارد یا خیر، مانند: 118 به جای "v1.18". .TP .B \-\-kabi_prefix=STRING هنگامی که پیشوند رشته STRING باشد، با رشته به عنوان STRING رفتار شود. .SH "نکات (NOTES)" برای فعال‌سازی تولید اطلاعات دیباگ در فرآیند ساخت هسته لینوکس، CONFIG_DEBUG_INFO را انتخاب کنید. این کار می‌تواند با استفاده از make menuconfig از طریق این مسیر انجام شود: "Kernel Hacking" -> "Compile-time checks and compiler options" -> "Compile the kernel with debug info". همچنین توصیه می‌شود CONFIG_DEBUG_INFO_BTF را با طی کردن مسیر menuconfig ذکرشده و سپس انتخاب "Generate BTF typeinfo" فعال کنید. اکثر توزیع‌های مدرن با پشتیبانی eBPF باید این گزینه را در تمامی هسته‌های خود فعال داشته باشند، که استفاده از pahole را تا حد زیادی تسهیل می‌کند. .PP بسیاری از توزیع‌ها همچنین بسته‌های debuginfo را ارائه می‌دهند، بنابراین فقط کافی است آن را در پیکربندی مخزن مدیر بسته خود فعال کنید و kernel-debuginfo یا هر برنامه فضای کاربری دیگری که به زبانی نوشته شده که کامپایلر برای آن اطلاعات دیباگ تولید می‌کند (مانند C یا ++C) را نصب نمایید. .SH "مثال‌ها (EXAMPLES)" تمام مثال‌های این بخش یا از /sys/kernel/btf/vmlinux (در صورت وجود) استفاده می‌کنند، یا با استفاده از اطلاعات build-id موجود در /sys/kernel/notes به دنبال فایل vmlinux مطابق با هسته در حال اجرا می‌گردند تا از تطابق آن اطمینان حاصل شود. .P نمایش یک نوع داده: .PP .nf $ pahole -C __u64 typedef long long unsigned int __u64; $ .fi .P اگر تنها آرگومان یک نام نوع باشد نیز کار می‌کند: .PP .nf $ pahole raw_spinlock_t typedef struct raw_spinlock raw_spinlock_t; $ .fi .P می‌توان چندین نوع داده را با کاما جدا کرده و ارسال نمود: .PP .nf $ pahole raw_spinlock_t,raw_spinlock struct raw_spinlock { arch_spinlock_t raw_lock; /* 0 4 */ /* size: 4, cachelines: 1, members: 1 */ /* last cacheline: 4 bytes */ }; typedef struct raw_spinlock raw_spinlock_t; $ .fi .P انواع داده می‌توانند گسترش یابند: .PP .nf $ pahole -E raw_spinlock struct raw_spinlock { /* typedef arch_spinlock_t */ struct qspinlock { union { /* typedef atomic_t */ struct { int counter; /* 0 4 */ } val; /* 0 4 */ struct { /* typedef u8 -> __u8 */ unsigned char locked; /* 0 1 */ /* typedef u8 -> __u8 */ unsigned char pending; /* 1 1 */ }; /* 0 2 */ struct { /* typedef u16 -> __u16 */ short unsigned int locked_pending; /* 0 2 */ /* typedef u16 -> __u16 */ short unsigned int tail; /* 2 2 */ }; /* 0 4 */ }; /* 0 4 */ } raw_lock; /* 0 4 */ /* size: 4, cachelines: 1, members: 1 */ /* last cacheline: 4 bytes */ }; $ .fi .P هنگام رمزگشایی اشکالات OOPS هسته، ممکن است بخواهید آفست‌ها و اندازه‌ها را در مبنای ۱۶ (هگزادسیمال) مشاهده کنید: .PP .nf $ pahole --hex thread_struct struct thread_struct { struct desc_struct tls_array[3]; /* 0 0x18 */ long unsigned int sp; /* 0x18 0x8 */ short unsigned int es; /* 0x20 0x2 */ short unsigned int ds; /* 0x22 0x2 */ short unsigned int fsindex; /* 0x24 0x2 */ short unsigned int gsindex; /* 0x26 0x2 */ long unsigned int fsbase; /* 0x28 0x8 */ long unsigned int gsbase; /* 0x30 0x8 */ struct perf_event * ptrace_bps[4]; /* 0x38 0x20 */ /* --- cacheline 1 boundary (64 bytes) was 24 bytes ago --- */ long unsigned int debugreg6; /* 0x58 0x8 */ long unsigned int ptrace_dr7; /* 0x60 0x8 */ long unsigned int cr2; /* 0x68 0x8 */ long unsigned int trap_nr; /* 0x70 0x8 */ long unsigned int error_code; /* 0x78 0x8 */ /* --- cacheline 2 boundary (128 bytes) --- */ struct io_bitmap * io_bitmap; /* 0x80 0x8 */ long unsigned int iopl_emul; /* 0x88 0x8 */ mm_segment_t addr_limit; /* 0x90 0x8 */ unsigned int sig_on_uaccess_err:1; /* 0x98: 0 0x4 */ unsigned int uaccess_err:1; /* 0x98:0x1 0x4 */ /* XXX 30 bits hole, try to pack */ /* XXX 36 bytes hole, try to pack */ /* --- cacheline 3 boundary (192 bytes) --- */ struct fpu fpu; /* 0xc0 0x1040 */ /* size: 4352, cachelines: 68, members: 20 */ /* sum members: 4312, holes: 1, sum holes: 36 */ /* sum bitfield members: 2 bits, bit holes: 1, sum bit holes: 30 bits */ }; $ .fi .P بسیار خب، می‌دانیم آفستی که باعث خطا شده در یک 'struct thread_struct' قرار دارد و آفست 0x178 است، بنابراین باید در struct با نام 'fpu' باشد... مشکلی نیست، 'struct thread_struct' را گسترش داده و با \fBgrep\fR ترکیب می‌کنیم: .PP .nf $ pahole --hex -E thread_struct | egrep '(0x178|struct fpu)' -B4 -A4 /* XXX 30 bits hole, try to pack */ /* XXX 36 bytes hole, try to pack */ /* --- cacheline 3 boundary (192 bytes) --- */ struct fpu { unsigned int last_cpu; /* 0xc0 0x4 */ /* XXX 4 bytes hole, try to pack */ -- /* typedef u8 -> __u8 */ unsigned char alimit; /* 0x171 0x1 */ /* XXX 6 bytes hole, try to pack */ struct math_emu_info * info; /* \fI0x178\fR 0x8 */ /* --- cacheline 6 boundary (384 bytes) --- */ /* typedef u32 -> __u32 */ unsigned int entry_eip; /* 0x180 0x4 */ } soft; /* 0x100 0x88 */ struct xregs_state { $ .fi .P می‌خواهید بدانید 'struct thread_struct' در کجای کدهای منبع هسته تعریف شده است؟ .PP .nf $ pahole -I thread_struct | head -2 /* Used at: /sys/kernel/btf/vmlinux */ /* <0> (null):0 */ $ .fi .P در BTF موجود نیست، بنابراین از DWARF استفاده می‌کنیم که کمی بیشتر طول می‌کشد و فرض می‌شود فایل vmlinux مطابق را پیدا کند: .PP .nf $ pahole -Fdwarf -I thread_struct | head -2 /* Used at: /home/acme/git/linux/arch/x86/kernel/head64.c */ /* <3333> /home/acme/git/linux/arch/x86/include/asm/processor.h:485 */ $ .fi .P برای یافتن بزرگ‌ترین ساختارهای داده در هسته لینوکس: .PP .nf $ pahole -s | sort -k2 -nr | head -5 cmp_data 290904 1 dec_datas 274520 1 cpu_entry_area 217088 0 pglist_data 172928 4 saved_cmdlines_buffer 131104 1 $ .fi .P ستون دوم اندازه بر حسب بایت و ستون سوم تعداد حفره‌های تراز در آن ساختار است. .P نمایش ساختارهای داده‌ای که دارای raw spinlock هستند و به سازوکار RCU ارتباط دارند: .PP .nf $ pahole --contains raw_spinlock_t --prefix rcu rcu_node rcu_data rcu_state $ .fi .P برای دیدن آن در متن اصلی، آن را با \fIgrep\fR ترکیب کنید: .PP .nf $ pahole rcu_state | grep raw_spinlock_t -B1 -A5 /* --- cacheline 52 boundary (3328 bytes) --- */ raw_spinlock_t ofl_lock; /* 3328 4 */ /* size: 3392, cachelines: 53, members: 35 */ /* sum members: 3250, holes: 7, sum holes: 82 */ /* padding: 60 */ }; $ .fi .SH "چاپ خوانا (PRETTY PRINTING)" .P ابزار pahole همچنین می‌تواند از انواع ساختارهای داده برای چاپ خوانای داده‌های خام مشخص‌شده از طریق --prettify استفاده کند. برای خواندن داده‌های خام از ورودی استاندارد، کافی است از '--prettify -' استفاده کنید. .P همچنین می‌تواند داده‌های خام را از stdin با توجه به نوع مشخص‌شده به صورت خوانا چاپ کند: .PP .nf $ pahole -C modversion_info drivers/scsi/sg.ko struct modversion_info { long unsigned int crc; /* 0 8 */ char name[56]; /* 8 56 */ /* size: 64, cachelines: 1, members: 2 */ }; $ $ objcopy -O binary --only-section=__versions drivers/scsi/sg.ko versions $ $ ls -la versions -rw-rw-r--. 1 acme acme 7616 Jun 25 11:33 versions $ $ pahole --count 3 -C modversion_info drivers/scsi/sg.ko --prettify versions { .crc = 0x8dabd84, .name = "module_layout", }, { .crc = 0x45e4617b, .name = "no_llseek", }, { .crc = 0xa23fae8c, .name = "param_ops_int", }, $ $ pahole --skip 1 --count 2 -C modversion_info drivers/scsi/sg.ko --prettify - < versions { .crc = 0x45e4617b, .name = "no_llseek", }, { .crc = 0xa23fae8c, .name = "param_ops_int", }, $ این معادل دستور زیر است: $ pahole --seek_bytes 64 --count 1 -C modversion_info drivers/scsi/sg.ko --prettify versions { .crc = 0x45e4617b, .name = "no_llseek", }, $ .fi .P .TP .B \-C, \-\-class_name=CLASS_NAME چاپ خوانا مطابق با این کلاس. می‌توان آرگومان‌هایی را به آن ارسال کرد تا نحوه انجام چاپ خوانا را تحت تأثیر قرار دهند، برای نمونه: .PP .nf -C 'perf_event_header(sizeof,type,type_enum=perf_event_type,filter=type==PERF_RECORD_EXIT)' .fi این دستور 'struct perf_event_header' را به عنوان نوع مورد استفاده برای چاپ خوانای رکوردها انتخاب می‌کند، مشخص می‌کند که فیلد 'size' در آن struct باید برای تعیین اندازه رکورد (رکوردهای با اندازه متغیر) استفاده شود، 'enum perf_event_type' باید برای چاپ خوانای مقدار عددی در perf_event_header->type به کار رود و علاوه بر این برای جستجوی ابتکاری structهایی با نام یکسان (با حروف کوچک) با مدخل enum که از فیلد type تبدیل شده است استفاده شود و به جای نوع پایه 'perf_event_header' برای چاپ خوانا به کار رود. بخش «مثال‌های چاپ خوانا (PRETTY PRINTING EXAMPLES)» را در زیر ببینید. .P علاوه بر این، بخش 'filter=' را می‌توان استفاده کرد که تاکنون فقط با عملگر '==' برای فیلتر کردن بر اساس فیلد 'type' و تبدیل رشته 'PERF_RECORD_EXIT' به یک عدد مطابق با type_enum عمل می‌کند. .P آرگومان 'sizeof' به طور پیش‌فرض به نام عضو 'size' تنظیم می‌شود؛ اگر نام متفاوت باشد، می‌توان از فرم 'sizeof=sz' استفاده کرد. همین موضوع برای فیلد 'type=other_member_name' نیز برقرار است که به طور پیش‌فرض 'type' در نظر گرفته می‌شود. .SH "مثال‌های چاپ خوانا (PRETTY PRINTING EXAMPLES)" .P بررسی هدر ELF برای یک فایل vmlinux با استفاده از BTF؛ ابتدا نوع هدر ELF را پیدا می‌کنیم: .PP .nf $ pahole --sizes | grep -i elf | grep -i _h elf64_hdr 64 0 elf32_hdr 52 0 $ .fi .P اکنون می‌توانیم از این برای نمایش نخستین رکورد از آفست صفر استفاده کنیم: .PP .nf $ pahole -C elf64_hdr --count 1 --prettify /lib/modules/5.8.0-rc3+/build/vmlinux { .e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .e_type = 2, .e_machine = 62, .e_version = 1, .e_entry = 16777216, .e_phoff = 64, .e_shoff = 775923840, .e_flags = 0, .e_ehsize = 64, .e_phentsize = 56, .e_phnum = 5, .e_shentsize = 64, .e_shnum = 80, .e_shstrndx = 79, }, $ .fi .P این معادل دستور زیر است: .PP .nf $ pahole --header elf64_hdr --prettify /lib/modules/5.8.0-rc3+/build/vmlinux .fi .P گزینه --header همچنین امکان ارجاع در سایر گزینه‌های خط فرمان به فیلدهای موجود در هدر را فراهم می‌کند. این قابلیت زمانی مفید است که بخواهید چندین رکورد را در یک فایل نمایش دهید و بازه‌ای که آن فیلدها در آن قرار دارند در فیلدهای هدر مشخص شده باشد، مانند فایل‌های perf.data: .PP .nf $ pahole --hex ~/bin/perf --header perf_file_header --prettify perf.data { .magic = 0x32454c4946524550, .size = 0x68, .attr_size = 0x88, .attrs = { .offset = 0xa8, .size = 0x88, }, .data = { .offset = 0x130, .size = 0x588, }, .event_types = { .offset = 0, .size = 0, }, .adds_features = { 0x16717ffc, 0, 0, 0 }, }, $ .fi .P بنابراین برای نمایش رکوردهای cgroups در بخش perf_file_header.data می‌توانیم از دستور زیر استفاده کنیم: .PP .nf $ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' --prettify perf.data { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 40, }, .id = 1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 48, }, .id = 1553, .path = "/system.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 48, }, .id = 8, .path = "/machine.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 128, }, .id = 7828, .path = "/machine.slice/libpod-42be8e8d4eb9d22405845005f0d04ea398548dccc934a150fbaa3c1f1f9492c2.scope", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 88, }, .id = 13, .path = "/machine.slice/machine-qemu\\x2d1\\x2drhel6.sandy.scope", }, $ .fi .P برای حالت متداول که هدر دارای عضوی با فیلدهای 'offset' و 'size' باشد، می‌توان از این شکل فشرده‌تر استفاده کرد: .PP .nf $ pahole ~/bin/perf --header=perf_file_header --range=data -C 'perf_event_header(sizeof,type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' --prettify perf.data .fi .P این دستور از ~/bin/perf برای دریافت تعاریف نوع استفاده می‌کند، 'struct perf_file_header' را به عنوان هدر تعریف می‌کند، سپس به اندازه '$header.data.offset' بایت از ابتدای فایل به جلو می‌رود و به اندازه '$header.data.size' بایت از چنین رکوردهایی را در نظر می‌گیرد. عبارت فیلتر می‌تواند یک پیشوند مشترک را حذف کند؛ در این مورد می‌توان آن را به طور معادل هم به صورت 'filter=type==CGROUP' نوشت یا حتی بخش '=filter' را نیز حذف کرد و به صورت فشرده 'type==CGROUP' درآورد: .P اگر نگاه کنیم به: .PP .nf $ pahole ~/bin/perf -C perf_event_header struct perf_event_header { __u32 type; /* 0 4 */ __u16 misc; /* 4 2 */ __u16 size; /* 6 2 */ /* size: 8, cachelines: 1, members: 3 */ /* last cacheline: 8 bytes */ }; $ .fi .P و همچنین: .PP .nf $ pahole ~/bin/perf -C perf_event_type enum perf_event_type { PERF_RECORD_MMAP = 1, PERF_RECORD_LOST = 2, PERF_RECORD_COMM = 3, PERF_RECORD_EXIT = 4, PERF_RECORD_THROTTLE = 5, PERF_RECORD_UNTHROTTLE = 6, PERF_RECORD_FORK = 7, PERF_RECORD_READ = 8, PERF_RECORD_SAMPLE = 9, PERF_RECORD_MMAP2 = 10, PERF_RECORD_AUX = 11, PERF_RECORD_ITRACE_START = 12, PERF_RECORD_LOST_SAMPLES = 13, PERF_RECORD_SWITCH = 14, PERF_RECORD_SWITCH_CPU_WIDE = 15, PERF_RECORD_NAMESPACES = 16, PERF_RECORD_KSYMBOL = 17, PERF_RECORD_BPF_EVENT = 18, PERF_RECORD_CGROUP = 19, PERF_RECORD_TEXT_POKE = 20, PERF_RECORD_MAX = 21, }; $ .fi .P و علاوه بر این: .PP .nf $ pahole ~/bin/perf -C perf_record_cgroup struct perf_record_cgroup { struct perf_event_header header; /* 0 8 */ __u64 id; /* 8 8 */ char path[4096]; /* 16 4096 */ /* size: 4112, cachelines: 65, members: 3 */ /* last cacheline: 16 bytes */ }; $ .fi .P سپس می‌توانیم ببینیم چگونه perf_event_header.type می‌تواند از یک __u32 به یک رشته (PERF_RECORD_CGROUP) تبدیل شود. اگر آن عبارت type_enum=perf_event_type را حذف کنیم، تبدیل 'struct perf_event_header' به ساختار توصیفی‌تر 'struct perf_record_cgroup' را از دست خواهیم داد و همچنین فیلد header.type نیز زیبانویسی نخواهد شد: .PP .nf $ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,filter=type==19)' --prettify perf.data { .type = 19, .misc = 0, .size = 40, }, { .type = 19, .misc = 0, .size = 48, }, { .type = 19, .misc = 0, .size = 48, }, { .type = 19, .misc = 0, .size = 128, }, { .type = 19, .misc = 0, .size = 88, }, $ .fi .P برخی از رکوردها در 'type_enum=perf_event_type' پیدا نمی‌شوند، بنابراین برخی رکوردها به نوعی که محتوای آن‌ها را به طور کامل نشان دهد تبدیل نمی‌شوند. برای perf می‌دانیم که آن‌ها در شمارش دیگری به نام 'enum perf_user_event_type' قرار دارند؛ بنابراین برای این موارد می‌توانیم یک «enum مجازی» بسازیم، یعنی مجموع دو enum، و سپس تمام آن ورودی‌ها رمزگشایی و به درستی تطبیق داده شوند؛ ابتدا چند رکورد نخست فقط با 'enum perf_event_type': .PP .nf $ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type)' --count 4 --prettify perf.data { .type = 79, .misc = 0, .size = 32, }, { .type = 73, .misc = 0, .size = 40, }, { .type = 74, .misc = 0, .size = 32, }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 40, }, .id = 1, .path = "/", }, $ .fi .P اکنون با هر دو شمارش، یعنی با 'type_enum=perf_event_type+perf_user_event_type': .PP .nf $ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type+perf_user_event_type)' --count 5 --prettify perf.data { .header = { .type = PERF_RECORD_TIME_CONV, .misc = 0, .size = 32, }, .time_shift = 31, .time_mult = 1016803377, .time_zero = 435759009518382, }, { .header = { .type = PERF_RECORD_THREAD_MAP, .misc = 0, .size = 40, }, .nr = 1, .entries = 0x50 0x7e 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00, }, { .header = { .type = PERF_RECORD_CPU_MAP, .misc = 0, .size = 32, }, .data = { .type = 1, .data = "", }, }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 40, }, .id = 1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 48, }, .id = 1553, .path = "/system.slice", }, $ .fi .P امکان ارسال چندین نوع وجود دارد؛ تنها باید مطمئن شد که آن‌ها در فایل به ترتیب ظاهر می‌شوند، یعنی برای مثال perf.data، به dump ساختار perf_file_header در بالا نگاه کنید؛ می‌توان ساختارهای perf_file_attr را در محدوده attrs هدر، و سپس perf_event_header را در محدوده data با دستور زیر چاپ کرد: .PP .nf pahole ~/bin/perf --header=perf_file_header \ -C 'perf_file_attr(range=attrs),perf_event_header(range=data,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' --prettify perf.data .fi .SH "همچنین ببینید (SEE ALSO)" \fIeu-readelf\fR(1), \fIreadelf\fR(1), \fIobjdump\fR(1). .P \fIhttps://www.kernel.org/doc/ols/2007/ols2007v2-pages-35-44.pdf\fR. .SH "نویسنده (AUTHOR)" برنامه \fBpahole\fR توسط Arnaldo Carvalho de Melo نوشته شده و نگهداری می‌شود. .P با تشکر از Andrii Nakryiko و Martin KaFai Lau برای ارائه کدگذار BTF و بهبود پایگاه‌کد، همراه با اطمینان از اینکه کدگذار BTF مطابق نیاز برای کدگذاری بخش .BTF هسته لینوکس از اطلاعات DWARF تولیدشده توسط gcc کار می‌کند. به همین منظور Andrii یک ابزار حذف تکرار BTF (deduplicator) در libbpf نوشت که توسط \fBpahole\fR استفاده می‌شود. .P همچنین با تشکر از Conectiva، Mandriva و Red Hat برای فراهم آوردن فرصت کار بر روی این ابزارها. .P لطفاً گزارش‌های اشکال را به ارسال کنید. .P نیازی به عضویت در فهرست پستی نیست.