ltrace.conf(5) ltrace configuration file ltrace.conf(5)

ltrace.conf - پرونده پیکربندی برای ltrace(1).

این صفحه راهنما ltrace.conf را توصیف می‌کند؛ پرونده‌ای که پیش‌نمونه‌های توابع موجود در باینری‌ها را برای استفاده توسط ltrace(1) شرح می‌دهد. دستور ltrace برای نمایش آرگومان‌های فراخوانی تابع به این اطلاعات نیاز دارد.

هر خط از یک پرونده پیکربندی حداکثر یک مورد را توصیف می‌کند. خطوطی که کاملاً از نویسه‌های فاصله خالی تشکیل شده‌اند نادیده گرفته می‌شوند، همان‌طور که خطوطی که با نویسه نقطه-ویرگول یا هش آغاز می‌شوند (خطوط توضیح) نیز نادیده گرفته می‌شوند. موارد توصیف‌شده می‌توانند پیش‌نمونه‌های توابع، یا تعاریف نام‌های مستعار انواع داده باشند.

یک پیش‌نمونه، نوع مقدار بازگشتی و انواع پارامترهای یک تابع را مشخص می‌کند. نحو ساختار به صورت زیر است:

[function] LENS NAME ([LENS{,LENS}]);

NAME نام نماد (symbol) است. در حالت ابتدایی، LENS به سادگی یک نوع داده است. هم لنزها و هم انواع داده در ادامه توصیف شده‌اند. کلیدواژه function در صورت وجود، تأثیری ندارد. می‌توان از آن برای اجبار تفسیر یک خط به عنوان پیش‌نمونه تابع استفاده کرد، هنگامی که نوع بازگشتی کلیدواژه‌ای باشد که ممکن است نوع متفاوتی از خط را شروع کند (مانند import).

برای مثال، یک پیش‌نمونه تابع ساده ممکن است شبیه این باشد:

int kill(int,int);

علیرغم شباهت ظاهری به زبان C، زبان ltrace.conf در واقع زبان اختصاصی خود است که فقط تا حدی از C الهام گرفته است.

دستور ltrace طیف وسیعی از انواع اولیه را متوجه می‌شود. این‌ها بر اساس قواعد مرسوم C بومی در یک معماری مفروض تفسیر می‌شوند. به عنوان مثال، ulong در یک ماشین ۳۲ بیتی GNU/Linux به عنوان عدد صحیح بدون علامت ۴ بایتی، اما در یک ماشین ۶۴ بیتی GNU/Linux به عنوان عدد صحیح بدون علامت ۸ بایتی تفسیر می‌شود.

نشان می‌دهد که یک تابع چیزی بازنمی‌گرداند. همچنین می‌تواند برای ایجاد یک اشاره‌گر عمومی استفاده شود؛ یعنی عددی با اندازه اشاره‌گر که در قالب هگزادسیمال قالب‌بندی شده است.
کمیت ۸ بیتی که به عنوان یک نویسه ارائه می‌شود.
نشان‌دهنده عدد صحیح کوتاه بدون علامت یا علامت‌دار است.
نشان‌دهنده عدد صحیح بدون علامت یا علامت‌دار است.
نشان‌دهنده عدد صحیح بلند بدون علامت یا علامت‌دار است.
نشان‌دهنده عدد ممیز شناور با دقت یگانه است.
نشان‌دهنده عدد ممیز شناور با دقت مضاعف است.

علاوه بر انواع اولیه، انواع مرکب زیر نیز ممکن هستند:

یک ساختار با انواع مشخص‌شده به عنوان فیلدها را توصیف می‌کند، مانند struct(int,int,float).

ترازسازی (Alignment) بر اساس مرسوم در معماری محاسبه می‌شود. ترازسازی سفارشی (مانند packed structs) و فیلدهای بیتی پشتیبانی نمی‌شوند. همچنین برای معماری‌هایی که بین ساختارها و کلاس‌های غیر-POD در ++C تفاوت وجود دارد، امکان تمایز بین آن‌ها وجود ندارد.

آرایه‌ای با طول EXPR را توصیف می‌کند که از انواع توصیف‌شده توسط LENS تشکیل شده است، مانند array(int, 6).

توجه داشته باشید که در C، آرایه‌ها در نقش آرگومان تابع به اشاره‌گرها تبدیل (decay) می‌شوند. ltrace در حال حاضر این مورد را به طور خودکار مدیریت می‌کند، اما برای صحت رسمی کامل، هر چنین آرگومانی باید به عنوان اشاره‌گر به آرایه‌ها توصیف شود.

