2012-11-23 16 views
7

मैं प्रक्रिया के सिस्कोल का पता लगाने के लिए ptrace का उपयोग कर रहा हूं। प्रक्रिया को फोर्क करने के बाद, मैं प्रक्रिया का पता लगाने के लिए PTRACE_TRACEME का उपयोग करता हूं। कोड इस तरह दिखता है:किसी प्रक्रिया के सभी ट्रेसिंग सिस्कोल्स और सभी फोर्कड प्रक्रिया

while (true) { 
    int status; 
    int gotPid; 
    gotPid = waitpid(pid, &status, 0); 

    if (WIFEXITED(status) || WIFSIGNALED(status)) { 
     break; 
    } 

    if (WIFSTOPPED(status)) { 
     handleTrace(); 
    } 
} 

तो फिर वहाँ है handleTrace समारोह है, जो इस तरह दिखता है।

long syscall; 
syscall = ptrace(PTRACE_PEEKUSER, 
    pid, 8 * ORIG_RAX, NULL); 

// do something with the syscall 

// continue program 
ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 

यह सब अच्छा है, लेकिन प्रक्रियाओं का पता लगाया प्रक्रिया (और यह भी प्रक्रिया द्वारा बनाई धागे) बनाता है, तो कार्यक्रम कांटे (या एक नया धागा बनाता है) मैं भी बच्चे को पता लगाने के लिए चाहते हैं। मुझे पता है कि यह PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK और PTRACE_O_TRACECLONE का उपयोग करके किया जा सकता है, लेकिन man दस्तावेज से, यह पता लगाना बहुत मुश्किल है कि यह वास्तव में कैसे किया जाता है। मुझे इस पर कुछ उदाहरण चाहिए।

संपादित करें:

मैं एक ऐसी ही सवाल मिली: How to ptrace a multi-threaded application? मैं निम्नलिखित कोड के साथ की कोशिश की। यह कोड प्रारंभ प्रक्रिया की सिस्टम कॉल को ट्रैक करता है और यह भी फोर्क प्रक्रियाओं को ट्रैक करना है। यह माता-पिता प्रक्रिया में fork() के बाद चलाया जाता है (बच्चा PTRACE_TRACEME और exec() पर कॉल करता है)।

EDIT2:

मैं कुछ और संशोधनों कोड पर, कुछ और प्रगति के साथ बनाया है।

long orig_eax; 
int status; 
int numPrograms = 1; 

while(1) { 
    int pid; 
    CHECK_ERROR_VALUE(pid = waitpid(-1, &status, __WALL)); 
    std::cout << pid << ": Got event." << std::endl; 
    if(WIFEXITED(status) || WIFSIGNALED(status)) { 
     std::cout << pid << ": Program exited." << std::endl; 
     if (--numPrograms == 0) { 
      break; 
     } 
     continue; 
    } 

    if (status >> 16 == PTRACE_EVENT_FORK || status >> 16 == PTRACE_EVENT_VFORK || 
      status >> 16 == PTRACE_EVENT_CLONE) { 
     int newpid; 
     CHECK_ERROR_VALUE(ptrace(PTRACE_GETEVENTMSG, child, NULL, (long) &newpid)); 
     std::cout << pid << ": Attached to offspring " << newpid << std::endl; 
     boost::this_thread::sleep(boost::posix_time::millisec(100)); 
     CHECK_ERROR_VALUE(ptrace(PTRACE_SETOPTIONS, 
       newpid, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE)); 
     CHECK_ERROR_VALUE(ptrace(PTRACE_SYSCALL, newpid, NULL, NULL)); 
     ++numPrograms; 
    } else { 
     CHECK_ERROR_VALUE(ptrace(PTRACE_SETOPTIONS, 
       pid, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE)); 
     CHECK_ERROR_VALUE(orig_eax = ptrace(PTRACE_PEEKUSER, 
       pid, 8 * ORIG_RAX, NULL)); 
     std::cout << pid << ": Syscall called: " << 
       SyscallMap::instance().get().right.at(orig_eax) << 
       std::endl; 
     CHECK_ERROR_VALUE(ptrace(PTRACE_SYSCALL, 
       pid, NULL, NULL)); 
    } 

} 

CHECK_ERROR_VALUE सिर्फ एक मैक्रो परिणाम कोड की जाँच करता है और उस में errno के विवरण के साथ एक अपवाद फेंक है।

जाहिर है, जब मुझे एक कांटा/क्लोन की घटना मिलती है तो नई प्रक्रिया अभी तक मौजूद नहीं है, और मुझे एक "प्रक्रिया मौजूद नहीं है" त्रुटि संदेश मिलता है यदि मैं इसे पट्रेस करने का प्रयास करता हूं। अगर मैं नई प्रक्रिया को छेड़छाड़ करने की कोशिश करने से पहले नींद डालता हूं, तो मुझे एक त्रुटि संदेश नहीं मिलता है। अब जब कार्यक्रम कांटा/क्लोन के बिंदु पर जाता है, तो यह नई प्रक्रिया का पता लगाना शुरू कर देता है, लेकिन यह माता-पिता प्रक्रिया में clone() सिस्कल के रिटर्न पॉइंट तक कभी नहीं पहुंचता है, जिसका अर्थ है कि बच्चा सफलतापूर्वक खत्म हो जाता है, लेकिन माता-पिता लटकता है अपने कांटा बिंदु पर।

उत्तर

1

strace इस करता है और यह README.linux फ़ाइल इस विषय पर कुछ जानकारी नहीं है है:

http://strace.git.sourceforge.net/git/gitweb.cgi?p=strace/strace;a=blob;f=README-linux-ptrace;h=97e2c019a075f216f125f8b9aa6da68fa2abf230;hb=refs/heads/master

यह है, तो YMMV इस मंच में गिरी कीड़े के बारे में शिकायत कर रहे है।

कोड बताता है कि बच्चे के पिड को कैसे प्राप्त किया जाए। हालांकि यह संभव हो सकता है कि बच्चे को कॉलिड या सेटगिड बिट्स के कारण कॉलरिड बिट्स सेट के कारण एक और उपयोगकर्ता आईडी मिल जाए। तो जवाब यह है कि आप बच्चे पीआईडी ​​पर ptrace कहते हैं और देखें कि क्या आप पहुंच प्राप्त करते हैं।

PTRACE_EVENT stops are observed by tracer as waitpid returning with 
WIFSTOPPED(status) == true, WSTOPSIG(status) == SIGTRAP. Additional bit 
is set in a higher byte of status word: value ((status >> 8) & 0xffff) 
will be (SIGTRAP | PTRACE_EVENT_foo << 8). The following events exist: 

PTRACE_EVENT_VFORK - stop before return from vfork/clone+CLONE_VFORK. 
When tracee is continued after this, it will wait for child to 
exit/exec before continuing its execution (IOW: usual behavior on 
vfork). 

PTRACE_EVENT_FORK - stop before return from fork/clone+SIGCHLD 

PTRACE_EVENT_CLONE - stop before return from clone 

PTRACE_EVENT_VFORK_DONE - stop before return from 
vfork/clone+CLONE_VFORK, but after vfork child unblocked this tracee by 
exiting or exec'ing. 

For all four stops described above: stop occurs in parent, not in newly 
created thread. PTRACE_GETEVENTMSG can be used to retrieve new thread's 
tid. 
:

यहाँ प्रासंगिक अनुभाग है