در این مقاله چه چیزهایی یاد بگیریم؟

  1. تنظیم و نصب ابزار DTrace در FreeBSD
  2. تست بعضی از سرویس دهنده های DTrace و دیدن خروجی آن

برای درک این مقاله چه چیزهایی را باید بدانیم؟

  1. آشنایی ابتدایی با کامپایل کردن هسته FreeBSD
  2. کمی مهارت های عیب یابی debugging

DTrace ابزاری است که توسط شرکت سان توسعه داده شده است. DTrace مخفف dynamic tracing است که یک ابزار عیب یابی می‌باشد که برای آنالیز و بدست آوردن بازدهی سیستم های real Time و موارد دیگر به کار می رود.

ابزار DTrace چند ویژگی منحصر به فرد دارد:

  1. اطلاعات سیستم را در زمانی که زیر بیشترین حجم کاری قرار دارد با کمترین سربار به سیستم جمع‌آوری می‌کند.
  2. امکان جمع‌آوری اطلاعات مربوط به هر قسمت از سیستم را فراهم کرده و همچنین این امکان را به ما می‌دهد که بررسی کنیم برنامه‌های کاربردی و هسته سیستم عامل در چه حالتی بهترین کارآیی را دارند.
  3. نشان می‌دهد که چه آرگومان هایی از یک تابع به تابع دیگر ارسال شده حتی اگر کد منبع توابع در دسترس نباشد.
  4. نشان می دهد هر تابع چه مقدار زمانی از سیستم رو اشغال کرده و صدا زده شده. این نمایش به صورت درصدی از زمان و نحوه اجرا می باشد.
  5. اطلاعات رو می توانید با آن فیلتر کرده و دقیقا چیزی رو که می خواهید ببینید.
  6. ممکن است به بعضی وقایع خاص عکس العمل نشان دهد مثل I/O ها، فراخوان توابع، کامل شدن برنامه های در حال اجرا، باز شدن یک thread جدید در هسته و غیره
  7. به شما امکان مشاهده سطح بالا و یا سطح پایین از توابع داخلی که یک راه انداز سخت‌افزار صدا می کند یا یک اسکریپت php برای اجرا صدا میکنه داشته باشید.
  8. اجازه می دهد ردیابی فراخوانی های سیستم را با همراه داشتن آپشن های زیاد مانند – a که برای قبول شده استدلال های زمان اجرا فراخوان سیستمی مورد استفاده قرار می گیرد.

برویم برای شروع

از آنجایی که من یه PC-BSD ایزوتوپ بر روی سیستم نصب دارم و به صورت پیش فرض قابلیت DTrace در کرنل نیست مجبورم کرنل را دوباره کامپایل و قابلیت را به آن اضافه کنم. برای این کار مراحل زیر را طی می کنیم:

۱- قسمت های KDTRACE_HOOKS و DDB_CTF را در فایل کانفیگ کرنل مانند زیر فعال می کنیم بر روی سیستم های ۶۴ بیت همچنین نیاز داریم KDTRACE_FRAME را برای سیمبل های gdb فعال کنیم.

options KDTRACE_HOOKS # all architectures – enable general DTrace hooks
options DDB_CTF # all architectures – kernel ELF linker loads CTF data
options KDTRACE_FRAME # amd64 – ensure frames are compiled in
makeoptions DEBUG="-g" # amd64? – build kernel with gdb(1) debug symbols
makeoptions WITH_CTF=1

۲- بعد از اینکه پارامترهای بالا را در فایل تنظیمات کرنل از حالت توضیح در آوردیم یا اضافه کردیم باید کرنل را مجددا کامپایل کنیم. با اجرای دستورات زیر:

# make buildkernel KERNCONF=DTRACE
# make installkernel KERNCONF=DTRACE
# shutdown -r NOW

۳- بعد از اجرای دستورات بالا به ترتیب، کرنل کامپایل و نصب می شود و با دستور آخر سیستم راه‌اندازی مجدد می شود.

بعد از بالا آمدن سیسم با کرنل جدید تمام ماژول های مربوط به DTrace رو در آن بارگذاری کنید.

# kldload dtraceall

۴- بعد از لود کردن ماژول های مربوطه باید تایید کنیم که چه قلاب های hooks نامرتب DTrace را در دسترس داریم.

# dtrace -l | head

۵- برای اینکه در محدوده کاربران دیگر سیستم هم بتونیم از ابزار DTrace استفاده کنیم خطوط زیر را به فایل make.conf اضافه می کنیم

STRIP=
CFLAGS+=-fno-omit-frame-pointer

این باعث می شود که trace هایی با اطلاعات بیشتر و بهتری نمایش داده شوند.

۶- بعد از انجام کارهای بالا کرنل را با آپشن WITH _ CTF=1 کامپایل می کنیم

چند مثال برای دستور DTrace:

بعد از کامپایل مجدد هسته و راه‌اندازی ابزار DTrace در سیستم عامل، ابزار DTrace در دسترس است. برای مثال به خروجی دستور زیر نگاه کنید.

# dtrace -l | head
ID PROVIDER MODULE FUNCTION NAME 
۱ dtrace BEGIN
۲ dtrace END
۳ dtrace ERROR
۴ dtmalloc nfsclient_req malloc
۵ dtmalloc nfsclient_req free
۶ dtmalloc nfsclient_bigfh malloc
۷ dtmalloc nfsclient_bigfh free
۸ dtmalloc nfsclient_diroff malloc
۹ dtmalloc nfsclient_diroff free

اجازه دهید چند دستور را امتحان کنیم.

برای مثال دستور زیر همراه با خروجی دستور