اشاره‌گری به یک نوع داده داده‌شده را توصیف می‌کند، مانند char* یا int***. توجه داشته باشید که مثال اول در واقع یک اشاره‌گر به یک نویسه را توصیف می‌کند، نه یک رشته. برای لنز string که برای این موارد کاربرد دارد، به ادامه مراجعه کنید.

لنزها نحوه توصیف انواع داده را تغییر می‌دهند. در ساده‌ترین حالت، یک لنز مستقیماً یک نوع داده است. در غیر این صورت یک نوع داده توسط لنز تزیین می‌شود. برنامه ltrace لنزهای زیر را متوجه می‌شود:

آرگومان، که باید یک نوع عدد صحیح باشد، در مبنای ۲ قالب‌بندی می‌شود.

oct(TYPE) آرگومان، که باید یک نوع عدد صحیح باشد، در مبنای ۸ قالب‌بندی می‌شود.

آرگومان، که باید یک نوع عدد صحیح یا ممیز شناور باشد، در مبنای ۱۶ قالب‌بندی می‌شود. آرگومان‌های ممیز شناور به double تبدیل شده و سپس با استفاده از اصلاح‌کننده %a در fprintf نمایش داده می‌شوند.
آرگومان در فهرست آرگومان‌ها نمایش داده نمی‌شود.
آرگومان‌های با مقدار صفر به صورت "false" و سایر مقادیر به صورت "true" نمایش داده می‌شوند.
آرگومان زیرین به عنوان یک بردار بیتی تفسیر شده و خلاصه‌ای از بیت‌های تنظیم‌شده در بردار نمایش داده می‌شود. به عنوان مثال اگر بیت‌های ۳، ۴، ۵ و ۷ از بردار بیتی تنظیم شده باشند، ltrace مقدار <3-5,7> را نشان می‌دهد. بردار بیتی خالی به صورت <> نمایش داده می‌شود. اگر تعداد بیت‌های تنظیم‌شده بیشتر از بیت‌های تنظیم‌نشده باشد، معکوس آن نمایش داده می‌شود: به عنوان مثال ~<0> زمانی که عدد 0xfffffffe نمایش داده می‌شود. بنابراین مجموعه کامل به صورت ~<> نمایش داده می‌شود.

اگر نوع زیرین از نوع عدد صحیح باشد، بیت‌ها به ترتیب طبیعی big-endian با بیت کم‌ارزش (LSB) به عنوان بیت ۰ نمایش داده می‌شوند. برای مثال bitvec(ushort) با مقدار 0x0102 صرف‌نظر از ترتیب بایت‌های زیرین، به صورت <1,8> نمایش داده می‌شود.

برای سایر انواع داده (به ویژه ساختارها و آرایه‌ها)، داده‌های زیرین بایت به بایت تفسیر می‌شوند. بیت ۰ از بایت اول شماره ۰ دارد، بیت ۰ از بایت دوم شماره ۸ و غیره. بنابراین bitvec(struct(int)) به ترتیب بایت‌ها حساس است و بایت‌های تشکیل‌دهنده عدد صحیح را به ترتیب حافظه آن‌ها نشان می‌دهد. اشاره‌گرها ابتدا ارجاع‌زدایی می‌شوند، بنابراین bitvec(array(char, 32)*) در واقع یک اشاره‌گر به یک بردار بیتی ۲۵۶ بیتی است.

string(TYPE)
string[EXPR]
string

فرم اول آرگومان استاندارد است، و دو فرم دیگر شکر نحوی هستند. در فرم استاندارد، آرگومان تابع به صورت رشته قالب‌بندی می‌شود. TYPE می‌تواند هر یک از فرم‌های زیر را داشته باشد: X*، یا array(X,EXPR)، یا array(X,EXPR)*. در اینجا X برای رشته‌های عادی char، یا برای رشته‌های نویسه-عریض یک نوع عدد صحیح است.

اگر یک آرایه داده شود، طول آن معمولاً یک عبارت zero خواهد بود (اما اجباری نیست). استفاده از آرگومانی که یک آرایه ساده است (یعنی نه یک اشاره‌گر به آرایه) به عنوان مثال در ساختارهای C، در مواردی مانند struct(string(array(char, 6))) که نوع معادل struct {char s[6];} در C را توصیف می‌کند، منطقی است.

از آنجا که رشته‌های ساده شبیه C بسیار رایج هستند، دو شکل خلاصه وجود دارد. اولین شکل خلاصه (با قلاب) همان معنی string(array(char, EXPR)*) را دارد. عبارت ساده string بدون هیچ آرگومانی معادل string[zero] در نظر گرفته می‌شود.

