سؤال

أخبرني أحد الزملاء ذات مرة أن الخيار الأخير عندما فشل كل شيء في تصحيح الأخطاء على Linux هو الاستخدام Strace.

لقد حاولت أن أتعلم العلم وراء هذه الأداة الغريبة، لكنني لست خبيرًا في إدارة النظام ولم أحصل على نتائج حقًا.

لذا،

  • ما هو بالضبط وماذا يفعل؟
  • كيف وفي أي الحالات يجب استخدامه؟
  • كيف ينبغي فهم المخرجات ومعالجتها؟

باختصار، بكلمات بسيطة, ، كيف تعمل هذه الأشياء؟

هل كانت مفيدة؟

المحلول

نظرة عامة على ستريس
يمكن اعتبار Strace مصحح أخطاء خفيف الوزن.فهو يسمح للمبرمج / المستخدم باكتشاف كيفية تفاعل البرنامج مع نظام التشغيل بسرعة.يقوم بذلك عن طريق مراقبة مكالمات وإشارات النظام.

الاستخدامات
مناسب عندما لا يكون لديك كود مصدر أو لا تريد أن تزعج نفسك بمراجعته.
كما أنه مفيد للتعليمات البرمجية الخاصة بك إذا كنت لا ترغب في فتح GDB، ولكنك مهتم فقط بفهم التفاعل الخارجي.

مقدمة صغيرة جيدة
لقد واجهت هذه المقدمة لاستخدامها في اليوم الآخر فقط: ستريس مرحبا بالعالم

نصائح أخرى

بكلمات بسيطة، يتتبع strace جميع مكالمات النظام الصادرة عن البرنامج بالإضافة إلى رموز الإرجاع الخاصة بها.فكر في أشياء مثل عمليات الملفات/المقبس وغيرها الكثير من العمليات الغامضة.

يكون هذا مفيدًا للغاية إذا كان لديك بعض المعرفة العملية بلغة C نظرًا لأن مكالمات النظام هنا ستمثل بشكل أكثر دقة مكالمات مكتبة C القياسية.

لنفترض أن برنامجك هو /usr/local/bin/cough.ببساطة استخدم:

strace /usr/local/bin/cough <any required argument for cough here>

أو

strace -o <out_file> /usr/local/bin/cough <any required argument for cough here>

للكتابة في "out_file".

سيتم نقل كل مخرجات التتبع إلى stderr (احذر، فغالبًا ما يطلب الحجم الهائل منه إعادة التوجيه إلى ملف).في أبسط الحالات، سيتم إيقاف برنامجك بسبب حدوث خطأ، وستكون قادرًا على معرفة مكان تفاعلاته الأخيرة مع نظام التشغيل في إخراج التتبع.

مزيد من المعلومات ينبغي أن تكون متاحة مع:

man strace

يسرد strace جميع مكالمات النظام يتم ذلك من خلال العملية التي يتم تطبيقها عليها.إذا كنت لا تعرف ما تعنيه مكالمات النظام، فلن تتمكن من الحصول على الكثير من الأميال منه.

ومع ذلك، إذا كانت مشكلتك تتضمن ملفات أو مسارات أو قيم بيئة، فإن تشغيل strace على البرنامج الذي به المشكلة وإعادة توجيه الإخراج إلى ملف ثم التقاط هذا الملف لسلسلة المسار/الملف/env قد يساعدك في معرفة ما هو برنامجك في الحقيقة تحاول القيام به، على عكس ما كنت تتوقعه.

