Sous Linux, avec le ps
à partir de procps(-ng)
:
ps -fwwp 2755
Dans les versions Linux antérieures à 4.2, il est cependant encore limité (par le noyau (/proc/2755/cmdline
) à 4k) et vous ne pouvez pas en obtenir plus sauf en demandant au processus de vous le dire ou en utilisant un débogueur.
$ 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"
Pour imprimer le 4e argument avec jusqu'à 5 000 caractères :
(gdb) set print elements 5000
(gdb) p ubp_av[3]
Si vous voulez quelque chose de non intrusif, vous pouvez essayer d'obtenir les informations de /proc/2755/mem
(notez que si le kernel.yama.ptrace_scope
n'est pas défini sur 0, vous aurez besoin des autorisations de superutilisateur pour cela). Ce qui suit fonctionne pour moi (imprime tous les arguments et les variables d'environnement), mais je pense qu'il n'y a pas beaucoup de garantie (l'erreur et la gestion des entrées inattendues sont laissées en exercice au lecteur) :
$ 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
(remplace "$!"
avec l'identifiant du processus). Ce qui précède utilise le fait que Linux place les chaînes pointées par argv[]
, envp[]
et le nom du fichier exécuté en bas de la pile du processus.
Ce qui précède recherche dans cette pile la chaîne la plus basse entre deux ensembles de deux ou plusieurs octets NUL consécutifs. Cela ne fonctionne pas si l'un des arguments ou des chaînes env est vide, car vous aurez alors une séquence de 2 octets NUL au milieu de ces argv ou envp. De plus, nous ne savons pas où s'arrêtent les chaînes argv et où commencent celles envp.
Une solution pour cela serait d'affiner cette heuristique en regardant en arrière pour le contenu réel de argv[]
(les pointeurs). Ce qui suit fonctionne sur l'architecture i386 et amd64 pour les exécutables ELF au moins :
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;' "$!"
Fondamentalement, il fait la même chose que ci-dessus, mais une fois qu'il a trouvé la première chaîne de argv[]
(ou au moins un des argv[]
ou envp[]
chaînes s'il y a des vides), il connaît son adresse, donc il regarde en arrière dans le reste supérieur de la pile pour un pointeur avec cette même valeur. Puis continue de regarder en arrière jusqu'à ce qu'il trouve un nombre qui ne peut pas être un pointeur vers ceux-ci, et c'est argc
. Alors le prochain entier est argv[0]
. Et connaissant argv[0]
et argc
, il peut afficher la liste des arguments.
Cela ne fonctionne pas si le processus a écrit dans son argv[]
éventuellement en remplaçant certains délimiteurs NUL ou si argc
vaut 0 (argc
vaut généralement au moins 1 pour inclure argv[0]
) mais devrait fonctionner dans le cas général au moins pour les exécutables ELF.
Dans 4.2 et versions ultérieures, /proc/<pid>/cmdline
n'est plus tronqué, mais ps
lui-même a une largeur d'affichage maximale de 128K.
Ajoutez un ou deux -w
drapeaux. Cela rend la sortie plus large. par exemple. ps auxww
.
Dans le noyau Linux 4.2 et plus récent, /proc/<pid>/cmdline
n'est plus tronqué et ce qui suit fonctionne bien :
xargs -0 printf '%s\n' < /proc/2755/cmdline