tracechild.cc revision 3115
1955SN/A/*
2955SN/A * Copyright (c) 2006 The Regents of The University of Michigan
31762SN/A * All rights reserved.
4955SN/A *
5955SN/A * Redistribution and use in source and binary forms, with or without
6955SN/A * modification, are permitted provided that the following conditions are
7955SN/A * met: redistributions of source code must retain the above copyright
8955SN/A * notice, this list of conditions and the following disclaimer;
9955SN/A * redistributions in binary form must reproduce the above copyright
10955SN/A * notice, this list of conditions and the following disclaimer in the
11955SN/A * documentation and/or other materials provided with the distribution;
12955SN/A * neither the name of the copyright holders nor the names of its
13955SN/A * contributors may be used to endorse or promote products derived from
14955SN/A * this software without specific prior written permission.
15955SN/A *
16955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27955SN/A *
282665Ssaidi@eecs.umich.edu * Authors: Gabe Black
294762Snate@binkert.org */
30955SN/A
315522Snate@binkert.org#include "tracechild.hh"
326143Snate@binkert.org#include <sys/wait.h>
334762Snate@binkert.org#include <sys/ptrace.h>
345522Snate@binkert.org#include <iostream>
35955SN/A#include <errno.h>
365522Snate@binkert.org
37955SN/Ausing namespace std;
385522Snate@binkert.org
394202Sbinkertn@umich.edubool TraceChild::startTracing(const char * pathToFile, const char * arg)
405742Snate@binkert.org{
41955SN/A        pid = fork();
424381Sbinkertn@umich.edu        if(pid == -1)
434381Sbinkertn@umich.edu        {
44955SN/A                cout << "fork failed" << endl;
45955SN/A                return false;
46955SN/A        }
474202Sbinkertn@umich.edu        else if(pid == 0)
48955SN/A        {
494382Sbinkertn@umich.edu                //We're the child. Get things ready and then exec the
504382Sbinkertn@umich.edu                //program to trace.
514382Sbinkertn@umich.edu
526654Snate@binkert.org                //Let our parent trace us
535517Snate@binkert.org                ptrace(PTRACE_TRACEME, 0, 0, 0);
547674Snate@binkert.org
557674Snate@binkert.org                //Start the program to trace
566143Snate@binkert.org                execl(pathToFile, arg);
576143Snate@binkert.org
586143Snate@binkert.org                //We should never get here, so this is an error!
598233Snate@binkert.org                return false;
608233Snate@binkert.org        }
618233Snate@binkert.org
628233Snate@binkert.org        //From this point forward, we know we're in the parent process.
638233Snate@binkert.org        if(!doWait())
648233Snate@binkert.org        {
658233Snate@binkert.org                cout << "Didn't wait successfully" << endl;
668233Snate@binkert.org                return false;
678233Snate@binkert.org        }
688233Snate@binkert.org        tracing = true;
698233Snate@binkert.org        if(!update(pid))
708233Snate@binkert.org        {
718233Snate@binkert.org                cout << "Didn't update successfully!" << endl;
726143Snate@binkert.org                return false;
738233Snate@binkert.org        }
748233Snate@binkert.org        return true;
758233Snate@binkert.org}
766143Snate@binkert.org
776143Snate@binkert.orgbool TraceChild::stopTracing()
786143Snate@binkert.org{
796143Snate@binkert.org        if(ptrace(PTRACE_KILL, pid, 0, 0) != 0)
808233Snate@binkert.org                return false;
818233Snate@binkert.org        tracing = false;
828233Snate@binkert.org        return true;
836143Snate@binkert.org}
848233Snate@binkert.org
858233Snate@binkert.orgbool TraceChild::step()
868233Snate@binkert.org{
878233Snate@binkert.org        ptraceSingleStep();
886143Snate@binkert.org}
896143Snate@binkert.org
906143Snate@binkert.orgbool TraceChild::ptraceSingleStep()
914762Snate@binkert.org{
926143Snate@binkert.org        if(!tracing)
938233Snate@binkert.org        {
948233Snate@binkert.org                cout << "Not tracing!" << endl;
958233Snate@binkert.org                return false;
968233Snate@binkert.org        }
978233Snate@binkert.org        if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0) != 0)
986143Snate@binkert.org        {
998233Snate@binkert.org                switch(errno)
1008233Snate@binkert.org                {
1018233Snate@binkert.org                        case EBUSY: cout << "EBUSY" << endl; break;
1028233Snate@binkert.org                        case EFAULT: cout << "EFAULT" << endl; break;
1036143Snate@binkert.org                        case EIO: cout << "EIO" << endl; break;
1046143Snate@binkert.org                        case EPERM: cout << "EPERM" << endl; break;
1056143Snate@binkert.org                        case ESRCH: cout << "ESRCH" << endl; break;
1066143Snate@binkert.org                        default: cout << "Unknown error" << endl; break;
1076143Snate@binkert.org                }
1086143Snate@binkert.org                cout << "Not able to single step!" << endl;
1096143Snate@binkert.org                tracing == false;
1106143Snate@binkert.org                return false;
1116143Snate@binkert.org        }
1127065Snate@binkert.org        doWait();
1136143Snate@binkert.org        update(pid);
1148233Snate@binkert.org}
1158233Snate@binkert.org
1168233Snate@binkert.orgbool TraceChild::doWait()
1178233Snate@binkert.org{
1188233Snate@binkert.org        int wait_val;
1198233Snate@binkert.org        wait(&wait_val);
1208233Snate@binkert.org        if(WIFEXITED(wait_val))
1218233Snate@binkert.org        {
1228233Snate@binkert.org                cerr << "Program exited! Exit status is "
1238233Snate@binkert.org                        << WEXITSTATUS(wait_val) << endl;
1248233Snate@binkert.org                tracing = false;
1258233Snate@binkert.org                return false;
1268233Snate@binkert.org        }
1278233Snate@binkert.org        if(WIFSIGNALED(wait_val))
1288233Snate@binkert.org        {
1298233Snate@binkert.org                if(WTERMSIG(wait_val))
1308233Snate@binkert.org                        cerr << "Program terminated by signal "
1318233Snate@binkert.org                                << WTERMSIG(wait_val) << endl;
1328233Snate@binkert.org                if(WCOREDUMP(wait_val))
1338233Snate@binkert.org                        cerr << "Program core dumped!" << endl;
1348233Snate@binkert.org                tracing = false;
1358233Snate@binkert.org                return false;
1368233Snate@binkert.org        }
1378233Snate@binkert.org        if(WIFSTOPPED(wait_val) && WSTOPSIG(wait_val) != SIGTRAP)
1388233Snate@binkert.org        {
1398233Snate@binkert.org                cerr << "Program stopped by signal "
1408233Snate@binkert.org                        << WSTOPSIG(wait_val) << endl;
1418233Snate@binkert.org                tracing = false;
1428233Snate@binkert.org                return false;
1438233Snate@binkert.org        }
1448233Snate@binkert.org        return true;
1456143Snate@binkert.org}
1466143Snate@binkert.org