להכיר את strace

כאשר אנחנו רוצים לדבג תוכנות, או להבין מה הם עושים בלינוקס/יוניקס, יש לנו כמה צעדים שאפשר לקחת, שיתנו לנו מענה שונה.

פקודה בשם strace היא אחת הפקודות שיכולה לעזור לנו לקבל מידע אודות קריאות מערכת שהתוכנה מבצעת וכן השימוש באותות.

פקודות מערכת הם פקודות שנמצאות בספריית c (המוכרת בשם libc או במימוש glibc שלה) של המערכת. המידע שאנחנו יכולים לקבל הוא מה הקריאה ששתמשנו, עם הפרטמרים מלאים של הפקודה עם התוכן שהזנו ן, וכן מה קיבלנו מהשימוש בפונקציות המערכת, כלומר תשובת החזרה שלה. וזה בלי להשתמש בהוראות לניפוי שגיאות או משהו מיוחד.

פעולה כזו יכולה לעזור לנו לדוגמא למצוא למה התוכנה שאנחנו משתמשים בה קורסת אחרי שאנחנו נותנים לה לפתוח קובץ. או מה מה שגיאת ה I/O שחוזרת לנו בניסיון עבודה עם קבצים למשל, כאשר המתכנת לא השתמש ביכולות לתפוס שגיאות במערכת ולטפל בהם כמו שצריך.

בשביל להבהיר את הנושא, ניקח לדוגמא תוכנית קטנה שמדפיסה לנו על המסך את המילה Hello World:

1 program test_strace;
2
3 begin
4   writeln('Hello World');
5 end.

במידה ונריץ את strace עם התוכנית שלנו (בצורה הבאה):

# strace -v test_strace

האפשרות -v אומרת לstrace להציג פקודות מלאות, כאשר האורך של המחרוזת בברירת מחדל הוא 32 תווים לכל פרמטר, אך נוכל לשחק עם זה בהתאם הצורך שלנו ע"י שימוש באפשרות -s עם האורך הרצוי.

לאחר ההרצה עם -v לבד, נקבל את הפלט הבא (הסרתי מידע רגיש במשתני המערכת):