تبرز Strace كأداة للتحقيق في أنظمة الإنتاج حيث لا يمكنك تشغيل هذه البرامج تحت مصحح الأخطاء.على وجه الخصوص، استخدمنا strace في الحالتين التاليتين:

  • يبدو أن برنامج foo في طريق مسدود ولم يعد يستجيب.قد يكون هذا هدفًا لـ gdb؛ومع ذلك، لم يكن لدينا دائمًا كود المصدر أو كنا نتعامل في بعض الأحيان مع لغات مكتوبة لم يكن من السهل تشغيلها تحت مصحح الأخطاء.في هذه الحالة، تقوم بتشغيل strace على برنامج قيد التشغيل بالفعل وستحصل على قائمة باستدعاءات النظام التي يتم إجراؤها.يعد هذا مفيدًا بشكل خاص إذا كنت تقوم بالتحقق من تطبيق عميل/خادم أو تطبيق يتفاعل مع قاعدة بيانات
  • التحقيق في سبب بطء البرنامج.وعلى وجه الخصوص، كنا قد انتقلنا للتو إلى نظام ملفات موزع جديد وكان معدل النقل الجديد للنظام بطيئًا للغاية.يمكنك تحديد strace باستخدام خيار "-T" الذي سيخبرك بمقدار الوقت المستغرق في كل استدعاء للنظام.ساعد هذا في تحديد سبب تسبب نظام الملفات في إبطاء الأمور.

للحصول على مثال للتحليل باستخدام strace، راجع إجابتي على هذا السؤال.

أستخدم strace طوال الوقت لتصحيح مشكلات الأذونات.التقنية تسير على النحو التالي:

$ strace -e trace=open,stat,read,write gnome-calculator

أين gnome-calculator هو الأمر الذي تريد تشغيله.

strace -tfp PID سوف يراقب مكالمات نظام عملية PID، وبالتالي يمكننا تصحيح/مراقبة حالة العملية/البرنامج.

يمكن استخدام Strace كأداة تصحيح أو كملف تعريف بدائي.

باعتبارك مصحح أخطاء، يمكنك رؤية كيفية استدعاء مكالمات النظام المحددة وتنفيذها وماذا تعود.هذا مهم جدًا، لأنه يسمح لك برؤية ليس فقط فشل البرنامج، ولكن أيضًا سبب فشل البرنامج.عادةً ما يكون ذلك مجرد نتيجة للترميز الرديء الذي لا يلتقط جميع النتائج المحتملة للبرنامج.وفي أحيان أخرى تكون مجرد مسارات مشفرة للملفات.بدون أثر، يمكنك تخمين الخطأ الذي حدث وأين وكيف.مع strace تحصل على تفاصيل استدعاء النظام، وعادةً ما يخبرك مجرد النظر إلى القيمة المرجعة بالكثير.

التنميط هو استخدام آخر.يمكنك استخدامه لتحديد وقت تنفيذ كل مكالمات النظام بشكل فردي، أو بشكل إجمالي.في حين أن هذا قد لا يكون كافيًا لإصلاح مشكلاتك، إلا أنه على الأقل سيؤدي إلى تضييق نطاق قائمة المشتبه بهم المحتملين بشكل كبير.إذا رأيت الكثير من أزواج الفتح/الإغلاق في ملف واحد، فمن المحتمل أنك تفتح الملفات وتغلقها بشكل غير ضروري في كل تنفيذ للحلقة، بدلاً من فتحها وإغلاقها خارج الحلقة.

Ltrace هو ابن عم ستريس المقرب، وهو أيضًا مفيد جدًا.يجب أن تتعلم كيفية التمييز بين مكان عنق الزجاجة الخاص بك.إذا كان إجمالي التنفيذ 8 ثوانٍ، وقضيت 0.05 ثانية فقط على مكالمات النظام، فلن يفيدك تعقب البرنامج كثيرًا، فالمشكلة تكمن في التعليمات البرمجية الخاصة بك، والتي عادةً ما تكون مشكلة منطقية، أو أن البرنامج يحتاج بالفعل إلى ليأخذ هذا الوقت الطويل للتشغيل.

