1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
|
#include "../config.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <iostream>
using namespace std;
int parent_wait_test()
{
int pfd[2];
if( pipe(pfd)!=0 ) {
perror("parent_wait_test: pipe creation error");
exit(1);
}
pid_t child1, child2, parent=getpid();
child1=fork();
if( child1==-1 ) {
perror("parent_wait_test: fork1 error");
exit(1);
}
if( child1==0 ) {
/* We are the first child - sync on the pipe and then exit */
close( pfd[1] ); /* Close the writing end */
char buffer;
if( read( pfd[0], &buffer, 1 )!=1 ) {
perror("parent_wait_test: child1 sync read error");
exit(1);
}
exit(0);
}
child2=fork();
if( child2==-1 ) {
perror("parent_wait_test: fork2 error");
kill( child1, SIGKILL );
exit(1);
}
if( child2==0 ) {
close( pfd[0] );
/* We are the second child - detach ourselves */
pid_t grandchild=fork();
if( grandchild==-1 ) {
perror("parent_wait_test: grandchild fork error");
exit(1);
}
if( grandchild==0 ) {
/* We are the grand child */
if( ptrace( PTRACE_ATTACH, child1, 0, 0 )!=0 ) {
perror("parent_wait_test: ptrace attach failed");
kill( child1, SIGKILL );
exit(1);
}
// Attched ok - free child1 to exit
write( pfd[1], "a", 1 );
close( pfd[1] );
// Now wait for the child to exit
int status;
while( waitpid( child1, &status, 0 )==child1 && !WIFEXITED(status) ) {
ptrace(PTRACE_CONT, child1, 0, 0);
}
// Sleep for a second (should be enough to make sure the parent waits successfully) and then kill the parent
sleep(1);
kill( parent, SIGKILL );
exit(0);
} else {
/* We are the second child */
exit(0);
}
}
/* We are the parent */
int status;
if( waitpid( child2, &status, 0 )<0 ) {
perror("parent_wait_test: wait(child2) failed");
kill( child1, SIGKILL);
exit(1);
}
if( !WIFEXITED(status) || WEXITSTATUS(status)!=0 ) {
// Something failed with the child
kill( child1, SIGKILL );
exit(1);
}
// Debugger child is ok (probably) - lets wait for the debuggee
if( waitpid( child1, &status, 0 )==child1 ) {
// Wait successful - make sure it really is
if( WIFEXITED(status) && WEXITSTATUS(status)==0 ) {
// Yes, everything is ok
return 1;
} else {
// The wait was successfull, but the subprocess not - exit with failure
exit(1);
}
} else {
// Maybe the wait failed, but maybe the system just told us that this process is not our child
if( errno==ECHILD ) {
// It's just that we cannot wait on this particular child. Signal the parent so
kill( parent, SIGKILL );
exit(1);
}
}
return 0;
}
int main()
{
cerr<<"Sizes: char "<<sizeof(char)<<", short "<<sizeof(short)<<", int "<<sizeof(int)<<", long "<<sizeof(long)<<", long long "<<sizeof(long long)<<
", void * "<<sizeof(void *)<<", size_t "<<sizeof(size_t)<<endl;
cerr<<"Sizes: pid_t "<<sizeof(pid_t)<<", gid_t "<<sizeof(gid_t)<<", dev_t "<<sizeof(dev_t)<<", ino_t "<<sizeof(ino_t)<<endl;
/* Check status of PTLIB_PARENT_CAN_WAIT */
pid_t child=fork();
if( child<0 ) {
perror("fork failed");
return 1;
}
if( child==0 ) {
/* Child processing */
if( parent_wait_test() )
exit(0);
exit(1);
} else {
/* Parent processing */
int status;
if( waitpid(child, &status, 0)==child ) {
if( WIFEXITED(status) && WEXITSTATUS(status)==0 ) {
/* Parent can wait */
printf("#define PTLIB_PARENT_CAN_WAIT 1\n");
} else if( WIFSIGNALED(status) && WTERMSIG(status)==SIGKILL ) {
printf("#define PTLIB_PARENT_CAN_WAIT 0\n");
} else {
fprintf(stderr, "Couldn't determine PTLIB_PARENT_CAN_WAIT value\n");
}
}
}
#if HAVE_PTRACE_GETREGS
/* Value for PTLIB_STATE_SIZE */
child=fork();
if( child<0 ) {
perror("Failed to create child process");
return 1;
}
if( child==0 ) {
/* We are the child */
ptrace( PTRACE_TRACEME, 0, 0, 0 );
kill( getpid(), SIGTRAP );
} else {
/* We are the parent */
int status;
waitpid( child, &status, 0 );
if( WIFSTOPPED(status) ) {
void *buffer[4096]; /* Large enough for sure */
int i=0;
int max1, max2;
/* Set the buffer to a known state */
for( i=0; i<4096; ++i )
buffer[i]=0;
/* Transfer registers */
ptrace(PTRACE_GETREGS, child, buffer, buffer);
/* The manual page says that only data (arg 4) is needed, but on some
* platforms addr (arg 3) is used instead */
/* Find out at least how high the buffer was filled */
for( max1=4095; max1>=0 && buffer[max1]==0; --max1)
buffer[max1]=(void*)1;
/* Transfer registers, again */
ptrace(PTRACE_GETREGS, child, buffer, buffer);
/* Find out at how high the buffer was filled when initialized to a differnet value */
for( max2=4095; max2>max1 && buffer[max2]==(void *)1; --max2)
;
/* Max2 is now how much data is being copied during a GETREGS call */
printf("#define PTLIB_STATE_SIZE (%d)\n", max2+1);
/* Kill the waiting process */
ptrace(PTRACE_KILL, child, 0, 0);
waitpid(child, &status, 0 );
} else {
fprintf(stderr, "Error: child %d did not trace correctly\n", child);
return 1;
}
}
#endif /* PTRACE_GETREGS */
return 0;
}
|