execve("/tmp/test_strace", ["test_strace"], ["LC_PAPER=en_US.UTF-8", "KDE_MULTIHEAD=false", "LC_ADDRESS=en_US.UTF-8", "SSH_AGENT_PID=", "LC_MONETARY=en_US.UTF-8", "DM_CONTROL=/var/run/xdmctl", "GPG_AGENT_INFO="..., "TERM=xterm", "SHELL=/bin/bash", "XDM_MANAGED=/var/run/xdmctl/xdmc"..., "GTK2_RC_FILES=/home/ik/.gtkrc-2."..., "GTK_RC_FILES=/etc/gtk/gtkrc:/hom"..., "GS_LIB=/home/ik/.fonts", "WINDOWID=", "LC_NUMERIC=en_US.UTF-8", "LC_ALL=en_US.UTF-8", "KDE_FULL_SESSION=true", "USER=ik", "LS_COLORS=no=00:fi=00:di=01;34:l"..., "LC_TELEPHONE=en_US.UTF-8", "SSH_AUTH_SOCK="..., "SESSION_MANAGER=local/white-star"..., "XPSERVERLIST=", "KONSOLE_DCOP=DCOPRef(konsole-323"..., "DESKTOP_SESSION=kde", "PATH=/usr/local/bin:/usr/bin:/bi"..., "LC_MESSAGES=en_US.UTF-8", "LC_IDENTIFICATION=en_US.UTF-8", "LC_COLLATE=en_US.UTF-8", "KONSOLE_DCOP_SESSION=DCOPRef(kon"..., "PWD=/tmp", "LANG=en_US.UTF-8", "KDE_SESSION_UID=", "LC_MEASUREMENT=en_US.UTF-8", "HISTCONTROL=ignoredups", "SHLVL=2", "HOME=/home/ik", "XCURSOR_THEME="..., "LOGNAME=ik", "LC_CTYPE=en_US.UTF-8", "DBUS_SESSION_BUS_ADDRESS="..., "DISPLAY=:0.0", "LC_TIME=en_US.UTF-8", "COLORTERM=", "LC_NAME=en_US.UTF-8", "OLDPWD=/home/ik", "_=/usr/bin/strace"]) = 0
getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0
rt_sigaction(SIGFPE, {0x41ef80, [], SA_RESTORER|SA_SIGINFO, 0x400a38}, NULL, 8 ) = 0
rt_sigaction(SIGSEGV, {0x41ef80, [], SA_RESTORER|SA_SIGINFO, 0x400a38}, NULL, 8 ) = 0
rt_sigaction(SIGBUS, {0x41ef80, [], SA_RESTORER|SA_SIGINFO, 0x400a38}, NULL, 8 ) = 0
rt_sigaction(SIGILL, {0x41ef80, [], SA_RESTORER|SA_SIGINFO, 0x400a38}, NULL, 8 ) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {c_iflags=0x5500, c_oflags=0x5, c_cflags=0xbf, c_lflags=0x8a3b, c_line=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
ioctl(2, SNDCTL_TMR_TIMEBASE or TCGETS, {c_iflags=0x5500, c_oflags=0x5, c_cflags=0xbf, c_lflags=0x8a3b, c_line=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {c_iflags=0x5500, c_oflags=0x5, c_cflags=0xbf, c_lflags=0x8a3b, c_line=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
ioctl(2, SNDCTL_TMR_TIMEBASE or TCGETS, {c_iflags=0x5500, c_oflags=0x5, c_cflags=0xbf, c_lflags=0x8a3b, c_line=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
readlink("/proc/self/exe", "/tmp/test_strace"..., 255) = 16
write(1, "Hello World\n"..., 12Hello World
)        = 12
exit_group(0)                           = ?

החלק הראשון של הפלט שאנחנו רואים הוא הפעולות שstrace עושה בעצמו, ובעצם רק מהחלק של write (מסומן עם קו תחתי) הוא מציג מה שהתוכנה שלנו באמת עושה מבחינת קריאות מערכת.

אפשר לראות שהתוכנית כותבת עם file descriptor שמייצג את STDOUT (כלומר 1 ביוניקס) את המילה Hello World וכן הסימן של לרדת שורה, ואנחנו מקבלים את התוצאה של הפלט שלנו היא 12 תווים שנכתבו.

לאחר מכן, אנחנו אומרים למערכת לצאת מהנקודה שאנחנו נמצאים בה, כאשר במקרה הזה, מדובר ב"פונקציית" main (במבנה של elf לא במבנה של שפת התכנות).

ככול שנשתמש יותר בפעולות מערכת, ככה נראה פלט גדול יותר של strace עצמו, ועורכים כדוגמת vim יודעים לצבוע את התחביר של strace ובכך אפשר להבין טוב יותר את הפלט שקיבלנו.

3 מחשבות על “להכיר את strace

  1. צפריר כהן

    ליתר דיוק: החל מ־execve מדובר כבר על פעולת התוכנית. וזוהי תמיד השורה הראשונה שרואים ב־trace.

    דוגמה נוספת: "איפה התוכנית החוצפנית הזו מעזה לחטט אצלי"?

    strace -eopen,stat -f gvim 2>&1 | grep $HOME

    פלט חלקי:

    [pid 475] open("/home/tzafrir/.icons", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 15
    [pid 475] stat("/home/tzafrir/.local/share/icons", 0x7fff7c4c60e0) = -1 ENOENT (No such file or directory)

    פעולת open (לקריאה) שהצליחה ואחת שנכשלה כי הקובץ לא היה קיים.

    [pid 480] stat("/home/tzafrir/.viminfo", {st_mode=S_IFREG|0600, st_size=14314, …}) = 0
    [pid 480] stat("/home/tzafrir/.viminfo.tmp", 0x7fff7c4c9a80) = -1 ENOENT (No such file or directory)

    פעולת stat (בדיקת פרטי הקובץ) שהצליחה ואחת שנכשלה כי הקובץ לא היה קיים.

    השתמשתי באפשרות ‎-f כדי לקבל דיווח גם על תהליכי־בן של התהליך המקורי. מרגע שיש כבר בן אחד, strace כותב את מספר התהליך (ה־PID) בתחילת השורה.

    כמוכן השתמשתי באפשרות ‏‎-e כדי להציג רק כמה קריאות מערכת שהיו חשובות לי.

  2. Shai

    למי שרוצה את הדיווח ברמת הפשטה קצת יותר גבוהה, יש גם את ltrace, שתופסת קריאות-ספריה ולא (רק) קריאות-מערכת. אני חושד, אבל, שהיא עובדת בעיקר עם ספריות מבוססות-C (מבחינת ה-ABI — אני לא יודע אם פסקל-חופשית תואמת לצורך העניין, אני די בטוח ש-CMUCL, שזה סוג של LISP, למשל, לא).

להשאיר תגובה

הזינו את פרטיכם בטופס, או לחצו על אחד מהאייקונים כדי להשתמש בחשבון קיים:

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s