توجه داشته باشید که char* به خودی خود یک اشاره‌گر به یک char را توصیف می‌کند. برنامه ltrace اشاره‌گر را ارجاع‌زدایی کرده و تک نویسه‌ای که به آن اشاره می‌کند را خوانده و نمایش می‌دهد.

enum(NAME[=VALUE]{,NAME[=VALUE]})
enum[TYPE](NAME[=VALUE]{,NAME[=VALUE]})

این یک لنز شمارشی را توصیف می‌کند. اگر یک آرگومان هر یک از مقادیر مشخص‌شده را داشته باشد، به جای آن به عنوان NAME متناظر نشان داده می‌شود. اگر یک VALUE حذف شود، مقدار متوالی بعدی پس از VALUE قبلی در نظر گرفته می‌شود. اگر اولین VALUE حذف شود، به طور پیش‌فرض 0 است.

در صورت ارائه، TYPE نوع داده زیرین است. بنابراین می‌توان شمارش‌هایی روی short یا long تعریف کرد—آرگومان‌هایی که در C انواع ساده و غیرشمارشی هستند، اما مقادیر آن‌ها را می‌توان به طور معناداری به عنوان شمارش توصیف کرد. در صورت حذف، TYPE به صورت int در نظر گرفته می‌شود.

یک خط در پرونده پیکربندی می‌تواند به جای توصیف یک پیش‌نمونه، یک نام مستعار برای نوع داده ایجاد کند. به جای نوشتن همان enum یا struct در جاهای متعدد (و احتمالاً به‌روزرسانی آن در زمان تغییر)، می‌توان نامی برای چنین نوعی معرفی کرد و بعداً فقط از آن نام استفاده کرد:

typedef NAME = LENS;

برای پرونده‌های پیکربندی این امکان وجود دارد که تعاریف را از سایر پرونده‌های پیکربندی درون‌ریزی کنند. خطی به شکل:

import "FILENAME";

تمامی تعاریف موجود در FILENAME.conf را در پرونده فعلی در دسترس قرار می‌دهد. پرونده درون‌ریزی‌شده در همان دایرکتوری‌هایی جستجو می‌شود که هنگام جستجوی یک پرونده پیکربندی مربوط به یک کتابخانه بررسی می‌شوند؛ برای جزئیات به ltrace(1) مراجعه کنید.

برنامه ltrace به شما امکان می‌دهد ساختارهای بازگشتی را بیان کنید. چنین ساختارهایی تا عمق مشخص‌شده توسط پارامتر -A باز می‌شوند. برای اعلان یک نوع بازگشتی، ابتدا باید نوع را با استفاده از اعلان پیش‌رو (forward declaration) به ltrace معرفی کنید. سپس می‌توانید از آن نوع در سایر تعاریف نوع به روش معمول استفاده کنید:

typedef NAME = struct;
typedef NAME = struct(NAME can be used here)

به عنوان مثال، ساختار پیوندی یگانه زیر و تابعی که چنین فهرستی را به عنوان آرگومان می‌گیرد را در نظر بگیرید:

typedef int_list = struct;
typedef int_list = struct(int, int_list*);
void ll(int_list*);

چنین اعلان‌هایی ممکن است خروجی شبیه به زیر ایجاد کنند:

ll({ 9, { 8, { 7, { 6, ... } } } }) = <void>

برنامه ltrace بازگشت را تشخیص می‌دهد و ساختارهایی را که قبلاً گسترش یافته‌اند دوباره باز نمی‌کند. بنابراین یک فهرست پیوندی دوگانه شبیه زیر خواهد بود:

typedef int_list = struct;
typedef int_list = struct(int, int_list*, int_list*);

با خروجی‌هایی برای مثال مانند:

ll({ 9, { 8, { 7, { 6, ..., ... }, recurse^ }, recurse^ }, nil })

نشانه‌های "recurse^" به این معنی هستند که اشاره‌گر داده‌شده به ساختاری اشاره می‌کند که در لایه قبلی باز شده بود. یک "recurse" ساده به این معنی است که به همین شیء اشاره دارد. به عنوان مثال "recurse^^^" یعنی به ساختاری در سه لایه بالاتر اشاره می‌کند. برای یک فهرست پیوندی دوگانه، اشاره‌گر به عنصر قبلی طبیعتاً همان عنصری است که به تازگی در دور قبلی باز شده است، و بنابراین همه آن‌ها یا recurse^ هستند یا nil. اگر اشاره‌گرهای بعدی و قبلی جابجا شوند، خروجی به تناسب تنظیم می‌شود:

