Ежедневната ми работа е предимно внедряване на софтуер, което означава, че прекарвам много време в опити да отговоря на въпроси като:
- Този софтуер работи за разработчика, но не и за мен. Защо?
- Вчера този софтуер работи за мен, но днес не работи. Защо?
Това е вид отстраняване на грешки, което е малко по-различно от обикновеното отстраняване на грешки в софтуера. Редовното отстраняване на грешки е свързано с логиката на кода, но отстраняването на грешки при внедряване е свързано с взаимодействието между кода и средата. Дори ако коренът на проблема е логическа грешка, фактът, че всичко работи на една машина, а не на друга, означава, че проблемът по някакъв начин е в средата.
Така че вместо обичайните инструменти за отстраняване на грешки като GDB Имам различен набор от инструменти за отстраняване на грешки при разполагане. И моят любим инструмент за справяне с проблема като „Защо този софтуер не работи за мен?“ Наречен Strace.
Какво е strace?
Основното приложение е много просто. Просто трябва да стартирате strace с която и да е команда и тя ще изхвърли всички системни повиквания (въпреки че първо вероятно ще трябва да я инсталирате сами Strace):
$ strace echo Hello
...Snip lots of stuff...
write(1, "Hellon", 6) = 6
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
Какви са тези системни повиквания? Това е нещо като API за ядрото на операционната система. Някога софтуерът имаше директен достъп до хардуера, на който работеше. Ако, например, трябваше да покаже нещо на екрана, той играеше с портове или карти с памет регистри за видео устройства. Когато многозадачните компютърни системи станаха популярни, цареше хаос, тъй като различни приложения се бореха за хардуера. Грешки в едно приложение могат да свалят други, ако не и цялата система. След това в процесора се появиха режими на привилегии (или „защита на звънене“). Ядрото стана най-привилегированото: получи пълен достъп до хардуера, създавайки по-малко привилегировани приложения, които вече трябваше да поискат достъп от ядрото, за да взаимодействат с хардуера чрез системни повиквания.
На двоично ниво системното извикване е малко по-различно от обикновеното извикване на функция, но повечето програми използват обвивка в стандартната библиотека. Тези. стандартната библиотека POSIX C съдържа извикване на функция напиши (), който съдържа целия специфичен за архитектурата код за системното извикване пиша.
Накратко, всяко взаимодействие между приложение и неговата среда (компютърни системи) се осъществява чрез системни повиквания. Следователно, когато софтуерът работи на една машина, но не и на друга, би било добре да погледнете резултатите от проследяването на системните повиквания. По-конкретно, ето списък с типични точки, които могат да бъдат анализирани с помощта на проследяване на системно повикване:
- Конзолен I/O
- Мрежови I/O
- Достъп до файловата система и файлов I/O
- Управление на живота на процесна нишка
- Управление на паметта на ниско ниво
- Достъп до специфични драйвери на устройства
Кога да използвам strace?
На теория, Strace използва се с всяка програма в потребителското пространство, защото всяка програма в потребителското пространство трябва да прави системни извиквания. Работи по-ефективно с компилирани програми на ниско ниво, но работи и с езици на високо ниво като Python, ако можете да пресечете допълнителния шум от времето за изпълнение и интерпретатора.
В целия си блясък Strace се проявява по време на отстраняване на грешки на софтуер, който работи добре на една машина, но внезапно спира да работи на друга, извеждайки неясни съобщения за файлове, разрешения или неуспешни опити за изпълнение на някакви команди или нещо друго... Жалко, но не става се комбинират толкова добре с проблеми на високо ниво, като например грешки при проверка на сертификат. Обикновено това изисква комбинация Straceпонякога
Ще използваме самостоятелен сървър като пример, но проследяването на системни повиквания често може да се извърши на по-сложни платформи за внедряване. Просто трябва да изберете правилните инструменти.
Прост пример за отстраняване на грешки
Да приемем, че искате да стартирате невероятното сървърно приложение foo и ето какво в крайна сметка получавате:
$ foo
Error opening configuration file: No such file or directory
Очевидно не може да намери конфигурационния файл, който сте написали. Това се случва, защото понякога, когато мениджърите на пакети компилират приложение, те заместват очакваните файлови местоположения. И ако следвате ръководството за инсталиране на една дистрибуция, в друга ще намерите файлове, напълно различни от това, където сте очаквали. Проблемът може да бъде решен за няколко секунди, ако съобщението за грешка казва къде да търсите конфигурационния файл, но не го прави. И така, къде да търсим?
Ако имате достъп до изходния код, можете да го прочетете и да разберете всичко. Добър резервен план, но не и най-бързото решение. Можете да прибегнете до програма за отстраняване на грешки стъпка по стъпка като GDB и вижте какво прави програмата, но е много по-ефективно да използвате инструмент, който е специално проектиран да показва взаимодействие с околната среда: Strace.
Продукция Strace може да изглежда излишно, но добрата новина е, че повечето от тях могат безопасно да бъдат игнорирани. Често е полезно да използвате оператора -o, за да запазите резултатите от проследяването в отделен файл:
$ strace -o /tmp/trace foo
Error opening configuration file: No such file or directory
$ cat /tmp/trace
execve("foo", ["foo"], 0x7ffce98dc010 /* 16 vars */) = 0
brk(NULL) = 0x56363b3fb000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=25186, ...}) = 0
mmap(NULL, 25186, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2f12cf1000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF2113 3 > 1 260A2 "..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1824496, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2f12cef000
mmap(NULL, 1837056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2f12b2e000
mprotect(0x7f2f12b50000, 1658880, PROT_NONE) = 0
mmap(0x7f2f12b50000, 1343488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f2f12b50000
mmap(0x7f2f12c98000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16a000) = 0x7f2f12c98000
mmap(0x7f2f12ce5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7f2f12ce5000
mmap(0x7f2f12ceb000, 14336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2f12ceb000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f2f12cf0500) = 0
mprotect(0x7f2f12ce5000, 16384, PROT_READ) = 0
mprotect(0x56363b08b000, 4096, PROT_READ) = 0
mprotect(0x7f2f12d1f000, 4096, PROT_READ) = 0
munmap(0x7f2f12cf1000, 25186) = 0
openat(AT_FDCWD, "/etc/foo/config.json", O_RDONLY) = -1 ENOENT (No such file or directory)
dup(2) = 3
fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
brk(NULL) = 0x56363b3fb000
brk(0x56363b41c000) = 0x56363b41c000
fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x8), ...}) = 0
write(3, "Error opening configuration file"..., 60) = 60
close(3) = 0
exit_group(1) = ?
+++ exited with 1 +++
Приблизително цялата първа страница на изхода Strace - Обикновено това е подготовка на ниско ниво за изстрелване. (Много обаждания mmap, mprotect, перо за неща като откриване на памет на ниско ниво и показване на динамични библиотеки.) Всъщност по време на отстраняване на грешки изходът Strace По-добре е да четете от самия край. По-долу ще има предизвикателство пиша, което показва съобщение за грешка. Поглеждаме отгоре и виждаме първото погрешно системно повикване - повикването openat, което извежда грешка ENOENT („файлът или директорията не са намерени“) се опитва да отвори /etc/foo/config.json. Тук трябва да е конфигурационният файл.
Това беше само пример, но бих казал, че 90% от времето, което използвам Strace, няма нищо много по-трудно за правене от това. По-долу е пълно ръководство за отстраняване на грешки стъпка по стъпка:
- Разстройте се поради неясно съобщение за системна грешка от програма
- Рестартирайте програмата с Strace
- Намерете съобщението за грешка в резултатите от проследяването
- Отидете по-високо, докато достигнете първото неуспешно системно повикване
Много е вероятно системното повикване в стъпка 4 да разкрие какво се е объркало.
съвети
Преди да ви покажа пример за по-сложно отстраняване на грешки, ще ви покажа няколко трика за ефективна употреба Strace:
човекът е твой приятел
На много *nix системи, пълен списък на системните извиквания към ядрото може да бъде получен чрез стартиране системни повиквания на човека. Ще видите неща като brk (2), което означава, че може да се получи повече информация чрез стартиране мъж 2 бр.
Малък рейк: човек 2 вилица показва ми страницата за черупката вилица () в GNU libc, което се оказва, че се реализира чрез извикване клонинг(). Семантика на повикването вилица остава същата, ако напишете програма, използваща вилица ()и стартирайте проследяване - няма да намеря обаждания вилица, вместо тях ще има клонинг(). Такива рейкове само ви объркват, ако започнете да сравнявате източника с изхода Strace.
Използвайте -o, за да запишете изхода във файл
Strace може да генерира обширен изход, така че често е полезно да съхранявате резултатите от проследяването в отделни файлове (както в примера по-горе). Това също помага да се избегне объркването на изхода на програмата с изхода Strace в конзолата.
Използвайте -s, за да видите повече данни за аргументи
Може да сте забелязали, че втората половина на съобщението за грешка не е показана в примерната трасировка по-горе. Това е защото Strace по подразбиране показва само първите 32 байта от низовия аргумент. Ако искате да видите повече, добавете нещо подобно -s 128 към обаждането Strace.
-y улеснява проследяването на файлове, сокети и т.н.
„Всичко е файл“ означава, че *nix системите извършват всички I/O, използвайки файлови дескриптори, независимо дали това се отнася за файл, мрежа или междупроцесни канали. Това е удобно за програмиране, но затруднява проследяването на това, което наистина се случва, когато видите общи чета и пиша в резултатите от проследяването на системните повиквания.
Чрез добавяне на оператор ш, ще принудите Strace анотирайте всеки файлов дескриптор в изхода с бележка към какво сочи.
Прикрепете към вече работещ процес с -p**
Както ще видите от примера по-долу, понякога трябва да проследите програма, която вече работи. Ако е известно, че се изпълнява като процес 1337 (да речем, от изхода ps), тогава можете да го проследите по следния начин:
$ strace -p 1337
...system call trace output...
Може да имате нужда от root права.
Използвайте -f за наблюдение на дъщерни процеси
Strace По подразбиране проследява само един процес. Ако този процес ражда дъщерни процеси, тогава може да се види системното извикване за раждане на дъщерния процес, но системните извиквания на дъщерния процес няма да бъдат показани.
Ако смятате, че грешката е в дъщерен процес, използвайте оператора -f, това ще позволи неговото проследяване. Недостатъкът на това е, че резултатът ще ви обърка още повече. Кога Strace проследява един процес или една нишка, показва единичен поток от събития на повикване. Когато проследява няколко процеса наведнъж, може да видите началото на повикване, прекъснато от съобщение , след това - куп извиквания за други клонове за изпълнение и едва след това - края на първия <…foocall resumed>. Или разделете всички резултати от трасирането в различни файлове, като също използвате оператора -фф (подробности в
Филтрирайте следите с помощта на -e
Както можете да видите, резултатът от проследяването е истинска купчина от всички възможни системни повиквания. Флаг -e Можете да филтрирате следата (вижте
Не всички грешки са лоши
Прост и често срещан пример е програма, която търси файл на няколко места едновременно, като черупка, която търси директория, която съдържа изпълним файл:
$ strace sh -c uname
...
stat("/home/user/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory)
stat("/usr/local/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory)
stat("/usr/bin/uname", {st_mode=S_IFREG|0755, st_size=39584, ...}) = 0
...
Евристиките като „последна неуспешна заявка преди докладване за грешка“ са добри при намирането на подходящи грешки. Както и да е, логично е да започнем от самия край.
Уроците по програмиране на C могат да ви помогнат да разберете системните повиквания.
Стандартните извиквания към C библиотеки не са системни извиквания, а само тънък повърхностен слой. Така че, ако разбирате поне малко как и какво да правите в C, ще ви бъде по-лесно да разберете резултатите от проследяването на системното извикване. Например, имате проблеми с отстраняването на грешки при повиквания към мрежови системи, погледнете същата класика
По-сложен пример за отстраняване на грешки
Вече казах, че примерът за просто отстраняване на грешки е пример за това, с което най-често трябва да се справям, когато работя Strace. Понякога обаче е необходимо истинско разследване, така че ето пример от реалния живот за по-разширено отстраняване на грешки.
# crontab -e -u logs
bcrontab: Fatal: Could not create temporary file
Добре, това означава bcron се опита да напише определен файл, но не се получи и той не иска да признае защо. Разкриване Strace:
# strace -o /tmp/trace crontab -e -u logs
bcrontab: Fatal: Could not create temporary file
# cat /tmp/trace
...
openat(AT_FDCWD, "bcrontab.14779.1573691864.847933", O_RDONLY) = 3
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000
read(3, "#Ansible: logsaggn20 14 * * * lo"..., 8192) = 150
read(3, "", 8192) = 0
munmap(0x7f82049b4000, 8192) = 0
close(3) = 0
socket(AF_UNIX, SOCK_STREAM, 0) = 3
connect(3, {sa_family=AF_UNIX, sun_path="/var/run/bcron-spool"}, 110) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000
write(3, "156:Slogs #Ansible: logsaggn20 1"..., 161) = 161
read(3, "32:ZCould not create temporary f"..., 8192) = 36
munmap(0x7f82049b4000, 8192) = 0
close(3) = 0
write(2, "bcrontab: Fatal: Could not creat"..., 49) = 49
unlink("bcrontab.14779.1573691864.847933") = 0
exit_group(111) = ?
+++ exited with 111 +++
В самия край има съобщение за грешка пиша, но този път нещо е различно. Първо, няма съответна грешка в системното извикване, която обикновено се появява преди това. Второ, ясно е, че някъде някой вече е прочел съобщението за грешка. Изглежда, че истинският проблем е някъде другаде и bcrontab просто възпроизвежда съобщението.
Ако погледнете човек 2 чете, можете да видите, че първият аргумент (3) е файлов дескриптор, който *nix използва за цялата I/O обработка. Как да разбера какво представлява файловият дескриптор 3? В този конкретен случай можете да бягате Strace с оператор ш (вижте по-горе) и автоматично ще ви каже, но за да разберете неща като тези, е полезно да знаете как да четете и анализирате резултатите от проследяването.
Източникът на файлов дескриптор може да бъде едно от много системни извиквания (всичко зависи от това за какво служи дескрипторът - конзола, мрежов сокет, самият файл или нещо друго), но както и да е, ние търсим извиквания чрез връщане на 3 (т.е. търсим „= 3“ в резултатите от проследяването). В този резултат има 2 от тях: openat на самия връх и гнездо По средата. openat отваря файла, но близо(3) след това ще покаже, че се затваря отново. (Rake: файловите дескриптори могат да се използват повторно, когато се отварят и затварят). Обадете се гнездо () подходящ, защото е последният преди Прочети(), и се оказва, че bcrontab работи с нещо през сокет. Следващият ред показва, че файловият дескриптор е свързан с unix домейн сокет по пътя /var/run/bcron-spool.
И така, трябва да намерим процеса, свързан с unix сокет от друга страна. Има няколко хитри трика за тази цел, като и двата са полезни за отстраняване на грешки при внедряване на сървъри. Първият е да използвате NETSTAT или по-нова ss (състояние на сокета). И двете команди показват активните мрежови връзки на системата и приемат изявлението -l за описание на гнездата за слушане, както и на оператора -p за показване на програми, свързани към сокета като клиент. (Има още много полезни опции, но тези две са достатъчни за тази задача.)
# ss -pl | grep /var/run/bcron-spool
u_str LISTEN 0 128 /var/run/bcron-spool 1466637 * 0 users:(("unixserver",pid=20629,fd=3))
Това предполага, че слушателят е командата inixserver, изпълняващ се с идентификатор на процес 20629. (И, случайно, той използва файлов дескриптор 3 като сокет.)
Вторият наистина полезен инструмент за намиране на същата информация се нарича също. Той изброява всички отворени файлове (или файлови дескриптори) в системата. Или можете да получите информация за един конкретен файл:
# lsof /var/run/bcron-spool
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
unixserve 20629 cron 3u unix 0x000000005ac4bd83 0t0 1466637 /var/run/bcron-spool type=STREAM
Процесът 20629 е дълготраен сървър, така че можете да го прикачите Strace използвайки нещо подобно strace -o /tmp/trace -p 20629. Ако редактирате задание на cron в друг терминал, ще получите изход за проследяване с грешка. И ето го резултата:
accept(3, NULL, NULL) = 4
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21181
close(4) = 0
accept(3, NULL, NULL) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21181, si_uid=998, si_status=0, si_utime=0, si_stime=0} ---
wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED, NULL) = 21181
wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0
rt_sigreturn({mask=[]}) = 43
accept(3, NULL, NULL) = 4
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21200
close(4) = 0
accept(3, NULL, NULL) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21200, si_uid=998, si_status=111, si_utime=0, si_stime=0} ---
wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 111}], WNOHANG|WSTOPPED, NULL) = 21200
wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0
rt_sigreturn({mask=[]}) = 43
accept(3, NULL, NULL
(Последно приемете () няма да бъде завършен при проследяване.) Отново, за съжаление, този резултат не съдържа грешката, която търсим. Не виждаме никакви съобщения, които bcrontag изпраща или получава от сокета. Вместо това пълен контрол на процеса (клонинг, изчакай4, SIGCHLD и т.н.) Този процес поражда дъщерен процес, който, както можете да предположите, върши истинската работа. И ако трябва да хванете следите й, добавете към обаждането strace -f. Това ще открием, когато търсим съобщението за грешка в новия резултат със strace -f -o /tmp/trace -p 20629:
21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied)
21470 write(1, "32:ZCould not create temporary f"..., 36) = 36
21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84
21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory)
21470 exit_group(111) = ?
21470 +++ exited with 111 +++
Сега, това е нещо. Процес 21470 получава грешка „достъпът е отказан“, когато се опитва да създаде файл на път tmp/spool.21470.1573692319.854640 (свързани с текущата работна директория). Ако знаехме само текущата работна директория, щяхме да знаем и пълния път и да можем да разберем защо процесът не може да създаде своя временен файл в нея. За съжаление, процесът вече е излязъл, така че не можете просто да използвате lsof -p 21470 за да намерите текущата директория, но можете да работите в обратна посока - потърсете PID 21470 системни извиквания, които променят директорията. (Ако няма такива, PID 21470 трябва да ги е наследил от своя родител и това вече е чрез lsof -p не може да се открие.) Това системно повикване е CHDIR (което лесно се установява с помощта на съвременните онлайн търсачки). И ето резултатът от обратни търсения въз основа на резултатите от проследяването, чак до сървър PID 20629:
20629 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21470
...
21470 execve("/usr/sbin/bcron-spool", ["bcron-spool"], 0x55d2460807e0 /* 27 vars */) = 0
...
21470 chdir("/var/spool/cron") = 0
...
21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied)
21470 write(1, "32:ZCould not create temporary f"..., 36) = 36
21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84
21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory)
21470 exit_group(111) = ?
21470 +++ exited with 111 +++
(Ако сте се изгубили, може да искате да прочетете предишната ми публикация
# ls -ld /var/spool/cron/tmp/
drwxr-xr-x 2 root root 4096 Nov 6 05:33 /var/spool/cron/tmp/
# ps u -p 20629
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
cron 20629 0.0 0.0 2276 752 ? Ss Nov14 0:00 unixserver -U /var/run/bcron-spool -- bcron-spool
Ето къде е заровено кучето! Сървърът работи като потребител cron, но само root има разрешение да пише в директорията /var/spool/cron/tmp/. Проста команда chown cron /var/spool/cron/tmp/ ще принуди bcron работят правилно. (Ако това не е проблемът, тогава следващият най-вероятен заподозрян е модул за сигурност на ядрото като SELinux или AppArmor, така че бих проверил регистъра на съобщенията на ядрото с dmesg.)
Общо
Проследяването на системни повиквания може да бъде непосилно за начинаещ, но се надявам, че съм показал, че те са бърз начин за отстраняване на грешки в цял клас често срещани проблеми с внедряването. Представете си, че се опитвате да дебъгвате мултипроцес bcronс помощта на програма за отстраняване на грешки стъпка по стъпка.
Разборът на резултатите от проследяването назад по веригата на системните повиквания изисква умения, но както казах, почти винаги, използвайки Strace, просто получавам резултата от трасирането и търся грешки, започвайки от края. Така или иначе, Strace ми помага да спестя много време за отстраняване на грешки. Надявам се и на вас да ви е от полза.
Източник: www.habr.com