# dtrace -n 'proc:::exec-success { trace(curpsinfo-
>pr_psargs); }'
dtrace: description 'proc:::exec-success ' matched 1
probe
CPU           ID                      FUNCTION:NAME
۰                ۴۶۵۲۲                    :exec-success                sh
۰                ۴۶۵۲۲                    :exec-success            swapctl
۰                ۴۶۵۲۲                    :exec-success               awk
۰                ۴۶۵۲۲                    :exec-success                sh
۰                ۴۶۵۲۲                    :exec-success            swapctl
۰                ۴۶۵۲۲                    :exec-success               awk
۰                ۴۶۵۲۲                    :exec-success             /bin/sh
۰                ۴۶۵۲۲                    :exec-success             uname
۰                ۴۶۵۲۲                    :exec-success                cut
۰                ۴۶۵۲۲                    :exec-success                 id
۰                ۴۶۵۲۲                    :exec-success             whoami
۰                ۴۶۵۲۲                    :exec-success                 id
۰                ۴۶۵۲۲                    :exec-success                 ls 

ما با دستور بالا به ابزار DTrace می گوییم که تمام برنامه های اجرایی که با موفقیت اجرا شدند را به ما نشان دهد و بگوید آرگومان های آنها کجا در دسترس است.

اجازه دهید آن خط را برای درک بیشتر توضیح دهیم. پروب های ابزار DTrace با ساختار زیر نوشته می شوند:

– provider:module:probefunc:probename

ما  از proc برای provider استفاده می کنیم و این ماژول را کنار می گذاریم و probefunc را با نام خالی آن استفاده می کنیم. این اجباری است برای آپشن های پیش فرض سیستم برای ارائه دهندگان (provider) خاص در آخر استفاده می کنیم از پروب exec-success و این عمل آرگومان های پروسه ها را چاپ می کند.

trace(curpsinfo->pr_psargs); 
نکته: در سیستم عامل FreeBSD نسخه جاری دستور trace(curpsinfo->pr_psargs); فقط args را چاپ می کند.

با یک مثال دیگر ادامه می دهیم.

در هنگام trace کردن، برنامه کاربردی syscall ها را با قابلیت خواندن و نوشتن صدا می زند تا بتواند trace را انجام دهد و ما به ارائه دهنده syscall ها نیاز داریم که برای اینکار یک اسکریپت با اسم trace_rw.d و محتویات زیر درست می کنیم

syscall::read:entry,
syscall::write:entry
/pid == $target/
{
}

به اسکریپت که ساختیم قابلیت اجرایی می دهیم.

بررسی ساختار اسکریپت و دستور DTrace

دستور زیر را در نظر بگیرید

Dtrace –s trace.d –p <pid>

اگر به صفحه توضیحات دستور (man page) مراجعه کنید متوجه می شوید که آپشن –p pid شماره پروسه های (pid) را می گیرد و در یک جدول نمادین کش می کند و بعد از اتمام آن را از جدول خارج می کند. اگر بیشتر از یک آپشن –p در خط فرمان وجود داشت. زمانی از ابزار DTrace خارج می شود که تمام pid ها تمام شده باشند و همچنین وضعیت خروج از هر پروسه را هنگام به پایان رسیدن آن گزارش می دهد.

همچنین در صفحه توضیحات دستور آپشن –s به ابزار DTrace می گوید که یک کد منبع را که با زبان D نوشته شده است را کامپایل کند. اگر آپشن –e به کار برده شده باشد ابزارهای تنظیم فعال نخواهد بود و اگر آپشن –l به کار برده شده باشد برنامه کامپایل می شود و پروب هایی که لیست شده بودند مچ و هماهنگ می شوند ولی ابزارهای تنظیم فعال نخواهد بود. اگر هیچ کدام از آپشن های –e ، -l ، -A و یا –G به کار برده نشده باشند ابزارهای تنظیم خاص زبان D فعال می شوند و trace ادامه پیدا می کند.

حال  به این دو خط کد زیر دقت کنید:

syscall::read:entry,
syscall::write:entry

زمانی که ما پروبی را صدا می زنیم نیاز داریم که بدانیم این کار را چگونه انجام دهیم.

 /pid == $target/
{
}

زمانی که ما آپشن –p را با موفقیت رد می کنیم نیاز داریم به ماکرو $target برای چک کردن pid پروسه ها و جستجو کردن آنها.

علامت / / که اگر مابین این علامت جمله یا عبارتی نبود از آپشن های معمول و پیش فرض سیستم استفاده می کنیم.

حالا می دانیم دستور dtrace –s tarce.d –p <pid> و اسکریپتی که درست کردیم از چه اجزایی تشکیل شده است و چگونه کار می کند. در این مرحله بجای <pid> یک شماره تصادفی pid می گذاریم و دستور را اجرا میکنیم.

نکته: pid مربوط به پروسه ها را می توانیم با دستور ps ax پیدا کنیم.
# dtrace -s trace.d -p 2003
dtrace: script 'trace.d' matched 2 probes
CPU                 ID                   FUNCTION:NAME
۰                   ۴۶۵۳۱                           read:entry
۰                   ۴۶۵۳۱                           read:entry
۰                   ۴۶۵۳۱                           read:entry
۰ 	             ۴۶۵۳۱                           read:entry
۰                   ۴۶۵۳۱                           read:entry
۰                   ۴۶۵۳۱                           read:entry
۰                   ۴۶۵۳۱                           read:entry
۰                   ۴۶۵۳۱                           read:entry
۰                   ۴۶۵۳۱                           read:entry
۰                   ۴۶۵۳۱                           read:entry
۰                   ۴۶۵۳۱                           read:entry
۰                   ۴۶۵۳۱                           read:entry
۰                   ۴۶۵۳۱                           read:entry