tracechild.cc revision 3115
12914SN/A/* 28856SN/A * Copyright (c) 2006 The Regents of The University of Michigan 38856SN/A * All rights reserved. 48856SN/A * 58856SN/A * Redistribution and use in source and binary forms, with or without 68856SN/A * modification, are permitted provided that the following conditions are 78856SN/A * met: redistributions of source code must retain the above copyright 88856SN/A * notice, this list of conditions and the following disclaimer; 98856SN/A * redistributions in binary form must reproduce the above copyright 108856SN/A * notice, this list of conditions and the following disclaimer in the 118856SN/A * documentation and/or other materials provided with the distribution; 128856SN/A * neither the name of the copyright holders nor the names of its 138856SN/A * contributors may be used to endorse or promote products derived from 142914SN/A * this software without specific prior written permission. 152914SN/A * 162914SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172914SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182914SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192914SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202914SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212914SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222914SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232914SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242914SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252914SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262914SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272914SN/A * 282914SN/A * Authors: Gabe Black 292914SN/A */ 302914SN/A 312914SN/A#include "tracechild.hh" 322914SN/A#include <sys/wait.h> 332914SN/A#include <sys/ptrace.h> 342914SN/A#include <iostream> 352914SN/A#include <errno.h> 362914SN/A 372914SN/Ausing namespace std; 382914SN/A 392914SN/Abool TraceChild::startTracing(const char * pathToFile, const char * arg) 402914SN/A{ 418856SN/A pid = fork(); 422914SN/A if(pid == -1) 432914SN/A { 448914Sandreas.hansson@arm.com cout << "fork failed" << endl; 458914Sandreas.hansson@arm.com return false; 463091SN/A } 472914SN/A else if(pid == 0) 482914SN/A { 498914Sandreas.hansson@arm.com //We're the child. Get things ready and then exec the 508914Sandreas.hansson@arm.com //program to trace. 518914Sandreas.hansson@arm.com 528914Sandreas.hansson@arm.com //Let our parent trace us 538914Sandreas.hansson@arm.com ptrace(PTRACE_TRACEME, 0, 0, 0); 542914SN/A 552914SN/A //Start the program to trace 568229SN/A execl(pathToFile, arg); 578229SN/A 582914SN/A //We should never get here, so this is an error! 599342SAndreas.Sandberg@arm.com return false; 609356Snilay@cs.wisc.edu } 612914SN/A 623091SN/A //From this point forward, we know we're in the parent process. 638914Sandreas.hansson@arm.com if(!doWait()) 648914Sandreas.hansson@arm.com { 653091SN/A cout << "Didn't wait successfully" << endl; 669342SAndreas.Sandberg@arm.com return false; 672914SN/A } 688914Sandreas.hansson@arm.com tracing = true; 694490SN/A if(!update(pid)) 704490SN/A { 714490SN/A cout << "Didn't update successfully!" << endl; 724490SN/A return false; 734490SN/A } 748948Sandreas.hansson@arm.com return true; 758948Sandreas.hansson@arm.com} 768948Sandreas.hansson@arm.com 774490SN/Abool TraceChild::stopTracing() 784490SN/A{ 794490SN/A if(ptrace(PTRACE_KILL, pid, 0, 0) != 0) 804490SN/A return false; 814490SN/A tracing = false; 824490SN/A return true; 833090SN/A} 843090SN/A 854490SN/Abool TraceChild::step() 864490SN/A{ 878914Sandreas.hansson@arm.com ptraceSingleStep(); 888914Sandreas.hansson@arm.com} 898914Sandreas.hansson@arm.com 904490SN/Abool TraceChild::ptraceSingleStep() 914490SN/A{ 924490SN/A if(!tracing) 933091SN/A { 942914SN/A cout << "Not tracing!" << endl; 958914Sandreas.hansson@arm.com return false; 963403SN/A } 978914Sandreas.hansson@arm.com if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0) != 0) 982914SN/A { 999342SAndreas.Sandberg@arm.com switch(errno) 1002914SN/A { 1019342SAndreas.Sandberg@arm.com case EBUSY: cout << "EBUSY" << endl; break; 1022914SN/A case EFAULT: cout << "EFAULT" << endl; break; 1038914Sandreas.hansson@arm.com case EIO: cout << "EIO" << endl; break; 1048914Sandreas.hansson@arm.com case EPERM: cout << "EPERM" << endl; break; 1058975Sandreas.hansson@arm.com case ESRCH: cout << "ESRCH" << endl; break; 1068975Sandreas.hansson@arm.com default: cout << "Unknown error" << endl; break; 1078914Sandreas.hansson@arm.com } 1084492SN/A cout << "Not able to single step!" << endl; 1094492SN/A tracing == false; 1104492SN/A return false; 1114492SN/A } 1124492SN/A doWait(); 1137823SN/A update(pid); 1144492SN/A} 1154871SN/A 1164666SN/Abool TraceChild::doWait() 1174666SN/A{ 1188708SN/A int wait_val; 1198914Sandreas.hansson@arm.com wait(&wait_val); 1208914Sandreas.hansson@arm.com if(WIFEXITED(wait_val)) 1218914Sandreas.hansson@arm.com { 1228914Sandreas.hansson@arm.com cerr << "Program exited! Exit status is " 1238914Sandreas.hansson@arm.com << WEXITSTATUS(wait_val) << endl; 1244492SN/A tracing = false; 1258856SN/A return false; 1268856SN/A } 1278856SN/A if(WIFSIGNALED(wait_val)) 1288856SN/A { 1298856SN/A if(WTERMSIG(wait_val)) 1308856SN/A cerr << "Program terminated by signal " 1318856SN/A << WTERMSIG(wait_val) << endl; 1328856SN/A if(WCOREDUMP(wait_val)) 1338856SN/A cerr << "Program core dumped!" << endl; 1348856SN/A tracing = false; 1358856SN/A return false; 1368975Sandreas.hansson@arm.com } 1378975Sandreas.hansson@arm.com if(WIFSTOPPED(wait_val) && WSTOPSIG(wait_val) != SIGTRAP) 1388975Sandreas.hansson@arm.com { 1398975Sandreas.hansson@arm.com cerr << "Program stopped by signal " 1408975Sandreas.hansson@arm.com << WSTOPSIG(wait_val) << endl; 1418856SN/A tracing = false; 1428856SN/A return false; 1438856SN/A } 1448856SN/A return true; 1458856SN/A} 1468856SN/A