Как разбирать strace в оболочке в обычный текст?

У меня есть журнал трассировки, созданный strace, например, при запуске PHP:

sudo strace -e sendto -fp $(pgrep -n php) -o strace.log

И результат выглядит следующим образом:

11208 sendto(4, "set 29170397297_-cache-schema 85 0 127240\r\n\257\202\v\0?\0\0\0\2\27\10stdClass\24\7\21\3cid\21\6schema\21\4d\37ata\25\n\247\21\5block\24\6\21\6fields\24\f\21\3bid\24\2\5\21\4type 0\37erial\21\10not null\5\21\6module\24\4\16\7\21\7va\37rchar\21\6length\[email protected]\16\t\5\21\7default\r\21\5de\[email protected]\5\16\v\16\f\6 \35\7\16\r\21\0010\21\5t \207C\30 @6\2\16\г\гп\4tatus @0\4\21\3INT /\7\6\0\21\4size \222\finy\21\6weight\24\3 ;\0\22\300 \6\[email protected]\340\5P\5custom\27\300,\17\16\23\16\24\21\nvisibility\340\t\34\7\5pages\24\2\205\3\4tex @\206\261\1it\365\0\5\240 \0\377 y\10\r\21\ftransl! N\2ble%\1ca! A\340\3Q\0\1 n\31\vprimary key\24\1\6\0\16\6\21\[email protected]\21\ts\24\1\21\3tmd\24\3 \31\0\20 2\v\n\6\2\16\16\21\7index \210\10\1\21\4list\24\5\240\36\0\21 \36\10\26\6\3\16\25\6\4\16\n \1\6\4\21\4name \7\0\na\317\2_ro\252\0\5! $\ 0\n\3\341\2\23\0\16\340\0\16A\214\2\21\3r!\354 @\v\22\21\10unsigned\5 @\332\0\36 \213\0\n \213\0\16 l\6%\16!\24\1\16%\271\0% @p\5\16 #\16 $\ 21\f\200l\241b @n\2\4\16\6 M\2\10\16&@E\4\21\4bod\201_\5\32\16\t\4\16\23B\\\2g\16\34 \30\3info .\0\7a\255\0\[email protected]!L\5\6forma\201\332B/!d\2\4\16\37 y\0* y\0\225a;\240\201\2 '\ 21\van\0_ \207\200\2\5\16\1\340\0U = @U\1\16\3 @\222\212\2lob @O\n\23\16)\21\6expire @\30\342\0\26\7\21\7create\241\17 < \25\0\n\203\1\"\177\0d Y\0\22\305\5\5small\240! a\32\0. \230\0.\240\240\0\1\240\240\3,\21\vb S\2kpo\"\313\2s\24\6!\220\2\t\21\2\241q\0\10 ?\4\21\tno \213\6ort\5\21\fm\";\3ine_A\313\232\241\3\2\5\16 #\340\4\16!\345\340\0U \223\340\0'AC\4sourc\202\202\340\3\27\0\v\200\27\0_C\326\340\0074\1\16\21 _\240\363\2\1\16\25\340\3\16\r\0\21\vmultipliers \31\0- \223\1\21\t\341\0\30B-\0\1!\10\0003a\253\0005\v\0005ac\327Dz\ "\ 364\20\0\10\6\0 @\333\r\0165\16\36\0163\21\nidenti $x\nr\0166\21\vadmin_ce\10\21\5label\21\f\244H\6 hook\21\23\240\r\0_\340\1\375\fs\21\3api\24\4\21\5own F\0062\16C\16B\21\17 H\5imum_v\260 $\ 25\7\6\1\21\17curr m\340\1\22!\242\0002\" \ 305\0022\21\20\340\1N\5_groupa\247\2\6\0163 \352\0\10 \352\2\0164\5 \325C%\341\0P\341\5\220\1\0162aQA\26\4\16:\5\21\17\201\321\1 c\"$\5back\21#\340\7b\0_\200!\340\3\311\1\16\7 C\340\0a!\312\1\no\300 #\240! & }\241\237\0\0\242e\341\4n\5\16;\24\10\16< \7\2=\21\35\340\1m\0\320\0\342\3XAz\v\16 > \16G\16?\1 6 @\16A\21\30\341\tT\201\5\1\21\22\200\243\0 B0\6 строка # o\4toolsbD\1\16C\260\0D! D\4C\16L\16E! P\0F\3\201T\16G\21\21ckeditor_set%\266\0gE\323\0\5% Q\0 # 4 @\345!)\ "W #\372\1\21\10\340\0!\0\1\31\0\32\240\334\4 #\16\n\21\10\300D\r\2O\21\25\300\r\6_input_\244+\340\16V\1\16+\31\340\4h X\0\2!;\0 #\245\0+\247\0Q T\7R\21\26comme #/\ 0 _%\266\2cko W\3pane;\4\5\24\10\21\7 @\v\0_\243\257\301\231\1\21\4F\35!\340\1\22F\323\0021\21\10\" \ 311'B\0e @\223A\254 & f`\346 \ "~\6\vcollap & д%\227\340\6\35\2\0\21\т\240\35\344\1a\3009\0\0 #\212\300.\0001\200L $\ 247\1enFl\344\0\216\300,\0\1G\5\3view\340\0002\300\177\372\0\1 K\0T!"..., 8196, MSG_NOSIGNAL | MSG_MORE, NULL, 0) = 8196

Похоже, что они представлены обычными C escape-кодами.

Я попытался их декодировать в оболочке printf следующим образом:

while read line; do printf "%s" "$line"; done < <(cat strace.log | head -n2)

но он потерпел неудачу (похоже, что это не имеет никакого смысла):

11208 sendto(4, "set 29170397297_-cache-schema 85 0 127240rn257202v0?00022710stdClass247213cid216schema214d37ata25n247215block246216fields24f213bid2425214type 037erial2110not [email protected][email protected] 35716r210010215t 207C 30 @6216rr n4tatus @04213int /760214size 222finy216weight243 ;022300 [email protected] 27300,171623162421nvisibility340t3475pages242 20534tex @206 2611it 36505240 0377 y10r21ftransl! N2ble% 1ca! a3403Q01 n31vprimary [email protected] 31020 2vn621616217index 210101214list24524036021 3610266316256416n 164214name 70na3172_ro 25205! $0n 3341223016340016A2142213r! 354 @v222110unsigned5 @332036 2130n 213016 l6%16!24116% 2710% @p516 # 16 $21f200l241b @n24166 M21016&@E4214bod201_53216t41623B\2g1634 303info [email protected]!L56forma201332B/!d241637 y0* y0 225a; 2402012'21van0_ 207 200251613400U = @U1163 @222 2122lob @On2316) 216expire @303420267217create24117 < 250n2031"1770d Y022 30555small240! A320.`2300.240240012402403,21vb S2kpo "3132s246! 2202t212241q010...код >

Есть ли лучший способ проанализировать вывод команды strace, чтобы увидеть простые строки, переданные в recvfrom/sendto?

В идеале можно печатать печатные символы, включая новые строки (\r\n), но обрезанные NULL и другие непечатаемые символы?

Ответ 1

Проблема, почему read не работает, поскольку оболочка уже ускользает от символов, поэтому строка удваивается экранированной, поэтому \r\n печатается как rn.

Чтобы игнорировать экранирование символов оболочкой, вы можете использовать read -r, которые позволяют обратным следам избегать любых символов (поэтому они обрабатываются буквально). Вот пример:

while read -r line; do printf "%b\n" "$line"; done < strace.log | strings

Поскольку это двоичные данные, приведенный выше пример также включает команду strings для отображения только печатаемых строк.

Strace также поддерживает печать всех строк в шестнадцатеричном формате, если указан -x, но он будет работать одинаково.


Вот версия для синтаксического анализа strace вывода в режиме реального времени:

while read -r line;
    do printf "%b\n" "$line" | strings
done < <(sudo strace -e recvfrom,sendto -s 1000 -fp $(pgrep -n php) 2>/dev/stdout)

Далее strings можно заменить более конкретным фильтром с помощью grep, чтобы получить только то, что находится внутри двойных кавычек:

grep -o '".\+[^"]"' | grep -o '[^"]\+[^"]'

однако это может все еще печатать двоичные форматы.

Чтобы этого избежать, упростите весь процесс, поэтому давайте определим следующий псевдоним форматирования:

alias format-strace='grep --line-buffered -o '\''".\+[^"]"'\'' | grep --line-buffered -o '\''[^"]*[^"]'\'' | while read -r line; do printf "%b" $line; done | tr "\r\n" "\275\276" | tr -d "[:cntrl:]" | tr "\275\276" "\r\n"'

где:

  • grep -o '".\+[^"]"' - выберите строку с двумя кавычками с кавычками
  • grep -o '[^"]*[^"]' - выберите текст в двойных кавычках
  • while read -r line - сохранить каждую строку в $line и do некоторое действие (help read)
  • printf "%b" $line - печать строки путем расширения escape-последовательностей обратной косой черты
  • tr "\r\n" "\275\276" - временно заменить \r\n на \275\276
  • tr -d "[:cntrl:]" - удалить все управляющие символы
  • tr "\275\276" "\r\n" - восстановить окончание строки

то полный пример для отслеживания некоторой команды (например, php) может выглядеть так:

strace -e trace=read,write,recvfrom,sendto -s 1000 -fp $(pgrep -n php) 2>&1 | format-strace

Проверьте аналогичный пример: Как просмотреть вывод выполняющегося процесса в другом сеансе bash в Unix.SE