أكبر مشكلة في strace/ltrace هي قراءة مخرجاتها.إذا كنت لا تعرف كيفية إجراء المكالمات، أو على الأقل أسماء syscalls/الوظائف، فسيكون من الصعب فك المعنى.يمكن أن تكون معرفة ما ترجعه الوظائف مفيدًا جدًا أيضًا، خاصة بالنسبة لرموز الأخطاء المختلفة.على الرغم من صعوبة فك الشفرات، إلا أنها في بعض الأحيان تُرجع لؤلؤة من المعرفة؛بمجرد أن رأيت موقفًا نفدت فيه inodes، ولكن ليس نفدت المساحة الحرة، وبالتالي لم تعطني جميع الأدوات المساعدة المعتادة أي تحذير، ولم أتمكن من إنشاء ملف جديد.لقد وجهتني قراءة رمز الخطأ من مخرجات strace في الاتجاه الصحيح.

Strace هي أداة تخبرك بكيفية تفاعل تطبيقك مع نظام التشغيل الخاص بك.

يقوم بذلك عن طريق إخبارك بنظام التشغيل الذي يستدعيه تطبيقك والمعلمات التي يستدعيها.

لذلك، على سبيل المثال، ترى الملفات التي يحاول برنامجك فتحها، وحالة نجاح المكالمة.

يمكنك تصحيح جميع أنواع المشاكل باستخدام هذه الأداة.على سبيل المثال، إذا قال التطبيق أنه لا يمكنه العثور على المكتبة التي تعلم أنك قمت بتثبيتها، فسوف يخبرك strace بالمكان الذي يبحث فيه التطبيق عن هذا الملف.

وهذا مجرد غيض من فيض.

يعد strace أداة جيدة لتعلم كيفية إجراء برنامجك لاستدعاءات النظام المختلفة (الطلبات إلى النواة) وكذلك الإبلاغ عن تلك التي فشلت بالإضافة إلى قيمة الخطأ المرتبطة بهذا الفشل.ليست كل حالات الفشل عبارة عن أخطاء.على سبيل المثال، قد يحصل التعليمة البرمجية التي تحاول البحث عن ملف على خطأ ENOENT (لا يوجد مثل هذا الملف أو الدليل) ولكن قد يكون هذا سيناريو مقبولًا في منطق التعليمات البرمجية.

إحدى حالات الاستخدام الجيد لاستخدام strace هي تصحيح حالات السباق أثناء إنشاء الملف المؤقت.على سبيل المثال، قد يواجه البرنامج الذي قد يقوم بإنشاء ملفات عن طريق إلحاق معرف العملية (PID) ببعض السلاسل المحددة مسبقًا مشكلات في السيناريوهات متعددة الخيوط.[PID+TID (معرف العملية + معرف مؤشر الترابط) أو استدعاء نظام أفضل مثل mkstemp سيصلح هذه المشكلة].

كما أنها جيدة لتصحيح الأعطال.قد تجد هذه المقالة (الخاصة بي) حول أعطال التتبع وتصحيح الأخطاء مفيد.

أعجبني بعض الإجابات حيث يقرأ strace يتحقق من كيفية تفاعلك مع نظام التشغيل الخاص بك.

وهذا هو بالضبط ما يمكننا رؤيته.يدعو النظام.إذا قارنت strace و ltrace الفرق أكثر وضوحا.

$>strace -c cd
Desktop  Documents  Downloads  examples.desktop  Music  Pictures  Public  Templates  Videos
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0         7           read
  0.00    0.000000           0         1           write
  0.00    0.000000           0        11           close
  0.00    0.000000           0        10           fstat
  0.00    0.000000           0        17           mmap
  0.00    0.000000           0        12           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         2           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0         2           ioctl
  0.00    0.000000           0         8         8 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         2           getdents
  0.00    0.000000           0         2         2 statfs
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         9           openat
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           prlimit64
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                    93        10 total

ومن ناحية أخرى هناك ltrace الذي يتتبع الوظائف.

