././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9415317 python-ptrace-0.9.8/0000775000175000017500000000000000000000000014632 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/COPYING0000664000175000017500000004313300000000000015671 0ustar00vstinnervstinner GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/MANIFEST.in0000664000175000017500000000112600000000000016370 0ustar00vstinnervstinnerinclude AUTHORS include COPYING include ChangeLog include INSTALL include MANIFEST.in include README.cptrace include TODO include tox.ini include SYSCALL_PROTOTYPES.codegen.py include cptrace/Makefile include cptrace/cptrace.c include cptrace/version.py include doc/*.rst doc/conf.py doc/make.bat doc/Makefile include examples/itrace.py include examples/simple_dbg.py include pyflakes.sh include python3.0.patch include setup_cptrace.py # Tests include runtests.py include test_doc.py include tests/test_*.py include tests/crash/*.c include tests/crash/BSDmakefile include tests/crash/Makefile ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9415317 python-ptrace-0.9.8/PKG-INFO0000664000175000017500000000333400000000000015732 0ustar00vstinnervstinnerMetadata-Version: 1.1 Name: python-ptrace Version: 0.9.8 Summary: python binding of ptrace Home-page: http://python-ptrace.readthedocs.io/ Author: Victor Stinner Author-email: UNKNOWN License: GNU GPL v2 Download-URL: http://python-ptrace.readthedocs.io/ Description: ============= python-ptrace ============= .. image:: https://img.shields.io/pypi/v/python-ptrace.svg :alt: Latest release on the Python Cheeseshop (PyPI) :target: https://pypi.python.org/pypi/python-ptrace .. image:: https://github.com/vstinner/python-ptrace/actions/workflows/build.yml/badge.svg :alt: Build status of python-ptrace on GitHub Actions :target: https://github.com/vstinner/python-ptrace/actions python-ptrace is a debugger using ptrace (Linux, BSD and Darwin system call to trace processes) written in Python. * `python-ptrace documentation `_ * `python-ptrace at GitHub `_ * `python-ptrace at the Python Cheeseshop (PyPI) `_ python-ptrace is an opensource project written in Python under GNU GPLv2 license. It supports Python 3.6 and newer. Platform: UNKNOWN Classifier: Intended Audience :: Developers Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Operating System :: OS Independent Classifier: Natural Language :: English Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1616012250.0 python-ptrace-0.9.8/README.rst0000664000175000017500000000161100000000000016320 0ustar00vstinnervstinner============= python-ptrace ============= .. image:: https://img.shields.io/pypi/v/python-ptrace.svg :alt: Latest release on the Python Cheeseshop (PyPI) :target: https://pypi.python.org/pypi/python-ptrace .. image:: https://github.com/vstinner/python-ptrace/actions/workflows/build.yml/badge.svg :alt: Build status of python-ptrace on GitHub Actions :target: https://github.com/vstinner/python-ptrace/actions python-ptrace is a debugger using ptrace (Linux, BSD and Darwin system call to trace processes) written in Python. * `python-ptrace documentation `_ * `python-ptrace at GitHub `_ * `python-ptrace at the Python Cheeseshop (PyPI) `_ python-ptrace is an opensource project written in Python under GNU GPLv2 license. It supports Python 3.6 and newer. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/SYSCALL_PROTOTYPES.codegen.py0000664000175000017500000000252400000000000021534 0ustar00vstinnervstinner#!/usr/bin/env python """ Generates the SYSCALL_PROTOTYPES dictionary from the Linux kernel source and prints out Python code representing it. """ import urllib2 import re url = "https://raw.githubusercontent.com/torvalds/linux/master/include/linux/syscalls.h" source = urllib2.urlopen(url).read() p1 = re.compile(r"^asmlinkage long sys(?:32)?_(.*?)\((.*?)\)", re.MULTILINE | re.DOTALL) p2 = re.compile(r"^(.*?)([^ *]+)$") SYSCALL_PROTOTYPES = {} for m1 in p1.finditer(source): call_name = m1.group(1) args = m1.group(2) args = args.replace("__user", "") args = " ".join(args.split()) args_tuple = () if args != "void": for arg in args.split(","): if arg.endswith(("*", "long", "int", "size_t")): arg_type = arg.strip() arg_name = "" else: m2 = p2.match(arg) arg_type = m2.group(1).strip() arg_name = m2.group(2).strip() args_tuple += ((arg_type, arg_name),) SYSCALL_PROTOTYPES[call_name] = ("long", args_tuple) for call_name in sorted(SYSCALL_PROTOTYPES): signature = SYSCALL_PROTOTYPES[call_name] args_tuple = signature[1] print('"%s": ("%s", (' % (call_name, signature[0])) for arg in args_tuple: print((' ("%s", "%s"),' % (arg[0], arg[1]))) print(')),') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9325316 python-ptrace-0.9.8/cptrace/0000775000175000017500000000000000000000000016253 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/cptrace/Makefile0000664000175000017500000000033300000000000017712 0ustar00vstinnervstinnerCC=gcc CFLAGS=-fPIC -shared -Wall -Wextra -Wextra $(shell python-config --cflags) LIBS=$(shell python-config --libs) LIBRARY=cptrace.so $(LIBRARY): cptrace.c $(CC) -o $@ $< $(CFLAGS) $(LIBS) clean: rm -f $(LIBRARY) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/cptrace/cptrace.c0000664000175000017500000000501200000000000020036 0ustar00vstinnervstinner#include #include #if __APPLE__ #include #endif #include #define UNUSED(arg) arg __attribute__((unused)) char python_ptrace_DOCSTR[] = "ptrace(command: int, pid: int, arg1=0, arg2=0, check_errno=False): call ptrace syscall.\r\n" "Raise a ValueError on error.\r\n" "Returns an unsigned integer.\r\n"; static bool cpython_cptrace( unsigned int request, pid_t pid, void *arg1, void *arg2, bool check_errno, unsigned long *result) { unsigned long ret; errno = 0; ret = ptrace(request, pid, arg1, arg2); if ((long)ret == -1) { /** * peek operations may returns -1 with errno=0: it's not an error. * For other operations, -1 is always an error */ if (!check_errno || errno) { PyErr_Format( PyExc_ValueError, "ptrace(request=%u, pid=%i, %p, %p) " "error #%i: %s", request, pid, arg1, arg2, errno, strerror(errno)); return false; } } if (result) *result = ret; return true; } static PyObject* cpython_ptrace(PyObject* UNUSED(self), PyObject *args, PyObject *keywds) { unsigned long result; unsigned int request; pid_t pid; unsigned long arg1 = 0; unsigned long arg2 = 0; bool check_errno = false; PyObject* check_errno_p = NULL; static char *kwlist[] = {"request", "pid", "arg1", "arg2", "check_errno", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "Ii|LLO", kwlist, &request, &pid, &arg1, &arg2, &check_errno_p )) { return NULL; } if (check_errno_p) { check_errno = PyObject_IsTrue(check_errno_p); } if (cpython_cptrace(request, pid, (void*)arg1, (void*)arg2, check_errno, &result)) return PyLong_FromUnsignedLong(result); else return NULL; } static PyMethodDef module_methods[] = { {"ptrace", (PyCFunction)cpython_ptrace, METH_VARARGS | METH_KEYWORDS, python_ptrace_DOCSTR}, {NULL, NULL, 0, NULL} }; PyDoc_STRVAR(module_doc, "ptrace module written in C"); #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef module_def = { PyModuleDef_HEAD_INIT, "cptrace", module_doc, 0, module_methods, NULL }; #endif PyMODINIT_FUNC #if PY_MAJOR_VERSION >= 3 PyInit_cptrace(void) #else initcptrace(void) #endif { #if PY_MAJOR_VERSION >= 3 return PyModule_Create(&module_def); #else (void)Py_InitModule3("cptrace", module_methods, module_doc); #endif } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/cptrace/version.py0000664000175000017500000000015600000000000020314 0ustar00vstinnervstinnerPACKAGE = "cptrace" VERSION = "0.6.1" WEBSITE = "http://python-ptrace.readthedocs.io/" LICENSE = "GNU GPL v2" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9345315 python-ptrace-0.9.8/doc/0000775000175000017500000000000000000000000015377 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/doc/Makefile0000664000175000017500000001272700000000000017050 0ustar00vstinnervstinner# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python-ptrace.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python-ptrace.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/python-ptrace" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/python-ptrace" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/doc/authors.rst0000664000175000017500000000122200000000000017613 0ustar00vstinnervstinner+++++++ Authors +++++++ Contributors ============ * Anthony Gelibert - fix cptrace on Apple * Dimitris Glynos - follow gdb.py commands * Jakub Wilk - fix for GNU/kFreeBSD * Mark Seaborn - Create -i option for strace * Mickaël Guérin aka KAeL - OpenBSD port * teythoon - convert all classes to new-style classes * T. Bursztyka aka Tuna - x86_64 port * Victor Stinner - python-ptrace author and maintainer Thanks ====== * procps authors (top and uptime programs) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1616012314.0 python-ptrace-0.9.8/doc/changelog.rst0000664000175000017500000002175000000000000020065 0ustar00vstinnervstinner.. _changelog: Changelog ========= python-ptrace 0.9.8 ------------------- * Added Arm 64bit (AArch64) support. * Implemented ``PTRACE_GETREGSET`` and ``PTRACE_SETREGSET`` required on AArch64 and available on Linux. * Issue #66: Fix ``SIGTRAP|0x80`` or ``SIGTRAP`` wait in syscall_state.exit (``PTRACE_O_TRACESYSGOOD``). * The development branch ``master`` was renamed to ``main``. See https://sfconservancy.org/news/2020/jun/23/gitbranchname/ for the rationale. python-ptrace 0.9.7 (2020-08-10) -------------------------------- * Add missing module to install directives * Update README.rst * Project back in beta and maintenance python-ptrace 0.9.6 (2020-08-10) -------------------------------- * Remove RUNNING_WINDOWS constant: python-ptrace doesn't not support Windows. * Drop Python 2.7 support. six dependency is no longer needed. * Add close_fds and pass_fds to createChild() function. Patch by Jean-Baptiste Skutnik. * Enhance strace.py output for open flags and open optional parameters. Patch by Jean-Baptiste Skutnik. * Add support for PowerPC 64-bit (ppc64). Patch by Jean-Baptiste Skutnik. python-ptrace 0.9.5 (2020-04-13) -------------------------------- * Fix readProcessMappings() for device id on 3 digits. Patch by Cat Stevens. * Drop Python 2 support. python-ptrace 0.9.4 (2019-07-30) -------------------------------- * Issue #36: Fix detaching from process object created without is_attached=True * The project now requires the six module. * Project moved to: https://github.com/vstinner/python-ptrace python-ptrace 0.9.3 (2017-09-19) -------------------------------- * Issue #42: Fix test_strace.py: tolerate the openat() syscall. python-ptrace 0.9.2 (2017-02-12) -------------------------------- * Issue #35: Fix strace.py when tracing multiple processes: use the correct process. Fix suggested by Daniel Trnka. python-ptrace 0.9.1 (2016-10-12) -------------------------------- * Added tracing of processes created with the clone syscall (commonly known as threads). * gdb.py: add ``gcore`` command, dump the process memory. * Allow command names without absolute path. * Fix ptrace binding: clear errno before calling ptrace(). * Fix PtraceSyscall.exit() for unknown error code * Project moved to GitHub: https://github.com/haypo/python-ptrace * Remove the ``ptrace.ctypes_errno`` module: use directly the ``ctypes.get_errno()`` function * Remove the ``ptrace.ctypes_errno`` module: use directly ``ctypes.c_int8``, ``ctypes.c_uint32``, ... types python-ptrace 0.9 (2016-04-23) ------------------------------ * Add all Linux syscall prototypes * Add error symbols (e.g. ENOENT), in addition to error text, for strace * Fix open mode so O_RDONLY shows if it's the only file access mode * Python 3: fix formatting of string syscall arguments (ex: filenames), decode bytes from the locale encoding * Issue #17: syscall parser now supports O_CLOEXEC and SOCK_CLOEXEC, fix unit tests on Python 3.4 and newer python-ptrace 0.8.1 (2014-10-30) -------------------------------- * Update MANIFEST.in to include all files * Fix to support Python 3.5 python-ptrace 0.8 (2014-10-05) ------------------------------ * Issue #9: Rewrite waitProcessEvent() and waitSignals() methods of PtraceProcess to not call waitpid() with pid=-1. There is a race condition with waitpid(-1) and fork, the status of the child process may be returned before the debugger is noticed of the creation of the new child process. * Issue #10: Fix PtraceProcess.readBytes() for processes not created by the debugger (ex: fork) if the kernel blocks access to private mappings of /proc/pid/mem. Fallback to PTRACE_PEEKTEXT which is slower but a debugger tracing the process is always allowed to use it. python-ptrace 0.7 (2013-03-05) ------------------------------ * Experimental support of Python 3.3 in the same code base * Drop support of Python 2.5 * Remove the ptrace.compatibility module * Fix Process.readStruct() and Process.readArray() on x86_64 * Experimental support of ARM architecture (Linux EAPI), strace.py has been tested on Raspberry Pi (armv6l) python-ptrace 0.6.6 (2013-12-16) -------------------------------- * Fix os_tools.RUNNING_LINUX for Python 2.x compiled on Linux kernel 3.x * Support FreeBSD on x86_64 * Add missing prototype of the unlinkat() system call. Patch written by Matthew Fernandez. python-ptrace 0.6.5 (2013-06-06) -------------------------------- * syscall: fix parsing socketcall on Linux x86 * syscall: fix prototype of socket() python-ptrace 0.6.4 (2012-02-26) -------------------------------- * Convert all classes to new-style classes, patch written by teythoon * Fix compilation on Apple, patch written by Anthony Gelibert * Support GNU/kFreeBSD, patch written by Jakub Wilk * Support sockaddr_in6 (IPv6 address) python-ptrace 0.6.3 (2011-02-16) -------------------------------- * Support distrom3 * Support Python 3 * Rename strace.py option --socketcall to --socket, and fix this option for FreeBSD and Linux/64 bits * Add MANIFEST.in: include all files in source distribution (tests, cptrace module, ...) python-ptrace 0.6.2 (2009-11-09) -------------------------------- * Fix 64 bits sub registers (set mask for eax, ebx, ecx, edx) python-ptrace 0.6.1 (2009-11-07) -------------------------------- * Create follow, showfollow, resetfollow, xray commands in gdb.py. Patch written by Dimitris Glynos * Project website moved to: ``http://bitbucket.org/haypo/python-ptrace/`` * Replace types (u)intXX_t by c_(u)intXX * Create MemoryMapping.search() method and MemoryMapping now keeps a weak reference to the process python-ptrace 0.6 (2009-02-13) ------------------------------ User visible changes: * python-ptrace now depends on Python 2.5 * Invalid memory access: add fault address in the name * Update Python 3.0 conversion patch * Create -i (--show-ip) option to strace.py: show instruction pointer * Add a new example (itrace.py) written by Mark Seaborn and based on strace.py API changes: * PtraceSyscall: store the instruction pointer at syscall enter (if the option instr_pointer=True, disabled by default) * Remove PROC_DIRNAME and procFilename() from ptrace.linux_proc Bugfixes: * Fix locateProgram() for relative path * Fix interpretation of memory fault on MOSVW instruction (source is ESI and destination is EDI, and not the inverse!) python-ptrace 0.5 (2008-09-13) ------------------------------ Visible changes: * Write an example (the most simple debugger) and begin to document the code * gdb.py: create "dbginfo" command * Parse socket syscalls on FreeBSD * On invalid memory access (SIGSEGV), eval the dereference expression to get the fault address on OS without siginfo (e.g. FreeBSD) * Fixes to get minimal Windows support: fix imports, fix locateProgram() Other changes: * Break the API: - Rename PtraceDebugger.traceSysgood() to PtraceDebugger.enableSysgood() - Rename PtraceDebugger.trace_sysgood to PtraceDebugger.use_sysgood - Remove PtraceProcess.readCode() * Create createChild() function which close all files except stdin, stdout and stderr * On FreeBSD, on process exit recalls waitpid(pid) to avoid zombi process python-ptrace 0.4.2 (2008-08-28) -------------------------------- * BUGFIX: Fix typo in gdb.py (commands => command_str), it wasn't possible to write more than one command... * BUGFIX: Fix typo in SignalInfo class (remove "self."). When a process received a signal SIGCHLD (because of a fork), the debugger exited because of this bug. * BUGFIX: Debugger._wait() return abnormal process exit as a normal event, the event is not raised as an exception * PtraceSignal: don't clear preformatted arguments (e.g. arguments of execve) python-ptrace 0.4.1 (2008-08-23) -------------------------------- * The project has a new dedicated website: http://python-ptrace.hachoir.org/ * Create cptrace: optional Python binding of ptrace written in C (faster than ptrace, the Python binding written in Python with ctypes) * Add name attribute to SignalInfo classes * Fixes to help Python 3.0 compatibility: don't use sys.exc_clear() (was useless) in writeBacktrace() * ProcessState: create utime, stime, starttime attributes python-ptrace 0.4.0 (2008-08-19) -------------------------------- Visible changes: * Rename the project to "python-ptrace" (old name was "Ptrace) * strace.py: create --ignore-regex option * PtraceSignal: support SIGBUS, display the related registers and the instruction * Support execve() syscall tracing Developer changes: * New API is incompatible with 0.3.2 * PtraceProcess.waitProcessEvent() accepts optional blocking=False argument * PtraceProcess.getreg()/setreg() are able to read/write i386 and x86-64 "sub-registers" like al or bx * Remove iterProc() function, replaced by openProc() with explicit call to .close() to make sure that files are closed * Create searchProcessesByName() * Replace CPU_PPC constant by CPU_POWERPC and create CPU_PPC32 and CPU_PPC64 * Create MemoryMapping object, used by readMappings() and findStack() methods of PtraceProcess * Always define all PtraceProcess methods but raise an error if the function is not implemented ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/doc/conf.py0000664000175000017500000001641700000000000016707 0ustar00vstinnervstinner# -*- coding: utf-8 -*- # # python-ptrace documentation build configuration file, created by # sphinx-quickstart on Mon Mar 31 10:08:56 2014. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'python-ptrace' copyright = u'2014, Victor Stinner' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = release = '0.9.8' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'python-ptracedoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'python-ptrace.tex', u'python-ptrace Documentation', u'Victor Stinner', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'python-ptrace', u'python-ptrace Documentation', [u'Victor Stinner'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'python-ptrace', u'python-ptrace Documentation', u'Victor Stinner', 'python-ptrace', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/doc/cptrace.rst0000664000175000017500000000056400000000000017557 0ustar00vstinnervstinner+++++++++++++++++++++ cptrace Python module +++++++++++++++++++++ Python binding for ptrace written in C. Example ======= Dummy example: :: >>> import cptrace >>> cptrace.ptrace(1, 1) Traceback (most recent call last): File "", line 1, in ValueError: ptrace(request=1, pid=1, 0x(nil), 0x(nil)) error #1: Operation not permitted ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/doc/gdb.rst0000664000175000017500000000605700000000000016675 0ustar00vstinnervstinner++++++ gdb.py ++++++ ``gdb.py`` is a command line debugger *similar to gdb*, but with fewer features: no symbol support, no C language support, no thread support, etc. Some commands ============= * ``cont``: continue execution * ``stepi``: execute one instruction * ``step``: execute one instruction, but don't enter into calls Type ``help`` to list all available commands. Features ======== * print command displays value as decimal and hexadecimal, but also the related memory mapping (if any):: (gdb) print $eip Decimal: 3086383120 Hexadecimal: 0xb7f67810 Address is part of mapping: 0xb7f67000-0xb7f81000 => /lib/ld-2.6.1.so (r-xp) * Nice output of signal: see [[signal|python-ptrace signal handling]] * Syscall tracer with command "sys": see `python-ptrace system call tracer `. Short example:: (gdb) sys long access(char* filename='/etc/ld.so.nohwcap' at 0xb7f7f35b, int mode=F_OK) = -2 (No such file or directory) * Supports multiple processes:: (gdb) proclist (active) (gdb) proc Process ID: 24187 (parent: 24182) Process state: T (traced) Process command line: [['tests/fork_execve'] (...) (gdb)|switch; proc Switch to Process ID: 24188 (parent: 24187) Process state: T (traced) Process command line: ['/bin/ls']] (...) * Allow multiple commands on the same line using ";" separator:: (gdb) print $eax; set $ax=0xdead; print $eax Decimal: 0 Hexadecimal: 0x00000000 Set $ax to 57005 Decimal: 57005 Hexadecimal: 0x0000dead * Only written in pure Python code, so it's easy to extend * Expression parser supports all arithmetic operator (``a+b``, ``a/b``, ``a< Quit gdb. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1586774186.0 python-ptrace-0.9.8/doc/index.rst0000664000175000017500000000734100000000000017245 0ustar00vstinnervstinner============= python-ptrace ============= .. image:: http://unmaintained.tech/badge.svg :target: http://unmaintained.tech/ :alt: No Maintenance Intended **This project is no longer maintained and is looking for a new maintainer.** python-ptrace is a debugger using ptrace (Linux, BSD and Darwin system call to trace processes) written in Python. * `python-ptrace documentation `_ * `python-ptrace at GitHub `_ * `python-ptrace at the Python Cheeseshop (PyPI) `_ python-ptrace is an opensource project written in Python under GNU GPLv2 license. It supports Python 3.6 and newer. Features ======== * High level Python object API : PtraceDebugger and PtraceProcess * Able to control multiple processes: catch fork events on Linux * Read/write bytes to arbitrary address: take care of memory alignment and split bytes to cpu word * Execution step by step using ptrace_singlestep() or hardware interruption 3 * Can use `distorm `_ disassembler * Dump registers, memory mappings, stack, etc. * :ref:`Syscall tracer and parser ` (strace.py command) Status: * Supported operating systems: Linux, FreeBSD, OpenBSD * Supported architectures: x86, x86_64 (Linux), PPC (Linux), ARM (Linux EAPI) Missing features: * Symbols: it's not possible to break on a function or read a variable value * No C language support: debugger shows assembler code, not your C (C++ or other language) code! * No thread support Table of Contents ================= .. toctree:: :maxdepth: 2 install usage syscall gdb process_events ptrace_signal cptrace authors changelog todo Links ===== Project using python-ptrace --------------------------- * `Fusil the fuzzer `_ python-ptrace announces ----------------------- * `fuzzing mailing list `_ * `reverse-engineering.net `_ ptrace usage ------------ * Sandboxing: `Plash `_ Similar projects ---------------- * `vtrace `_: Python library (Windows and Linux) supporting threads * `subterfuge `_ by Mike Coleman: Python library (Linux): contains Python binding of ptrace written in C for Python 2.1/2.2. It doesn't work with Python 2.5 (old project, not maintained since 2002) * `strace `_ program (Linux, BSD) * ltrace program (Linux) * truss program (Solaris and BSD) * `pytstop `_ by Philippe Biondi: debugger similar to gdb but in very alpha stage (e.g. no disassembler), using ptrace Python binding written in C (from subterfuge) * `strace.py `_ by Philippe Biondi * `Fenris `_: suite of tools suitable for code analysis, debugging, protocol analysis, reverse engineering, forensics, diagnostics, security audits, vulnerability research * `PyDBG `_: Windows debugger written in pure Python Interesting articles ----------------------- * (fr) `Surveiller les connexions avec auditd `_ (2007) * `Playing with ptrace() for fun and profit `_ (2006) * `PTRACE_SETOPTIONS tests `_ (2005) * `Process Tracing Using Ptrace `_ (2002) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1586774181.0 python-ptrace-0.9.8/doc/install.rst0000664000175000017500000000401500000000000017577 0ustar00vstinnervstinner+++++++++++++++++++++ Install python-ptrace +++++++++++++++++++++ python-ptrace supports Python 3.6 and newer. Linux packages ============== * Debian: `python-ptrace Debian package `_. * Mandriva: `python-ptrace Mandriva package `_ * OpenEmbedded: `python-ptrace recipe `_ * Arch Linux: `python-ptrace Arch Linux package `_ * Gentoo: `dev-python/python-ptrace `_ See also `python-ptrace on Python Package Index (PyPI) `_ Install from source =================== Download tarball ---------------- Get the latest tarball at the `Python Package Index (PyPI) `_. Download development version ---------------------------- Download the development version using Git:: git clone https://github.com/vstinner/python-ptrace.git `Browse python-ptrace source code `_. Option dependency ----------------- * distorm disassembler (optional) http://www.ragestorm.net/distorm/ Installation ------------ Note: pip is strongly recommanded. Type as root:: python3 setup.py install Or using sudo program:: sudo python3 setup.py install cptrace ======= For faster debug and to avoid ctypes, you can also install cptrace: Python binding of the ptrace() function written in C:: python3 setup_cptrace.py install Run tests ========= Run tests with tox ------------------ To run all tests, just type:: tox The `tox project `_ creates a clean virtual environment to run tests. Run tests manually ------------------ Type:: python3 runtests.py python3 test_doc.py It's also possible to run a specific test:: PYTHONPATH=$PWD python3 tests/test_strace.py ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/doc/make.bat0000664000175000017500000001176600000000000017017 0ustar00vstinnervstinner@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\python-ptrace.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\python-ptrace.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/doc/process_events.rst0000664000175000017500000000362300000000000021177 0ustar00vstinnervstinner++++++++++++++++++++++++++++ python-ptrace process events ++++++++++++++++++++++++++++ Process events ============== All process events are based on ProcessEvent class. * ProcessExit: process exited with an exitcode, killed by a signal or exited abnormally * ProcessSignal: process received a signal * NewProcessEvent: new process created, e.g. after a fork() syscall Attributes: * All events have a "process" attribute * ProcessExit has "exitcode" and "signum" attributes (both can be None) * ProcessSignal has "signum" and "name" attributes For NewProcessEvent, use process.parent attribute to get the parent process. Note: ProcessSignal has a display() method to display its content. Use it just after receiving the message because it reads process memory to analyze the reasons why the signal was sent. Wait for any process event ========================== The most generic function is waitProcessEvent(): it waits for any process event (exit, signal or new process): :: event = debugger.waitProcessEvent() To wait one or more signals, use waitSignals() methods. With no argument, it waits for any signal. Events different than signal are raised as Python exception. Examples: :: signal = debugger.waitSignals() signal = debugger.waitSignals(SIGTRAP) signal = debugger.waitSignals(SIGINT, SIGTERM) Note: signal is a ProcessSignal object, use signal.signum to get the signal number. Wait for a specific process events ================================== To wait any event from a process, use waitEvent() method: :: event = process.waitEvent() To wait one or more signals, use waitSignals() method. With no argument, it waits for any signal. Other process events are raised as Python exception. Examples: :: signal = process.waitSignals() signal = process.waitSignals(SIGTRAP) signal = process.waitSignals(SIGINT, SIGTERM) Note: As debugger.waitSignals(), signal is a ProcessSignal object. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/doc/ptrace_signal.rst0000664000175000017500000000563300000000000020753 0ustar00vstinnervstinner.. _signal: +++++++++++++++++++++++++++++ python-ptrace signal handling +++++++++++++++++++++++++++++ Introduction ============ PtraceSignal tries to display useful information when a signal is received. Depending on the signal number, it shows different information. It uses the current instruction decoded as assembler code to understand why the signal is raised. Only Intel x86 (i386, maybe x86_64) is supported now. When a process receives a signal, python-ptrace tries to explain why the signal was emitted. General information (not shown for all signals, e.g. not for SIGABRT): * CPU instruction causing the crash * CPU registers related to the crash * Memory mappings of the memory addresses Categorize signals: * SIGFPE - Division by zero * SIGSEGV, SIGBUS - Invalid memory read - Invalid memory write - Stack overflow - Invalid memory access * SIGABRT - Program abort * SIGCHLD - Child process exit Examples ======== Division by zero (SIGFPE) ------------------------- :: Signal: SIGFPE Division by zero - instruction: IDIV DWORD [[EBP-0x8] - register ebp=0xbfdc4a98 Invalid memory read/write (SIGSEGV) ----------------------------------- :: Signal: SIGSEGV Invalid read from 0x00000008 - instruction: MOV EAX, [EAX+0x8]] - mapping: 0x00000008 is not mapped in memory - register eax=0x00000000 :: PID: 23766 Signal: SIGSEGV Invalid write to 0x00000008 (size=4 bytes) - instruction: MOV DWORD [[EAX+0x8],|0x2a - mapping: 0x00000008..0x0000000b is not mapped in memory - register eax=0x00000000 Given information: * Address of the segmentation fault * (if possible) Size of the invalid memory read/write * CPU instruction causing the crash * CPU registers related to the crash * Memory mappings of the related memory address Stack overflow (SIGSEGV) ------------------------ :: Signal: SIGSEGV STACK OVERFLOW! Stack pointer is in 0xbf534000-0xbfd34000 => [stack]] (rw-p) - instruction: MOV BYTE [[EBP-0x1004],|0x0 - mapping: 0xbf533430 is not mapped in memory - register =0xbf533430 - register ebp=0xbf534448 Child exit (SIGCHLD) -------------------- :: PID: 24008 Signal: SIGCHLD Child process 24009 exited normally Signal sent by user 1000 Information: * Child process identifier * Child process user identifier Examples ======== Invalid read: :: Signal: SIGSEGV Invalid read from 0x00000008 - instruction: MOV EAX, [EAX+0x8] - mapping: (no memory mapping) - register eax=0x00000000 Invalid write (MOV): :: Signal: SIGSEGV Invalid write to 0x00000008 (size=4 bytes) - instruction: MOV DWORD [EAX+0x8], 0x2a - mapping: (no memory mapping) - register eax=0x00000000 abort(): :: Signal: SIGABRT Program received signal SIGABRT, Aborted. Source code =========== See: * ``ptrace/debugger/ptrace_signal.py`` * ``ptrace/debugger/signal_reason.py`` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/doc/syscall.rst0000664000175000017500000000544000000000000017606 0ustar00vstinnervstinner.. _syscall: +++++++++++++++++++++++++++++ Trace system calls (syscalls) +++++++++++++++++++++++++++++ python-ptrace can trace system calls using ``PTRACE_SYSCALL``. PtraceSyscall ============= ptrace.syscall module contains PtraceSyscall class: it's a parser of Linux syscalls similar to strace program. Example:: connect(5, , 28) = 0 open('/usr/lib/i686/cmov/libcrypto.so.0.9.8', 0, 0 ) = 4 mmap2(0xb7e87000, 81920, 3, 2066, 4, 297) = 0xb7e87000 rt_sigaction(SIGWINCH, 0xbfb7d4a8, 0xbfb7d41c, 8) = 0 You can get more information: result type, value address, argument types, and argument names. Examples:: long open(const char* filename='/usr/lib/i686/cmov/libcrypto.so.0.9.8' at 0xb7efc027, int flags=0, int mode=0 ) = 4 long fstat64(unsigned long fd=4, struct stat* buf=0xbfa46e2c) = 0 long set_robust_list(struct robust_list_head* head=0xb7be5710, size_t len_ptr=12) = 0 strace.py ========= Program strace.py is very close to strace program: display syscalls of a program. Example: Features -------- * Nice output of signal: see [[signal|python-ptrace signal handling]] * Supports multiple processes * Can trace running process * Can display arguments name, type and address * Option ``--filename`` to show only syscall using file names * Option ``--socketcall`` to show only syscall related to network (socket usage) * Option ``--syscalls`` to list all known syscalls Example ------- :: $ ./strace.py /bin/ls execve(/bin/ls, [['/bin/ls'],|[/* 40 vars */]]) = 756 brk(0) = 0x0805c000 access('/etc/ld.so.nohwcap', 0) = -2 (No such file or directory) mmap2(NULL, 8192, 3, 34, -1, 0) = 0xb7f56000 access('/etc/ld.so.preload', 4) = -2 (No such file or directory) (...) close(1) = 0 munmap(0xb7c5c000, 4096) = 0 exit_group(0) ---done--- Options ------- The program has many options. Example with ``--socketcall`` (display only network functions):: $ ./strace.py --socketcall nc localhost 8080 execve(/bin/nc, [['/bin/nc',|'localhost', '8080']], [[/*|40 vars */]]) = 12948 socket(AF_FILE, SOCK_STREAM, 0) = 3 connect(3, , 110) = -2 (No such file or directory) socket(AF_FILE, SOCK_STREAM, 0) = 3 connect(3, , 110) = -2 (No such file or directory) socket(AF_INET, SOCK_STREAM, 6) = 3 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, 3217455272L, 4) = 0 connect(3, , 16) = -111 (Connection refused) (...) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/doc/todo.rst0000664000175000017500000000314500000000000017101 0ustar00vstinnervstinnerTODO ==== Main tasks ---------- * Fix strace.py --socketcall: SyscallState.enter() calls ignore_callback before socketcall are proceed * Support other backends: - GDB MI: http://code.google.com/p/pygdb/ - ktrace: (FreeBSD and Darwin): would help Darwin support - utrace (new Linux debugger): http://sourceware.org/systemtap/wiki/utrace - vtrace? - PyDBG: works on Windows * Backtrace symbols: - GNU BFD? - elfsh? - addr2line program? - See dl_iterate_phdr() function of libdl * Support other disassemblers (than distorm), and so both Intel syntax (Intel and AT&T) - BFD - http://www.ragestorm.net/distorm/ - libasm (ERESI) - libdisasm (bastard) - http://www.woodmann.com/collaborative/tools/index.php/Category:X86_Disassembler_Libraries * Support threads: other backends (than python-ptrace) already support threads Minor tasks ----------- * Fix gdb.py "step" command on a jump. Example where step will never stop:: (gdb) where ASM 0xb7e3b917: JMP 0xb7e3b8c4 (eb ab) ASM 0xb7e3b919: LEA ESI, [ESI+0x0] (8db426 00000000) * Remove gdb.py "except PtraceError, err: if err.errno == ESRCH" hack, process death detection should be done by PtraceProcess or PtraceDebugger * Use Intel hardware breakpoints: set vtrace source code * Support Darwin: - ktrace? need to recompile Darwin kernel with KTRACE option - get registers: http://unixjunkie.blogspot.com/2006/01/darwin-ptrace-and-registers.html - PT_DENY_ATTACH: http://steike.com/code/debugging-itunes-with-gdb/ - PT_DENY_ATTACH: http://landonf.bikemonkey.org/code/macosx/ptrace_deny_attach.20041010201303.11809.mojo.html ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/doc/usage.rst0000664000175000017500000000463400000000000017244 0ustar00vstinnervstinner+++++++++++++++++++ python-ptrace usage +++++++++++++++++++ Hello World =========== Short example attaching a running process. It gets the instruction pointer, executes a single step, and gets the new instruction pointer:: import ptrace.debugger import signal import subprocess import sys def debugger_example(pid): debugger = ptrace.debugger.PtraceDebugger() print("Attach the running process %s" % pid) process = debugger.addProcess(pid, False) # process is a PtraceProcess instance print("IP before: %#x" % process.getInstrPointer()) print("Execute a single step") process.singleStep() # singleStep() gives back control to the process. We have to wait # until the process is trapped again to retrieve the control on the # process. process.waitSignals(signal.SIGTRAP) print("IP after: %#x" % process.getInstrPointer()) process.detach() debugger.quit() def main(): args = [sys.executable, '-c', 'import time; time.sleep(60)'] child_popen = subprocess.Popen(args) debugger_example(child_popen.pid) child_popen.kill() child_popen.wait() if __name__ == "__main__": main() API === PtraceProcess ------------- The PtraceProcess class is an helper to manipulate a traced process. Example:: tracer = PtraceProcess(pid) # attach the process tracer.singleStep() # execute one instruction tracer.cont() # continue execution tracer.syscall() # break at next syscall tracer.detach() # detach process # Get status tracer.getreg('al') # get AL register value regs = tracer.getregs() # read all registers bytes = tracer.readBytes(regs.ax, 10) # read 10 bytes tracer.dumpCode() # dump code (as assembler or hexa is the disassembler is missing) tracer.dumpStack() # dump stack (memory words around ESP) # Modify the process shellcode = '...' ip = tracer.getInstrPointer() # get EIP/RIP register bytes = tracer.writeBytes(ip, shellcode) # write some bytes tracer.setreg('ebx', 0) # set EBX register value to zero Read ``ptrace/debugger/process.py`` source code to see more methods. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9345315 python-ptrace-0.9.8/examples/0000775000175000017500000000000000000000000016450 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/examples/itrace.py0000775000175000017500000000335600000000000020303 0ustar00vstinnervstinner#!/usr/bin/env python """ Here is a tool which I have been using to debug libc startup code where I didn't find gdb very helpful. It single steps the process and prints each instruction pointer address. To go faster, it allows a number of syscalls to run before starting single-stepping. It's possible to pipe the addresses through addr2line to get a very simple tracing debugger. :-) I couldn't see a way to catch syscalls and single step at the same time. As a consequence the tool can't handle multiple threads. Mark """ import signal from ptrace.debugger import ProcessExit, ProcessSignal import strace class Tracer(strace.SyscallTracer): def createCommonOptions(self, parser): parser.add_option( "-n", dest="syscall_limit", type="int", default=None, help="Number of syscalls before switching to single step") super(Tracer, self).createCommonOptions(parser) def syscallTrace(self, process): syscall_limit = self.options.syscall_limit i = 0 while i < syscall_limit or syscall_limit is None: print(i) i += 1 process.syscall() self.debugger.waitSyscall() i = 0 while self.debugger: eip = process.getInstrPointer() print(i, process.pid, "[%08x]" % eip) i += 1 process.singleStep() event = self.debugger.waitProcessEvent() if isinstance(event, ProcessExit): print("process exit") return if (isinstance(event, ProcessSignal) and event.signum & ~128 != signal.SIGTRAP): print("died with signal %i" % event.signum) return if __name__ == "__main__": Tracer().main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/examples/simple_dbg.py0000775000175000017500000000316200000000000021134 0ustar00vstinnervstinner#!/usr/bin/env python from ptrace.debugger.debugger import PtraceDebugger from ptrace.debugger.child import createChild from ptrace.tools import locateProgram from sys import stderr, argv, exit def playWithProcess(process): # Do anything you want with the process here... print("Dump process registers") process.dumpRegs() print("Continue process execution") process.cont() print("Wait next process event...") event = process.waitEvent() print("New process event: %s" % event) def traceProgram(arguments): # Copy the environment variables env = None # Get the full path of the program arguments[0] = locateProgram(arguments[0]) # Create the child process return createChild(arguments, False, env) def main(): # Check the command line if len(argv) < 2: print("usage: %s program [arg1 arg2 ...]" % argv[0], file=stderr) print(" or: %s pid" % argv[0], file=stderr) exit(1) # Get the process identifier is_attached = False has_pid = False if len(argv) == 2: try: # User asked to attach a process pid = int(argv[1]) has_pid = True except ValueError: pass if not has_pid: # User asked to create a new program and trace it arguments = argv[1:] pid = traceProgram(arguments) is_attached = True # Create the debugger and attach the process dbg = PtraceDebugger() process = dbg.addProcess(pid, is_attached) # Play with the process and then quit playWithProcess(process) dbg.quit() if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065905.0 python-ptrace-0.9.8/gdb.py0000775000175000017500000007222600000000000015754 0ustar00vstinnervstinner#!/usr/bin/env python from ptrace import PtraceError from ptrace.debugger import (PtraceDebugger, Application, ProcessExit, NewProcessEvent, ProcessSignal, ProcessExecution, ProcessError) from optparse import OptionParser from os import getpid from sys import stdout, stderr, exit from logging import getLogger, info, warning, error from ptrace.version import __version__ as VERSION, WEBSITE from ptrace.error import PTRACE_ERRORS, writeError from ptrace.binding import HAS_PTRACE_SINGLESTEP from ptrace.disasm import HAS_DISASSEMBLER from ptrace.ctypes_tools import (truncateWord, formatWordHex, formatAddress, formatAddressRange, word2bytes) from ptrace.process_tools import dumpProcessInfo from ptrace.tools import inverseDict from ptrace.func_call import FunctionCallOptions from ptrace.signames import signalName, SIGNAMES from signal import SIGTRAP, SIGINT from ptrace.terminal import enableEchoMode, terminalWidth from errno import ESRCH from ptrace.cpu_info import CPU_POWERPC from ptrace.debugger import ChildError from ptrace.debugger.memory_mapping import readProcessMappings from ptrace.os_tools import RUNNING_PYTHON3 try: unichr raw_input except NameError: # Python 3 unichr = chr raw_input = input import re if stdout.isatty(): try: # Use readline for better raw_input() import readline # noqa except ImportError: pass # Match a register name: $eax, $gp0, $orig_eax REGISTER_REGEX = re.compile(r"\$[a-z]+[a-z0-9_]+") # BYTES_REGEX = re.compile(r"""(?:'([^'\\]*)'|"([^"\\]*)")""") SIGNALS = inverseDict(SIGNAMES) # name -> signum COMMANDS = ( # trace instructions ("cont", "continue execution"), ("step", "execute one instruction (do not enter in a call)"), ("stepi", "execute one instruction (enter the call)"), ("until", "execute code until specified address (until
)"), ("set", "set register value (set =)"), ("sys", "continue execution to next syscall"), ("signal", "send a signal to the process (signal )"), ("signals", "display signals"), # current process info ("regs", "display registers"), ("where", "display true code content (show breakpoints effects on code). e.g. 'where $eip', 'where $eip $eip+20'"), ("print", "display a value (print )"), ("hexdump", "dump memory as specified address or address range (hexdump
or hexdump )"), ("gcore", "generate core file of the process"), ("where2", "display original code content (don't show effects of breakpoint on code)"), ("stack", "display stack content"), ("backtrace", "dump the backtrace"), ("proc", "display process information"), ("maps", "display memory mappings"), # breakpoints ("break", "set a breakpoint (break
)"), ("breakpoints", "display breakpoints"), ("delete", "delete a breakpoint (delete
)"), # processes ("attach", 'attach a new process (e.g. "attach 2390")'), ("proclist", "list of traced processes"), ("switch", "switch active process (switch or switch )"), ("follow", r'''follow a term (e.g. "follow '\x12\x14\x27\x13'")'''), ("showfollow", 'show all "followed" terms'), ("resetfollow", 'reset all "followed" terms'), ("xray", 'show addresses of (and possible pointers to) "followed" terms'), # other ("dbginfo", "information about the debugger"), ("quit", "quit debugger"), ("help", "display this help"), ) def formatAscii(data): def asciiChar(byte): if 32 <= byte <= 126: return unichr(byte) else: return '.' if RUNNING_PYTHON3: return u''.join(asciiChar(byte) for byte in data) else: return u''.join(asciiChar(ord(byte)) for byte in data) def formatHexa(data): if RUNNING_PYTHON3: return u' '.join(u"%02x" % byte for byte in data) else: return u' '.join(u"%02x" % ord(byte) for byte in data) # finds possible pointer values in process memory space, # pointing to address def getPointers(process, address): address = word2bytes(address) procmaps = readProcessMappings(process) for pm in procmaps: for found in pm.search(address): yield found class Gdb(Application): def __init__(self): Application.__init__(self) # Parse self.options self.parseOptions() # Setup output (log) self.setupLog() self.last_signal = {} # We assume user wants all possible information self.syscall_options = FunctionCallOptions( write_types=True, write_argname=True, write_address=True, ) # FIXME: Remove self.breaks! self.breaks = dict() self.followterms = [] def setupLog(self): self._setupLog(stdout) def parseOptions(self): parser = OptionParser( usage="%prog [options] -- program [arg1 arg2 ...]") self.createCommonOptions(parser) self.createLogOptions(parser) self.options, self.program = parser.parse_args() if self.options.pid is None and not self.program: parser.print_help() exit(1) self.processOptions() self.show_pid = self.options.fork def _continueProcess(self, process, signum=None): if not signum and process in self.last_signal: signum = self.last_signal[process] if signum: error("Send %s to %s" % (signalName(signum), process)) process.cont(signum) try: del self.last_signal[process] except KeyError: pass else: process.cont() def cont(self, signum=None): for process in self.debugger: process.syscall_state.clear() if process == self.process: self._continueProcess(process, signum) else: self._continueProcess(process) # Wait for a process signal signal = self.debugger.waitSignals() process = signal.process # Hit breakpoint? if signal.signum == SIGTRAP: ip = self.process.getInstrPointer() if not CPU_POWERPC: # Go before "INT 3" instruction ip -= 1 breakpoint = self.process.findBreakpoint(ip) if breakpoint: error("Stopped at %s" % breakpoint) breakpoint.desinstall(set_ip=True) else: self.processSignal(signal) return None def readRegister(self, regs): name = regs.group(0)[1:] value = self.process.getreg(name) return str(value) def parseInteger(self, text): # Remove spaces and convert to lower case text = text.strip() if " " in text: raise ValueError("Space are forbidden: %r" % text) text = text.lower() # Replace registers by their value orig_text = text text = REGISTER_REGEX.sub(self.readRegister, text) # Replace hexadecimal numbers by decimal numbers def readHexadecimal(regs): text = regs.group(0) if text.startswith("0x"): text = text[2:] elif not re.search("[a-f]", text): return text value = int(text, 16) return str(value) text = re.sub(r"(?:0x)?[0-9a-f]+", readHexadecimal, text) # Reject invalid characters if not re.match(r"^[()<>+*/&0-9-]+$", text): raise ValueError("Invalid expression: %r" % orig_text) # Use integer division (a//b) instead of float division (a/b) text = text.replace("/", "//") # Finally, evaluate the expression is_pointer = text.startswith("*") if is_pointer: text = text[1:] try: value = eval(text) value = truncateWord(value) except SyntaxError: raise ValueError("Invalid expression: %r" % orig_text) if is_pointer: value = self.process.readWord(value) return value def parseIntegers(self, text): values = [] for item in text.split(): item = item.strip() value = self.parseInteger(item) values.append(value) return values def parseBytes(self, text): # FIXME: Validate input # if not BYTES_REGEX.match(text): # raise ValueError('Follow text must be enclosed in quotes!') text = 'b' + text.lstrip() value = eval(text) if not isinstance(value, bytes): raise TypeError("Input is not a bytes string!") return value def addFollowTerm(self, text): # Allow terms of the form 'string', "string", '\x04', "\x01\x14" term = self.parseBytes(text) self.followterms.append(term) def showFollowTerms(self): print(self.followterms) def _xray(self): for term in self.followterms: for process in self.debugger: for procmap in readProcessMappings(process): for address in procmap.search(term): yield (process, procmap, address, term) # displays the offsets of all terms found in the process memory mappings # along with possible addresses of pointers pointing to these terms def xray(self): for process, procmap, address, term in self._xray(): pointers = " ".join(formatAddress(ptr_addr) for ptr_addr in getPointers(process, address)) print("term[%s] pid[%i] %s %s pointers: %s" % ( repr(term), process.pid, procmap, formatAddress(address), pointers)) def execute(self, command): errmsg = None if command == "cont": errmsg = self.cont() elif command == "proc": self.procInfo() elif command == "proclist": self.procList() elif command.startswith("attach "): errmsg = self.attachProcess(command[7:]) elif command == "regs": self.process.dumpRegs() elif command == "stack": self.process.dumpStack() elif command == "gcore": self.gcore(self.process) elif command == "backtrace": errmsg = self.backtrace() elif command == "where" or command.startswith("where "): errmsg = self.where(command[6:]) elif command == "where2" or command.startswith("where2 "): errmsg = self.where(command[7:], manage_bp=True) elif command == "maps": self.process.dumpMaps() elif command == "dbginfo": self.debuggerInfo() elif command == "step": errmsg = self.step(False) elif command == "stepi": errmsg = self.step(True) elif command == "sys": errmsg = self.syscallTrace() elif command == "help": self.help() elif command.startswith("set "): errmsg = self.set(command) elif command.startswith("until "): errmsg = self.until(command[6:]) elif command.startswith("switch") or command == "switch": errmsg = self.switch(command[6:]) elif command.startswith("break "): errmsg = self.breakpoint(command[6:]) elif command.startswith("breakpoints"): self.displayBreakpoints() elif command.startswith("signals"): self.displaySignals() elif command.startswith("delete "): errmsg = self.delete(command[7:]) elif command.startswith("hexdump "): errmsg = self.hexdump(command[8:]) elif command.startswith("signal "): errmsg = self.signal(command[7:]) elif command.startswith("print "): errmsg = self.print_(command[6:]) elif command.startswith("follow "): errmsg = self.addFollowTerm(command[7:]) elif command == "showfollow": self.showFollowTerms() elif command == "resetfollow": self.followterms = [] elif command == "xray": self.xray() else: errmsg = "Unknown command: %r" % command if errmsg: print(errmsg, file=stderr) return False return True def parseSignum(self, command): try: return SIGNALS[command] except KeyError: pass try: return SIGNALS["SIG" + command] except KeyError: pass try: return self.parseInteger(command) except ValueError: raise ValueError("Invalid signal number: %r" % command) def signal(self, command): try: signum = self.parseSignum(command) except ValueError as err: return str(err) last_process = self.process try: errmsg = self.cont(signum) return errmsg finally: try: del self.last_signal[last_process] except KeyError: pass def print_(self, command): try: value = self.parseInteger(command) except ValueError as err: return str(err) error("Decimal: %s" % value) error("Hexadecimal: %s" % formatWordHex(value)) for map in self.process.readMappings(): if value not in map: continue error("Address is part of mapping: %s" % map) return None def gcore(self, process): import re childPid = str(process).split('#')[-1][:-1] maps_file = open("/proc/" + childPid + "/maps", 'r') mem_file = open("/proc/" + childPid + "/mem", 'r', 0) from sys import argv dump = open("/vmdump/" + argv[1] + ".dump", "wb") for line in maps_file.readlines(): # for each mapped region m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line) if m.group(3) == 'r': # if this is a readable region if "/lib" not in line and "/usr" not in line: # for eliminating of shared libs start = int(m.group(1), 16) end = int(m.group(2), 16) mem_file.seek(start) # seek to region start chunk = mem_file.read(end - start) # read region contents dump.write(chunk,) # dump contents to standard output maps_file.close() mem_file.close() dump.close() def hexdump(self, command): max_line = 20 width = (terminalWidth() - len(formatAddress(1)) - 3) // 4 width = max(width, 1) limited = None parts = command.split(" ", 1) if 1 < len(parts): try: start_address = self.parseInteger(parts[0]) end_address = self.parseInteger(parts[1]) if end_address <= start_address: raise ValueError('End address (%s) is smaller than start address(%s)!' % (formatAddress(end_address), formatAddress(start_address))) except ValueError as err: return str(err) size = end_address - start_address max_size = width * max_line if max_size < size: limited = max_size end_address = start_address + max_size else: try: start_address = self.parseInteger(command) except ValueError as err: return str(err) end_address = start_address + 5 * width read_error = None address = start_address while address < end_address: size = min(end_address - address, width) try: # Read bytes memory = self.process.readBytes(address, size) # Format bytes hexa = formatHexa(memory) hexa = hexa.ljust(width * 3 - 1, ' ') ascii = formatAscii(memory) ascii = ascii.ljust(width, ' ') # Display previous read error, if any if read_error: warning("Warning: Unable to read memory %s" % ( formatAddressRange(*read_error))) read_error = None # Display line error("%s| %s| %s" % (formatAddress(address), hexa, ascii)) except PtraceError: if not read_error: read_error = [address, address + size] else: read_error[1] = address + size address += size # Display last read error, if any if read_error: warning("Warning: Unable to read memory %s" % ( formatAddressRange(*read_error))) if limited: warning("(limit to %s bytes)" % max_size) return None def backtrace(self): trace = self.process.getBacktrace() for func in trace: error(func) if trace.truncated: error("--limited to depth %s--" % len(trace)) return None def where(self, command, manage_bp=False): start = None stop = None try: values = self.parseIntegers(command) except ValueError as err: return str(err) if 1 <= len(values): start = values[0] if 2 <= len(values): stop = values[1] self.process.dumpCode(start, stop, manage_bp=manage_bp) return None def procInfo(self): dumpProcessInfo(error, self.process.pid, max_length=160) def procList(self): for process in self.debugger: text = str(process) if self.process == process: text += " (active)" error(text) def set(self, command): try: key, value = command[4:].split("=", 1) key = key.strip().lower() if not key.startswith("$"): return 'Register name (%s) have to start with "$"' % key key = key[1:] except ValueError: return "Invalid command: %r" % command try: value = self.parseInteger(value) except ValueError as err: return str(err) try: self.process.setreg(key, value) except ProcessError as err: return "Unable to set $%s=%s: %s" % (key, value, err) error("Set $%s to %s" % (key, value)) return None def displayInstr(self, prefix): try: if HAS_DISASSEMBLER: instr = self.process.disassembleOne() error("%s %s: %s" % ( prefix, formatAddress(instr.address), instr.text)) else: self.process.dumpCode() except PtraceError as err: error("Unable to read current instruction: %s" % err) def attachProcess(self, text): try: pid = self.parseInteger(text) except ValueError as err: return str(err) process = self.debugger.addProcess(pid, False) self.switchProcess(process) def step(self, enter_call, address=None): if address is None: self.displayInstr("Execute") if (not HAS_PTRACE_SINGLESTEP) or (not enter_call): if address is None: address = self.process.getInstrPointer() size = self.readInstrSize(address, default_size=None) if not size: return "Unable to read instruction size at %s" \ % formatAddress(address) address += size size = self.readInstrSize(address) # Set a breakpoint breakpoint = self.process.createBreakpoint(address, size) # Continue the process self.process.cont() else: # Use ptrace single step command self.process.singleStep() breakpoint = None # Execute processus until next TRAP try: self.process.waitSignals(SIGTRAP) if breakpoint: breakpoint.desinstall(set_ip=True) except: # noqa: E722 if breakpoint: breakpoint.desinstall() raise return None def newProcess(self, event): error("New process: %s" % event.process) # FIXME: This function doesn't work with multiple processes # especially when a parent waits for a child def syscallTrace(self): # Trace until syscall enter self.process.syscall() self.process.waitSyscall() # Process the syscall event state = self.process.syscall_state syscall = state.event(self.syscall_options) # Display syscall if syscall: if syscall.result is not None: text = "%s = %s" % (syscall.format(), syscall.result_text) if self.show_pid: text = "Process %s exits %s" % (syscall.process.pid, text) error(text) else: text = syscall.format() if self.show_pid: text = "Process %s enters %s" % (syscall.process.pid, text) error(text) return None def until(self, command): try: address = self.parseInteger(command) except ValueError as err: return str(err) errmsg = self.step(False, address) if errmsg: return errmsg self.displayInstr("Current") return None def switch(self, command): if not command: process_list = self.debugger.list if len(process_list) == 1: return "There is only one process!" index = process_list.index(self.process) index = (index + 1) % len(process_list) process = process_list[index] self.switchProcess(process) return try: pid = self.parseInteger(command) except ValueError as err: return str(err) try: process = self.debugger[pid] self.switchProcess(process) except KeyError: return "There is not process %s" % pid return None def switchProcess(self, process): if self.process == process: return error("Switch to %s" % process) self.process = process def nextProcess(self): try: process = next(iter(self.debugger)) self.switchProcess(process) except StopIteration: pass def displayBreakpoints(self): found = False for process in self.debugger: for bp in process.breakpoints.values(): found = True error("%s:%s" % (process, bp)) if not found: error("(no breakpoint)") def displaySignals(self): signals = list(SIGNAMES.items()) signals.sort(key=lambda key_value: key_value[0]) for signum, name in signals: error("% 2s: %s" % (signum, name)) def readInstrSize(self, address, default_size=None): if not HAS_DISASSEMBLER: return default_size try: # Get address and size of instruction at specified address instr = self.process.disassembleOne(address) return instr.size except PtraceError as err: warning("Warning: Unable to read instruction size at %s: %s" % ( formatAddress(address), err)) return default_size def breakpoint(self, command): try: address = self.parseInteger(command) except ValueError as err: return str(err) # Create breakpoint size = self.readInstrSize(address) try: bp = self.process.createBreakpoint(address, size) except PtraceError as err: return "Unable to set breakpoint at %s: %s" % ( formatAddress(address), err) error("New breakpoint: %s" % bp) return None def delete(self, command): try: address = self.parseInteger(command) except ValueError as err: return str(err) breakpoint = self.process.findBreakpoint(address) if not breakpoint: return "No breakpoint at %s " % formatAddress(address) breakpoint.desinstall() error("%s deleted" % breakpoint) return None def help(self): for command, description in COMMANDS: error("%s: %s" % (command, description)) error('') error("Value can be an hexadecimal/decimal number or a register name ($reg)") error("You can use operators a+b, a-b, a*b, a/b, a<>b, a**b, and parenthesis in expressions") error( 'Use ";" to write multiple commands on the same line (e.g. "step; print $eax")') def processSignal(self, event): event.display() self.switchProcess(event.process) self.last_signal[self.process] = event.signum error("%s interrupted by %s" % (self.process, event.name)) def processExecution(self, event): error(event) self.switchProcess(event.process) self.interrupt() def debuggerInfo(self): error("Debugger process ID: %s" % getpid()) error("python-ptrace version %s" % VERSION) error("Website: %s" % WEBSITE) def interrupt(self): waitlist = [] for process in self.debugger: if process.is_stopped: continue try: if process.isTraced(): continue except NotImplementedError: pass warning("Interrupt %s (send SIGINT)" % process) process.kill(SIGINT) waitlist.append(process) for process in waitlist: info("Wait %s interruption" % process) try: process.waitSignals(SIGINT) except ProcessSignal as event: event.display() except KeyboardInterrupt: pass def deleteProcess(self, pid): try: process = self.debugger[pid] except KeyError: return event = process.processTerminated() error(str(event)) if process == self.process: self.nextProcess() def restoreTerminal(self): if enableEchoMode(): error("Terminal: restore echo mode") def mainLoop(self): # Read command try: self.restoreTerminal() command = raw_input(self.invite).strip() except EOFError: print() return True except KeyboardInterrupt: error("User interrupt!") self.interrupt() return False # If command is empty, reuse previous command if not command: if self.previous_command: command = self.previous_command info("Replay previous command: %s" % command) else: return False self.previous_command = None # User wants to quit? if command == "quit": return True # Execute the user command try: command_str = command ok = True for command in command_str.split(";"): command = command.strip() try: ok &= self.execute(command) except Exception as err: print("Command error: %s" % err) raise ok = False if not ok: break if ok: self.previous_command = command_str except KeyboardInterrupt: self.interrupt() except NewProcessEvent as event: self.newProcess(event) except ProcessSignal as event: self.processSignal(event) except ProcessExit as event: error(event) self.nextProcess() except ProcessExecution as event: self.processExecution(event) except PtraceError as err: error("ERROR: %s" % err) if err.errno == ESRCH: self.deleteProcess(err.pid) return False def runDebugger(self): self.setupDebugger() # Create new process try: self.process = self.createProcess() except ChildError as err: writeError(getLogger(), err, "Unable to create child process") return if not self.process: return # Trace syscalls self.invite = '(gdb) ' self.previous_command = None while True: if not self.debugger: # There is no more process: quit return done = self.mainLoop() if done: return def main(self): self.debugger = PtraceDebugger() try: self.runDebugger() except KeyboardInterrupt: error("Interrupt debugger: quit!") except PTRACE_ERRORS as err: writeError(getLogger(), err, "Debugger error") self.process = None self.debugger.quit() error("Quit gdb.") self.restoreTerminal() if __name__ == "__main__": Gdb().main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9365315 python-ptrace-0.9.8/ptrace/0000775000175000017500000000000000000000000016110 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1586774410.0 python-ptrace-0.9.8/ptrace/__init__.py0000664000175000017500000000024000000000000020215 0ustar00vstinnervstinnerfrom ptrace.signames import SIGNAMES, signalName # noqa from ptrace.error import PtraceError # noqa from ptrace.version import VERSION, __version__ # noqa ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9365315 python-ptrace-0.9.8/ptrace/binding/0000775000175000017500000000000000000000000017522 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/binding/__init__.py0000664000175000017500000000227100000000000021635 0ustar00vstinnervstinnerfrom ptrace.binding.func import ( # noqa HAS_PTRACE_SINGLESTEP, HAS_PTRACE_EVENTS, HAS_PTRACE_IO, HAS_PTRACE_SIGINFO, HAS_PTRACE_GETREGS, HAS_PTRACE_GETREGSET, REGISTER_NAMES, ptrace_attach, ptrace_traceme, ptrace_detach, ptrace_kill, ptrace_cont, ptrace_syscall, ptrace_setregs, ptrace_peektext, ptrace_poketext, ptrace_peekuser, ptrace_registers_t) if HAS_PTRACE_EVENTS: from ptrace.binding.func import (WPTRACEEVENT, # noqa PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK, PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC, ptrace_setoptions, ptrace_geteventmsg) if HAS_PTRACE_SINGLESTEP: from ptrace.binding.func import ptrace_singlestep # noqa if HAS_PTRACE_SIGINFO: from ptrace.binding.func import ptrace_getsiginfo # noqa if HAS_PTRACE_IO: from ptrace.binding.func import ptrace_io # noqa from ptrace.binding.freebsd_struct import ( # noqa ptrace_io_desc, PIOD_READ_D, PIOD_WRITE_D, PIOD_READ_I, PIOD_WRITE_I) if HAS_PTRACE_GETREGS or HAS_PTRACE_GETREGSET: from ptrace.binding.func import ptrace_getregs # noqa ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/binding/cpu.py0000664000175000017500000000414400000000000020666 0ustar00vstinnervstinnerfrom ptrace.cpu_info import ( CPU_POWERPC, CPU_INTEL, CPU_X86_64, CPU_I386, CPU_ARM32, CPU_AARCH64) CPU_INSTR_POINTER = None CPU_STACK_POINTER = None CPU_FRAME_POINTER = None CPU_SUB_REGISTERS = {} if CPU_POWERPC: CPU_INSTR_POINTER = "nip" # FIXME: Is it the right register? CPU_STACK_POINTER = 'gpr1' elif CPU_ARM32: CPU_INSTR_POINTER = 'r15' CPU_STACK_POINTER = 'r14' CPU_FRAME_POINTER = 'r11' elif CPU_AARCH64: CPU_INSTR_POINTER = 'pc' CPU_STACK_POINTER = 'sp' CPU_FRAME_POINTER = 'r29' elif CPU_X86_64: CPU_INSTR_POINTER = "rip" CPU_STACK_POINTER = "rsp" CPU_FRAME_POINTER = "rbp" CPU_SUB_REGISTERS = { # main register name, shift, mask 'al': ('rax', 0, 0xff), 'bl': ('rbx', 0, 0xff), 'cl': ('rcx', 0, 0xff), 'dl': ('rdx', 0, 0xff), 'ah': ('rax', 8, 0xff), 'bh': ('rbx', 8, 0xff), 'ch': ('rcx', 8, 0xff), 'dh': ('rdx', 8, 0xff), 'ax': ('rax', 0, 0xffff), 'bx': ('rbx', 0, 0xffff), 'cx': ('rcx', 0, 0xffff), 'dx': ('rdx', 0, 0xffff), 'eax': ('rax', 32, None), 'ebx': ('rbx', 32, None), 'ecx': ('rcx', 32, None), 'edx': ('rdx', 32, None), } elif CPU_I386: CPU_INSTR_POINTER = "eip" CPU_STACK_POINTER = "esp" CPU_FRAME_POINTER = "ebp" CPU_SUB_REGISTERS = { 'al': ('eax', 0, 0xff), 'bl': ('ebx', 0, 0xff), 'cl': ('ecx', 0, 0xff), 'dl': ('edx', 0, 0xff), 'ah': ('eax', 8, 0xff), 'bh': ('ebx', 8, 0xff), 'ch': ('ecx', 8, 0xff), 'dh': ('edx', 8, 0xff), 'ax': ('eax', 0, 0xffff), 'bx': ('ebx', 0, 0xffff), 'cx': ('ecx', 0, 0xffff), 'dx': ('edx', 0, 0xffff), } if CPU_INTEL: CPU_SUB_REGISTERS.update({ 'cf': ('eflags', 0, 1), 'pf': ('eflags', 2, 1), 'af': ('eflags', 4, 1), 'zf': ('eflags', 6, 1), 'sf': ('eflags', 7, 1), 'tf': ('eflags', 8, 1), 'if': ('eflags', 9, 1), 'df': ('eflags', 10, 1), 'of': ('eflags', 11, 1), 'iopl': ('eflags', 12, 2), }) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/binding/freebsd_struct.py0000664000175000017500000000373300000000000023120 0ustar00vstinnervstinnerfrom ctypes import (Structure, c_int, c_uint, c_ulong, c_void_p, c_uint16, c_uint32, c_size_t) from ptrace.cpu_info import CPU_X86_64 PIOD_READ_D = 1 PIOD_WRITE_D = 2 PIOD_READ_I = 3 PIOD_WRITE_I = 4 # /usr/include/machine/reg.h if CPU_X86_64: register_t = c_ulong class reg(Structure): _fields_ = ( ("r15", register_t), ("r14", register_t), ("r13", register_t), ("r12", register_t), ("r11", register_t), ("r10", register_t), ("r9", register_t), ("r8", register_t), ("rdi", register_t), ("rsi", register_t), ("rbp", register_t), ("rbx", register_t), ("rdx", register_t), ("rcx", register_t), ("rax", register_t), ("trapno", c_uint32), ("fs", c_uint16), ("gs", c_uint16), ("err", c_uint32), ("es", c_uint16), ("ds", c_uint16), ("rip", register_t), ("cs", register_t), ("rflags", register_t), ("rsp", register_t), ("ss", register_t), ) else: class reg(Structure): _fields_ = ( ("fs", c_uint), ("es", c_uint), ("ds", c_uint), ("edi", c_uint), ("esi", c_uint), ("ebp", c_uint), ("isp", c_uint), ("ebx", c_uint), ("edx", c_uint), ("ecx", c_uint), ("eax", c_uint), ("trapno", c_uint), ("err", c_uint), ("eip", c_uint), ("cs", c_uint), ("eflags", c_uint), ("esp", c_uint), ("ss", c_uint), ("gs", c_uint), ) class ptrace_io_desc(Structure): _fields_ = ( ("piod_op", c_int), ("piod_offs", c_void_p), ("piod_addr", c_void_p), ("piod_len", c_size_t), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/binding/func.py0000664000175000017500000002176300000000000021040 0ustar00vstinnervstinnerfrom os import strerror from ctypes import addressof, c_int, get_errno, set_errno, sizeof from ptrace import PtraceError from ptrace.ctypes_tools import formatAddress from ptrace.os_tools import RUNNING_LINUX, RUNNING_BSD, RUNNING_OPENBSD from ptrace.cpu_info import CPU_64BITS, CPU_WORD_SIZE, CPU_POWERPC, CPU_AARCH64 if RUNNING_OPENBSD: from ptrace.binding.openbsd_struct import ( reg as ptrace_registers_t, fpreg as user_fpregs_struct) elif RUNNING_BSD: from ptrace.binding.freebsd_struct import ( reg as ptrace_registers_t) elif RUNNING_LINUX: from ptrace.binding.linux_struct import ( user_regs_struct as ptrace_registers_t, user_fpregs_struct, siginfo, iovec_struct) if not CPU_64BITS: from ptrace.binding.linux_struct import user_fpxregs_struct else: raise NotImplementedError("Unknown OS!") REGISTER_NAMES = tuple(name for name, type in ptrace_registers_t._fields_) HAS_PTRACE_SINGLESTEP = True HAS_PTRACE_EVENTS = False HAS_PTRACE_IO = False HAS_PTRACE_SIGINFO = False HAS_PTRACE_GETREGS = False HAS_PTRACE_GETREGSET = False HAS_PTRACE_SETREGS = False HAS_PTRACE_SETREGSET = False # Special flags that are required to wait for cloned processes (threads) # See wait(2) THREAD_TRACE_FLAGS = 0x00000000 pid_t = c_int # PTRACE_xxx constants from /usr/include/sys/ptrace.h # (Linux 2.6.21 Ubuntu Feisty i386) PTRACE_TRACEME = 0 PTRACE_PEEKTEXT = 1 PTRACE_PEEKDATA = 2 PTRACE_PEEKUSER = 3 PTRACE_POKETEXT = 4 PTRACE_POKEDATA = 5 PTRACE_POKEUSER = 6 PTRACE_CONT = 7 PTRACE_KILL = 8 if HAS_PTRACE_SINGLESTEP: PTRACE_SINGLESTEP = 9 if RUNNING_OPENBSD: # OpenBSD 4.2 i386 PTRACE_ATTACH = 9 PTRACE_DETACH = 10 HAS_PTRACE_GETREGS = True PTRACE_GETREGS = 33 PTRACE_SETREGS = 34 PTRACE_GETFPREGS = 35 PTRACE_SETFPREGS = 36 HAS_PTRACE_IO = True PTRACE_IO = 11 HAS_PTRACE_SINGLESTEP = True PTRACE_SINGLESTEP = 32 # PT_STEP # HAS_PTRACE_EVENTS = True # PTRACE_SETOPTIONS = 12 # PT_SET_EVENT_MASK # PTRACE_GETEVENTMSG = 14 # PT_GET_PROCESS_STATE elif RUNNING_BSD: # FreeBSD 7.0RC1 i386 PTRACE_ATTACH = 10 PTRACE_DETACH = 11 PTRACE_SYSCALL = 22 if not CPU_POWERPC: HAS_PTRACE_GETREGS = True PTRACE_GETREGS = 33 PTRACE_SETREGS = 34 HAS_PTRACE_IO = True PTRACE_IO = 12 else: # Linux if not CPU_AARCH64: HAS_PTRACE_GETREGS = True HAS_PTRACE_SETREGS = True PTRACE_GETREGS = 12 PTRACE_SETREGS = 13 HAS_PTRACE_GETREGSET = True HAS_PTRACE_SETREGSET = True PTRACE_GETREGSET = 0x4204 PTRACE_SETREGSET = 0x4205 NT_PRSTATUS = 1 PTRACE_ATTACH = 16 PTRACE_DETACH = 17 PTRACE_SYSCALL = 24 if RUNNING_LINUX: PTRACE_GETFPREGS = 14 PTRACE_SETFPREGS = 15 if not CPU_64BITS: PTRACE_GETFPXREGS = 18 PTRACE_SETFPXREGS = 19 HAS_PTRACE_SIGINFO = True PTRACE_GETSIGINFO = 0x4202 PTRACE_SETSIGINFO = 0x4203 HAS_PTRACE_EVENTS = True PTRACE_SETOPTIONS = 0x4200 PTRACE_GETEVENTMSG = 0x4201 # Linux introduces the __WALL flag for wait THREAD_TRACE_FLAGS = 0x40000000 PTRACE_O_TRACESYSGOOD = 0x00000001 PTRACE_O_TRACEFORK = 0x00000002 PTRACE_O_TRACEVFORK = 0x00000004 PTRACE_O_TRACECLONE = 0x00000008 PTRACE_O_TRACEEXEC = 0x00000010 PTRACE_O_TRACEVFORKDONE = 0x00000020 PTRACE_O_TRACEEXIT = 0x00000040 # Wait extended result codes for the above trace options PTRACE_EVENT_FORK = 1 PTRACE_EVENT_VFORK = 2 PTRACE_EVENT_CLONE = 3 PTRACE_EVENT_EXEC = 4 PTRACE_EVENT_VFORK_DONE = 5 PTRACE_EVENT_EXIT = 6 try: from cptrace import ptrace as _ptrace HAS_CPTRACE = True except ImportError: HAS_CPTRACE = False from ctypes import c_long, c_ulong from ptrace.ctypes_libc import libc # Load ptrace() function from the system C library _ptrace = libc.ptrace _ptrace.argtypes = (c_ulong, c_ulong, c_ulong, c_ulong) _ptrace.restype = c_ulong def ptrace(command, pid=0, arg1=0, arg2=0, check_errno=False): if HAS_CPTRACE: try: set_errno(0) result = _ptrace(command, pid, arg1, arg2, check_errno) except ValueError as errobj: message = str(errobj) errno = get_errno() raise PtraceError(message, errno=errno, pid=pid) else: result = _ptrace(command, pid, arg1, arg2) result_signed = c_long(result).value if result_signed == -1: errno = get_errno() # peek operations may returns -1 with errno=0: # it's not an error. For other operations, -1 # is always an error if not(check_errno) or errno: message = "ptrace(cmd=%s, pid=%s, %r, %r) error #%s: %s" % ( command, pid, arg1, arg2, errno, strerror(errno)) raise PtraceError(message, errno=errno, pid=pid) return result def ptrace_traceme(): ptrace(PTRACE_TRACEME) def ptrace_attach(pid): ptrace(PTRACE_ATTACH, pid) def ptrace_detach(pid, signal=0): ptrace(PTRACE_DETACH, pid, 0, signal) def _peek(command, pid, address): if address % CPU_WORD_SIZE: raise PtraceError( "ptrace can't read a word from an unaligned address (%s)!" % formatAddress(address), pid=pid) return ptrace(command, pid, address, check_errno=True) def _poke(command, pid, address, word): if address % CPU_WORD_SIZE: raise PtraceError( "ptrace can't write a word to an unaligned address (%s)!" % formatAddress(address), pid=pid) ptrace(command, pid, address, word) def ptrace_peektext(pid, address): return _peek(PTRACE_PEEKTEXT, pid, address) def ptrace_peekdata(pid, address): return _peek(PTRACE_PEEKDATA, pid, address) def ptrace_peekuser(pid, address): return _peek(PTRACE_PEEKUSER, pid, address) def ptrace_poketext(pid, address, word): _poke(PTRACE_POKETEXT, pid, address, word) def ptrace_pokedata(pid, address, word): _poke(PTRACE_POKEDATA, pid, address, word) def ptrace_pokeuser(pid, address, word): _poke(PTRACE_POKEUSER, pid, address, word) def ptrace_kill(pid): ptrace(PTRACE_KILL, pid) if HAS_PTRACE_EVENTS: def WPTRACEEVENT(status): return status >> 16 def ptrace_setoptions(pid, options): ptrace(PTRACE_SETOPTIONS, pid, 0, options) def ptrace_geteventmsg(pid): new_pid = pid_t() ptrace(PTRACE_GETEVENTMSG, pid, 0, addressof(new_pid)) return new_pid.value if RUNNING_LINUX: def ptrace_syscall(pid, signum=0): ptrace(PTRACE_SYSCALL, pid, 0, signum) def ptrace_cont(pid, signum=0): ptrace(PTRACE_CONT, pid, 0, signum) def ptrace_getsiginfo(pid): info = siginfo() ptrace(PTRACE_GETSIGINFO, pid, 0, addressof(info)) return info def ptrace_setsiginfo(pid, info): ptrace(PTRACE_SETSIGINFO, pid, 0, addressof(info)) def ptrace_getfpregs(pid): fpregs = user_fpregs_struct() ptrace(PTRACE_GETFPREGS, pid, 0, addressof(fpregs)) return fpregs def ptrace_setfpregs(pid, fpregs): ptrace(PTRACE_SETFPREGS, pid, 0, addressof(fpregs)) if not CPU_64BITS: def ptrace_getfpxregs(pid): fpxregs = user_fpxregs_struct() ptrace(PTRACE_GETFPXREGS, pid, 0, addressof(fpxregs)) return fpxregs def ptrace_setfpxregs(pid, fpxregs): ptrace(PTRACE_SETFPXREGS, pid, 0, addressof(fpxregs)) if HAS_PTRACE_GETREGS: def ptrace_getregs(pid): regs = ptrace_registers_t() ptrace(PTRACE_GETREGS, pid, 0, addressof(regs)) return regs elif HAS_PTRACE_GETREGSET: def ptrace_getregs(pid): regs = ptrace_registers_t() iov = iovec_struct() setattr(iov, "buf", addressof(regs)) setattr(iov, "len", sizeof(regs)) ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, addressof(iov)) return regs if HAS_PTRACE_SETREGS: def ptrace_setregs(pid, regs): ptrace(PTRACE_SETREGS, pid, 0, addressof(regs)) elif HAS_PTRACE_SETREGSET: def ptrace_setregs(pid, regs): iov = iovec_struct() setattr(iov, "buf", addressof(regs)) setattr(iov, "len", sizeof(regs)) ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, addressof(iov)) if HAS_PTRACE_SINGLESTEP: def ptrace_singlestep(pid): ptrace(PTRACE_SINGLESTEP, pid) else: def ptrace_syscall(pid, signum=0): ptrace(PTRACE_SYSCALL, pid, 1, signum) def ptrace_cont(pid, signum=0): ptrace(PTRACE_CONT, pid, 1, signum) if HAS_PTRACE_GETREGS: def ptrace_getregs(pid): regs = ptrace_registers_t() ptrace(PTRACE_GETREGS, pid, addressof(regs)) return regs def ptrace_setregs(pid, regs): ptrace(PTRACE_SETREGS, pid, addressof(regs)) if HAS_PTRACE_SINGLESTEP: def ptrace_singlestep(pid): ptrace(PTRACE_SINGLESTEP, pid, 1) if HAS_PTRACE_IO: def ptrace_io(pid, io_desc): ptrace(PTRACE_IO, pid, addressof(io_desc)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/binding/linux_struct.py0000664000175000017500000001727200000000000022650 0ustar00vstinnervstinnerfrom ctypes import (Structure, Union, sizeof, c_char, c_ushort, c_int, c_uint, c_ulong, c_void_p, c_uint16, c_uint32, c_uint64, c_size_t) from ptrace.cpu_info import CPU_64BITS, CPU_PPC32, CPU_PPC64, CPU_ARM32, CPU_AARCH64 pid_t = c_int uid_t = c_ushort clock_t = c_uint # From /usr/include/asm-i386/user.h # Also more reliably in the kernel sources: # arch/$ARCH/include/uapi/asm/ptrace.h class register_structure(Structure): def __str__(self): regs = {} for reg in self.__class__._fields_: regs.update({reg[0]: getattr(self, reg[0])}) return str(regs) class user_regs_struct(register_structure): if CPU_PPC32: _fields_ = ( ("gpr0", c_ulong), ("gpr1", c_ulong), ("gpr2", c_ulong), ("gpr3", c_ulong), ("gpr4", c_ulong), ("gpr5", c_ulong), ("gpr6", c_ulong), ("gpr7", c_ulong), ("gpr8", c_ulong), ("gpr9", c_ulong), ("gpr10", c_ulong), ("gpr11", c_ulong), ("gpr12", c_ulong), ("gpr13", c_ulong), ("gpr14", c_ulong), ("gpr15", c_ulong), ("gpr16", c_ulong), ("gpr17", c_ulong), ("gpr18", c_ulong), ("gpr19", c_ulong), ("gpr20", c_ulong), ("gpr21", c_ulong), ("gpr22", c_ulong), ("gpr23", c_ulong), ("gpr24", c_ulong), ("gpr25", c_ulong), ("gpr26", c_ulong), ("gpr27", c_ulong), ("gpr28", c_ulong), ("gpr29", c_ulong), ("gpr30", c_ulong), ("gpr31", c_ulong), ("nip", c_ulong), ("msr", c_ulong), ("orig_gpr3", c_ulong), ("ctr", c_ulong), ("link", c_ulong), ("xer", c_ulong), ("ccr", c_ulong), ("mq", c_ulong), # FIXME: ppc64 => softe ("trap", c_ulong), ("dar", c_ulong), ("dsisr", c_ulong), ("result", c_ulong), ) elif CPU_PPC64: _fields_ = ( ("gpr0", c_ulong), ("gpr1", c_ulong), ("gpr2", c_ulong), ("gpr3", c_ulong), ("gpr4", c_ulong), ("gpr5", c_ulong), ("gpr6", c_ulong), ("gpr7", c_ulong), ("gpr8", c_ulong), ("gpr9", c_ulong), ("gpr10", c_ulong), ("gpr11", c_ulong), ("gpr12", c_ulong), ("gpr13", c_ulong), ("gpr14", c_ulong), ("gpr15", c_ulong), ("gpr16", c_ulong), ("gpr17", c_ulong), ("gpr18", c_ulong), ("gpr19", c_ulong), ("gpr20", c_ulong), ("gpr21", c_ulong), ("gpr22", c_ulong), ("gpr23", c_ulong), ("gpr24", c_ulong), ("gpr25", c_ulong), ("gpr26", c_ulong), ("gpr27", c_ulong), ("gpr28", c_ulong), ("gpr29", c_ulong), ("gpr30", c_ulong), ("gpr31", c_ulong), ("nip", c_ulong), ("msr", c_ulong), ("orig_gpr3", c_ulong), ("ctr", c_ulong), ("link", c_ulong), ("xer", c_ulong), ("ccr", c_ulong), ("softe", c_ulong), ("trap", c_ulong), ("dar", c_ulong), ("dsisr", c_ulong), ("result", c_ulong), ) elif CPU_ARM32: _fields_ = tuple(("r%i" % reg, c_ulong) for reg in range(18)) elif CPU_AARCH64: _fields_ = tuple([*[("r%i" % reg, c_ulong) for reg in range(31)], ('sp', c_ulong), ('pc', c_ulong), ('pstate', c_ulong)] ) elif CPU_64BITS: _fields_ = ( ("r15", c_ulong), ("r14", c_ulong), ("r13", c_ulong), ("r12", c_ulong), ("rbp", c_ulong), ("rbx", c_ulong), ("r11", c_ulong), ("r10", c_ulong), ("r9", c_ulong), ("r8", c_ulong), ("rax", c_ulong), ("rcx", c_ulong), ("rdx", c_ulong), ("rsi", c_ulong), ("rdi", c_ulong), ("orig_rax", c_ulong), ("rip", c_ulong), ("cs", c_ulong), ("eflags", c_ulong), ("rsp", c_ulong), ("ss", c_ulong), ("fs_base", c_ulong), ("gs_base", c_ulong), ("ds", c_ulong), ("es", c_ulong), ("fs", c_ulong), ("gs", c_ulong) ) else: _fields_ = ( ("ebx", c_ulong), ("ecx", c_ulong), ("edx", c_ulong), ("esi", c_ulong), ("edi", c_ulong), ("ebp", c_ulong), ("eax", c_ulong), ("ds", c_ushort), ("__ds", c_ushort), ("es", c_ushort), ("__es", c_ushort), ("fs", c_ushort), ("__fs", c_ushort), ("gs", c_ushort), ("__gs", c_ushort), ("orig_eax", c_ulong), ("eip", c_ulong), ("cs", c_ushort), ("__cs", c_ushort), ("eflags", c_ulong), ("esp", c_ulong), ("ss", c_ushort), ("__ss", c_ushort), ) class user_fpregs_struct(register_structure): if CPU_64BITS: _fields_ = ( ("cwd", c_uint16), ("swd", c_uint16), ("ftw", c_uint16), ("fop", c_uint16), ("rip", c_uint64), ("rdp", c_uint64), ("mxcsr", c_uint32), ("mxcr_mask", c_uint32), ("st_space", c_uint32 * 32), ("xmm_space", c_uint32 * 64), ("padding", c_uint32 * 24) ) else: _fields_ = ( ("cwd", c_ulong), ("swd", c_ulong), ("twd", c_ulong), ("fip", c_ulong), ("fcs", c_ulong), ("foo", c_ulong), ("fos", c_ulong), ("st_space", c_ulong * 20) ) if not CPU_64BITS: class user_fpxregs_struct(register_structure): _fields_ = ( ("cwd", c_ushort), ("swd", c_ushort), ("twd", c_ushort), ("fop", c_ushort), ("fip", c_ulong), ("fcs", c_ulong), ("foo", c_ulong), ("fos", c_ulong), ("mxcsr", c_ulong), ("reserved", c_ulong), ("st_space", c_ulong * 32), ("xmm_space", c_ulong * 32), ("padding", c_ulong * 56) ) # From /usr/include/asm-generic/siginfo.h class _sifields_sigfault_t(Union): _fields_ = ( ("_addr", c_void_p), ) class _sifields_sigchld_t(Structure): _fields_ = ( ("pid", pid_t), ("uid", uid_t), ("status", c_int), ("utime", clock_t), ("stime", clock_t), ) class _sifields_t(Union): _fields_ = ( ("pad", c_char * (128 - 3 * sizeof(c_int))), ("_sigchld", _sifields_sigchld_t), ("_sigfault", _sifields_sigfault_t), # ("_kill", _sifields_kill_t), # ("_timer", _sifields_timer_t), # ("_rt", _sifields_rt_t), # ("_sigpoll", _sifields_sigpoll_t), ) class siginfo(Structure): _fields_ = ( ("si_signo", c_int), ("si_errno", c_int), ("si_code", c_int), ("_sifields", _sifields_t) ) _anonymous_ = ("_sifields",) class iovec_struct(Structure): _fields_ = ( ("buf", c_void_p), ("len", c_size_t) ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/binding/openbsd_struct.py0000664000175000017500000000161500000000000023135 0ustar00vstinnervstinnerfrom ctypes import Structure, c_int, c_uint, c_ulong, c_void_p, c_char PIOD_READ_D = 1 PIOD_WRITE_D = 2 PIOD_READ_I = 3 PIOD_WRITE_I = 4 size_t = c_ulong pid_t = c_int # /usr/include/machine/reg.h class reg(Structure): _fields_ = ( ("eax", c_uint), ("ecx", c_uint), ("edx", c_uint), ("ebx", c_uint), ("esp", c_uint), ("ebp", c_uint), ("esi", c_uint), ("edi", c_uint), ("eip", c_uint), ("eflags", c_uint), ("cs", c_uint), ("ss", c_uint), ("ds", c_uint), ("es", c_uint), ("fs", c_uint), ("gs", c_uint), ) class fpreg(Structure): _fields_ = ( ("__data", c_char * 116), ) class ptrace_io_desc(Structure): _fields_ = ( ("piod_op", c_int), ("piod_offs", c_void_p), ("piod_addr", c_void_p), ("piod_len", size_t), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/cpu_info.py0000664000175000017500000000316000000000000020264 0ustar00vstinnervstinner""" Constants about the CPU: - CPU_BIGENDIAN (bool) - CPU_64BITS (bool) - CPU_WORD_SIZE (int) - CPU_MAX_UINT (int) - CPU_PPC32 (bool) - CPU_PPC64 (bool) - CPU_I386 (bool) - CPU_X86_64 (bool) - CPU_INTEL (bool) - CPU_POWERPC (bool) """ try: from os import uname HAS_UNAME = True except ImportError: HAS_UNAME = False from platform import architecture from sys import byteorder from ctypes import sizeof, c_void_p CPU_BIGENDIAN = (byteorder == 'big') CPU_64BITS = (sizeof(c_void_p) == 8) if CPU_64BITS: CPU_WORD_SIZE = 8 # bytes CPU_MAX_UINT = 0xffffffffffffffff else: CPU_WORD_SIZE = 4 # bytes CPU_MAX_UINT = 0xffffffff if HAS_UNAME: # guess machine type using uname() _machine = uname()[4] CPU_PPC32 = (_machine == 'ppc') CPU_PPC64 = (_machine in ('ppc64', 'ppc64le')) CPU_I386 = (_machine in ("i386", "i686")) # compatible Intel 32 bits CPU_X86_64 = (_machine in ("x86_64", "amd64")) # compatible Intel 64 bits CPU_ARM32 = _machine.startswith('arm') CPU_AARCH64 = (_machine == 'aarch64') del _machine else: # uname() fallback for Windows # I hope that your Windows doesn't run on PPC32/PPC64 CPU_PPC32 = False CPU_PPC64 = False CPU_I386 = False CPU_X86_64 = False CPU_ARM32 = False CPU_AARCH64 = False bits, linkage = architecture() if bits == '32bit': CPU_I386 = True elif bits == '64bit': CPU_X86_64 = True else: raise ValueError("Unknown architecture bits: %r" % bits) CPU_INTEL = (CPU_I386 or CPU_X86_64) CPU_POWERPC = (CPU_PPC32 or CPU_PPC64) CPU_ARM = (CPU_ARM32 or CPU_AARCH64) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/ctypes_libc.py0000664000175000017500000000037700000000000020771 0ustar00vstinnervstinner""" Load the system C library. Variables: - LIBC_FILENAME: the C library filename - libc: the loaded library """ from ctypes import CDLL from ctypes.util import find_library LIBC_FILENAME = find_library('c') libc = CDLL(LIBC_FILENAME, use_errno=True) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/ctypes_tools.py0000664000175000017500000000761100000000000021216 0ustar00vstinnervstinnerfrom struct import pack, unpack from ptrace.cpu_info import CPU_64BITS from ctypes import cast, POINTER def int2uint64(value): """ Convert a signed 64 bits integer into an unsigned 64 bits integer. >>> print(int2uint64(1)) 1 >>> print(int2uint64(2**64 + 1)) # ignore bits larger than 64 bits 1 >>> print(int2uint64(-1)) 18446744073709551615 >>> print(int2uint64(-2)) 18446744073709551614 """ return (value & 0xffffffffffffffff) def uint2int64(value): """ Convert an unsigned 64 bits integer into a signed 64 bits integer. >>> print(uint2int64(1)) 1 >>> print(uint2int64(2**64 + 1)) # ignore bits larger than 64 bits 1 >>> print(uint2int64(18446744073709551615)) -1 >>> print(uint2int64(18446744073709551614)) -2 """ value = value & 0xffffffffffffffff if value & 0x8000000000000000: return value - 0x10000000000000000 else: return value def truncateWord32(value): """ Truncate an unsigned integer to 32 bits. """ return value & 0xFFFFFFFF def truncateWord64(value): """ Truncate an unsigned integer to 64 bits. """ return value & 0xFFFFFFFFFFFFFFFF def formatUintHex16(value): """ Format an 16 bits unsigned integer. """ return u"0x%04x" % value def formatUintHex32(value): """ Format an 32 bits unsigned integer. """ return u"0x%08x" % value def formatUintHex64(value): """ Format an 64 bits unsigned integer. """ return u"0x%016x" % value def int2uint32(value): """ Convert a signed 32 bits integer into an unsigned 32 bits integer. >>> print(int2uint32(1)) 1 >>> print(int2uint32(2**32 + 1)) # ignore bits larger than 32 bits 1 >>> print(int2uint32(-1)) 4294967295 """ return value & 0xffffffff def uint2int32(value): """ Convert an unsigned 32 bits integer into a signed 32 bits integer. >>> print(uint2int32(1)) 1 >>> print(uint2int32(2**32 + 1)) # ignore bits larger than 32 bits 1 >>> print(uint2int32(4294967295)) -1 >>> print(uint2int32(4294967294)) -2 >>> print(uint2int32(18446744073709551615)) -1 """ value = value & 0xffffffff if value & 0x80000000: v = value - 0x100000000 else: v = value return v uint2int = uint2int32 int2uint = int2uint32 if CPU_64BITS: ulong2long = uint2int64 long2ulong = int2uint64 formatWordHex = formatUintHex64 truncateWord = truncateWord64 else: ulong2long = uint2int32 long2ulong = int2uint32 formatWordHex = formatUintHex32 truncateWord = truncateWord32 def formatAddress(address): """ Format an address to hexadecimal. Return "NULL" for zero. """ if address: return formatWordHex(address) else: return u"NULL" def formatAddressRange(start, end): """ Format an address range, e.g. "0x80004000-0x8000ffff". """ return u"%s-%s" % (formatWordHex(start), formatWordHex(end)) def ntoh_ushort(value): """ Convert an unsigned short integer from network endian to host endian. """ return unpack("H", value))[0] def ntoh_uint(value): """ Convert an unsigned integer from network endian to host endian. """ return unpack("I", value))[0] def word2bytes(word): """ Convert an unsigned integer (a CPU word) to a bytes string. """ return pack("L", word) def bytes2word(bytes): """ Convert a bytes string to an unsigned integer (a CPU word). """ return unpack("L", bytes)[0] def bytes2type(bytes, type): """ Cast a bytes string to an object of the specified type. """ return cast(bytes, POINTER(type))[0] def bytes2array(bytes, basetype, size): """ Cast a bytes string to an array of objects of the specified type and size. """ return bytes2type(bytes, basetype * size) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9375315 python-ptrace-0.9.8/ptrace/debugger/0000775000175000017500000000000000000000000017674 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/debugger/__init__.py0000664000175000017500000000112300000000000022002 0ustar00vstinnervstinnerfrom ptrace.debugger.breakpoint import Breakpoint # noqa from ptrace.debugger.process_event import (ProcessEvent, ProcessExit, # noqa NewProcessEvent, ProcessExecution) from ptrace.debugger.ptrace_signal import ProcessSignal # noqa from ptrace.debugger.process_error import ProcessError # noqa from ptrace.debugger.child import ChildError # noqa from ptrace.debugger.process import PtraceProcess # noqa from ptrace.debugger.debugger import PtraceDebugger, DebuggerError # noqa from ptrace.debugger.application import Application # noqa ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/debugger/application.py0000664000175000017500000000677500000000000022570 0ustar00vstinnervstinnerfrom optparse import OptionGroup from logging import (getLogger, StreamHandler, DEBUG, INFO, WARNING, ERROR) from sys import exit from ptrace import PtraceError from logging import error from ptrace.tools import locateProgram from ptrace.debugger import ProcessExit, DebuggerError from errno import EPERM from ptrace.debugger.child import createChild class Application(object): def __init__(self): pass def _setupLog(self, fd): logger = getLogger() handler = StreamHandler(fd) logger.addHandler(handler) if self.options.debug: level = DEBUG elif self.options.verbose: level = INFO elif self.options.quiet: level = ERROR else: level = WARNING logger.setLevel(level) def processOptions(self): if self.program: self.program[0] = locateProgram(self.program[0]) def createLogOptions(self, parser): log = OptionGroup(parser, "Logging") log.add_option("--quiet", "-q", help="Be quiet (set log level to ERROR)", action="store_true", default=False) log.add_option("--verbose", "-v", help="Debug mode (set log level to INFO)", action="store_true", default=False) log.add_option("--debug", help="Debug mode (set log level to DEBUG)", action="store_true", default=False) parser.add_option_group(log) def createChild(self, arguments, env=None): return createChild(arguments, self.options.no_stdout, env) def setupDebugger(self): # Set ptrace options if self.options.fork: try: self.debugger.traceFork() except DebuggerError: error("--fork option is not supported by your OS, sorry!") exit(1) if self.options.trace_exec: self.debugger.traceExec() if self.options.trace_clone: self.debugger.traceClone() def createProcess(self): if self.options.pid: pid = self.options.pid is_attached = False error("Attach process %s" % pid) else: pid = self.createChild(self.program) is_attached = True try: return self.debugger.addProcess(pid, is_attached=is_attached) except (ProcessExit, PtraceError) as err: if isinstance(err, PtraceError) \ and err.errno == EPERM: error( "ERROR: You are not allowed to trace process %s (permission denied or process already traced)" % pid) else: error("ERROR: Process can no be attached! %s" % err) return None def createCommonOptions(self, parser): parser.add_option("--pid", "-p", help="Attach running process specified by its identifier", type="int", default=None) parser.add_option("--fork", "-f", help="Trace fork() event and child processes", action="store_true", default=False) parser.add_option("--trace-exec", help="Trace execve() event", action="store_true", default=False) parser.add_option("--trace-clone", help="Trace clone() event", action="store_true", default=False) parser.add_option("--no-stdout", help="Use /dev/null as stdout/stderr, or close stdout and stderr if /dev/null doesn't exist", action="store_true", default=False) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065691.0 python-ptrace-0.9.8/ptrace/debugger/backtrace.py0000664000175000017500000000550400000000000022171 0ustar00vstinnervstinnerfrom ptrace.ctypes_tools import formatAddress, formatWordHex from ptrace.cpu_info import CPU_WORD_SIZE, CPU_MAX_UINT from ptrace import PtraceError class BacktraceFrame(object): """ Backtrace frame. Attributes: - ip: instruction pointer - name: name of the function - arguments: value of the arguments """ def __init__(self, ip): self.ip = ip self.name = u"???" self.arguments = [] def __str__(self): arguments = (formatWordHex(arg) for arg in self.arguments) return u"IP=%s: %s (%s)" % (formatAddress(self.ip), self.name, ", ".join(arguments)) class Backtrace(object): """ Backtrace: all process frames since the start function. """ def __init__(self): self.frames = [] self.truncated = False def append(self, frame): self.frames.append(frame) def __iter__(self): return iter(self.frames) def __len__(self): return len(self.frames) def getBacktrace(process, max_args=6, max_depth=20): """ Get the current backtrace of the specified process: - max_args: maximum number of arguments in a frame - max_depth: maximum number of frames Return a Backtrace object. """ backtrace = Backtrace() # Get current instruction and frame pointer ip = process.getInstrPointer() fp = process.getFramePointer() depth = 0 while True: # Hit maximum trace depth? if max_depth <= depth: backtrace.truncated = True break # Read next frame pointer try: nextfp = process.readWord(fp) except PtraceError: nextfp = None # Guess number of function argument if fp and nextfp: nargs = ((nextfp - fp) // CPU_WORD_SIZE) - 2 nargs = min(nargs, max_args) else: nargs = 0 # Create frame frame = getBacktraceFrame(process, ip, fp, nargs) backtrace.append(frame) # End of the stack? if not nextfp: break # Move to next instruction/frame pointer ip = process.readWord(fp + CPU_WORD_SIZE) if ip == CPU_MAX_UINT: # Linux hack to detect end of the stack break fp = nextfp depth += 1 return backtrace def getBacktraceFrame(process, ip, fp, nargs): """ Get a backtrace frame: - ip: instruction pointer - fp: frame pointer - nargs: number of arguments Return a BacktraceFrame object. """ frame = BacktraceFrame(ip) address = fp + CPU_WORD_SIZE try: for index in range(nargs): address += CPU_WORD_SIZE word = process.readWord(address) frame.arguments.append(word) except PtraceError: # Ignore argument read error pass return frame ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065699.0 python-ptrace-0.9.8/ptrace/debugger/breakpoint.py0000664000175000017500000000365100000000000022411 0ustar00vstinnervstinnerfrom ptrace.ctypes_tools import formatAddress from ptrace import PtraceError from logging import info from weakref import ref from ptrace.cpu_info import CPU_POWERPC, CPU_WORD_SIZE from ptrace.ctypes_tools import word2bytes class Breakpoint(object): """ Software breakpoint. Use desinstall() method to remove the breakpoint from the process. """ def __init__(self, process, address, size=None): self._installed = False self.process = ref(process) self.address = address if CPU_POWERPC: size = CPU_WORD_SIZE elif size is None: size = 1 self.size = size # Store instruction bytes info("Install %s" % self) self.old_bytes = process.readBytes(address, size) if CPU_POWERPC: # Replace instruction with "TRAP" new_bytes = word2bytes(0x0cc00000) else: # Replace instruction with "INT 3" new_bytes = b"\xCC" * size process.writeBytes(address, new_bytes) self._installed = True def desinstall(self, set_ip=False): """ Remove the breakpoint from the associated process. If set_ip is True, restore the instruction pointer to the address of the breakpoint. """ if not self._installed: return self._installed = False info("Desinstall %s" % self) process = self.process() if not process: return if process.running: process.writeBytes(self.address, self.old_bytes) if set_ip: process.setInstrPointer(self.address) process.removeBreakpoint(self) def __str__(self): return "" % ( formatAddress(self.address), formatAddress(self.address + self.size - 1)) def __del__(self): try: self.desinstall(False) except PtraceError: pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065641.0 python-ptrace-0.9.8/ptrace/debugger/child.py0000664000175000017500000001044500000000000021335 0ustar00vstinnervstinner""" Error pipe and serialization code comes from Python 2.5 subprocess module. """ from os import ( fork, execvp, execvpe, waitpid, close, dup2, pipe, read, write, devnull, sysconf, set_inheritable) from sys import exc_info from traceback import format_exception from ptrace.binding import ptrace_traceme from ptrace import PtraceError from sys import exit from errno import EINTR import fcntl import pickle try: MAXFD = sysconf("SC_OPEN_MAX") except Exception: MAXFD = 256 class ChildError(RuntimeError): pass class ChildPtraceError(ChildError): pass def _set_cloexec_flag(fd): try: cloexec_flag = fcntl.FD_CLOEXEC except AttributeError: cloexec_flag = 1 old = fcntl.fcntl(fd, fcntl.F_GETFD) fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) def _waitpid_no_intr(pid, options): """Like os.waitpid, but retries on EINTR""" while True: try: return waitpid(pid, options) except OSError as e: if e.errno == EINTR: continue else: raise def _read_no_intr(fd, buffersize): """Like os.read, but retries on EINTR""" while True: try: return read(fd, buffersize) except OSError as e: if e.errno == EINTR: continue else: raise def _write_no_intr(fd, s): """Like os.write, but retries on EINTR""" while True: try: return write(fd, s) except OSError as e: if e.errno == EINTR: continue else: raise def _createParent(pid, errpipe_read): # Wait for exec to fail or succeed; possibly raising exception data = _read_no_intr(errpipe_read, 1048576) # Exceptions limited to 1 MB close(errpipe_read) if data: _waitpid_no_intr(pid, 0) child_exception = pickle.loads(data) raise child_exception def _createChild(arguments, no_stdout, env, errpipe_write, close_fds=True, pass_fds=()): # Child code try: ptrace_traceme() except PtraceError as err: raise ChildError(str(err)) for fd in pass_fds: set_inheritable(fd, True) if close_fds: # Close all files except 0, 1, 2 and errpipe_write for fd in range(3, MAXFD): if fd == errpipe_write or (fd in pass_fds): continue try: close(fd) except OSError: pass try: _execChild(arguments, no_stdout, env) except: # noqa: E722 exc_type, exc_value, tb = exc_info() # Save the traceback and attach it to the exception object exc_lines = format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) _write_no_intr(errpipe_write, pickle.dumps(exc_value)) exit(255) def _execChild(arguments, no_stdout, env): if no_stdout: try: null = open(devnull, 'wb') dup2(null.fileno(), 1) dup2(1, 2) null.close() except IOError: close(2) close(1) try: if env is not None: execvpe(arguments[0], arguments, env) else: execvp(arguments[0], arguments) except Exception as err: raise ChildError(str(err)) def createChild(arguments, no_stdout, env=None, close_fds=True, pass_fds=()): """ Create a child process: - arguments: list of string where (e.g. ['ls', '-la']) - no_stdout: if True, use null device for stdout/stderr - env: environment variables dictionary Use: - env={} to start with an empty environment - env=None (default) to copy the environment """ if pass_fds and not close_fds: close_fds = True errpipe_read, errpipe_write = pipe() _set_cloexec_flag(errpipe_write) # Fork process pid = fork() if pid: close(errpipe_write) _createParent(pid, errpipe_read) return pid else: close(errpipe_read) _createChild(arguments, no_stdout, env, errpipe_write, close_fds=close_fds, pass_fds=pass_fds) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/debugger/debugger.py0000664000175000017500000002317600000000000022043 0ustar00vstinnervstinnerfrom logging import info, warning, error from ptrace import PtraceError from os import waitpid, WNOHANG from signal import SIGTRAP, SIGSTOP from errno import ECHILD from ptrace.debugger import PtraceProcess, ProcessSignal from ptrace.binding import HAS_PTRACE_EVENTS from time import sleep if HAS_PTRACE_EVENTS: from ptrace.binding.func import ( PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK, PTRACE_O_TRACEEXEC, PTRACE_O_TRACESYSGOOD, PTRACE_O_TRACECLONE, THREAD_TRACE_FLAGS) class DebuggerError(PtraceError): pass class PtraceDebugger(object): """ Debugger managing one or multiple processes at the same time. Methods ======= * Process list: - addProcess(): add a new process - deleteProcess(): remove a process from the debugger * Wait for an event: - waitProcessEvent(): wait for a process event - waitSignals(): wait for a signal - waitSyscall(): wait for the next syscall event * Options: - traceFork(): enable fork() tracing - traceExec(): enable exec() tracing - traceClone(): enable clone() tracing - enableSysgood(): enable sysgood option * Other: - quit(): quit the debugger, terminate all processes Operations ========== - iterate on all processes: "for process in debugger: ..." - get a process by its identifier: "process = debugger[pid]" - get the number of processes: len(debugger) Attributes ========== - dict: processes dictionary (pid -> PtraceProcess) - list: processes list - options: ptrace options - trace_fork (bool): fork() tracing is enabled? - trace_exec (bool): exec() tracing is enabled? - trace_clone (bool): clone() tracing is enabled? - use_sysgood (bool): sysgood option is enabled? """ def __init__(self): self.dict = {} # pid -> PtraceProcess object self.list = [] self.options = 0 self.trace_fork = False self.trace_exec = False self.trace_clone = False self.use_sysgood = False self.enableSysgood() def addProcess(self, pid, is_attached, parent=None, is_thread=False): """ Add a new process using its identifier. Use is_attached=False to attach an existing (running) process, and is_attached=True to trace a new (stopped) process. """ if pid in self.dict: raise KeyError("The process %s is already registered!" % pid) process = PtraceProcess(self, pid, is_attached, parent=parent, is_thread=is_thread) info("Attach %s to debugger" % process) self.dict[pid] = process self.list.append(process) try: process.waitSignals(SIGTRAP, SIGSTOP) except KeyboardInterrupt: error( "User interrupt! Force the process %s attach " "(don't wait for signals)." % pid) except ProcessSignal as event: event.display() except: # noqa: E722 process.is_attached = False process.detach() raise if HAS_PTRACE_EVENTS and self.options: process.setoptions(self.options) return process def quit(self): """ Quit the debugger: terminate all processes in reverse order. """ info("Quit debugger") # Terminate processes in reverse order # to kill children before parents processes = list(self.list) for process in reversed(processes): process.terminate() process.detach() def _waitpid(self, wanted_pid, blocking=True): """ Wait for a process event from a specific process (if wanted_pid is set) or any process (wanted_pid=None). The call is blocking is blocking option is True. Return the tuple (pid, status). See os.waitpid() documentation for explanations about the result. """ flags = 0 if not blocking: flags |= WNOHANG if wanted_pid: if wanted_pid not in self.dict: raise DebuggerError("Unknown PID: %r" % wanted_pid, pid=wanted_pid) process = self.dict[wanted_pid] if process.is_thread: flags |= THREAD_TRACE_FLAGS pid, status = waitpid(wanted_pid, flags) else: pid, status = waitpid(-1, flags) if (blocking or pid) and wanted_pid and (pid != wanted_pid): raise DebuggerError("Unwanted PID: %r (instead of %s)" % (pid, wanted_pid), pid=pid) return pid, status def _wait_event_pid(self, wanted_pid, blocking=True): """ Wait for a process event from the specified process identifier. If blocking=False, return None if there is no new event, otherwise return an object based on ProcessEvent. """ process = None while not process: try: pid, status = self._waitpid(wanted_pid, blocking) except OSError as err: if err.errno == ECHILD: process = self.dict[wanted_pid] return process.processTerminated() else: raise err if not blocking and not pid: return None try: process = self.dict[pid] except KeyError: warning("waitpid() warning: Unknown PID %r" % pid) return process.processStatus(status) def _wait_event(self, wanted_pid, blocking=True): if wanted_pid is not None: return self._wait_event_pid(wanted_pid, blocking) pause = 0.001 while True: pids = tuple(self.dict) if len(pids) > 1: for pid in pids: process = self._wait_event_pid(pid, False) if process is not None: return process if not blocking: return None pause = min(pause * 2, 0.5) sleep(pause) else: return self._wait_event_pid(pids[0], blocking) def waitProcessEvent(self, pid=None, blocking=True): """ Wait for a process event from a specific process (if pid option is set) or any process (default). If blocking=False, return None if there is no new event, otherwise return an object based on ProcessEvent. """ return self._wait_event(pid, blocking) def waitSignals(self, *signals, **kw): """ Wait for any signal or some specific signals (if specified) from a specific process (if pid keyword is set) or any process (default). Return a ProcessSignal object or raise an unexpected ProcessEvent. """ pid = kw.get('pid', None) while True: event = self._wait_event(pid) if event.__class__ != ProcessSignal: raise event signum = event.signum if signum in signals or not signals: return event raise event def waitSyscall(self, process=None): """ Wait for the next syscall event (enter or exit) for a specific process (if specified) or any process (default). Return a ProcessSignal object or raise an unexpected ProcessEvent. """ signum = SIGTRAP if self.use_sysgood: signum |= 0x80 if process: return self.waitSignals(signum, pid=process.pid) else: return self.waitSignals(signum) def deleteProcess(self, process=None, pid=None): """ Delete a process from the process list. """ if not process: try: process = self.dict[pid] except KeyError: return try: del self.dict[process.pid] except KeyError: pass try: self.list.remove(process) except ValueError: pass def traceFork(self): """ Enable fork() tracing. Do nothing if it's not supported. """ if not HAS_PTRACE_EVENTS: raise DebuggerError( "Tracing fork events is not supported on this architecture or operating system") self.options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK self.trace_fork = True info("Debugger trace forks (options=%s)" % self.options) def traceExec(self): """ Enable exec() tracing. Do nothing if it's not supported. """ if not HAS_PTRACE_EVENTS: # no effect on OS without ptrace events return self.trace_exec = True self.options |= PTRACE_O_TRACEEXEC def traceClone(self): """ Enable clone() tracing. Do nothing if it's not supported. """ if not HAS_PTRACE_EVENTS: # no effect on OS without ptrace events return self.trace_clone = True self.options |= PTRACE_O_TRACECLONE def enableSysgood(self): """ Enable sysgood option: ask the kernel to set bit #7 of the signal number if the signal comes from the kernel space. If the signal comes from the user space, the bit is unset. """ if not HAS_PTRACE_EVENTS: # no effect on OS without ptrace events return self.use_sysgood = True self.options |= PTRACE_O_TRACESYSGOOD def __getitem__(self, pid): return self.dict[pid] def __iter__(self): return iter(self.list) def __len__(self): return len(self.list) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1586773864.0 python-ptrace-0.9.8/ptrace/debugger/memory_mapping.py0000664000175000017500000001004600000000000023272 0ustar00vstinnervstinnerfrom ptrace.os_tools import HAS_PROC from ptrace.debugger.process_error import ProcessError from ptrace.ctypes_tools import formatAddress import re from weakref import ref if HAS_PROC: from ptrace.linux_proc import openProc, ProcError PROC_MAP_REGEX = re.compile( # Address range: '08048000-080b0000 ' r'([0-9a-f]+)-([0-9a-f]+) ' # Permission: 'r-xp ' r'(.{4}) ' # Offset: '0804d000' r'([0-9a-f]+) ' # Device (major:minor): 'fe:01 ' r'([0-9a-f]{2,3}):([0-9a-f]{2}) ' # Inode: '3334030' r'([0-9]+)' # Filename: ' /usr/bin/synergyc' r'(?: +(.*))?') class MemoryMapping(object): """ Process memory mapping (metadata about the mapping). Attributes: - start (int): first byte address - end (int): last byte address + 1 - permissions (str) - offset (int): for file, offset in bytes from the file start - major_device / minor_device (int): major / minor device number - inode (int) - pathname (str) - _process: weak reference to the process Operations: - "address in mapping" checks the address is in the mapping. - "search(somestring)" returns the offsets of "somestring" in the mapping - "str(mapping)" create one string describing the mapping - "repr(mapping)" create a string representation of the mapping, useful in list contexts """ def __init__(self, process, start, end, permissions, offset, major_device, minor_device, inode, pathname): self._process = ref(process) self.start = start self.end = end self.permissions = permissions self.offset = offset self.major_device = major_device self.minor_device = minor_device self.inode = inode self.pathname = pathname def __contains__(self, address): return self.start <= address < self.end def __str__(self): text = "%s-%s" % (formatAddress(self.start), formatAddress(self.end)) if self.pathname: text += " => %s" % self.pathname text += " (%s)" % self.permissions return text __repr__ = __str__ def search(self, bytestr): process = self._process() bytestr_len = len(bytestr) buf_len = 64 * 1024 if buf_len < bytestr_len: buf_len = bytestr_len remaining = self.end - self.start covered = self.start while remaining >= bytestr_len: if remaining > buf_len: requested = buf_len else: requested = remaining data = process.readBytes(covered, requested) if data == "": break offset = data.find(bytestr) if (offset == -1): skip = requested - bytestr_len + 1 else: yield (covered + offset) skip = offset + bytestr_len covered += skip remaining -= skip def readProcessMappings(process): """ Read all memory mappings of the specified process. Return a list of MemoryMapping objects, or empty list if it's not possible to read the mappings. May raise a ProcessError. """ maps = [] if not HAS_PROC: return maps try: mapsfile = openProc("%s/maps" % process.pid) except ProcError as err: raise ProcessError(process, "Unable to read process maps: %s" % err) try: for line in mapsfile: line = line.rstrip() match = PROC_MAP_REGEX.match(line) if not match: raise ProcessError( process, "Unable to parse memory mapping: %r" % line) map = MemoryMapping( process, int(match.group(1), 16), int(match.group(2), 16), match.group(3), int(match.group(4), 16), int(match.group(5), 16), int(match.group(6), 16), int(match.group(7)), match.group(8)) maps.append(map) finally: mapsfile.close() return maps ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/debugger/parse_expr.py0000664000175000017500000000400100000000000022411 0ustar00vstinnervstinnerimport re # Match a register name: $eax, $gp0, $orig_eax REGISTER_REGEX = re.compile(r"([a-z]+[a-z0-9_]+)") # Hexadecimal number (e.g. 0xa) HEXADECIMAL_REGEX = re.compile(r"0x[0-9a-f]+") # Make sure that the expression does not contain invalid characters # Examples: # (1-2)<<5 # 340&91 EXPR_REGEX = re.compile(r"^[()<>+*/&0-9-]+$") def replaceHexadecimal(regs): """ Convert an hexadecimal number to decimal number (as string). Callback used by parseExpression(). """ text = regs.group(0) if text.startswith("0x"): text = text[2:] elif not re.search("[a-f]", text): return text value = int(text, 16) return str(value) def parseExpression(process, text): """ Parse an expression. Syntax: - "10": decimal number - "0x10": hexadecimal number - "eax": register value - "a+b", "a-b", "a*b", "a/b", "a**b", "a<>b": operators >>> from ptrace.mockup import FakeProcess >>> process = FakeProcess() >>> parseExpression(process, "1+1") 2 >>> process.setreg("eax", 3) >>> parseExpression(process, "eax*0x10") 48 """ # Remove spaces and convert to lower case text = text.strip() orig_text = text if " " in text: raise ValueError("Space are forbidden: %r" % text) text = text.lower() def readRegister(regs): name = regs.group(1) value = process.getreg(name) return str(value) # Replace hexadecimal by decimal text = HEXADECIMAL_REGEX.sub(replaceHexadecimal, text) # Replace registers by their value text = REGISTER_REGEX.sub(readRegister, text) # Reject invalid characters if not EXPR_REGEX.match(text): raise ValueError("Invalid expression: %r" % orig_text) # Use integer division (a//b) instead of float division (a/b) text = text.replace("/", "//") # Finally, evaluate the expression try: value = eval(text) except SyntaxError: raise ValueError("Invalid expression: %r" % orig_text) return value ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1616012250.0 python-ptrace-0.9.8/ptrace/debugger/process.py0000664000175000017500000006225100000000000021732 0ustar00vstinnervstinnerfrom ptrace.binding import ( HAS_PTRACE_SINGLESTEP, HAS_PTRACE_EVENTS, HAS_PTRACE_SIGINFO, HAS_PTRACE_IO, HAS_PTRACE_GETREGS, HAS_PTRACE_GETREGSET, ptrace_attach, ptrace_detach, ptrace_cont, ptrace_syscall, ptrace_setregs, ptrace_peektext, ptrace_poketext, REGISTER_NAMES) from ptrace.os_tools import HAS_PROC, RUNNING_BSD, RUNNING_PYTHON3 from ptrace.tools import dumpRegs from ptrace.cpu_info import CPU_WORD_SIZE from ptrace.ctypes_tools import bytes2word, word2bytes, bytes2type, bytes2array from signal import SIGTRAP, SIGSTOP, SIGKILL from ptrace.ctypes_tools import formatAddress, formatWordHex from ctypes import sizeof, c_char_p from logging import info, warning, error from ptrace.error import PtraceError from errno import ESRCH, EACCES from ptrace.debugger import (Breakpoint, ProcessExit, ProcessSignal, NewProcessEvent, ProcessExecution) from os import (kill, WIFSTOPPED, WSTOPSIG, WIFSIGNALED, WTERMSIG, WIFEXITED, WEXITSTATUS) from ptrace.disasm import HAS_DISASSEMBLER from ptrace.debugger.backtrace import getBacktrace from ptrace.debugger.process_error import ProcessError from ptrace.debugger.memory_mapping import readProcessMappings from ptrace.binding.cpu import CPU_INSTR_POINTER, CPU_STACK_POINTER, CPU_FRAME_POINTER, CPU_SUB_REGISTERS from ptrace.debugger.syscall_state import SyscallState if HAS_PTRACE_SINGLESTEP: from ptrace.binding import ptrace_singlestep if HAS_PTRACE_SIGINFO: from ptrace.binding import ptrace_getsiginfo if HAS_PTRACE_IO: from ctypes import create_string_buffer, addressof from ptrace.binding import ( ptrace_io, ptrace_io_desc, PIOD_READ_D, PIOD_WRITE_D) if HAS_PTRACE_EVENTS: from ptrace.binding import ( ptrace_setoptions, ptrace_geteventmsg, WPTRACEEVENT, PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK, PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC) NEW_PROCESS_EVENT = ( PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK, PTRACE_EVENT_CLONE) if HAS_PTRACE_GETREGS or HAS_PTRACE_GETREGSET: from ptrace.binding import ptrace_getregs else: from ptrace.binding import ptrace_peekuser, ptrace_registers_t if HAS_DISASSEMBLER: from ptrace.disasm import disassemble, disassembleOne, MAX_INSTR_SIZE if HAS_PROC: from ptrace.linux_proc import readProcessStat MIN_CODE_SIZE = 32 MAX_CODE_SIZE = 1024 DEFAULT_NB_INSTR = 10 DEFAULT_CODE_SIZE = 24 class PtraceProcess(object): """ Process traced by a PtraceDebugger. Methods ======= * control execution: - singleStep(): execute one instruction - cont(): continue the execution - syscall(): break at next syscall - setInstrPointer(): change the instruction pointer - kill(): send a signal to the process - terminate(): kill the process * wait an event: - waitEvent(): wait next process event - waitSignals(): wait a signal * get status - getreg(): get a register - getInstrPointer(): get the instruction pointer - getStackPointer(): get the stack pointer - getFramePointer(): get the stack pointer - getregs(): get all registers, e.g. regs=getregs(); print regs.eax - disassemble(): assembler code of the next instructions - disassembleOne(): assembler code of the next instruction - findStack(): get stack memory mapping - getsiginfo(): get signal information - getBacktrace(): get the current backtrace * set status - setreg(): set a register - setregs(): set all registers * memory access: - readWord(): read a memory word - readBytes(): read some bytes - readStruct(): read a structure - readArray(): read an array - readCString(): read a C string - readMappings(): get all memory mappings - writeWord(): write a memory word - writeBytes(): write some bytes * display status: - dumpCode(): display the next instructions - dumpStack(): display some memory words around the stack pointer - dumpMaps(): display memory mappings - dumpRegs(): display all registers * breakpoint: - createBreakpoint(): set a breakpoint - findBreakpoint(): find a breakpoint - removeBreakpoint(): remove a breakpoint * other: - setoptions(): set ptrace options See each method to get better documentation. You are responsible to manage the process state: some methods may fail or crash your processus if they are called when the process is in the wrong state. Attributes ========== * main attributes: - pid: identifier of the process - debugger: PtraceDebugger instance - breakpoints: dictionary of active breakpoints - parent: parent PtraceProcess (None if process has no parent) * state: - running: if True, the process is alive, otherwise the process doesn't exist anymore - exited: if True, the process has exited (attributed only used on BSD operation systems) - is_attached: if True, the process is attached by ptrace - was_attached: if True, the process will be detached at exit - is_stopped: if True, the process is stopped, otherwise it's running - syscall_state: control syscall tracing Sometimes, is_stopped value is wrong. You might use isTraced() to make sure that the process is stopped. """ def __init__(self, debugger, pid, is_attached, parent=None, is_thread=False): self.debugger = debugger self.breakpoints = {} self.pid = pid self.running = True self.exited = False self.parent = parent self.was_attached = is_attached self.is_attached = False self.is_stopped = True self.is_thread = is_thread if not is_attached: self.attach() else: self.is_attached = True if HAS_PROC: self.read_mem_file = None self.syscall_state = SyscallState(self) def isTraced(self): if not HAS_PROC: self.notImplementedError() stat = readProcessStat(self.pid) return (stat.state == 'T') def attach(self): if self.is_attached: return info("Attach process %s" % self.pid) ptrace_attach(self.pid) self.is_attached = True def dumpCode(self, start=None, stop=None, manage_bp=False, log=None): if not log: log = error try: ip = self.getInstrPointer() except PtraceError as err: if start is None: log("Unable to read instruction pointer: %s" % err) return ip = None if start is None: start = ip try: self._dumpCode(start, stop, ip, manage_bp, log) except PtraceError as err: log("Unable to dump code at %s: %s" % ( formatAddress(start), err)) def _dumpCode(self, start, stop, ip, manage_bp, log): if stop is not None: stop = max(start, stop) stop = min(stop, start + MAX_CODE_SIZE - 1) if not HAS_DISASSEMBLER: if stop is not None: size = stop - start + 1 else: size = MIN_CODE_SIZE code = self.readBytes(start, size) if RUNNING_PYTHON3: text = " ".join("%02x" % byte for byte in code) else: text = " ".join("%02x" % ord(byte) for byte in code) log("CODE: %s" % text) return log("CODE:") if manage_bp: address = start for line in range(10): bp = False if address in self.breakpoints: bytes = self.breakpoints[address].old_bytes instr = disassembleOne(bytes, address) bp = True else: instr = self.disassembleOne(address) text = "%s| %s (%s)" % (formatAddress( instr.address), instr.text, instr.hexa) if instr.address == ip: text += " <==" if bp: text += " * BREAKPOINT *" log(text) address = address + instr.size if stop is not None and stop <= address: break else: for instr in self.disassemble(start, stop): text = "%s| %s (%s)" % (formatAddress( instr.address), instr.text, instr.hexa) if instr.address == ip: text += " <==" log(text) def disassemble(self, start=None, stop=None, nb_instr=None): if not HAS_DISASSEMBLER: self.notImplementedError() if start is None: start = self.getInstrPointer() if stop is not None: stop = max(start, stop) size = stop - start + 1 else: if nb_instr is None: nb_instr = DEFAULT_NB_INSTR size = nb_instr * MAX_INSTR_SIZE code = self.readBytes(start, size) for index, instr in enumerate(disassemble(code, start)): yield instr if nb_instr and nb_instr <= (index + 1): break def disassembleOne(self, address=None): if not HAS_DISASSEMBLER: self.notImplementedError() if address is None: address = self.getInstrPointer() code = self.readBytes(address, MAX_INSTR_SIZE) return disassembleOne(code, address) def findStack(self): for map in self.readMappings(): if map.pathname == "[stack]": return map return None def detach(self): if not self.is_attached: return self.is_attached = False if self.running: info("Detach %s" % self) ptrace_detach(self.pid) self.debugger.deleteProcess(process=self) def _notRunning(self): self.running = False if HAS_PROC and self.read_mem_file: try: self.read_mem_file.close() except IOError: pass self.detach() def kill(self, signum): kill(self.pid, signum) def terminate(self, wait_exit=True): if not self.running or not self.was_attached: return True warning("Terminate %s" % self) done = False try: if self.is_stopped: self.cont(SIGKILL) else: self.kill(SIGKILL) except PtraceError as event: if event.errno == ESRCH: done = True else: raise event if not done: if not wait_exit: return False self.waitExit() self._notRunning() return True def waitExit(self): while True: # Wait for any process signal event = self.waitEvent() event_cls = event.__class__ # Process exited: we are done if event_cls == ProcessExit: return # Event different than a signal? Raise an exception if event_cls != ProcessSignal: raise event # Send the signal to the process signum = event.signum if signum not in (SIGTRAP, SIGSTOP): self.cont(signum) else: self.cont() def processStatus(self, status): # Process exited? if WIFEXITED(status): code = WEXITSTATUS(status) event = self.processExited(code) # Process killed by a signal? elif WIFSIGNALED(status): signum = WTERMSIG(status) event = self.processKilled(signum) # Invalid process status? elif not WIFSTOPPED(status): raise ProcessError(self, "Unknown process status: %r" % status) # Ptrace event? elif HAS_PTRACE_EVENTS and WPTRACEEVENT(status): event = WPTRACEEVENT(status) event = self.ptraceEvent(event) else: signum = WSTOPSIG(status) event = self.processSignal(signum) return event def processTerminated(self): self._notRunning() return ProcessExit(self) def processExited(self, code): if RUNNING_BSD and not self.exited: # on FreeBSD, we have to waitpid() twice # to avoid zombi process!? self.exited = True self.waitExit() self._notRunning() return ProcessExit(self, exitcode=code) def processKilled(self, signum): self._notRunning() return ProcessExit(self, signum=signum) def processSignal(self, signum): self.is_stopped = True return ProcessSignal(signum, self) def ptraceEvent(self, event): if not HAS_PTRACE_EVENTS: self.notImplementedError() if event in NEW_PROCESS_EVENT: new_pid = ptrace_geteventmsg(self.pid) is_thread = (event == PTRACE_EVENT_CLONE) new_process = self.debugger.addProcess( new_pid, is_attached=True, parent=self, is_thread=is_thread) return NewProcessEvent(new_process) elif event == PTRACE_EVENT_EXEC: return ProcessExecution(self) else: raise ProcessError(self, "Unknown ptrace event: %r" % event) def getregs(self): if HAS_PTRACE_GETREGS or HAS_PTRACE_GETREGSET: return ptrace_getregs(self.pid) else: # FIXME: Optimize getreg() when used with this function words = [] nb_words = sizeof(ptrace_registers_t) // CPU_WORD_SIZE for offset in range(nb_words): word = ptrace_peekuser(self.pid, offset * CPU_WORD_SIZE) bytes = word2bytes(word) words.append(bytes) bytes = ''.join(words) return bytes2type(bytes, ptrace_registers_t) def getreg(self, name): try: name, shift, mask = CPU_SUB_REGISTERS[name] except KeyError: shift = 0 mask = None if name not in REGISTER_NAMES: raise ProcessError(self, "Unknown register: %r" % name) regs = self.getregs() value = getattr(regs, name) value >>= shift if mask: value &= mask return value def setregs(self, regs): ptrace_setregs(self.pid, regs) def setreg(self, name, value): regs = self.getregs() if name in CPU_SUB_REGISTERS: full_name, shift, mask = CPU_SUB_REGISTERS[name] full_value = getattr(regs, full_name) full_value &= ~mask full_value |= ((value & mask) << shift) value = full_value name = full_name if name not in REGISTER_NAMES: raise ProcessError(self, "Unknown register: %r" % name) setattr(regs, name, value) self.setregs(regs) def singleStep(self): if not HAS_PTRACE_SINGLESTEP: self.notImplementedError() ptrace_singlestep(self.pid) def filterSignal(self, signum): if signum == SIGTRAP: # Never transfer SIGTRAP signal return 0 else: return signum def syscall(self, signum=0): signum = self.filterSignal(signum) ptrace_syscall(self.pid, signum) self.is_stopped = False def setInstrPointer(self, ip): if CPU_INSTR_POINTER: self.setreg(CPU_INSTR_POINTER, ip) else: raise ProcessError( self, "Instruction pointer register is not defined") def getInstrPointer(self): if CPU_INSTR_POINTER: return self.getreg(CPU_INSTR_POINTER) else: raise ProcessError( self, "Instruction pointer register is not defined") def getStackPointer(self): if CPU_STACK_POINTER: return self.getreg(CPU_STACK_POINTER) else: raise ProcessError(self, "Stack pointer register is not defined") def getFramePointer(self): if CPU_FRAME_POINTER: return self.getreg(CPU_FRAME_POINTER) else: raise ProcessError(self, "Stack pointer register is not defined") def _readBytes(self, address, size): offset = address % CPU_WORD_SIZE if offset: # Read word address -= offset word = self.readWord(address) bytes = word2bytes(word) # Read some bytes from the word subsize = min(CPU_WORD_SIZE - offset, size) data = bytes[offset:offset + subsize] # <-- FIXME: Big endian! # Move cursor size -= subsize address += CPU_WORD_SIZE else: data = b'' while size: # Read word word = self.readWord(address) bytes = word2bytes(word) # Read bytes from the word if size < CPU_WORD_SIZE: data += bytes[:size] # <-- FIXME: Big endian! break data += bytes # Move cursor size -= CPU_WORD_SIZE address += CPU_WORD_SIZE return data def readWord(self, address): """Address have to be aligned!""" word = ptrace_peektext(self.pid, address) return word if HAS_PTRACE_IO: def readBytes(self, address, size): buffer = create_string_buffer(size) io_desc = ptrace_io_desc( piod_op=PIOD_READ_D, piod_offs=address, piod_addr=addressof(buffer), piod_len=size) ptrace_io(self.pid, io_desc) return buffer.raw elif HAS_PROC: def readBytes(self, address, size): if not self.read_mem_file: filename = '/proc/%u/mem' % self.pid try: self.read_mem_file = open(filename, 'rb', 0) except IOError as err: message = "Unable to open %s: fallback to ptrace implementation" % filename if err.errno != EACCES: error(message) else: info(message) self.readBytes = self._readBytes return self.readBytes(address, size) try: mem = self.read_mem_file mem.seek(address) data = mem.read(size) except (IOError, ValueError) as err: raise ProcessError(self, "readBytes(%s, %s) error: %s" % ( formatAddress(address), size, err)) if len(data) == 0 and size: # Issue #10: If the process was not created by the debugger # (ex: fork), the kernel may deny reading private mappings of # /proc/pid/mem to the debugger, depending on the kernel # version and kernel config (ex: SELinux enabled or not). # # Fallback to PTRACE_PEEKTEXT. It is slower but a debugger # tracing the process is always allowed to use it. self.readBytes = self._readBytes return self.readBytes(address, size) return data else: readBytes = _readBytes def getsiginfo(self): if not HAS_PTRACE_SIGINFO: self.notImplementedError() return ptrace_getsiginfo(self.pid) def writeBytes(self, address, bytes): if HAS_PTRACE_IO: size = len(bytes) bytes = create_string_buffer(bytes) io_desc = ptrace_io_desc( piod_op=PIOD_WRITE_D, piod_offs=address, piod_addr=addressof(bytes), piod_len=size) ptrace_io(self.pid, io_desc) else: offset = address % CPU_WORD_SIZE if offset: # Write partial word (end) address -= offset size = CPU_WORD_SIZE - offset word = self.readBytes(address, CPU_WORD_SIZE) if len(bytes) < size: size = len(bytes) word = word[:offset] + bytes[:size] + \ word[offset + size:] # <-- FIXME: Big endian! else: # <-- FIXME: Big endian! word = word[:offset] + bytes[:size] self.writeWord(address, bytes2word(word)) bytes = bytes[size:] address += CPU_WORD_SIZE # Write full words while CPU_WORD_SIZE <= len(bytes): # Read one word word = bytes[:CPU_WORD_SIZE] word = bytes2word(word) self.writeWord(address, word) # Move to next word bytes = bytes[CPU_WORD_SIZE:] address += CPU_WORD_SIZE if not bytes: return # Write partial word (begin) size = len(bytes) word = self.readBytes(address, CPU_WORD_SIZE) # FIXME: Write big endian version of the next line word = bytes + word[size:] self.writeWord(address, bytes2word(word)) def readStruct(self, address, struct): bytes = self.readBytes(address, sizeof(struct)) bytes = c_char_p(bytes) return bytes2type(bytes, struct) def readArray(self, address, basetype, count): bytes = self.readBytes(address, sizeof(basetype) * count) bytes = c_char_p(bytes) return bytes2array(bytes, basetype, count) def readCString(self, address, max_size, chunk_length=256): string = [] size = 0 truncated = False while True: done = False data = self.readBytes(address, chunk_length) pos = data.find(b'\0') if pos != -1: done = True data = data[:pos] if max_size <= size + chunk_length: data = data[:(max_size - size)] string.append(data) truncated = True break string.append(data) if done: break size += chunk_length address += chunk_length return b''.join(string), truncated def dumpStack(self, log=None): if not log: log = error stack = self.findStack() if stack: log("STACK: %s" % stack) self._dumpStack(log) def _dumpStack(self, log): sp = self.getStackPointer() displayed = 0 for index in range(-5, 5 + 1): delta = index * CPU_WORD_SIZE try: value = self.readWord(sp + delta) log("STACK%+ 3i: %s" % (delta, formatWordHex(value))) displayed += 1 except PtraceError: pass if not displayed: log("ERROR: unable to read the stack (SP=%s)" % formatAddress(sp)) def readMappings(self): return readProcessMappings(self) def dumpMaps(self, log=None): if not log: log = error for map in self.readMappings(): log("MAPS: %s" % map) def writeWord(self, address, word): """ Address have to be aligned! """ ptrace_poketext(self.pid, address, word) def dumpRegs(self, log=None): if not log: log = error try: regs = self.getregs() dumpRegs(log, regs) except PtraceError as err: log("Unable to read registers: %s" % err) def cont(self, signum=0): signum = self.filterSignal(signum) ptrace_cont(self.pid, signum) self.is_stopped = False def setoptions(self, options): if not HAS_PTRACE_EVENTS: self.notImplementedError() info("Set %s options to %s" % (self, options)) ptrace_setoptions(self.pid, options) def waitEvent(self): return self.debugger.waitProcessEvent(pid=self.pid) def waitSignals(self, *signals): return self.debugger.waitSignals(*signals, pid=self.pid) def waitSyscall(self): self.debugger.waitSyscall(self) def findBreakpoint(self, address): for bp in self.breakpoints.values(): if bp.address <= address < bp.address + bp.size: return bp return None def createBreakpoint(self, address, size=1): bp = self.findBreakpoint(address) if bp: raise ProcessError(self, "A breakpoint is already set: %s" % bp) bp = Breakpoint(self, address, size) self.breakpoints[address] = bp return bp def getBacktrace(self, max_args=6, max_depth=20): return getBacktrace(self, max_args=max_args, max_depth=max_depth) def removeBreakpoint(self, breakpoint): del self.breakpoints[breakpoint.address] def __del__(self): try: self.detach() except PtraceError: pass def __str__(self): return self.__repr__() def __repr__(self): return "" % self.pid def __hash__(self): return hash(self.pid) def notImplementedError(self): raise NotImplementedError() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/debugger/process_error.py0000664000175000017500000000031700000000000023136 0ustar00vstinnervstinnerfrom ptrace.error import PtraceError class ProcessError(PtraceError): def __init__(self, process, message): PtraceError.__init__(self, message, pid=process.pid) self.process = process ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/debugger/process_event.py0000664000175000017500000000353400000000000023132 0ustar00vstinnervstinnerfrom ptrace.signames import signalName class ProcessEvent(Exception): """ A process event: program exit, program killed by a signal, program received a signal, etc. The attribute "process" contains the related process. """ def __init__(self, process, message): Exception.__init__(self, message) self.process = process class ProcessExit(ProcessEvent): """ Process exit event: - process kill by a signal (if signum attribute is not None) - process exited with a code (if exitcode attribute is not None) - process terminated abnormally (otherwise) """ def __init__(self, process, signum=None, exitcode=None): pid = process.pid if signum: message = "Process %s killed by signal %s" % ( pid, signalName(signum)) elif exitcode is not None: if not exitcode: message = "Process %s exited normally" % pid else: message = "Process %s exited with code %s" % (pid, exitcode) else: message = "Process %s terminated abnormally" % pid ProcessEvent.__init__(self, process, message) self.signum = signum self.exitcode = exitcode class ProcessExecution(ProcessEvent): """ Process execution: event send just after the process calls the exec() syscall if exec() tracing option is enabled. """ def __init__(self, process): ProcessEvent.__init__( self, process, "Process %s execution" % process.pid) class NewProcessEvent(ProcessEvent): """ New process: event send when a process calls the fork() syscall if fork() tracing option is enabled. The attribute process contains the new child process. """ def __init__(self, process): ProcessEvent.__init__(self, process, "New process %s" % process.pid) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/debugger/ptrace_signal.py0000664000175000017500000001644600000000000023074 0ustar00vstinnervstinnerfrom logging import error from ptrace.disasm import HAS_DISASSEMBLER from signal import SIGFPE, SIGSEGV, SIGABRT try: from signal import SIGCHLD except ImportError: SIGCHLD = None try: from signal import SIGBUS except ImportError: SIGBUS = None from ptrace.os_tools import RUNNING_LINUX from ptrace.cpu_info import CPU_64BITS from ptrace.debugger import ProcessEvent from ptrace.error import PtraceError from ptrace import signalName from ptrace.debugger.signal_reason import ( DivisionByZero, Abort, StackOverflow, InvalidMemoryAccess, InvalidRead, InvalidWrite, InstructionError, ChildExit) from ptrace.debugger.parse_expr import parseExpression import re # Match a pointer dereference (e.g. "DWORD [EDX+0x8]") DEREF_REGEX = r'(?P(BYTE|WORD|DWORD|DQWORD) )?\[(?P[^]]+)\]' NAMED_WORD_SIZE = { 'BYTE': 1, 'WORD': 2, 'DWORD': 4, 'DQWORD': 8, } # Match any Intel instruction (e.g. "ADD") INSTR_REGEX = '(?:[A-Z]{3,10})' def findDerefSize(match): name = match.group("deref_size") try: return NAMED_WORD_SIZE[name] except KeyError: return None def evalFaultAddress(process, match): expr = match.group('deref') if not expr: return None try: return parseExpression(process, expr) except ValueError as err: error("err: %s" % err) return None class ProcessSignal(ProcessEvent): def __init__(self, signum, process): # Initialize attributes self.name = signalName(signum) ProcessEvent.__init__(self, process, "Signal %s" % self.name) self.signum = signum self.reason = None def _analyze(self): if self.signum in (SIGSEGV, SIGBUS): self.memoryFault() elif self.signum == SIGFPE: self.mathError() elif self.signum == SIGCHLD: self.childExit() elif self.signum == SIGABRT: self.reason = Abort() return self.reason def getInstruction(self): if not HAS_DISASSEMBLER: return None try: return self.process.disassembleOne() except PtraceError: return None def memoryFaultInstr(self, instr, fault_address): asm = instr.text # Invalid write (e.g. "MOV [...], value") match = re.search(r"^(?:MOV|TEST)[A-Z]* %s," % DEREF_REGEX, asm) if match: if fault_address is None: fault_address = evalFaultAddress(self.process, match) self.reason = InvalidWrite(fault_address, size=findDerefSize(match), instr=instr, process=self.process) return # Invalid read (e.g. "CMP BYTE [EAX+EDX-0x1], 0x0") match = re.search(r"^%s %s," % (INSTR_REGEX, DEREF_REGEX), asm) if match: if fault_address is None: fault_address = evalFaultAddress(self.process, match) self.reason = InvalidRead(fault_address, size=findDerefSize(match), instr=instr, process=self.process) return # Invalid read (e.g. "MOV reg, [...]") match = re.match(r"%s [^,]+, %s" % (INSTR_REGEX, DEREF_REGEX), asm) if match: if fault_address is None: fault_address = evalFaultAddress(self.process, match) self.reason = InvalidRead(fault_address, size=findDerefSize(match), instr=instr, process=self.process) return # MOVS* and SCAS* instructions (e.g. "MOVSB" or "REP SCASD") match = re.search( r"^(?:REP(?:NZ)? )?(?PMOVS|SCAS)(?P[BWD])?", asm) if match: self.reason = self.movsInstr(fault_address, instr, match) return def movsInstr(self, fault_address, instr, match): operator = match.group("operator") suffix = match.group("suffix") size = {'B': 1, 'W': 2, 'D': 4}.get(suffix) error_cls = InvalidMemoryAccess try: process = self.process if CPU_64BITS: source_reg = 'rsi' dest_reg = 'rdi' else: source_reg = 'esi' dest_reg = 'edi' source_addr = process.getreg(source_reg) registers = {source_reg: source_addr} write = (operator == 'MOVS') if write: dest_addr = process.getreg(dest_reg) registers[dest_reg] = dest_addr if fault_address is not None: if fault_address == source_addr: error_cls = InvalidRead if write and fault_address == dest_addr: error_cls = InvalidWrite else: if write: fault_address = (source_addr, dest_addr) else: fault_address = (source_addr,) except PtraceError: registers = {} return error_cls(fault_address, size=size, instr=instr, registers=registers, process=self.process) def getSignalInfo(self): if RUNNING_LINUX: return self.process.getsiginfo() else: return None def memoryFault(self): # Get fault siginfo = self.getSignalInfo() if siginfo: fault_address = siginfo._sigfault._addr if not fault_address: fault_address = 0 else: fault_address = None # Get current instruction instr = self.getInstruction() # Call to invalid address? if fault_address is not None: try: ip = self.process.getInstrPointer() if ip == fault_address: self.reason = InstructionError(ip, process=self.process) return except PtraceError: pass # Stack overflow? stack = self.process.findStack() if stack: sp = self.process.getStackPointer() if not (stack.start <= sp <= stack.end): self.reason = StackOverflow( sp, stack, instr=instr, process=self.process) return # Guess error type using the assembler instruction if instr: self.memoryFaultInstr(instr, fault_address) if self.reason: return # Last chance: use generic invalid memory access error self.reason = InvalidMemoryAccess( fault_address, instr=instr, process=self.process) def mathError(self): instr = self.getInstruction() if not instr: return match = re.match(r"I?DIV (.*)", instr.text) if not match: return self.reason = DivisionByZero(instr=instr, process=self.process) def childExit(self): siginfo = self.getSignalInfo() if siginfo: child = siginfo._sigchld self.reason = ChildExit(child.pid, child.status, child.uid) else: self.reason = ChildExit() def display(self, log=None): self._analyze() if not log: log = error log("-" * 60) log("PID: %s" % self.process.pid) log("Signal: %s" % self.name) if self.reason: self.reason.display(log) log("-" * 60) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/debugger/signal_reason.py0000664000175000017500000001350600000000000023077 0ustar00vstinnervstinnerfrom ptrace.ctypes_tools import formatAddress, formatWordHex from ptrace.error import PtraceError from ptrace.cpu_info import CPU_I386, CPU_X86_64 from ptrace.process_tools import formatProcessStatus import re # Find all Intel registers (in upper case) if CPU_I386: regex = 'E[A-Z]{2}|[CDEFGS]S|[ABCD]L' elif CPU_X86_64: regex = '[ER][A-Z]{2}|[CDEFGS]S|[ABCD]L' else: regex = None if regex: REGISTER_REGEX = re.compile(r'\b(?:%s)\b' % regex) else: REGISTER_REGEX = None def extractRegisters(process, instr): registers = {} if not process or not instr or not REGISTER_REGEX: return registers asm = instr.text asm = asm.upper() # Skip the operator ("MOV CL, [EAX]" => "CL, [EAX]") asm = asm.split(" ", 1)[1] for match in REGISTER_REGEX.finditer(asm): name = match.group(0) name = name.lower() try: value = process.getreg(name) registers[name] = value except PtraceError: pass return registers def findMappings(addresses, process, size): mappings = [] if addresses is None or not process: return mappings if not isinstance(addresses, (list, tuple)): addresses = (addresses,) if not size: size = 0 process_mappings = process.readMappings() if not process_mappings: return mappings for address in addresses: address_str = formatAddress(address) if 1 < size: address_str += "..%s" % formatAddress(address + size - 1) found = False for map in process_mappings: if (map.start <= address < map.end) \ or (map.start <= (address + size - 1) < map.end): found = True mappings.append("%s is part of %s" % (address_str, map)) if not found: mappings.append("%s is not mapped in memory" % address_str) return mappings class SignalInfo(Exception): def __init__(self, name, text, address=None, size=None, instr=None, process=None, registers=None): Exception.__init__(self, text) self.name = name self.text = text self.instr = instr self.registers = extractRegisters(process, instr) if registers: self.registers.update(registers) self.mappings = findMappings(address, process, size) def display(self, log): log(self.text) self.displayExtra(log) if self.instr: log("- instruction: %s" % self.instr) for mapping in self.mappings: log("- mapping: %s" % mapping) for name, value in self.registers.items(): log("- register %s=%s" % (name, formatWordHex(value))) def displayExtra(self, log): pass class DivisionByZero(SignalInfo): def __init__(self, instr=None, process=None): SignalInfo.__init__(self, "div_by_zero", "Division by zero", instr=instr, process=process) class Abort(SignalInfo): def __init__(self): SignalInfo.__init__(self, "abort", "Program received signal SIGABRT, Aborted.") class StackOverflow(SignalInfo): def __init__(self, stack_ptr, stack_map, instr=None, process=None): text = "STACK OVERFLOW! Stack pointer is in %s" % stack_map SignalInfo.__init__(self, "stack_overflow", text, address=stack_ptr, registers={ '': stack_ptr}, instr=instr, process=process) self.stack_ptr = stack_ptr self.stack_map = stack_map class InvalidMemoryAccess(SignalInfo): NAME = "invalid_mem_access" PREFIX = "Invalid memory access" PREFIX_ADDR = "Invalid memory access to %s" def __init__(self, address=None, size=None, instr=None, registers=None, process=None): """ address is an integer or a list of integer """ if address is not None: if isinstance(address, (list, tuple)): arguments = " or ".join(formatAddress(addr) for addr in address) else: arguments = formatAddress(address) message = self.PREFIX_ADDR % arguments else: message = self.PREFIX if size: message += " (size=%s bytes)" % size name = self.NAME if address is not None: name += "-" + formatAddress(address).lower() SignalInfo.__init__(self, name, message, address=address, size=size, instr=instr, process=process, registers=registers) class InvalidRead(InvalidMemoryAccess): NAME = "invalid_read" PREFIX = "Invalid read" PREFIX_ADDR = "Invalid read from %s" class InvalidWrite(InvalidMemoryAccess): NAME = "invalid_write" PREFIX = "Invalid write" PREFIX_ADDR = "Invalid write to %s" class InstructionError(SignalInfo): def __init__(self, address, process=None): SignalInfo.__init__(self, "instr_error", "UNABLE TO EXECUTE CODE AT %s (SEGMENTATION FAULT)" % formatAddress( address), address=address, process=process, registers={'': address}) class ChildExit(SignalInfo): def __init__(self, pid=None, status=None, uid=None): if pid is not None and status is not None: message = formatProcessStatus(status, "Child process %s" % pid) else: message = "Child process exited" SignalInfo.__init__(self, "child_exit", message) self.pid = pid self.status = status self.uid = uid def displayExtra(self, log): if self.uid is not None: log("Signal sent by user %s" % self.uid) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1616012250.0 python-ptrace-0.9.8/ptrace/debugger/syscall_state.py0000664000175000017500000000257700000000000023133 0ustar00vstinnervstinnerfrom ptrace.syscall import PtraceSyscall from signal import SIGTRAP class SyscallState(object): def __init__(self, process): self.process = process self.ignore_exec_trap = True self.ignore_callback = None self.clear() def event(self, options): if self.next_event == "exit": return self.exit() else: return self.enter(options) def enter(self, options): # syscall enter regs = self.process.getregs() self.syscall = PtraceSyscall(self.process, options, regs) self.name = self.syscall.name if (not self.ignore_callback) \ or (not self.ignore_callback(self.syscall)): self.syscall.enter(regs) else: self.syscall = None self.next_event = "exit" return self.syscall def exit(self): if self.syscall: self.syscall.exit() if self.ignore_exec_trap \ and self.name == "execve" \ and not self.process.debugger.trace_exec: # Ignore the SIGTRAP after exec() syscall exit self.process.syscall() self.process.waitSignals(SIGTRAP, SIGTRAP | 0x80) syscall = self.syscall self.clear() return syscall def clear(self): self.syscall = None self.name = None self.next_event = "enter" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/disasm.py0000664000175000017500000000474000000000000017747 0ustar00vstinnervstinner""" Disassembler: only enabled if HAS_DISASSEMBLER is True. """ try: from ptrace.cpu_info import CPU_I386, CPU_X86_64 try: from distorm3 import Decode if CPU_X86_64: from distorm3 import Decode64Bits as DecodeBits MAX_INSTR_SIZE = 11 elif CPU_I386: from distorm3 import Decode32Bits as DecodeBits MAX_INSTR_SIZE = 8 else: raise ImportError("CPU not supported") DISTORM3 = True except ImportError: DISTORM3 = False from ptrace.pydistorm import Decode if CPU_X86_64: from ptrace.pydistorm import Decode64Bits as DecodeBits MAX_INSTR_SIZE = 11 elif CPU_I386: from ptrace.pydistorm import Decode32Bits as DecodeBits MAX_INSTR_SIZE = 8 else: raise ImportError("CPU not supported") from ptrace import PtraceError class Instruction(object): """ A CPU instruction. Attributes: - address (int): address of the instruction - size (int): size of the instruction in bytes - mnemonic (str): name of the instruction - operands (str): string describing the operands - hexa (str): bytes of the instruction as an hexadecimal string - text (str): string representing the whole instruction """ def __init__(self, instr): if DISTORM3: self.address, self.size, self.text, self.hexa = instr else: self.address = instr.offset self.size = instr.size self.hexa = str(instr.instructionHex) self.text = "%s %s" % (instr.mnemonic, instr.operands) def __str__(self): return self.text def disassemble(code, address=0x100): """ Disassemble the specified byte string, where address is the address of the first instruction. """ for instr in Decode(address, code, DecodeBits): yield Instruction(instr) def disassembleOne(code, address=0x100): """ Disassemble the first instruction of the byte string, where address is the address of the instruction. """ for instr in disassemble(code, address): return instr raise PtraceError("Unable to disassemble %r" % code) HAS_DISASSEMBLER = True except (ImportError, OSError): # OSError if libdistorm64.so doesn't exist HAS_DISASSEMBLER = False ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/error.py0000664000175000017500000000352700000000000017622 0ustar00vstinnervstinnerfrom sys import exc_info from traceback import format_exception from logging import ERROR, getLogger from ptrace.logging_tools import getLogFunc, changeLogLevel PTRACE_ERRORS = Exception def writeBacktrace(logger, log_level=ERROR): """ Write a backtrace into the logger with the specified log level. """ log_func = getLogFunc(logger, log_level) try: info = exc_info() trace = format_exception(*info) if trace[0] != "None\n": trace = ''.join(trace).rstrip() for line in trace.split("\n"): log_func(line.rstrip()) return except Exception: pass log_func("Unable to get backtrace") def formatError(error): """ Format an error as a string. Write the error type as prefix. Eg. "[ValueError] invalid value". """ return "[%s] %s" % (error.__class__.__name__, error) def writeError(logger, error, title="ERROR", log_level=ERROR): """ Write an error into the logger: - logger: the logger (if None, use getLogger()) - error: the exception object - title: error message prefix (e.g. title="Initialization error") - log_level: log level of the error If the exception is a SystemExit or a KeyboardInterrupt, re-emit (raise) the exception and don't write it. """ if not logger: logger = getLogger() if error.__class__ in (SystemExit, KeyboardInterrupt): raise error log_func = getLogFunc(logger, log_level) log_func("%s: %s" % (title, formatError(error))) writeBacktrace(logger, log_level=changeLogLevel(log_level, -1)) class PtraceError(Exception): """ Ptrace error: have the optional attributes errno and pid. """ def __init__(self, message, errno=None, pid=None): Exception.__init__(self, message) self.errno = errno self.pid = pid ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/func_arg.py0000664000175000017500000000702700000000000020254 0ustar00vstinnervstinnerfrom ptrace.error import PTRACE_ERRORS, writeError from logging import getLogger from ptrace.ctypes_tools import formatAddress class FunctionArgument(object): """ Description of a function argument. Attributes: - function: a Function object - index (int): index of the argument (starting at zero) - options: a FunctionCallOptions object - value (int) - type (str, optional) - text (str): string describing the argument Don't use text attribute directly, use getText() to format the argument instead. """ def __init__(self, function, index, options, value=None, type=None, name=None): self.function = function self.index = index self.options = options self.value = value self.type = type self.name = name self.text = None def getText(self): if not self.text: try: text = self.createText() if text is not None: self.text = str(text) elif self.type and self.type.endswith("*"): self.text = formatAddress(self.value) else: self.text = repr(self.value) except PTRACE_ERRORS as err: writeError(getLogger(), err, "Format argument %s of function %s() value error" % (self.name, self.function.name)) self.text = repr(self.value) return self.text def format(self): text = self.getText() options = self.options if options.write_argname and self.name: if options.write_types and self.type: return "%s %s=%s" % (self.type, self.name, text) else: return "%s=%s" % (self.name, text) elif options.write_types and self.type: return "(%s)%s" % (self.type, text) else: return text def createText(self): return repr(self.value) def formatPointer(self, value, address): if self.options.write_address: return "%s at %s" % (value, formatAddress(address)) else: return value def readStruct(self, address, struct): address = self.value struct_name = struct.__name__ data = self.function.process.readStruct(address, struct) arguments = [] for name, argtype in struct._fields_: value = getattr(data, name) try: text = self.formatStructValue(struct_name, name, value) if text is not None: text = str(text) else: text = repr(value) except PTRACE_ERRORS as err: writeError(getLogger(), err, "Format struct value error") text = repr(value) arguments.append("%s=%s" % (name, text)) data = "<%s %s>" % (struct_name, ", ".join(arguments)) return self.formatPointer(data, address) def formatStructValue(self, struct, name, value): return None def readArray(self, address, basetype, count): array = self.function.process.readArray(address, basetype, count) arguments = [] for index in range(count): value = array[index] value = str(value) arguments.append(value) arguments = ", ".join(arguments) return self.formatPointer("<(%s)>" % arguments, address) def __repr__(self): return "argument %s of %s()" % (self.name, self.function.name) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065641.0 python-ptrace-0.9.8/ptrace/func_call.py0000664000175000017500000000470600000000000020417 0ustar00vstinnervstinnerfrom ptrace.func_arg import FunctionArgument class FunctionCallOptions(object): """ Options to format a function call and its arguments. """ def __init__(self, write_types=False, write_argname=False, replace_socketcall=True, string_max_length=300, write_address=False, max_array_count=20): self.write_address = write_address self.write_types = write_types self.write_argname = write_argname self.replace_socketcall = replace_socketcall self.string_max_length = string_max_length self.max_array_count = max_array_count self.instr_pointer = False class FunctionCall(object): """ A function call. Attributes: - name (str): function name - arguments: list of FunctionArgument objects - restype (str, optional): result type - resvalue (optional): result value - argument_class: class used to build the new arguments Methods: - format(): create a string representation of the call - addArgument(): add a new argument - clearArguments(): remove all arguments """ def __init__(self, name, options, argument_class=FunctionArgument): self.name = name self.options = options self.arguments = [] self.restype = None self.resvalue = None self.argument_class = argument_class def addArgument(self, value=None, name=None, type=None): arg = self.argument_class( self, len(self.arguments), self.options, value, type, name) self.arguments.append(arg) def clearArguments(self): self.arguments = [] def __getitem__(self, key): if isinstance(key, str): for arg in self.arguments: if arg.name == key: return arg raise KeyError("%r has no argument called %r" % (self, key)) else: # Integer key return self.arguments[key] def format(self): arguments = [arg.format() for arg in self.arguments] # Remove empty optionnal arguments while arguments and not arguments[-1]: arguments.pop(-1) arguments = ", ".join(arguments) if self.restype and self.options.write_types: return "%s %s(%s)" % (self.restype, self.name, arguments) else: return "%s(%s)" % (self.name, arguments) def __repr__(self): return "" % self.name ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065898.0 python-ptrace-0.9.8/ptrace/linux_proc.py0000664000175000017500000001417100000000000020650 0ustar00vstinnervstinner""" Functions and variables to access to Linux proc directory. Constant: - PAGE_SIZE: size of a memory page """ from os import readlink, listdir from resource import getpagesize from ptrace.tools import timestampUNIX from datetime import timedelta PAGE_SIZE = getpagesize() class ProcError(Exception): """ Linux proc directory error. """ pass def openProc(path): """ Open a proc entry in read only mode. """ filename = "/proc/%s" % path try: return open(filename) except IOError as err: raise ProcError("Unable to open %r: %s" % (filename, err)) def readProc(path): """ Read the content of a proc entry. Eg. readProc("stat") to read /proc/stat. """ with openProc(path) as procfile: return procfile.read() def readProcessProc(pid, key): """ Read the content of a process entry in the proc directory. Eg. readProcessProc(pid, "status") to read /proc/pid/status. """ try: filename = "/proc/%s/%s" % (pid, key) with open(filename) as proc: return proc.read() except IOError as err: raise ProcError("Process %s doesn't exist: %s" % (pid, err)) class ProcessState(object): """ Processus state. Attributes: - state (str): process status ('R', 'S', 'T', ...) - program (str): program name - pid (int): process identifier - ppid (int): parent process identifier - pgrp (int): process group - session (int): session identifier - tty_nr (int): tty number - tpgid (int) - utime (int): user space time (jiffies) - stime (int): kernel space time (jiffies) - starttime (int): start time """ STATE_NAMES = { "R": "running", "S": "sleeping", "D": "disk", "Z": "zombie", "T": "traced", "W": "paging", } def __init__(self, stat): # pid (program) ... => "pid (program", "..." part, stat = stat.rsplit(')', 1) self.pid, self.program = part.split('(', 1) self.pid = int(self.pid) # "state ..." => state, "..." stat = stat.split() self.state = stat[0] stat = [int(item) for item in stat[1:]] # Read next numbers self.ppid = stat[0] self.pgrp = stat[1] self.session = stat[2] self.tty_nr = stat[3] self.tpgid = stat[4] self.utime = stat[10] self.stime = stat[11] self.starttime = stat[18] def readProcessStat(pid): """ Read the process state ('stat') as a ProcessState object. """ stat = readProcessProc(pid, 'stat') return ProcessState(stat) def readProcessStatm(pid): """ Read the process memory status ('statm') as a list of integers. Values are in bytes (and not in pages). """ statm = readProcessProc(pid, 'statm') statm = [int(item) * PAGE_SIZE for item in statm.split()] return statm def readProcessProcList(pid, key): """ Read a process entry as a list of strings. """ data = readProcessProc(pid, key) if not data: # Empty file: empty list return [] data = data.split("\0") if not data[-1]: del data[-1] return data def readProcessLink(pid, key): """ Read a process link. """ try: filename = "/proc/%s/%s" % (pid, key) return readlink(filename) except OSError as err: raise ProcError("Unable to read proc link %r: %s" % (filename, err)) def readProcesses(): """ Read all processes identifiers. The function is a generator, use it with: :: for pid in readProcesses(): ... """ for filename in listdir('/proc'): try: yield int(filename) except ValueError: # Filename is not an integer (e.g. "stat" from /proc/stat) continue def readProcessCmdline(pid, escape_stat=True): """ Read the process command line. If escape_stat is True, format program name with "[%s]" if the process has no command line, e.g. "[khelper]". """ # Try /proc/42/cmdline try: cmdline = readProcessProcList(pid, 'cmdline') if cmdline: return cmdline except ProcError: pass # Try /proc/42/stat try: stat = readProcessStat(pid) program = stat.program if escape_stat: program = "[%s]" % program return [program] except ProcError: return None def searchProcessesByName(process_name): """ Find all processes matching the program name pattern. Eg. pattern "ssh" will find the program "/usr/bin/ssh". This function is a generator yielding the process identifier, use it with: :: for pid in searchProcessByName(pattern): ... """ suffix = '/' + process_name for pid in readProcesses(): cmdline = readProcessCmdline(pid) if not cmdline: continue program = cmdline[0] if program == process_name or program.endswith(suffix): yield pid def searchProcessByName(process_name): """ Function similar to searchProcessesByName() but only return the identifier of the first matching process. Raise a ProcError if there is no matching process. """ for pid in searchProcessesByName(process_name): return pid raise ProcError("Unable to find process: %r" % process_name) def getUptime(): """ Get the system uptime as a datetime.timedelta object. """ uptime = readProc('uptime') uptime = uptime.strip().split() uptime = float(uptime[0]) return timedelta(seconds=uptime) def getSystemBoot(): """ Get the system boot date as a datetime.datetime object. """ if getSystemBoot.value is None: stat_file = openProc('stat') for line in stat_file: if not line.startswith("btime "): continue seconds = int(line[6:]) btime = timestampUNIX(seconds, True) getSystemBoot.value = btime break stat_file.close() if getSystemBoot.value is None: raise ProcError("Unable to read system boot time!") return getSystemBoot.value getSystemBoot.value = None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/logging_tools.py0000664000175000017500000000132100000000000021325 0ustar00vstinnervstinnerfrom ptrace.tools import minmax from logging import ERROR, WARNING, INFO, DEBUG def getLogFunc(logger, level): """ Get the logger function for the specified logging level. """ if level == ERROR: return logger.error elif level == WARNING: return logger.warning elif level == INFO: return logger.info elif level == DEBUG: return logger.debug else: return logger.error def changeLogLevel(level, delta): """ Compute log level and make sure that the result is in DEBUG..ERROR. >>> changeLogLevel(ERROR, -1) == WARNING True >>> changeLogLevel(DEBUG, 1) == INFO True """ return minmax(DEBUG, level + delta * 10, ERROR) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/mockup.py0000664000175000017500000000037000000000000017760 0ustar00vstinnervstinner""" Mockup classes used in unit tests. """ class FakeProcess(object): def __init__(self): self.regs = {} def setreg(self, name, value): self.regs[name] = value def getreg(self, name): return self.regs[name] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065641.0 python-ptrace-0.9.8/ptrace/os_tools.py0000664000175000017500000000135000000000000020322 0ustar00vstinnervstinner""" Constants about the operating system: - RUNNING_PYPY (bool) - RUNNING_LINUX (bool) - RUNNING_FREEBSD (bool) - RUNNING_OPENBSD (bool) - RUNNING_MACOSX (bool) - RUNNING_BSD (bool) - HAS_PROC (bool) - HAS_PTRACE (bool) """ from sys import platform, version, version_info RUNNING_PYTHON3 = version_info[0] == 3 RUNNING_PYPY = ("pypy" in version.lower()) RUNNING_LINUX = platform.startswith('linux') RUNNING_FREEBSD = (platform.startswith('freebsd') or platform.startswith('gnukfreebsd')) RUNNING_OPENBSD = platform.startswith('openbsd') RUNNING_MACOSX = (platform == 'darwin') RUNNING_BSD = RUNNING_FREEBSD or RUNNING_MACOSX or RUNNING_OPENBSD HAS_PROC = RUNNING_LINUX HAS_PTRACE = (RUNNING_BSD or RUNNING_LINUX) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065641.0 python-ptrace-0.9.8/ptrace/process_tools.py0000664000175000017500000000724600000000000021371 0ustar00vstinnervstinnerfrom ptrace.os_tools import RUNNING_LINUX if RUNNING_LINUX: from ptrace.linux_proc import (ProcError, openProc, readProcessProcList, readProcessLink, readProcessStat) from ptrace.signames import signalName # noqa from os import ( WIFSTOPPED, WSTOPSIG, WIFSIGNALED, WTERMSIG, WIFEXITED, WEXITSTATUS, WCOREDUMP) def dumpProcessInfo(log, pid, max_length=None): """ Dump all information about a process: - log: callback to write display one line - pid: process identifier - max_length (default: None): maximum number of environment variables """ if not RUNNING_LINUX: log("Process ID: %s" % pid) return try: stat = readProcessStat(pid) except ProcError: # Permission denied stat = None text = "Process ID: %s" % pid if stat: text += " (parent: %s)" % stat.ppid log(text) if stat: state = stat.state try: state = "%s (%s)" % (state, stat.STATE_NAMES[state]) except KeyError: pass log("Process state: %s" % state) try: log("Process command line: %r" % readProcessProcList(pid, 'cmdline')) except ProcError: # Permission denied pass try: env = readProcessProcList(pid, 'environ') if max_length: # Truncate environment if it's too long length = 0 removed = 0 index = 0 while index < len(env): var = env[index] if max_length < length + len(var): del env[index] removed += 1 else: length += len(var) index += 1 env = ', '.join("%s=%r" % tuple(item.split("=", 1)) for item in env) if removed: env += ', ... (skip %s vars)' % removed log("Process environment: %s" % env) except ProcError: # Permission denied pass try: log("Process working directory: %s" % readProcessLink(pid, 'cwd')) except ProcError: # Permission denied pass try: user = None group = None status_file = openProc("%s/status" % pid) for line in status_file: if line.startswith("Uid:"): user = [int(id) for id in line[5:].split("\t")] if line.startswith("Gid:"): group = [int(id) for id in line[5:].split("\t")] status_file.close() if user: text = "User identifier: %s" % user[0] if user[0] != user[1]: text += " (effective: %s)" % user[1] log(text) if group: text = "Group identifier: %s" % group[0] if group[0] != group[1]: text += " (effective: %s)" % group[1] log(text) except ProcError: # Permission denied pass def formatProcessStatus(status, title="Process"): """ Format a process status (integer) as a string. """ if WIFSTOPPED(status): signum = WSTOPSIG(status) text = "%s stopped by signal %s" % (title, signalName(signum)) elif WIFSIGNALED(status): signum = WTERMSIG(status) text = "%s killed by signal %s" % (title, signalName(signum)) else: if not WIFEXITED(status): raise ValueError("Invalid status: %r" % status) exitcode = WEXITSTATUS(status) if exitcode: text = "%s exited with code %s" % (title, exitcode) else: text = "%s exited normally" % title if WCOREDUMP(status): text += " (core dumped)" return text ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/profiler.py0000664000175000017500000000232000000000000020301 0ustar00vstinnervstinnerfrom profile import Profile from os import unlink from io import StringIO import pstats def calibrate(n): """ https://docs.python.org/3/library/profile.html#calibration """ if n > 0: pr = Profile() magics = [] for i in range(n): magics.append(pr.calibrate(10000)) return sum(magics) / n def runProfiler(logger, func, args=tuple(), kw={}, verbose=True, nb_func=25, sort_by=('time',), nb_cal=0): """ Run a function in a profiler and then display the functions sorted by time. """ profile_filename = "/tmp/profiler" prof = Profile(bias=calibrate(nb_cal)) try: logger.warning("Run profiler") result = prof.runcall(func, *args, **kw) logger.error("Profiler: Process data...") prof.dump_stats(profile_filename) stat = pstats.Stats(prof) stat.strip_dirs() stat.sort_stats(*sort_by) logger.error("Profiler: Result:") log = StringIO() stat.stream = log stat.print_stats(nb_func) log.seek(0) for line in log: logger.error(line.rstrip()) return result finally: unlink(profile_filename) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065740.0 python-ptrace-0.9.8/ptrace/pydistorm.py0000664000175000017500000000660500000000000020523 0ustar00vstinnervstinner""" :[diStorm64 1.7.27}: Copyright RageStorm (C) 2007, Gil Dabah diStorm is licensed under the BSD license. http://ragestorm.net/distorm/ --- Python binding of diStorm64 library written by Victor Stinner """ from ctypes import cdll, c_long, c_ulong, c_int, c_uint, c_char, POINTER, Structure, addressof, byref, c_void_p, create_string_buffer, sizeof, cast # Define (u)int32_t and (u)int64_t types int32_t = c_int uint32_t = c_uint if sizeof(c_ulong) == 8: int64_t = c_long uint64_t = c_ulong else: from ctypes import c_longlong, c_ulonglong assert sizeof(c_longlong) == 8 assert sizeof(c_ulonglong) == 8 int64_t = c_longlong uint64_t = c_ulonglong SUPPORT_64BIT_OFFSET = True if SUPPORT_64BIT_OFFSET: _OffsetType = uint64_t else: _OffsetType = uint32_t LIB_FILENAME = 'libdistorm64.so' distorm = cdll.LoadLibrary(LIB_FILENAME) Decode16Bits = 0 Decode32Bits = 1 Decode64Bits = 2 DECODERS = (Decode16Bits, Decode32Bits, Decode64Bits) internal_decode = distorm.internal_decode DECRES_NONE = 0 DECRES_SUCCESS = 1 DECRES_MEMORYERR = 2 DECRES_INPUTERR = 3 MAX_INSTRUCTIONS = 100 MAX_TEXT_SIZE = 60 class _WString(Structure): _fields_ = ( ("pos", c_uint), ("p", c_char * MAX_TEXT_SIZE), ) def __str__(self): # FIXME: Use pos? return self.p class _DecodedInst(Structure): _fields_ = ( ("mnemonic", _WString), ("operands", _WString), ("instructionHex", _WString), ("size", c_uint), ("offset", _OffsetType), ) def __str__(self): return "%s %s" % (self.mnemonic, self.operands) internal_decode.argtypes = (_OffsetType, c_void_p, c_int, c_int, c_void_p, c_uint, POINTER(c_uint)) def Decode(codeOffset, code, dt=Decode32Bits): """ Errors: TypeError, IndexError, MemoryError, ValueError """ # Check arguments if not isinstance(codeOffset, int): raise TypeError("codeOffset have to be an integer") if not isinstance(code, bytes): raise TypeError("code have to be a bytes, not %s" % (type(code).__name__,)) if dt not in DECODERS: raise IndexError( "Decoding-type must be either Decode16Bits, Decode32Bits or Decode64Bits.") # Allocate memory for decoder code_buffer = create_string_buffer(code) decodedInstructionsCount = c_uint() result = create_string_buffer(sizeof(_DecodedInst) * MAX_INSTRUCTIONS) # Prepare arguments codeLen = len(code) code = addressof(code_buffer) while codeLen: # Call internal decoder res = internal_decode(codeOffset, code, codeLen, dt, result, MAX_INSTRUCTIONS, byref(decodedInstructionsCount)) # Check for errors if res == DECRES_INPUTERR: raise ValueError("Invalid argument") count = decodedInstructionsCount.value if res == DECRES_MEMORYERR and not count: raise MemoryError() # No more instruction if not count: break # Yield instruction and compute decoded size size = 0 instr_array = cast(result, POINTER(_DecodedInst)) for index in range(count): instr = instr_array[index] size += instr.size yield instr # Update parameters to move to next instructions code += size codeOffset += size codeLen -= size ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/signames.py0000664000175000017500000000277700000000000020305 0ustar00vstinnervstinner""" Name of process signals. SIGNAMES contains a dictionary mapping a signal number to it's name. But you should better use signalName() instead of SIGNAMES since it returns a string even if the signal is unknown. """ PREFERRED_NAMES = ("SIGABRT", "SIGHUP", "SIGCHLD", "SIGPOLL") def getSignalNames(): """ Create signal names dictionary (e.g. 9 => 'SIGKILL') using dir(signal). If multiple signal names have the same number, use the first matching name in PREFERRED_NAME to select preferred name (e.g. SIGIOT=SIGABRT=17). """ import signal allnames = {} for name in dir(signal): if not name.startswith("SIG"): continue signum = getattr(signal, name) try: allnames[signum].append(name) except KeyError: allnames[signum] = [name] signames = {} for signum, names in allnames.items(): if not signum: # Skip signal 0 continue name = None for preferred in PREFERRED_NAMES: if preferred in names: name = preferred break if not name: name = names[0] signames[signum] = name return signames SIGNAMES = getSignalNames() def signalName(signum): """ Get the name of a signal >>> from signal import SIGINT >>> signalName(SIGINT) 'SIGINT' >>> signalName(404) 'signal<404>' """ try: return SIGNAMES[signum] except KeyError: return "signal<%s>" % signum ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9395316 python-ptrace-0.9.8/ptrace/syscall/0000775000175000017500000000000000000000000017562 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065641.0 python-ptrace-0.9.8/ptrace/syscall/__init__.py0000664000175000017500000000052300000000000021673 0ustar00vstinnervstinnerfrom ptrace.syscall.names import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES # noqa from ptrace.syscall.prototypes import SYSCALL_PROTOTYPES, FILENAME_ARGUMENTS # noqa from ptrace.syscall.syscall_argument import SyscallArgument # noqa from ptrace.syscall.ptrace_syscall import PtraceSyscall, SYSCALL_REGISTER, RETURN_VALUE_REGISTER # noqa ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/syscall/freebsd_constants.py0000664000175000017500000000116200000000000023642 0ustar00vstinnervstinnerfrom ptrace.syscall.posix_constants import SYSCALL_ARG_DICT RLIMIT_RESOURCE = { 0: "RLIMIT_CPU", 1: "RLIMIT_FSIZE", 2: "RLIMIT_DATA", 3: "RLIMIT_STACK", 4: "RLIMIT_CORE", 5: "RLIMIT_RSS", 6: "RLIMIT_MEMLOCK", 7: "RLIMIT_NPROC", 8: "RLIMIT_NOFILE", 9: "RLIMIT_SBSIZE", 10: "RLIMIT_VMEM", } SIGPROCMASK_HOW = {1: " SIG_BLOCK", 2: "SIG_UNBLOCK", 3: "SIG_SETMASK"} SYSCALL_ARG_DICT.update({ "getrlimit": {"resource": RLIMIT_RESOURCE}, "setrlimit": {"resource": RLIMIT_RESOURCE}, "sigprocmask": {"how": SIGPROCMASK_HOW}, "rt_sigprocmask": {"how": SIGPROCMASK_HOW}, }) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/syscall/freebsd_syscall.py0000664000175000017500000002206600000000000023306 0ustar00vstinnervstinner# FreeBSD kernel syscall list from FreeBSD 7.0RC1 for i386 # # List extracted from: # /usr/include/sys/syscall.h SYSCALL_NAMES = { 0: "syscall", 1: "exit", 2: "fork", 3: "read", 4: "write", 5: "open", 6: "close", 7: "wait4", # 8: old creat 9: "link", 10: "unlink", # 11: obsolete execv 12: "chdir", 13: "fchdir", 14: "mknod", 15: "chmod", 16: "chown", 17: "break", 18: "freebsd4_getfsstat", # 19: old lseek 20: "getpid", 21: "mount", 22: "unmount", 23: "setuid", 24: "getuid", 25: "geteuid", 26: "ptrace", 27: "recvmsg", 28: "sendmsg", 29: "recvfrom", 30: "accept", 31: "getpeername", 32: "getsockname", 33: "access", 34: "chflags", 35: "fchflags", 36: "sync", 37: "kill", # 38: old stat 39: "getppid", # 40: old lstat 41: "dup", 42: "pipe", 43: "getegid", 44: "profil", 45: "ktrace", # 46: old sigaction 47: "getgid", # 48: old sigprocmask 49: "getlogin", 50: "setlogin", 51: "acct", # 52: old sigpending 53: "sigaltstack", 54: "ioctl", 55: "reboot", 56: "revoke", 57: "symlink", 58: "readlink", 59: "execve", 60: "umask", 61: "chroot", # 62: old fstat # 63: old getkerninfo # 64: old getpagesize 65: "msync", 66: "vfork", # 67: obsolete vread # 68: obsolete vwrite 69: "sbrk", 70: "sstk", # 71: old mmap 72: "vadvise", 73: "munmap", 74: "mprotect", 75: "madvise", # 76: obsolete vhangup # 77: obsolete vlimit 78: "mincore", 79: "getgroups", 80: "setgroups", 81: "getpgrp", 82: "setpgid", 83: "setitimer", # 84: old wait 85: "swapon", 86: "getitimer", # 87: old gethostname # 88: old sethostname 89: "getdtablesize", 90: "dup2", 92: "fcntl", 93: "select", 95: "fsync", 96: "setpriority", 97: "socket", 98: "connect", # 99: old accept 100: "getpriority", # 101: old send # 102: old recv # 103: old sigreturn 104: "bind", 105: "setsockopt", 106: "listen", # 107: obsolete vtimes # 108: old sigvec # 109: old sigblock # 110: old sigsetmask # 111: old sigsuspend # 112: old sigstack # 113: old recvmsg # 114: old sendmsg # 115: obsolete vtrace 116: "gettimeofday", 117: "getrusage", 118: "getsockopt", 120: "readv", 121: "writev", 122: "settimeofday", 123: "fchown", 124: "fchmod", # 125: old recvfrom 126: "setreuid", 127: "setregid", 128: "rename", # 129: old truncate # 130: old ftruncate 131: "flock", 132: "mkfifo", 133: "sendto", 134: "shutdown", 135: "socketpair", 136: "mkdir", 137: "rmdir", 138: "utimes", # 139: obsolete 4.2 sigreturn 140: "adjtime", # 141: old getpeername # 142: old gethostid # 143: old sethostid # 144: old getrlimit # 145: old setrlimit # 146: old killpg 147: "setsid", 148: "quotactl", # 149: old quota # 150: old getsockname 155: "nfssvc", # 156: old getdirentries 157: "freebsd4_statfs", 158: "freebsd4_fstatfs", 160: "lgetfh", 161: "getfh", 162: "getdomainname", 163: "setdomainname", 164: "uname", 165: "sysarch", 166: "rtprio", 169: "semsys", 170: "msgsys", 171: "shmsys", 173: "freebsd6_pread", 174: "freebsd6_pwrite", 176: "ntp_adjtime", 181: "setgid", 182: "setegid", 183: "seteuid", 188: "stat", 189: "fstat", 190: "lstat", 191: "pathconf", 192: "fpathconf", 194: "getrlimit", 195: "setrlimit", 196: "getdirentries", 197: "freebsd6_mmap", 198: "__syscall", 199: "freebsd6_lseek", 200: "freebsd6_truncate", 201: "freebsd6_ftruncate", 202: "__sysctl", 203: "mlock", 204: "munlock", 205: "undelete", 206: "futimes", 207: "getpgid", 209: "poll", 220: "__semctl", 221: "semget", 222: "semop", 224: "msgctl", 225: "msgget", 226: "msgsnd", 227: "msgrcv", 228: "shmat", 229: "shmctl", 230: "shmdt", 231: "shmget", 232: "clock_gettime", 233: "clock_settime", 234: "clock_getres", 235: "ktimer_create", 236: "ktimer_delete", 237: "ktimer_settime", 238: "ktimer_gettime", 239: "ktimer_getoverrun", 240: "nanosleep", 248: "ntp_gettime", 250: "minherit", 251: "rfork", 252: "openbsd_poll", 253: "issetugid", 254: "lchown", 255: "aio_read", 256: "aio_write", 257: "lio_listio", 272: "getdents", 274: "lchmod", 275: "netbsd_lchown", 276: "lutimes", 277: "netbsd_msync", 278: "nstat", 279: "nfstat", 280: "nlstat", 289: "preadv", 290: "pwritev", 297: "freebsd4_fhstatfs", 298: "fhopen", 299: "fhstat", 300: "modnext", 301: "modstat", 302: "modfnext", 303: "modfind", 304: "kldload", 305: "kldunload", 306: "kldfind", 307: "kldnext", 308: "kldstat", 309: "kldfirstmod", 310: "getsid", 311: "setresuid", 312: "setresgid", # 313: obsolete signanosleep 314: "aio_return", 315: "aio_suspend", 316: "aio_cancel", 317: "aio_error", 318: "oaio_read", 319: "oaio_write", 320: "olio_listio", 321: "yield", # 322: obsolete thr_sleep # 323: obsolete thr_wakeup 324: "mlockall", 325: "munlockall", 326: "__getcwd", 327: "sched_setparam", 328: "sched_getparam", 329: "sched_setscheduler", 330: "sched_getscheduler", 331: "sched_yield", 332: "sched_get_priority_max", 333: "sched_get_priority_min", 334: "sched_rr_get_interval", 335: "utrace", 336: "freebsd4_sendfile", 337: "kldsym", 338: "jail", 340: "sigprocmask", 341: "sigsuspend", 342: "freebsd4_sigaction", 343: "sigpending", 344: "freebsd4_sigreturn", 345: "sigtimedwait", 346: "sigwaitinfo", 347: "__acl_get_file", 348: "__acl_set_file", 349: "__acl_get_fd", 350: "__acl_set_fd", 351: "__acl_delete_file", 352: "__acl_delete_fd", 353: "__acl_aclcheck_file", 354: "__acl_aclcheck_fd", 355: "extattrctl", 356: "extattr_set_file", 357: "extattr_get_file", 358: "extattr_delete_file", 359: "aio_waitcomplete", 360: "getresuid", 361: "getresgid", 362: "kqueue", 363: "kevent", 371: "extattr_set_fd", 372: "extattr_get_fd", 373: "extattr_delete_fd", 374: "__setugid", 375: "nfsclnt", 376: "eaccess", 378: "nmount", 379: "kse_exit", 380: "kse_wakeup", 381: "kse_create", 382: "kse_thr_interrupt", 383: "kse_release", 384: "__mac_get_proc", 385: "__mac_set_proc", 386: "__mac_get_fd", 387: "__mac_get_file", 388: "__mac_set_fd", 389: "__mac_set_file", 390: "kenv", 391: "lchflags", 392: "uuidgen", 393: "sendfile", 394: "mac_syscall", 395: "getfsstat", 396: "statfs", 397: "fstatfs", 398: "fhstatfs", 400: "ksem_close", 401: "ksem_post", 402: "ksem_wait", 403: "ksem_trywait", 404: "ksem_init", 405: "ksem_open", 406: "ksem_unlink", 407: "ksem_getvalue", 408: "ksem_destroy", 409: "__mac_get_pid", 410: "__mac_get_link", 411: "__mac_set_link", 412: "extattr_set_link", 413: "extattr_get_link", 414: "extattr_delete_link", 415: "__mac_execve", 416: "sigaction", 417: "sigreturn", 421: "getcontext", 422: "setcontext", 423: "swapcontext", 424: "swapoff", 425: "__acl_get_link", 426: "__acl_set_link", 427: "__acl_delete_link", 428: "__acl_aclcheck_link", 429: "sigwait", 430: "thr_create", 431: "thr_exit", 432: "thr_self", 433: "thr_kill", 434: "_umtx_lock", 435: "_umtx_unlock", 436: "jail_attach", 437: "extattr_list_fd", 438: "extattr_list_file", 439: "extattr_list_link", 440: "kse_switchin", 441: "ksem_timedwait", 442: "thr_suspend", 443: "thr_wake", 444: "kldunloadf", 445: "audit", 446: "auditon", 447: "getauid", 448: "setauid", 449: "getaudit", 450: "setaudit", 451: "getaudit_addr", 452: "setaudit_addr", 453: "auditctl", 454: "_umtx_op", 455: "thr_new", 456: "sigqueue", 457: "kmq_open", 458: "kmq_setattr", 459: "kmq_timedreceive", 460: "kmq_timedsend", 461: "kmq_notify", 462: "kmq_unlink", 463: "abort2", 464: "thr_set_name", 465: "aio_fsync", 466: "rtprio_thread", 471: "sctp_peeloff", 472: "sctp_generic_sendmsg", 473: "sctp_generic_sendmsg_iov", 474: "sctp_generic_recvmsg", 475: "pread", 476: "pwrite", 477: "mmap", 478: "lseek", 479: "truncate", 480: "ftruncate", 481: "thr_kill2", } SOCKET_SYSCALL_NAMES = set(( "socket", "socketpair", "connect", "sendto", "recvfrom", "sendmsg", "recvmsg", "bind", "listen", "accept", "getpeername", "getsockname", "getsockopt", "setsockopt", "shutdown", )) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9395316 python-ptrace-0.9.8/ptrace/syscall/linux/0000775000175000017500000000000000000000000020721 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1596470844.0 python-ptrace-0.9.8/ptrace/syscall/linux/__init__.py0000664000175000017500000000000000000000000023020 0ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/syscall/linux/aarch64.py0000664000175000017500000001513300000000000022526 0ustar00vstinnervstinner# From https://github.com/hrw/syscalls-table/ SYSCALL_NAMES = { 0: "io_setup", 1: "io_destroy", 2: "io_submit", 3: "io_cancel", 4: "io_getevents", 5: "setxattr", 6: "lsetxattr", 7: "fsetxattr", 8: "getxattr", 9: "lgetxattr", 10: "fgetxattr", 11: "listxattr", 12: "llistxattr", 13: "flistxattr", 14: "removexattr", 15: "lremovexattr", 16: "fremovexattr", 17: "getcwd", 18: "lookup_dcookie", 19: "eventfd2", 20: "epoll_create1", 21: "epoll_ctl", 22: "epoll_pwait", 23: "dup", 24: "dup3", 25: "fcntl", 26: "inotify_init1", 27: "inotify_add_watch", 28: "inotify_rm_watch", 29: "ioctl", 30: "ioprio_set", 31: "ioprio_get", 32: "flock", 33: "mknodat", 34: "mkdirat", 35: "unlinkat", 36: "symlinkat", 37: "linkat", 38: "renameat", 39: "umount2", 40: "mount", 41: "pivot_root", 42: "nfsservctl", 43: "statfs", 44: "fstatfs", 45: "truncate", 46: "ftruncate", 47: "fallocate", 48: "faccessat", 49: "chdir", 50: "fchdir", 51: "chroot", 52: "fchmod", 53: "fchmodat", 54: "fchownat", 55: "fchown", 56: "openat", 57: "close", 58: "vhangup", 59: "pipe2", 60: "quotactl", 61: "getdents64", 62: "lseek", 63: "read", 64: "write", 65: "readv", 66: "writev", 67: "pread64", 68: "pwrite64", 69: "preadv", 70: "pwritev", 71: "sendfile", 72: "pselect6", 73: "ppoll", 74: "signalfd4", 75: "vmsplice", 76: "splice", 77: "tee", 78: "readlinkat", 79: "newfstatat", 80: "fstat", 81: "sync", 82: "fsync", 83: "fdatasync", 84: "sync_file_range", 85: "timerfd_create", 86: "timerfd_settime", 87: "timerfd_gettime", 88: "utimensat", 89: "acct", 90: "capget", 91: "capset", 92: "personality", 93: "exit", 94: "exit_group", 95: "waitid", 96: "set_tid_address", 97: "unshare", 98: "futex", 99: "set_robust_list", 100: "get_robust_list", 101: "nanosleep", 102: "getitimer", 103: "setitimer", 104: "kexec_load", 105: "init_module", 106: "delete_module", 107: "timer_create", 108: "timer_gettime", 109: "timer_getoverrun", 110: "timer_settime", 111: "timer_delete", 112: "clock_settime", 113: "clock_gettime", 114: "clock_getres", 115: "clock_nanosleep", 116: "syslog", 117: "ptrace", 118: "sched_setparam", 119: "sched_setscheduler", 120: "sched_getscheduler", 121: "sched_getparam", 122: "sched_setaffinity", 123: "sched_getaffinity", 124: "sched_yield", 125: "sched_get_priority_max", 126: "sched_get_priority_min", 127: "sched_rr_get_interval", 128: "restart_syscall", 129: "kill", 130: "tkill", 131: "tgkill", 132: "sigaltstack", 133: "rt_sigsuspend", 134: "rt_sigaction", 135: "rt_sigprocmask", 136: "rt_sigpending", 137: "rt_sigtimedwait", 138: "rt_sigqueueinfo", 139: "rt_sigreturn", 140: "setpriority", 141: "getpriority", 142: "reboot", 143: "setregid", 144: "setgid", 145: "setreuid", 146: "setuid", 147: "setresuid", 148: "getresuid", 149: "setresgid", 150: "getresgid", 151: "setfsuid", 152: "setfsgid", 153: "times", 154: "setpgid", 155: "getpgid", 156: "getsid", 157: "setsid", 158: "getgroups", 159: "setgroups", 160: "uname", 161: "sethostname", 162: "setdomainname", 163: "getrlimit", 164: "setrlimit", 165: "getrusage", 166: "umask", 167: "prctl", 168: "getcpu", 169: "gettimeofday", 170: "settimeofday", 171: "adjtimex", 172: "getpid", 173: "getppid", 174: "getuid", 175: "geteuid", 176: "getgid", 177: "getegid", 178: "gettid", 179: "sysinfo", 180: "mq_open", 181: "mq_unlink", 182: "mq_timedsend", 183: "mq_timedreceive", 184: "mq_notify", 185: "mq_getsetattr", 186: "msgget", 187: "msgctl", 188: "msgrcv", 189: "msgsnd", 190: "semget", 191: "semctl", 192: "semtimedop", 193: "semop", 194: "shmget", 195: "shmctl", 196: "shmat", 197: "shmdt", 198: "socket", 199: "socketpair", 200: "bind", 201: "listen", 202: "accept", 203: "connect", 204: "getsockname", 205: "getpeername", 206: "sendto", 207: "recvfrom", 208: "setsockopt", 209: "getsockopt", 210: "shutdown", 211: "sendmsg", 212: "recvmsg", 213: "readahead", 214: "brk", 215: "munmap", 216: "mremap", 217: "add_key", 218: "request_key", 219: "keyctl", 220: "clone", 221: "execve", 222: "mmap", 223: "fadvise64", 224: "swapon", 225: "swapoff", 226: "mprotect", 227: "msync", 228: "mlock", 229: "munlock", 230: "mlockall", 231: "munlockall", 232: "mincore", 233: "madvise", 234: "remap_file_pages", 235: "mbind", 236: "get_mempolicy", 237: "set_mempolicy", 238: "migrate_pages", 239: "move_pages", 240: "rt_tgsigqueueinfo", 241: "perf_event_open", 242: "accept4", 243: "recvmmsg", 260: "wait4", 261: "prlimit64", 262: "fanotify_init", 263: "fanotify_mark", 264: "name_to_handle_at", 265: "open_by_handle_at", 266: "clock_adjtime", 267: "syncfs", 268: "setns", 269: "sendmmsg", 270: "process_vm_readv", 271: "process_vm_writev", 272: "kcmp", 273: "finit_module", 274: "sched_setattr", 275: "sched_getattr", 276: "renameat2", 277: "seccomp", 278: "getrandom", 279: "memfd_create", 280: "bpf", 281: "execveat", 282: "userfaultfd", 283: "membarrier", 284: "mlock2", 285: "copy_file_range", 286: "preadv2", 287: "pwritev2", 288: "pkey_mprotect", 289: "pkey_alloc", 290: "pkey_free", 291: "statx", 292: "io_pgetevents", 293: "rseq", 294: "kexec_file_load", 424: "pidfd_send_signal", 425: "io_uring_setup", 426: "io_uring_enter", 427: "io_uring_register", 428: "open_tree", 429: "move_mount", 430: "fsopen", 431: "fsconfig", 432: "fsmount", 433: "fspick", 434: "pidfd_open", 435: "clone3", 436: "close_range", 437: "openat2", 438: "pidfd_getfd", 439: "faccessat2", } SOCKET_SYSCALL_NAMES = set(( "socket", "socketpair", "connect", "sendto", "recvfrom", "sendmsg", "recvmsg", "bind", "listen", "accept", "getsockname", "getpeername", "getsockopt", "setsockopt", "shutdown", )) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1596470844.0 python-ptrace-0.9.8/ptrace/syscall/linux/i386.py0000664000175000017500000001554700000000000022000 0ustar00vstinnervstinner# Linux kernel syscall list from Linux 2.6.21 for i386 # # List extracted from Linux kernel source code, see: # arch/i386/kernel/syscall_table.S SYSCALL_NAMES = { 0: "restart_syscall", 1: "exit", 2: "fork", 3: "read", 4: "write", 5: "open", 6: "close", 7: "waitpid", 8: "creat", 9: "link", 10: "unlink", 11: "execve", 12: "chdir", 13: "time", 14: "mknod", 15: "chmod", 16: "lchown16", # 17: - 18: "stat", 19: "lseek", 20: "getpid", 21: "mount", 22: "oldumount", 23: "setuid16", 24: "getuid16", 25: "stime", 26: "ptrace", 27: "alarm", 28: "fstat", 29: "pause", 30: "utime", # 31: - # 32: - 33: "access", 34: "nice", # 35: - 36: "sync", 37: "kill", 38: "rename", 39: "mkdir", 40: "rmdir", 41: "dup", 42: "pipe", 43: "times", # 44: - 45: "brk", 46: "setgid16", 47: "getgid16", 48: "signal", 49: "geteuid16", 50: "getegid16", 51: "acct", 52: "umount", # 53: - 54: "ioctl", 55: "fcntl", # 56: - 57: "setpgid", # 58: - 59: "oldolduname", 60: "umask", 61: "chroot", 62: "ustat", 63: "dup2", 64: "getppid", 65: "getpgrp", 66: "setsid", 67: "sigaction", 68: "sgetmask", 69: "ssetmask", 70: "setreuid16", 71: "setregid16", 72: "sigsuspend", 73: "sigpending", 74: "sethostname", 75: "setrlimit", 76: "old_getrlimit", 77: "getrusage", 78: "gettimeofday", 79: "settimeofday", 80: "getgroups16", 81: "setgroups16", 82: "old_select", 83: "symlink", 84: "lstat", 85: "readlink", 86: "uselib", 87: "swapon", 88: "reboot", 89: "old_readdir", 90: "old_mmap", 91: "munmap", 92: "truncate", 93: "ftruncate", 94: "fchmod", 95: "fchown16", 96: "getpriority", 97: "setpriority", # 98: - 99: "statfs", 100: "fstatfs", 101: "ioperm", 102: "socketcall", 103: "syslog", 104: "setitimer", 105: "getitimer", 106: "newstat", 107: "newlstat", 108: "newfstat", 109: "olduname", 110: "iopl", 111: "vhangup", # 112: old "idle" 113: "vm86old", 114: "wait4", 115: "swapoff", 116: "sysinfo", 117: "ipc", 118: "fsync", 119: "sigreturn", 120: "clone", 121: "setdomainname", 122: "uname", 123: "modify_ldt", 124: "adjtimex", 125: "mprotect", 126: "sigprocmask", # 127: old "create_module" 128: "init_module", 129: "delete_module", # 130: old "get_kernel_syms" 131: "quotactl", 132: "getpgid", 133: "fchdir", 134: "bdflush", 135: "sysfs", 136: "personality", # 137: reserved for afs_syscall 138: "setfsuid16", 139: "setfsgid16", 140: "llseek", 141: "getdents", 142: "select", 143: "flock", 144: "msync", 145: "readv", 146: "writev", 147: "getsid", 148: "fdatasync", 149: "sysctl", 150: "mlock", 151: "munlock", 152: "mlockall", 153: "munlockall", 154: "sched_setparam", 155: "sched_getparam", 156: "sched_setscheduler", 157: "sched_getscheduler", 158: "sched_yield", 159: "sched_get_priority_max", 160: "sched_get_priority_min", 161: "sched_rr_get_interval", 162: "nanosleep", 163: "mremap", 164: "setresuid16", 165: "getresuid16", 166: "vm86", # 167: old "query_module" 168: "poll", 169: "nfsservctl", 170: "setresgid16", 171: "getresgid16", 172: "prctl", 173: "rt_sigreturn", 174: "rt_sigaction", 175: "rt_sigprocmask", 176: "rt_sigpending", 177: "rt_sigtimedwait", 178: "rt_sigqueueinfo", 179: "rt_sigsuspend", 180: "pread64", 181: "pwrite64", 182: "chown16", 183: "getcwd", 184: "capget", 185: "capset", 186: "sigaltstack", 187: "sendfile", # 188: (reserved) # 189: (reserved) 190: "vfork", 191: "getrlimit", 192: "mmap2", 193: "truncate64", 194: "ftruncate64", 195: "stat64", 196: "lstat64", 197: "fstat64", 198: "lchown", 199: "getuid", 200: "getgid", 201: "geteuid", 202: "getegid", 203: "setreuid", 204: "setregid", 205: "getgroups", 206: "setgroups", 207: "fchown", 208: "setresuid", 209: "getresuid", 210: "setresgid", 211: "getresgid", 212: "chown", 213: "setuid", 214: "setgid", 215: "setfsuid", 216: "setfsgid", # ------------------------------- 217: "pivot_root", 218: "mincore", 219: "madvise", 220: "getdents64", 221: "fcntl64", # 222: - # 223: - 224: "gettid", 225: "readahead", 226: "setxattr", 227: "lsetxattr", 228: "fsetxattr", 229: "getxattr", 230: "lgetxattr", 231: "fgetxattr", 232: "listxattr", 233: "llistxattr", 234: "flistxattr", 235: "removexattr", 236: "lremovexattr", 237: "fremovexattr", 238: "tkill", 239: "sendfile64", 240: "futex", 241: "sched_setaffinity", 242: "sched_getaffinity", 243: "set_thread_area", 244: "get_thread_area", 245: "io_setup", 246: "io_destroy", 247: "io_getevents", 248: "io_submit", 249: "io_cancel", 250: "fadvise64", # 251: - 252: "exit_group", 253: "lookup_dcookie", 254: "epoll_create", 255: "epoll_ctl", 256: "epoll_wait", 257: "remap_file_pages", 258: "set_tid_address", 259: "timer_create", 260: "timer_settime", 261: "timer_gettime", 262: "timer_getoverrun", 263: "timer_delete", 264: "clock_settime", 265: "clock_gettime", 266: "clock_getres", 267: "clock_nanosleep", 268: "statfs64", 269: "fstatfs64", 270: "tgkill", 271: "utimes", 272: "fadvise64_64", # 273: - 274: "mbind", 275: "get_mempolicy", 276: "set_mempolicy", 277: "mq_open", 278: "mq_unlink", 279: "mq_timedsend", 280: "mq_timedreceive", 281: "mq_notify", 282: "mq_getsetattr", 283: "kexec_load", 284: "waitid", # 285: - 286: "add_key", 287: "request_key", 288: "keyctl", 289: "ioprio_set", 290: "ioprio_get", 291: "inotify_init", 292: "inotify_add_watch", 293: "inotify_rm_watch", 294: "migrate_pages", 295: "openat", 296: "mkdirat", 297: "mknodat", 298: "fchownat", 299: "futimesat", 300: "fstatat64", 301: "unlinkat", 302: "renameat", 303: "linkat", 304: "symlinkat", 305: "readlinkat", 306: "fchmodat", 307: "faccessat", 308: "pselect6", 309: "ppoll", 310: "unshare", 311: "set_robust_list", 312: "get_robust_list", 313: "splice", 314: "sync_file_range", 315: "tee", 316: "vmsplice", 317: "move_pages", 318: "getcpu", 319: "epoll_pwait", } SOCKET_SYSCALL_NAMES = set(("socketcall",)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1596470844.0 python-ptrace-0.9.8/ptrace/syscall/linux/powerpc32.py0000664000175000017500000002221300000000000023117 0ustar00vstinnervstinner# From the kernel sources, arch/powerpc/kernel/syscalls/syscall.tbl SYSCALL_NAMES = { 0: "restart_syscall", 1: "exit", 2: "fork", 3: "read", 4: "write", 5: "open", 6: "close", 7: "waitpid", 8: "creat", 9: "link", 10: "unlink", 11: "execve", 12: "chdir", 13: "time", 14: "mknod", 15: "chmod", 16: "lchown", 17: "break", 18: "oldstat", 19: "lseek", 20: "getpid", 21: "mount", 22: "umount", 23: "setuid", 24: "getuid", 25: "stime", 26: "ptrace", 27: "alarm", 28: "oldfstat", 29: "pause", 30: "utime", 31: "stty", 32: "gtty", 33: "access", 34: "nice", 35: "ftime", 36: "sync", 37: "kill", 38: "rename", 39: "mkdir", 40: "rmdir", 41: "dup", 42: "pipe", 43: "times", 44: "prof", 45: "brk", 46: "setgid", 47: "getgid", 48: "signal", 49: "geteuid", 50: "getegid", 51: "acct", 52: "umount2", 53: "lock", 54: "ioctl", 55: "fcntl", 56: "mpx", 57: "setpgid", 58: "ulimit", 59: "oldolduname", 60: "umask", 61: "chroot", 62: "ustat", 63: "dup2", 64: "getppid", 65: "getpgrp", 66: "setsid", 67: "sigaction", 68: "sgetmask", 69: "ssetmask", 70: "setreuid", 71: "setregid", 72: "sigsuspend", 73: "sigpending", 74: "sethostname", 75: "setrlimit", 76: "getrlimit", 77: "getrusage", 78: "gettimeofday", 79: "settimeofday", 80: "getgroups", 81: "setgroups", 82: "select", 83: "symlink", 84: "oldlstat", 85: "readlink", 86: "uselib", 87: "swapon", 88: "reboot", 89: "readdir", 90: "mmap", 91: "munmap", 92: "truncate", 93: "ftruncate", 94: "fchmod", 95: "fchown", 96: "getpriority", 97: "setpriority", 98: "profil", 99: "statfs", 100: "fstatfs", 101: "ioperm", 102: "socketcall", 103: "syslog", 104: "setitimer", 105: "getitimer", 106: "stat", 107: "lstat", 108: "fstat", 109: "olduname", 110: "iopl", 111: "vhangup", 112: "idle", 113: "vm86", 114: "wait4", 115: "swapoff", 116: "sysinfo", 117: "ipc", 118: "fsync", 119: "sigreturn", 120: "clone", 121: "setdomainname", 122: "uname", 123: "modify_ldt", 124: "adjtimex", 125: "mprotect", 126: "sigprocmask", 127: "create_module", 128: "init_module", 129: "delete_module", 130: "get_kernel_syms", 131: "quotactl", 132: "getpgid", 133: "fchdir", 134: "bdflush", 135: "sysfs", 136: "personality", 137: "afs_syscall", 138: "setfsuid", 139: "setfsgid", 140: "_llseek", 141: "getdents", 142: "_newselect", 143: "flock", 144: "msync", 145: "readv", 146: "writev", 147: "getsid", 148: "fdatasync", 149: "_sysctl", 150: "mlock", 151: "munlock", 152: "mlockall", 153: "munlockall", 154: "sched_setparam", 155: "sched_getparam", 156: "sched_setscheduler", 157: "sched_getscheduler", 158: "sched_yield", 159: "sched_get_priority_max", 160: "sched_get_priority_min", 161: "sched_rr_get_interval", 162: "nanosleep", 163: "mremap", 164: "setresuid", 165: "getresuid", 166: "query_module", 167: "poll", 168: "nfsservctl", 169: "setresgid", 170: "getresgid", 171: "prctl", 172: "rt_sigreturn", 173: "rt_sigaction", 174: "rt_sigprocmask", 175: "rt_sigpending", 176: "rt_sigtimedwait", 177: "", 178: "", 179: "pread64", 180: "pwrite64", 181: "chown", 182: "getcwd", 183: "capget", 184: "capset", 185: "sigaltstack", 186: "sendfile", 187: "getpmsg", 188: "", 189: "vfork", 190: "ugetrlimit", 191: "readahead", 192: "mmap2", 193: "truncate64", 194: "ftruncate64", 195: "stat64", 196: "lstat64", 197: "fstat64", 198: "", 199: "", 200: "", 201: "", 202: "getdents64", 203: "pivot_root", 204: "fcntl64", 205: "madvise", 206: "mincore", 207: "gettid", 208: "tkill", 209: "setxattr", 210: "lsetxattr", 211: "fsetxattr", 212: "getxattr", 213: "lgetxattr", 214: "fgetxattr", 215: "listxattr", 216: "llistxattr", 217: "flistxattr", 218: "removexattr", 219: "lremovexattr", 220: "fremovexattr", 221: "futex", 222: "sched_setaffinity", 223: "sched_getaffinity", 225: "tuxcall", 226: "sendfile64", 227: "io_setup", 228: "io_destroy", 229: "io_getevents", 230: "io_submit", 231: "io_cancel", 232: "set_tid_address", 233: "fadvise64", 234: "exit_group", 235: "lookup_dcookie", 236: "epoll_create", 237: "epoll_ctl", 238: "epoll_wait", 239: "remap_file_pages", 240: "timer_create", 241: "timer_settime", 242: "timer_gettime", 243: "timer_getoverrun", 244: "timer_delete", 245: "clock_settime", 246: "clock_gettime", 247: "clock_getres", 248: "clock_nanosleep", 249: "swapcontext", 250: "tgkill", 251: "utimes", 252: "statfs64", 253: "fstatfs64", 254: "fadvise64_64", 255: "rtas", 256: "sys_debug_setcontext", 258: "migrate_pages", 259: "mbind", 260: "get_mempolicy", 261: "set_mempolicy", 262: "mq_open", 263: "mq_unlink", 264: "mq_timedsend", 265: "mq_timedreceive", 266: "mq_notify", 267: "mq_getsetattr", 268: "kexec_load", 269: "add_key", 270: "request_key", 271: "keyctl", 272: "waitid", 273: "ioprio_set", 274: "ioprio_get", 275: "inotify_init", 276: "inotify_add_watch", 277: "inotify_rm_watch", 280: "pselect6", 281: "ppoll", 282: "unshare", 283: "splice", 284: "tee", 285: "vmsplice", 286: "openat", 287: "mkdirat", 288: "mknodat", 289: "fchownat", 290: "futimesat", 291: "fstatat64", 292: "unlinkat", 293: "renameat", 294: "linkat", 295: "symlinkat", 296: "readlinkat", 297: "fchmodat", 298: "faccessat", 299: "get_robust_list", 300: "set_robust_list", 301: "move_pages", 302: "getcpu", 303: "epoll_pwait", 304: "utimensat", 305: "signalfd", 306: "timerfd_create", 307: "eventfd", 308: "sync_file_range2", 309: "fallocate", 310: "subpage_prot", 311: "timerfd_settime", 312: "timerfd_gettime", 313: "signalfd4", 314: "eventfd2", 315: "epoll_create1", 316: "dup3", 317: "pipe2", 318: "inotify_init1", 319: "perf_event_open", 320: "preadv", 321: "pwritev", 322: "rt_tgsigqueueinfo", 323: "fanotify_init", 324: "fanotify_mark", 325: "prlimit64", 326: "socket", 327: "bind", 328: "connect", 329: "listen", 330: "accept", 331: "getsockname", 332: "getpeername", 333: "socketpair", 334: "send", 335: "sendto", 336: "recv", 337: "recvfrom", 338: "shutdown", 339: "setsockopt", 340: "getsockopt", 341: "sendmsg", 342: "recvmsg", 343: "recvmmsg", 344: "accept4", 345: "name_to_handle_at", 346: "open_by_handle_at", 347: "clock_adjtime", 348: "syncfs", 349: "sendmmsg", 350: "setns", 351: "process_vm_readv", 352: "process_vm_writev", 353: "finit_module", 354: "kcmp", 355: "sched_setattr", 356: "sched_getattr", 357: "renameat2", 358: "seccomp", 359: "getrandom", 360: "memfd_create", 361: "bpf", 362: "execveat", 363: "switch_endian", 364: "userfaultfd", 365: "membarrier", 378: "mlock2", 379: "copy_file_range", 380: "preadv2", 381: "pwritev2", 382: "kexec_file_load", 383: "statx", 384: "pkey_alloc", 385: "pkey_free", 386: "pkey_mprotect", 387: "rseq", 388: "io_pgetevents", 393: "semget", 394: "semctl", 395: "shmget", 396: "shmctl", 397: "shmat", 398: "shmdt", 399: "msgget", 400: "msgsnd", 401: "msgrcv", 402: "msgctl", 403: "clock_gettime64", 404: "clock_settime64", 405: "clock_adjtime64", 406: "clock_getres_time64", 407: "clock_nanosleep_time64", 408: "timer_gettime64", 409: "timer_settime64", 410: "timerfd_gettime64", 411: "timerfd_settime64", 412: "utimensat_time64", 413: "pselect6_time64", 414: "ppoll_time64", 416: "io_pgetevents_time64", 417: "recvmmsg_time64", 418: "mq_timedsend_time64", 419: "mq_timedreceive_time64", 420: "semtimedop_time64", 421: "rt_sigtimedwait_time64", 422: "futex_time64", 423: "sched_rr_get_interval_time64", 424: "pidfd_send_signal", 425: "io_uring_setup", 426: "io_uring_enter", 427: "io_uring_register", 428: "open_tree", 429: "move_mount", 430: "fsopen", 431: "fsconfig", 432: "fsmount", 433: "fspick", 434: "pidfd_open", 435: "clone3", 437: "openat2", 438: "pidfd_getfd" } SOCKET_SYSCALL_NAMES = set(( "socket", "socketpair", "connect", "sendto", "recvfrom", "sendmsg", "recvmsg", "bind", "listen", "accept", "getsockname", "getpeername", "getsockopt", "setsockopt", "shutdown", )) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1596470844.0 python-ptrace-0.9.8/ptrace/syscall/linux/powerpc64.py0000664000175000017500000002073600000000000023134 0ustar00vstinnervstinner# From the kernel sources, arch/powerpc/kernel/syscalls/syscall.tbl SYSCALL_NAMES = { 0: "restart_syscall", 1: "exit", 2: "fork", 3: "read", 4: "write", 5: "open", 6: "close", 7: "waitpid", 8: "creat", 9: "link", 10: "unlink", 11: "execve", 12: "chdir", 13: "time", 14: "mknod", 15: "chmod", 16: "lchown", 17: "break", 18: "oldstat", 19: "lseek", 20: "getpid", 21: "mount", 22: "umount", 23: "setuid", 24: "getuid", 25: "stime", 26: "ptrace", 27: "alarm", 28: "oldfstat", 29: "pause", 30: "utime", 31: "stty", 32: "gtty", 33: "access", 34: "nice", 35: "ftime", 36: "sync", 37: "kill", 38: "rename", 39: "mkdir", 40: "rmdir", 41: "dup", 42: "pipe", 43: "times", 44: "prof", 45: "brk", 46: "setgid", 47: "getgid", 48: "signal", 49: "geteuid", 50: "getegid", 51: "acct", 52: "umount2", 53: "lock", 54: "ioctl", 55: "fcntl", 56: "mpx", 57: "setpgid", 58: "ulimit", 59: "oldolduname", 60: "umask", 61: "chroot", 62: "ustat", 63: "dup2", 64: "getppid", 65: "getpgrp", 66: "setsid", 67: "sigaction", 68: "sgetmask", 69: "ssetmask", 70: "setreuid", 71: "setregid", 72: "sigsuspend", 73: "sigpending", 74: "sethostname", 75: "setrlimit", 76: "getrlimit", 77: "getrusage", 78: "gettimeofday", 79: "settimeofday", 80: "getgroups", 81: "setgroups", 82: "select", 83: "symlink", 84: "oldlstat", 85: "readlink", 86: "uselib", 87: "swapon", 88: "reboot", 89: "readdir", 90: "mmap", 91: "munmap", 92: "truncate", 93: "ftruncate", 94: "fchmod", 95: "fchown", 96: "getpriority", 97: "setpriority", 98: "profil", 99: "statfs", 100: "fstatfs", 101: "ioperm", 102: "socketcall", 103: "syslog", 104: "setitimer", 105: "getitimer", 106: "stat", 107: "lstat", 108: "fstat", 109: "olduname", 110: "iopl", 111: "vhangup", 112: "idle", 113: "vm86", 114: "wait4", 115: "swapoff", 116: "sysinfo", 117: "ipc", 118: "fsync", 119: "sigreturn", 120: "clone", 121: "setdomainname", 122: "uname", 123: "modify_ldt", 124: "adjtimex", 125: "mprotect", 126: "sigprocmask", 127: "create_module", 128: "init_module", 129: "delete_module", 130: "get_kernel_syms", 131: "quotactl", 132: "getpgid", 133: "fchdir", 134: "bdflush", 135: "sysfs", 136: "personality", 137: "afs_syscall", 138: "setfsuid", 139: "setfsgid", 140: "_llseek", 141: "getdents", 142: "_newselect", 143: "flock", 144: "msync", 145: "readv", 146: "writev", 147: "getsid", 148: "fdatasync", 149: "_sysctl", 150: "mlock", 151: "munlock", 152: "mlockall", 153: "munlockall", 154: "sched_setparam", 155: "sched_getparam", 156: "sched_setscheduler", 157: "sched_getscheduler", 158: "sched_yield", 159: "sched_get_priority_max", 160: "sched_get_priority_min", 161: "sched_rr_get_interval", 162: "nanosleep", 163: "mremap", 164: "setresuid", 165: "getresuid", 166: "query_module", 167: "poll", 168: "nfsservctl", 169: "setresgid", 170: "getresgid", 171: "prctl", 172: "rt_sigreturn", 173: "rt_sigaction", 174: "rt_sigprocmask", 175: "rt_sigpending", 176: "rt_sigtimedwait", 177: "rt_sigqueueinfo", 178: "rt_sigsuspend", 179: "pread64", 180: "pwrite64", 181: "chown", 182: "getcwd", 183: "capget", 184: "capset", 185: "sigaltstack", 186: "sendfile", 187: "getpmsg", 188: "putpmsg", 189: "vfork", 190: "ugetrlimit", 191: "readahead", 198: "pciconfig_read", 199: "pciconfig_write", 200: "pciconfig_iobase", 201: "multiplexer", 202: "getdents64", 203: "pivot_root", 205: "madvise", 206: "mincore", 207: "gettid", 208: "tkill", 209: "setxattr", 210: "lsetxattr", 211: "fsetxattr", 212: "getxattr", 213: "lgetxattr", 214: "fgetxattr", 215: "listxattr", 216: "llistxattr", 217: "flistxattr", 218: "removexattr", 219: "lremovexattr", 220: "fremovexattr", 221: "futex", 222: "sched_setaffinity", 223: "sched_getaffinity", 225: "tuxcall", 227: "io_setup", 228: "io_destroy", 229: "io_getevents", 230: "io_submit", 231: "io_cancel", 232: "set_tid_address", 233: "fadvise64", 234: "exit_group", 235: "lookup_dcookie", 236: "epoll_create", 237: "epoll_ctl", 238: "epoll_wait", 239: "remap_file_pages", 240: "timer_create", 241: "timer_settime", 242: "timer_gettime", 243: "timer_getoverrun", 244: "timer_delete", 245: "clock_settime", 246: "clock_gettime", 247: "clock_getres", 248: "clock_nanosleep", 249: "swapcontext", 250: "tgkill", 251: "utimes", 252: "statfs64", 253: "fstatfs64", 255: "rtas", 256: "sys_debug_setcontext", 258: "migrate_pages", 259: "mbind", 260: "get_mempolicy", 261: "set_mempolicy", 262: "mq_open", 263: "mq_unlink", 264: "mq_timedsend", 265: "mq_timedreceive", 266: "mq_notify", 267: "mq_getsetattr", 268: "kexec_load", 269: "add_key", 270: "request_key", 271: "keyctl", 272: "waitid", 273: "ioprio_set", 274: "ioprio_get", 275: "inotify_init", 276: "inotify_add_watch", 277: "inotify_rm_watch", 280: "pselect6", 281: "ppoll", 282: "unshare", 283: "splice", 284: "tee", 285: "vmsplice", 286: "openat", 287: "mkdirat", 288: "mknodat", 289: "fchownat", 290: "futimesat", 291: "newfstatat", 292: "unlinkat", 293: "renameat", 294: "linkat", 295: "symlinkat", 296: "readlinkat", 297: "fchmodat", 298: "faccessat", 299: "get_robust_list", 300: "set_robust_list", 301: "move_pages", 302: "getcpu", 303: "epoll_pwait", 304: "utimensat", 305: "signalfd", 306: "timerfd_create", 307: "eventfd", 308: "sync_file_range2", 309: "fallocate", 310: "subpage_prot", 311: "timerfd_settime", 312: "timerfd_gettime", 313: "signalfd4", 314: "eventfd2", 315: "epoll_create1", 316: "dup3", 317: "pipe2", 318: "inotify_init1", 319: "perf_event_open", 320: "preadv", 321: "pwritev", 322: "rt_tgsigqueueinfo", 323: "fanotify_init", 324: "fanotify_mark", 325: "prlimit64", 326: "socket", 327: "bind", 328: "connect", 329: "listen", 330: "accept", 331: "getsockname", 332: "getpeername", 333: "socketpair", 334: "send", 335: "sendto", 336: "recv", 337: "recvfrom", 338: "shutdown", 339: "setsockopt", 340: "getsockopt", 341: "sendmsg", 342: "recvmsg", 343: "recvmmsg", 344: "accept4", 345: "name_to_handle_at", 346: "open_by_handle_at", 347: "clock_adjtime", 348: "syncfs", 349: "sendmmsg", 350: "setns", 351: "process_vm_readv", 352: "process_vm_writev", 353: "finit_module", 354: "kcmp", 355: "sched_setattr", 356: "sched_getattr", 357: "renameat2", 358: "seccomp", 359: "getrandom", 360: "memfd_create", 361: "bpf", 362: "execveat", 363: "switch_endian", 364: "userfaultfd", 365: "membarrier", 378: "mlock2", 379: "copy_file_range", 380: "preadv2", 381: "pwritev2", 382: "kexec_file_load", 383: "statx", 384: "pkey_alloc", 385: "pkey_free", 386: "pkey_mprotect", 387: "rseq", 388: "io_pgetevents", 392: "semtimedop", 393: "semget", 394: "semctl", 395: "shmget", 396: "shmctl", 397: "shmat", 398: "shmdt", 399: "msgget", 400: "msgsnd", 401: "msgrcv", 402: "msgctl", 424: "pidfd_send_signal", 425: "io_uring_setup", 426: "io_uring_enter", 427: "io_uring_register", 428: "open_tree", 429: "move_mount", 430: "fsopen", 431: "fsconfig", 432: "fsmount", 433: "fspick", 434: "pidfd_open", 435: "clone3", 437: "openat2", 438: "pidfd_getfd" } SOCKET_SYSCALL_NAMES = set(( "socket", "socketpair", "connect", "sendto", "recvfrom", "sendmsg", "recvmsg", "bind", "listen", "accept", "getsockname", "getpeername", "getsockopt", "setsockopt", "shutdown", )) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/syscall/linux/x86_64.py0000664000175000017500000002075000000000000022235 0ustar00vstinnervstinner# Linux kernel 5.8.0 on Intel Xeon E5-2670 SYSCALL_NAMES = { 0: "read", 1: "write", 2: "open", 3: "close", 4: "stat", 5: "fstat", 6: "lstat", 7: "poll", 8: "lseek", 9: "mmap", 10: "mprotect", 11: "munmap", 12: "brk", 13: "rt_sigaction", 14: "rt_sigprocmask", 15: "rt_sigreturn", 16: "ioctl", 17: "pread64", 18: "pwrite64", 19: "readv", 20: "writev", 21: "access", 22: "pipe", 23: "select", 24: "sched_yield", 25: "mremap", 26: "msync", 27: "mincore", 28: "madvise", 29: "shmget", 30: "shmat", 31: "shmctl", 32: "dup", 33: "dup2", 34: "pause", 35: "nanosleep", 36: "getitimer", 37: "alarm", 38: "setitimer", 39: "getpid", 40: "sendfile", 41: "socket", 42: "connect", 43: "accept", 44: "sendto", 45: "recvfrom", 46: "sendmsg", 47: "recvmsg", 48: "shutdown", 49: "bind", 50: "listen", 51: "getsockname", 52: "getpeername", 53: "socketpair", 54: "setsockopt", 55: "getsockopt", 56: "clone", 57: "fork", 58: "vfork", 59: "execve", 60: "exit", 61: "wait4", 62: "kill", 63: "uname", 64: "semget", 65: "semop", 66: "semctl", 67: "shmdt", 68: "msgget", 69: "msgsnd", 70: "msgrcv", 71: "msgctl", 72: "fcntl", 73: "flock", 74: "fsync", 75: "fdatasync", 76: "truncate", 77: "ftruncate", 78: "getdents", 79: "getcwd", 80: "chdir", 81: "fchdir", 82: "rename", 83: "mkdir", 84: "rmdir", 85: "creat", 86: "link", 87: "unlink", 88: "symlink", 89: "readlink", 90: "chmod", 91: "fchmod", 92: "chown", 93: "fchown", 94: "lchown", 95: "umask", 96: "gettimeofday", 97: "getrlimit", 98: "getrusage", 99: "sysinfo", 100: "times", 101: "ptrace", 102: "getuid", 103: "syslog", 104: "getgid", 105: "setuid", 106: "setgid", 107: "geteuid", 108: "getegid", 109: "setpgid", 110: "getppid", 111: "getpgrp", 112: "setsid", 113: "setreuid", 114: "setregid", 115: "getgroups", 116: "setgroups", 117: "setresuid", 118: "getresuid", 119: "setresgid", 120: "getresgid", 121: "getpgid", 122: "setfsuid", 123: "setfsgid", 124: "getsid", 125: "capget", 126: "capset", 127: "rt_sigpending", 128: "rt_sigtimedwait", 129: "rt_sigqueueinfo", 130: "rt_sigsuspend", 131: "sigaltstack", 132: "utime", 133: "mknod", 134: "uselib", 135: "personality", 136: "ustat", 137: "statfs", 138: "fstatfs", 139: "sysfs", 140: "getpriority", 141: "setpriority", 142: "sched_setparam", 143: "sched_getparam", 144: "sched_setscheduler", 145: "sched_getscheduler", 146: "sched_get_priority_max", 147: "sched_get_priority_min", 148: "sched_rr_get_interval", 149: "mlock", 150: "munlock", 151: "mlockall", 152: "munlockall", 153: "vhangup", 154: "modify_ldt", 155: "pivot_root", 156: "_sysctl", 157: "prctl", 158: "arch_prctl", 159: "adjtimex", 160: "setrlimit", 161: "chroot", 162: "sync", 163: "acct", 164: "settimeofday", 165: "mount", 166: "umount2", 167: "swapon", 168: "swapoff", 169: "reboot", 170: "sethostname", 171: "setdomainname", 172: "iopl", 173: "ioperm", 174: "create_module", 175: "init_module", 176: "delete_module", 177: "get_kernel_syms", 178: "query_module", 179: "quotactl", 180: "nfsservctl", 181: "getpmsg", 182: "putpmsg", 183: "afs_syscall", 184: "tuxcall", 185: "security", 186: "gettid", 187: "readahead", 188: "setxattr", 189: "lsetxattr", 190: "fsetxattr", 191: "getxattr", 192: "lgetxattr", 193: "fgetxattr", 194: "listxattr", 195: "llistxattr", 196: "flistxattr", 197: "removexattr", 198: "lremovexattr", 199: "fremovexattr", 200: "tkill", 201: "time", 202: "futex", 203: "sched_setaffinity", 204: "sched_getaffinity", 205: "set_thread_area", 206: "io_setup", 207: "io_destroy", 208: "io_getevents", 209: "io_submit", 210: "io_cancel", 211: "get_thread_area", 212: "lookup_dcookie", 213: "epoll_create", 214: "epoll_ctl_old", 215: "epoll_wait_old", 216: "remap_file_pages", 217: "getdents64", 218: "set_tid_address", 219: "restart_syscall", 220: "semtimedop", 221: "fadvise64", 222: "timer_create", 223: "timer_settime", 224: "timer_gettime", 225: "timer_getoverrun", 226: "timer_delete", 227: "clock_settime", 228: "clock_gettime", 229: "clock_getres", 230: "clock_nanosleep", 231: "exit_group", 232: "epoll_wait", 233: "epoll_ctl", 234: "tgkill", 235: "utimes", 236: "vserver", 237: "mbind", 238: "set_mempolicy", 239: "get_mempolicy", 240: "mq_open", 241: "mq_unlink", 242: "mq_timedsend", 243: "mq_timedreceive", 244: "mq_notify", 245: "mq_getsetattr", 246: "kexec_load", 247: "waitid", 248: "add_key", 249: "request_key", 250: "keyctl", 251: "ioprio_set", 252: "ioprio_get", 253: "inotify_init", 254: "inotify_add_watch", 255: "inotify_rm_watch", 256: "migrate_pages", 257: "openat", 258: "mkdirat", 259: "mknodat", 260: "fchownat", 261: "futimesat", 262: "newfstatat", 263: "unlinkat", 264: "renameat", 265: "linkat", 266: "symlinkat", 267: "readlinkat", 268: "fchmodat", 269: "faccessat", 270: "pselect6", 271: "ppoll", 272: "unshare", 273: "set_robust_list", 274: "get_robust_list", 275: "splice", 276: "tee", 277: "sync_file_range", 278: "vmsplice", 279: "move_pages", 280: "utimensat", 281: "epoll_pwait", 282: "signalfd", 283: "timerfd", 284: "eventfd", 285: "fallocate", 286: "timerfd_settime", 287: "timerfd_gettime", 288: "accept4", 289: "signalfd4", 290: "eventfd2", 291: "epoll_create1", 292: "dup3", 293: "pipe2", 294: "inotify_init1", 295: "preadv", 296: "pwritev", 297: "rt_tgsigqueueinfo", 298: "perf_event_open", 299: "recvmmsg", 300: "fanotify_init", 301: "fanotify_mark", 302: "prlimit64", 303: "name_to_handle_at", 304: "open_by_handle_at", 305: "clock_adjtime", 306: "syncfs", 307: "sendmmsg", 308: "setns", 309: "getcpu", 310: "process_vm_readv", 311: "process_vm_writev", 312: "kcmp", 313: "finit_module", 314: "sched_setattr", 315: "sched_getattr", 316: "renameat2", 317: "seccomp", 318: "getrandom", 319: "memfd_create", 320: "kexec_file_load", 321: "bpf", 322: "execveat", 323: "userfaultfd", 324: "membarrier", 325: "mlock2", 326: "copy_file_range", 327: "preadv2", 328: "pwritev2", 329: "pkey_mprotect", 330: "pkey_alloc", 331: "pkey_free", 332: "statx", 333: "io_pgetevents", 334: "rseq", 424: "pidfd_send_signal", 425: "io_uring_setup", 426: "io_uring_enter", 427: "io_uring_register", 428: "open_tree", 429: "move_mount", 430: "fsopen", 431: "fsconfig", 432: "fsmount", 433: "fspick", 434: "pidfd_open", 435: "clone3", 436: "close_range", 437: "openat2", 438: "pidfd_getfd", 439: "faccessat2", 440: "process_madvise", 512: "rt_sigaction", 513: "rt_sigreturn", 514: "ioctl", 515: "readv", 516: "writev", 517: "recvfrom", 518: "sendmsg", 519: "recvmsg", 520: "execve", 521: "ptrace", 522: "rt_sigpending", 523: "rt_sigtimedwait", 524: "rt_sigqueueinfo", 525: "sigaltstack", 526: "timer_create", 527: "mq_notify", 528: "kexec_load", 529: "waitid", 530: "set_robust_list", 531: "get_robust_list", 532: "vmsplice", 533: "move_pages", 534: "preadv", 535: "pwritev", 536: "rt_tgsigqueueinfo", 537: "recvmmsg", 538: "sendmmsg", 539: "process_vm_readv", 540: "process_vm_writev", 541: "setsockopt", 542: "getsockopt", 543: "io_setup", 544: "io_submit", 545: "execveat", 546: "preadv2", 547: "pwritev2", } SOCKET_SYSCALL_NAMES = set(( "socket", "socketpair", "connect", "sendto", "recvfrom", "sendmsg", "recvmsg", "bind", "listen", "accept", "getsockname", "getpeername", "getsockopt", "setsockopt", "shutdown", )) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/syscall/linux_constants.py0000664000175000017500000000142400000000000023370 0ustar00vstinnervstinnerfrom ptrace.syscall.posix_constants import SYSCALL_ARG_DICT SIGSET_SIZE = 64 FD_SETSIZE = 1024 RLIMIT_RESOURCE = { 0: "RLIMIT_CPU", 1: "RLIMIT_FSIZE", 2: "RLIMIT_DATA", 3: "RLIMIT_STACK", 4: "RLIMIT_CORE", 5: "RLIMIT_RSS", 6: "RLIMIT_NPROC", 7: "RLIMIT_NOFILE", 8: "RLIMIT_MEMLOCK", 9: "RLIMIT_AS", 10: "RLIMIT_LOCKS", 11: "RLIMIT_SIGPENDING", 12: "RLIMIT_MSGQUEUE", 13: "RLIMIT_NICE", 14: "RLIMIT_RTPRIO", 15: "RLIMIT_NLIMITS", } SIGPROCMASK_HOW = {0: "SIG_BLOCK", 1: "SIG_UNBLOCK", 2: "SIG_SETMASK"} SYSCALL_ARG_DICT.update({ "getrlimit": {"resource": RLIMIT_RESOURCE}, "setrlimit": {"resource": RLIMIT_RESOURCE}, "sigprocmask": {"how": SIGPROCMASK_HOW}, "rt_sigprocmask": {"how": SIGPROCMASK_HOW}, }) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/syscall/linux_struct.py0000664000175000017500000000243100000000000022677 0ustar00vstinnervstinnerfrom ctypes import (Structure, c_char, c_short, c_int, c_uint, c_long, c_ulong) time_t = c_long suseconds_t = c_long rlim_t = c_long class timeval(Structure): _fields_ = ( ("tv_sec", time_t), ("tv_usec", suseconds_t), ) class timespec(Structure): _fields_ = ( ("tv_sec", time_t), ("tv_nsec", c_long), ) class pollfd(Structure): _fields_ = ( ("fd", c_int), ("events", c_short), ("revents", c_short), ) class rlimit(Structure): _fields_ = ( ("rlim_cur", rlim_t), ("rlim_max", rlim_t), ) class new_utsname(Structure): _fields_ = ( ("sysname", c_char * 65), ("nodename", c_char * 65), ("release", c_char * 65), ("version", c_char * 65), ("machine", c_char * 65), ("domainname", c_char * 65), ) # Arch depend class user_desc(Structure): _fields_ = ( ("entry_number", c_uint), ("base_addr", c_ulong), ("limit", c_uint), ("_bits_", c_char), # unsigned int seg_32bit:1; # unsigned int contents:2; # unsigned int read_exec_only:1; # unsigned int limit_in_pages:1; # unsigned int seg_not_present:1; # unsigned int useable:1; ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/syscall/names.py0000664000175000017500000000164200000000000021242 0ustar00vstinnervstinnerfrom ptrace.cpu_info import CPU_X86_64, CPU_I386, CPU_PPC64, CPU_PPC32, CPU_AARCH64 from ptrace.os_tools import RUNNING_LINUX, RUNNING_FREEBSD if RUNNING_LINUX: if CPU_X86_64: from ptrace.syscall.linux.x86_64 import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES elif CPU_I386: from ptrace.syscall.linux.i386 import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES elif CPU_PPC64: from ptrace.syscall.linux.powerpc64 import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES elif CPU_PPC32: from ptrace.syscall.linux.powerpc32 import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES elif CPU_AARCH64: from ptrace.syscall.linux.aarch64 import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES else: raise NotImplementedError("Unsupported CPU architecture") elif RUNNING_FREEBSD: from ptrace.syscall.freebsd_syscall import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES else: SYSCALL_NAMES = {} SOCKET_SYSCALL_NAMES = set() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065641.0 python-ptrace-0.9.8/ptrace/syscall/posix_arg.py0000664000175000017500000000642500000000000022136 0ustar00vstinnervstinnerfrom ptrace.tools import readBits, formatBits from ptrace.signames import signalName from ptrace.ctypes_tools import uint2int # From /usr/include/bits/mman.h (Ubuntu Feisty, i386) MMAP_PROT_BITMASK = ( (1, "PROT_READ"), (2, "PROT_WRITE"), (4, "PROT_EXEC"), (0x01000000, "PROT_GROWSDOWN"), (0x02000000, "PROT_GROWSUP"), ) def formatMmapProt(argument): return formatBits(argument.value, MMAP_PROT_BITMASK, "PROT_NONE") # From /usr/include/bits/mman.h (Ubuntu Feisty, i386) ACCESS_MODE_BITMASK = ( (1, "X_OK"), (2, "W_OK"), (4, "R_OK"), ) def formatAccessMode(argument): return formatBits(argument.value, ACCESS_MODE_BITMASK, "F_OK") # From /usr/include/bits/fcntl.h (Ubuntu Feisty, i386) OPEN_FLAGS_BITMASK = [ (0o1, "O_WRONLY"), (0o2, "O_RDWR"), (0o100, "O_CREAT"), (0o200, "O_EXCL"), (0o400, "O_NOCTTY"), (0o1000, "O_TRUNC"), (0o2000, "O_APPEND"), (0o4000, "O_NONBLOCK"), (0o10000, "O_SYNC"), (0o20000, "O_ASYNC"), (0o40000, "O_DIRECT"), (0o100000, "O_LARGEFILE"), (0o200000, "O_DIRECTORY"), (0o400000, "O_NOFOLLOW"), (0o1000000, "O_NOATIME"), (0o2000000, "O_CLOEXEC"), (0o10000000, "O_PATH"), # Linux 2.6.39 (0o20200000, "O_TMPFILE"), # Linux 3.11 ] def formatOpenFlags(argument): value = argument.value flags = readBits(int(value), OPEN_FLAGS_BITMASK) # Add default access mode if neither of the others are present. if not flags or flags[0] not in ("O_WRONLY", "O_RDWR"): flags.insert(0, "O_RDONLY") text = "|".join(flags) if value: text = "%s (%s)" % (text, oct(argument.value)) return text OPEN_MODE_BITMASK = [ (0o0400, "S_IRUSR"), (0o0200, "S_IWUSR"), (0o0100, "S_IXUSR"), (0o0040, "S_IRGRP"), (0o0020, "S_IWGRP"), (0o0010, "S_IXGRP"), (0o0004, "S_IROTH"), (0o0002, "S_IWOTH"), (0o0001, "S_IXOTH"), ] def formatOpenMode(argument): value = argument.value flags = readBits(int(value), OPEN_MODE_BITMASK) text = "|".join(flags) # Overwrite text, add it depending on verbosity later if value: text = "%s" % oct(argument.value) return text CLONE_FLAGS_BITMASK = ( (0x00000100, "CLONE_VM"), (0x00000200, "CLONE_FS"), (0x00000400, "CLONE_FILES"), (0x00000800, "CLONE_SIGHAND"), (0x00002000, "CLONE_PTRACE"), (0x00004000, "CLONE_VFORK"), (0x00008000, "CLONE_PARENT"), (0x00010000, "CLONE_THREAD"), (0x00020000, "CLONE_NEWNS"), (0x00040000, "CLONE_SYSVSEM"), (0x00080000, "CLONE_SETTLS"), (0x00100000, "CLONE_PARENT_SETTID"), (0x00200000, "CLONE_CHILD_CLEARTID"), (0x00400000, "CLONE_DETACHED"), (0x00800000, "CLONE_UNTRACED"), (0x01000000, "CLONE_CHILD_SETTID"), (0x02000000, "CLONE_STOPPED"), (0x04000000, "CLONE_NEWUTS"), (0x08000000, "CLONE_NEWIPC"), ) def formatCloneFlags(argument): flags = argument.value bits = readBits(flags, CLONE_FLAGS_BITMASK) signum = flags & 0xFF if signum: bits.insert(0, signalName(signum)) if bits: bits = "%s" % ("|".join(bits)) return "<%s> (%s)" % (bits, str(flags)) else: return str(flags) AT_FDCWD = -100 def formatDirFd(argument): value = uint2int(argument.value) return "AT_FDCWD" if value == AT_FDCWD else str(value) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/syscall/posix_constants.py0000664000175000017500000000274000000000000023375 0ustar00vstinnervstinnerfrom ptrace.syscall.socketcall_constants import ( SOCKET_FAMILY, SOCKET_PROTOCOL, SETSOCKOPT_LEVEL, SETSOCKOPT_OPTNAME) SYSCALL_ARG_DICT = { "lseek": { "origin": {0: "SEEK_SET", 1: "SEEK_CUR", 2: "SEEK_END"}, }, "futex": { "op": { 0: "FUTEX_WAIT", 1: "FUTEX_WAKE", 2: "FUTEX_FD", 3: "FUTEX_REQUEUE", 4: "FUTEX_CMP_REQUEUE", 5: "FUTEX_WAKE_OP", 6: "FUTEX_LOCK_PI", 7: "FUTEX_UNLOCK_PI", 8: "FUTEX_TRYLOCK_PI", }, }, "fcntl": { "cmd": { 0: "F_DUPFD", 1: "F_GETFD", 2: "F_SETFD", 3: "F_GETFL", 4: "F_SETFL", 5: "F_GETOWN", 6: "F_SETOWN", 7: "F_GETLK", 8: "F_SETLK", 9: "F_SETLKW", }, }, "ipc": { "call": { 1: "SEMOP", 2: "SEMGET", 3: "SEMCTL", 4: "SEMTIMEDOP", 11: "MSGSND", 12: "MSGRCV", 13: "MSGGET", 14: "MSGCTL", 21: "SHMAT", 22: "SHMDT", 23: "SHMGET", 24: "SHMCTL", }, }, "socket": { "domain": SOCKET_FAMILY, "protocol": SOCKET_PROTOCOL, }, "getsockopt": { "level": SETSOCKOPT_LEVEL, "optname": SETSOCKOPT_OPTNAME, }, } SYSCALL_ARG_DICT["setsockopt"] = SYSCALL_ARG_DICT["getsockopt"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/syscall/prototypes.py0000664000175000017500000013224200000000000022370 0ustar00vstinnervstinner# From Linux kernel source code # include/linux/syscalls.h # arch/i386/kernel/syscall_table.S # arch/um/include/sysdep-i386/syscalls.h # arch/um/sys-i386/sys_call_table.S ALIASES = { "brk": ("break",), "fadvise64": ("posix_fadvise",), "fstatat64": ("fstatat",), "getcwd": ("__getcwd",), "mmap_pgoff": ("mmap", "mmap2",), "pread64": ("pread",), "prlimit64": ("prlimit",), "pselect6": ("pselect",), "pwrite64": ("pwrite",), } # Name of arguments containing a filename or a path FILENAME_ARGUMENTS = set( ("filename", "pathname", "path", "oldname", "newname", "old", "new")) SYSCALL_PROTOTYPES = { "accept": ("long", ( ("int", "sockfd"), ("struct sockaddr *", "addr"), ("int *", "addrlen"), )), "accept4": ("long", ( ("int", "sockfd"), ("struct sockaddr *", "addr"), ("int *", "addrlen"), ("int", "flags"), )), "access": ("long", ( ("const char *", "filename"), ("int", "mode"), )), "acct": ("long", ( ("const char *", "name"), )), "add_key": ("long", ( ("const char *", "_type"), ("const char *", "_description"), ("const void *", "_payload"), ("size_t", "plen"), ("key_serial_t", "destringid"), )), "adjtimex": ("long", ( ("struct timex *", "txc_p"), )), "alarm": ("long", ( ("unsigned int", "seconds"), )), "bdflush": ("long", ( ("int", "func"), ("long", "data"), )), "bind": ("long", ( ("int", "sockfd"), ("struct sockaddr *", "addr"), ("int", "addrlen"), )), "bpf": ("long", ( ("int", "cmd"), ("union bpf_attr *", "attr"), ("unsigned int", "size"), )), "brk": ("long", ( ("unsigned long", "brk"), )), "capget": ("long", ( ("cap_user_header_t", "header"), ("cap_user_data_t", "dataptr"), )), "capset": ("long", ( ("cap_user_header_t", "header"), ("const cap_user_data_t", "data"), )), "chdir": ("long", ( ("const char *", "filename"), )), "chmod": ("long", ( ("const char *", "filename"), ("umode_t", "mode"), )), "chown": ("long", ( ("const char *", "filename"), ("uid_t", "user"), ("gid_t", "group"), )), "chown16": ("long", ( ("const char *", "filename"), ("old_uid_t", "user"), ("old_gid_t", "group"), )), "chroot": ("long", ( ("const char *", "filename"), )), "clock_adjtime": ("long", ( ("clockid_t", "which_clock"), ("struct timex *", "tx"), )), "clock_getres": ("long", ( ("clockid_t", "which_clock"), ("struct timespec *", "tp"), )), "clock_gettime": ("long", ( ("clockid_t", "which_clock"), ("struct timespec *", "tp"), )), "clock_nanosleep": ("long", ( ("clockid_t", "which_clock"), ("int", "flags"), ("const struct timespec *", "rqtp"), ("struct timespec *", "rmtp"), )), "clock_settime": ("long", ( ("clockid_t", "which_clock"), ("const struct timespec *", "tp"), )), "clone": ("long", ( ("unsigned long", "flags"), ("unsigned long", "child_stack"), ("int *", "ptid"), ("int *", "ctid"), ("unsigned long", "regs"), )), "close": ("long", ( ("unsigned int", "fd"), )), "connect": ("long", ( ("int", "sockfd"), ("struct sockaddr *", "addr"), ("int", "addrlen"), )), "copy_file_range": ("long", ( ("int", "fd_in"), ("loff_t *", "off_in"), ("int", "fd_out"), ("loff_t *", "off_out"), ("size_t", "len"), ("unsigned int", "flags"), )), "creat": ("long", ( ("const char *", "pathname"), ("umode_t", "mode"), )), "delete_module": ("long", ( ("const char *", "name_user"), ("unsigned int", "flags"), )), "dup": ("long", ( ("unsigned int", "fildes"), )), "dup2": ("long", ( ("unsigned int", "oldfd"), ("unsigned int", "newfd"), )), "dup3": ("long", ( ("unsigned int", "oldfd"), ("unsigned int", "newfd"), ("int", "flags"), )), "epoll_create": ("long", ( ("int", "size"), )), "epoll_create1": ("long", ( ("int", "flags"), )), "epoll_ctl": ("long", ( ("int", "epfd"), ("int", "op"), ("int", "fd"), ("struct epoll_event *", "event"), )), "epoll_pwait": ("long", ( ("int", "epfd"), ("struct epoll_event *", "events"), ("int", "maxevents"), ("int", "timeout"), ("const sigset_t *", "sigmask"), ("size_t", "sigsetsize"), )), "epoll_wait": ("long", ( ("int", "epfd"), ("struct epoll_event *", "events"), ("int", "maxevents"), ("int", "timeout"), )), "eventfd": ("long", ( ("unsigned int", "count"), )), "eventfd2": ("long", ( ("unsigned int", "count"), ("int", "flags"), )), "execve": ("long", ( ("const char *", "filename"), ("const char *const *", "argv"), ("const char *const *", "envp"), )), "execveat": ("long", ( ("int", "dfd"), ("const char *", "filename"), ("const char *const *", "argv"), ("const char *const *", "envp"), ("int", "flags"), )), "exit": ("long", ( ("int", "error_code"), )), "exit_group": ("long", ( ("int", "error_code"), )), "faccessat": ("long", ( ("int", "dfd"), ("const char *", "filename"), ("int", "mode"), )), "fadvise64": ("long", ( ("int", "fd"), ("loff_t", "offset"), ("size_t", "len"), ("int", "advice"), )), "fadvise64_64": ("long", ( ("int", "fd"), ("loff_t", "offset"), ("loff_t", "len"), ("int", "advice"), )), "fallocate": ("long", ( ("int", "fd"), ("int", "mode"), ("loff_t", "offset"), ("loff_t", "len"), )), "fanotify_init": ("long", ( ("unsigned int", "flags"), ("unsigned int", "event_f_flags"), )), "fanotify_mark": ("long", ( ("int", "fanotify_fd"), ("unsigned int", "flags"), ("u64", "mask"), ("int", "fd"), ("const char *", "pathname"), )), "fchdir": ("long", ( ("unsigned int", "fd"), )), "fchmod": ("long", ( ("unsigned int", "fd"), ("umode_t", "mode"), )), "fchmodat": ("long", ( ("int", "dfd"), ("const char *", "filename"), ("umode_t", "mode"), )), "fchown": ("long", ( ("unsigned int", "fd"), ("uid_t", "user"), ("gid_t", "group"), )), "fchown16": ("long", ( ("unsigned int", "fd"), ("old_uid_t", "user"), ("old_gid_t", "group"), )), "fchownat": ("long", ( ("int", "dfd"), ("const char *", "filename"), ("uid_t", "user"), ("gid_t", "group"), ("int", "flag"), )), "fcntl": ("long", ( ("unsigned int", "fd"), ("unsigned int", "cmd"), ("unsigned long", "arg"), )), "fcntl64": ("long", ( ("unsigned int", "fd"), ("unsigned int", "cmd"), ("unsigned long", "arg"), )), "fdatasync": ("long", ( ("unsigned int", "fd"), )), "fgetxattr": ("long", ( ("int", "fd"), ("const char *", "name"), ("void *", "value"), ("size_t", "size"), )), "finit_module": ("long", ( ("int", "fd"), ("const char *", "uargs"), ("int", "flags"), )), "flistxattr": ("long", ( ("int", "fd"), ("char *", "list"), ("size_t", "size"), )), "flock": ("long", ( ("unsigned int", "fd"), ("unsigned int", "cmd"), )), "fork": ("long", ( )), "fremovexattr": ("long", ( ("int", "fd"), ("const char *", "name"), )), "fsetxattr": ("long", ( ("int", "fd"), ("const char *", "name"), ("const void *", "value"), ("size_t", "size"), ("int", "flags"), )), "fstat": ("long", ( ("unsigned int", "fd"), ("struct __old_kernel_stat *", "statbuf"), )), "fstat64": ("long", ( ("unsigned long", "fd"), ("struct stat64 *", "statbuf"), )), "fstatat64": ("long", ( ("int", "dfd"), ("const char *", "filename"), ("struct stat64 *", "statbuf"), ("int", "flag"), )), "fstatfs": ("long", ( ("unsigned int", "fd"), ("struct statfs *", "buf"), )), "fstatfs64": ("long", ( ("unsigned int", "fd"), ("size_t", "sz"), ("struct statfs64 *", "buf"), )), "fsync": ("long", ( ("unsigned int", "fd"), )), "ftruncate": ("long", ( ("unsigned int", "fd"), ("unsigned long", "length"), )), "ftruncate64": ("long", ( ("unsigned int", "fd"), ("loff_t", "length"), )), "futex": ("long", ( ("u32 *", "uaddr"), ("int", "op"), ("u32", "val"), ("struct timespec *", "utime"), ("u32 *", "uaddr2"), ("u32", "val3"), )), "futimesat": ("long", ( ("int", "dfd"), ("const char *", "filename"), ("struct timeval *", "utimes"), )), "get_mempolicy": ("long", ( ("int *", "policy"), ("unsigned long *", "nmask"), ("unsigned long", "maxnode"), ("unsigned long", "addr"), ("unsigned long", "flags"), )), "get_robust_list": ("long", ( ("int", "pid"), ("struct robust_list_head * *", "head_ptr"), ("size_t *", "len_ptr"), )), "getcpu": ("long", ( ("unsigned *", "cpu"), ("unsigned *", "node"), ("struct getcpu_cache *", "cache"), )), "getcwd": ("long", ( ("char *", "pathname"), ("unsigned long", "size"), )), "getdents": ("long", ( ("unsigned int", "fd"), ("struct linux_dirent *", "dirent"), ("unsigned int", "count"), )), "getdents64": ("long", ( ("unsigned int", "fd"), ("struct linux_dirent64 *", "dirent"), ("unsigned int", "count"), )), "getegid": ("long", ( )), "getegid16": ("long", ( )), "geteuid": ("long", ( )), "geteuid16": ("long", ( )), "getgid": ("long", ( )), "getgid16": ("long", ( )), "getgroups": ("long", ( ("int", "gidsetsize"), ("gid_t *", "grouplist"), )), "getgroups16": ("long", ( ("int", "gidsetsize"), ("old_gid_t *", "grouplist"), )), "gethostname": ("long", ( ("char *", "name"), ("int", "len"), )), "getitimer": ("long", ( ("int", "which"), ("struct itimerval *", "value"), )), "getpeername": ("long", ( ("int", "sockfd"), ("struct sockaddr *", "addr"), ("int *", "addrlen"), )), "getpgid": ("long", ( ("pid_t", "pid"), )), "getpgrp": ("long", ( )), "getpid": ("long", ( )), "getppid": ("long", ( )), "getpriority": ("long", ( ("int", "which"), ("int", "who"), )), "getrandom": ("long", ( ("char *", "buf"), ("size_t", "count"), ("unsigned int", "flags"), )), "getresgid": ("long", ( ("gid_t *", "rgid"), ("gid_t *", "egid"), ("gid_t *", "sgid"), )), "getresgid16": ("long", ( ("old_gid_t *", "rgid"), ("old_gid_t *", "egid"), ("old_gid_t *", "sgid"), )), "getresuid": ("long", ( ("uid_t *", "ruid"), ("uid_t *", "euid"), ("uid_t *", "suid"), )), "getresuid16": ("long", ( ("old_uid_t *", "ruid"), ("old_uid_t *", "euid"), ("old_uid_t *", "suid"), )), "getrlimit": ("long", ( ("unsigned int", "resource"), ("struct rlimit *", "rlim"), )), "getrusage": ("long", ( ("int", "who"), ("struct rusage *", "ru"), )), "getsid": ("long", ( ("pid_t", "pid"), )), "getsockname": ("long", ( ("int", "sockfd"), ("struct sockaddr *", "addr"), ("int *", "addrlen"), )), "getsockopt": ("long", ( ("int", "fd"), ("int", "level"), ("int", "optname"), ("char *", "optval"), ("int *", "optlen"), )), "gettid": ("long", ( )), "gettimeofday": ("long", ( ("struct timeval *", "tv"), ("struct timezone *", "tz"), )), "getuid": ("long", ( )), "getuid16": ("long", ( )), "getxattr": ("long", ( ("const char *", "path"), ("const char *", "name"), ("void *", "value"), ("size_t", "size"), )), "init_module": ("long", ( ("void *", "umod"), ("unsigned long", "len"), ("const char *", "uargs"), )), "inotify_add_watch": ("long", ( ("int", "fd"), ("const char *", "path"), ("u32", "mask"), )), "inotify_init": ("long", ( )), "inotify_init1": ("long", ( ("int", "flags"), )), "inotify_rm_watch": ("long", ( ("int", "fd"), ("__s32", "wd"), )), "io_cancel": ("long", ( ("aio_context_t", "ctx_id"), ("struct iocb *", "iocb"), ("struct io_event *", "result"), )), "io_destroy": ("long", ( ("aio_context_t", "ctx"), )), "io_getevents": ("long", ( ("aio_context_t", "ctx_id"), ("long", "min_nr"), ("long", "nr"), ("struct io_event *", "events"), ("struct timespec *", "timeout"), )), "io_setup": ("long", ( ("unsigned", "nr_reqs"), ("aio_context_t *", "ctx"), )), "io_submit": ("long", ( ("aio_context_t", "ctx_id"), ("long", "nr"), ("struct iocb * *", "iocbpp"), )), "ioctl": ("long", ( ("unsigned int", "fd"), ("unsigned int", "cmd"), ("unsigned long", "arg"), )), "ioperm": ("long", ( ("unsigned long", "from"), ("unsigned long", "num"), ("int", "on"), )), "ioprio_get": ("long", ( ("int", "which"), ("int", "who"), )), "ioprio_set": ("long", ( ("int", "which"), ("int", "who"), ("int", "ioprio"), )), "ipc": ("long", ( ("unsigned int", "call"), ("int", "first"), ("unsigned long", "second"), ("unsigned long", "third"), ("void *", "ptr"), ("long", "fifth"), )), "kcmp": ("long", ( ("pid_t", "pid1"), ("pid_t", "pid2"), ("int", "type"), ("unsigned long", "idx1"), ("unsigned long", "idx2"), )), "kexec_file_load": ("long", ( ("int", "kernel_fd"), ("int", "initrd_fd"), ("unsigned long", "cmdline_len"), ("const char *", "cmdline_ptr"), ("unsigned long", "flags"), )), "kexec_load": ("long", ( ("unsigned long", "entry"), ("unsigned long", "nr_segments"), ("struct kexec_segment *", "segments"), ("unsigned long", "flags"), )), "keyctl": ("long", ( ("int", "cmd"), ("unsigned long", "arg2"), ("unsigned long", "arg3"), ("unsigned long", "arg4"), ("unsigned long", "arg5"), )), "kill": ("long", ( ("int", "pid"), ("int", "sig"), )), "lchown": ("long", ( ("const char *", "filename"), ("uid_t", "user"), ("gid_t", "group"), )), "lchown16": ("long", ( ("const char *", "filename"), ("old_uid_t", "user"), ("old_gid_t", "group"), )), "lgetxattr": ("long", ( ("const char *", "path"), ("const char *", "name"), ("void *", "value"), ("size_t", "size"), )), "link": ("long", ( ("const char *", "oldname"), ("const char *", "newname"), )), "linkat": ("long", ( ("int", "olddfd"), ("const char *", "oldname"), ("int", "newdfd"), ("const char *", "newname"), ("int", "flags"), )), "listen": ("long", ( ("int", "sockfd"), ("int", "backlog"), )), "listxattr": ("long", ( ("const char *", "path"), ("char *", "list"), ("size_t", "size"), )), "llistxattr": ("long", ( ("const char *", "path"), ("char *", "list"), ("size_t", "size"), )), "llseek": ("long", ( ("unsigned int", "fd"), ("unsigned long", "offset_high"), ("unsigned long", "offset_low"), ("loff_t *", "result"), ("unsigned int", "whence"), )), "lookup_dcookie": ("long", ( ("u64", "cookie64"), ("char *", "buf"), ("size_t", "len"), )), "lremovexattr": ("long", ( ("const char *", "path"), ("const char *", "name"), )), "lseek": ("long", ( ("unsigned int", "fd"), ("off_t", "offset"), ("unsigned int", "whence"), )), "lsetxattr": ("long", ( ("const char *", "path"), ("const char *", "name"), ("const void *", "value"), ("size_t", "size"), ("int", "flags"), )), "lstat": ("long", ( ("const char *", "filename"), ("struct __old_kernel_stat *", "statbuf"), )), "lstat64": ("long", ( ("const char *", "filename"), ("struct stat64 *", "statbuf"), )), "madvise": ("long", ( ("unsigned long", "start"), ("size_t", "len"), ("int", "behavior"), )), "mbind": ("long", ( ("unsigned long", "start"), ("unsigned long", "len"), ("unsigned long", "mode"), ("const unsigned long *", "nmask"), ("unsigned long", "maxnode"), ("unsigned", "flags"), )), "membarrier": ("long", ( ("int", "cmd"), ("int", "flags"), )), "memfd_create": ("long", ( ("const char *", "uname_ptr"), ("unsigned int", "flags"), )), "migrate_pages": ("long", ( ("pid_t", "pid"), ("unsigned long", "maxnode"), ("const unsigned long *", "from"), ("const unsigned long *", "to"), )), "mincore": ("long", ( ("unsigned long", "start"), ("size_t", "len"), ("unsigned char *", "vec"), )), "mkdir": ("long", ( ("const char *", "pathname"), ("umode_t", "mode"), )), "mkdirat": ("long", ( ("int", "dfd"), ("const char *", "pathname"), ("umode_t", "mode"), )), "mknod": ("long", ( ("const char *", "filename"), ("umode_t", "mode"), ("unsigned", "dev"), )), "mknodat": ("long", ( ("int", "dfd"), ("const char *", "filename"), ("umode_t", "mode"), ("unsigned", "dev"), )), "mlock": ("long", ( ("unsigned long", "start"), ("size_t", "len"), )), "mlock2": ("long", ( ("unsigned long", "start"), ("size_t", "len"), ("int", "flags"), )), "mlockall": ("long", ( ("int", "flags"), )), "mmap_pgoff": ("long", ( ("unsigned long", "addr"), ("unsigned long", "len"), ("unsigned long", "prot"), ("unsigned long", "flags"), ("unsigned long", "fd"), ("unsigned long", "pgoff"), )), "mount": ("long", ( ("char *", "dev_name"), ("char *", "dir_name"), ("char *", "type"), ("unsigned long", "flags"), ("void *", "data"), )), "move_pages": ("long", ( ("pid_t", "pid"), ("unsigned long", "nr_pages"), ("const void * *", "pages"), ("const int *", "nodes"), ("int *", "status"), ("int", "flags"), )), "mprotect": ("long", ( ("unsigned long", "start"), ("size_t", "len"), ("unsigned long", "prot"), )), "mq_getsetattr": ("long", ( ("mqd_t", "mqdes"), ("const struct mq_attr *", "mqstat"), ("struct mq_attr *", "omqstat"), )), "mq_notify": ("long", ( ("mqd_t", "mqdes"), ("const struct sigevent *", "notification"), )), "mq_open": ("long", ( ("const char *", "name"), ("int", "oflag"), ("umode_t", "mode"), ("struct mq_attr *", "attr"), )), "mq_timedreceive": ("long", ( ("mqd_t", "mqdes"), ("char *", "msg_ptr"), ("size_t", "msg_len"), ("unsigned int *", "msg_prio"), ("const struct timespec *", "abs_timeout"), )), "mq_timedsend": ("long", ( ("mqd_t", "mqdes"), ("const char *", "msg_ptr"), ("size_t", "msg_len"), ("unsigned int", "msg_prio"), ("const struct timespec *", "abs_timeout"), )), "mq_unlink": ("long", ( ("const char *", "name"), )), "mremap": ("long", ( ("unsigned long", "addr"), ("unsigned long", "old_len"), ("unsigned long", "new_len"), ("unsigned long", "flags"), ("unsigned long", "new_addr"), )), "msgctl": ("long", ( ("int", "msqid"), ("int", "cmd"), ("struct msqid_ds *", "buf"), )), "msgget": ("long", ( ("key_t", "key"), ("int", "msgflg"), )), "msgrcv": ("long", ( ("int", "msqid"), ("struct msgbuf *", "msgp"), ("size_t", "msgsz"), ("long", "msgtyp"), ("int", "msgflg"), )), "msgsnd": ("long", ( ("int", "msqid"), ("struct msgbuf *", "msgp"), ("size_t", "msgsz"), ("int", "msgflg"), )), "msync": ("long", ( ("unsigned long", "start"), ("size_t", "len"), ("int", "flags"), )), "munlock": ("long", ( ("unsigned long", "start"), ("size_t", "len"), )), "munlockall": ("long", ( )), "munmap": ("long", ( ("unsigned long", "addr"), ("size_t", "len"), )), "name_to_handle_at": ("long", ( ("int", "dirfd"), ("const char *", "name"), ("struct file_handle *", "handle"), ("int *", "mnt_id"), ("int", "flag"), )), "nanosleep": ("long", ( ("struct timespec *", "rqtp"), ("struct timespec *", "rmtp"), )), "newfstat": ("long", ( ("unsigned int", "fd"), ("struct stat *", "statbuf"), )), "newfstatat": ("long", ( ("int", "dfd"), ("const char *", "filename"), ("struct stat *", "statbuf"), ("int", "flag"), )), "newlstat": ("long", ( ("const char *", "filename"), ("struct stat *", "statbuf"), )), "newstat": ("long", ( ("const char *", "filename"), ("struct stat *", "statbuf"), )), "newuname": ("long", ( ("struct new_utsname *", "name"), )), "ni_syscall": ("long", ( )), "nice": ("long", ( ("int", "increment"), )), "old_getrlimit": ("long", ( ("unsigned int", "resource"), ("struct rlimit *", "rlim"), )), "old_mmap": ("long", ( ("struct mmap_arg_struct *", "arg"), )), "old_readdir": ("long", ( ("unsigned int", "fd"), ("struct old_linux_dirent *", "dirp"), ("unsigned int", "count"), )), "old_select": ("long", ( ("struct sel_arg_struct *", "arg"), )), "oldumount": ("long", ( ("char *", "name"), )), "olduname": ("long", ( ("struct oldold_utsname *", "buf"), )), "open": ("long", ( ("const char *", "filename"), ("int", "flags"), ("umode_t", "mode"), )), "open_by_handle_at": ("long", ( ("int", "mount_fd"), ("struct file_handle *", "handle"), ("int", "flags"), )), "openat": ("long", ( ("int", "dirfd"), ("const char *", "filename"), ("int", "flags"), ("umode_t", "mode"), )), "pause": ("long", ( )), "pciconfig_iobase": ("long", ( ("long", "which"), ("unsigned long", "bus"), ("unsigned long", "devfn"), )), "pciconfig_read": ("long", ( ("unsigned long", "bus"), ("unsigned long", "dfn"), ("unsigned long", "off"), ("unsigned long", "len"), ("void *", "buf"), )), "pciconfig_write": ("long", ( ("unsigned long", "bus"), ("unsigned long", "dfn"), ("unsigned long", "off"), ("unsigned long", "len"), ("void *", "buf"), )), "perf_event_open": ("long", ( ("struct perf_event_attr *", "attr_uptr"), ("pid_t", "pid"), ("int", "cpu"), ("int", "group_fd"), ("unsigned long", "flags"), )), "personality": ("long", ( ("unsigned int", "personality"), )), "pipe": ("long", ( ("int *", "fildes"), )), "pipe2": ("long", ( ("int *", "fildes"), ("int", "flags"), )), "pivot_root": ("long", ( ("const char *", "new_root"), ("const char *", "put_old"), )), "poll": ("long", ( ("struct pollfd *", "ufds"), ("unsigned int", "nfds"), ("int", "timeout"), )), "ppoll": ("long", ( ("struct pollfd *", "fds"), ("unsigned int", "nfds"), ("struct timespec *", "tmo_p"), ("const sigset_t *", "sigmask"), ("size_t", ""), )), "prctl": ("long", ( ("int", "option"), ("unsigned long", "arg2"), ("unsigned long", "arg3"), ("unsigned long", "arg4"), ("unsigned long", "arg5"), )), "pread64": ("long", ( ("unsigned int", "fd"), ("char *", "buf"), ("size_t", "count"), ("loff_t", "pos"), )), "preadv": ("long", ( ("unsigned long", "fd"), ("const struct iovec *", "vec"), ("unsigned long", "vlen"), ("unsigned long", "pos_l"), ("unsigned long", "pos_h"), )), "prlimit64": ("long", ( ("pid_t", "pid"), ("unsigned int", "resource"), ("const struct rlimit64 *", "new_rlim"), ("struct rlimit64 *", "old_rlim"), )), "process_vm_readv": ("long", ( ("pid_t", "pid"), ("const struct iovec *", "lvec"), ("unsigned long", "liovcnt"), ("const struct iovec *", "rvec"), ("unsigned long", "riovcnt"), ("unsigned long", "flags"), )), "process_vm_writev": ("long", ( ("pid_t", "pid"), ("const struct iovec *", "lvec"), ("unsigned long", "liovcnt"), ("const struct iovec *", "rvec"), ("unsigned long", "riovcnt"), ("unsigned long", "flags"), )), "pselect6": ("long", ( ("int", "nfds"), ("fd_set *", "readfds"), ("fd_set *", "writefds"), ("fd_set *", "exceptfds"), ("struct timespec *", "timeout"), ("void *", "sigmask"), )), "ptrace": ("long", ( ("long", "request"), ("long", "pid"), ("unsigned long", "addr"), ("unsigned long", "data"), )), "pwrite64": ("long", ( ("unsigned int", "fd"), ("const char *", "buf"), ("size_t", "count"), ("loff_t", "pos"), )), "pwritev": ("long", ( ("unsigned long", "fd"), ("const struct iovec *", "vec"), ("unsigned long", "vlen"), ("unsigned long", "pos_l"), ("unsigned long", "pos_h"), )), "quotactl": ("long", ( ("unsigned int", "cmd"), ("const char *", "special"), ("qid_t", "id"), ("void *", "addr"), )), "read": ("long", ( ("unsigned int", "fd"), ("char *", "buf"), ("size_t", "count"), )), "readahead": ("long", ( ("int", "fd"), ("loff_t", "offset"), ("size_t", "count"), )), "readlink": ("long", ( ("const char *", "path"), ("char *", "buf"), ("int", "bufsiz"), )), "readlinkat": ("long", ( ("int", "dfd"), ("const char *", "path"), ("char *", "buf"), ("int", "bufsiz"), )), "readv": ("long", ( ("unsigned long", "fd"), ("const struct iovec *", "vec"), ("unsigned long", "vlen"), )), "reboot": ("long", ( ("int", "magic1"), ("int", "magic2"), ("unsigned int", "cmd"), ("void *", "arg"), )), "recv": ("long", ( ("int", "sockfd"), ("void *", "buf"), ("size_t", "len"), ("unsigned", "flags"), )), "recvfrom": ("long", ( ("int", "sockfd"), ("void *", "buf"), ("size_t", "len"), ("unsigned", "flags"), ("struct sockaddr *", "src_addr"), ("int *", "addrlen"), )), "recvmmsg": ("long", ( ("int", "fd"), ("struct mmsghdr *", "msg"), ("unsigned int", "vlen"), ("unsigned", "flags"), ("struct timespec *", "timeout"), )), "recvmsg": ("long", ( ("int", "fd"), ("struct user_msghdr *", "msg"), ("unsigned", "flags"), )), "remap_file_pages": ("long", ( ("unsigned long", "start"), ("unsigned long", "size"), ("unsigned long", "prot"), ("unsigned long", "pgoff"), ("unsigned long", "flags"), )), "removexattr": ("long", ( ("const char *", "path"), ("const char *", "name"), )), "rename": ("long", ( ("const char *", "oldname"), ("const char *", "newname"), )), "renameat": ("long", ( ("int", "olddfd"), ("const char *", "oldname"), ("int", "newdfd"), ("const char *", "newname"), )), "renameat2": ("long", ( ("int", "olddfd"), ("const char *", "oldname"), ("int", "newdfd"), ("const char *", "newname"), ("unsigned int", "flags"), )), "request_key": ("long", ( ("const char *", "_type"), ("const char *", "_description"), ("const char *", "_callout_info"), ("key_serial_t", "destringid"), )), "restart_syscall": ("long", ( )), "rmdir": ("long", ( ("const char *", "pathname"), )), "rt_sigaction": ("long", ( ("int", "signum"), ("const struct sigaction *", "act"), ("struct sigaction *", "oldact"), ("size_t", ""), )), "rt_sigpending": ("long", ( ("sigset_t *", "set"), ("size_t", "sigsetsize"), )), "rt_sigprocmask": ("long", ( ("int", "how"), ("sigset_t *", "set"), ("sigset_t *", "oset"), ("size_t", "sigsetsize"), )), "rt_sigqueueinfo": ("long", ( ("int", "pid"), ("int", "sig"), ("siginfo_t *", "uinfo"), )), "rt_sigsuspend": ("long", ( ("sigset_t *", "unewset"), ("size_t", "sigsetsize"), )), "rt_sigtimedwait": ("long", ( ("const sigset_t *", "uthese"), ("siginfo_t *", "uinfo"), ("const struct timespec *", "uts"), ("size_t", "sigsetsize"), )), "rt_tgsigqueueinfo": ("long", ( ("pid_t", "tgid"), ("pid_t", "pid"), ("int", "sig"), ("siginfo_t *", "uinfo"), )), "sched_get_priority_max": ("long", ( ("int", "policy"), )), "sched_get_priority_min": ("long", ( ("int", "policy"), )), "sched_getaffinity": ("long", ( ("pid_t", "pid"), ("unsigned int", "len"), ("unsigned long *", "user_mask_ptr"), )), "sched_getattr": ("long", ( ("pid_t", "pid"), ("struct sched_attr *", "attr"), ("unsigned int", "size"), ("unsigned int", "flags"), )), "sched_getparam": ("long", ( ("pid_t", "pid"), ("struct sched_param *", "param"), )), "sched_getscheduler": ("long", ( ("pid_t", "pid"), )), "sched_rr_get_interval": ("long", ( ("pid_t", "pid"), ("struct timespec *", "interval"), )), "sched_setaffinity": ("long", ( ("pid_t", "pid"), ("unsigned int", "len"), ("unsigned long *", "user_mask_ptr"), )), "sched_setattr": ("long", ( ("pid_t", "pid"), ("struct sched_attr *", "attr"), ("unsigned int", "flags"), )), "sched_setparam": ("long", ( ("pid_t", "pid"), ("struct sched_param *", "param"), )), "sched_setscheduler": ("long", ( ("pid_t", "pid"), ("int", "policy"), ("struct sched_param *", "param"), )), "sched_yield": ("long", ( )), "seccomp": ("long", ( ("unsigned int", "op"), ("unsigned int", "flags"), ("const char *", "uargs"), )), "select": ("long", ( ("int", "nfds"), ("fd_set *", "readfds"), ("fd_set *", "writefds"), ("fd_set *", "errorfds"), ("struct timeval *", "timeout"), )), "semctl": ("long", ( ("int", "semid"), ("int", "semnum"), ("int", "cmd"), ("unsigned long", "arg"), )), "semget": ("long", ( ("key_t", "key"), ("int", "nsems"), ("int", "semflg"), )), "semop": ("long", ( ("int", "semid"), ("struct sembuf *", "sops"), ("unsigned", "nsops"), )), "semtimedop": ("long", ( ("int", "semid"), ("struct sembuf *", "sops"), ("unsigned", "nsops"), ("const struct timespec *", "timeout"), )), "send": ("long", ( ("int", "sockfd"), ("void *", "buf"), ("size_t", "len"), ("unsigned", "flags"), )), "sendfile": ("long", ( ("int", "out_fd"), ("int", "in_fd"), ("off_t *", "offset"), ("size_t", "count"), )), "sendfile64": ("long", ( ("int", "out_fd"), ("int", "in_fd"), ("loff_t *", "offset"), ("size_t", "count"), )), "sendmmsg": ("long", ( ("int", "fd"), ("struct mmsghdr *", "msg"), ("unsigned int", "vlen"), ("unsigned", "flags"), )), "sendmsg": ("long", ( ("int", "fd"), ("struct user_msghdr *", "msg"), ("unsigned", "flags"), )), "sendto": ("long", ( ("int", "sockfd"), ("void *", "buf"), ("size_t", "len"), ("unsigned", "flags"), ("struct sockaddr *", "dest_addr"), ("int", "addrlen"), )), "set_mempolicy": ("long", ( ("int", "mode"), ("const unsigned long *", "nmask"), ("unsigned long", "maxnode"), )), "set_robust_list": ("long", ( ("struct robust_list_head *", "head"), ("size_t", "len"), )), "set_tid_address": ("long", ( ("int *", "tidptr"), )), "setdomainname": ("long", ( ("char *", "name"), ("int", "len"), )), "setfsgid": ("long", ( ("gid_t", "gid"), )), "setfsgid16": ("long", ( ("old_gid_t", "gid"), )), "setfsuid": ("long", ( ("uid_t", "uid"), )), "setfsuid16": ("long", ( ("old_uid_t", "uid"), )), "setgid": ("long", ( ("gid_t", "gid"), )), "setgid16": ("long", ( ("old_gid_t", "gid"), )), "setgroups": ("long", ( ("int", "gidsetsize"), ("gid_t *", "grouplist"), )), "setgroups16": ("long", ( ("int", "gidsetsize"), ("old_gid_t *", "grouplist"), )), "sethostname": ("long", ( ("char *", "name"), ("int", "len"), )), "setitimer": ("long", ( ("int", "which"), ("struct itimerval *", "value"), ("struct itimerval *", "ovalue"), )), "setns": ("long", ( ("int", "fd"), ("int", "nstype"), )), "setpgid": ("long", ( ("pid_t", "pid"), ("pid_t", "pgid"), )), "setpriority": ("long", ( ("int", "which"), ("int", "who"), ("int", "niceval"), )), "setregid": ("long", ( ("gid_t", "rgid"), ("gid_t", "egid"), )), "setregid16": ("long", ( ("old_gid_t", "rgid"), ("old_gid_t", "egid"), )), "setresgid": ("long", ( ("gid_t", "rgid"), ("gid_t", "egid"), ("gid_t", "sgid"), )), "setresgid16": ("long", ( ("old_gid_t", "rgid"), ("old_gid_t", "egid"), ("old_gid_t", "sgid"), )), "setresuid": ("long", ( ("uid_t", "ruid"), ("uid_t", "euid"), ("uid_t", "suid"), )), "setresuid16": ("long", ( ("old_uid_t", "ruid"), ("old_uid_t", "euid"), ("old_uid_t", "suid"), )), "setreuid": ("long", ( ("uid_t", "ruid"), ("uid_t", "euid"), )), "setreuid16": ("long", ( ("old_uid_t", "ruid"), ("old_uid_t", "euid"), )), "setrlimit": ("long", ( ("unsigned int", "resource"), ("struct rlimit *", "rlim"), )), "setsid": ("long", ( )), "setsockopt": ("long", ( ("int", "fd"), ("int", "level"), ("int", "optname"), ("char *", "optval"), ("int", "optlen"), )), "settimeofday": ("long", ( ("struct timeval *", "tv"), ("struct timezone *", "tz"), )), "setuid": ("long", ( ("uid_t", "uid"), )), "setuid16": ("long", ( ("old_uid_t", "uid"), )), "setxattr": ("long", ( ("const char *", "path"), ("const char *", "name"), ("const void *", "value"), ("size_t", "size"), ("int", "flags"), )), "sgetmask": ("long", ( )), "shmat": ("long", ( ("int", "shmid"), ("char *", "shmaddr"), ("int", "shmflg"), )), "shmctl": ("long", ( ("int", "shmid"), ("int", "cmd"), ("struct shmid_ds *", "buf"), )), "shmdt": ("long", ( ("char *", "shmaddr"), )), "shmget": ("long", ( ("key_t", "key"), ("size_t", "size"), ("int", "flag"), )), "shutdown": ("long", ( ("int", "sockfd"), ("int", "how"), )), "sigaction": ("long", ( ("int", "signum"), ("const struct old_sigaction *", "act"), ("struct old_sigaction *", "oldact"), )), "sigaltstack": ("long", ( ("const struct sigaltstack *", "uss"), ("struct sigaltstack *", "uoss"), )), "signal": ("long", ( ("int", "sig"), ("__sighandler_t", "handler"), )), "signalfd": ("long", ( ("int", "ufd"), ("sigset_t *", "user_mask"), ("size_t", "sizemask"), )), "signalfd4": ("long", ( ("int", "ufd"), ("sigset_t *", "user_mask"), ("size_t", "sizemask"), ("int", "flags"), )), "sigpending": ("long", ( ("old_sigset_t *", "set"), )), "sigprocmask": ("long", ( ("int", "how"), ("old_sigset_t *", "set"), ("old_sigset_t *", "oset"), )), "sigsuspend": ("long", ( ("int", "unused1"), ("int", "unused2"), ("old_sigset_t", "mask"), )), "socket": ("long", ( ("int", "domain"), ("int", "type"), ("int", "protocol"), )), "socketcall": ("long", ( ("int", "call"), ("unsigned long *", "args"), )), "socketpair": ("long", ( ("int", "domain"), ("int", "type"), ("int", "protocol"), ("int *", "sv"), )), "splice": ("long", ( ("int", "fd_in"), ("loff_t *", "off_in"), ("int", "fd_out"), ("loff_t *", "off_out"), ("size_t", "len"), ("unsigned int", "flags"), )), "spu_create": ("long", ( ("const char *", "name"), ("unsigned int", "flags"), ("umode_t", "mode"), ("int", "fd"), )), "spu_run": ("long", ( ("int", "fd"), ("__u32 *", "unpc"), ("__u32 *", "ustatus"), )), "ssetmask": ("long", ( ("int", "newmask"), )), "stat": ("long", ( ("const char *", "filename"), ("struct __old_kernel_stat *", "statbuf"), )), "stat64": ("long", ( ("const char *", "filename"), ("struct stat64 *", "statbuf"), )), "statfs": ("long", ( ("const char *", "path"), ("struct statfs *", "buf"), )), "statfs64": ("long", ( ("const char *", "path"), ("size_t", "sz"), ("struct statfs64 *", "buf"), )), "statx": ("long", ( ("int", "dirfd"), ("const char *", "pathname"), ("int", "flags"), ("unsigned int", "mask"), ("struct statx *", "statxbuf"), )), "stime": ("long", ( ("time_t *", "tptr"), )), "swapoff": ("long", ( ("const char *", "specialfile"), )), "swapon": ("long", ( ("const char *", "specialfile"), ("int", "swap_flags"), )), "symlink": ("long", ( ("const char *", "old"), ("const char *", "new"), )), "symlinkat": ("long", ( ("const char *", "oldname"), ("int", "newdfd"), ("const char *", "newname"), )), "sync": ("long", ( )), "sync_file_range": ("long", ( ("int", "fd"), ("loff_t", "offset"), ("loff_t", "nbytes"), ("unsigned int", "flags"), )), "sync_file_range2": ("long", ( ("int", "fd"), ("unsigned int", "flags"), ("loff_t", "offset"), ("loff_t", "nbytes"), )), "syncfs": ("long", ( ("int", "fd"), )), "sysctl": ("long", ( ("struct __sysctl_args *", "args"), )), "sysfs": ("long", ( ("int", "option"), ("unsigned long", "arg1"), ("unsigned long", "arg2"), )), "sysinfo": ("long", ( ("struct sysinfo *", "info"), )), "syslog": ("long", ( ("int", "type"), ("char *", "buf"), ("int", "len"), )), "tee": ("long", ( ("int", "fdin"), ("int", "fdout"), ("size_t", "len"), ("unsigned int", "flags"), )), "tgkill": ("long", ( ("int", "tgid"), ("int", "pid"), ("int", "sig"), )), "time": ("long", ( ("time_t *", "tloc"), )), "timer_create": ("long", ( ("clockid_t", "which_clock"), ("struct sigevent *", "timer_event_spec"), ("timer_t *", "created_timer_id"), )), "timer_delete": ("long", ( ("timer_t", "timer_id"), )), "timer_getoverrun": ("long", ( ("timer_t", "timer_id"), )), "timer_gettime": ("long", ( ("timer_t", "timer_id"), ("struct itimerspec *", "setting"), )), "timer_settime": ("long", ( ("timer_t", "timer_id"), ("int", "flags"), ("const struct itimerspec *", "new_setting"), ("struct itimerspec *", "old_setting"), )), "timerfd_create": ("long", ( ("int", "clockid"), ("int", "flags"), )), "timerfd_gettime": ("long", ( ("int", "ufd"), ("struct itimerspec *", "otmr"), )), "timerfd_settime": ("long", ( ("int", "ufd"), ("int", "flags"), ("const struct itimerspec *", "utmr"), ("struct itimerspec *", "otmr"), )), "times": ("long", ( ("struct tms *", "tbuf"), )), "tkill": ("long", ( ("int", "pid"), ("int", "sig"), )), "truncate": ("long", ( ("const char *", "path"), ("long", "length"), )), "truncate64": ("long", ( ("const char *", "path"), ("loff_t", "length"), )), "umask": ("long", ( ("int", "mask"), )), "umount": ("long", ( ("char *", "name"), ("int", "flags"), )), "uname": ("long", ( ("struct old_utsname *", "buf"), )), "unlink": ("long", ( ("const char *", "pathname"), )), "unlinkat": ("long", ( ("int", "dfd"), ("const char *", "pathname"), ("int", "flag"), )), "unshare": ("long", ( ("unsigned long", "unshare_flags"), )), "uselib": ("long", ( ("const char *", "library"), )), "userfaultfd": ("long", ( ("int", "flags"), )), "ustat": ("long", ( ("unsigned", "dev"), ("struct ustat *", "ubuf"), )), "utime": ("long", ( ("char *", "filename"), ("struct utimbuf *", "times"), )), "utimensat": ("long", ( ("int", "dfd"), ("const char *", "filename"), ("struct timespec *", "utimes"), ("int", "flags"), )), "utimes": ("long", ( ("char *", "filename"), ("struct timeval *", "utimes"), )), "vfork": ("long", ( )), "vhangup": ("long", ( )), "vmsplice": ("long", ( ("int", "fd"), ("const struct iovec *", "iov"), ("unsigned long", "nr_segs"), ("unsigned int", "flags"), )), "wait4": ("long", ( ("pid_t", "pid"), ("int *", "stat_addr"), ("int", "options"), ("struct rusage *", "ru"), )), "waitid": ("long", ( ("int", "which"), ("pid_t", "pid"), ("struct siginfo *", "infop"), ("int", "options"), ("struct rusage *", "ru"), )), "waitpid": ("long", ( ("pid_t", "pid"), ("int *", "stat_addr"), ("int", "options"), )), "write": ("long", ( ("unsigned int", "fd"), ("const char *", "buf"), ("size_t", "count"), )), "writev": ("long", ( ("unsigned long", "fd"), ("const struct iovec *", "vec"), ("unsigned long", "vlen"), )), } for orig, copies in ALIASES.items(): orig = SYSCALL_PROTOTYPES[orig] for copy in copies: SYSCALL_PROTOTYPES[copy] = orig ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/syscall/ptrace_syscall.py0000664000175000017500000001220500000000000023144 0ustar00vstinnervstinnerfrom os import strerror from errno import errorcode from ptrace.cpu_info import CPU_X86_64, CPU_POWERPC, CPU_I386, CPU_ARM32, CPU_AARCH64 from ptrace.ctypes_tools import ulong2long, formatAddress, formatWordHex from ptrace.func_call import FunctionCall from ptrace.syscall import SYSCALL_NAMES, SYSCALL_PROTOTYPES, SyscallArgument from ptrace.syscall.socketcall import setupSocketCall from ptrace.os_tools import RUNNING_LINUX, RUNNING_BSD from ptrace.cpu_info import CPU_WORD_SIZE from ptrace.binding.cpu import CPU_INSTR_POINTER if CPU_POWERPC: SYSCALL_REGISTER = "gpr0" elif CPU_ARM32: SYSCALL_REGISTER = "r7" elif CPU_AARCH64: SYSCALL_REGISTER = "r8" elif RUNNING_LINUX: if CPU_X86_64: SYSCALL_REGISTER = "orig_rax" else: SYSCALL_REGISTER = "orig_eax" else: if CPU_X86_64: SYSCALL_REGISTER = "rax" else: SYSCALL_REGISTER = "eax" if CPU_ARM32: RETURN_VALUE_REGISTER = "r0" elif CPU_AARCH64: RETURN_VALUE_REGISTER = "r0" elif CPU_I386: RETURN_VALUE_REGISTER = "eax" elif CPU_X86_64: RETURN_VALUE_REGISTER = "rax" elif CPU_POWERPC: RETURN_VALUE_REGISTER = "result" else: raise NotImplementedError("Unsupported CPU architecture") PREFORMAT_ARGUMENTS = { "select": (1, 2, 3), "execve": (0, 1, 2), "clone": (0, 1), } class PtraceSyscall(FunctionCall): def __init__(self, process, options, regs=None): FunctionCall.__init__(self, "syscall", options, SyscallArgument) self.process = process self.restype = "long" self.result = None self.result_text = None self.instr_pointer = None if not regs: regs = self.process.getregs() self.readSyscall(regs) def enter(self, regs=None): if not regs: regs = self.process.getregs() argument_values = self.readArgumentValues(regs) self.readArguments(argument_values) if self.name == "socketcall" and self.options.replace_socketcall: setupSocketCall(self, self.process, self[0], self[1].value) # Some arguments are lost after the syscall, so format them now if self.name in PREFORMAT_ARGUMENTS: for index in PREFORMAT_ARGUMENTS[self.name]: argument = self.arguments[index] argument.format() if self.options.instr_pointer: self.instr_pointer = getattr(regs, CPU_INSTR_POINTER) def readSyscall(self, regs): # Read syscall number self.syscall = getattr(regs, SYSCALL_REGISTER) # Get syscall variables self.name = SYSCALL_NAMES.get( self.syscall, "syscall<%s>" % self.syscall) def readArgumentValues(self, regs): if CPU_X86_64: return (regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9) if CPU_ARM32: return (regs.r0, regs.r1, regs.r2, regs.r3, regs.r4, regs.r5, regs.r6) if CPU_AARCH64: return (regs.r0, regs.r1, regs.r2, regs.r3, regs.r4, regs.r5, regs.r6, regs.r7) if RUNNING_BSD: sp = self.process.getStackPointer() return [self.process.readWord(sp + index * CPU_WORD_SIZE) for index in range(1, 6 + 1)] if CPU_I386: return (regs.ebx, regs.ecx, regs.edx, regs.esi, regs.edi, regs.ebp) if CPU_POWERPC: return (regs.gpr3, regs.gpr4, regs.gpr5, regs.gpr6, regs.gpr7, regs.gpr8) raise NotImplementedError() def readArguments(self, argument_values): if self.name in SYSCALL_PROTOTYPES: self.restype, formats = SYSCALL_PROTOTYPES[self.name] for value, format in zip(argument_values, formats): argtype, argname = format self.addArgument(value=value, name=argname, type=argtype) else: for value in argument_values: self.addArgument(value=value) def exit(self): if self.name in PREFORMAT_ARGUMENTS: preformat = set(PREFORMAT_ARGUMENTS[self.name]) else: preformat = set() # Data pointed by arguments may have changed during the syscall # e.g. uname() syscall for index, argument in enumerate(self.arguments): if index in preformat: # Don't lose preformatted arguments continue if argument.type and not argument.type.endswith("*"): continue argument.text = None self.result = self.process.getreg(RETURN_VALUE_REGISTER) if self.restype.endswith("*"): text = formatAddress(self.result) else: uresult = self.result self.result = ulong2long(self.result) if self.result < 0 and (-self.result) in errorcode: errcode = -self.result text = "%s %s (%s)" % ( self.result, errorcode[errcode], strerror(errcode)) elif not(0 <= self.result <= 9): text = "%s (%s)" % (self.result, formatWordHex(uresult)) else: text = str(self.result) self.result_text = text return text def __str__(self): return "" % self.name ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/syscall/socketcall.py0000664000175000017500000000450000000000000022257 0ustar00vstinnervstinnerfrom ptrace.cpu_info import CPU_WORD_SIZE from ptrace.ctypes_tools import ntoh_ushort, ntoh_uint # noqa from ptrace.syscall import SYSCALL_PROTOTYPES from ptrace.syscall.socketcall_constants import SOCKETCALL, SOCKET_FAMILY # noqa from ptrace.syscall.socketcall_struct import sockaddr, sockaddr_in, sockaddr_in6, sockaddr_un from ctypes import c_int from ptrace.os_tools import RUNNING_LINUX from socket import AF_INET, AF_INET6, inet_ntoa # noqa if RUNNING_LINUX: from socket import AF_NETLINK from ptrace.syscall.socketcall_struct import sockaddr_nl AF_FILE = 1 def formatOptVal(argument): function = argument.function optlen = function["optlen"].value if optlen == 4: addr = argument.value text = function.process.readStruct(addr, c_int) return argument.formatPointer("<%s>" % text, addr) else: return None def formatSockaddr(argument, argtype): address = argument.value value = argument.function.process.readStruct(address, sockaddr) family = value.family if family == AF_INET: return argument.readStruct(address, sockaddr_in) if family == AF_INET6: return argument.readStruct(address, sockaddr_in6) if family == AF_FILE: return argument.readStruct(address, sockaddr_un) if RUNNING_LINUX: if family == AF_NETLINK: return argument.readStruct(address, sockaddr_nl) family = SOCKET_FAMILY.get(family, family) return argument.formatPointer("" % family, address) def setupSocketCall(function, process, socketcall, address): # Reset function call function.clearArguments() # function.argument_class = SocketCallArgument # Setup new function call function.process = process function.name = socketcall.getText() # Create arguments function.restype, formats = SYSCALL_PROTOTYPES[function.name] for argtype, argname in formats: value = process.readWord(address) function.addArgument(value, argname, argtype) address += CPU_WORD_SIZE def formatSockaddrInStruct(argument, name, value): if name == "sin_port": return ntoh_ushort(value) return None def formatSockaddrIn6Struct(argument, name, value): if name == "sin6_port": return ntoh_ushort(value) # if name == "sin6_addr": # FIXME: ... return None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/syscall/socketcall_constants.py0000664000175000017500000000325000000000000024354 0ustar00vstinnervstinnerimport socket SOCKETCALL = { 1: "socket", 2: "bind", 3: "connect", 4: "listen", 5: "accept", 6: "getsockname", 7: "getpeername", 8: "socketpair", 9: "send", 10: "recv", 11: "sendto", 12: "recvfrom", 13: "shutdown", 14: "setsockopt", 15: "getsockopt", 16: "sendmsg", 17: "recvmsg", } SOCKET_FAMILY = { 0: "AF_UNSPEC", 1: "AF_FILE", 2: "AF_INET", 3: "AF_AX25", 4: "AF_IPX", 5: "AF_APPLETALK", 6: "AF_NETROM", 7: "AF_BRIDGE", 8: "AF_ATMPVC", 9: "AF_X25", 10: "AF_INET6", 11: "AF_ROSE", 12: "AF_DECnet", 13: "AF_NETBEUI", 14: "AF_SECURITY", 15: "AF_KEY", 16: "AF_NETLINK", 17: "AF_PACKET", 18: "AF_ASH", 19: "AF_ECONET", 20: "AF_ATMSVC", 22: "AF_SNA", 23: "AF_IRDA", 24: "AF_PPPOX", 25: "AF_WANPIPE", 31: "AF_BLUETOOTH", } SOCKET_TYPE = { 1: "SOCK_STREAM", 2: "SOCK_DGRAM", 3: "SOCK_RAW", 4: "SOCK_RDM", 5: "SOCK_SEQPACKET", 10: "SOCK_PACKET", } def formatSocketType(argument): value = argument.value text = [] if hasattr(socket, 'SOCK_CLOEXEC'): cloexec = value & socket.SOCK_CLOEXEC value &= ~socket.SOCK_CLOEXEC else: cloexec = False text = SOCKET_TYPE.get(value, str(value)) if cloexec: text += '|SOCK_CLOEXEC' return text SOCKET_PROTOCOL = { 1: "IPPROTO_ICMP", 58: "IPPROTO_ICMPV6", } SETSOCKOPT_LEVEL = { 0: "SOL_IP", 1: "SOL_SOCKET", } SETSOCKOPT_OPTNAME = { # level 0 (SOL_IP) 1: "IP_TOS", # level 1 (SOL_SOCKET) 2: "SO_REUSEADDR", 9: "SO_KEEPALIVE", 20: "SO_RCVTIMEO", 21: "SO_SNDTIMEO", } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/syscall/socketcall_struct.py0000664000175000017500000000472200000000000023671 0ustar00vstinnervstinnerfrom ctypes import Structure, Union, c_char, c_ushort, c_ubyte, c_uint16, c_uint32 from ptrace.os_tools import RUNNING_BSD, RUNNING_LINUX from socket import inet_ntoa from struct import pack from ptrace.ctypes_tools import ntoh_uint, ntoh_ushort def ip_int2str(ip): """ Convert an IP address (as an integer) to a string. >>> ip_int2str(0x7f000001) '127.0.0.1' """ ip_bytes = pack("!I", ip) return inet_ntoa(ip_bytes) if RUNNING_BSD: sa_family_t = c_ubyte else: sa_family_t = c_ushort class sockaddr(Structure): if RUNNING_BSD: _fields_ = ( ("len", c_ubyte), ("family", sa_family_t), ) else: _fields_ = ( ("family", sa_family_t), ) class in_addr(Structure): _fields_ = ( ("s_addr", c_uint32), ) def __repr__(self): ip = ntoh_uint(self.s_addr) return ip_int2str(ip) class in6_addr(Union): _fields_ = ( ("addr8", c_ubyte * 16), ("addr16", c_uint16 * 8), ("addr32", c_uint32 * 4), ) def __repr__(self): text = ':'.join(("%04x" % ntoh_ushort(part)) for part in self.addr16) return "" % text # INET socket class sockaddr_in(Structure): if RUNNING_BSD: _fields_ = ( ("sin_len", c_ubyte), ("sin_family", sa_family_t), ("sin_port", c_uint16), ("sin_addr", in_addr), ) else: _fields_ = ( ("sin_family", sa_family_t), ("sin_port", c_uint16), ("sin_addr", in_addr), ) class sockaddr_in6(Structure): if RUNNING_BSD: _fields_ = ( ("sin6_len", c_ubyte), ("sin6_family", sa_family_t), ("sin6_port", c_uint16), ("sin6_flowinfo", c_uint32), ("sin6_addr", in6_addr), ) else: _fields_ = ( ("sin6_family", sa_family_t), ("sin6_port", c_uint16), ("sin6_flowinfo", c_uint32), ("sin6_addr", in6_addr), ("sin6_scope_ip", c_uint32), ) # UNIX socket class sockaddr_un(Structure): _fields_ = ( ("sun_family", sa_family_t), ("sun_path", c_char * 108), ) # Netlink socket if RUNNING_LINUX: class sockaddr_nl(Structure): _fields_ = ( ("nl_family", sa_family_t), ("nl_pad", c_ushort), ("nl_pid", c_uint32), ("nl_groups", c_uint32), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065767.0 python-ptrace-0.9.8/ptrace/syscall/syscall_argument.py0000664000175000017500000002112500000000000023511 0ustar00vstinnervstinnerfrom ptrace.cpu_info import CPU_WORD_SIZE from ptrace.ctypes_tools import uint2int, formatWordHex, formatAddress from ptrace.signames import signalName from ctypes import c_int from ptrace.error import PTRACE_ERRORS, writeError from logging import getLogger, INFO from ptrace.func_arg import FunctionArgument from ptrace.syscall.posix_arg import ( formatMmapProt, formatAccessMode, formatOpenFlags, formatCloneFlags, formatDirFd, formatOpenMode) from ptrace.func_call import FunctionCall from ptrace.syscall.socketcall import (setupSocketCall, formatOptVal, formatSockaddr, formatSockaddrInStruct, formatSockaddrIn6Struct) from ptrace.syscall.socketcall_constants import SOCKETCALL import os import re from ptrace.os_tools import RUNNING_LINUX, RUNNING_FREEBSD from ptrace.syscall import FILENAME_ARGUMENTS from ptrace.syscall.socketcall_constants import formatSocketType if RUNNING_LINUX: from ptrace.syscall.linux_struct import ( timeval, timespec, pollfd, rlimit, new_utsname, user_desc) from ptrace.syscall.linux_constants import SYSCALL_ARG_DICT, FD_SETSIZE elif RUNNING_FREEBSD: from ptrace.syscall.freebsd_constants import SYSCALL_ARG_DICT else: SYSCALL_ARG_DICT = {} KNOWN_STRUCTS = [] if RUNNING_LINUX: KNOWN_STRUCTS.extend( (timeval, timespec, pollfd, rlimit, new_utsname, user_desc)) KNOWN_STRUCTS = dict((struct.__name__, struct) for struct in KNOWN_STRUCTS) ARGUMENT_CALLBACK = { # Prototype: callback(argument) -> str "access": {"mode": formatAccessMode}, "open": {"flags": formatOpenFlags, "mode": formatOpenMode}, "openat": {"dirfd": formatDirFd, "flags": formatOpenFlags, "mode": formatOpenMode}, "name_to_handle_at": {"dirfd": formatDirFd}, "mmap": {"prot": formatMmapProt}, "mmap2": {"prot": formatMmapProt}, "clone": {"flags": formatCloneFlags}, "socket": {"type": formatSocketType}, "setsockopt": {"optval": formatOptVal}, } POINTER_CALLBACK = { # Prototype: callback(argument, argtype) -> str "sockaddr": formatSockaddr, } STRUCT_CALLBACK = { # Prototype: callback(argument, attr_name, attr_value) -> str "sockaddr_in": formatSockaddrInStruct, "sockaddr_in6": formatSockaddrIn6Struct, } INTEGER_TYPES = set(( "int", "size_t", "clockid_t", "long", "socklen_t", "pid_t", "uid_t", "gid_t", )) def iterBits(data): for char in data: byte = ord(chr(char)) for index in range(8): yield ((byte >> index) & 1) == 1 class SyscallArgument(FunctionArgument): def createText(self): value = self.value argtype = self.type name = self.name if not argtype or not name: return formatWordHex(self.value) syscall = self.function.name # Special cases try: return SYSCALL_ARG_DICT[syscall][name][value] except KeyError: pass try: callback = ARGUMENT_CALLBACK[syscall][name] except KeyError: callback = None if callback: return callback(self) if syscall == "execve": if name in ("argv", "envp"): return self.readCStringArray(value) if syscall == "socketcall": if name == "call": try: return SOCKETCALL[value] except KeyError: return str(value) if name == "args": func_call = FunctionCall("socketcall", self.options) setupSocketCall(func_call, self.function.process, self.function[0], self.value) text = "<%s>" % func_call.format() return self.formatPointer(text, self.value) if syscall == "write" and name == "buf": fd = self.function[0].value if fd < 3: length = self.function[2].value return self.readString(value, length) if name == "signum": return signalName(value) # Remove "const " prefix if argtype.startswith("const "): argtype = argtype[6:] if name in FILENAME_ARGUMENTS and argtype == "char *": return self.readCString(value) # Format depending on the type if argtype.endswith("*"): try: # Strip in case there is a space between the name and '*' text = self.formatValuePointer(argtype[:-1].strip()) if text: return text except PTRACE_ERRORS as err: writeError( getLogger(), err, "Warning: Format %r value error" % self, log_level=INFO) return formatAddress(self.value) # Array like "int[2]" match = re.match(r"(.*)\[([0-9])+\]", argtype) if match: basetype = match.group(1) count = int(match.group(2)) if basetype == "int": return self.readArray(self.value, c_int, count) # Simple types if argtype in ("unsigned int", "unsigned long", "u32"): return str(self.value) if argtype in INTEGER_TYPES: return str(uint2int(self.value)) # Default formatter: hexadecimal return formatWordHex(self.value) def formatValuePointer(self, argtype): address = self.value if not address: return "NULL" if argtype.startswith("struct "): argtype = argtype[7:] # Try a callback try: callback = POINTER_CALLBACK[argtype] except KeyError: callback = None if callback: return callback(self, argtype) if argtype == "int": pointee = self.function.process.readStruct(address, c_int) return self.formatPointer("<%s>" % pointee, address) if argtype in KNOWN_STRUCTS: struct = KNOWN_STRUCTS[argtype] return self.readStruct(address, struct) if RUNNING_LINUX and argtype == "fd_set": # The function is either select or pselect, so arg[0] is nfds nfds = self.function.arguments[0].value fd_set = filter(lambda x: int(x) < nfds, self.readBits(address, FD_SETSIZE)) return self.formatPointer("[%s]" % " ".join(fd_set), address) syscall = self.function.name if syscall == "rt_sigprocmask" and argtype == "sigset_t": size = self.function["sigsetsize"].value * 8 def formatter(key): key += 1 return signalName(key) fd_set = self.readBits(address, size, format=formatter) return self.formatPointer("" % " ".join(fd_set), address) return None def readBits(self, address, count, format=str): bytes = self.function.process.readBytes(address, count // 8) fd_set = [format(index) for index, bit in enumerate(iterBits(bytes)) if bit] return fd_set def readCString(self, address): if address: max_size = self.options.string_max_length data, truncated = self.function.process.readCString( address, max_size) text = os.fsdecode(data) text = repr(text) if truncated: text += "..." else: text = "NULL" return self.formatPointer(text, address) def readString(self, address, size): if address: max_len = self.options.string_max_length truncated = (max_len < size) size = min(size, max_len) data = self.function.process.readBytes(address, size) text = os.fsdecode(data) text = repr(text) if truncated: text += "..." else: text = "NULL" return self.formatPointer(text, address) def readCStringArray(self, address): if not address: return "NULL" address0 = address max_count = self.options.max_array_count text = [] while True: str_addr = self.function.process.readWord(address) address += CPU_WORD_SIZE text.append(self.readCString(str_addr)) if not str_addr: break if max_count <= len(text): text.append("(... more than %s strings ...)" % max_count) break text = "<(%s)>" % ", ".join(text) return self.formatPointer(text, address0) def formatStructValue(self, struct, name, value): if struct in STRUCT_CALLBACK: callback = STRUCT_CALLBACK[struct] return callback(self, name, value) return None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/ptrace/terminal.py0000664000175000017500000000160600000000000020300 0ustar00vstinnervstinner""" Terminal functions. """ from termios import tcgetattr, tcsetattr, ECHO, TCSADRAIN, TIOCGWINSZ from sys import stdin, stdout from fcntl import ioctl from struct import unpack import os TERMIO_LFLAGS = 3 def _terminalSize(): fd = stdout.fileno() size = ioctl(fd, TIOCGWINSZ, '1234') height, width = unpack('hh', size) return (width, height) def terminalWidth(): """ Get the terminal width in characters. """ return _terminalSize()[0] def enableEchoMode(): """ Enable echo mode in the terminal. Return True if the echo mode is set correctly, or False if the mode was already set. """ fd = stdin.fileno() if not os.isatty(fd): return False state = tcgetattr(fd) if state[TERMIO_LFLAGS] & ECHO: return False state[TERMIO_LFLAGS] = state[TERMIO_LFLAGS] | ECHO tcsetattr(fd, TCSADRAIN, state) return True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1616012234.0 python-ptrace-0.9.8/ptrace/tools.py0000664000175000017500000001051000000000000017617 0ustar00vstinnervstinnerfrom ctypes import sizeof from ptrace.ctypes_tools import formatUintHex16, formatUintHex32, formatWordHex from datetime import datetime, timedelta from os import getenv, access, X_OK, pathsep, getcwd from os.path import join as path_join, isabs, dirname, normpath def dumpRegs(log, regs): """ Dump all registers using log callback (write one line). """ width = max(len(name) for name, type in regs._fields_) name_format = "%% %us" % width for name, type in regs._fields_: value = getattr(regs, name) name = name_format % name if sizeof(type) == 32: value = formatUintHex32(value) elif sizeof(type) == 16: value = formatUintHex16(value) else: value = formatWordHex(value) log("%s = %s" % (name, value)) def readBits(value, bitmasks): """ Extract bits from the integer value using a list of bit masks. bitmasks is a list of tuple (mask, text). >>> bitmask = ( ... (1, "exec"), ... (2, "write"), ... (4, "read")) ... >>> readBits(5, bitmask) ['exec', 'read'] >>> readBits(12, bitmask) ['read', '8'] """ bitset = [] for mask, item in bitmasks: if not value & mask: continue bitset.append(item) value = value & ~mask if value: bitset.append(str(value)) return bitset def formatBits(value, bitmasks, empty_text=None, format_value=str): """ Format a value using a bitmask: see readBits() functions. >>> bitmask = ( ... (1, "exec"), ... (2, "write"), ... (4, "read")) ... >>> formatBits(5, bitmask, empty_text="no permission") ' (5)' >>> formatBits(0, bitmask, empty_text="no permission") 'no permission' """ orig_value = value text = readBits(value, bitmasks) if text: text = "%s" % ("|".join(text)) if value: text = "<%s> (%s)" % (text, format_value(orig_value)) return text else: if empty_text: return empty_text else: return str(value) LOCAL_TIMEZONE_OFFSET = datetime.fromtimestamp( 0) - datetime.utcfromtimestamp(0) # Start of UNIX timestamp (Epoch): 1st January 1970 at 00:00 UNIX_TIMESTAMP_T0 = datetime(1970, 1, 1) def timestampUNIX(value, is_local): """ Convert an UNIX (32-bit) timestamp to datetime object. Timestamp value is the number of seconds since the 1st January 1970 at 00:00. Maximum value is 2147483647: 19 january 2038 at 03:14:07. May raise ValueError for invalid value: value have to be in 0..2147483647. >>> timestampUNIX(0, False) datetime.datetime(1970, 1, 1, 0, 0) >>> timestampUNIX(1154175644.37, False) datetime.datetime(2006, 7, 29, 12, 20, 44, 370000) """ timestamp = UNIX_TIMESTAMP_T0 + timedelta(seconds=value) if is_local: timestamp += LOCAL_TIMEZONE_OFFSET return timestamp def locateProgram(program): """ Locate a program using the PATH environment variable. Return the unchanged program value if it's not possible to get the full program path. """ if isabs(program): return program if dirname(program): # ./test => $PWD/./test # ../python => $PWD/../python program = path_join(getcwd(), program) program = normpath(program) return program paths = getenv('PATH') if not paths: return program for path in paths.split(pathsep): filename = path_join(path, program) if access(filename, X_OK): return filename return program def minmax(min_value, value, max_value): """ Restrict value to [min_value; max_value] >>> minmax(-2, -3, 10) -2 >>> minmax(-2, 27, 10) 10 >>> minmax(-2, 0, 10) 0 """ return min(max(min_value, value), max_value) def inverseDict(data): """ Inverse a dictionary. >>> inverseDict({"0x10": 16, "0x20": 32}) == {32: '0x20', 16: '0x10'} True """ result = {} for key, value in data.items(): result[value] = key return result def signal_to_exitcode(signum): """ Converts a signal number to an exit code. UNIX: https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html >>> import signal >>> signal_to_exitcode(signal.SIGQUIT) 131 """ return 128 + signum ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/ptrace/version.py0000664000175000017500000000024000000000000020143 0ustar00vstinnervstinnerPACKAGE = "python-ptrace" VERSION = (0, 9, 8) __version__ = '.'.join(map(str, VERSION)) WEBSITE = "http://python-ptrace.readthedocs.io/" LICENSE = "GNU GPL v2" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9405315 python-ptrace-0.9.8/python_ptrace.egg-info/0000775000175000017500000000000000000000000021203 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1616012532.0 python-ptrace-0.9.8/python_ptrace.egg-info/PKG-INFO0000664000175000017500000000333400000000000022303 0ustar00vstinnervstinnerMetadata-Version: 1.1 Name: python-ptrace Version: 0.9.8 Summary: python binding of ptrace Home-page: http://python-ptrace.readthedocs.io/ Author: Victor Stinner Author-email: UNKNOWN License: GNU GPL v2 Download-URL: http://python-ptrace.readthedocs.io/ Description: ============= python-ptrace ============= .. image:: https://img.shields.io/pypi/v/python-ptrace.svg :alt: Latest release on the Python Cheeseshop (PyPI) :target: https://pypi.python.org/pypi/python-ptrace .. image:: https://github.com/vstinner/python-ptrace/actions/workflows/build.yml/badge.svg :alt: Build status of python-ptrace on GitHub Actions :target: https://github.com/vstinner/python-ptrace/actions python-ptrace is a debugger using ptrace (Linux, BSD and Darwin system call to trace processes) written in Python. * `python-ptrace documentation `_ * `python-ptrace at GitHub `_ * `python-ptrace at the Python Cheeseshop (PyPI) `_ python-ptrace is an opensource project written in Python under GNU GPLv2 license. It supports Python 3.6 and newer. Platform: UNKNOWN Classifier: Intended Audience :: Developers Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Operating System :: OS Independent Classifier: Natural Language :: English Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1616012532.0 python-ptrace-0.9.8/python_ptrace.egg-info/SOURCES.txt0000664000175000017500000000475700000000000023104 0ustar00vstinnervstinnerCOPYING MANIFEST.in README.rst SYSCALL_PROTOTYPES.codegen.py gdb.py runtests.py setup.cfg setup.py setup_cptrace.py strace.py test_doc.py tox.ini cptrace/Makefile cptrace/cptrace.c cptrace/version.py doc/Makefile doc/authors.rst doc/changelog.rst doc/conf.py doc/cptrace.rst doc/gdb.rst doc/index.rst doc/install.rst doc/make.bat doc/process_events.rst doc/ptrace_signal.rst doc/syscall.rst doc/todo.rst doc/usage.rst examples/itrace.py examples/simple_dbg.py ptrace/__init__.py ptrace/cpu_info.py ptrace/ctypes_libc.py ptrace/ctypes_tools.py ptrace/disasm.py ptrace/error.py ptrace/func_arg.py ptrace/func_call.py ptrace/linux_proc.py ptrace/logging_tools.py ptrace/mockup.py ptrace/os_tools.py ptrace/process_tools.py ptrace/profiler.py ptrace/pydistorm.py ptrace/signames.py ptrace/terminal.py ptrace/tools.py ptrace/version.py ptrace/binding/__init__.py ptrace/binding/cpu.py ptrace/binding/freebsd_struct.py ptrace/binding/func.py ptrace/binding/linux_struct.py ptrace/binding/openbsd_struct.py ptrace/debugger/__init__.py ptrace/debugger/application.py ptrace/debugger/backtrace.py ptrace/debugger/breakpoint.py ptrace/debugger/child.py ptrace/debugger/debugger.py ptrace/debugger/memory_mapping.py ptrace/debugger/parse_expr.py ptrace/debugger/process.py ptrace/debugger/process_error.py ptrace/debugger/process_event.py ptrace/debugger/ptrace_signal.py ptrace/debugger/signal_reason.py ptrace/debugger/syscall_state.py ptrace/syscall/__init__.py ptrace/syscall/freebsd_constants.py ptrace/syscall/freebsd_syscall.py ptrace/syscall/linux_constants.py ptrace/syscall/linux_struct.py ptrace/syscall/names.py ptrace/syscall/posix_arg.py ptrace/syscall/posix_constants.py ptrace/syscall/prototypes.py ptrace/syscall/ptrace_syscall.py ptrace/syscall/socketcall.py ptrace/syscall/socketcall_constants.py ptrace/syscall/socketcall_struct.py ptrace/syscall/syscall_argument.py ptrace/syscall/linux/__init__.py ptrace/syscall/linux/aarch64.py ptrace/syscall/linux/i386.py ptrace/syscall/linux/powerpc32.py ptrace/syscall/linux/powerpc64.py ptrace/syscall/linux/x86_64.py python_ptrace.egg-info/PKG-INFO python_ptrace.egg-info/SOURCES.txt python_ptrace.egg-info/dependency_links.txt python_ptrace.egg-info/top_level.txt tests/test_gdb.py tests/test_strace.py tests/crash/BSDmakefile tests/crash/Makefile tests/crash/abort.c tests/crash/call_null.c tests/crash/div_zero.c tests/crash/execve.c tests/crash/fork.c tests/crash/invalid_read.c tests/crash/invalid_write.c tests/crash/pthread.c tests/crash/socket_ipv4_tcp.c tests/crash/stack_overflow.c././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1616012532.0 python-ptrace-0.9.8/python_ptrace.egg-info/dependency_links.txt0000664000175000017500000000000100000000000025251 0ustar00vstinnervstinner ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1616012532.0 python-ptrace-0.9.8/python_ptrace.egg-info/top_level.txt0000664000175000017500000000000700000000000023732 0ustar00vstinnervstinnerptrace ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065867.0 python-ptrace-0.9.8/runtests.py0000775000175000017500000002120400000000000017075 0ustar00vstinnervstinner#!/usr/bin/env python3 """Run Tulip unittests. Usage: python3 runtests.py [flags] [pattern] ... Patterns are matched against the fully qualified name of the test, including package, module, class and method, e.g. 'tests.test_events.PolicyTests.testPolicy'. For full help, try --help. runtests.py --coverage is equivalent of: $(COVERAGE) run --branch runtests.py -v $(COVERAGE) html $(list of files) $(COVERAGE) report -m $(list of files) """ # Originally written by Beech Horn (for NDB). import gc import importlib.machinery import logging import optparse import os import re import sys import textwrap try: import coverage except ImportError: coverage = None try: import unittest from unittest.signals import installHandler except ImportError: import unittest2 as unittest from unittest2.signals import installHandler ARGS = optparse.OptionParser(description="Run all unittests.", usage="%prog") ARGS.add_option( '-v', '--verbose', action="store_true", dest='verbose', default=0, help='verbose') ARGS.add_option( '-x', action="store_true", dest='exclude', help='exclude tests') ARGS.add_option( '-f', '--failfast', action="store_true", default=False, dest='failfast', help='Stop on first fail or error') ARGS.add_option( '-c', '--catch', action="store_true", default=False, dest='catchbreak', help='Catch control-C and display results') ARGS.add_option( '--forever', action="store_true", dest='forever', default=False, help='run tests forever to catch sporadic errors') ARGS.add_option( '--findleaks', action='store_true', dest='findleaks', help='detect tests that leak memory') ARGS.add_option( '-q', action="store_true", dest='quiet', help='quiet') ARGS.add_option( '--tests', action="store", dest='testsdir', default='tests', help='tests directory') ARGS.add_option( '--coverage', action="store_true", dest='coverage', help='enable html coverage report') ARGS.add_option( '--pattern', action="append", help='optional regex patterns to match test ids (default all tests)') def load_module(modname, sourcefile): loader = importlib.machinery.SourceFileLoader(modname, sourcefile) return loader.load_module() def load_modules(basedir, suffix='.py'): def list_dir(prefix, dir): files = [] modpath = os.path.join(dir, '__init__.py') if os.path.isfile(modpath): mod = os.path.split(dir)[-1] files.append(('{0}{1}'.format(prefix, mod), modpath)) prefix = '{0}{1}.'.format(prefix, mod) for name in os.listdir(dir): path = os.path.join(dir, name) if os.path.isdir(path): files.extend(list_dir('{0}{1}.'.format(prefix, name), path)) else: if (name != '__init__.py' and name.endswith(suffix) and not name.startswith(('.', '_'))): files.append(('{0}{1}'.format(prefix, name[:-3]), path)) return files mods = [] for modname, sourcefile in list_dir('', basedir): if modname == 'runtests': continue try: mod = load_module(modname, sourcefile) mods.append((mod, sourcefile)) except SyntaxError: raise except Exception as err: print("Skipping '{0}': {1}".format(modname, err), file=sys.stderr) return mods class TestsFinder: def __init__(self, testsdir, includes=(), excludes=()): self._testsdir = testsdir self._includes = includes self._excludes = excludes self.find_available_tests() def find_available_tests(self): """ Find available test classes without instantiating them. """ self._test_factories = [] mods = [mod for mod, _ in load_modules(self._testsdir)] for mod in mods: for name in set(dir(mod)): if 'Test' in name: self._test_factories.append(getattr(mod, name)) def load_tests(self): """ Load test cases from the available test classes and apply optional include / exclude filters. """ loader = unittest.TestLoader() suite = unittest.TestSuite() for test_factory in self._test_factories: tests = loader.loadTestsFromTestCase(test_factory) if self._includes: tests = [test for test in tests if any(re.search(pat, test.id()) for pat in self._includes)] if self._excludes: tests = [test for test in tests if not any(re.search(pat, test.id()) for pat in self._excludes)] suite.addTests(tests) return suite class TestResult(unittest.TextTestResult): def __init__(self, stream, descriptions, verbosity): super().__init__(stream, descriptions, verbosity) self.leaks = [] def startTest(self, test): super().startTest(test) gc.collect() def addSuccess(self, test): super().addSuccess(test) gc.collect() if gc.garbage: if self.showAll: self.stream.writeln( " Warning: test created {} uncollectable " "object(s).".format(len(gc.garbage))) # move the uncollectable objects somewhere so we don't see # them again self.leaks.append((self.getDescription(test), gc.garbage[:])) del gc.garbage[:] class TestRunner(unittest.TextTestRunner): resultclass = TestResult def run(self, test): result = super().run(test) if result.leaks: self.stream.writeln("{0} tests leaks:".format(len(result.leaks))) for name, leaks in result.leaks: self.stream.writeln(' ' * 4 + name + ':') for leak in leaks: self.stream.writeln(' ' * 8 + repr(leak)) return result def runtests(): args, commands = ARGS.parse_args() if args.coverage and coverage is None: URL = "bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py" print(textwrap.dedent(""" coverage package is not installed. To install coverage3 for Python 3, you need: - Setuptools (https://pypi.python.org/pypi/setuptools) What worked for me: - download {0} * curl -O https://{0} - python3 ez_setup.py - python3 -m easy_install coverage """.format(URL)).strip()) sys.exit(1) testsdir = os.path.abspath(args.testsdir) if not os.path.isdir(testsdir): print("Tests directory is not found: {0}\n".format(testsdir)) ARGS.print_help() return excludes = includes = [] if args.exclude: excludes = args.pattern else: includes = args.pattern v = 0 if args.quiet else args.verbose + 1 failfast = args.failfast catchbreak = args.catchbreak findleaks = args.findleaks runner_factory = TestRunner if findleaks else unittest.TextTestRunner if args.coverage: cov = coverage.coverage(branch=True, source=['asyncio'], ) cov.start() finder = TestsFinder(args.testsdir, includes, excludes) logger = logging.getLogger() if v == 0: logger.setLevel(logging.CRITICAL) elif v == 1: logger.setLevel(logging.ERROR) elif v == 2: logger.setLevel(logging.WARNING) elif v == 3: logger.setLevel(logging.INFO) elif v >= 4: logger.setLevel(logging.DEBUG) if catchbreak: installHandler() try: if args.forever: while True: tests = finder.load_tests() result = runner_factory(verbosity=v, failfast=failfast).run(tests) if not result.wasSuccessful(): sys.exit(1) else: tests = finder.load_tests() result = runner_factory(verbosity=v, failfast=failfast).run(tests) sys.exit(not result.wasSuccessful()) finally: if args.coverage: cov.stop() cov.save() cov.html_report(directory='htmlcov') print("\nCoverage report:") cov.report(show_missing=False) here = os.path.dirname(os.path.abspath(__file__)) print("\nFor html report:") print("open file://{0}/htmlcov/index.html".format(here)) if __name__ == '__main__': runtests() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9415317 python-ptrace-0.9.8/setup.cfg0000664000175000017500000000010300000000000016445 0ustar00vstinnervstinner[bdist_wheel] universal = 1 [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1616012250.0 python-ptrace-0.9.8/setup.py0000775000175000017500000000426700000000000016360 0ustar00vstinnervstinner#!/usr/bin/env python # Prepare a release: # # - git pull --rebase # check that there is no incoming changesets # - check version in ptrace/version.py and doc/conf.py # - set release date in doc/changelog.rst # - check that "python3 setup.py sdist" contains all files tracked by # the SCM (Git): update MANIFEST.in if needed # - git commit -a -m "prepare release VERSION" # - Remove untracked files/dirs: git clean -fdx # - run tests, type: tox --parallel auto # - git push # - check GitHub Actions status: # https://github.com/vstinner/python-ptrace/actions # # Release a new version: # # - git tag VERSION # - Remove untracked files/dirs: git clean -fdx # - python3 setup.py sdist bdist_wheel # - git push --tags # - twine upload dist/* # # After the release: # # - increment version in ptrace/version.py and doc/conf.py # - git commit -a -m "post-release" # - git push from imp import load_source from os import path try: # setuptools supports bdist_wheel from setuptools import setup except ImportError: from distutils.core import setup MODULES = ["ptrace", "ptrace.binding", "ptrace.syscall", "ptrace.syscall.linux", "ptrace.debugger"] SCRIPTS = ("strace.py", "gdb.py") CLASSIFIERS = [ 'Intended Audience :: Developers', 'Development Status :: 4 - Beta', 'Environment :: Console', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Operating System :: OS Independent', 'Natural Language :: English', 'Programming Language :: Python', 'Programming Language :: Python :: 3', ] with open('README.rst') as fp: LONG_DESCRIPTION = fp.read() ptrace = load_source("version", path.join("ptrace", "version.py")) PACKAGES = {} for name in MODULES: PACKAGES[name] = name.replace(".", "/") install_options = { "name": ptrace.PACKAGE, "version": ptrace.__version__, "url": ptrace.WEBSITE, "download_url": ptrace.WEBSITE, "author": "Victor Stinner", "description": "python binding of ptrace", "long_description": LONG_DESCRIPTION, "classifiers": CLASSIFIERS, "license": ptrace.LICENSE, "packages": list(PACKAGES.keys()), "package_dir": PACKAGES, "scripts": SCRIPTS, } setup(**install_options) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/setup_cptrace.py0000775000175000017500000000250500000000000020052 0ustar00vstinnervstinner#!/usr/bin/env python SOURCES = ['cptrace/cptrace.c'] CLASSIFIERS = [ 'Intended Audience :: Developers', 'Development Status :: 4 - Beta', 'Environment :: Console', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Operating System :: OS Independent', 'Natural Language :: English', 'Programming Language :: C', 'Programming Language :: Python', ] LONG_DESCRIPTION = open('doc/cptrace.rst').read() def main(): from imp import load_source from os import path from sys import argv if "--setuptools" in argv: argv.remove("--setuptools") from setuptools import setup, Extension else: from distutils.core import setup, Extension cptrace_ext = Extension('cptrace', sources=SOURCES) cptrace = load_source("version", path.join("cptrace", "version.py")) install_options = { "name": cptrace.PACKAGE, "version": cptrace.VERSION, "url": cptrace.WEBSITE, "download_url": cptrace.WEBSITE, "license": cptrace.LICENSE, "author": "Victor Stinner", "description": "python binding of ptrace written in C", "long_description": LONG_DESCRIPTION, "classifiers": CLASSIFIERS, "ext_modules": [cptrace_ext], } setup(**install_options) if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/strace.py0000775000175000017500000002501100000000000016467 0ustar00vstinnervstinner#!/usr/bin/env python from ptrace import PtraceError from ptrace.debugger import (PtraceDebugger, Application, ProcessExit, ProcessSignal, NewProcessEvent, ProcessExecution) from ptrace.syscall import (SYSCALL_NAMES, SYSCALL_PROTOTYPES, FILENAME_ARGUMENTS, SOCKET_SYSCALL_NAMES) from ptrace.func_call import FunctionCallOptions from sys import stderr, exit from optparse import OptionParser from logging import getLogger, error from ptrace.error import PTRACE_ERRORS, writeError from ptrace.ctypes_tools import formatAddress from ptrace.tools import signal_to_exitcode import sys import re class SyscallTracer(Application): def __init__(self): Application.__init__(self) # Parse self.options self.parseOptions() # Setup output (log) self.setupLog() def setupLog(self): if self.options.output: fd = open(self.options.output, 'w') self._output = fd else: fd = stderr self._output = None self._setupLog(fd) def parseOptions(self): parser = OptionParser( usage="%prog [options] -- program [arg1 arg2 ...]") self.createCommonOptions(parser) parser.add_option("--enter", help="Show system call enter and exit", action="store_true", default=False) parser.add_option("--profiler", help="Use profiler", action="store_true", default=False) parser.add_option("--type", help="Display arguments type and result type (default: no)", action="store_true", default=False) parser.add_option("--name", help="Display argument name (default: no)", action="store_true", default=False) parser.add_option("--string-length", "-s", help="String max length (default: 300)", type="int", default=300) parser.add_option("--array-count", help="Maximum number of array items (default: 20)", type="int", default=20) parser.add_option("--raw-socketcall", help="Raw socketcall form", action="store_true", default=False) parser.add_option("--output", "-o", help="Write output to specified log file", type="str") parser.add_option("--ignore-regex", help="Regex used to filter syscall names (e.g. --ignore='^(gettimeofday|futex|f?stat)')", type="str") parser.add_option("--address", help="Display structure address", action="store_true", default=False) parser.add_option("--syscalls", '-e', help="Comma separated list of shown system calls (other will be skipped)", type="str", default=None) parser.add_option("--socket", help="Show only socket functions", action="store_true", default=False) parser.add_option("--filename", help="Show only syscall using filename", action="store_true", default=False) parser.add_option("--show-pid", help="Prefix line with process identifier", action="store_true", default=False) parser.add_option("--list-syscalls", help="Display system calls and exit", action="store_true", default=False) parser.add_option("-i", "--show-ip", help="print instruction pointer at time of syscall", action="store_true", default=False) self.createLogOptions(parser) self.options, self.program = parser.parse_args() if self.options.list_syscalls: syscalls = list(SYSCALL_NAMES.items()) syscalls.sort(key=lambda data: data[0]) for num, name in syscalls: print("% 3s: %s" % (num, name)) exit(0) if self.options.pid is None and not self.program: parser.print_help() exit(1) # Create "only" filter only = set() if self.options.syscalls: # split by "," and remove spaces for item in self.options.syscalls.split(","): item = item.strip() if not item or item in only: continue ok = True valid_names = list(SYSCALL_NAMES.values()) for name in only: if name not in valid_names: print("ERROR: unknown syscall %r" % name, file=stderr) ok = False if not ok: print(file=stderr) print( "Use --list-syscalls options to get system calls list", file=stderr) exit(1) # remove duplicates only.add(item) if self.options.filename: for syscall, format in SYSCALL_PROTOTYPES.items(): restype, arguments = format if any(argname in FILENAME_ARGUMENTS for argtype, argname in arguments): only.add(syscall) if self.options.socket: only |= SOCKET_SYSCALL_NAMES self.only = only if self.options.ignore_regex: try: self.ignore_regex = re.compile(self.options.ignore_regex) except Exception as err: print("Invalid regular expression! %s" % err) print("(regex: %r)" % self.options.ignore_regex) exit(1) else: self.ignore_regex = None if self.options.fork: self.options.show_pid = True self.processOptions() def ignoreSyscall(self, syscall): name = syscall.name if self.only and (name not in self.only): return True if self.ignore_regex and self.ignore_regex.match(name): return True return False def displaySyscall(self, syscall): text = syscall.format() if syscall.result is not None: text = "%-40s = %s" % (text, syscall.result_text) prefix = [] if self.options.show_pid: prefix.append("[%s]" % syscall.process.pid) if self.options.show_ip: prefix.append("[%s]" % formatAddress(syscall.instr_pointer)) if prefix: text = ''.join(prefix) + ' ' + text error(text) def syscallTrace(self, process): # First query to break at next syscall self.prepareProcess(process) exitcode = 0 while True: # No more process? Exit if not self.debugger: break # Wait until next syscall enter try: event = self.debugger.waitSyscall() except ProcessExit as event: self.processExited(event) if event.exitcode is not None: exitcode = event.exitcode continue except ProcessSignal as event: event.display() event.process.syscall(event.signum) exitcode = signal_to_exitcode(event.signum) continue except NewProcessEvent as event: self.newProcess(event) continue except ProcessExecution as event: self.processExecution(event) continue # Process syscall enter or exit self.syscall(event.process) return exitcode def syscall(self, process): state = process.syscall_state syscall = state.event(self.syscall_options) if syscall and (syscall.result is not None or self.options.enter): self.displaySyscall(syscall) # Break at next syscall process.syscall() def processExited(self, event): # Display syscall which has not exited state = event.process.syscall_state if (state.next_event == "exit") \ and (not self.options.enter) \ and state.syscall: self.displaySyscall(state.syscall) # Display exit message error("*** %s ***" % event) def prepareProcess(self, process): process.syscall() process.syscall_state.ignore_callback = self.ignoreSyscall def newProcess(self, event): process = event.process error("*** New process %s ***" % process.pid) self.prepareProcess(process) process.parent.syscall() def processExecution(self, event): process = event.process error("*** Process %s execution ***" % process.pid) process.syscall() def runDebugger(self): # Create debugger and traced process self.setupDebugger() process = self.createProcess() if not process: return self.syscall_options = FunctionCallOptions( write_types=self.options.type, write_argname=self.options.name, string_max_length=self.options.string_length, replace_socketcall=not self.options.raw_socketcall, write_address=self.options.address, max_array_count=self.options.array_count, ) self.syscall_options.instr_pointer = self.options.show_ip return self.syscallTrace(process) def main(self): if self.options.profiler: from ptrace.profiler import runProfiler exitcode = runProfiler(getLogger(), self._main) else: exitcode = self._main() if self._output is not None: self._output.close() sys.exit(exitcode) def _main(self): self.debugger = PtraceDebugger() exitcode = 0 try: exitcode = self.runDebugger() except ProcessExit as event: self.processExited(event) if event.exitcode is not None: exitcode = event.exitcode except PtraceError as err: error("ptrace() error: %s" % err) if err.errno is not None: exitcode = err.errno except KeyboardInterrupt: error("Interrupted.") exitcode = 1 except PTRACE_ERRORS as err: writeError(getLogger(), err, "Debugger error") exitcode = 1 self.debugger.quit() return exitcode def createChild(self, program): pid = Application.createChild(self, program) error("execve(%s, %s, [/* 40 vars */]) = %s" % ( program[0], program, pid)) return pid if __name__ == "__main__": SyscallTracer().main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/test_doc.py0000775000175000017500000000230300000000000017011 0ustar00vstinnervstinner#!/usr/bin/env python from doctest import testfile, ELLIPSIS, testmod from sys import exit, path as sys_path from os.path import dirname def testDoc(filename, name=None): print("--- %s: Run tests" % filename) failure, nb_test = testfile( filename, optionflags=ELLIPSIS, name=name) if failure: exit(1) print("--- %s: End of tests" % filename) def importModule(name): mod = __import__(name) components = name.split('.') for comp in components[1:]: mod = getattr(mod, comp) return mod def testModule(name): print("--- Test module %s" % name) module = importModule(name) failure, nb_test = testmod(module) if failure: exit(1) print("--- End of test") def main(): ptrace_dir = dirname(__file__) sys_path.append(ptrace_dir) # Test documentation in doc/*.rst files # testDoc('doc/c_tools.rst') # Test documentation of some functions/classes testModule("ptrace.ctypes_tools") testModule("ptrace.debugger.parse_expr") testModule("ptrace.logging_tools") testModule("ptrace.signames") testModule("ptrace.syscall.socketcall") testModule("ptrace.tools") if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9405315 python-ptrace-0.9.8/tests/0000775000175000017500000000000000000000000015774 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1616012532.9415317 python-ptrace-0.9.8/tests/crash/0000775000175000017500000000000000000000000017074 5ustar00vstinnervstinner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/BSDmakefile0000664000175000017500000000040400000000000021123 0ustar00vstinnervstinnerSOURCES=stack_overflow.c div_zero.c call_null.c abort.c fork.c invalid_write.c invalid_read.c PROGRAMS=${SOURCES:S/.c//g} pthread CFLAGS=-Wall -O0 -g all: $(PROGRAMS) pthread: pthread.c $(CC) -o $@ $(CFLAGS) pthread.c -lpthread clean: rm -f $(PROGRAMS) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/Makefile0000664000175000017500000000047700000000000020544 0ustar00vstinnervstinnerCC=gcc SOURCES=stack_overflow.c div_zero.c call_null.c abort.c fork.c execve.c invalid_write.c invalid_read.c socket_ipv4_tcp.c PROGRAMS=$(patsubst %.c,%,$(SOURCES)) pthread CFLAGS=-Wall -Wextra -Werror -O0 -g all: $(PROGRAMS) pthread: pthread.c $(CC) -o $@ $(CFLAGS) pthread.c -lpthread clean: rm -f $(PROGRAMS) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/abort.c0000664000175000017500000000007600000000000020352 0ustar00vstinnervstinner#include int main() { abort(); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/call_null.c0000664000175000017500000000010600000000000021202 0ustar00vstinnervstinnerint main() { void (*func) (void) = 0; func(); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/div_zero.c0000664000175000017500000000010700000000000021057 0ustar00vstinnervstinnerint main() { int x = 1; int y = 0; x /= y; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/execve.c0000664000175000017500000000054500000000000020523 0ustar00vstinnervstinner#include #include #include #include int main() { char *arg[]= {"/bin/ls", NULL }; int pid; pid = fork(); if (pid) { waitpid(pid, NULL, 0); exit(EXIT_SUCCESS); } else { (void)uname(NULL); execve(arg[0], arg, NULL); exit(EXIT_FAILURE); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/fork.c0000664000175000017500000000201700000000000020201 0ustar00vstinnervstinner#include #include #include #include #include #include int parent_pid; void parent(pid_t child_pid) { int status; int result; printf("[parent:%i] wait for child exit\n", parent_pid); result = waitpid(child_pid, &status, 0); if (result != child_pid) { perror("waitpid"); exit(1); } printf("[parent:%i] child exited with status %i\n", parent_pid, status); } void child() { struct utsname buf; int err; int pid = getpid(); printf("[child:%i] uname()\n", pid); err = uname(&buf); if (err) { perror("uname"); exit(1); } printf("[child:%i] done, exit.\n", pid); } int main() { pid_t pid; /* fork process */ parent_pid = getpid(); printf("[parent:%i] fork\n", parent_pid); pid = fork(); if (pid < 0) { perror("fork"); exit(1); } if (pid) { parent(pid); } else { child(); } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/invalid_read.c0000664000175000017500000000022000000000000021653 0ustar00vstinnervstinnertypedef struct { int x; int y; int z; } point_t; int main() { point_t *point = 0; int z; z = point->z; return z; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/invalid_write.c0000664000175000017500000000020600000000000022076 0ustar00vstinnervstinnertypedef struct { int x; int y; int z; } point_t; int main() { point_t *point = 0; point->z = 42; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/pthread.c0000664000175000017500000000101300000000000020662 0ustar00vstinnervstinner#include #include #define UNUSED(x) x __attribute__((unused)) pthread_t thread; pthread_mutex_t mutex; int global_counter; void* nothing(void *UNUSED(data)) { printf("[thread] exit thread\n"); pthread_exit(NULL); } int main() { global_counter = 1; printf("[main] create thread\n"); pthread_create(&thread, NULL, nothing, NULL); printf("[main] join thread\n"); pthread_join(thread, NULL); printf("[main] exit\n"); pthread_mutex_destroy(&mutex); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/socket_ipv4_tcp.c0000664000175000017500000000126300000000000022342 0ustar00vstinnervstinner#include #include /* close() */ #include /* perror() */ #include /* struct sockaddr_in */ int main() { int fd; int val; int ret; struct sockaddr_in addr; fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) perror("socket"); val = 1; (void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); addr.sin_family = AF_INET; addr.sin_port = htons(80); addr.sin_addr.s_addr = 0x7f000001; ret = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); if (ret < 0) perror("connect"); ret = close(fd); if (ret) perror("close"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1571666464.0 python-ptrace-0.9.8/tests/crash/stack_overflow.c0000664000175000017500000000025200000000000022267 0ustar00vstinnervstinnerchar toto() { char buffer[4096]; buffer[0] = 0; toto(); return buffer[0] + buffer[sizeof(buffer)-1]; } int main() { char c = toto(); return c; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/tests/test_gdb.py0000775000175000017500000000477600000000000020162 0ustar00vstinnervstinner#!/usr/bin/env python import os import re import subprocess import sys import unittest GDB = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'gdb.py')) class TestGdb(unittest.TestCase): def run_command(self, command): if isinstance(command, str): command = command.encode('ascii') command = command + b'\n' args = [sys.executable, GDB, '--', sys.executable, '-c', 'pass'] proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout, _ = proc.communicate(command) exitcode = proc.wait() self.assertEqual(exitcode, 0) if stdout.startswith(b'(gdb) '): stdout = stdout[6:] pos = stdout.rfind(b'(gdb) ') if pos: stdout = stdout[:pos] stdout = stdout.rstrip() if b'Traceback' in stdout: self.fail('Traceback in output: %r' % stdout) return stdout def check_stdout(self, pattern, stdout): self.assertTrue(re.search(pattern, stdout, re.MULTILINE), (pattern, stdout)) def test_proc(self): stdout = self.run_command('proc') for pattern in ( b'^Process ID: [0-9]+', b'^Process state: ', b'^Process environment: ', b'^User identifier: [0-9]+', b'^Group identifier: [0-9]+', ): self.assertTrue(re.search(pattern, stdout, re.MULTILINE), (pattern, stdout)) def test_print(self): stdout = self.run_command('print 1+2') self.check_stdout(b'^Decimal: 3\n', stdout) def test_where(self): stdout = self.run_command('where') self.check_stdout(b'^CODE:', stdout) def test_regs(self): # Just check that the command doesn't raise an exception self.run_command('regs') def test_backtrace(self): # Just check that the command doesn't raise an exception self.run_command('backtrace') def test_maps(self): stdout = self.run_command('maps') self.check_stdout(b'^MAPS: ', stdout) def test_dbginfo(self): stdout = self.run_command('dbginfo') self.check_stdout(b'^Debugger process ID: [0-9]+', stdout) self.check_stdout(b'^python-ptrace version [0-9]+\\.[0-9]+', stdout) self.check_stdout(b'^Website: ', stdout) if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1612443136.0 python-ptrace-0.9.8/tests/test_strace.py0000775000175000017500000000762600000000000020704 0ustar00vstinnervstinner#!/usr/bin/env python import os import re import subprocess import sys import tempfile import unittest import signal STRACE = os.path.normpath( os.path.join(os.path.dirname(__file__), '..', 'strace.py')) AARCH64 = (getattr(os.uname(), 'machine', None) == 'aarch64') class TestStrace(unittest.TestCase): def strace(self, *args): """ Strace the given command and return the strace output. """ with tempfile.NamedTemporaryFile(mode='wb+') as temp: args = (sys.executable, STRACE, '-o', temp.name, '--') + args with open(os.devnull, "wb") as devnull: proc = subprocess.Popen(args, stdout=devnull, stderr=subprocess.STDOUT) exitcode = proc.wait() temp.seek(0) strace = temp.readlines() strace = b''.join(strace) self.assertIsNone(re.match(b'^Traceback', strace), strace) return strace, exitcode def assert_syscall(self, code, regex): """ Strace the given python code and match the strace output against the given regular expression. """ stdout, _ = self.strace(sys.executable, '-c', code) pattern = re.compile(regex, re.MULTILINE) self.assertTrue(pattern.search(stdout), stdout) def test_basic(self): stdout, _ = self.strace(sys.executable, '-c', 'pass') for syscall in (b'exit', b'mmap', b'open'): pattern = re.compile(b'^' + syscall, re.MULTILINE) self.assertTrue(pattern.search(stdout), stdout) def test_exitcode(self): for ec in range(2): stdout, exitcode = self.strace(sys.executable, '-c', 'exit(%d)' % ec) self.assertEqual(exitcode, ec) def test_exitsignal(self): signum = int(signal.SIGQUIT) stdout, exitcode = self.strace(sys.executable, '-c', 'import os; os.kill(os.getpid(), %d)' % signum) self.assertEqual(exitcode, (127 + 1) + signum) def test_getcwd(self): cwd = os.getcwd() stdout, _ = self.strace(sys.executable, '-c', 'import os; os.getcwd()') pattern = re.compile(b'^getcwd\\((.*),', re.MULTILINE) match = pattern.search(stdout) self.assertTrue(match, stdout) expected = repr(cwd) expected = os.fsencode(expected) self.assertEqual(match.group(1), expected) def test_open(self): code = 'open(%a).close()' % __file__ self.assert_syscall( code, br"^open(at)?\(.*test_strace\.pyc?', O_RDONLY(\|O_CLOEXEC)?") def test_chdir(self): self.assert_syscall("import os; os.chdir('directory')", br"^chdir\('directory'\)\s+= -2 ENOENT") def test_rename(self): pattern = br"^rename\('oldpath', 'newpath'\)" if AARCH64: pattern = br"^renameat\(.*'oldpath'.*'newpath'\)" self.assert_syscall("import os; os.rename('oldpath', 'newpath')", pattern) def test_link(self): pattern = br"^link\('oldpath', 'newpath'\)" if AARCH64: pattern = br"^linkat\(.*'oldpath'.*'newpath'.*\)" self.assert_syscall("import os; os.link('oldpath', 'newpath')", pattern) def test_symlink(self): pattern = br"^symlink\('target', 'linkpath'\)" if AARCH64: pattern = br"^symlinkat\(.*'target'.*'linkpath'\)" try: self.assert_syscall("import os; os.symlink('target', 'linkpath')", pattern) finally: try: os.unlink('linkpath') except OSError: pass def test_socket(self): self.assert_syscall( "import socket; socket.socket(socket.AF_INET,socket.SOCK_STREAM).close()", br'^socket\(AF_INET, SOCK_STREAM(\|SOCK_CLOEXEC)?') if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597065961.0 python-ptrace-0.9.8/tox.ini0000664000175000017500000000065500000000000016153 0ustar00vstinnervstinner[tox] envlist = py3, pep8 [testenv] basepython = python3 commands= python test_doc.py python runtests.py -v [testenv:py3] basepython = python3 [testenv:pep8] deps = flake8 commands = flake8 ptrace/ tests/ gdb.py runtests.py setup_cptrace.py setup.py strace.py SYSCALL_PROTOTYPES.codegen.py test_doc.py [flake8] # E501 line too long (88 > 79 characters) # W503 line break before binary operator ignore = E501,W503