ll({ 9, nil, { 8, recurse^, { 7, recurse^, { 6, ..., ... } } } })

برنامه ltrace از برخی عبارت‌های ابتدایی پشتیبانی می‌کند. هر عبارت می‌تواند یکی از موارد زیر باشد:

یک عدد صحیح.
مقدار آرگومان NUM-ام. عبارت دارای همان مقدار آرگومان متناظر است. arg1 به آرگومان اول، و arg0 به مقدار بازگشتی تابع داده‌شده اشاره دارد.
مقدار بازگشتی تابع، همانند arg0.
مقدار عنصر NUM-ام از نوع ساختار پیرامونی. به عنوان مثال struct(ulong,array(int,elt1)) ساختاری را توصیف می‌کند که عنصر اول آن یک طول است و عنصر دوم آن آرایه‌ای از intها به همان طول است.

zero
zero(EXPR)

آرایه‌ای را توصیف می‌کند که تا اولین عنصری که هر بایت آن ۰ است امتداد می‌یابد. اگر عبارتی داده شود، آن حداکثر طول آرایه خواهد بود. اگر پایان‌دهنده NUL زودتر پیدا نشود، آرایه در همان نقطه پایان می‌یابد.

گاهی اوقات پیش‌نمونه واقعی تابع بسته به پارامترهای دقیق داده‌شده کمی متفاوت است. به عنوان مثال، تعداد و انواع پارامترهای printf از قبل مشخص نیست، اما ممکن است ltrace بتواند آن‌ها را در زمان اجرا تعیین کند. این ویژگی کاربرد وسیع‌تری دارد، اما در حال حاضر تنها بسته پارامتری که ltrace پشتیبانی می‌کند، خود رشته قالب به سبک printf است:

هنگامی که format در فهرست پارامترها دیده می‌شود، آرگومان رشته‌ای زیرین تجزیه شده و از مشخص‌کننده‌های قالب به سبک GNU برای تعیین آرگومان‌های واقعی بعدی استفاده می‌شود. به عنوان مثال اگر رشته قالب "%s %d\n" باشد، گویی format با string, string, int جایگزین شده است.

توابع C اغلب از یک یا چند آرگومان برای بازگرداندن مقادیر به فراخواننده استفاده می‌کنند. فراخواننده اشاره‌گری به فضای ذخیره‌سازی فراهم می‌کند که تابع فراخوانده‌شده آن را مقداردهی اولیه می‌کند. برنامه ltrace پشتیبانی‌هایی برای این الگو دارد.

هنگامی که یک باینری در حال ردیابی به یک فراخوانی تابع می‌رسد، ltrace ابتدا همه آرگومان‌ها را واکشی می‌کند. سپس بخش چپ از فهرست آرگومان را نمایش می‌دهد. تنها زمانی که تابع بازمی‌گردد، ltrace بخش راست را نیز نمایش می‌دهد. معمولاً بخش چپ همه آرگومان‌ها را شامل می‌شود و بخش راست فقط حاوی مقدار بازگشتی است. اما ltrace به شما اجازه می‌دهد تا با استفاده از عملگر + که در جلوی یک آرگومان قرار می‌گیرد، دقیقاً محل قرارگیری خط جداکننده را پیکربندی کنید:

int asprintf(+string*, format);

در اینجا، اولین آرگومان به asprintf به عنوان آرگومان بازگشتی مشخص شده است، به این معنی که نمایش کل فهرست آرگومان تا زمان بازگشت تابع به تعویق می‌افتد:

a.out->asprintf( <unfinished ...>
libc.so.6->malloc(100) = 0x245b010
[... more calls here ...]
<... asprintf resumed> "X=1", "X=%d", 1) = 5

در حال حاضر امکان داشتن یک آرگومان "inout" که اطلاعات را در هر دو جهت منتقل کند وجود ندارد.

در ادامه، اولی پیش‌نمونه C و به دنبال آن خط پیکربندی ltrace آمده است.

void func_charp_string(char str[]);
void func_charp_string(string);

enum e_foo {RED, GREEN, BLUE};
void func_enum(enum e_foo bar);

void func_enum(enum(RED,GREEN,BLUE));
- یا -
typedef e_foo = enum(RED,GREEN,BLUE);
void func_enum(e_foo);
void func_arrayi(int arr[], int len);
void func_arrayi(array(int,arg2)*,int);

struct S1 {float f; char a; char b;};
struct S2 {char str[6]; float f;};
struct S1 func_struct(int a, struct S2, double d);

struct(float,char,char) func_struct(int, struct(string(array(char, 6)),float), double);

Petr Machata <pmachata@redhat.com>

October 2012