V systému Linux pomocí ps
od procps(-ng)
:
ps -fwwp 2755
Ve verzích Linuxu starších než 4.2 je to stále omezeno (kernel (/proc/2755/cmdline
) až 4k) a nemůžete získat více, než když požádáte proces, aby vám to řekl, nebo použijete debugger.
$ sh -c 'sleep 1000' $(seq 4000) &
[1] 31149
$ gdb -p $! /bin/sh
[...]
Attaching to program: /bin/dash, process 31149
[...]
(gdb) bt
#0 0x00007f40d11f40aa in wait4 () at ../sysdeps/unix/syscall-template.S:81
[...]
#7 0x00007f40d115c995 in __libc_start_main (main=0x4022c0, argc=4003, ubp_av=0x7fff5b9f5a88, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff5b9f5a78)
at libc-start.c:260
#8 0x00000000004024a5 in ?? ()
#9 0x00007fff5b9f5a78 in ?? ()
#10 0x0000000000000000 in ?? ()
(gdb) frame 7
#7 0x00007f40d115c995 in __libc_start_main (main=0x4022c0, argc=4003, ubp_av=0x7fff5b9f5a88, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff5b9f5a78)
at libc-start.c:260
(gdb) x/4003s *ubp_av
0x7fff5b9ff83e: "sh"
0x7fff5b9ff841: "-c"
0x7fff5b9ff844: "sleep 1000"
0x7fff5b9ff84f: "1"
0x7fff5b9ff851: "2"
[...]
0x7fff5ba04212: "3999"
0x7fff5ba04217: "4000"
Chcete-li vytisknout 4. argument s až 5000 znaky:
(gdb) set print elements 5000
(gdb) p ubp_av[3]
Pokud chcete něco nevtíravého, můžete zkusit získat informace z /proc/2755/mem
(všimněte si, že pokud kernel.yama.ptrace_scope
není nastaveno na 0, budete k tomu potřebovat oprávnění superuživatele). Toto níže pro mě funguje (vytiskne všechny argumenty a proměnné prostředí), ale podle mého názoru neexistuje žádná velká záruka (chyby a neočekávané vstupy jsou ponechány jako cvičení pro čtenáře):
$ perl -e '$p=shift;open MAPS, "/proc/$p/maps";
($m)=grep /\[stack\]/, <MAPS>;
($a,$b)=map hex, $m =~ /[\da-f]+/g;
open MEM, "/proc/$p/mem" or die "open mem: $!";
seek MEM,$a,0; read MEM, $c,$b-$a;
print((split /\0{2,}/,$c)[-1])' "$!" | tr \\0 \\n | head
sh
-c
sleep 1000
1
2
3
4
5
6
7
(nahraďte "$!"
s ID procesu). Výše uvedené využívá skutečnosti, že Linux vkládá řetězce, na které ukazuje argv[]
, envp[]
a spuštěný název souboru ve spodní části zásobníku procesu.
Výše uvedené hledá v tomto zásobníku nejspodnější řetězec mezi dvěma sadami dvou nebo více po sobě jdoucích bajtů NUL. Nefunguje to, pokud je některý z argumentů nebo řetězců env prázdný, protože pak budete mít uprostřed těchto argv nebo envp sekvenci 2 bajtů NUL. Také nevíme, kde končí řetězce argv a kde začínají řetězce envp.
Řešením by bylo upřesnit tuto heuristiku tím, že se zpětně podíváme na skutečný obsah argv[]
(ukazatele). Toto níže funguje alespoň na architektuře i386 a amd64 pro spustitelné soubory ELF:
perl -le '$p=shift;open MAPS, "/proc/$p/maps";
($m)=grep /\[stack\]/, <MAPS>;
($a,$b)=map hex, $m =~ /[\da-f]+/g;
open MEM, "/proc/$p/mem" or die "open mem: $!";
seek MEM,$a,0; read MEM, $c,$b-$a;
$c =~ /.*\0\0\K[^\0].*\0[^\0]*$/s;
@a=unpack"L!*",substr$c,0,$-[0];
for ($i = $#a; $i >=0 && $a[$i] != $a+$-[0];$i--) {}
for ($i--; $i >= 0 && ($a[$i]>$a || $a[$i]==0); $i--) {}
$argc=$a[$i++];
print for unpack"(Z*)$argc",substr$c,$a[$i]-$a;' "$!"
V zásadě to dělá totéž jako výše, ale jakmile najde první řetězec argv[]
(nebo alespoň jeden z argv[]
nebo envp[]
řetězce, pokud jsou prázdné), zná svou adresu, takže hledá ukazatel se stejnou hodnotou zpět v horním zbytku zásobníku. Pak se dívá zpět, dokud nenajde číslo, které nemůže být ukazatelem na ně, a to je argc
. Další celé číslo je pak argv[0]
. A znát argv[0]
a argc
, může zobrazit seznam argumentů.
To nefunguje, pokud proces zapsal do svého argv[]
možná přepíše některé oddělovače NUL nebo pokud argc
je 0 (argc
je obecně alespoň 1, aby zahrnoval argv[0]
), ale měl by fungovat v obecném případě alespoň pro spustitelné soubory ELF.
Ve verzi 4.2 a novějších /proc/<pid>/cmdline
již není zkrácen, ale ps
sám má maximální šířku displeje 128 kB.
Přidejte jeden nebo dva -w
vlajky. Dělá to výstup širší. např. ps auxww
.
V jádře Linuxu 4.2 a novějším /proc/<pid>/cmdline
již není zkrácen a následující funguje dobře:
xargs -0 printf '%s\n' < /proc/2755/cmdline