$>ltrace -c cd
Desktop  Documents  Downloads  examples.desktop  Music  Pictures  Public  Templates  Videos
% time     seconds  usecs/call     calls      function
------ ----------- ----------- --------- --------------------
 15.52    0.004946         329        15 memcpy
 13.34    0.004249          94        45 __ctype_get_mb_cur_max
 12.87    0.004099        2049         2 fclose
 12.12    0.003861          83        46 strlen
 10.96    0.003491         109        32 __errno_location
 10.37    0.003303         117        28 readdir
  8.41    0.002679         133        20 strcoll
  5.62    0.001791         111        16 __overflow
  3.24    0.001032         114         9 fwrite_unlocked
  1.26    0.000400         100         4 __freading
  1.17    0.000372          41         9 getenv
  0.70    0.000222         111         2 fflush
  0.67    0.000214         107         2 __fpending
  0.64    0.000203         101         2 fileno
  0.62    0.000196         196         1 closedir
  0.43    0.000138         138         1 setlocale
  0.36    0.000114         114         1 _setjmp
  0.31    0.000098          98         1 realloc
  0.25    0.000080          80         1 bindtextdomain
  0.21    0.000068          68         1 opendir
  0.19    0.000062          62         1 strrchr
  0.18    0.000056          56         1 isatty
  0.16    0.000051          51         1 ioctl
  0.15    0.000047          47         1 getopt_long
  0.14    0.000045          45         1 textdomain
  0.13    0.000042          42         1 __cxa_atexit
------ ----------- ----------- --------- --------------------
100.00    0.031859                   244 total

على الرغم من أنني راجعت الأدلة عدة مرات، إلا أنني لم أجد أصل الاسم strace ولكن من المحتمل أن يكون تتبع استدعاء النظام، لأن هذا واضح.

هناك ثلاث ملاحظات أكبر لنقولها strace.

ملاحظة 1:كل من هذه الوظائف strace و ltrace يستخدمون مكالمة النظام ptrace.لذا ptrace استدعاء النظام هو على نحو فعال كيف strace يعمل.

The ptrace() system call provides a means by which one process (the "tracer") may observe and control the execution of another process (the "tracee"), and examine and change the tracee's memory and registers. It is primarily used to implement breakpoint debugging and system call tracing.

ملاحظة 2:هناك معلمات مختلفة يمكنك استخدامها معها strace, ، منذ strace يمكن أن يكون مطولاً جداً.أحب التجربة -c وهو بمثابة ملخص للأشياء.مرتكز على -c يمكنك تحديد مكالمة نظام واحدة مثل -e trace=open حيث سترى تلك المكالمة فقط.قد يكون هذا مثيرًا للاهتمام إذا كنت تفحص الملفات التي سيتم فتحها أثناء الأمر الذي تقوم بتتبعه.وبالطبع، يمكنك استخدام grep لنفس الغرض ولكن لاحظ أنك بحاجة إلى إعادة التوجيه بهذه الطريقة 2>&1 | grep etc لفهم أن ملفات التكوين يتم الرجوع إليها عند إصدار الأمر.

ملاحظة 3:أجد هذه الملاحظة مهمة جدًا.أنت لا تقتصر على بنية معينة. strace سوف يذهلك، لأنه يمكن أن يتتبع ثنائيات من بنيات مختلفة.enter image description here

الحد الأدنى من الأمثلة القابلة للتشغيل

إذا لم يكن المفهوم واضحًا، فهناك مثال أبسط لم تره يشرحه.

في هذه الحالة، هذا المثال هو تجميع Linux x86_64 القائم بذاته (بدون libc) helloworld:

مرحبا.س

.text
.global _start
_start:
    /* write */
    mov $1, %rax    /* syscall number */
    mov $1, %rdi    /* stdout */
    mov $msg, %rsi  /* buffer */
    mov $len, %rdx  /* buffer len */
    syscall

    /* exit */
    mov $60, %rax   /* exit status */
    mov $0, %rdi    /* syscall number */
    syscall
