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