msg:
    .ascii "hello\n"
len = . - msg

جيثب المنبع.

تجميع وتشغيل:

as -o hello.o hello.S
ld -o hello.out hello.o
./hello.out

المخرجات المتوقعة:

hello

الآن دعونا نستخدم strace في هذا المثال:

env -i ASDF=qwer strace -o strace.log -s999 -v ./hello.out arg0 arg1
cat strace.log

نحن نستخدم:

strace.log يحتوي الآن على:

execve("./hello.out", ["./hello.out", "arg0", "arg1"], ["ASDF=qwer"]) = 0
write(1, "hello\n", 6)                  = 6
exit(0)                                 = ?
+++ exited with 0 +++

مع هذا المثال البسيط، كل حرف من الناتج يكون واضحًا بذاته:

  • execve خط:يظهر كيف strace أعدم hello.out, ، بما في ذلك وسيطات CLI والبيئة كما هو موثق في man execve

  • write خط:يُظهر استدعاء نظام الكتابة الذي قمنا به. 6 هو طول السلسلة "hello\n".

    = 6 هي القيمة المرجعة لاستدعاء النظام، كما هو موثق في man 2 write هو عدد البايتات المكتوبة.

  • exit خط:يُظهر مكالمة نظام الخروج التي قمنا بها.لا توجد قيمة إرجاع، منذ توقف البرنامج!

أمثلة أكثر تعقيدا

إن تطبيق strace هو بالطبع معرفة النظام الذي يستدعي البرامج المعقدة التي تقوم بها بالفعل للمساعدة في تصحيح أخطاء برنامجك/تحسينه.

والجدير بالذكر أن معظم مكالمات النظام التي من المحتمل أن تواجهها في Linux تحتوي على أغلفة glibc، العديد منهم من POSIX.

داخليًا، تستخدم مغلفات glibc التجميع المضمّن كما يلي تقريبًا: كيفية استدعاء استدعاء النظام عبر sysenter في التجميع المضمن؟

المثال التالي الذي يجب عليك دراسته هو POSIX write مرحبا بالعالم:

ج الرئيسية

#define _XOPEN_SOURCE 700
#include <unistd.h>

int main(void) {
    char *msg = "hello\n";
    write(1, msg, 6);
    return 0;
}

تجميع وتشغيل:

gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out

هذه المرة، سترى أنه تم إجراء مجموعة من مكالمات النظام بواسطة glibc من قبل main لإعداد بيئة جميلة لـ main.

وذلك لأننا لا نستخدم الآن برنامجًا قائمًا بذاته، بل نستخدم برنامج glibc الأكثر شيوعًا، والذي يسمح بوظيفة libc.

ثم في كل نهاية، strace.log يتضمن:

write(1, "hello\n", 6)                  = 6
exit_group(0)                           = ?
+++ exited with 0 +++

لذلك نستنتج أن write تستخدم وظيفة POSIX، مفاجأة!، Linux write مكالمة النظام.

ونحن نلاحظ ذلك أيضا return 0 يؤدي إلى exit_group اتصل بدلا من exit.هههه لم أكن أعلم بهذا الأمر!هذا هو السبب strace بارد جدا. man exit_group ثم يشرح:

استدعاء النظام هذا يعادل الخروج (2) فيما عدا أنه لا ينهي مؤشر ترابط الاستدعاء فحسب، بل جميع سلاسل الرسائل الموجودة في مجموعة مؤشرات ترابط عملية الاستدعاء.

وهنا مثال آخر حيث قمت بدراسة استدعاء النظام dlopen الاستخدامات: https://unix.stackexchange.com/questions/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710

تم الاختبار في Ubuntu 16.04 وGCC 6.4.0 وLinux kernel 4.4.0.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top