edb-debugger-1.0.0/0000755000175000017500000000000013273160725013350 5ustar eteraneteranedb-debugger-1.0.0/travis_install_capstone.sh0000755000175000017500000000030013273160654020633 0ustar eteraneteran#!/bin/sh set -ex mkdir -p $HOME/src cd $HOME/src git clone --depth=50 --branch=3.0.4 https://github.com/aquynh/capstone.git cd capstone ./make.sh sudo ./make.sh install cd $TRAVIS_BUILD_DIR edb-debugger-1.0.0/BUGS0000644000175000017500000000014513273160654014034 0ustar eteraneteranThis file has been superseded by the issue tracker at: https://github.com/eteran/edb-debugger/issues edb-debugger-1.0.0/edb.desktop0000644000175000017500000000023613273160654015477 0ustar eteraneteran[Desktop Entry] Name=edb GenericName=edb debugger Comment=edb debugger Exec=edb Icon=edb Terminal=false Type=Application Categories=Development;Qt;Debugger; edb-debugger-1.0.0/COPYING0000644000175000017500000004325413273160654014414 0ustar eteraneteran GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, 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 Lesser 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 Street, 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 Lesser General Public License instead of this License. edb-debugger-1.0.0/appveyor.yml0000644000175000017500000000374213273160654015747 0ustar eteraneteranversion: "{build}" environment: CAPSTONE_SDK: C:\capstone\sdk matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 BOOST_INCLUDEDIR: C:\Libraries\boost_1_64_0 CAPSTONE_ARCHIVE: capstone-3.0.5-rc2-win64 CMAKE_GENERATOR: Visual Studio 15 2017 Win64 QT_BASEDIR: C:\Qt\5.9\msvc2017_64 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 BOOST_INCLUDEDIR: C:\Libraries\boost_1_63_0 CAPSTONE_ARCHIVE: capstone-3.0.5-rc2-win32 CMAKE_GENERATOR: Visual Studio 14 2015 QT_BASEDIR: C:\Qt\5.9\msvc2015 configuration: - Debug - Release install: - ps: new-item -itemtype directory -path C:\capstone\sdk | out-null - ps: new-item -itemtype directory -path C:\capstone\sdk\include\capstone | out-null - ps: new-item -itemtype directory -path C:\capstone\sdk\lib | out-null - ps: "[Environment]::CurrentDirectory = 'C:\\capstone'" - ps: (new-object net.webclient).DownloadFile("https://github.com/aquynh/capstone/releases/download/3.0.5-rc2/${env:CAPSTONE_ARCHIVE}.zip", 'capstone.zip') - ps: expand-archive C:\capstone\capstone.zip -destinationpath C:\capstone - ps: copy-item C:\capstone\${env:CAPSTONE_ARCHIVE}\include\*.h C:\capstone\sdk\include\capstone - ps: copy-item C:\capstone\${env:CAPSTONE_ARCHIVE}\capstone.lib C:\capstone\sdk\lib\capstone_dll.lib before_build: - cmd: git submodule update --init - cmd: cd C:\projects - cmd: md build - cmd: cd build - cmd: cmake -Wno-dev -G "%CMAKE_GENERATOR%" -DCMAKE_BUILD_TYPE=%configuration% -DCMAKE_INSTALL_PREFIX=C:\projects\install -DBOOST_INCLUDEDIR="%BOOST_INCLUDEDIR%" -DCAPSTONE_SDK="%CAPSTONE_SDK%" -DQt5Core_DIR="%QT_BASEDIR%\lib\cmake\Qt5Core" -DQt5_DIR="%QT_BASEDIR%\lib\cmake\Qt5" ..\edb-debugger build_script: - cmd: msbuild C:\projects\build\edb.sln /t:edb /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - cmd: msbuild C:\projects\build\edb.sln /t:DebuggerCore /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" edb-debugger-1.0.0/plugins/0000755000175000017500000000000013273160654015032 5ustar eteraneteranedb-debugger-1.0.0/plugins/BinaryInfo/0000755000175000017500000000000013273160654017072 5ustar eteraneteranedb-debugger-1.0.0/plugins/BinaryInfo/ELFXX.cpp0000644000175000017500000001377213273160654020476 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "ELFXX.h" #include "elf/elf_phdr.h" #include "ByteShiftArray.h" #include "IDebugger.h" #include "IProcess.h" #include "IRegion.h" #include "Util.h" #include "edb.h" #include "string_hash.h" #include #include #include #include #include namespace BinaryInfoPlugin { class ELFBinaryException : public std::exception { virtual const char *what() const noexcept = 0; }; class InvalidArguments : public ELFBinaryException { public: virtual const char * what() const noexcept override { return "Invalid Arguments"; } }; class ReadFailure : public ELFBinaryException { public: virtual const char * what() const noexcept override { return "Read Failure"; } }; class InvalidELF : public ELFBinaryException { public: virtual const char * what() const noexcept override { return "Invalid ELF"; } }; class InvalidArchitecture : public ELFBinaryException { public: virtual const char * what() const noexcept override { return "Invalid Architecture"; } }; template ELFXX::ELFXX(const std::shared_ptr ®ion) : region_(region) { using phdr_type = typename elfxx_header::elf_phdr; if (!region_) { throw InvalidArguments(); } IProcess *const process = edb::v1::debugger_core->process(); if (!process) { throw ReadFailure(); } if(!process->read_bytes(region_->start(), &header_, sizeof(elfxx_header))) { throw ReadFailure(); } validate_header(); headers_.push_back({region_->start(), header_.e_ehsize}); headers_.push_back({region_->start() + header_.e_phoff, static_cast(header_.e_phentsize * header_.e_phnum) }); auto phdr_size = header_.e_phentsize; if (phdr_size < sizeof(phdr_type)) { qDebug()<< QString::number(region_->start(), 16) << "program header size less than expected"; base_address_ = region_->start(); return; } phdr_type phdr; auto phdr_base = region_->start() + header_.e_phoff; edb::address_t lowest = ULLONG_MAX; // iterate all of the program headers for (quint16 entry = 0; entry < header_.e_phnum; entry++) { if (!process->read_bytes(phdr_base + (phdr_size * entry), &phdr, sizeof(phdr_type))) { qDebug() << "Failed to read program header"; base_address_ = region_->start(); return; } if (phdr.p_type == PT_LOAD && phdr.p_vaddr < lowest) { lowest = phdr.p_vaddr; } } if (lowest == ULLONG_MAX) { qDebug() << "binary base address not found. Assuming " << QString::number(region_->start(), 16); base_address_ = region->start(); } else { base_address_ = lowest; } } //------------------------------------------------------------------------------ // Name: ~ELFXX // Desc: destructor //------------------------------------------------------------------------------ template ELFXX::~ELFXX() { } //------------------------------------------------------------------------------ // Name: header_size // Desc: returns the number of bytes in this executable's header //------------------------------------------------------------------------------ template size_t ELFXX::header_size() const { size_t size = header_.e_ehsize; // Do the program headers immediately follow the ELF header? if (size == header_.e_phoff) { size += header_.e_phentsize * header_.e_phnum; } return size; } //------------------------------------------------------------------------------ // Name: base_address // Desc: returns the base address of the module //------------------------------------------------------------------------------ template edb::address_t ELFXX::base_address() const { return base_address_; } //------------------------------------------------------------------------------ // Name: headers // Desc: returns a list of all headers in this binary //------------------------------------------------------------------------------ template QVector ELFXX::headers() const { return headers_; } //------------------------------------------------------------------------------ // Name: validate_header // Desc: ensures that the header that we read was valid //------------------------------------------------------------------------------ template void ELFXX::validate_header() { if(std::memcmp(header_.e_ident, ELFMAG, SELFMAG) != 0) { throw InvalidELF(); } if (header_.e_ident[EI_CLASS] != elfxx_header::ELFCLASS) { throw InvalidArchitecture(); } } //------------------------------------------------------------------------------ // Name: entry_point // Desc: returns the entry point if any of the binary //------------------------------------------------------------------------------ template edb::address_t ELFXX::entry_point() { return header_.e_entry + region_->start() - base_address_; } //------------------------------------------------------------------------------ // Name: header // Desc: returns a copy of the file header or NULL if the region wasn't a valid, // known binary type //------------------------------------------------------------------------------ template const void *ELFXX::header() const { return &header_; } // explicit instantiations template class ELFXX; template class ELFXX; } edb-debugger-1.0.0/plugins/BinaryInfo/ELF64.cpp0000644000175000017500000001030013273160654020350 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "ELFXX.h" #include "ByteShiftArray.h" #include "IDebugger.h" #include "IProcess.h" #include "IRegion.h" #include "Util.h" #include "edb.h" #include "string_hash.h" #include #include #include #include namespace BinaryInfoPlugin { //------------------------------------------------------------------------------ // Name: native // Desc: returns true if this binary is native to the arch edb was built for //------------------------------------------------------------------------------ template<> bool ELF64::native() const { return edb::v1::debugger_core->cpu_type() == edb::string_hash("x86-64"); } //------------------------------------------------------------------------------ // Name: debug_pointer // Desc: attempts to locate the ELF debug pointer in the target process and // returns it, 0 of not found //------------------------------------------------------------------------------ template<> edb::address_t ELF64::debug_pointer() { if(IProcess *process = edb::v1::debugger_core->process()) { const edb::address_t section_offset = header_.e_phoff; const std::size_t count = header_.e_phnum; elf64_phdr section_header; for(std::size_t i = 0; i < count; ++i) { if(process->read_bytes(region_->start() + (section_offset + i * sizeof(elf64_phdr)), §ion_header, sizeof(elf64_phdr))) { if(section_header.p_type == PT_DYNAMIC) { try { QVector buf(section_header.p_memsz); if(process->read_bytes(section_header.p_vaddr, &buf[0], section_header.p_memsz)) { auto dynamic = reinterpret_cast(&buf[0]); while(dynamic->d_tag != DT_NULL) { if(dynamic->d_tag == DT_DEBUG) { return dynamic->d_un.d_val; } ++dynamic; } } } catch(const std::bad_alloc &) { qDebug() << "[Elf64::debug_pointer] no more memory"; return 0; } } } } } return 0; } //------------------------------------------------------------------------------ // Name: calculate_main // Desc: uses a heuristic to locate "main" //------------------------------------------------------------------------------ template<> edb::address_t ELF64::calculate_main() { edb::address_t entry_point = this->entry_point(); ByteShiftArray ba(14); if(IProcess *process = edb::v1::debugger_core->process()) { for(int i = 0; i < 50; ++i) { quint8 byte; if(process->read_bytes(entry_point + i, &byte, sizeof(byte))) { ba << byte; edb::address_t address = 0; if(ba.size() >= 13) { // beginning of a call preceeded by a 64-bit mov and followed by a hlt if(ba[0] == 0x48 && ba[1] == 0xc7 && ba[7] == 0xe8 && ba[12] == 0xf4) { // Seems that this 64-bit mov still has a 32-bit immediate address = *reinterpret_cast(ba.data() + 3) & 0xffffffff; } // same heuristic except for PIC binaries else if (ba.size() >= 14 && ba[0] == 0x48 && ba[1] == 0x8d && ba[2] == 0x3d && ba[7] == 0xFF && ba[8] == 0x15 && ba[13] == 0xf4) { // It's signed relative! auto rel = *reinterpret_cast(ba.data() + 3); // ba[0] is entry_point + i - 13. instruction is 7 bytes long. address = rel + entry_point + i - 13 + 7; } if (address) { // TODO: make sure that this address resides in an executable region qDebug() << "No main symbol found, calculated it to be " << edb::v1::format_pointer(address) << " using heuristic"; return address; } } } else { break; } } } return 0; } } edb-debugger-1.0.0/plugins/BinaryInfo/pe_binary.h0000644000175000017500000001107113273160654021213 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PE_BINARY_20121007_H_ #define PE_BINARY_20121007_H_ #include #ifdef WIN32 #include #else typedef uint8_t BYTE; typedef uint8_t BOOLEAN; typedef int16_t SHORT; typedef uint16_t WORD; typedef uint16_t USHORT; typedef int32_t INT; typedef int32_t LONG; typedef uint32_t DWORD; typedef uint32_t ULONG; typedef uint32_t UINT; typedef uint64_t ULONGLONG; typedef int64_t LONGLONG; #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 #endif namespace BinaryInfoPlugin { struct IMAGE_DOS_HEADER { WORD e_magic; // "MZ" WORD e_cblp; WORD e_cp; WORD e_crlc; WORD e_cparhdr; WORD e_minalloc; WORD e_maxalloc; WORD e_ss; WORD e_sp; WORD e_csum; WORD e_ip; WORD e_cs; WORD e_lfarlc; WORD e_ovno; WORD e_res[4]; WORD e_oemid; WORD e_oeminfo; WORD e_res2[10]; LONG e_lfanew; }; struct IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; }; struct IMAGE_OPTIONAL_HEADER64 { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; ULONGLONG ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; ULONGLONG SizeOfStackReserve; ULONGLONG SizeOfStackCommit; ULONGLONG SizeOfHeapReserve; ULONGLONG SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; }; struct IMAGE_OPTIONAL_HEADER32 { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; }; struct IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; }; struct IMAGE_NT_HEADERS32 { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; }; struct IMAGE_NT_HEADERS64 { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER64 OptionalHeader; }; } #endif edb-debugger-1.0.0/plugins/BinaryInfo/DialogHeader.h0000644000175000017500000000236413273160654021560 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DIALOG_HEADER_20111128_H_ #define DIALOG_HEADER_20111128_H_ #include "Types.h" #include class QStringListModel; class QSortFilterProxyModel; class QModelIndex; namespace BinaryInfoPlugin { namespace Ui { class DialogHeader; } class DialogHeader : public QDialog { Q_OBJECT public: DialogHeader(QWidget *parent = 0); virtual ~DialogHeader(); public Q_SLOTS: void on_btnExplore_clicked(); private: virtual void showEvent(QShowEvent *event); private: Ui::DialogHeader *const ui; QSortFilterProxyModel *filter_model_; }; } #endif edb-debugger-1.0.0/plugins/BinaryInfo/BinaryInfo.h0000644000175000017500000000315113273160654021303 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef ELFBINARYINFO_20061122_H_ #define ELFBINARYINFO_20061122_H_ #include "IPlugin.h" #include "ISymbolGenerator.h" #include "Types.h" class QMenu; namespace BinaryInfoPlugin { class BinaryInfo : public QObject, public IPlugin, public ISymbolGenerator { Q_OBJECT Q_INTERFACES(IPlugin) #if QT_VERSION >= 0x050000 Q_PLUGIN_METADATA(IID "edb.IPlugin/1.0") #endif Q_CLASSINFO("author", "Evan Teran") Q_CLASSINFO("url", "http://www.codef00.com") public: BinaryInfo(); private: virtual void private_init() override; virtual QWidget* options_page() override; public: virtual QMenu *menu(QWidget *parent = 0) override; virtual QString extra_arguments() const override; virtual ArgumentStatus parse_arguments(QStringList &args) override; public: virtual bool generate_symbol_file(const QString &filename, const QString &symbol_file) override; public Q_SLOTS: void explore_header(); private: QMenu *menu_; }; } #endif edb-debugger-1.0.0/plugins/BinaryInfo/ELF32.cpp0000644000175000017500000000723113273160654020354 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "ELFXX.h" #include "ByteShiftArray.h" #include "IDebugger.h" #include "IProcess.h" #include "IRegion.h" #include "Util.h" #include "edb.h" #include "string_hash.h" #include #include #include #include namespace BinaryInfoPlugin { //------------------------------------------------------------------------------ // Name: nativ // Desc: returns true if this binary is native to the arch edb was built for //------------------------------------------------------------------------------ template<> bool ELF32::native() const { return edb::v1::debugger_core->cpu_type() == edb::string_hash("x86"); } //------------------------------------------------------------------------------ // Name: debug_pointer // Desc: attempts to locate the ELF debug pointer in the target process and // returns it, 0 of not found //------------------------------------------------------------------------------ template<> edb::address_t ELF32::debug_pointer() { if(IProcess *process = edb::v1::debugger_core->process()) { const edb::address_t section_offset = header_.e_phoff; const std::size_t count = header_.e_phnum; elf32_phdr section_header; for(std::size_t i = 0; i < count; ++i) { if(process->read_bytes(region_->start() + (section_offset + i * sizeof(elf32_phdr)), §ion_header, sizeof(elf32_phdr))) { if(section_header.p_type == PT_DYNAMIC) { try { QVector buf(section_header.p_memsz); if(process->read_bytes(section_header.p_vaddr, &buf[0], section_header.p_memsz)) { auto dynamic = reinterpret_cast(&buf[0]); while(dynamic->d_tag != DT_NULL) { if(dynamic->d_tag == DT_DEBUG) { return dynamic->d_un.d_val; } ++dynamic; } } } catch(const std::bad_alloc &) { qDebug() << "[ELF32::debug_pointer] no more memory"; return 0; } } } } } return 0; } //------------------------------------------------------------------------------ // Name: calculate_main // Desc: uses a heuristic to locate "main" //------------------------------------------------------------------------------ template<> edb::address_t ELF32::calculate_main() { edb::address_t entry_point = this->entry_point(); ByteShiftArray ba(11); if(IProcess *process = edb::v1::debugger_core->process()) { for(int i = 0; i < 50; ++i) { quint8 byte; if(process->read_bytes(entry_point + i, &byte, sizeof(byte))) { ba << byte; if(ba.size() >= 11) { // beginning of a call preceeded by a push and followed by a hlt if(ba[0] == 0x68 && ba[5] == 0xe8 && ba[10] == 0xf4) { edb::address_t address(0); std::memcpy(&address,ba.data() + 1,sizeof(uint32_t)); // TODO: make sure that this address resides in an executable region qDebug() << "No main symbol found, calculated it to be " << edb::v1::format_pointer(address) << " using heuristic"; return address; } } } else { break; } } } return 0; } } edb-debugger-1.0.0/plugins/BinaryInfo/OptionsPage.cpp0000644000175000017500000000360213273160654022027 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "OptionsPage.h" #include #include #include "demangle.h" #include "ui_OptionsPage.h" namespace BinaryInfoPlugin { OptionsPage::OptionsPage(QWidget* parent) : QWidget(parent), ui(new Ui::OptionsPage) { ui->setupUi(this); } OptionsPage::~OptionsPage() { delete ui; } void OptionsPage::showEvent(QShowEvent*) { QSettings settings; if(DEMANGLING_SUPPORTED) { ui->checkBox->setChecked(settings.value("BinaryInfo/demangling_enabled", true).toBool()); } else { ui->checkBox->setEnabled(false); ui->checkBox->setChecked(false); } ui->txtDebugDir->setText(settings.value("BinaryInfo/debug_info_path", "/usr/lib/debug").toString()); } void OptionsPage::on_checkBox_toggled(bool checked) { QSettings settings; settings.setValue("BinaryInfo/demangling_enabled", checked); } void OptionsPage::on_txtDebugDir_textChanged(const QString &text) { QSettings settings; settings.setValue("BinaryInfo/debug_info_path", text); } void OptionsPage::on_btnDebugDir_clicked() { QString dir = QFileDialog::getExistingDirectory( this, tr("Choose a directory"), QString(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if(!dir.isNull()) { ui->txtDebugDir->setText(dir); } } } edb-debugger-1.0.0/plugins/BinaryInfo/DialogHeader.cpp0000644000175000017500000004444313273160654022117 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "DialogHeader.h" #include "edb.h" #include "ELFXX.h" #include "MemoryRegions.h" #include "PE32.h" #include #include #include "ui_DialogHeader.h" namespace BinaryInfoPlugin { namespace { template QTreeWidgetItem *create_elf_magic(const T *header) { auto item = new QTreeWidgetItem; item->setText(0, QT_TRANSLATE_NOOP("BinaryInfo", "Magic")); item->setText(1, QString("0x%1, %2, %3, %4") .arg(header->e_ident[EI_MAG0], 0, 16) .arg(static_cast(header->e_ident[EI_MAG1])) .arg(static_cast(header->e_ident[EI_MAG2])) .arg(static_cast(header->e_ident[EI_MAG3])) ); return item; } template QTreeWidgetItem *create_elf_class(const T *header) { auto item = new QTreeWidgetItem; item->setText(0, QT_TRANSLATE_NOOP("BinaryInfo", "Class")); switch(header->e_ident[EI_CLASS]) { case ELFCLASS32: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "32-bit")); break; case ELFCLASS64: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "64-bit")); break; default: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Invalid")); break; } return item; } template QTreeWidgetItem *create_elf_data(const T *header) { auto item = new QTreeWidgetItem; item->setText(0, QT_TRANSLATE_NOOP("BinaryInfo", "Data")); switch(header->e_ident[EI_DATA]) { case ELFDATA2LSB: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "2's complement, little endian")); break; case ELFDATA2MSB: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "2's complement, big endian")); break; default: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Invalid")); break; } return item; } template QTreeWidgetItem *create_elf_version(const T *header) { auto item = new QTreeWidgetItem; item->setText(0, QT_TRANSLATE_NOOP("BinaryInfo", "Version")); switch(header->e_ident[EI_VERSION]) { case EV_CURRENT: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Current")); break; default: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Invalid")); break; } return item; } template QTreeWidgetItem *create_elf_abi(const T *header) { auto item = new QTreeWidgetItem; item->setText(0, QT_TRANSLATE_NOOP("BinaryInfo", "ABI")); switch(header->e_ident[EI_OSABI]) { case ELFOSABI_SYSV: //case ELFOSABI_NONE: // alias item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "UNIX System V ABI")); break; case ELFOSABI_HPUX: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "HP-UX")); break; case ELFOSABI_NETBSD: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "NetBSD")); break; case ELFOSABI_GNU: // case ELFOSABI_LINUX: // alias item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "GNU/Linux")); break; case ELFOSABI_SOLARIS: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Sun Solaris")); break; case ELFOSABI_AIX: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "IBM AIX")); break; case ELFOSABI_IRIX: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "SGI Irix")); break; case ELFOSABI_FREEBSD: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "FreeBSD")); break; case ELFOSABI_TRU64: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Compaq TRU64 UNIX")); break; case ELFOSABI_MODESTO: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Novell Modesto")); break; case ELFOSABI_OPENBSD: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "OpenBSD")); break; case ELFOSABI_ARM_AEABI: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "ARM EABI")); break; case ELFOSABI_ARM: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "ARM")); break; case ELFOSABI_STANDALONE: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Standalone (embedded) application")); break; default: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Invalid")); break; } return item; } template QTreeWidgetItem *create_elf_abi_version(const T *header) { auto item = new QTreeWidgetItem; item->setText(0, QT_TRANSLATE_NOOP("BinaryInfo", "ABI Version")); item->setText(1, QString("%1").arg(header->e_ident[EI_MAG0], 0, 10)); return item; } template QTreeWidgetItem *create_elf_type(const T *header) { auto item = new QTreeWidgetItem; item->setText(0, QT_TRANSLATE_NOOP("BinaryInfo", "Type")); switch(header->e_type) { case ET_NONE: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "No file type")); break; case ET_REL: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Relocatable file")); break; case ET_EXEC: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Executable file")); break; case ET_DYN: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Shared object file")); break; case ET_CORE: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Core file")); break; default: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "")); break; } return item; } template QTreeWidgetItem *create_elf_machine(const T *header) { auto item = new QTreeWidgetItem; item->setText(0, QT_TRANSLATE_NOOP("BinaryInfo", "Machine")); switch(header->e_machine) { case EM_NONE: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "No machine")); break; case EM_M32: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "AT&T WE 32100")); break; case EM_SPARC: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "SUN SPARC")); break; case EM_386: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Intel 80386")); break; case EM_68K: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Motorola m68k family")); break; case EM_88K: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Motorola m88k family")); break; case EM_860: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Intel 80860")); break; case EM_MIPS: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "MIPS R3000 big-endian")); break; case EM_S370: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "IBM System/370")); break; case EM_MIPS_RS3_LE: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "MIPS R3000 little-endian")); break; case EM_PARISC: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "HPPA")); break; case EM_VPP500: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Fujitsu VPP500")); break; case EM_SPARC32PLUS: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Sun's \"v8plus\"")); break; case EM_960: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Intel 80960")); break; case EM_PPC: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "PowerPC")); break; case EM_PPC64: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "PowerPC 64-bit")); break; case EM_S390: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "IBM S390")); break; case EM_V800: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "NEC V800 series")); break; case EM_FR20: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Fujitsu FR20")); break; case EM_RH32: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "TRW RH-32")); break; case EM_RCE: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Motorola RCE")); break; case EM_ARM: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "ARM")); break; case EM_FAKE_ALPHA: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Digital Alpha")); break; case EM_SH: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Hitachi SH")); break; case EM_SPARCV9: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "SPARC v9 64-bit")); break; case EM_TRICORE: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Siemens Tricore")); break; case EM_ARC: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Argonaut RISC Core")); break; case EM_H8_300: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Hitachi H8/300")); break; case EM_H8_300H: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Hitachi H8/300H")); break; case EM_H8S: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Hitachi H8S")); break; case EM_H8_500: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Hitachi H8/500")); break; case EM_IA_64: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Intel Merced")); break; case EM_MIPS_X: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Stanford MIPS-X")); break; case EM_COLDFIRE: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Motorola Coldfire")); break; case EM_68HC12: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Motorola M68HC12")); break; case EM_MMA: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Fujitsu MMA Multimedia Accelerator")); break; case EM_PCP: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Siemens PCP")); break; case EM_NCPU: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Sony nCPU embeeded RISC")); break; case EM_NDR1: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Denso NDR1 microprocessor")); break; case EM_STARCORE: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Motorola Start*Core processor")); break; case EM_ME16: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Toyota ME16 processor")); break; case EM_ST100: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "STMicroelectronic ST100 processor")); break; case EM_TINYJ: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Advanced Logic Corp. Tinyj emb.fam")); break; case EM_X86_64: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "AMD x86-64 architecture")); break; case EM_PDSP: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Sony DSP Processor")); break; case EM_FX66: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Siemens FX66 microcontroller")); break; case EM_ST9PLUS: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "STMicroelectronics ST9+ 8/16 mc")); break; case EM_ST7: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "STmicroelectronics ST7 8 bit mc")); break; case EM_68HC16: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Motorola MC68HC16 microcontroller")); break; case EM_68HC11: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Motorola MC68HC11 microcontroller")); break; case EM_68HC08: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Motorola MC68HC08 microcontroller")); break; case EM_68HC05: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Motorola MC68HC05 microcontroller")); break; case EM_SVX: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Silicon Graphics SVx")); break; case EM_ST19: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "STMicroelectronics ST19 8 bit mc")); break; case EM_VAX: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Digital VAX")); break; case EM_CRIS: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Axis Communications 32-bit embedded processor")); break; case EM_JAVELIN: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Infineon Technologies 32-bit embedded processor")); break; case EM_FIREPATH: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Element 14 64-bit DSP Processor")); break; case EM_ZSP: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "LSI Logic 16-bit DSP Processor")); break; case EM_MMIX: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Donald Knuth's educational 64-bit processor")); break; case EM_HUANY: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Harvard University machine-independent object files")); break; case EM_PRISM: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "SiTera Prism")); break; case EM_AVR: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Atmel AVR 8-bit microcontroller")); break; case EM_FR30: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Fujitsu FR30")); break; case EM_D10V: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Mitsubishi D10V")); break; case EM_D30V: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Mitsubishi D30V")); break; case EM_V850: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "NEC v850")); break; case EM_M32R: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Mitsubishi M32R")); break; case EM_MN10300: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Matsushita MN10300")); break; case EM_MN10200: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Matsushita MN10200")); break; case EM_PJ: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "picoJava")); break; case EM_OPENRISC: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "OpenRISC 32-bit embedded processor")); break; case EM_ARC_A5: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "ARC Cores Tangent-A5")); break; case EM_XTENSA: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Tensilica Xtensa Architecture")); break; default: item->setText(1, QT_TRANSLATE_NOOP("BinaryInfo", "Unknown")); break; } return item; } template QTreeWidgetItem *create_elf_object_version(const T *header) { auto item = new QTreeWidgetItem; item->setText(0, QT_TRANSLATE_NOOP("BinaryInfo", "Object File Version")); item->setText(1, QString("%1").arg(header->e_version, 0, 10)); return item; } template QTreeWidgetItem *create_elf_entry_point(const T *header) { auto item = new QTreeWidgetItem; item->setText(0, QT_TRANSLATE_NOOP("BinaryInfo", "Entry Point")); item->setText(1, QString("%1").arg(header->e_entry, 0, 16)); return item; } #if 0 elf32_off e_phoff; /* Program header table file offset */ elf32_off e_shoff; /* Section header table file offset */ elf32_word e_flags; /* Processor-specific flags */ elf32_half e_ehsize; /* ELF header size in bytes */ elf32_half e_phentsize; /* Program header table entry size */ elf32_half e_phnum; /* Program header table entry count */ elf32_half e_shentsize; /* Section header table entry size */ elf32_half e_shnum; /* Section header table entry count */ elf32_half e_shstrndx; /* Section header string table index */ #endif } //------------------------------------------------------------------------------ // Name: DialogHeader // Desc: //------------------------------------------------------------------------------ DialogHeader::DialogHeader(QWidget *parent) : QDialog(parent), ui(new Ui::DialogHeader) { ui->setupUi(this); ui->tableView->verticalHeader()->hide(); #if QT_VERSION >= 0x050000 ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); #else ui->tableView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents); #endif filter_model_ = new QSortFilterProxyModel(this); connect(ui->txtSearch, SIGNAL(textChanged(const QString &)), filter_model_, SLOT(setFilterFixedString(const QString &))); } //------------------------------------------------------------------------------ // Name: ~DialogHeader // Desc: //------------------------------------------------------------------------------ DialogHeader::~DialogHeader() { delete ui; } //------------------------------------------------------------------------------ // Name: showEvent // Desc: //------------------------------------------------------------------------------ void DialogHeader::showEvent(QShowEvent *) { filter_model_->setFilterKeyColumn(3); filter_model_->setSourceModel(&edb::v1::memory_regions()); ui->tableView->setModel(filter_model_); ui->treeWidget->clear(); } //------------------------------------------------------------------------------ // Name: on_btnExplore_clicked // Desc: //------------------------------------------------------------------------------ void DialogHeader::on_btnExplore_clicked() { ui->treeWidget->clear(); const QItemSelectionModel *const selModel = ui->tableView->selectionModel(); const QModelIndexList sel = selModel->selectedRows(); if(sel.size() == 0) { QMessageBox::critical( this, tr("No Region Selected"), tr("You must select a region which is to be scanned for executable headers.")); } else { for(const QModelIndex &selected_item: sel) { const QModelIndex index = filter_model_->mapToSource(selected_item); if(auto region = *reinterpret_cast *>(index.internalPointer())) { if(auto binary_info = edb::v1::get_binary_info(region)) { if(auto elf32 = dynamic_cast(binary_info.get())) { auto header = reinterpret_cast(elf32->header()); auto root = new QTreeWidgetItem; root->setText(0, tr("ELF32")); root->addChild(create_elf_magic(header)); root->addChild(create_elf_class(header)); root->addChild(create_elf_data(header)); root->addChild(create_elf_version(header)); root->addChild(create_elf_abi(header)); root->addChild(create_elf_abi_version(header)); root->addChild(create_elf_type(header)); root->addChild(create_elf_machine(header)); root->addChild(create_elf_object_version(header)); root->addChild(create_elf_entry_point(header)); ui->treeWidget->insertTopLevelItem(0, root); } if(auto elf64 = dynamic_cast(binary_info.get())) { auto header = reinterpret_cast(elf64->header()); auto root = new QTreeWidgetItem; root->setText(0, tr("ELF64")); root->addChild(create_elf_magic(header)); root->addChild(create_elf_class(header)); root->addChild(create_elf_data(header)); root->addChild(create_elf_version(header)); root->addChild(create_elf_abi(header)); root->addChild(create_elf_abi_version(header)); root->addChild(create_elf_type(header)); root->addChild(create_elf_machine(header)); root->addChild(create_elf_object_version(header)); root->addChild(create_elf_entry_point(header)); ui->treeWidget->insertTopLevelItem(0, root); } if(auto pe32 = dynamic_cast(binary_info.get())) { Q_UNUSED(pe32); #if 0 auto header = reinterpret_cast(pe32->header()); #endif auto root = new QTreeWidgetItem; root->setText(0, tr("PE32")); ui->treeWidget->insertTopLevelItem(0, root); } } } } } } } edb-debugger-1.0.0/plugins/BinaryInfo/CMakeLists.txt0000644000175000017500000000217213273160654021634 0ustar eteraneterancmake_minimum_required (VERSION 2.8) include("GNUInstallDirs") set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) include("${PROJECT_SOURCE_DIR}/cmake/EnableCXX11.cmake") set(PluginName "BinaryInfo") set(UI_FILES OptionsPage.ui DialogHeader.ui) if(Qt5Core_FOUND) find_package(Qt5 5.0.0 REQUIRED Widgets) qt5_wrap_ui(UI_H ${UI_FILES}) else(Qt5Core_FOUND) find_package(Qt4 4.6.0 QUIET REQUIRED QtCore QtGui) include(${QT_USE_FILE}) qt4_wrap_ui(UI_H ${UI_FILES}) endif() # we put the header files from the include directory here # too so automoc can "just work" add_library(${PluginName} SHARED BinaryInfo.cpp BinaryInfo.h demangle.h DialogHeader.cpp DialogHeader.h ELFXX.cpp ELF32.cpp ELF64.cpp elf_binary.h OptionsPage.cpp OptionsPage.h PE32.cpp PE32.h pe_binary.h symbols.cpp symbols.h ${UI_H} ) if(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt5::Widgets) else(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt4::QtGui) endif() set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}) install (TARGETS ${PluginName} DESTINATION ${CMAKE_INSTALL_LIBDIR}/edb) edb-debugger-1.0.0/plugins/BinaryInfo/elf_binary.h0000644000175000017500000022371013273160654021362 0ustar eteraneteran/* Copyright (C) 2012 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_BINARY_20121007_H_ #define ELF_BINARY_20121007_H_ namespace BinaryInfoPlugin { #include "elf/elf_types.h" #include "elf/elf_header.h" #include "elf/elf_shdr.h" #include "elf/elf_sym.h" #include "elf/elf_syminfo.h" #include "elf/elf_rel.h" #include "elf/elf_rela.h" #include "elf/elf_phdr.h" #include "elf/elf_dyn.h" #include "elf/elf_verdef.h" #include "elf/elf_verdaux.h" #include "elf/elf_verneed.h" #include "elf/elf_vernaux.h" #include "elf/elf_auxv.h" #include "elf/elf_nhdr.h" #include "elf/elf_move.h" /* Motorola 68k specific definitions. */ /* Values for Elf32_Ehdr.e_flags. */ #define EF_CPU32 0x00810000 /* m68k relocs. */ #define R_68K_NONE 0 /* No reloc */ #define R_68K_32 1 /* Direct 32 bit */ #define R_68K_16 2 /* Direct 16 bit */ #define R_68K_8 3 /* Direct 8 bit */ #define R_68K_PC32 4 /* PC relative 32 bit */ #define R_68K_PC16 5 /* PC relative 16 bit */ #define R_68K_PC8 6 /* PC relative 8 bit */ #define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ #define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ #define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ #define R_68K_GOT32O 10 /* 32 bit GOT offset */ #define R_68K_GOT16O 11 /* 16 bit GOT offset */ #define R_68K_GOT8O 12 /* 8 bit GOT offset */ #define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ #define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ #define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ #define R_68K_PLT32O 16 /* 32 bit PLT offset */ #define R_68K_PLT16O 17 /* 16 bit PLT offset */ #define R_68K_PLT8O 18 /* 8 bit PLT offset */ #define R_68K_COPY 19 /* Copy symbol at runtime */ #define R_68K_GLOB_DAT 20 /* Create GOT entry */ #define R_68K_JMP_SLOT 21 /* Create PLT entry */ #define R_68K_RELATIVE 22 /* Adjust by program base */ #define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ #define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ #define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ #define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ #define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ #define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ #define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ #define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ #define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ #define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ #define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ #define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ #define R_68K_TLS_LE32 37 /* 32 bit offset relative to static TLS block */ #define R_68K_TLS_LE16 38 /* 16 bit offset relative to static TLS block */ #define R_68K_TLS_LE8 39 /* 8 bit offset relative to static TLS block */ #define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ #define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ #define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ /* Keep this the last entry. */ #define R_68K_NUM 43 /* Intel 80386 specific definitions. */ /* i386 relocs. */ #define R_386_NONE 0 /* No reloc */ #define R_386_32 1 /* Direct 32 bit */ #define R_386_PC32 2 /* PC relative 32 bit */ #define R_386_GOT32 3 /* 32 bit GOT entry */ #define R_386_PLT32 4 /* 32 bit PLT address */ #define R_386_COPY 5 /* Copy symbol at runtime */ #define R_386_GLOB_DAT 6 /* Create GOT entry */ #define R_386_JMP_SLOT 7 /* Create PLT entry */ #define R_386_RELATIVE 8 /* Adjust by program base */ #define R_386_GOTOFF 9 /* 32 bit offset to GOT */ #define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ #define R_386_32PLT 11 #define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ #define R_386_TLS_IE 15 /* Address of GOT entry for static TLS block offset */ #define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block offset */ #define R_386_TLS_LE 17 /* Offset relative to static TLS block */ #define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of general dynamic thread local data */ #define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of local dynamic thread local data in LE code */ #define R_386_16 20 #define R_386_PC16 21 #define R_386_8 22 #define R_386_PC8 23 #define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic thread local data */ #define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ #define R_386_TLS_GD_CALL 26 /* Relocation for call to __tls_get_addr() */ #define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ #define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic thread local data in LE code */ #define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ #define R_386_TLS_LDM_CALL 30 /* Relocation for call to __tls_get_addr() in LDM code */ #define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ #define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ #define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS block offset */ #define R_386_TLS_LE_32 34 /* Negated offset relative to static TLS block */ #define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ #define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ #define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ /* 38? */ #define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ #define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS descriptor for relaxation. */ #define R_386_TLS_DESC 41 /* TLS descriptor containing pointer to code and to argument, returning the TLS offset for the symbol. */ #define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ /* Keep this the last entry. */ #define R_386_NUM 43 /* SUN SPARC specific definitions. */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ /* Values for Elf64_Ehdr.e_flags. */ #define EF_SPARCV9_MM 3 #define EF_SPARCV9_TSO 0 #define EF_SPARCV9_PSO 1 #define EF_SPARCV9_RMO 2 #define EF_SPARC_LEDATA 0x800000 /* little endian data */ #define EF_SPARC_EXT_MASK 0xFFFF00 #define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ #define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ #define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ #define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ /* SPARC relocs. */ #define R_SPARC_NONE 0 /* No reloc */ #define R_SPARC_8 1 /* Direct 8 bit */ #define R_SPARC_16 2 /* Direct 16 bit */ #define R_SPARC_32 3 /* Direct 32 bit */ #define R_SPARC_DISP8 4 /* PC relative 8 bit */ #define R_SPARC_DISP16 5 /* PC relative 16 bit */ #define R_SPARC_DISP32 6 /* PC relative 32 bit */ #define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ #define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ #define R_SPARC_HI22 9 /* High 22 bit */ #define R_SPARC_22 10 /* Direct 22 bit */ #define R_SPARC_13 11 /* Direct 13 bit */ #define R_SPARC_LO10 12 /* Truncated 10 bit */ #define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ #define R_SPARC_GOT13 14 /* 13 bit GOT entry */ #define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ #define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ #define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ #define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ #define R_SPARC_COPY 19 /* Copy symbol at runtime */ #define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ #define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ #define R_SPARC_RELATIVE 22 /* Adjust by program base */ #define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ /* Additional Sparc64 relocs. */ #define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ #define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ #define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ #define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ #define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ #define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ #define R_SPARC_10 30 /* Direct 10 bit */ #define R_SPARC_11 31 /* Direct 11 bit */ #define R_SPARC_64 32 /* Direct 64 bit */ #define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ #define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ #define R_SPARC_HM10 35 /* High middle 10 bits of ... */ #define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ #define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ #define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ #define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ #define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ #define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ #define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ #define R_SPARC_7 43 /* Direct 7 bit */ #define R_SPARC_5 44 /* Direct 5 bit */ #define R_SPARC_6 45 /* Direct 6 bit */ #define R_SPARC_DISP64 46 /* PC relative 64 bit */ #define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ #define R_SPARC_HIX22 48 /* High 22 bit complemented */ #define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ #define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ #define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ #define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ #define R_SPARC_REGISTER 53 /* Global register usage */ #define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ #define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ #define R_SPARC_TLS_GD_HI22 56 #define R_SPARC_TLS_GD_LO10 57 #define R_SPARC_TLS_GD_ADD 58 #define R_SPARC_TLS_GD_CALL 59 #define R_SPARC_TLS_LDM_HI22 60 #define R_SPARC_TLS_LDM_LO10 61 #define R_SPARC_TLS_LDM_ADD 62 #define R_SPARC_TLS_LDM_CALL 63 #define R_SPARC_TLS_LDO_HIX22 64 #define R_SPARC_TLS_LDO_LOX10 65 #define R_SPARC_TLS_LDO_ADD 66 #define R_SPARC_TLS_IE_HI22 67 #define R_SPARC_TLS_IE_LO10 68 #define R_SPARC_TLS_IE_LD 69 #define R_SPARC_TLS_IE_LDX 70 #define R_SPARC_TLS_IE_ADD 71 #define R_SPARC_TLS_LE_HIX22 72 #define R_SPARC_TLS_LE_LOX10 73 #define R_SPARC_TLS_DTPMOD32 74 #define R_SPARC_TLS_DTPMOD64 75 #define R_SPARC_TLS_DTPOFF32 76 #define R_SPARC_TLS_DTPOFF64 77 #define R_SPARC_TLS_TPOFF32 78 #define R_SPARC_TLS_TPOFF64 79 #define R_SPARC_GOTDATA_HIX22 80 #define R_SPARC_GOTDATA_LOX10 81 #define R_SPARC_GOTDATA_OP_HIX22 82 #define R_SPARC_GOTDATA_OP_LOX10 83 #define R_SPARC_GOTDATA_OP 84 #define R_SPARC_H34 85 #define R_SPARC_SIZE32 86 #define R_SPARC_SIZE64 87 #define R_SPARC_JMP_IREL 248 #define R_SPARC_IRELATIVE 249 #define R_SPARC_GNU_VTINHERIT 250 #define R_SPARC_GNU_VTENTRY 251 #define R_SPARC_REV32 252 /* Keep this the last entry. */ #define R_SPARC_NUM 253 /* For Sparc64, legal values for d_tag of Elf64_Dyn. */ #define DT_SPARC_REGISTER 0x70000001 #define DT_SPARC_NUM 2 /* MIPS R3000 specific definitions. */ /* Legal values for e_flags field of Elf32_Ehdr. */ #define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ #define EF_MIPS_PIC 2 /* Contains PIC code */ #define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ #define EF_MIPS_XGOT 8 #define EF_MIPS_64BIT_WHIRL 16 #define EF_MIPS_ABI2 32 #define EF_MIPS_ABI_ON32 64 #define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ /* Legal values for MIPS architecture level. */ #define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ #define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ #define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ #define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ #define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ #define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ #define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ /* The following are non-official names and should not be used. */ #define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ #define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ #define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ #define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ #define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ #define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ #define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ /* Special section indices. */ #define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ #define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ #define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ #define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ #define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ /* Legal values for sh_type field of Elf32_Shdr. */ #define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ #define SHT_MIPS_MSYM 0x70000001 #define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ #define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ #define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ #define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ #define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ #define SHT_MIPS_PACKAGE 0x70000007 #define SHT_MIPS_PACKSYM 0x70000008 #define SHT_MIPS_RELD 0x70000009 #define SHT_MIPS_IFACE 0x7000000b #define SHT_MIPS_CONTENT 0x7000000c #define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ #define SHT_MIPS_SHDR 0x70000010 #define SHT_MIPS_FDESC 0x70000011 #define SHT_MIPS_EXTSYM 0x70000012 #define SHT_MIPS_DENSE 0x70000013 #define SHT_MIPS_PDESC 0x70000014 #define SHT_MIPS_LOCSYM 0x70000015 #define SHT_MIPS_AUXSYM 0x70000016 #define SHT_MIPS_OPTSYM 0x70000017 #define SHT_MIPS_LOCSTR 0x70000018 #define SHT_MIPS_LINE 0x70000019 #define SHT_MIPS_RFDESC 0x7000001a #define SHT_MIPS_DELTASYM 0x7000001b #define SHT_MIPS_DELTAINST 0x7000001c #define SHT_MIPS_DELTACLASS 0x7000001d #define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ #define SHT_MIPS_DELTADECL 0x7000001f #define SHT_MIPS_SYMBOL_LIB 0x70000020 #define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ #define SHT_MIPS_TRANSLATE 0x70000022 #define SHT_MIPS_PIXIE 0x70000023 #define SHT_MIPS_XLATE 0x70000024 #define SHT_MIPS_XLATE_DEBUG 0x70000025 #define SHT_MIPS_WHIRL 0x70000026 #define SHT_MIPS_EH_REGION 0x70000027 #define SHT_MIPS_XLATE_OLD 0x70000028 #define SHT_MIPS_PDR_EXCEPTION 0x70000029 /* Legal values for sh_flags field of Elf32_Shdr. */ #define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ #define SHF_MIPS_MERGE 0x20000000 #define SHF_MIPS_ADDR 0x40000000 #define SHF_MIPS_STRINGS 0x80000000 #define SHF_MIPS_NOSTRIP 0x08000000 #define SHF_MIPS_LOCAL 0x04000000 #define SHF_MIPS_NAMES 0x02000000 #define SHF_MIPS_NODUPE 0x01000000 /* Symbol tables. */ /* MIPS specific values for `st_other'. */ #define STO_MIPS_DEFAULT 0x0 #define STO_MIPS_INTERNAL 0x1 #define STO_MIPS_HIDDEN 0x2 #define STO_MIPS_PROTECTED 0x3 #define STO_MIPS_PLT 0x8 #define STO_MIPS_SC_ALIGN_UNUSED 0xff /* MIPS specific values for `st_info'. */ #define STB_MIPS_SPLIT_COMMON 13 /* Entries found in sections of type SHT_MIPS_GPTAB. */ union elf32_gptab { struct { elf32_word gt_current_g_value; /* -G value used for compilation */ elf32_word gt_unused; /* Not used */ } gt_header; /* First entry in section */ struct { elf32_word gt_g_value; /* If this value were used for -G */ elf32_word gt_bytes; /* This many bytes would be used */ } gt_entry; /* Subsequent entries in section */ }; /* Entry found in sections of type SHT_MIPS_REGINFO. */ struct elf32_reginfo { elf32_word ri_gprmask; /* General registers used */ elf32_word ri_cprmask[4]; /* Coprocessor registers used */ elf32_sword ri_gp_value; /* $gp register value */ }; /* Entries found in sections of type SHT_MIPS_OPTIONS. */ struct elf_options { unsigned char kind; /* Determines interpretation of the variable part of descriptor. */ unsigned char size; /* Size of descriptor, including header. */ elf32_section section; /* Section header index of section affected, 0 for global options. */ elf32_word info; /* Kind-specific information. */ }; /* Values for `kind' field in Elf_Options. */ #define ODK_NULL 0 /* Undefined. */ #define ODK_REGINFO 1 /* Register usage information. */ #define ODK_EXCEPTIONS 2 /* Exception processing options. */ #define ODK_PAD 3 /* Section padding options. */ #define ODK_HWPATCH 4 /* Hardware workarounds performed */ #define ODK_FILL 5 /* record the fill value used by the linker. */ #define ODK_TAGS 6 /* reserve space for desktop tools to write. */ #define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ #define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ /* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ #define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ #define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ #define OEX_PAGE0 0x10000 /* page zero must be mapped. */ #define OEX_SMM 0x20000 /* Force sequential memory mode? */ #define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ #define OEX_PRECISEFP OEX_FPDBUG #define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ #define OEX_FPU_INVAL 0x10 #define OEX_FPU_DIV0 0x08 #define OEX_FPU_OFLO 0x04 #define OEX_FPU_UFLO 0x02 #define OEX_FPU_INEX 0x01 /* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ #define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ #define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ #define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ #define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ #define OPAD_PREFIX 0x1 #define OPAD_POSTFIX 0x2 #define OPAD_SYMBOL 0x4 /* Entry found in `.options' section. */ struct elf_options_hw { elf32_word hwp_flags1; /* Extra flags. */ elf32_word hwp_flags2; /* Extra flags. */ }; /* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ #define OHWA0_R4KEOP_CHECKED 0x00000001 #define OHWA1_R4KEOP_CLEAN 0x00000002 /* MIPS relocs. */ #define R_MIPS_NONE 0 /* No reloc */ #define R_MIPS_16 1 /* Direct 16 bit */ #define R_MIPS_32 2 /* Direct 32 bit */ #define R_MIPS_REL32 3 /* PC relative 32 bit */ #define R_MIPS_26 4 /* Direct 26 bit shifted */ #define R_MIPS_HI16 5 /* High 16 bit */ #define R_MIPS_LO16 6 /* Low 16 bit */ #define R_MIPS_GPREL16 7 /* GP relative 16 bit */ #define R_MIPS_LITERAL 8 /* 16 bit literal entry */ #define R_MIPS_GOT16 9 /* 16 bit GOT entry */ #define R_MIPS_PC16 10 /* PC relative 16 bit */ #define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ #define R_MIPS_GPREL32 12 /* GP relative 32 bit */ #define R_MIPS_SHIFT5 16 #define R_MIPS_SHIFT6 17 #define R_MIPS_64 18 #define R_MIPS_GOT_DISP 19 #define R_MIPS_GOT_PAGE 20 #define R_MIPS_GOT_OFST 21 #define R_MIPS_GOT_HI16 22 #define R_MIPS_GOT_LO16 23 #define R_MIPS_SUB 24 #define R_MIPS_INSERT_A 25 #define R_MIPS_INSERT_B 26 #define R_MIPS_DELETE 27 #define R_MIPS_HIGHER 28 #define R_MIPS_HIGHEST 29 #define R_MIPS_CALL_HI16 30 #define R_MIPS_CALL_LO16 31 #define R_MIPS_SCN_DISP 32 #define R_MIPS_REL16 33 #define R_MIPS_ADD_IMMEDIATE 34 #define R_MIPS_PJUMP 35 #define R_MIPS_RELGOT 36 #define R_MIPS_JALR 37 #define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ #define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ #define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ #define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ #define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ #define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ #define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ #define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ #define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ #define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ #define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ #define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ #define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ #define R_MIPS_GLOB_DAT 51 #define R_MIPS_COPY 126 #define R_MIPS_JUMP_SLOT 127 /* Keep this the last entry. */ #define R_MIPS_NUM 128 /* Legal values for p_type field of Elf32_Phdr. */ #define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ #define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ #define PT_MIPS_OPTIONS 0x70000002 /* Special program header types. */ #define PF_MIPS_LOCAL 0x10000000 /* Legal values for d_tag field of Elf32_Dyn. */ #define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ #define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ #define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ #define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ #define DT_MIPS_FLAGS 0x70000005 /* Flags */ #define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ #define DT_MIPS_MSYM 0x70000007 #define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ #define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ #define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ #define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ #define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ #define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ #define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ #define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ #define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ #define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ #define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ #define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in DT_MIPS_DELTA_CLASS. */ #define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ #define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in DT_MIPS_DELTA_INSTANCE. */ #define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ #define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in DT_MIPS_DELTA_RELOC. */ #define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta relocations refer to. */ #define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in DT_MIPS_DELTA_SYM. */ #define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the class declaration. */ #define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in DT_MIPS_DELTA_CLASSSYM. */ #define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ #define DT_MIPS_PIXIE_INIT 0x70000023 #define DT_MIPS_SYMBOL_LIB 0x70000024 #define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 #define DT_MIPS_LOCAL_GOTIDX 0x70000026 #define DT_MIPS_HIDDEN_GOTIDX 0x70000027 #define DT_MIPS_PROTECTED_GOTIDX 0x70000028 #define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ #define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ #define DT_MIPS_DYNSTR_ALIGN 0x7000002b #define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ #define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve function stored in GOT. */ #define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added by rld on dlopen() calls. */ #define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ #define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ #define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ /* The address of .got.plt in an executable using the new non-PIC ABI. */ #define DT_MIPS_PLTGOT 0x70000032 /* The base of the PLT in an executable using the new non-PIC ABI if that PLT is writable. For a non-writable PLT, this is omitted or has a zero value. */ #define DT_MIPS_RWPLT 0x70000034 #define DT_MIPS_NUM 0x35 /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ #define RHF_NONE 0 /* No flags */ #define RHF_QUICKSTART (1 << 0) /* Use quickstart */ #define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ #define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ #define RHF_NO_MOVE (1 << 3) #define RHF_SGI_ONLY (1 << 4) #define RHF_GUARANTEE_INIT (1 << 5) #define RHF_DELTA_C_PLUS_PLUS (1 << 6) #define RHF_GUARANTEE_START_INIT (1 << 7) #define RHF_PIXIE (1 << 8) #define RHF_DEFAULT_DELAY_LOAD (1 << 9) #define RHF_REQUICKSTART (1 << 10) #define RHF_REQUICKSTARTED (1 << 11) #define RHF_CORD (1 << 12) #define RHF_NO_UNRES_UNDEF (1 << 13) #define RHF_RLD_ORDER_SAFE (1 << 14) /* Entries found in sections of type SHT_MIPS_LIBLIST. */ struct elf32_lib { elf32_word l_name; /* Name (string table index) */ elf32_word l_time_stamp; /* Timestamp */ elf32_word l_checksum; /* Checksum */ elf32_word l_version; /* Interface version */ elf32_word l_flags; /* Flags */ }; struct elf64_lib { elf64_word l_name; /* Name (string table index) */ elf64_word l_time_stamp; /* Timestamp */ elf64_word l_checksum; /* Checksum */ elf64_word l_version; /* Interface version */ elf64_word l_flags; /* Flags */ }; /* Legal values for l_flags. */ #define LL_NONE 0 #define LL_EXACT_MATCH (1 << 0) /* Require exact match */ #define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ #define LL_REQUIRE_MINOR (1 << 2) #define LL_EXPORTS (1 << 3) #define LL_DELAY_LOAD (1 << 4) #define LL_DELTA (1 << 5) /* Entries found in sections of type SHT_MIPS_CONFLICT. */ typedef elf32_addr elf32_conflict; #if 0 /* HPPA specific definitions. */ /* Legal values for e_flags field of Elf32_Ehdr. */ #define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ #define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ #define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ #define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ #define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch prediction. */ #define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ #define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ /* Defined values for `e_flags & EF_PARISC_ARCH' are: */ #define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ #define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ #define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ /* Additional section indeces. */ #define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared symbols in ANSI C. */ #define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ /* Legal values for sh_type field of Elf32_Shdr. */ #define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ #define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ #define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ /* Legal values for sh_flags field of Elf32_Shdr. */ #define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ #define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ #define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ #define STT_HP_OPAQUE (STT_LOOS + 0x1) #define STT_HP_STUB (STT_LOOS + 0x2) /* HPPA relocs. */ #define R_PARISC_NONE 0 /* No reloc. */ #define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ #define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ #define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ #define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ #define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ #define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ #define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ #define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ #define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ #define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ #define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ #define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ #define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ #define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ #define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ #define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ #define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ #define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ #define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ #define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ #define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ #define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ #define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ #define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ #define R_PARISC_FPTR64 64 /* 64 bits function address. */ #define R_PARISC_PLABEL32 65 /* 32 bits function address. */ #define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ #define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ #define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ #define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ #define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ #define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ #define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ #define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ #define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ #define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ #define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ #define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ #define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ #define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ #define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ #define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ #define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ #define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ #define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ #define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ #define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ #define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ #define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ #define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ #define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ #define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ #define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ #define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ #define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ #define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ #define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ #define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ #define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ #define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ #define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ #define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ #define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ #define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ #define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ #define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ #define R_PARISC_LORESERVE 128 #define R_PARISC_COPY 128 /* Copy relocation. */ #define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ #define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ #define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ #define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ #define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ #define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ #define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ #define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ #define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ #define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ #define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ #define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ #define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ #define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ #define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ #define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ #define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ #define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ #define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ #define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ #define R_PARISC_GNU_VTENTRY 232 #define R_PARISC_GNU_VTINHERIT 233 #define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ #define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ #define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ #define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ #define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ #define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ #define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ #define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ #define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ #define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ #define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ #define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ #define R_PARISC_TLS_LE21L R_PARISC_TPREL21L #define R_PARISC_TLS_LE14R R_PARISC_TPREL14R #define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L #define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R #define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 #define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 #define R_PARISC_HIRESERVE 255 /* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ #define PT_HP_TLS (PT_LOOS + 0x0) #define PT_HP_CORE_NONE (PT_LOOS + 0x1) #define PT_HP_CORE_VERSION (PT_LOOS + 0x2) #define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) #define PT_HP_CORE_COMM (PT_LOOS + 0x4) #define PT_HP_CORE_PROC (PT_LOOS + 0x5) #define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) #define PT_HP_CORE_STACK (PT_LOOS + 0x7) #define PT_HP_CORE_SHM (PT_LOOS + 0x8) #define PT_HP_CORE_MMF (PT_LOOS + 0x9) #define PT_HP_PARALLEL (PT_LOOS + 0x10) #define PT_HP_FASTBIND (PT_LOOS + 0x11) #define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) #define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) #define PT_HP_STACK (PT_LOOS + 0x14) #define PT_PARISC_ARCHEXT 0x70000000 #define PT_PARISC_UNWIND 0x70000001 /* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ #define PF_PARISC_SBP 0x08000000 #define PF_HP_PAGE_SIZE 0x00100000 #define PF_HP_FAR_SHARED 0x00200000 #define PF_HP_NEAR_SHARED 0x00400000 #define PF_HP_CODE 0x01000000 #define PF_HP_MODIFY 0x02000000 #define PF_HP_LAZYSWAP 0x04000000 #define PF_HP_SBP 0x08000000 /* Alpha specific definitions. */ /* Legal values for e_flags field of Elf64_Ehdr. */ #define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ #define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ /* Legal values for sh_type field of Elf64_Shdr. */ /* These two are primerily concerned with ECOFF debugging info. */ #define SHT_ALPHA_DEBUG 0x70000001 #define SHT_ALPHA_REGINFO 0x70000002 /* Legal values for sh_flags field of Elf64_Shdr. */ #define SHF_ALPHA_GPREL 0x10000000 /* Legal values for st_other field of Elf64_Sym. */ #define STO_ALPHA_NOPV 0x80 /* No PV required. */ #define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ /* Alpha relocs. */ #define R_ALPHA_NONE 0 /* No reloc */ #define R_ALPHA_REFLONG 1 /* Direct 32 bit */ #define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ #define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ #define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ #define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ #define R_ALPHA_GPDISP 6 /* Add displacement to GP */ #define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ #define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ #define R_ALPHA_SREL16 9 /* PC relative 16 bit */ #define R_ALPHA_SREL32 10 /* PC relative 32 bit */ #define R_ALPHA_SREL64 11 /* PC relative 64 bit */ #define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ #define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ #define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ #define R_ALPHA_COPY 24 /* Copy symbol at runtime */ #define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ #define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ #define R_ALPHA_RELATIVE 27 /* Adjust by program base */ #define R_ALPHA_TLS_GD_HI 28 #define R_ALPHA_TLSGD 29 #define R_ALPHA_TLS_LDM 30 #define R_ALPHA_DTPMOD64 31 #define R_ALPHA_GOTDTPREL 32 #define R_ALPHA_DTPREL64 33 #define R_ALPHA_DTPRELHI 34 #define R_ALPHA_DTPRELLO 35 #define R_ALPHA_DTPREL16 36 #define R_ALPHA_GOTTPREL 37 #define R_ALPHA_TPREL64 38 #define R_ALPHA_TPRELHI 39 #define R_ALPHA_TPRELLO 40 #define R_ALPHA_TPREL16 41 /* Keep this the last entry. */ #define R_ALPHA_NUM 46 /* Magic values of the LITUSE relocation addend. */ #define LITUSE_ALPHA_ADDR 0 #define LITUSE_ALPHA_BASE 1 #define LITUSE_ALPHA_BYTOFF 2 #define LITUSE_ALPHA_JSR 3 #define LITUSE_ALPHA_TLS_GD 4 #define LITUSE_ALPHA_TLS_LDM 5 /* Legal values for d_tag of Elf64_Dyn. */ #define DT_ALPHA_PLTRO (DT_LOPROC + 0) #define DT_ALPHA_NUM 1 /* PowerPC specific declarations */ /* Values for Elf32/64_Ehdr.e_flags. */ #define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ /* Cygnus local bits below */ #define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ #define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib flag */ /* PowerPC relocations defined by the ABIs */ #define R_PPC_NONE 0 #define R_PPC_ADDR32 1 /* 32bit absolute address */ #define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ #define R_PPC_ADDR16 3 /* 16bit absolute address */ #define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ #define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ #define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ #define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ #define R_PPC_ADDR14_BRTAKEN 8 #define R_PPC_ADDR14_BRNTAKEN 9 #define R_PPC_REL24 10 /* PC relative 26 bit */ #define R_PPC_REL14 11 /* PC relative 16 bit */ #define R_PPC_REL14_BRTAKEN 12 #define R_PPC_REL14_BRNTAKEN 13 #define R_PPC_GOT16 14 #define R_PPC_GOT16_LO 15 #define R_PPC_GOT16_HI 16 #define R_PPC_GOT16_HA 17 #define R_PPC_PLTREL24 18 #define R_PPC_COPY 19 #define R_PPC_GLOB_DAT 20 #define R_PPC_JMP_SLOT 21 #define R_PPC_RELATIVE 22 #define R_PPC_LOCAL24PC 23 #define R_PPC_UADDR32 24 #define R_PPC_UADDR16 25 #define R_PPC_REL32 26 #define R_PPC_PLT32 27 #define R_PPC_PLTREL32 28 #define R_PPC_PLT16_LO 29 #define R_PPC_PLT16_HI 30 #define R_PPC_PLT16_HA 31 #define R_PPC_SDAREL16 32 #define R_PPC_SECTOFF 33 #define R_PPC_SECTOFF_LO 34 #define R_PPC_SECTOFF_HI 35 #define R_PPC_SECTOFF_HA 36 /* PowerPC relocations defined for the TLS access ABI. */ #define R_PPC_TLS 67 /* none (sym+add)@tls */ #define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ #define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ #define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ #define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ #define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ #define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ #define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ #define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ #define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ #define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ #define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ #define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ #define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ #define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ #define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ #define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ #define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ #define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ #define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ #define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ #define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ #define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ #define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ #define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ #define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ #define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ #define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ /* The remaining relocs are from the Embedded ELF ABI, and are not in the SVR4 ELF ABI. */ #define R_PPC_EMB_NADDR32 101 #define R_PPC_EMB_NADDR16 102 #define R_PPC_EMB_NADDR16_LO 103 #define R_PPC_EMB_NADDR16_HI 104 #define R_PPC_EMB_NADDR16_HA 105 #define R_PPC_EMB_SDAI16 106 #define R_PPC_EMB_SDA2I16 107 #define R_PPC_EMB_SDA2REL 108 #define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ #define R_PPC_EMB_MRKREF 110 #define R_PPC_EMB_RELSEC16 111 #define R_PPC_EMB_RELST_LO 112 #define R_PPC_EMB_RELST_HI 113 #define R_PPC_EMB_RELST_HA 114 #define R_PPC_EMB_BIT_FLD 115 #define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ /* Diab tool relocations. */ #define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ #define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ #define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ #define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ #define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ #define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ /* GNU extension to support local ifunc. */ #define R_PPC_IRELATIVE 248 /* GNU relocs used in PIC code sequences. */ #define R_PPC_REL16 249 /* half16 (sym+add-.) */ #define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ #define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ #define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ /* This is a phony reloc to handle any old fashioned TOC16 references that may still be in object files. */ #define R_PPC_TOC16 255 /* PowerPC specific values for the Dyn d_tag field. */ #define DT_PPC_GOT (DT_LOPROC + 0) #define DT_PPC_NUM 1 /* PowerPC64 relocations defined by the ABIs */ #define R_PPC64_NONE R_PPC_NONE #define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ #define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ #define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ #define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ #define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ #define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ #define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ #define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN #define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN #define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ #define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ #define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN #define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN #define R_PPC64_GOT16 R_PPC_GOT16 #define R_PPC64_GOT16_LO R_PPC_GOT16_LO #define R_PPC64_GOT16_HI R_PPC_GOT16_HI #define R_PPC64_GOT16_HA R_PPC_GOT16_HA #define R_PPC64_COPY R_PPC_COPY #define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT #define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT #define R_PPC64_RELATIVE R_PPC_RELATIVE #define R_PPC64_UADDR32 R_PPC_UADDR32 #define R_PPC64_UADDR16 R_PPC_UADDR16 #define R_PPC64_REL32 R_PPC_REL32 #define R_PPC64_PLT32 R_PPC_PLT32 #define R_PPC64_PLTREL32 R_PPC_PLTREL32 #define R_PPC64_PLT16_LO R_PPC_PLT16_LO #define R_PPC64_PLT16_HI R_PPC_PLT16_HI #define R_PPC64_PLT16_HA R_PPC_PLT16_HA #define R_PPC64_SECTOFF R_PPC_SECTOFF #define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO #define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI #define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA #define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ #define R_PPC64_ADDR64 38 /* doubleword64 S + A */ #define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ #define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ #define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ #define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ #define R_PPC64_UADDR64 43 /* doubleword64 S + A */ #define R_PPC64_REL64 44 /* doubleword64 S + A - P */ #define R_PPC64_PLT64 45 /* doubleword64 L + A */ #define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ #define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ #define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ #define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ #define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ #define R_PPC64_TOC 51 /* doubleword64 .TOC */ #define R_PPC64_PLTGOT16 52 /* half16* M + A */ #define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ #define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ #define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ #define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ #define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ #define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ #define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ #define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ #define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ #define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ #define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ #define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ #define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ #define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ /* PowerPC64 relocations defined for the TLS access ABI. */ #define R_PPC64_TLS 67 /* none (sym+add)@tls */ #define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ #define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ #define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ #define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ #define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ #define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ #define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ #define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ #define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ #define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ #define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ #define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ #define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ #define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ #define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ #define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ #define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ #define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ #define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ #define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ #define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ #define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ #define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ #define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ #define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ #define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ #define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ #define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ #define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ #define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ #define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ #define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ #define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ #define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ #define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ #define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ #define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ #define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ #define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ /* GNU extension to support local ifunc. */ #define R_PPC64_JMP_IREL 247 #define R_PPC64_IRELATIVE 248 #define R_PPC64_REL16 249 /* half16 (sym+add-.) */ #define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ #define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ #define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ /* PowerPC64 specific values for the Dyn d_tag field. */ #define DT_PPC64_GLINK (DT_LOPROC + 0) #define DT_PPC64_OPD (DT_LOPROC + 1) #define DT_PPC64_OPDSZ (DT_LOPROC + 2) #define DT_PPC64_NUM 3 /* ARM specific declarations */ /* Processor specific flags for the ELF header e_flags field. */ #define EF_ARM_RELEXEC 0x01 #define EF_ARM_HASENTRY 0x02 #define EF_ARM_INTERWORK 0x04 #define EF_ARM_APCS_26 0x08 #define EF_ARM_APCS_FLOAT 0x10 #define EF_ARM_PIC 0x20 #define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ #define EF_ARM_NEW_ABI 0x80 #define EF_ARM_OLD_ABI 0x100 #define EF_ARM_SOFT_FLOAT 0x200 #define EF_ARM_VFP_FLOAT 0x400 #define EF_ARM_MAVERICK_FLOAT 0x800 /* Other constants defined in the ARM ELF spec. version B-01. */ /* NB. These conflict with values defined above. */ #define EF_ARM_SYMSARESORTED 0x04 #define EF_ARM_DYNSYMSUSESEGIDX 0x08 #define EF_ARM_MAPSYMSFIRST 0x10 #define EF_ARM_EABIMASK 0XFF000000 /* Constants defined in AAELF. */ #define EF_ARM_BE8 0x00800000 #define EF_ARM_LE8 0x00400000 #define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) #define EF_ARM_EABI_UNKNOWN 0x00000000 #define EF_ARM_EABI_VER1 0x01000000 #define EF_ARM_EABI_VER2 0x02000000 #define EF_ARM_EABI_VER3 0x03000000 #define EF_ARM_EABI_VER4 0x04000000 #define EF_ARM_EABI_VER5 0x05000000 /* Additional symbol types for Thumb. */ #define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ #define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ /* ARM-specific values for sh_flags */ #define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ #define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined in the input to a link step. */ /* ARM-specific program header flags */ #define PF_ARM_SB 0x10000000 /* Segment contains the location addressed by the static base. */ #define PF_ARM_PI 0x20000000 /* Position-independent segment. */ #define PF_ARM_ABS 0x40000000 /* Absolute segment. */ /* Processor specific values for the Phdr p_type field. */ #define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ /* Processor specific values for the Shdr sh_type field. */ #define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ #define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ #define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ /* ARM relocs. */ #define R_ARM_NONE 0 /* No reloc */ #define R_ARM_PC24 1 /* PC relative 26 bit branch */ #define R_ARM_ABS32 2 /* Direct 32 bit */ #define R_ARM_REL32 3 /* PC relative 32 bit */ #define R_ARM_PC13 4 #define R_ARM_ABS16 5 /* Direct 16 bit */ #define R_ARM_ABS12 6 /* Direct 12 bit */ #define R_ARM_THM_ABS5 7 #define R_ARM_ABS8 8 /* Direct 8 bit */ #define R_ARM_SBREL32 9 #define R_ARM_THM_PC22 10 #define R_ARM_THM_PC8 11 #define R_ARM_AMP_VCALL9 12 #define R_ARM_SWI24 13 /* Obsolete static relocation. */ #define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ #define R_ARM_THM_SWI8 14 #define R_ARM_XPC25 15 #define R_ARM_THM_XPC22 16 #define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ #define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ #define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ #define R_ARM_COPY 20 /* Copy symbol at runtime */ #define R_ARM_GLOB_DAT 21 /* Create GOT entry */ #define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ #define R_ARM_RELATIVE 23 /* Adjust by program base */ #define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ #define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ #define R_ARM_GOT32 26 /* 32 bit GOT entry */ #define R_ARM_PLT32 27 /* 32 bit PLT address */ #define R_ARM_ALU_PCREL_7_0 32 #define R_ARM_ALU_PCREL_15_8 33 #define R_ARM_ALU_PCREL_23_15 34 #define R_ARM_LDR_SBREL_11_0 35 #define R_ARM_ALU_SBREL_19_12 36 #define R_ARM_ALU_SBREL_27_20 37 #define R_ARM_TLS_GOTDESC 90 #define R_ARM_TLS_CALL 91 #define R_ARM_TLS_DESCSEQ 92 #define R_ARM_THM_TLS_CALL 93 #define R_ARM_GNU_VTENTRY 100 #define R_ARM_GNU_VTINHERIT 101 #define R_ARM_THM_PC11 102 /* thumb unconditional branch */ #define R_ARM_THM_PC9 103 /* thumb conditional branch */ #define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic thread local data */ #define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic thread local data */ #define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS block */ #define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of static TLS block offset */ #define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static TLS block */ #define R_ARM_THM_TLS_DESCSEQ 129 #define R_ARM_IRELATIVE 160 #define R_ARM_RXPC25 249 #define R_ARM_RSBREL32 250 #define R_ARM_THM_RPC22 251 #define R_ARM_RREL32 252 #define R_ARM_RABS22 253 #define R_ARM_RPC24 254 #define R_ARM_RBASE 255 /* Keep this the last entry. */ #define R_ARM_NUM 256 /* IA-64 specific declarations. */ /* Processor specific flags for the Ehdr e_flags field. */ #define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ #define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ #define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ /* Processor specific values for the Phdr p_type field. */ #define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ #define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ #define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) #define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) #define PT_IA_64_HP_STACK (PT_LOOS + 0x14) /* Processor specific flags for the Phdr p_flags field. */ #define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ /* Processor specific values for the Shdr sh_type field. */ #define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ #define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ /* Processor specific flags for the Shdr sh_flags field. */ #define SHF_IA_64_SHORT 0x10000000 /* section near gp */ #define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ /* Processor specific values for the Dyn d_tag field. */ #define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) #define DT_IA_64_NUM 1 /* IA-64 relocations. */ #define R_IA64_NONE 0x00 /* none */ #define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ #define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ #define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ #define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ #define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ #define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ #define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ #define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ #define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ #define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ #define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ #define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ #define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ #define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ #define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ #define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ #define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ #define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ #define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ #define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ #define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ #define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ #define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ #define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ #define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ #define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ #define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ #define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ #define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ #define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ #define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ #define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ #define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ #define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ #define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ #define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ #define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ #define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ #define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ #define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ #define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ #define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ #define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ #define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ #define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ #define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ #define R_IA64_REL32MSB 0x6c /* data 4 + REL */ #define R_IA64_REL32LSB 0x6d /* data 4 + REL */ #define R_IA64_REL64MSB 0x6e /* data 8 + REL */ #define R_IA64_REL64LSB 0x6f /* data 8 + REL */ #define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ #define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ #define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ #define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ #define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ #define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ #define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ #define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ #define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ #define R_IA64_COPY 0x84 /* copy relocation */ #define R_IA64_SUB 0x85 /* Addend and symbol difference */ #define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ #define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ #define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ #define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ #define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ #define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ #define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ #define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ #define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ #define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ #define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ #define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ #define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ #define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ #define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ #define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ #define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ #define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ #define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ /* SH specific declarations */ /* Processor specific flags for the ELF header e_flags field. */ #define EF_SH_MACH_MASK 0x1f #define EF_SH_UNKNOWN 0x0 #define EF_SH1 0x1 #define EF_SH2 0x2 #define EF_SH3 0x3 #define EF_SH_DSP 0x4 #define EF_SH3_DSP 0x5 #define EF_SH4AL_DSP 0x6 #define EF_SH3E 0x8 #define EF_SH4 0x9 #define EF_SH2E 0xb #define EF_SH4A 0xc #define EF_SH2A 0xd #define EF_SH4_NOFPU 0x10 #define EF_SH4A_NOFPU 0x11 #define EF_SH4_NOMMU_NOFPU 0x12 #define EF_SH2A_NOFPU 0x13 #define EF_SH3_NOMMU 0x14 #define EF_SH2A_SH4_NOFPU 0x15 #define EF_SH2A_SH3_NOFPU 0x16 #define EF_SH2A_SH4 0x17 #define EF_SH2A_SH3E 0x18 /* SH relocs. */ #define R_SH_NONE 0 #define R_SH_DIR32 1 #define R_SH_REL32 2 #define R_SH_DIR8WPN 3 #define R_SH_IND12W 4 #define R_SH_DIR8WPL 5 #define R_SH_DIR8WPZ 6 #define R_SH_DIR8BP 7 #define R_SH_DIR8W 8 #define R_SH_DIR8L 9 #define R_SH_SWITCH16 25 #define R_SH_SWITCH32 26 #define R_SH_USES 27 #define R_SH_COUNT 28 #define R_SH_ALIGN 29 #define R_SH_CODE 30 #define R_SH_DATA 31 #define R_SH_LABEL 32 #define R_SH_SWITCH8 33 #define R_SH_GNU_VTINHERIT 34 #define R_SH_GNU_VTENTRY 35 #define R_SH_TLS_GD_32 144 #define R_SH_TLS_LD_32 145 #define R_SH_TLS_LDO_32 146 #define R_SH_TLS_IE_32 147 #define R_SH_TLS_LE_32 148 #define R_SH_TLS_DTPMOD32 149 #define R_SH_TLS_DTPOFF32 150 #define R_SH_TLS_TPOFF32 151 #define R_SH_GOT32 160 #define R_SH_PLT32 161 #define R_SH_COPY 162 #define R_SH_GLOB_DAT 163 #define R_SH_JMP_SLOT 164 #define R_SH_RELATIVE 165 #define R_SH_GOTOFF 166 #define R_SH_GOTPC 167 /* Keep this the last entry. */ #define R_SH_NUM 256 /* S/390 specific definitions. */ /* Valid values for the e_flags field. */ #define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ /* Additional s390 relocs */ #define R_390_NONE 0 /* No reloc. */ #define R_390_8 1 /* Direct 8 bit. */ #define R_390_12 2 /* Direct 12 bit. */ #define R_390_16 3 /* Direct 16 bit. */ #define R_390_32 4 /* Direct 32 bit. */ #define R_390_PC32 5 /* PC relative 32 bit. */ #define R_390_GOT12 6 /* 12 bit GOT offset. */ #define R_390_GOT32 7 /* 32 bit GOT offset. */ #define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ #define R_390_COPY 9 /* Copy symbol at runtime. */ #define R_390_GLOB_DAT 10 /* Create GOT entry. */ #define R_390_JMP_SLOT 11 /* Create PLT entry. */ #define R_390_RELATIVE 12 /* Adjust by program base. */ #define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ #define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ #define R_390_GOT16 15 /* 16 bit GOT offset. */ #define R_390_PC16 16 /* PC relative 16 bit. */ #define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ #define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ #define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ #define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ #define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ #define R_390_64 22 /* Direct 64 bit. */ #define R_390_PC64 23 /* PC relative 64 bit. */ #define R_390_GOT64 24 /* 64 bit GOT offset. */ #define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ #define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ #define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ #define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ #define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ #define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ #define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ #define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ #define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ #define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ #define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ #define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ #define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ #define R_390_TLS_GDCALL 38 /* Tag for function call in general dynamic TLS code. */ #define R_390_TLS_LDCALL 39 /* Tag for function call in local dynamic TLS code. */ #define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic thread local data. */ #define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic thread local data. */ #define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS block offset. */ #define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS block offset. */ #define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS block offset. */ #define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic thread local data in LE code. */ #define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic thread local data in LE code. */ #define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for negated static TLS block offset. */ #define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for negated static TLS block offset. */ #define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for negated static TLS block offset. */ #define R_390_TLS_LE32 50 /* 32 bit negated offset relative to static TLS block. */ #define R_390_TLS_LE64 51 /* 64 bit negated offset relative to static TLS block. */ #define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS block. */ #define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS block. */ #define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ #define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ #define R_390_TLS_TPOFF 56 /* Negated offset in static TLS block. */ #define R_390_20 57 /* Direct 20 bit. */ #define R_390_GOT20 58 /* 20 bit GOT offset. */ #define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ #define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS block offset. */ /* Keep this the last entry. */ #define R_390_NUM 61 /* CRIS relocations. */ #define R_CRIS_NONE 0 #define R_CRIS_8 1 #define R_CRIS_16 2 #define R_CRIS_32 3 #define R_CRIS_8_PCREL 4 #define R_CRIS_16_PCREL 5 #define R_CRIS_32_PCREL 6 #define R_CRIS_GNU_VTINHERIT 7 #define R_CRIS_GNU_VTENTRY 8 #define R_CRIS_COPY 9 #define R_CRIS_GLOB_DAT 10 #define R_CRIS_JUMP_SLOT 11 #define R_CRIS_RELATIVE 12 #define R_CRIS_16_GOT 13 #define R_CRIS_32_GOT 14 #define R_CRIS_16_GOTPLT 15 #define R_CRIS_32_GOTPLT 16 #define R_CRIS_32_GOTREL 17 #define R_CRIS_32_PLT_GOTREL 18 #define R_CRIS_32_PLT_PCREL 19 #define R_CRIS_NUM 20 /* AMD x86-64 relocations. */ #define R_X86_64_NONE 0 /* No reloc */ #define R_X86_64_64 1 /* Direct 64 bit */ #define R_X86_64_PC32 2 /* PC relative 32 bit signed */ #define R_X86_64_GOT32 3 /* 32 bit GOT entry */ #define R_X86_64_PLT32 4 /* 32 bit PLT address */ #define R_X86_64_COPY 5 /* Copy symbol at runtime */ #define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ #define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ #define R_X86_64_RELATIVE 8 /* Adjust by program base */ #define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative offset to GOT */ #define R_X86_64_32 10 /* Direct 32 bit zero extended */ #define R_X86_64_32S 11 /* Direct 32 bit sign extended */ #define R_X86_64_16 12 /* Direct 16 bit zero extended */ #define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ #define R_X86_64_8 14 /* Direct 8 bit sign extended */ #define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ #define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ #define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ #define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ #define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset to two GOT entries for GD symbol */ #define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset to two GOT entries for LD symbol */ #define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ #define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset to GOT entry for IE symbol */ #define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ #define R_X86_64_PC64 24 /* PC relative 64 bit */ #define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ #define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative offset to GOT */ #define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ #define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset to GOT entry */ #define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ #define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ #define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset to PLT entry */ #define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ #define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ #define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ #define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS descriptor. */ #define R_X86_64_TLSDESC 36 /* TLS descriptor. */ #define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ #define R_X86_64_NUM 38 /* AM33 relocations. */ #define R_MN10300_NONE 0 /* No reloc. */ #define R_MN10300_32 1 /* Direct 32 bit. */ #define R_MN10300_16 2 /* Direct 16 bit. */ #define R_MN10300_8 3 /* Direct 8 bit. */ #define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ #define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ #define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ #define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ #define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ #define R_MN10300_24 9 /* Direct 24 bit. */ #define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ #define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ #define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ #define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ #define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ #define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ #define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ #define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ #define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ #define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ #define R_MN10300_COPY 20 /* Copy symbol at runtime. */ #define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ #define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ #define R_MN10300_RELATIVE 23 /* Adjust by program base. */ #define R_MN10300_NUM 24 /* M32R relocs. */ #define R_M32R_NONE 0 /* No reloc. */ #define R_M32R_16 1 /* Direct 16 bit. */ #define R_M32R_32 2 /* Direct 32 bit. */ #define R_M32R_24 3 /* Direct 24 bit. */ #define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ #define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ #define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ #define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ #define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ #define R_M32R_LO16 9 /* Low 16 bit. */ #define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ #define R_M32R_GNU_VTINHERIT 11 #define R_M32R_GNU_VTENTRY 12 /* M32R relocs use SHT_RELA. */ #define R_M32R_16_RELA 33 /* Direct 16 bit. */ #define R_M32R_32_RELA 34 /* Direct 32 bit. */ #define R_M32R_24_RELA 35 /* Direct 24 bit. */ #define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ #define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ #define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ #define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ #define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ #define R_M32R_LO16_RELA 41 /* Low 16 bit */ #define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ #define R_M32R_RELA_GNU_VTINHERIT 43 #define R_M32R_RELA_GNU_VTENTRY 44 #define R_M32R_REL32 45 /* PC relative 32 bit. */ #define R_M32R_GOT24 48 /* 24 bit GOT entry */ #define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ #define R_M32R_COPY 50 /* Copy symbol at runtime */ #define R_M32R_GLOB_DAT 51 /* Create GOT entry */ #define R_M32R_JMP_SLOT 52 /* Create PLT entry */ #define R_M32R_RELATIVE 53 /* Adjust by program base */ #define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ #define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ #define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned low */ #define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed low */ #define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ #define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to GOT with unsigned low */ #define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to GOT with signed low */ #define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to GOT */ #define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT with unsigned low */ #define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT with signed low */ #define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ #define R_M32R_NUM 256 /* Keep this the last entry. */ #endif } #endif edb-debugger-1.0.0/plugins/BinaryInfo/PE32.h0000644000175000017500000000320513273160654017714 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PE32_20070718_H_ #define PE32_20070718_H_ #include "IBinary.h" #include "pe_binary.h" namespace BinaryInfoPlugin { class PEBinaryException : public std::exception { public: enum reasonEnum { INVALID_ARGUMENTS = 1, READ_FAILURE = 2, INVALID_PE = 3, INVALID_ARCHITECTURE = 4 }; PEBinaryException(reasonEnum reason); virtual const char * what() const noexcept override; private: reasonEnum reason_; }; class PE32 : public IBinary { public: PE32(const std::shared_ptr ®ion); virtual ~PE32(); public: virtual bool native() const; virtual edb::address_t calculate_main(); virtual edb::address_t debug_pointer(); virtual edb::address_t entry_point(); virtual size_t header_size() const; virtual const void *header() const; virtual QVector
headers() const; virtual edb::address_t base_address() const; private: std::shared_ptr region_; IMAGE_DOS_HEADER dos_; IMAGE_NT_HEADERS32 pe_; }; } #endif edb-debugger-1.0.0/plugins/BinaryInfo/symbols.h0000644000175000017500000000162213273160654020734 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef SYMBOLS_20110312_H_ #define SYMBOLS_20110312_H_ class QString; #include namespace BinaryInfoPlugin { bool generate_symbols(const QString &filename, std::ostream &os = std::cout); } #endif edb-debugger-1.0.0/plugins/BinaryInfo/DialogHeader.ui0000644000175000017500000000756413273160654021755 0ustar eteraneteran Evan Teran BinaryInfoPlugin::DialogHeader 0 0 691 590 Header Explorer Regions To Search: Filter Monospace QAbstractItemView::NoEditTriggers true QAbstractItemView::SingleSelection QAbstractItemView::SelectRows true true Results: Header Value 6 &Close false &Help Qt::Horizontal 40 20 Explore Header true txtSearch tableView btnClose btnHelp btnExplore btnClose clicked() DialogHeader reject() 66 422 265 468 edb-debugger-1.0.0/plugins/BinaryInfo/symbols.cpp0000644000175000017500000004352613273160654021300 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "symbols.h" #include "demangle.h" #include "edb.h" #include #include #include #include #include #include #include #include #include #include #include "elf/elf_types.h" #include "elf/elf_header.h" #include "elf/elf_rela.h" #include "elf/elf_rel.h" #include "elf/elf_sym.h" #include "elf/elf_shdr.h" #include "elf/elf_syminfo.h" namespace BinaryInfoPlugin { namespace { struct elf32_model { typedef quint32 address_t; typedef elf32_header elf_header_t; typedef elf32_shdr elf_section_header_t; typedef elf32_sym elf_symbol_t; typedef elf32_rela elf_relocation_a_t; typedef elf32_rel elf_relocation_t; static const int plt_entry_size = 0x10; static quint32 elf_r_sym(quint32 x) { return ELF32_R_SYM(x); } static quint32 elf_r_type(quint32 x) { return ELF32_R_TYPE(x); } static unsigned char elf_st_type(unsigned char x) { return ELF32_ST_TYPE(x); } static unsigned char elf_st_bind(unsigned char x) { return ELF32_ST_BIND(x); } struct symbol { address_t address; size_t size; QString name; char type; bool operator<(const symbol &rhs) const { return address < rhs.address || (address == rhs.address && name < rhs.name); } bool operator==(const symbol &rhs) const { return address == rhs.address && size == rhs.size && name == rhs.name && type == rhs.type; } QString to_string() const { return QString("%1 %2 %3 %4").arg(edb::value32(address).toHexString(), edb::value32(size).toHexString()).arg(type).arg(name); } }; }; struct elf64_model { typedef quint64 address_t; typedef elf64_header elf_header_t; typedef elf64_shdr elf_section_header_t; typedef elf64_sym elf_symbol_t; typedef elf64_rela elf_relocation_a_t; typedef elf64_rel elf_relocation_t; static const int plt_entry_size = 0x10; static quint64 elf_r_sym(quint64 x) { return ELF64_R_SYM(x); } static quint64 elf_r_type(quint64 x) { return ELF64_R_TYPE(x); } static unsigned char elf_st_type(unsigned char x) { return ELF64_ST_TYPE(x); } static unsigned char elf_st_bind(unsigned char x) { return ELF64_ST_BIND(x); } struct symbol { address_t address; size_t size; QString name; char type; bool operator<(const symbol &rhs) const { return address < rhs.address || (address == rhs.address && name < rhs.name); } bool operator==(const symbol &rhs) const { return address == rhs.address && size == rhs.size && name == rhs.name && type == rhs.type; } QString to_string() const { return QString("%1 %2 %3 %4").arg(edb::value64(address).toHexString(), edb::value32(size).toHexString()).arg(type).arg(name); } }; }; bool is_elf32(const void *ptr) { auto elf32_hdr = reinterpret_cast(ptr); if(std::memcmp(elf32_hdr->e_ident, ELFMAG, SELFMAG) == 0) { return elf32_hdr->e_ident[EI_CLASS] == ELFCLASS32; } return false; } bool is_elf64(const void *ptr) { auto elf64_hdr = reinterpret_cast(ptr); if(std::memcmp(elf64_hdr->e_ident, ELFMAG, SELFMAG) == 0) { return elf64_hdr->e_ident[EI_CLASS] == ELFCLASS64; } return false; } /* The symbol type. At least the following types are used; others are, as well, depending on the object file format. If lowercase, the symbol is local; if uppercase, the symbol is global (external). "A" The symbol's value is absolute, and will not be changed by further linking. "B" "b" The symbol is in the uninitialized data section (known as BSS). "C" The symbol is common. Common symbols are uninitialized data. When linking, multiple common symbols may appear with the same name. If the symbol is defined anywhere, the common symbols are treated as undefined references. "D" "d" The symbol is in the initialized data section. "G" "g" The symbol is in an initialized data section for small objects. Some object file formats permit more efficient access to small data objects, such as a global int variable as opposed to a large global array. "N" The symbol is a debugging symbol. "p" The symbols is in a stack unwind section. "R" "r" The symbol is in a read only data section. "S" "s" The symbol is in an uninitialized data section for small objects. "T" "t" The symbol is in the text (code) section. "U" The symbol is undefined. "u" The symbol is a unique global symbol. This is a GNU extension to the standard set of ELF symbol bindings. For such a symbol the dynamic linker will make sure that in the entire process there is just one symbol with this name and type in use. "V" "v" The symbol is a weak object. When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is used with no error. When a weak undefined symbol is linked and the symbol is not defined, the value of the weak symbol becomes zero with no error. On some systems, uppercase indicates that a default value has been specified. "W" "w" The symbol is a weak symbol that has not been specifically tagged as a weak object symbol. When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is used with no error. When a weak undefined symbol is linked and the symbol is not defined, the value of the symbol is determined in a system-specific manner without error. On some systems, upper- case indicates that a default value has been specified. "-" The symbol is a stabs symbol in an a.out object file. In this case, the next values printed are the stabs other field, the stabs desc field, and the stab type. Stabs symbols are used to hold debugging information. "?" The symbol type is unknown, or object file format specific. */ template void collect_symbols(const void *p, size_t size, QList &symbols) { Q_UNUSED(size); typedef typename M::address_t address_t; typedef typename M::elf_header_t elf_header_t; typedef typename M::elf_section_header_t elf_section_header_t; typedef typename M::elf_symbol_t elf_symbol_t; typedef typename M::elf_relocation_a_t elf_relocation_a_t; typedef typename M::elf_relocation_t elf_relocation_t; typedef typename M::symbol symbol; const auto base = reinterpret_cast(p); const auto header = static_cast(p); if (header->e_shnum == 0 || header->e_shentsize == 0) { return; } const auto sections_begin = reinterpret_cast(base + header->e_shoff); const elf_section_header_t *const sections_end = sections_begin + header->e_shnum; auto section_strings = reinterpret_cast(base + sections_begin[header->e_shstrndx].sh_offset); address_t plt_address = 0; address_t got_address = 0; QSet plt_addresses; // collect special section addresses for(const elf_section_header_t *section = sections_begin; section != sections_end; ++section) { if(strcmp(§ion_strings[section->sh_name], ".plt") == 0) { plt_address = section->sh_addr; } else if(strcmp(§ion_strings[section->sh_name], ".got") == 0) { got_address = section->sh_addr; } } // print out relocated symbols for special sections for(const elf_section_header_t *section = sections_begin; section != sections_end; ++section) { address_t base_address = 0; if(strcmp(§ion_strings[section->sh_name], ".rela.plt") == 0) { base_address = plt_address; } else if(strcmp(§ion_strings[section->sh_name], ".rel.plt") == 0) { base_address = plt_address; } else if(strcmp(§ion_strings[section->sh_name], ".rela.got") == 0) { base_address = got_address; } else if(strcmp(§ion_strings[section->sh_name], ".rel.got") == 0) { base_address = got_address; } else { continue; } switch(section->sh_type) { case SHT_RELA: { int n = 0; auto relocation = reinterpret_cast(base + section->sh_offset); if(section->sh_link == 0) { break; } for(size_t i = 0; i < section->sh_size / section->sh_entsize; ++i) { const int sym_index = M::elf_r_sym(relocation[i].r_info); const elf_section_header_t *linked = §ions_begin[section->sh_link]; auto symbol_tab = reinterpret_cast(base + linked->sh_offset); auto string_tab = reinterpret_cast(base + sections_begin[linked->sh_link].sh_offset); const address_t symbol_address = base_address + ++n * M::plt_entry_size; const char *sym_name = §ion_strings[section->sh_name]; if(strlen(sym_name) > (sizeof(".rela.") - 1) && memcmp(sym_name, ".rela.", (sizeof(".rela.") - 1)) == 0) { sym_name += 6; } plt_addresses.insert(symbol_address); symbol sym; sym.address = symbol_address; sym.size = (symbol_tab[sym_index].st_size ? symbol_tab[sym_index].st_size : 0x10); sym.name = &string_tab[symbol_tab[sym_index].st_name]; sym.name += "@"; sym.name += sym_name; sym.type = 'P'; symbols.push_back(sym); } } break; case SHT_REL: { int n = 0; auto relocation = reinterpret_cast(base + section->sh_offset); if(section->sh_link == 0) { break; } for(size_t i = 0; i < section->sh_size / section->sh_entsize; ++i) { const int sym_index = M::elf_r_sym(relocation[i].r_info); const elf_section_header_t *linked = §ions_begin[section->sh_link]; auto symbol_tab = reinterpret_cast(base + linked->sh_offset); auto string_tab = reinterpret_cast(base + sections_begin[linked->sh_link].sh_offset); const address_t symbol_address = base_address + ++n * M::plt_entry_size; const char *sym_name = §ion_strings[section->sh_name]; if(strlen(sym_name) > (sizeof(".rel.") - 1) && memcmp(sym_name, ".rel.", (sizeof(".rel.") - 1)) == 0) { sym_name += 5; } plt_addresses.insert(symbol_address); symbol sym; sym.address = symbol_address; sym.size = (symbol_tab[sym_index].st_size ? symbol_tab[sym_index].st_size : 0x10); sym.name = &string_tab[symbol_tab[sym_index].st_name]; sym.name += "@"; sym.name += sym_name; sym.type = 'P'; symbols.push_back(sym); } } break; } } // collect regular symbols for(const elf_section_header_t *section = sections_begin; section != sections_end; ++section) { switch(section->sh_type) { case SHT_SYMTAB: case SHT_DYNSYM: { auto symbol_tab = reinterpret_cast(base + section->sh_offset); auto string_tab = reinterpret_cast(base + sections_begin[section->sh_link].sh_offset); for(size_t i = 0; i < section->sh_size / section->sh_entsize; ++i) { const elf_section_header_t *related_section = 0; if(symbol_tab[i].st_shndx != SHN_UNDEF && symbol_tab[i].st_shndx < SHN_LORESERVE) { related_section = §ions_begin[symbol_tab[i].st_shndx]; } Q_UNUSED(related_section); if(plt_addresses.find(symbol_tab[i].st_value) == plt_addresses.end()) { if(symbol_tab[i].st_value && strlen(&string_tab[symbol_tab[i].st_name]) > 0) { symbol sym; sym.address = symbol_tab[i].st_value; sym.size = symbol_tab[i].st_size; sym.name = &string_tab[symbol_tab[i].st_name]; sym.type = (M::elf_st_type(symbol_tab[i].st_info) == STT_FUNC ? 'T' : 'D'); symbols.push_back(sym); } } } } break; } } // collect unnamed symbols for(const elf_section_header_t *section = sections_begin; section != sections_end; ++section) { switch(section->sh_type) { case SHT_SYMTAB: case SHT_DYNSYM: { auto symbol_tab = reinterpret_cast(base + section->sh_offset); auto string_tab = reinterpret_cast(base + sections_begin[section->sh_link].sh_offset); for(size_t i = 0; i < section->sh_size / section->sh_entsize; ++i) { const elf_section_header_t *related_section = 0; if(symbol_tab[i].st_shndx != SHN_UNDEF && symbol_tab[i].st_shndx < SHN_LORESERVE) { related_section = §ions_begin[symbol_tab[i].st_shndx]; } Q_UNUSED(related_section); if(plt_addresses.find(symbol_tab[i].st_value) == plt_addresses.end()) { if(symbol_tab[i].st_value && strlen(&string_tab[symbol_tab[i].st_name]) == 0) { symbol sym; sym.address = symbol_tab[i].st_value; sym.size = symbol_tab[i].st_size; for(const elf_section_header_t *section = sections_begin; section != sections_end; ++section) { if(sym.address>=section->sh_addr && sym.address+sym.size<=section->sh_addr+section->sh_size) { const std::int64_t offset=sym.address-section->sh_addr; const QString hexPrefix=std::abs(offset)>9?"0x":""; const QString offsetStr=offset ? "+"+hexPrefix+QString::number(offset,16) : ""; const QString sectionName(§ion_strings[section->sh_name]); if(!sectionName.isEmpty()) { sym.name = QString(sectionName+offsetStr); break; } } } if(sym.name.isEmpty()) sym.name = QString("$sym_%1").arg(edb::v1::format_pointer(symbol_tab[i].st_value)); sym.type = (M::elf_st_type(symbol_tab[i].st_info) == STT_FUNC ? 'T' : 'D'); symbols.push_back(sym); } } } } break; } } } //-------------------------------------------------------------------------- // Name: output_symbols // Desc: outputs the symbols to OS ensuring uniqueness and adding any // needed demangling //-------------------------------------------------------------------------- template void output_symbols(QList &symbols, std::ostream &os) { qSort(symbols.begin(), symbols.end()); auto new_end = std::unique(symbols.begin(), symbols.end()); const auto demanglingEnabled = QSettings().value("BinaryInfo/demangling_enabled", true).toBool(); for(auto it = symbols.begin(); it != new_end; ++it) { if(demanglingEnabled) { it->name = demangle(it->name); } os << qPrintable(it->to_string()) << '\n'; } } //-------------------------------------------------------------------------- // Name: generate_symbols_internal // Desc: //-------------------------------------------------------------------------- bool generate_symbols_internal(QFile &file, std::shared_ptr &debugFile, std::ostream &os) { if(auto file_ptr = reinterpret_cast(file.map(0, file.size(), QFile::NoOptions))) { if(is_elf64(file_ptr)) { typedef typename elf64_model::symbol symbol; QList symbols; collect_symbols(file_ptr, file.size(), symbols); // if there was a debug file if(debugFile) { // and we sucessfully opened it if(debugFile->open(QIODevice::ReadOnly)) { // map it and include it with the symbols if(auto debug_ptr = reinterpret_cast(debugFile->map(0, debugFile->size(), QFile::NoOptions))) { // this should never fail... but just being sure if(is_elf64(debug_ptr)) { collect_symbols(debug_ptr, debugFile->size(), symbols); } } } } output_symbols(symbols, os); return true; } else if(is_elf32(file_ptr)) { typedef typename elf32_model::symbol symbol; QList symbols; collect_symbols(file_ptr, file.size(), symbols); // if there was a debug file if(debugFile) { // and we sucessfully opened it if(debugFile->open(QIODevice::ReadOnly)) { // map it and include it with the symbols if(auto debug_ptr = reinterpret_cast(debugFile->map(0, debugFile->size(), QFile::NoOptions))) { // this should never fail... but just being sure if(is_elf32(debug_ptr)) { collect_symbols(debug_ptr, debugFile->size(), symbols); } } } } output_symbols(symbols, os); return true; } else { qDebug() << "unknown file type"; } } return false; } } //-------------------------------------------------------------------------- // Name: generate_symbols // Desc: //-------------------------------------------------------------------------- bool generate_symbols(const QString &filename, std::ostream &os) { QFile file(filename); if(file.open(QIODevice::ReadOnly)) { #if QT_VERSION >= 0x040700 os << qPrintable(QDateTime::currentDateTimeUtc().toString(Qt::ISODate)) << " +0000" << '\n'; #else os << qPrintable(QDateTime::currentDateTime().toUTC().toString(Qt::ISODate)) << "+0000" << '\n'; #endif const QByteArray md5 = edb::v1::get_file_md5(filename); os << md5.toHex().data() << ' ' << qPrintable(QFileInfo(filename).absoluteFilePath()) << '\n'; const QString debugInfoPath = QSettings().value("BinaryInfo/debug_info_path", "/usr/lib/debug").toString(); std::shared_ptr debugFile; if(!debugInfoPath.isEmpty()) { debugFile = std::make_shared(QString("%1/%2.debug").arg(debugInfoPath, filename)); if(!debugFile->exists()) // systems such as Ubuntu don't have .debug suffix, try without it debugFile = std::make_shared(QString("%1/%2").arg(debugInfoPath, filename)); } return generate_symbols_internal(file, debugFile, os); } return false; } } edb-debugger-1.0.0/plugins/BinaryInfo/PE32.cpp0000644000175000017500000001123113273160654020245 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PE32.h" #include "edb.h" #include "IDebugger.h" #include "IProcess.h" #include "IRegion.h" #include "string_hash.h" #include "pe_binary.h" #include namespace BinaryInfoPlugin { PEBinaryException::PEBinaryException(reasonEnum reason): reason_(reason) {} const char * PEBinaryException::what() const noexcept { return "TODO"; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ PE32::PE32(const std::shared_ptr ®ion) : region_(region) { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ const WORD dos_magic = 0x5A4D; const LONG pe_magic = 0x00004550; #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ const WORD dos_magic = 0x4D5A; const LONG pe_magic = 0x50450000; #endif if (!region_) { throw PEBinaryException(PEBinaryException::reasonEnum::INVALID_ARGUMENTS); } IProcess *process = edb::v1::debugger_core->process(); if (!process) { throw PEBinaryException(PEBinaryException::reasonEnum::READ_FAILURE); } if (!process->read_bytes(region_->start(), &dos_, sizeof(dos_))) { throw PEBinaryException(PEBinaryException::reasonEnum::READ_FAILURE); } if (dos_.e_magic != dos_magic || dos_.e_lfanew == 0) { throw PEBinaryException(PEBinaryException::reasonEnum::INVALID_PE); } if (!process->read_bytes(region_->start() + dos_.e_lfanew, &pe_, sizeof(pe_))) { throw PEBinaryException(PEBinaryException::reasonEnum::READ_FAILURE); } if (pe_.Signature != pe_magic) { throw PEBinaryException(PEBinaryException::reasonEnum::INVALID_PE); } } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ PE32::~PE32() { } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PE32::entry_point() { return region_->start() + pe_.OptionalHeader.AddressOfEntryPoint; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PE32::base_address() const { return pe_.OptionalHeader.ImageBase; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PE32::calculate_main() { return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PE32::native() const { return true; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PE32::debug_pointer() { return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ size_t PE32::header_size() const { return sizeof(pe_) + dos_.e_lfanew; } //------------------------------------------------------------------------------ // Name: headers // Desc: returns a list of all headers in this binary //------------------------------------------------------------------------------ QVector PE32::headers() const { QVector
results; results.push_back({region_->start(), sizeof(pe_) + dos_.e_lfanew}); return results; } //------------------------------------------------------------------------------ // Name: header // Desc: returns a copy of the file header or NULL if the region wasn't a valid, // known binary type //------------------------------------------------------------------------------ const void *PE32::header() const { return 0; } } edb-debugger-1.0.0/plugins/BinaryInfo/ELFXX.h0000644000175000017500000000304013273160654020126 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef ELF32_20070718_H_ #define ELF32_20070718_H_ #include "IBinary.h" #include "elf_binary.h" namespace BinaryInfoPlugin { template class ELFXX : public IBinary { public: ELFXX(const std::shared_ptr ®ion); virtual ~ELFXX(); public: virtual bool native() const; virtual edb::address_t calculate_main(); virtual edb::address_t debug_pointer(); virtual edb::address_t entry_point(); virtual size_t header_size() const; virtual const void *header() const; virtual QVector
headers() const; virtual edb::address_t base_address() const; private: void validate_header(); private: std::shared_ptr region_; elfxx_header header_; edb::address_t base_address_; QVector
headers_; }; typedef ELFXX ELF32; typedef ELFXX ELF64; } #endif edb-debugger-1.0.0/plugins/BinaryInfo/OptionsPage.ui0000644000175000017500000000304413273160654021662 0ustar eteraneteran BinaryInfoPlugin::OptionsPage 0 0 334 323 BinaryInfo Plugin Demangle auto-generated symbols Debug Info Directory txtDebugDir ... Qt::Vertical 20 262 edb-debugger-1.0.0/plugins/BinaryInfo/demangle.h0000644000175000017500000000151613273160654021022 0ustar eteraneteran#ifndef EDB_DEMANGLE_H_20151113 #define EDB_DEMANGLE_H_20151113 #include #include #ifdef __GNUG__ #include #include #define DEMANGLING_SUPPORTED true inline QString demangle(const QString& mangled) { if(!mangled.startsWith("_Z")) return mangled; // otherwise we'll try to demangle C functions coinciding with types like "f" as "float", which is bad int failed=0; QStringList split=mangled.split("@"); // for cases like funcName@plt std::unique_ptr demangled(abi::__cxa_demangle(split.front().toStdString().c_str(),0,0,&failed), std::free); if(failed) return mangled; split.front()=QString(demangled.get()); return split.join("@"); } #else #define DEMANGLING_SUPPORTED false inline QString demangle(const QString& mangled) { return mangled; } #endif #endif edb-debugger-1.0.0/plugins/BinaryInfo/OptionsPage.h0000644000175000017500000000231113273160654021470 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef OPTIONS_PAGE_20151113_H #define OPTIONS_PAGE_20151113_H #include #include namespace BinaryInfoPlugin { namespace Ui { class OptionsPage; } class OptionsPage : public QWidget { Q_OBJECT public: OptionsPage(QWidget* parent = 0); virtual ~OptionsPage(); public: virtual void showEvent(QShowEvent* event); public Q_SLOTS: void on_checkBox_toggled(bool checked = false); void on_txtDebugDir_textChanged(const QString &text); void on_btnDebugDir_clicked(); private: Ui::OptionsPage* const ui; }; } #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/0000755000175000017500000000000013273160654017640 5ustar eteraneteranedb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_phdr.h0000644000175000017500000001313413273160654021576 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_PHDR_20121007_H_ #define ELF_PHDR_20121007_H_ #include "elf/elf_types.h" /* Program segment header. */ struct elf32_phdr { elf32_word p_type; /* Segment type */ elf32_off p_offset; /* Segment file offset */ elf32_addr p_vaddr; /* Segment virtual address */ elf32_addr p_paddr; /* Segment physical address */ elf32_word p_filesz; /* Segment size in file */ elf32_word p_memsz; /* Segment size in memory */ elf32_word p_flags; /* Segment flags */ elf32_word p_align; /* Segment alignment */ }; struct elf64_phdr { elf64_word p_type; /* Segment type */ elf64_word p_flags; /* Segment flags */ elf64_off p_offset; /* Segment file offset */ elf64_addr p_vaddr; /* Segment virtual address */ elf64_addr p_paddr; /* Segment physical address */ elf64_xword p_filesz; /* Segment size in file */ elf64_xword p_memsz; /* Segment size in memory */ elf64_xword p_align; /* Segment alignment */ }; /* Special value for e_phnum. This indicates that the real number of program headers is too large to fit into e_phnum. Instead the real value is in the field sh_info of section 0. */ #define PN_XNUM 0xffff /* Legal values for p_type (segment type). */ #define PT_NULL 0 /* Program header table entry unused */ #define PT_LOAD 1 /* Loadable program segment */ #define PT_DYNAMIC 2 /* Dynamic linking information */ #define PT_INTERP 3 /* Program interpreter */ #define PT_NOTE 4 /* Auxiliary information */ #define PT_SHLIB 5 /* Reserved */ #define PT_PHDR 6 /* Entry for header table itself */ #define PT_TLS 7 /* Thread-local storage segment */ #define PT_NUM 8 /* Number of defined types */ #define PT_LOOS 0x60000000 /* Start of OS-specific */ #define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ #define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ #define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ #define PT_PAX_FLAGS 0x65041580 /* Indicates PaX flag markings */ #define PT_LOSUNW 0x6ffffffa #define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ #define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ #define PT_HISUNW 0x6fffffff #define PT_HIOS 0x6fffffff /* End of OS-specific */ #define PT_LOPROC 0x70000000 /* Start of processor-specific */ #define PT_HIPROC 0x7fffffff /* End of processor-specific */ /* Legal values for p_flags (segment flags). */ #define PF_X (1 << 0) /* Segment is executable */ #define PF_W (1 << 1) /* Segment is writable */ #define PF_R (1 << 2) /* Segment is readable */ #define PF_PAGEEXEC (1 << 4) /* Enable PAGEEXEC */ #define PF_NOPAGEEXEC (1 << 5) /* Disable PAGEEXEC */ #define PF_SEGMEXEC (1 << 6) /* Enable SEGMEXEC */ #define PF_NOSEGMEXEC (1 << 7) /* Disable SEGMEXEC */ #define PF_MPROTECT (1 << 8) /* Enable MPROTECT */ #define PF_NOMPROTECT (1 << 9) /* Disable MPROTECT */ #define PF_RANDEXEC (1 << 10) /* Enable RANDEXEC */ #define PF_NORANDEXEC (1 << 11) /* Disable RANDEXEC */ #define PF_EMUTRAMP (1 << 12) /* Enable EMUTRAMP */ #define PF_NOEMUTRAMP (1 << 13) /* Disable EMUTRAMP */ #define PF_RANDMMAP (1 << 14) /* Enable RANDMMAP */ #define PF_NORANDMMAP (1 << 15) /* Disable RANDMMAP */ #define PF_MASKOS 0x0ff00000 /* OS-specific */ #define PF_MASKPROC 0xf0000000 /* Processor-specific */ /* Legal values for note segment descriptor types for core files. */ #define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ #define NT_FPREGSET 2 /* Contains copy of fpregset struct */ #define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ #define NT_PRXREG 4 /* Contains copy of prxregset struct */ #define NT_TASKSTRUCT 4 /* Contains copy of task structure */ #define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ #define NT_AUXV 6 /* Contains copy of auxv array */ #define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ #define NT_ASRS 8 /* Contains copy of asrset struct */ #define NT_PSTATUS 10 /* Contains copy of pstatus struct */ #define NT_PSINFO 13 /* Contains copy of psinfo struct */ #define NT_PRCRED 14 /* Contains copy of prcred struct */ #define NT_UTSNAME 15 /* Contains copy of utsname struct */ #define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ #define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ #define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ #define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ #define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ #define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ #define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ #define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ #define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ /* Legal values for the note segment descriptor types for object files. */ #define NT_VERSION 1 /* Contains a version string. */ #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_types.h0000644000175000017500000000407613273160654022012 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_TYPES_20121007_H_ #define ELF_TYPES_20121007_H_ #if defined(_MSC_VER) && _MSC_VER < 1600 typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; #else #include #endif /* Type for a 16-bit quantity. */ typedef uint16_t elf32_half; typedef uint16_t elf64_half; /* Types for signed and unsigned 32-bit quantities. */ typedef uint32_t elf32_word; typedef int32_t elf32_sword; typedef uint32_t elf64_word; typedef int32_t elf64_sword; /* Types for signed and unsigned 64-bit quantities. */ typedef uint64_t elf32_xword; typedef int64_t elf32_sxword; typedef uint64_t elf64_xword; typedef int64_t elf64_sxword; /* Type of addresses. */ typedef uint32_t elf32_addr; typedef uint64_t elf64_addr; /* Type of file offsets. */ typedef uint32_t elf32_off; typedef uint64_t elf64_off; /* Type for section indices, which are 16-bit quantities. */ typedef uint16_t elf32_section; typedef uint16_t elf64_section; /* Type for version symbol information. */ typedef elf32_half elf32_versym; typedef elf64_half elf64_versym; #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_verdef.h0000644000175000017500000000463013273160654022115 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_VERDEF_20121007_H_ #define ELF_VERDEF_20121007_H_ #include "elf/elf_types.h" /* Version definition sections. */ struct elf32_verdef { elf32_half vd_version; /* Version revision */ elf32_half vd_flags; /* Version information */ elf32_half vd_ndx; /* Version Index */ elf32_half vd_cnt; /* Number of associated aux entries */ elf32_word vd_hash; /* Version name hash value */ elf32_word vd_aux; /* Offset in bytes to verdaux array */ elf32_word vd_next; /* Offset in bytes to next verdef entry */ }; struct elf64_verdef { elf64_half vd_version; /* Version revision */ elf64_half vd_flags; /* Version information */ elf64_half vd_ndx; /* Version Index */ elf64_half vd_cnt; /* Number of associated aux entries */ elf64_word vd_hash; /* Version name hash value */ elf64_word vd_aux; /* Offset in bytes to verdaux array */ elf64_word vd_next; /* Offset in bytes to next verdef entry */ }; /* Legal values for vd_version (version revision). */ #define VER_DEF_NONE 0 /* No version */ #define VER_DEF_CURRENT 1 /* Current version */ #define VER_DEF_NUM 2 /* Given version number */ /* Legal values for vd_flags (version information flags). */ #define VER_FLG_BASE 0x1 /* Version definition of file itself */ #define VER_FLG_WEAK 0x2 /* Weak version identifier */ /* Versym symbol index values. */ #define VER_NDX_LOCAL 0 /* Symbol is local. */ #define VER_NDX_GLOBAL 1 /* Symbol is global. */ #define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ #define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_auxv.h0000644000175000017500000000771313273160654021632 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_AUXV_20121007_H_ #define ELF_AUXV_20121007_H_ #include "elf/elf_types.h" /* Auxiliary vector. */ /* This vector is normally only used by the program interpreter. The usual definition in an ABI supplement uses the name auxv_t. The vector is not usually defined in a standard file, but it can't hurt. We rename it to avoid conflicts. The sizes of these types are an arrangement between the exec server and the program interpreter, so we don't fully specify them here. */ struct elf32_auxv_t { uint32_t a_type; /* Entry type */ union { uint32_t a_val; /* Integer value */ /* We use to have pointer elements added here. We cannot do that, though, since it does not work when using 32-bit definitions on 64-bit platforms and vice versa. */ } a_un; }; struct elf64_auxv_t { uint64_t a_type; /* Entry type */ union { uint64_t a_val; /* Integer value */ /* We use to have pointer elements added here. We cannot do that, though, since it does not work when using 32-bit definitions on 64-bit platforms and vice versa. */ } a_un; }; // Legal values for a_type (entry type). enum { AT_NULL = 0, // End of vector AT_IGNORE = 1, // Entry should be ignored AT_EXECFD = 2, // File descriptor of program AT_PHDR = 3, // Program headers for program AT_PHENT = 4, // Size of program header entry AT_PHNUM = 5, // Number of program headers AT_PAGESZ = 6, // System page size AT_BASE = 7, // Base address of interpreter AT_FLAGS = 8, // Flags AT_ENTRY = 9, // Entry point of program AT_NOTELF = 10, // Program is not ELF AT_UID = 11, // Real uid AT_EUID = 12, // Effective uid AT_GID = 13, // Real gid AT_EGID = 14, // Effective gid AT_CLKTCK = 17, // Frequency of times() // Some more special a_type values describing the hardware. AT_PLATFORM = 15, // String identifying platform. AT_HWCAP = 16, // Machine dependent hints about processor capabilities. // This entry gives some information about the FPU initialization // performed by the kernel. AT_FPUCW = 18, // Used FPU control word. // Cache block sizes. AT_DCACHEBSIZE = 19, // Data cache block size. AT_ICACHEBSIZE = 20, // Instruction cache block size. AT_UCACHEBSIZE = 21, // Unified cache block size. // A special ignored value for PPC, used by the kernel to control the // interpretation of the AUXV. Must be > 16. AT_IGNOREPPC = 22, // Entry should be ignored. AT_SECURE = 23, // Boolean, was exec setuid-like? AT_BASE_PLATFORM = 24, // String identifying real platforms. AT_RANDOM = 25, // Address of 16 random bytes. AT_EXECFN = 31, // Filename of executable. // Pointer to the global system page used for system calls and other // nice things. AT_SYSINFO = 32, AT_SYSINFO_EHDR = 33, // Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains // log2 of line size; mask those to get cache size. AT_L1I_CACHESHAPE = 34, AT_L1D_CACHESHAPE = 35, AT_L2_CACHESHAPE = 36, AT_L3_CACHESHAPE = 37 }; #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_rel.h0000644000175000017500000000267213273160654021430 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_REL_20121007_H_ #define ELF_REL_20121007_H_ #include "elf/elf_types.h" // Relocation table entry without addend (in section of type SHT_REL). struct elf32_rel { elf32_addr r_offset; /* Address */ elf32_word r_info; /* Relocation type and symbol index */ }; /* I have seen two different definitions of the Elf64_Rel and Elf64_Rela structures, so we'll leave them out until Novell (or whoever) gets their act together. */ /* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ struct elf64_rel { elf64_addr r_offset; /* Address */ elf64_xword r_info; /* Relocation type and symbol index */ }; #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_nhdr.h0000644000175000017500000000552313273160654021577 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_NHDR_20121007_H_ #define ELF_NHDR_20121007_H_ #include "elf/elf_types.h" /* Note section contents. Each entry in the note section begins with a header of a fixed form. */ struct elf32_nhdr { elf32_word n_namesz; /* Length of the note's name. */ elf32_word n_descsz; /* Length of the note's descriptor. */ elf32_word n_type; /* Type of the note. */ }; struct elf64_nhdr { elf64_word n_namesz; /* Length of the note's name. */ elf64_word n_descsz; /* Length of the note's descriptor. */ elf64_word n_type; /* Type of the note. */ }; /* Known names of notes. */ /* Solaris entries in the note section have this name. */ #define ELF_NOTE_SOLARIS "SUNW Solaris" /* Note entries for GNU systems have this name. */ #define ELF_NOTE_GNU "GNU" /* Defined types of notes for Solaris. */ /* Value of descriptor (one word) is desired pagesize for the binary. */ #define ELF_NOTE_PAGESIZE_HINT 1 /* Defined note types for GNU systems. */ /* ABI information. The descriptor consists of words: word 0: OS descriptor word 1: major version of the ABI word 2: minor version of the ABI word 3: subminor version of the ABI */ #define NT_GNU_ABI_TAG 1 #define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ /* Known OSes. These values can appear in word 0 of an NT_GNU_ABI_TAG note section entry. */ #define ELF_NOTE_OS_LINUX 0 #define ELF_NOTE_OS_GNU 1 #define ELF_NOTE_OS_SOLARIS2 2 #define ELF_NOTE_OS_FREEBSD 3 /* Synthetic hwcap information. The descriptor begins with two words: word 0: number of entries word 1: bitmask of enabled entries Then follow variable-length entries, one byte followed by a '\0'-terminated hwcap name string. The byte gives the bit number to test if enabled, (1U << bit) & bitmask. */ #define NT_GNU_HWCAP 2 /* Build ID bits as generated by ld --build-id. The descriptor consists of any nonzero number of bytes. */ #define NT_GNU_BUILD_ID 3 /* Version note generated by GNU gold containing a version string. */ #define NT_GNU_GOLD_VERSION 4 #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_rela.h0000644000175000017500000000325713273160654021571 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_RELA_20121007_H_ #define ELF_RELA_20121007_H_ #include "elf/elf_types.h" /* Relocation table entry with addend (in section of type SHT_RELA). */ struct elf32_rela { elf32_addr r_offset; /* Address */ elf32_word r_info; /* Relocation type and symbol index */ elf32_sword r_addend; /* Addend */ }; struct elf64_rela { elf64_addr r_offset; /* Address */ elf64_xword r_info; /* Relocation type and symbol index */ elf64_sxword r_addend; /* Addend */ }; /* How to extract and insert information held in the r_info field. */ #define ELF32_R_SYM(val) ((val) >> 8) #define ELF32_R_TYPE(val) ((val) & 0xff) #define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) #define ELF64_R_SYM(i) ((i) >> 32) #define ELF64_R_TYPE(i) ((i) & 0xffffffff) #define ELF64_R_INFO(sym,type) ((((elf64_xword) (sym)) << 32) + (type)) #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_syminfo.h0000644000175000017500000001066413273160654022332 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_SYMINFO_20121007_H_ #define ELF_SYMINFO_20121007_H_ #include "elf/elf_types.h" /* The syminfo section if available contains additional information about every dynamic symbol. */ struct elf32_syminfo { elf32_half si_boundto; /* Direct bindings, symbol bound to */ elf32_half si_flags; /* Per symbol flags */ }; struct elf64_syminfo { elf64_half si_boundto; /* Direct bindings, symbol bound to */ elf64_half si_flags; /* Per symbol flags */ }; /* Possible values for si_boundto. */ #define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ #define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ #define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ /* Possible bitmasks for si_flags. */ #define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ #define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ #define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ #define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy loaded */ /* Syminfo version values. */ #define SYMINFO_NONE 0 #define SYMINFO_CURRENT 1 #define SYMINFO_NUM 2 /* How to extract and insert information held in the st_info field. */ #define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) #define ELF32_ST_TYPE(val) ((val) & 0xf) #define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) /* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ #define ELF64_ST_BIND(val) ELF32_ST_BIND (val) #define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) #define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) /* Legal values for ST_BIND subfield of st_info (symbol binding). */ #define STB_LOCAL 0 /* Local symbol */ #define STB_GLOBAL 1 /* Global symbol */ #define STB_WEAK 2 /* Weak symbol */ #define STB_NUM 3 /* Number of defined types. */ #define STB_LOOS 10 /* Start of OS-specific */ #define STB_GNU_UNIQUE 10 /* Unique symbol. */ #define STB_HIOS 12 /* End of OS-specific */ #define STB_LOPROC 13 /* Start of processor-specific */ #define STB_HIPROC 15 /* End of processor-specific */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_NOTYPE 0 /* Symbol type is unspecified */ #define STT_OBJECT 1 /* Symbol is a data object */ #define STT_FUNC 2 /* Symbol is a code object */ #define STT_SECTION 3 /* Symbol associated with a section */ #define STT_FILE 4 /* Symbol's name is file name */ #define STT_COMMON 5 /* Symbol is a common data object */ #define STT_TLS 6 /* Symbol is thread-local data object*/ #define STT_NUM 7 /* Number of defined types. */ #define STT_LOOS 10 /* Start of OS-specific */ #define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ #define STT_HIOS 12 /* End of OS-specific */ #define STT_LOPROC 13 /* Start of processor-specific */ #define STT_HIPROC 15 /* End of processor-specific */ /* Symbol table indices are found in the hash buckets and chain table of a symbol hash table section. This special index value indicates the end of a chain, meaning no further symbols are found in that bucket. */ #define STN_UNDEF 0 /* End of a chain. */ /* How to extract and insert information held in the st_other field. */ #define ELF32_ST_VISIBILITY(o) ((o) & 0x03) /* For ELF64 the definitions are the same. */ #define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) /* Symbol visibility specification encoded in the st_other field. */ #define STV_DEFAULT 0 /* Default symbol visibility rules */ #define STV_INTERNAL 1 /* Processor specific hidden class */ #define STV_HIDDEN 2 /* Sym unavailable in other modules */ #define STV_PROTECTED 3 /* Not preemptible, not exported */ #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_move.h0000644000175000017500000000334013273160654021605 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_MOVE_20121007_H_ #define ELF_MOVE_20121007_H_ #include "elf/elf_types.h" // Move records. struct elf32_move { elf32_xword m_value; // Symbol value. elf32_word m_info; // Size and index. elf32_word m_poffset; // Symbol offset. elf32_half m_repeat; // Repeat count. elf32_half m_stride; // Stride info. }; struct elf64_move { elf64_xword m_value; // Symbol value. elf64_xword m_info; // Size and index. elf64_xword m_poffset; // Symbol offset. elf64_half m_repeat; // Repeat count. elf64_half m_stride; // Stride info. }; // Macro to construct move records. #define ELF32_M_SYM(info) ((info) >> 8) #define ELF32_M_SIZE(info) ((unsigned char) (info)) #define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) #define ELF64_M_SYM(info) ELF32_M_SYM (info) #define ELF64_M_SIZE(info) ELF32_M_SIZE (info) #define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_header.h0000644000175000017500000002306313273160654022073 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_HEADER_20121007_H_ #define ELF_HEADER_20121007_H_ #include "elf/elf_types.h" // The ELF file header. This appears at the start of every ELF file. enum { EI_NIDENT = 16 }; /* Fields in the e_ident array. The EI_* macros are indices into the array. The macros under each EI_* macro are the values the byte may have. */ #define EI_MAG0 0 /* File identification byte 0 index */ #define ELFMAG0 0x7f /* Magic number byte 0 */ #define EI_MAG1 1 /* File identification byte 1 index */ #define ELFMAG1 'E' /* Magic number byte 1 */ #define EI_MAG2 2 /* File identification byte 2 index */ #define ELFMAG2 'L' /* Magic number byte 2 */ #define EI_MAG3 3 /* File identification byte 3 index */ #define ELFMAG3 'F' /* Magic number byte 3 */ /* Conglomeration of the identification bytes, for easy testing as a word. */ #define ELFMAG "\177ELF" #define SELFMAG 4 #define EI_CLASS 4 /* File class byte index */ #define ELFCLASSNONE 0 /* Invalid class */ #define ELFCLASS32 1 /* 32-bit objects */ #define ELFCLASS64 2 /* 64-bit objects */ #define ELFCLASSNUM 3 #define EI_DATA 5 /* Data encoding byte index */ #define ELFDATANONE 0 /* Invalid data encoding */ #define ELFDATA2LSB 1 /* 2's complement, little endian */ #define ELFDATA2MSB 2 /* 2's complement, big endian */ #define ELFDATANUM 3 #define EI_VERSION 6 /* File version byte index */ /* Value must be EV_CURRENT */ /* Legal values for e_version (version). */ #define EV_NONE 0 /* Invalid ELF version */ #define EV_CURRENT 1 /* Current version */ #define EV_NUM 2 #define EI_OSABI 7 /* OS ABI identification */ #define ELFOSABI_NONE 0 /* UNIX System V ABI */ #define ELFOSABI_SYSV 0 /* Alias. */ #define ELFOSABI_HPUX 1 /* HP-UX */ #define ELFOSABI_NETBSD 2 /* NetBSD. */ #define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ #define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ #define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ #define ELFOSABI_AIX 7 /* IBM AIX. */ #define ELFOSABI_IRIX 8 /* SGI Irix. */ #define ELFOSABI_FREEBSD 9 /* FreeBSD. */ #define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ #define ELFOSABI_MODESTO 11 /* Novell Modesto. */ #define ELFOSABI_OPENBSD 12 /* OpenBSD. */ #define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ #define ELFOSABI_ARM 97 /* ARM */ #define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ #define EI_ABIVERSION 8 /* ABI version */ #define EI_PAD 9 /* Byte index of padding bytes */ /* Legal values for e_type (object file type). */ #define ET_NONE 0 /* No file type */ #define ET_REL 1 /* Relocatable file */ #define ET_EXEC 2 /* Executable file */ #define ET_DYN 3 /* Shared object file */ #define ET_CORE 4 /* Core file */ #define ET_NUM 5 /* Number of defined types */ #define ET_LOOS 0xfe00 /* OS-specific range start */ #define ET_HIOS 0xfeff /* OS-specific range end */ #define ET_LOPROC 0xff00 /* Processor-specific range start */ #define ET_HIPROC 0xffff /* Processor-specific range end */ /* Legal values for e_machine (architecture). */ #define EM_NONE 0 /* No machine */ #define EM_M32 1 /* AT&T WE 32100 */ #define EM_SPARC 2 /* SUN SPARC */ #define EM_386 3 /* Intel 80386 */ #define EM_68K 4 /* Motorola m68k family */ #define EM_88K 5 /* Motorola m88k family */ #define EM_860 7 /* Intel 80860 */ #define EM_MIPS 8 /* MIPS R3000 big-endian */ #define EM_S370 9 /* IBM System/370 */ #define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ #define EM_PARISC 15 /* HPPA */ #define EM_VPP500 17 /* Fujitsu VPP500 */ #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ #define EM_960 19 /* Intel 80960 */ #define EM_PPC 20 /* PowerPC */ #define EM_PPC64 21 /* PowerPC 64-bit */ #define EM_S390 22 /* IBM S390 */ #define EM_V800 36 /* NEC V800 series */ #define EM_FR20 37 /* Fujitsu FR20 */ #define EM_RH32 38 /* TRW RH-32 */ #define EM_RCE 39 /* Motorola RCE */ #define EM_ARM 40 /* ARM */ #define EM_FAKE_ALPHA 41 /* Digital Alpha */ #define EM_SH 42 /* Hitachi SH */ #define EM_SPARCV9 43 /* SPARC v9 64-bit */ #define EM_TRICORE 44 /* Siemens Tricore */ #define EM_ARC 45 /* Argonaut RISC Core */ #define EM_H8_300 46 /* Hitachi H8/300 */ #define EM_H8_300H 47 /* Hitachi H8/300H */ #define EM_H8S 48 /* Hitachi H8S */ #define EM_H8_500 49 /* Hitachi H8/500 */ #define EM_IA_64 50 /* Intel Merced */ #define EM_MIPS_X 51 /* Stanford MIPS-X */ #define EM_COLDFIRE 52 /* Motorola Coldfire */ #define EM_68HC12 53 /* Motorola M68HC12 */ #define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ #define EM_PCP 55 /* Siemens PCP */ #define EM_NCPU 56 /* Sony nCPU embeeded RISC */ #define EM_NDR1 57 /* Denso NDR1 microprocessor */ #define EM_STARCORE 58 /* Motorola Start*Core processor */ #define EM_ME16 59 /* Toyota ME16 processor */ #define EM_ST100 60 /* STMicroelectronic ST100 processor */ #define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ #define EM_X86_64 62 /* AMD x86-64 architecture */ #define EM_PDSP 63 /* Sony DSP Processor */ #define EM_FX66 66 /* Siemens FX66 microcontroller */ #define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ #define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ #define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ #define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ #define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ #define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ #define EM_SVX 73 /* Silicon Graphics SVx */ #define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ #define EM_VAX 75 /* Digital VAX */ #define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ #define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ #define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ #define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ #define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ #define EM_HUANY 81 /* Harvard University machine-independent object files */ #define EM_PRISM 82 /* SiTera Prism */ #define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ #define EM_FR30 84 /* Fujitsu FR30 */ #define EM_D10V 85 /* Mitsubishi D10V */ #define EM_D30V 86 /* Mitsubishi D30V */ #define EM_V850 87 /* NEC v850 */ #define EM_M32R 88 /* Mitsubishi M32R */ #define EM_MN10300 89 /* Matsushita MN10300 */ #define EM_MN10200 90 /* Matsushita MN10200 */ #define EM_PJ 91 /* picoJava */ #define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ #define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ #define EM_NUM 95 /* If it is necessary to assign new unofficial EM_* values, please pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision with official or non-GNU unofficial values. */ #define EM_ALPHA 0x9026 struct elf32_phdr; struct elf32_header { typedef elf32_phdr elf_phdr; enum { ELFCLASS = ELFCLASS32 }; unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ elf32_half e_type; /* Object file type */ elf32_half e_machine; /* Architecture */ elf32_word e_version; /* Object file version */ elf32_addr e_entry; /* Entry point virtual address */ elf32_off e_phoff; /* Program header table file offset */ elf32_off e_shoff; /* Section header table file offset */ elf32_word e_flags; /* Processor-specific flags */ elf32_half e_ehsize; /* ELF header size in bytes */ elf32_half e_phentsize; /* Program header table entry size */ elf32_half e_phnum; /* Program header table entry count */ elf32_half e_shentsize; /* Section header table entry size */ elf32_half e_shnum; /* Section header table entry count */ elf32_half e_shstrndx; /* Section header string table index */ }; struct elf64_phdr; struct elf64_header { typedef elf64_phdr elf_phdr; enum { ELFCLASS = ELFCLASS64 }; unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ elf64_half e_type; /* Object file type */ elf64_half e_machine; /* Architecture */ elf64_word e_version; /* Object file version */ elf64_addr e_entry; /* Entry point virtual address */ elf64_off e_phoff; /* Program header table file offset */ elf64_off e_shoff; /* Section header table file offset */ elf64_word e_flags; /* Processor-specific flags */ elf64_half e_ehsize; /* ELF header size in bytes */ elf64_half e_phentsize; /* Program header table entry size */ elf64_half e_phnum; /* Program header table entry count */ elf64_half e_shentsize; /* Section header table entry size */ elf64_half e_shnum; /* Section header table entry count */ elf64_half e_shstrndx; /* Section header string table index */ }; #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_vernaux.h0000644000175000017500000000321313273160654022326 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_VERNAUX_20121007_H_ #define ELF_VERNAUX_20121007_H_ #include "elf/elf_types.h" /* Auxiliary needed version information. */ struct elf32_vernaux { elf32_word vna_hash; /* Hash value of dependency name */ elf32_half vna_flags; /* Dependency specific information */ elf32_half vna_other; /* Unused */ elf32_word vna_name; /* Dependency name string offset */ elf32_word vna_next; /* Offset in bytes to next vernaux entry */ }; struct elf64_vernaux { elf64_word vna_hash; /* Hash value of dependency name */ elf64_half vna_flags; /* Dependency specific information */ elf64_half vna_other; /* Unused */ elf64_word vna_name; /* Dependency name string offset */ elf64_word vna_next; /* Offset in bytes to next vernaux entry */ }; /* Legal values for vna_flags. */ #define VER_FLG_WEAK 0x2 /* Weak version identifier */ #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_verneed.h0000644000175000017500000000346013273160654022272 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_VERNEED_20121007_H_ #define ELF_VERNEED_20121007_H_ #include "elf/elf_types.h" /* Version dependency section. */ struct elf32_verneed { elf32_half vn_version; /* Version of structure */ elf32_half vn_cnt; /* Number of associated aux entries */ elf32_word vn_file; /* Offset of filename for this dependency */ elf32_word vn_aux; /* Offset in bytes to vernaux array */ elf32_word vn_next; /* Offset in bytes to next verneed entry */ }; struct elf64_verneed { elf64_half vn_version; /* Version of structure */ elf64_half vn_cnt; /* Number of associated aux entries */ elf64_word vn_file; /* Offset of filename for this dependency */ elf64_word vn_aux; /* Offset in bytes to vernaux array */ elf64_word vn_next; /* Offset in bytes to next verneed entry */ }; /* Legal values for vn_version (version revision). */ #define VER_NEED_NONE 0 /* No version */ #define VER_NEED_CURRENT 1 /* Current version */ #define VER_NEED_NUM 2 /* Given version number */ #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_sym.h0000644000175000017500000000300513273160654021445 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_SYM_20121007_H_ #define ELF_SYM_20121007_H_ #include "elf/elf_types.h" // Symbol table entry. struct elf32_sym { elf32_word st_name; // Symbol name (string tbl index) elf32_addr st_value; // Symbol value elf32_word st_size; // Symbol size unsigned char st_info; // Symbol type and binding unsigned char st_other; // Symbol visibility elf32_section st_shndx; // Section index }; struct elf64_sym { elf64_word st_name; // Symbol name (string tbl index) unsigned char st_info; // Symbol type and binding unsigned char st_other; // Symbol visibility elf64_section st_shndx; // Section index elf64_addr st_value; // Symbol value elf64_xword st_size; // Symbol size }; #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_verdaux.h0000644000175000017500000000235113273160654022316 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_VERDAUX_20121007_H_ #define ELF_VERDAUX_20121007_H_ #include "elf/elf_types.h" /* Auxialiary version information. */ struct elf32_verdaux { elf32_word vda_name; /* Version or dependency names */ elf32_word vda_next; /* Offset in bytes to next verdaux entry */ }; struct elf64_verdaux { elf64_word vda_name; /* Version or dependency names */ elf64_word vda_next; /* Offset in bytes to next verdaux entry */ }; #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_dyn.h0000644000175000017500000002052113273160654021431 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_DYN_20121007_H_ #define ELF_DYN_20121007_H_ #include "elf/elf_types.h" /* Dynamic section entry. */ struct elf32_dyn { elf32_sword d_tag; /* Dynamic entry type */ union { elf32_word d_val; /* Integer value */ elf32_addr d_ptr; /* Address value */ } d_un; }; struct elf64_dyn { elf64_sxword d_tag; /* Dynamic entry type */ union { elf64_xword d_val; /* Integer value */ elf64_addr d_ptr; /* Address value */ } d_un; }; /* Legal values for d_tag (dynamic entry type). */ #define DT_NULL 0 /* Marks end of dynamic section */ #define DT_NEEDED 1 /* Name of needed library */ #define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ #define DT_PLTGOT 3 /* Processor defined value */ #define DT_HASH 4 /* Address of symbol hash table */ #define DT_STRTAB 5 /* Address of string table */ #define DT_SYMTAB 6 /* Address of symbol table */ #define DT_RELA 7 /* Address of Rela relocs */ #define DT_RELASZ 8 /* Total size of Rela relocs */ #define DT_RELAENT 9 /* Size of one Rela reloc */ #define DT_STRSZ 10 /* Size of string table */ #define DT_SYMENT 11 /* Size of one symbol table entry */ #define DT_INIT 12 /* Address of init function */ #define DT_FINI 13 /* Address of termination function */ #define DT_SONAME 14 /* Name of shared object */ #define DT_RPATH 15 /* Library search path (deprecated) */ #define DT_SYMBOLIC 16 /* Start symbol search here */ #define DT_REL 17 /* Address of Rel relocs */ #define DT_RELSZ 18 /* Total size of Rel relocs */ #define DT_RELENT 19 /* Size of one Rel reloc */ #define DT_PLTREL 20 /* Type of reloc in PLT */ #define DT_DEBUG 21 /* For debugging; unspecified */ #define DT_TEXTREL 22 /* Reloc might modify .text */ #define DT_JMPREL 23 /* Address of PLT relocs */ #define DT_BIND_NOW 24 /* Process relocations of object */ #define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ #define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ #define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ #define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ #define DT_RUNPATH 29 /* Library search path */ #define DT_FLAGS 30 /* Flags for the object being loaded */ #define DT_ENCODING 32 /* Start of encoded range */ #define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ #define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ #define DT_NUM 34 /* Number used */ #define DT_LOOS 0x6000000d /* Start of OS-specific */ #define DT_HIOS 0x6ffff000 /* End of OS-specific */ #define DT_LOPROC 0x70000000 /* Start of processor-specific */ #define DT_HIPROC 0x7fffffff /* End of processor-specific */ #define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ /* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's approach. */ #define DT_VALRNGLO 0x6ffffd00 #define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ #define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ #define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ #define DT_CHECKSUM 0x6ffffdf8 #define DT_PLTPADSZ 0x6ffffdf9 #define DT_MOVEENT 0x6ffffdfa #define DT_MOVESZ 0x6ffffdfb #define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ #define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting the following DT_* entry. */ #define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ #define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ #define DT_VALRNGHI 0x6ffffdff #define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ #define DT_VALNUM 12 /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the Dyn.d_un.d_ptr field of the Elf*_Dyn structure. If any adjustment is made to the ELF object after it has been built these entries will need to be adjusted. */ #define DT_ADDRRNGLO 0x6ffffe00 #define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ #define DT_TLSDESC_PLT 0x6ffffef6 #define DT_TLSDESC_GOT 0x6ffffef7 #define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ #define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ #define DT_CONFIG 0x6ffffefa /* Configuration information. */ #define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ #define DT_AUDIT 0x6ffffefc /* Object auditing. */ #define DT_PLTPAD 0x6ffffefd /* PLT padding. */ #define DT_MOVETAB 0x6ffffefe /* Move table. */ #define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ #define DT_ADDRRNGHI 0x6ffffeff #define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ #define DT_ADDRNUM 11 /* The versioning entry types. The next are defined as part of the GNU extension. */ #define DT_VERSYM 0x6ffffff0 #define DT_RELACOUNT 0x6ffffff9 #define DT_RELCOUNT 0x6ffffffa /* These were chosen by Sun. */ #define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ #define DT_VERDEF 0x6ffffffc /* Address of version definition table */ #define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ #define DT_VERNEED 0x6ffffffe /* Address of table with needed versions */ #define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ #define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ #define DT_VERSIONTAGNUM 16 /* Sun added these machine-independent extensions in the "processor-specific" range. Be compatible. */ #define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ #define DT_FILTER 0x7fffffff /* Shared object to get values from */ #define DT_EXTRATAGIDX(tag) ((elf32_word)-((elf32_sword) (tag) <<1>>1)-1) #define DT_EXTRANUM 3 /* Values of `d_un.d_val' in the DT_FLAGS entry. */ #define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ #define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ #define DF_TEXTREL 0x00000004 /* Object contains text relocations */ #define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ #define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ /* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 entry in the dynamic section. */ #define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ #define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ #define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ #define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ #define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ #define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ #define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ #define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ #define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ #define DF_1_TRANS 0x00000200 #define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ #define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ #define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ #define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ #define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ #define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ #define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ /* Flags for the feature selection in DT_FEATURE_1. */ #define DTF_1_PARINIT 0x00000001 #define DTF_1_CONFEXP 0x00000002 /* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ #define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ #define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not generally available. */ #endif edb-debugger-1.0.0/plugins/BinaryInfo/elf/elf_shdr.h0000644000175000017500000001363413273160654021606 0ustar eteraneteran/* Copyright (C) 2012 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. 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, see . */ #ifndef ELF_SHDR_20121007_H_ #define ELF_SHDR_20121007_H_ #include "elf/elf_types.h" // Section header. struct elf32_shdr { elf32_word sh_name; /* Section name (string tbl index) */ elf32_word sh_type; /* Section type */ elf32_word sh_flags; /* Section flags */ elf32_addr sh_addr; /* Section virtual addr at execution */ elf32_off sh_offset; /* Section file offset */ elf32_word sh_size; /* Section size in bytes */ elf32_word sh_link; /* Link to another section */ elf32_word sh_info; /* Additional section information */ elf32_word sh_addralign; /* Section alignment */ elf32_word sh_entsize; /* Entry size if section holds table */ }; struct elf64_shdr { elf64_word sh_name; /* Section name (string tbl index) */ elf64_word sh_type; /* Section type */ elf64_xword sh_flags; /* Section flags */ elf64_addr sh_addr; /* Section virtual addr at execution */ elf64_off sh_offset; /* Section file offset */ elf64_xword sh_size; /* Section size in bytes */ elf64_word sh_link; /* Link to another section */ elf64_word sh_info; /* Additional section information */ elf64_xword sh_addralign; /* Section alignment */ elf64_xword sh_entsize; /* Entry size if section holds table */ }; /* Special section indices. */ #define SHN_UNDEF 0 /* Undefined section */ #define SHN_LORESERVE 0xff00 /* Start of reserved indices */ #define SHN_LOPROC 0xff00 /* Start of processor-specific */ #define SHN_BEFORE 0xff00 /* Order section before all others (Solaris). */ #define SHN_AFTER 0xff01 /* Order section after all others (Solaris). */ #define SHN_HIPROC 0xff1f /* End of processor-specific */ #define SHN_LOOS 0xff20 /* Start of OS-specific */ #define SHN_HIOS 0xff3f /* End of OS-specific */ #define SHN_ABS 0xfff1 /* Associated symbol is absolute */ #define SHN_COMMON 0xfff2 /* Associated symbol is common */ #define SHN_XINDEX 0xffff /* Index is in extra table. */ #define SHN_HIRESERVE 0xffff /* End of reserved indices */ /* Legal values for sh_type (section type). */ #define SHT_NULL 0 /* Section header table entry unused */ #define SHT_PROGBITS 1 /* Program data */ #define SHT_SYMTAB 2 /* Symbol table */ #define SHT_STRTAB 3 /* String table */ #define SHT_RELA 4 /* Relocation entries with addends */ #define SHT_HASH 5 /* Symbol hash table */ #define SHT_DYNAMIC 6 /* Dynamic linking information */ #define SHT_NOTE 7 /* Notes */ #define SHT_NOBITS 8 /* Program space with no data (bss) */ #define SHT_REL 9 /* Relocation entries, no addends */ #define SHT_SHLIB 10 /* Reserved */ #define SHT_DYNSYM 11 /* Dynamic linker symbol table */ #define SHT_INIT_ARRAY 14 /* Array of constructors */ #define SHT_FINI_ARRAY 15 /* Array of destructors */ #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ #define SHT_GROUP 17 /* Section group */ #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ #define SHT_NUM 19 /* Number of defined types. */ #define SHT_LOOS 0x60000000 /* Start OS-specific. */ #define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ #define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ #define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ #define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ #define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ #define SHT_SUNW_move 0x6ffffffa #define SHT_SUNW_COMDAT 0x6ffffffb #define SHT_SUNW_syminfo 0x6ffffffc #define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ #define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ #define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ #define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ #define SHT_HIOS 0x6fffffff /* End OS-specific type */ #define SHT_LOPROC 0x70000000 /* Start of processor-specific */ #define SHT_HIPROC 0x7fffffff /* End of processor-specific */ #define SHT_LOUSER 0x80000000 /* Start of application-specific */ #define SHT_HIUSER 0x8fffffff /* End of application-specific */ /* Legal values for sh_flags (section flags). */ #define SHF_WRITE (1 << 0) /* Writable */ #define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ #define SHF_EXECINSTR (1 << 2) /* Executable */ #define SHF_MERGE (1 << 4) /* Might be merged */ #define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ #define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ #define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ #define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling required */ #define SHF_GROUP (1 << 9) /* Section is member of a group. */ #define SHF_TLS (1 << 10) /* Section hold thread-local data. */ #define SHF_MASKOS 0x0ff00000 /* OS-specific. */ #define SHF_MASKPROC 0xf0000000 /* Processor-specific */ #define SHF_ORDERED (1 << 30) /* Special ordering requirement (Solaris). */ #define SHF_EXCLUDE (1 << 31) /* Section is excluded unless referenced or allocated (Solaris).*/ /* Section group handling. */ #define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ #endif edb-debugger-1.0.0/plugins/BinaryInfo/BinaryInfo.cpp0000644000175000017500000001127413273160654021643 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "BinaryInfo.h" #include "DialogHeader.h" #include "ELFXX.h" #include "IBinary.h" #include "ISymbolManager.h" #include "PE32.h" #include "edb.h" #include "symbols.h" #include "OptionsPage.h" #include #include #include #include namespace BinaryInfoPlugin { namespace { //------------------------------------------------------------------------------ // Name: create_binary_info_elf32 // Desc: //------------------------------------------------------------------------------ std::unique_ptr create_binary_info_elf32(const std::shared_ptr ®ion) { return std::unique_ptr(new ELF32(region)); } //------------------------------------------------------------------------------ // Name: create_binary_info_elf64 // Desc: //------------------------------------------------------------------------------ std::unique_ptr create_binary_info_elf64(const std::shared_ptr ®ion) { return std::unique_ptr(new ELF64(region)); } //------------------------------------------------------------------------------ // Name: create_binary_info_pe32 // Desc: //------------------------------------------------------------------------------ std::unique_ptr create_binary_info_pe32(const std::shared_ptr ®ion) { return std::unique_ptr(new PE32(region)); } } //------------------------------------------------------------------------------ // Name: BinaryInfo // Desc: //------------------------------------------------------------------------------ BinaryInfo::BinaryInfo() : menu_(0) { } //------------------------------------------------------------------------------ // Name: private_init // Desc: //------------------------------------------------------------------------------ void BinaryInfo::private_init() { edb::v1::register_binary_info(create_binary_info_elf32); edb::v1::register_binary_info(create_binary_info_elf64); edb::v1::register_binary_info(create_binary_info_pe32); edb::v1::symbol_manager().set_symbol_generator(this); } QWidget* BinaryInfo::options_page() { return new OptionsPage; } //------------------------------------------------------------------------------ // Name: menu // Desc: //------------------------------------------------------------------------------ QMenu *BinaryInfo::menu(QWidget *parent) { Q_ASSERT(parent); if(!menu_) { menu_ = new QMenu(tr("Binary Info"), parent); menu_->addAction(tr("&Explore Binary Header"), this, SLOT(explore_header())); } return menu_; } //------------------------------------------------------------------------------ // Name: explore_header // Desc: //------------------------------------------------------------------------------ void BinaryInfo::explore_header() { static auto dialog = new DialogHeader(edb::v1::debugger_ui); dialog->show(); } //------------------------------------------------------------------------------ // Name: extra_arguments // Desc: //------------------------------------------------------------------------------ QString BinaryInfo::extra_arguments() const { return " --symbols : generate symbols for and exit"; } //------------------------------------------------------------------------------ // Name: parse_arguments // Desc: //------------------------------------------------------------------------------ IPlugin::ArgumentStatus BinaryInfo::parse_arguments(QStringList &args) { if(args.size() == 3 && args[1] == "--symbols") { generate_symbols(args[2]); return ARG_EXIT; } return ARG_SUCCESS; } //------------------------------------------------------------------------------ // Name: generate_symbol_file // Desc: //------------------------------------------------------------------------------ bool BinaryInfo::generate_symbol_file(const QString &filename, const QString &symbol_file) { std::ofstream file(qPrintable(symbol_file)); if(file) { if(generate_symbols(filename, file)) { return true; } } return false; } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(BinaryInfo, BinaryInfo) #endif } edb-debugger-1.0.0/plugins/BreakpointManager/0000755000175000017500000000000013273160654020423 5ustar eteraneteranedb-debugger-1.0.0/plugins/BreakpointManager/DialogBreakpoints.ui0000644000175000017500000001104613273160654024365 0ustar eteraneteran Evan Teran BreakpointManagerPlugin::DialogBreakpoints 0 0 803 264 Breakpoint Manager &Import Breakpoints Set Breakpoint &Condition Qt::Vertical 20 40 &Close true &Remove Breakpoint &Add Breakpoint QAbstractItemView::NoEditTriggers true QAbstractItemView::SingleSelection QAbstractItemView::SelectRows true false Address Condition Original Byte Type Function Qt::Vertical 20 40 &Export Breakpoints tableWidget btnAdd btnRemove btnCondition okButton okButton clicked() DialogBreakpoints accept() 793 254 516 174 on_btnImport_clicked() on_btnExport_clicked() edb-debugger-1.0.0/plugins/BreakpointManager/DialogBreakpoints.cpp0000644000175000017500000002712413273160654024536 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "DialogBreakpoints.h" #include "Expression.h" #include "IDebugger.h" #include "IBreakpoint.h" #include "edb.h" #include "MemoryRegions.h" #include #include #include #include #include #include #include #include #include #include "ui_DialogBreakpoints.h" namespace BreakpointManagerPlugin { //------------------------------------------------------------------------------ // Name: DialogBreakpoints // Desc: //------------------------------------------------------------------------------ DialogBreakpoints::DialogBreakpoints(QWidget *parent) : QDialog(parent), ui(new Ui::DialogBreakpoints) { ui->setupUi(this); #if QT_VERSION >= 0x050000 ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); #else ui->tableWidget->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents); #endif } //------------------------------------------------------------------------------ // Name: ~DialogBreakpoints // Desc: //------------------------------------------------------------------------------ DialogBreakpoints::~DialogBreakpoints() { delete ui; } //------------------------------------------------------------------------------ // Name: showEvent // Desc: //------------------------------------------------------------------------------ void DialogBreakpoints::showEvent(QShowEvent *) { connect(edb::v1::disassembly_widget(), SIGNAL(signal_updated()), this, SLOT(updateList())); updateList(); } void DialogBreakpoints::hideEvent(QHideEvent *) { disconnect(edb::v1::disassembly_widget(), SIGNAL(signal_updated()), this, SLOT(updateList())); } //------------------------------------------------------------------------------ // Name: updateList // Desc: //------------------------------------------------------------------------------ void DialogBreakpoints::updateList() { ui->tableWidget->setSortingEnabled(false); ui->tableWidget->setRowCount(0); const IDebugger::BreakpointList breakpoint_state = edb::v1::debugger_core->backup_breakpoints(); for(const std::shared_ptr &bp: breakpoint_state) { //Skip if it's an internal bp; we don't want to insert a row for it. if (bp->internal()) { continue; } const int row = ui->tableWidget->rowCount(); ui->tableWidget->insertRow(row); const edb::address_t address = bp->address(); const QString condition = bp->condition; const bool onetime = bp->one_time(); const QString symname = edb::v1::find_function_symbol(address, QString(), 0); const QString bytes = edb::v1::format_bytes(bp->original_bytes(), bp->size()); auto item = new QTableWidgetItem(edb::v1::format_pointer(address)); item->setData(Qt::UserRole, address); ui->tableWidget->setItem(row, 0, item); ui->tableWidget->setItem(row, 1, new QTableWidgetItem(condition)); ui->tableWidget->setItem(row, 2, new QTableWidgetItem(bytes)); ui->tableWidget->setItem(row, 3, new QTableWidgetItem(onetime ? tr("One Time") : tr("Standard"))); ui->tableWidget->setItem(row, 4, new QTableWidgetItem(symname)); } ui->tableWidget->setSortingEnabled(true); } //------------------------------------------------------------------------------ // Name: on_btnAdd_clicked // Desc: //------------------------------------------------------------------------------ void DialogBreakpoints::on_btnAdd_clicked() { bool ok; QString text = QInputDialog::getText(this, tr("Add Breakpoint"), tr("Address:"), QLineEdit::Normal, QString(), &ok); if(ok && !text.isEmpty()) { Expression expr(text, edb::v1::get_variable, edb::v1::get_value); ExpressionError err; const edb::address_t address = expr.evaluate_expression(&ok, &err); if(ok) { edb::v1::create_breakpoint(address); updateList(); } else { QMessageBox::critical(this, tr("Error In Address Expression!"), err.what()); } } } //------------------------------------------------------------------------------ // Name: on_btnCondition_clicked // Desc: //------------------------------------------------------------------------------ void DialogBreakpoints::on_btnCondition_clicked() { QList sel = ui->tableWidget->selectedItems(); if(!sel.empty()) { QTableWidgetItem *const item = sel[0]; bool ok; const edb::address_t address = item->data(Qt::UserRole).toULongLong(); const QString condition = edb::v1::get_breakpoint_condition(address); const QString text = QInputDialog::getText(this, tr("Set Breakpoint Condition"), tr("Expression:"), QLineEdit::Normal, condition, &ok); if(ok) { edb::v1::set_breakpoint_condition(address, text); updateList(); } } } #if 0 //------------------------------------------------------------------------------ // Name: on_btnAddFunction_clicked // Desc: //------------------------------------------------------------------------------ void DialogBreakpoints::on_btnAddFunction_clicked() { bool ok; const QString text = QInputDialog::getText(this, tr("Add Breakpoint On Library Function"), tr("Function Name:"), QLineEdit::Normal, QString(), &ok); if(ok && !text.isEmpty()) { const QList> syms = edb::v1::symbol_manager().symbols(); for(const std::shared_ptr ¤t: syms) { if(current.name_no_prefix == text) { edb::v1::create_breakpoint(current.address); } } updateList(); } } #endif //------------------------------------------------------------------------------ // Name: on_btnRemove_clicked // Desc: //------------------------------------------------------------------------------ void DialogBreakpoints::on_btnRemove_clicked() { QList sel = ui->tableWidget->selectedItems(); if(!sel.empty()) { QTableWidgetItem *const item = sel[0]; const edb::address_t address = item->data(Qt::UserRole).toULongLong(); edb::v1::remove_breakpoint(address); } updateList(); } //------------------------------------------------------------------------------ // Name: on_tableWidget_cellDoubleClicked // Desc: //------------------------------------------------------------------------------ void DialogBreakpoints::on_tableWidget_cellDoubleClicked(int row, int col) { switch(col) { case 0: // address if(QTableWidgetItem *const address_item = ui->tableWidget->item(row, 0)) { const edb::address_t address = address_item->data(Qt::UserRole).toULongLong(); edb::v1::jump_to_address(address); } break; case 1: // condition if(QTableWidgetItem *const address_item = ui->tableWidget->item(row, 0)) { bool ok; const edb::address_t address = address_item->data(Qt::UserRole).toULongLong(); const QString condition = edb::v1::get_breakpoint_condition(address); const QString text = QInputDialog::getText(this, tr("Set Breakpoint Condition"), tr("Expression:"), QLineEdit::Normal, condition, &ok); if(ok) { edb::v1::set_breakpoint_condition(address, text); updateList(); } } break; } } //------------------------------------------------------------------------------ // Name: on_btnImport_clicked() // Desc: Opens a file selection window to choose a file with newline-separated, // hex address breakpoints. //------------------------------------------------------------------------------ void DialogBreakpoints::on_btnImport_clicked() { //Let the user choose the file; get the file name. QString home_directory = QDir::homePath(); QString file_name = QFileDialog::getOpenFileName(this, tr("Breakpoint Import File"), home_directory, NULL); if (file_name.isEmpty()) { return; } //Open the file; fail if error or it doesn't exist. QFile file(file_name); if (!file.open(QIODevice::ReadOnly)) { QMessageBox::critical(this, tr("Error Opening File"), tr("Unable to open breakpoint file: %1").arg(file_name)); return; } //Keep a list of any lines in the file that don't make valid breakpoints. QStringList errors; //Iterate through each line; attempt to make a breakpoint for each line. //Addreses should be prefixed with 0x, i.e. a hex number. //Count each breakpoint successfully made. int count = 0; Q_FOREVER { //Get the address QString line = file.readLine().trimmed(); if(line.isEmpty()) { break; } bool ok; int base = 16; edb::address_t address = line.toULong(&ok, base); //Skip if there's an issue. if (!ok) { errors.append(line); continue; } //If there's an issue with the line or address isn't in any region, //add to error list and skip. edb::v1::memory_regions().sync(); std::shared_ptr p = edb::v1::memory_regions().find_region(address); if (!p) { errors.append(line); continue; } //If the bp already exists, skip. No error. if (edb::v1::debugger_core->find_breakpoint(address)) { continue; } //If the line was converted to an address, try to create the breakpoint. //Access debugger_core directly to avoid many possible error windows by edb::v1::create_breakpoint() if (const std::shared_ptr bp = edb::v1::debugger_core->add_breakpoint(address)) { count++; } else{ errors.append(line); } } //Report any errors to the user if (errors.size() > 0) { QMessageBox::warning(this, tr("Invalid Breakpoints"), tr("The following breakpoints were not made:\n%1").arg(errors.join(""))); } //Report breakpoints successfully made QMessageBox::information(this, tr("Breakpoint Import"), tr("Imported %1 breakpoints.").arg(count)); updateList(); } //------------------------------------------------------------------------------ // Name: on_btnExport_clicked() // Desc: Opens a file selection window to choose a file to save newline-separated, // hex address breakpoints. //------------------------------------------------------------------------------ void DialogBreakpoints::on_btnExport_clicked() { //Get the current list of breakpoints const IDebugger::BreakpointList breakpoint_state = edb::v1::debugger_core->backup_breakpoints(); //Create a list for addresses to be exported at the end QList export_list; //Go through our breakpoints and add for export if not one-time and not internal. for(const std::shared_ptr &bp: breakpoint_state) { if (!bp->one_time() && !bp->internal()) { export_list.append(bp->address()); } } //If there are no breakpoints, fail if (export_list.isEmpty()) { QMessageBox::critical(this, tr("No Breakpoints"), tr("There are no breakpoints to export.")); return; } //Now ask the user for a file, open it, and write each address to it. QString filename = QFileDialog::getSaveFileName(this, tr("Breakpoint Export File"), QDir::homePath()); if (filename.isEmpty()) { return; } QFile file(filename); if (!file.open(QIODevice::WriteOnly)) { return; } for(edb::address_t address: export_list) { int base = 16; QString string_address = "0x" + QString::number(address, base) + "\n"; file.write(string_address.toLatin1()); } QMessageBox::information(this, tr("Breakpoint Export"), tr("Exported %1 breakpoints").arg(export_list.size())); } } edb-debugger-1.0.0/plugins/BreakpointManager/BreakpointManager.h0000644000175000017500000000247413273160654024174 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef BREAKPOINTMANAGER_20060430_H_ #define BREAKPOINTMANAGER_20060430_H_ #include "IPlugin.h" class QMenu; class QDialog; namespace BreakpointManagerPlugin { class BreakpointManager : public QObject, public IPlugin { Q_OBJECT Q_INTERFACES(IPlugin) #if QT_VERSION >= 0x050000 Q_PLUGIN_METADATA(IID "edb.IPlugin/1.0") #endif Q_CLASSINFO("author", "Evan Teran") Q_CLASSINFO("url", "http://www.codef00.com") public: BreakpointManager(); virtual ~BreakpointManager(); public: virtual QMenu *menu(QWidget *parent = 0); public Q_SLOTS: void show_menu(); private: QMenu * menu_; QPointer dialog_; }; } #endif edb-debugger-1.0.0/plugins/BreakpointManager/CMakeLists.txt0000644000175000017500000000177313273160654023173 0ustar eteraneterancmake_minimum_required (VERSION 2.8) include("GNUInstallDirs") set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) include("${PROJECT_SOURCE_DIR}/cmake/EnableCXX11.cmake") set(PluginName "BreakpointManager") set(UI_FILES DialogBreakpoints.ui) if(Qt5Core_FOUND) find_package(Qt5 5.0.0 REQUIRED Widgets) qt5_wrap_ui(UI_H ${UI_FILES}) else(Qt5Core_FOUND) find_package(Qt4 4.6.0 QUIET REQUIRED QtCore QtGui) include(${QT_USE_FILE}) qt4_wrap_ui(UI_H ${UI_FILES}) endif() # we put the header files from the include directory here # too so automoc can "just work" add_library(${PluginName} SHARED BreakpointManager.cpp BreakpointManager.h DialogBreakpoints.cpp DialogBreakpoints.h ${UI_H} ) if(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt5::Widgets) else(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt4::QtGui) endif() set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}) install (TARGETS ${PluginName} DESTINATION ${CMAKE_INSTALL_LIBDIR}/edb) edb-debugger-1.0.0/plugins/BreakpointManager/BreakpointManager.cpp0000644000175000017500000000430513273160654024522 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "BreakpointManager.h" #include "DialogBreakpoints.h" #include "edb.h" #include #include namespace BreakpointManagerPlugin { //------------------------------------------------------------------------------ // Name: BreakpointManager // Desc: //------------------------------------------------------------------------------ BreakpointManager::BreakpointManager() : menu_(0), dialog_(0) { } //------------------------------------------------------------------------------ // Name: ~BreakpointManager // Desc: //------------------------------------------------------------------------------ BreakpointManager::~BreakpointManager() { delete dialog_; } //------------------------------------------------------------------------------ // Name: menu // Desc: //------------------------------------------------------------------------------ QMenu *BreakpointManager::menu(QWidget *parent) { Q_ASSERT(parent); if(!menu_) { menu_ = new QMenu(tr("BreakpointManager"), parent); menu_->addAction(tr("&Breakpoints"), this, SLOT(show_menu()), QKeySequence(tr("Ctrl+B"))); } return menu_; } //------------------------------------------------------------------------------ // Name: show_menu // Desc: //------------------------------------------------------------------------------ void BreakpointManager::show_menu() { if(!dialog_) { dialog_ = new DialogBreakpoints(edb::v1::debugger_ui); } dialog_->show(); } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(BreakpointManager, BreakpointManager) #endif } edb-debugger-1.0.0/plugins/BreakpointManager/DialogBreakpoints.h0000644000175000017500000000261713273160654024203 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DIALOGBREAKPOINTS_20061101_H_ #define DIALOGBREAKPOINTS_20061101_H_ #include namespace BreakpointManagerPlugin { namespace Ui { class DialogBreakpoints; } class DialogBreakpoints : public QDialog { Q_OBJECT public: DialogBreakpoints(QWidget *parent = 0); virtual ~DialogBreakpoints(); public Q_SLOTS: void updateList(); void on_btnAdd_clicked(); void on_btnRemove_clicked(); void on_btnCondition_clicked(); void on_tableWidget_cellDoubleClicked(int row, int col); void on_btnImport_clicked(); void on_btnExport_clicked(); private: virtual void showEvent(QShowEvent *event); virtual void hideEvent(QHideEvent *event); private: Ui::DialogBreakpoints *const ui; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/0000755000175000017500000000000013273160654017367 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/unix/0000755000175000017500000000000013273160654020352 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/unix/freebsd/0000755000175000017500000000000013273160654021764 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/unix/freebsd/DebuggerCore.h0000644000175000017500000000613213273160654024474 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DEBUGGERCORE_20090529_H_ #define DEBUGGERCORE_20090529_H_ #include "DebuggerCoreUNIX.h" #include namespace DebuggerCore { class DebuggerCore : public DebuggerCoreUNIX { Q_OBJECT Q_INTERFACES(IDebugger) Q_CLASSINFO("author", "Evan Teran") Q_CLASSINFO("url", "http://www.codef00.com") public: DebuggerCore(); virtual ~DebuggerCore(); public: virtual edb::address_t page_size() const; virtual bool has_extension(quint64 ext) const; virtual std::shared_ptr wait_debug_event(int msecs); virtual bool attach(edb::pid_t pid); virtual void detach(); virtual void kill(); virtual void pause(); virtual void resume(edb::EVENT_STATUS status); virtual void step(edb::EVENT_STATUS status); virtual void get_state(State *state); virtual void set_state(const State &state); virtual bool open(const QString &path, const QString &cwd, const QList &args, const QString &tty); public: // thread support stuff (optional) virtual QList thread_ids() const { return threads_.keys(); } virtual edb::tid_t active_thread() const { return active_thread_; } virtual void set_active_thread(edb::tid_t); public: virtual QList> memory_regions() const; virtual edb::address_t process_code_address() const; virtual edb::address_t process_data_address() const; public: virtual IState *create_state() const; public: // process properties virtual QList process_args(edb::pid_t pid) const; virtual QString process_exe(edb::pid_t pid) const; virtual QString process_cwd(edb::pid_t pid) const; virtual edb::pid_t parent_pid(edb::pid_t pid) const; virtual QDateTime process_start(edb::pid_t pid) const; virtual quint64 cpu_type() const; public: virtual QMap enumerate_processes() const; virtual QList loaded_modules() const; public: virtual QString stack_pointer() const; virtual QString frame_pointer() const; virtual QString instruction_pointer() const; public: virtual QString format_pointer(edb::address_t address) const; private: virtual long read_data(edb::address_t address, bool *ok); virtual bool write_data(edb::address_t address, long value); private: struct thread_info { public: thread_info() : status(0) { } thread_info(int s) : status(s) { } int status; }; typedef QHash threadmap_t; edb::address_t page_size_; threadmap_t threads_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/freebsd/PlatformProcess.cpp0000644000175000017500000000133513273160654025615 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformProcess.h" edb-debugger-1.0.0/plugins/DebuggerCore/unix/freebsd/PlatformEvent.h0000644000175000017500000000311313273160654024721 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_EVENT_20121005_H_ #define PLATFORM_EVENT_20121005_H_ #include #include "IDebugEvent.h" namespace DebuggerCore { class PlatformEvent : IDebugEvent { Q_DECLARE_TR_FUNCTIONS(PlatformEvent) friend class DebuggerCore; public: PlatformEvent(); public: virtual PlatformEvent *clone() const; public: virtual Message error_description() const; virtual REASON reason() const; virtual TRAP_REASON trap_reason() const; virtual bool exited() const; virtual bool is_error() const; virtual bool is_kill() const; virtual bool is_stop() const; virtual bool is_trap() const; virtual bool terminated() const; virtual bool stopped() const; virtual edb::pid_t process() const; virtual edb::tid_t thread() const; virtual int code() const; private: int status; edb::pid_t pid; edb::tid_t tid; void * fault_address_; long fault_code_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/freebsd/PlatformRegion.h0000644000175000017500000000347713273160654025100 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_REGION_20120330_H_ #define PLATFORM_REGION_20120330_H_ #include "IRegion.h" #include #include namespace DebuggerCore { class PlatformRegion : public IRegion { Q_DECLARE_TR_FUNCTIONS(PlatformRegion) public: PlatformRegion(edb::address_t start, edb::address_t end, edb::address_t base, const QString &name, permissions_t permissions); virtual ~PlatformRegion(); public: virtual IRegion *clone() const; public: virtual bool accessible() const; virtual bool readable() const; virtual bool writable() const; virtual bool executable() const; virtual edb::address_t size() const; public: virtual void set_permissions(bool read, bool write, bool execute); virtual void set_start(edb::address_t address); virtual void set_end(edb::address_t address); public: virtual edb::address_t start() const; virtual edb::address_t end() const; virtual edb::address_t base() const; virtual QString name() const; virtual permissions_t permissions() const; private: edb::address_t start_; edb::address_t end_; edb::address_t base_; QString name_; permissions_t permissions_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/freebsd/PlatformRegion.cpp0000644000175000017500000000450713273160654025426 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformRegion.h" #include "MemoryRegions.h" #include "edb.h" #include "IDebugger.h" #include "State.h" #include "IDebugEventHandler.h" #include #include #include namespace DebuggerCore { PlatformRegion::PlatformRegion(edb::address_t start, edb::address_t end, edb::address_t base, const QString &name, permissions_t permissions) : start_(start), end_(end), base_(base), name_(name), permissions_(permissions) { } PlatformRegion::~PlatformRegion() { } IRegion *PlatformRegion::clone() const { return new PlatformRegion(start_, end_, base_, name_, permissions_); } bool PlatformRegion::accessible() const { return readable() || writable() || executable(); } bool PlatformRegion::readable() const { return (permissions_ & PROT_READ) != 0; } bool PlatformRegion::writable() const { return (permissions_ & PROT_WRITE) != 0; } bool PlatformRegion::executable() const { return (permissions_ & PROT_EXEC) != 0; } edb::address_t PlatformRegion::size() const { return end_ - start_; } void PlatformRegion::set_permissions(bool read, bool write, bool execute) { Q_UNUSED(read); Q_UNUSED(write); Q_UNUSED(execute); } edb::address_t PlatformRegion::start() const { return start_; } edb::address_t PlatformRegion::end() const { return end_; } edb::address_t PlatformRegion::base() const { return base_; } QString PlatformRegion::name() const { return name_; } IRegion::permissions_t PlatformRegion::permissions() const { return permissions_; } void PlatformRegion::set_start(edb::address_t address) { start_ = address; } void PlatformRegion::set_end(edb::address_t address) { end_ = address; } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/freebsd/PlatformProcess.h0000644000175000017500000000153113273160654025260 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATOFORM_PROCESS_20150517_H_ #define PLATOFORM_PROCESS_20150517_H_ #include "IProcess.h" class PlatformProcess : public IProcess { }; #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/freebsd/PlatformState.cpp0000644000175000017500000004644513273160654025272 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformState.h" namespace DebuggerCore { //------------------------------------------------------------------------------ // Name: PlatformState // Desc: //------------------------------------------------------------------------------ PlatformState::PlatformState() { memset(®s_, 0, sizeof(regs_)); memset(&fpregs_, 0, sizeof(fpregs_)); memset(&dr_, 0, sizeof(dr_)); fs_base = 0; gs_base = 0; } //------------------------------------------------------------------------------ // Name: PlatformState::clone // Desc: makes a copy of the state object //------------------------------------------------------------------------------ IState *PlatformState::clone() const { return new PlatformState(*this); } //------------------------------------------------------------------------------ // Name: flags_to_string // Desc: returns the flags in a string form appropriate for this platform //------------------------------------------------------------------------------ QString PlatformState::flags_to_string(edb::reg_t flags) const { char buf[14]; qsnprintf( buf, sizeof(buf), "%c %c %c %c %c %c %c", ((flags & 0x001) ? 'C' : 'c'), ((flags & 0x004) ? 'P' : 'p'), ((flags & 0x010) ? 'A' : 'a'), ((flags & 0x040) ? 'Z' : 'z'), ((flags & 0x080) ? 'S' : 's'), ((flags & 0x400) ? 'D' : 'd'), ((flags & 0x800) ? 'O' : 'o')); return buf; } //------------------------------------------------------------------------------ // Name: flags_to_string // Desc: returns the flags in a string form appropriate for this platform //------------------------------------------------------------------------------ QString PlatformState::flags_to_string() const { return flags_to_string(flags()); } //------------------------------------------------------------------------------ // Name: value // Desc: returns a Register object which represents the register with the name // supplied //------------------------------------------------------------------------------ Register PlatformState::value(const QString ®) const { const QString lreg = reg.toLower(); #if defined(EDB_X86) if(lreg == "eax") return Register("eax", regs_.r_eax, Register::TYPE_GPR); else if(lreg == "ebx") return Register("ebx", regs_.r_ebx, Register::TYPE_GPR); else if(lreg == "ecx") return Register("ecx", regs_.r_ecx, Register::TYPE_GPR); else if(lreg == "edx") return Register("edx", regs_.r_edx, Register::TYPE_GPR); else if(lreg == "ebp") return Register("ebp", regs_.r_ebp, Register::TYPE_GPR); else if(lreg == "esp") return Register("esp", regs_.r_esp, Register::TYPE_GPR); else if(lreg == "esi") return Register("esi", regs_.r_esi, Register::TYPE_GPR); else if(lreg == "edi") return Register("edi", regs_.r_edi, Register::TYPE_GPR); else if(lreg == "eip") return Register("eip", regs_.r_eip, Register::TYPE_IP); else if(lreg == "ax") return Register("ax", regs_.r_eax & 0xffff, Register::TYPE_GPR); else if(lreg == "bx") return Register("bx", regs_.r_ebx & 0xffff, Register::TYPE_GPR); else if(lreg == "cx") return Register("cx", regs_.r_ecx & 0xffff, Register::TYPE_GPR); else if(lreg == "dx") return Register("dx", regs_.r_edx & 0xffff, Register::TYPE_GPR); else if(lreg == "bp") return Register("bp", regs_.r_ebp & 0xffff, Register::TYPE_GPR); else if(lreg == "sp") return Register("sp", regs_.r_esp & 0xffff, Register::TYPE_GPR); else if(lreg == "si") return Register("si", regs_.r_esi & 0xffff, Register::TYPE_GPR); else if(lreg == "di") return Register("di", regs_.r_edi & 0xffff, Register::TYPE_GPR); else if(lreg == "al") return Register("al", regs_.r_eax & 0xff, Register::TYPE_GPR); else if(lreg == "bl") return Register("bl", regs_.r_ebx & 0xff, Register::TYPE_GPR); else if(lreg == "cl") return Register("cl", regs_.r_ecx & 0xff, Register::TYPE_GPR); else if(lreg == "dl") return Register("dl", regs_.r_edx & 0xff, Register::TYPE_GPR); else if(lreg == "ah") return Register("ah", (regs_.r_eax >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bh") return Register("bh", (regs_.r_ebx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "ch") return Register("ch", (regs_.r_ecx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dh") return Register("dh", (regs_.r_edx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "cs") return Register("cs", regs_.r_cs, Register::TYPE_SEG); else if(lreg == "ds") return Register("ds", regs_.r_ds, Register::TYPE_SEG); else if(lreg == "es") return Register("es", regs_.r_es, Register::TYPE_SEG); else if(lreg == "fs") return Register("fs", regs_.r_fs, Register::TYPE_SEG); else if(lreg == "gs") return Register("gs", regs_.r_gs, Register::TYPE_SEG); else if(lreg == "ss") return Register("ss", regs_.r_ss, Register::TYPE_SEG); else if(lreg == "fs_base") return Register("fs_base", fs_base, Register::TYPE_SEG); else if(lreg == "gs_base") return Register("gs_base", gs_base, Register::TYPE_SEG); else if(lreg == "eflags") return Register("eflags", regs_.r_eflags, Register::TYPE_COND); #elif defined(EDB_X86_64) if(lreg == "rax") return Register("rax", regs_.r_rax, Register::TYPE_GPR); else if(lreg == "rbx") return Register("rbx", regs_.r_rbx, Register::TYPE_GPR); else if(lreg == "rcx") return Register("rcx", regs_.r_rcx, Register::TYPE_GPR); else if(lreg == "rdx") return Register("rdx", regs_.r_rdx, Register::TYPE_GPR); else if(lreg == "rbp") return Register("rbp", regs_.r_rbp, Register::TYPE_GPR); else if(lreg == "rsp") return Register("rsp", regs_.r_rsp, Register::TYPE_GPR); else if(lreg == "rsi") return Register("rsi", regs_.r_rsi, Register::TYPE_GPR); else if(lreg == "rdi") return Register("rdi", regs_.r_rdi, Register::TYPE_GPR); else if(lreg == "rip") return Register("rip", regs_.r_rip, Register::TYPE_IP); else if(lreg == "r8") return Register("r8", regs_.r_r8, Register::TYPE_GPR); else if(lreg == "r9") return Register("r9", regs_.r_r9, Register::TYPE_GPR); else if(lreg == "r10") return Register("r10", regs_.r_r10, Register::TYPE_GPR); else if(lreg == "r11") return Register("r11", regs_.r_r11, Register::TYPE_GPR); else if(lreg == "r12") return Register("r12", regs_.r_r12, Register::TYPE_GPR); else if(lreg == "r13") return Register("r13", regs_.r_r13, Register::TYPE_GPR); else if(lreg == "r14") return Register("r14", regs_.r_r14, Register::TYPE_GPR); else if(lreg == "r15") return Register("r15", regs_.r_r15, Register::TYPE_GPR); else if(lreg == "eax") return Register("eax", regs_.r_rax & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ebx") return Register("ebx", regs_.r_rbx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ecx") return Register("ecx", regs_.r_rcx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "edx") return Register("edx", regs_.r_rdx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ebp") return Register("ebp", regs_.r_rbp & 0xffffffff, Register::TYPE_GPR); else if(lreg == "esp") return Register("esp", regs_.r_rsp & 0xffffffff, Register::TYPE_GPR); else if(lreg == "esi") return Register("esi", regs_.r_rsi & 0xffffffff, Register::TYPE_GPR); else if(lreg == "edi") return Register("edi", regs_.r_rdi & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r8d") return Register("r8d", regs_.r_r8 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r9d") return Register("r9d", regs_.r_r9 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r10d") return Register("r10d", regs_.r_r10 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r11d") return Register("r11d", regs_.r_r11 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r12d") return Register("r12d", regs_.r_r12 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r13d") return Register("r13d", regs_.r_r13 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r14d") return Register("r14d", regs_.r_r14 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r15d") return Register("r15d", regs_.r_r15 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ax") return Register("ax", regs_.r_rax & 0xffff, Register::TYPE_GPR); else if(lreg == "bx") return Register("bx", regs_.r_rbx & 0xffff, Register::TYPE_GPR); else if(lreg == "cx") return Register("cx", regs_.r_rcx & 0xffff, Register::TYPE_GPR); else if(lreg == "dx") return Register("dx", regs_.r_rdx & 0xffff, Register::TYPE_GPR); else if(lreg == "bp") return Register("bp", regs_.r_rbp & 0xffff, Register::TYPE_GPR); else if(lreg == "sp") return Register("sp", regs_.r_rsp & 0xffff, Register::TYPE_GPR); else if(lreg == "si") return Register("si", regs_.r_rsi & 0xffff, Register::TYPE_GPR); else if(lreg == "di") return Register("di", regs_.r_rdi & 0xffff, Register::TYPE_GPR); else if(lreg == "r8w") return Register("r8w", regs_.r_r8 & 0xffff, Register::TYPE_GPR); else if(lreg == "r9w") return Register("r9w", regs_.r_r9 & 0xffff, Register::TYPE_GPR); else if(lreg == "r10w") return Register("r10w", regs_.r_r10 & 0xffff, Register::TYPE_GPR); else if(lreg == "r11w") return Register("r11w", regs_.r_r11 & 0xffff, Register::TYPE_GPR); else if(lreg == "r12w") return Register("r12w", regs_.r_r12 & 0xffff, Register::TYPE_GPR); else if(lreg == "r13w") return Register("r13w", regs_.r_r13 & 0xffff, Register::TYPE_GPR); else if(lreg == "r14w") return Register("r14w", regs_.r_r14 & 0xffff, Register::TYPE_GPR); else if(lreg == "r15w") return Register("r15w", regs_.r_r15 & 0xffff, Register::TYPE_GPR); else if(lreg == "al") return Register("al", regs_.r_rax & 0xff, Register::TYPE_GPR); else if(lreg == "bl") return Register("bl", regs_.r_rbx & 0xff, Register::TYPE_GPR); else if(lreg == "cl") return Register("cl", regs_.r_rcx & 0xff, Register::TYPE_GPR); else if(lreg == "dl") return Register("dl", regs_.r_rdx & 0xff, Register::TYPE_GPR); else if(lreg == "ah") return Register("ah", (regs_.r_rax >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bh") return Register("bh", (regs_.r_rbx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "ch") return Register("ch", (regs_.r_rcx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dh") return Register("dh", (regs_.r_rdx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "spl") return Register("spl", (regs_.r_rsp >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bpl") return Register("bpl", (regs_.r_rbp >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "sil") return Register("sil", (regs_.r_rsi >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dil") return Register("dil", (regs_.r_rdi >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "r8b") return Register("r8b", regs_.r_r8 & 0xff, Register::TYPE_GPR); else if(lreg == "r9b") return Register("r9b", regs_.r_r9 & 0xff, Register::TYPE_GPR); else if(lreg == "r10b") return Register("r10b", regs_.r_r10 & 0xff, Register::TYPE_GPR); else if(lreg == "r11b") return Register("r11b", regs_.r_r11 & 0xff, Register::TYPE_GPR); else if(lreg == "r12b") return Register("r12b", regs_.r_r12 & 0xff, Register::TYPE_GPR); else if(lreg == "r13b") return Register("r13b", regs_.r_r13 & 0xff, Register::TYPE_GPR); else if(lreg == "r14b") return Register("r14b", regs_.r_r14 & 0xff, Register::TYPE_GPR); else if(lreg == "r15b") return Register("r15b", regs_.r_r15 & 0xff, Register::TYPE_GPR); else if(lreg == "cs") return Register("cs", regs_.r_cs, Register::TYPE_SEG); else if(lreg == "ds") return Register("ds", regs_.r_ds, Register::TYPE_SEG); else if(lreg == "es") return Register("es", regs_.r_es, Register::TYPE_SEG); else if(lreg == "fs") return Register("fs", regs_.r_fs, Register::TYPE_SEG); else if(lreg == "gs") return Register("gs", regs_.r_gs, Register::TYPE_SEG); else if(lreg == "ss") return Register("ss", regs_.r_ss, Register::TYPE_SEG); else if(lreg == "fs_base") return Register("fs_base", fs_base, Register::TYPE_SEG); else if(lreg == "gs_base") return Register("gs_base", gs_base, Register::TYPE_SEG); else if(lreg == "rflags") return Register("rflags", regs_.r_rflags, Register::TYPE_COND); #endif return Register(); } //------------------------------------------------------------------------------ // Name: frame_pointer // Desc: returns what is conceptually the frame pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::frame_pointer() const { #if defined(EDB_X86) return regs_.r_ebp; #elif defined(EDB_X86_64) return regs_.r_rbp; #endif } //------------------------------------------------------------------------------ // Name: instruction_pointer // Desc: returns the instruction pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::instruction_pointer() const { #if defined(EDB_X86) return regs_.r_eip; #elif defined(EDB_X86_64) return regs_.r_rip; #endif } //------------------------------------------------------------------------------ // Name: stack_pointer // Desc: returns the stack pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::stack_pointer() const { #if defined(EDB_X86) return regs_.r_esp; #elif defined(EDB_X86_64) return regs_.r_rsp; #endif } //------------------------------------------------------------------------------ // Name: debug_register // Desc: //------------------------------------------------------------------------------ edb::reg_t PlatformState::debug_register(int n) const { return dr_[n]; } //------------------------------------------------------------------------------ // Name: flags // Desc: //------------------------------------------------------------------------------ edb::reg_t PlatformState::flags() const { #if defined(EDB_X86) return regs_.r_eflags; #elif defined(EDB_X86_64) return regs_.r_rflags; #endif } //------------------------------------------------------------------------------ // Name: fpu_register // Desc: //------------------------------------------------------------------------------ long double PlatformState::fpu_register(int n) const { return reinterpret_cast(&fpregs_)[n]; } //------------------------------------------------------------------------------ // Name: adjust_stack // Desc: //------------------------------------------------------------------------------ void PlatformState::adjust_stack(int bytes) { #if defined(EDB_X86) regs_.r_esp += bytes; #elif defined(EDB_X86_64) regs_.r_rsp += bytes; #endif } //------------------------------------------------------------------------------ // Name: clear // Desc: //------------------------------------------------------------------------------ void PlatformState::clear() { memset(®s_, 0, sizeof(regs_)); memset(&fpregs_, 0, sizeof(fpregs_)); memset(&dr_, 0, sizeof(dr_)); #if defined(EDB_X86) fs_base = 0; gs_base = 0; #endif } //------------------------------------------------------------------------------ // Name: set_debug_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_debug_register(int n, edb::reg_t value) { dr_[n] = value; } //------------------------------------------------------------------------------ // Name: set_flags // Desc: //------------------------------------------------------------------------------ void PlatformState::set_flags(edb::reg_t flags) { #if defined(EDB_X86) regs_.r_eflags = flags; #elif defined(EDB_X86_64) regs_.r_rflags = flags; #endif } //------------------------------------------------------------------------------ // Name: set_instruction_pointer // Desc: //------------------------------------------------------------------------------ void PlatformState::set_instruction_pointer(edb::address_t value) { #if defined(EDB_X86) regs_.r_eip = value; #elif defined(EDB_X86_64) regs_.r_rip = value; #endif } //------------------------------------------------------------------------------ // Name: set_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_register(const QString &name, edb::reg_t value) { const QString lreg = name.toLower(); #if defined(EDB_X86) if(lreg == "eax") { regs_.r_eax = value; } else if(lreg == "ebx") { regs_.r_ebx = value; } else if(lreg == "ecx") { regs_.r_ecx = value; } else if(lreg == "edx") { regs_.r_edx = value; } else if(lreg == "ebp") { regs_.r_ebp = value; } else if(lreg == "esp") { regs_.r_esp = value; } else if(lreg == "esi") { regs_.r_esi = value; } else if(lreg == "edi") { regs_.r_edi = value; } else if(lreg == "eip") { regs_.r_eip = value; } else if(lreg == "cs") { regs_.r_cs = value; } else if(lreg == "ds") { regs_.r_ds = value; } else if(lreg == "es") { regs_.r_es = value; } else if(lreg == "fs") { regs_.r_fs = value; } else if(lreg == "gs") { regs_.r_gs = value; } else if(lreg == "ss") { regs_.r_ss = value; } else if(lreg == "eflags") { regs_.r_eflags = value; } #elif defined(EDB_X86_64) if(lreg == "rax") { regs_.r_rax = value; } else if(lreg == "rbx") { regs_.r_rbx = value; } else if(lreg == "rcx") { regs_.r_rcx = value; } else if(lreg == "rdx") { regs_.r_rdx = value; } else if(lreg == "rbp") { regs_.r_rbp = value; } else if(lreg == "rsp") { regs_.r_rsp = value; } else if(lreg == "rsi") { regs_.r_rsi = value; } else if(lreg == "rdi") { regs_.r_rdi = value; } else if(lreg == "r8") { regs_.r_r8 = value; } else if(lreg == "r9") { regs_.r_r9 = value; } else if(lreg == "r10") { regs_.r_r10 = value; } else if(lreg == "r11") { regs_.r_r11 = value; } else if(lreg == "r12") { regs_.r_r12 = value; } else if(lreg == "r13") { regs_.r_r13 = value; } else if(lreg == "r14") { regs_.r_r14 = value; } else if(lreg == "r15") { regs_.r_r15 = value; } else if(lreg == "rip") { regs_.r_rip = value; } else if(lreg == "cs") { regs_.r_cs = value; } else if(lreg == "ds") { regs_.r_ds = value; } else if(lreg == "es") { regs_.r_es = value; } else if(lreg == "fs") { regs_.r_fs = value; } else if(lreg == "gs") { regs_.r_gs = value; } else if(lreg == "ss") { regs_.r_ss = value; } else if(lreg == "rflags") { regs_.r_rflags = value; } #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ quint64 PlatformState::mmx_register(int n) const { Q_UNUSED(n); return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QByteArray PlatformState::xmm_register(int n) const { Q_UNUSED(n); return QByteArray(); } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/freebsd/PlatformState.h0000644000175000017500000000370513273160654024727 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORMSTATE_20110330_H_ #define PLATFORMSTATE_20110330_H_ #include "IState.h" #include "Types.h" #include #include namespace DebuggerCore { class PlatformState : public IState { friend class DebuggerCore; public: PlatformState(); public: virtual IState *clone() const; public: virtual QString flags_to_string() const; virtual QString flags_to_string(edb::reg_t flags) const; virtual Register value(const QString ®) const; virtual edb::address_t frame_pointer() const; virtual edb::address_t instruction_pointer() const; virtual edb::address_t stack_pointer() const; virtual edb::reg_t debug_register(int n) const; virtual edb::reg_t flags() const; virtual long double fpu_register(int n) const; virtual void adjust_stack(int bytes); virtual void clear(); virtual void set_debug_register(int n, edb::reg_t value); virtual void set_flags(edb::reg_t flags); virtual void set_instruction_pointer(edb::address_t value); virtual void set_register(const QString &name, edb::reg_t value); virtual quint64 mmx_register(int n) const; virtual QByteArray xmm_register(int n) const; private: struct reg regs_; struct fpreg fpregs_; edb::reg_t dr_[8]; edb::address_t fs_base; edb::address_t gs_base; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/freebsd/PlatformEvent.cpp0000644000175000017500000001731113273160654025261 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformEvent.h" #include "edb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for the SIG* definitions namespace DebuggerCore { //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ PlatformEvent::PlatformEvent() : status(0), pid(-1), tid(-1), fault_address_(0), fault_code_(0) { } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ PlatformEvent *PlatformEvent::clone() const { return new PlatformEvent(*this); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::Message PlatformEvent::error_description() const { Q_ASSERT(is_error()); auto fault_address = reinterpret_cast(fault_address_); switch(code()) { case SIGSEGV: return Message( tr("Illegal Access Fault"), tr( "

The debugged application encountered a segmentation fault.
The address 0x%1 could not be accessed.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

").arg(edb::v1::format_pointer(fault_address)) ); case SIGILL: return Message( tr("Illegal Instruction Fault"), tr( "

The debugged application attempted to execute an illegal instruction.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); case SIGFPE: switch(fault_code_) { case FPE_INTDIV: return Message( tr("Divide By Zero"), tr( "

The debugged application tried to divide an integer value by an integer divisor of zero.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); default: return Message( tr("Floating Point Exception"), tr( "

The debugged application encountered a floating-point exception.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); } case SIGABRT: return Message( tr("Application Aborted"), tr( "

The debugged application has aborted.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); case SIGBUS: return Message( tr("Bus Error"), tr( "

The debugged application tried to read or write data that is misaligned.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); #ifdef SIGSTKFLT case SIGSTKFLT: return Message( tr("Stack Fault"), tr( "

The debugged application encountered a stack fault.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); #endif case SIGPIPE: return Message( tr("Broken Pipe Fault"), tr( "

The debugged application encountered a broken pipe fault.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); default: return Message(); } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::REASON PlatformEvent:: reason() const { // this basically converts our value into a 'switchable' value for convenience if(stopped()) { return EVENT_STOPPED; } else if(terminated()) { return EVENT_TERMINATED; } else if(exited()) { return EVENT_EXITED; } else { return EVENT_UNKNOWN; } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::TRAP_REASON PlatformEvent::trap_reason() const { switch(fault_code_) { case TRAP_TRACE: return TRAP_STEPPING; default: return TRAP_BREAKPOINT; } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::exited() const { return WIFEXITED(status) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_error() const { if(stopped()) { switch(code()) { case SIGTRAP: case SIGSTOP: return false; case SIGSEGV: case SIGILL: case SIGFPE: case SIGABRT: case SIGBUS: #ifdef SIGSTKFLT case SIGSTKFLT: #endif case SIGPIPE: return true; default: return false; } } else { return false; } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_kill() const { return stopped() && code() == SIGKILL; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_stop() const { return stopped() && code() == SIGSTOP; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_trap() const { return stopped() && code() == SIGTRAP; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::terminated() const { return WIFSIGNALED(status) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::stopped() const { return WIFSTOPPED(status) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ edb::pid_t PlatformEvent::process() const { return pid; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ edb::tid_t PlatformEvent::thread() const { return tid; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ int PlatformEvent::code() const { if(stopped()) { return WSTOPSIG(status); } if(terminated()) { return WTERMSIG(status); } if(exited()) { return WEXITSTATUS(status); } return 0; } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/freebsd/DebuggerCore.cpp0000644000175000017500000004164613273160654025040 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "DebuggerCore.h" #include "PlatformEvent.h" #include "PlatformRegion.h" #include "PlatformState.h" #include "State.h" #include "string_hash.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DebuggerCore { namespace { void SET_OK(bool &ok, long value) { ok = (value != -1) || (errno == 0); } int resume_code(int status) { if(WIFSIGNALED(status)) { return WTERMSIG(status); } else if(WIFSTOPPED(status)) { return WSTOPSIG(status); } return 0; } } //------------------------------------------------------------------------------ // Name: DebuggerCore // Desc: constructor //------------------------------------------------------------------------------ DebuggerCore::DebuggerCore() { #if defined(_SC_PAGESIZE) page_size_ = sysconf(_SC_PAGESIZE); #elif defined(_SC_PAGE_SIZE) page_size_ = sysconf(_SC_PAGE_SIZE); #else page_size_ = PAGE_SIZE; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::has_extension(quint64 ext) const { return false; } //------------------------------------------------------------------------------ // Name: page_size // Desc: returns the size of a page on this system //------------------------------------------------------------------------------ edb::address_t DebuggerCore::page_size() const { return page_size_; } //------------------------------------------------------------------------------ // Name: ~DebuggerCore // Desc: //------------------------------------------------------------------------------ DebuggerCore::~DebuggerCore() { detach(); } //------------------------------------------------------------------------------ // Name: wait_debug_event // Desc: waits for a debug event, msecs is a timeout // it will return false if an error or timeout occurs //------------------------------------------------------------------------------ std::shared_ptr DebuggerCore::wait_debug_event(int msecs) { if(attached()) { int status; bool timeout; const edb::tid_t tid = native::waitpid_timeout(pid(), &status, 0, msecs, &timeout); if(!timeout) { if(tid > 0) { // normal event auto e = std::make_shared(); e->pid = pid(); e->tid = tid; e->status = status; char errbuf[_POSIX2_LINE_MAX]; if(kvm_t *const kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) { int rc; struct kinfo_proc *const proc = kvm_getprocs(kd, KERN_PROC_PID, pid(), &rc); struct proc p; kvm_read(kd, (unsigned long)proc->ki_paddr, &p, sizeof(p)); struct ksiginfo siginfo; kvm_read(kd, (unsigned long)p.p_ksi, &siginfo, sizeof(siginfo)); // TODO: why doesn't this get the fault address correctly? // perhaps I need to target the tid instead? e->fault_code_ = siginfo.ksi_code; e->fault_address_ = siginfo.ksi_addr; //printf("ps_sig : %d\n", siginfo.ksi_signo); //printf("ps_type : %d\n", p.p_stype); kvm_close(kd); } else { e->fault_code_ = 0; e->fault_address_ = 0; } active_thread_ = tid; threads_[tid].status = status; return e; } } } return nullptr; } //------------------------------------------------------------------------------ // Name: read_data // Desc: //------------------------------------------------------------------------------ long DebuggerCore::read_data(edb::address_t address, bool *ok) { Q_ASSERT(ok); errno = 0; const long v = ptrace(PT_READ_D, pid(), reinterpret_cast(address), 0); SET_OK(*ok, v); return v; } //------------------------------------------------------------------------------ // Name: write_data // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::write_data(edb::address_t address, long value) { return ptrace(PT_WRITE_D, pid(), reinterpret_cast(address), value) != -1; } //------------------------------------------------------------------------------ // Name: attach // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::attach(edb::pid_t pid) { detach(); const long ret = ptrace(PT_ATTACH, pid, 0, 0); if(ret == 0) { pid_ = pid; active_thread_ = pid; threads_.clear(); threads_.insert(pid, thread_info()); // TODO: attach to all of the threads } return ret == 0; } //------------------------------------------------------------------------------ // Name: detach // Desc: //------------------------------------------------------------------------------ void DebuggerCore::detach() { if(attached()) { // TODO: do i need to stop each thread first, and wait for them? clear_breakpoints(); for(auto it = threads_.begin(); it != threads_.end(); ++it) { ptrace(PT_DETACH, it.key(), 0, 0); } pid_ = 0; threads_.clear(); } } //------------------------------------------------------------------------------ // Name: kill // Desc: //------------------------------------------------------------------------------ void DebuggerCore::kill() { if(attached()) { clear_breakpoints(); ptrace(PT_KILL, pid(), 0, 0); native::waitpid(pid(), 0, WAIT_ANY); pid_ = 0; threads_.clear(); } } //------------------------------------------------------------------------------ // Name: pause // Desc: stops *all* threads of a process //------------------------------------------------------------------------------ void DebuggerCore::pause() { if(attached()) { for(auto it = threads_.begin(); it != threads_.end(); ++it) { ::kill(it.key(), SIGSTOP); } } } //------------------------------------------------------------------------------ // Name: resume // Desc: //------------------------------------------------------------------------------ void DebuggerCore::resume(edb::EVENT_STATUS status) { // TODO: assert that we are paused if(attached()) { if(status != edb::DEBUG_STOP) { const edb::tid_t tid = active_thread(); const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(threads_[tid].status) : 0; ptrace(PT_CONTINUE, tid, reinterpret_cast(1), code); } } } //------------------------------------------------------------------------------ // Name: step // Desc: //------------------------------------------------------------------------------ void DebuggerCore::step(edb::EVENT_STATUS status) { // TODO: assert that we are paused if(attached()) { if(status != edb::DEBUG_STOP) { const edb::tid_t tid = active_thread(); const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(threads_[tid].status) : 0; ptrace(PT_STEP, tid, reinterpret_cast(1), code); } } } //------------------------------------------------------------------------------ // Name: get_state // Desc: //------------------------------------------------------------------------------ void DebuggerCore::get_state(State *state) { Q_ASSERT(state); // TODO: assert that we are paused auto state_impl = static_cast(state->impl_); if(attached()) { #if defined(EDB_X86) if(ptrace(PT_GETREGS, active_thread(), reinterpret_cast(&state_impl->regs_), 0) != -1) { state_impl->gs_base = 0; state_impl->fs_base = 0; } #endif // TODO implement this } else { state->clear(); } } //------------------------------------------------------------------------------ // Name: set_state // Desc: //------------------------------------------------------------------------------ void DebuggerCore::set_state(const State &state) { // TODO: assert that we are paused auto state_impl = static_cast(state.impl_); if(attached()) { ptrace(PT_SETREGS, active_thread(), reinterpret_cast(&state_impl->regs_), 0); // TODO: FPU // TODO: Debug Registers } } //------------------------------------------------------------------------------ // Name: open // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::open(const QString &path, const QString &cwd, const QList &args, const QString &tty) { detach(); pid_t pid; switch(pid = fork()) { case 0: // we are in the child now... // set ourselves (the child proc) up to be traced ptrace(PT_TRACE_ME, 0, 0, 0); // redirect it's I/O if(!tty.isEmpty()) { FILE *const std_out = freopen(qPrintable(tty), "r+b", stdout); FILE *const std_in = freopen(qPrintable(tty), "r+b", stdin); FILE *const std_err = freopen(qPrintable(tty), "r+b", stderr); Q_UNUSED(std_out); Q_UNUSED(std_in); Q_UNUSED(std_err); } // do the actual exec execute_process(path, cwd, args); // we should never get here! abort(); break; case -1: // error! pid_ = 0; return false; default: // parent do { threads_.clear(); int status; if(native::waitpid(pid, &status, 0) == -1) { return false; } // the very first event should be a STOP of type SIGTRAP if(!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) { detach(); return false; } // setup the first event data for the primary thread threads_.insert(pid, thread_info()); pid_ = pid; active_thread_ = pid; threads_[pid].status = status; return true; } while(0); break; } } //------------------------------------------------------------------------------ // Name: set_active_thread // Desc: //------------------------------------------------------------------------------ void DebuggerCore::set_active_thread(edb::tid_t tid) { Q_ASSERT(threads_.contains(tid)); active_thread_ = tid; } //------------------------------------------------------------------------------ // Name: create_state // Desc: //------------------------------------------------------------------------------ IState *DebuggerCore::create_state() const { return new PlatformState; } //------------------------------------------------------------------------------ // Name: enumerate_processes // Desc: //------------------------------------------------------------------------------ QMap DebuggerCore::enumerate_processes() const { QMap ret; char ebuffer[_POSIX2_LINE_MAX]; int numprocs; if(kvm_t *const kaccess = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, 0, O_RDONLY, ebuffer)) { if(struct kinfo_proc *const kprocaccess = kvm_getprocs(kaccess, KERN_PROC_ALL, 0, &numprocs)) { for(int i = 0; i < numprocs; ++i) { ProcessInfo procInfo; procInfo.pid = kprocaccess[i].ki_pid; procInfo.uid = kprocaccess[i].ki_uid; procInfo.name = kprocaccess[i].ki_comm; ret.insert(procInfo.pid, procInfo); } } kvm_close(kaccess); } else { QMessageBox::warning(0, "Error Listing Processes", ebuffer); } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::process_exe(edb::pid_t pid) const { // TODO: implement this return QString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::process_cwd(edb::pid_t pid) const { // TODO: implement this return QString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::pid_t DebuggerCore::parent_pid(edb::pid_t pid) const { // TODO: implement this return -1; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList> DebuggerCore::memory_regions() const { QList> regions; if(pid_ != 0) { char buffer[PATH_MAX] = {}; struct ptrace_vm_entry vm_entry; memset(&vm_entry, 0, sizeof(vm_entry)); vm_entry.pve_entry = 0; while(ptrace(PT_VM_ENTRY, pid_, reinterpret_cast(&vm_entry), NULL) == 0) { vm_entry.pve_path = buffer; vm_entry.pve_pathlen = sizeof(buffer); const edb::address_t start = vm_entry.pve_start; const edb::address_t end = vm_entry.pve_end; const edb::address_t base = vm_entry.pve_start - vm_entry.pve_offset; const QString name = vm_entry.pve_path; const IRegion::permissions_t permissions = vm_entry.pve_prot; regions.push_back(std::make_shared(start, end, base, name, permissions)); memset(buffer, 0, sizeof(buffer)); } } return regions; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList DebuggerCore::process_args(edb::pid_t pid) const { QList ret; if(pid != 0) { // TODO: assert attached! } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t DebuggerCore::process_code_address() const { qDebug() << "TODO: implement DebuggerCore::process_code_address"; return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t DebuggerCore::process_data_address() const { qDebug() << "TODO: implement DebuggerCore::process_data_address"; return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList DebuggerCore::loaded_modules() const { QList modules; qDebug() << "TODO: implement DebuggerCore::loaded_modules"; return modules; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QDateTime DebuggerCore::process_start(edb::pid_t pid) const { qDebug() << "TODO: implement DebuggerCore::process_start"; return QDateTime(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ quint64 DebuggerCore::cpu_type() const { #ifdef EDB_X86 return edb::string_hash<'x', '8', '6'>::value; #elif defined(EDB_X86_64) return edb::string_hash<'x', '8', '6', '-', '6', '4'>::value; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::format_pointer(edb::address_t address) const { char buf[32]; #ifdef EDB_X86 qsnprintf(buf, sizeof(buf), "%08x", address); #elif defined(EDB_X86_64) qsnprintf(buf, sizeof(buf), "%016llx", address); #endif return buf; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::stack_pointer() const { #ifdef EDB_X86 return "esp"; #elif defined(EDB_X86_64) return "rsp"; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::frame_pointer() const { #ifdef EDB_X86 return "ebp"; #elif defined(EDB_X86_64) return "rbp"; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::instruction_pointer() const { #ifdef EDB_X86 return "eip"; #elif defined(EDB_X86_64) return "rip"; #endif } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(DebuggerCore, DebuggerCore) #endif } edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/0000755000175000017500000000000013273160654021511 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/DialogMemoryAccess.ui0000644000175000017500000000741713273160654025573 0ustar eteraneteran DebuggerCorePlugin::DialogMemoryAccess 0 0 360 276 Memory Access Error true <html><head/><body><p>EDB has detected that on this kernel, access to debugee memory <br/>does not work through <span style=" font-family:'Courier New,courier';">/proc/&lt;pid&gt;/mem</span>. </p><p>Possible causes include: </p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">EDB's feature detection has a bug</li></ul><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kernel is older and restricts writes to <span style=" font-family:'Courier New,courier';">/proc/&lt;pid&gt;/mem</span></li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kernel has <span style=" font-weight:600;">grsecurity</span> enabled</li></ul><p>EDB has a fallback method of accessing debugee memory, <br/>but it may have a negative impact on performance. <br/>If you experience poor performance, please file a bug report at:</p><p><a href="http://github.com/eteran/edb-debugger/issues"><span style=" text-decoration: underline; color:#2980b9;">http://github.com/eteran/edb-debugger/issues</span></a>.</p></body></html> Qt::RichText false Never show this message again true Qt::Horizontal QDialogButtonBox::Ok buttonBox accepted() DialogMemoryAccess accept() 248 254 157 274 buttonBox rejected() DialogMemoryAccess reject() 316 260 286 274 edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/PlatformThread.cpp0000644000175000017500000001414013273160654025131 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformThread.h" #include "DebuggerCore.h" #include "IProcess.h" #include "PlatformCommon.h" #include #ifndef _GNU_SOURCE #define _GNU_SOURCE /* or _BSD_SOURCE or _SVID_SOURCE */ #endif #include /* For SYS_xxx definitions */ namespace DebuggerCorePlugin { //------------------------------------------------------------------------------ // Name: PlatformThread // Desc: //------------------------------------------------------------------------------ PlatformThread::PlatformThread(DebuggerCore *core, IProcess *process, edb::tid_t tid) : core_(core), process_(process), tid_(tid) { assert(process); assert(core); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ PlatformThread::~PlatformThread() { } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::tid_t PlatformThread::tid() const { return tid_; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString PlatformThread::name() const { struct user_stat thread_stat; int n = get_user_stat(QString("/proc/%1/task/%2/stat").arg(process_->pid()).arg(tid_), &thread_stat); if(n >= 2) { return thread_stat.comm; } return QString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ int PlatformThread::priority() const { struct user_stat thread_stat; int n = get_user_stat(QString("/proc/%1/task/%2/stat").arg(process_->pid()).arg(tid_), &thread_stat); if(n >= 30) { return thread_stat.priority; } return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PlatformThread::instruction_pointer() const { // FIXME(ARM): doesn't work at least on ARM32 struct user_stat thread_stat; int n = get_user_stat(QString("/proc/%1/task/%2/stat").arg(process_->pid()).arg(tid_), &thread_stat); if(n >= 18) { return thread_stat.kstkeip; } return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString PlatformThread::runState() const { struct user_stat thread_stat; int n = get_user_stat(QString("/proc/%1/task/%2/stat").arg(process_->pid()).arg(tid_), &thread_stat); if(n >= 3) { switch(thread_stat.state) { // 03 case 'R': return tr("%1 (Running)").arg(thread_stat.state); break; case 'S': return tr("%1 (Sleeping)").arg(thread_stat.state); break; case 'D': return tr("%1 (Disk Sleep)").arg(thread_stat.state); break; case 'T': return tr("%1 (Stopped)").arg(thread_stat.state); break; case 't': return tr("%1 (Tracing Stop)").arg(thread_stat.state); break; case 'Z': return tr("%1 (Zombie)").arg(thread_stat.state); break; case 'X': case 'x': return tr("%1 (Dead)").arg(thread_stat.state); break; case 'W': return tr("%1 (Waking/Paging)").arg(thread_stat.state); break; case 'K': return tr("%1 (Wakekill)").arg(thread_stat.state); break; case 'P': return tr("%1 (Parked)").arg(thread_stat.state); break; default: return tr("%1").arg(thread_stat.state); break; } } return tr("Unknown"); } //------------------------------------------------------------------------------ // Name: resume // Desc: resumes this thread, passing the signal that stopped it // (unless the signal was SIGSTOP) //------------------------------------------------------------------------------ Status PlatformThread::resume() { return core_->ptrace_continue(tid_, resume_code(status_)); } //------------------------------------------------------------------------------ // Name: resume // Desc: resumes this thread , passing the signal that stopped it // (unless the signal was SIGSTOP, or the passed status != DEBUG_EXCEPTION_NOT_HANDLED) //------------------------------------------------------------------------------ Status PlatformThread::resume(edb::EVENT_STATUS status) { const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(status_) : 0; return core_->ptrace_continue(tid_, code); } //------------------------------------------------------------------------------ // Name: stop // Desc: //------------------------------------------------------------------------------ Status PlatformThread::stop() { if(syscall(SYS_tgkill, process_->pid(), tid_, SIGSTOP)==-1) { const char*const strError=strerror(errno); qWarning() << "Unable to stop thread" << tid_ << ": tgkill failed:" << strError; return Status(strError); } // TODO(eteran): should this just be this? //::kill(tid_, SIGSTOP); return Status::Ok; } //------------------------------------------------------------------------------ // Name: isPaused // Desc: returns true if this thread is currently in the debugger's wait list //------------------------------------------------------------------------------ bool PlatformThread::isPaused() const { return core_->waited_threads_.contains(tid_); } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/FeatureDetect.cpp0000644000175000017500000000725613273160654024753 0ustar eteraneteran/* Copyright (C) 2016 - 2016 Evan Teran evan.teran@gmail.com 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, see . */ #include "FeatureDetect.h" #include "version.h" #include #include #include #include #include #include #include #include namespace DebuggerCorePlugin { namespace feature { namespace { // Custom class to work with files, since various wrappers // appear to be unreliable to check whether writes succeeded class File { int fd; bool success; public: File(const std::string &filename) { fd = ::open(filename.c_str(), O_RDWR); success = fd != -1; } ssize_t write(const void *buf, size_t count) { const auto result = ::write(fd, buf, count); success = result != -1; return result; } ssize_t read(void *buf, size_t count) { const auto result = ::read(fd, buf, count); success = result != -1; return result; } size_t seekp(size_t offset) { const auto result = ::lseek(fd, offset, SEEK_SET); success = result != -1; return result; } ~File() { close(fd); } explicit operator bool() { return success; } }; void kill_child(int pid) { if (kill(pid, SIGKILL) == -1) { perror("failed to kill child"); } } } //------------------------------------------------------------------------------ // Name: detect_proc_access // Desc: detects whether or not reads/writes through /proc//mem work // correctly //------------------------------------------------------------------------------ bool detect_proc_access(bool *read_broken, bool *write_broken) { switch (pid_t pid = fork()) { case 0: if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { perror("child: PTRACE_TRACEME failed"); abort(); } // force a signal raise(SIGCONT); for (;;) { sleep(10); } abort(); case -1: perror("fork"); return false; default: { int status; if (waitpid(pid, &status, __WALL) == -1) { perror("parent: waitpid failed"); kill_child(pid); return false; } if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGCONT) { std::cerr << "unexpected status returned by waitpid: 0x" << std::hex << status << "\n"; kill_child(pid); return false; } File file("/proc/" + std::to_string(pid) + "/mem"); if (!file) { perror("failed to open memory file"); kill_child(pid); return false; } const auto pageAlignMask = ~(sysconf(_SC_PAGESIZE) - 1); const auto addr = reinterpret_cast(&edb::version) & pageAlignMask; file.seekp(addr); if (!file) { perror("failed to seek to address to read"); kill_child(pid); return false; } int buf = 0x12345678; { file.read(&buf, sizeof(buf)); if (!file) { *read_broken = true; *write_broken = true; kill_child(pid); return false; } } file.seekp(addr); if (!file) { perror("failed to seek to address to write"); kill_child(pid); return false; } { file.write(&buf, sizeof(buf)); if (!file) { *read_broken = false; *write_broken = true; } else { *read_broken = false; *write_broken = false; } } kill_child(pid); return true; } } } } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/PlatformThread.h0000644000175000017500000000515513273160654024604 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_THREAD_20151013_H_ #define PLATFORM_THREAD_20151013_H_ #include "IThread.h" #include "IBreakpoint.h" #include #include class IProcess; namespace DebuggerCorePlugin { class DebuggerCore; class PlatformState; class PlatformThread : public IThread { Q_DECLARE_TR_FUNCTIONS(PlatformThread) friend class DebuggerCore; public: enum SignalStatus { Stopped, Signaled }; public: PlatformThread(DebuggerCore *core, IProcess *process, edb::tid_t tid); virtual ~PlatformThread() override; private: PlatformThread(const PlatformThread &) = delete; PlatformThread& operator=(const PlatformThread &) = delete; public: virtual edb::tid_t tid() const override; virtual QString name() const override; virtual int priority() const override; virtual edb::address_t instruction_pointer() const override; virtual QString runState() const override; public: virtual void get_state(State *state) override; virtual void set_state(const State &state) override; public: virtual Status step() override; virtual Status step(edb::EVENT_STATUS status) override; virtual Status resume() override; virtual Status resume(edb::EVENT_STATUS status) override; virtual Status stop() override; public: virtual bool isPaused() const override; private: void fillSegmentBases(PlatformState* state); bool fillStateFromPrStatus(PlatformState* state); bool fillStateFromSimpleRegs(PlatformState* state); #ifdef EDB_ARM32 bool fillStateFromVFPRegs(PlatformState* state); #endif private: unsigned long get_debug_register(std::size_t n); long set_debug_register(std::size_t n, long value); private: DebuggerCore *const core_; IProcess *const process_; edb::tid_t tid_; int status_; SignalStatus signal_status_; #if defined EDB_ARM32 || defined EDB_ARM64 private: Status doStep(edb::tid_t tid, long status); std::shared_ptr singleStepBreakpoint; #endif }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/DebuggerCore.h0000644000175000017500000000777513273160654024237 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DEBUGGERCORE_20090529_H_ #define DEBUGGERCORE_20090529_H_ #include #include "DebuggerCoreUNIX.h" #include #include #include #include class IBinary; class Status; namespace DebuggerCorePlugin { class PlatformThread; class DebuggerCore : public DebuggerCoreUNIX { Q_OBJECT #if QT_VERSION >= 0x050000 Q_PLUGIN_METADATA(IID "edb.IDebugger/1.0") #endif Q_INTERFACES(IDebugger) Q_CLASSINFO("author", "Evan Teran") Q_CLASSINFO("url", "http://www.codef00.com") friend class PlatformProcess; friend class PlatformThread; CPUMode cpu_mode() const override { return cpu_mode_; } public: DebuggerCore(); virtual ~DebuggerCore() override; public: virtual std::size_t pointer_size() const override; virtual edb::address_t page_size() const override; virtual bool has_extension(quint64 ext) const override; virtual std::shared_ptr wait_debug_event(int msecs) override; virtual Status attach(edb::pid_t pid) override; virtual Status detach() override; virtual void kill() override; virtual void get_state(State *state) override; virtual void set_state(const State &state) override; virtual Status open(const QString &path, const QString &cwd, const QList &args, const QString &tty) override; virtual MeansOfCapture last_means_of_capture() const override; public: virtual edb::pid_t parent_pid(edb::pid_t pid) const override; public: virtual IState *create_state() const override; public: virtual quint64 cpu_type() const override; private: virtual QMap> enumerate_processes() const override; public: virtual QString stack_pointer() const override; virtual QString frame_pointer() const override; virtual QString instruction_pointer() const override; virtual QString flag_register() const override; public: virtual QString format_pointer(edb::address_t address) const override; public: virtual IProcess *process() const override; private: Status ptrace_getsiginfo(edb::tid_t tid, siginfo_t *siginfo); Status ptrace_continue(edb::tid_t tid, long status); Status ptrace_step(edb::tid_t tid, long status); Status ptrace_set_options(edb::tid_t tid, long options); Status ptrace_get_event_message(edb::tid_t tid, unsigned long *message); long ptrace_traceme(); private: void reset(); Status stop_threads(); std::shared_ptr handle_event(edb::tid_t tid, int status); void handle_thread_exit(edb::tid_t tid, int status); int attach_thread(edb::tid_t tid); void detectCPUMode(); long ptraceOptions() const; private: typedef QHash> threadmap_t; private: threadmap_t threads_; QSet waited_threads_; edb::tid_t active_thread_; std::unique_ptr binary_info_; IProcess *process_; std::size_t pointer_size_; #if defined(EDB_X86) || defined(EDB_X86_64) const bool edbIsIn64BitSegment; const bool osIs64Bit; const edb::seg_reg_t USER_CS_32; const edb::seg_reg_t USER_CS_64; const edb::seg_reg_t USER_SS; #endif MeansOfCapture lastMeansOfCapture = MeansOfCapture::NeverCaptured; bool proc_mem_write_broken_; bool proc_mem_read_broken_; CPUMode cpu_mode_=CPUMode::Unknown; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/PlatformProcess.cpp0000644000175000017500000006300313273160654025342 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #define _LARGEFILE64_SOURCE #include "PlatformProcess.h" #include "DebuggerCore.h" #include "IBreakpoint.h" #include "PlatformThread.h" #include "PlatformCommon.h" #include "PlatformRegion.h" #include "MemoryRegions.h" #include "Module.h" #include "edb.h" #include "linker.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DebuggerCorePlugin { namespace { // Used as size of ptrace word #define EDB_WORDSIZE sizeof(long) void set_ok(bool &ok, long value) { ok = (value != -1) || (errno == 0); } QStringList split_max(const QString &str, int maxparts) { int prev_idx = 0, idx = 0; QStringList items; for (const QChar &c : str) { if (c == ' ') { if (prev_idx < idx) { if (items.size() < maxparts - 1) items << str.mid(prev_idx, idx - prev_idx); else { items << str.right(str.size() - prev_idx); break; } } prev_idx = idx + 1; } ++idx; } if (prev_idx < str.size() && items.size() < maxparts) { items << str.right(str.size() - prev_idx); } return items; } //------------------------------------------------------------------------------ // Name: process_map_line // Desc: parses the data from a line of a memory map file //------------------------------------------------------------------------------ std::shared_ptr process_map_line(const QString &line) { edb::address_t start; edb::address_t end; edb::address_t base; IRegion::permissions_t permissions; QString name; const QStringList items = split_max(line, 6); if(items.size() >= 3) { bool ok; const QStringList bounds = items[0].split("-"); if(bounds.size() == 2) { start = edb::address_t::fromHexString(bounds[0],&ok); if(ok) { end = edb::address_t::fromHexString(bounds[1],&ok); if(ok) { base = edb::address_t::fromHexString(items[2],&ok); if(ok) { const QString perms = items[1]; permissions = 0; if(perms[0] == 'r') permissions |= PROT_READ; if(perms[1] == 'w') permissions |= PROT_WRITE; if(perms[2] == 'x') permissions |= PROT_EXEC; if(items.size() >= 6) { name = items[5]; } return std::make_shared(start, end, base, name, permissions); } } } } } return nullptr;; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ template QList loaded_modules_(const IProcess* process, const std::unique_ptr &binary_info_) { QList ret; if(binary_info_) { edb::linux_struct::r_debug dynamic_info; if(const edb::address_t debug_pointer = binary_info_->debug_pointer()) { if(process) { if(process->read_bytes(debug_pointer, &dynamic_info, sizeof(dynamic_info))) { if(dynamic_info.r_map) { auto link_address = edb::address_t::fromZeroExtended(dynamic_info.r_map); while(link_address) { edb::linux_struct::link_map map; if(process->read_bytes(link_address, &map, sizeof(map))) { char path[PATH_MAX]; if(!process->read_bytes(edb::address_t::fromZeroExtended(map.l_name), &path, sizeof(path))) { path[0] = '\0'; } if(map.l_addr) { Module module; module.name = path; module.base_address = map.l_addr; ret.push_back(module); } link_address = edb::address_t::fromZeroExtended(map.l_next); } else { break; } } } } } } } // fallback if(ret.isEmpty()) { const QList> r = edb::v1::memory_regions().regions(); QSet found_modules; for(const std::shared_ptr ®ion: r) { // we assume that modules will be listed by absolute path if(region->name().startsWith("/")) { if(!found_modules.contains(region->name())) { Module module; module.name = region->name(); module.base_address = region->start(); found_modules.insert(region->name()); ret.push_back(module); } } } } return ret; } } //------------------------------------------------------------------------------ // Name: PlatformProcess // Desc: //------------------------------------------------------------------------------ PlatformProcess::PlatformProcess(DebuggerCore *core, edb::pid_t pid) : core_(core), pid_(pid), ro_mem_file_(0), rw_mem_file_(0) { if (!core_->proc_mem_read_broken_) { QFile* memory_file = new QFile(QString("/proc/%1/mem").arg(pid_)); auto flags = QIODevice::ReadOnly | QIODevice::Unbuffered; if (!core_->proc_mem_write_broken_) { flags |= QIODevice::WriteOnly; } if (memory_file->open(flags)) { ro_mem_file_ = memory_file; if (!core_->proc_mem_write_broken_) { rw_mem_file_ = memory_file; } } else { delete memory_file; } } } //------------------------------------------------------------------------------ // Name: ~PlatformProcess // Desc: //------------------------------------------------------------------------------ PlatformProcess::~PlatformProcess() { delete ro_mem_file_; } //------------------------------------------------------------------------------ // Name: seek_addr // Desc: seeks memory file to given address, taking possible negativity of the // address into account //------------------------------------------------------------------------------ void seek_addr(QFile& file, edb::address_t address) { if(address <= UINT64_MAX/2) { file.seek(address); } else { const int fd=file.handle(); // Seek in two parts to avoid specifying negative offset: off64_t is a signed type const off64_t halfAddressTruncated=address>>1; lseek64(fd,halfAddressTruncated,SEEK_SET); const off64_t secondHalfAddress=address-halfAddressTruncated; lseek64(fd,secondHalfAddress,SEEK_CUR); } } //------------------------------------------------------------------------------ // Name: read_bytes // Desc: reads bytes into starting at
// Note: returns the number of bytes read // Note: if the read is short, only the first bytes are defined //------------------------------------------------------------------------------ std::size_t PlatformProcess::read_bytes(edb::address_t address, void* buf, std::size_t len) const { quint64 read = 0; Q_ASSERT(buf); Q_ASSERT(core_->process_ == this); auto ptr = reinterpret_cast(buf); if(len != 0) { // small reads take the fast path if(len == 1) { auto it = core_->breakpoints_.find(address); if(it != core_->breakpoints_.end()) { *ptr = (*it)->original_bytes()[0]; return 1; } if(ro_mem_file_) { seek_addr(*ro_mem_file_, address); read = ro_mem_file_->read(ptr, 1); if (read == 1) { return 1; } return 0; } else { bool ok; quint8 x = read_byte_via_ptrace(address, &ok); if(ok) { *ptr = x; return 1; } return 0; } } if(ro_mem_file_) { seek_addr(*ro_mem_file_, address); read = ro_mem_file_->read(ptr, len); if(read == 0 || read == quint64(-1)) { return 0; } } else { for(std::size_t index = 0; index < len; ++index) { // read a byte, if we failed, we are done bool ok; const quint8 x = read_byte_via_ptrace(address + index, &ok); if(!ok) { break; } // store it reinterpret_cast(buf)[index] = x; ++read; } } // replace any breakpoints Q_FOREACH(const std::shared_ptr &bp, core_->breakpoints_) { auto*const bpBytes=bp->original_bytes(); const auto bpAddr=bp->address(); // show the original bytes in the buffer.. for(size_t i=0; i < bp->size(); ++i) { if(bpAddr + i >= address && bpAddr + i < address + read) { ptr[bpAddr + i - address] = bpBytes[i]; } } } } return read; } //------------------------------------------------------------------------------ // Name: patch_bytes // Desc: same as write_bytes, except that it also records the original data // that was found at the address being written to. // Note: unlike the read_bytes, write_bytes functions, this will not apply the // write if we could not properly backup bytes as requested. // Note: on the off chance that we can READ bytes, but can't WRITE // bytes, we will return the number of bytes written, but record // bytes of patch data. //------------------------------------------------------------------------------ std::size_t PlatformProcess::patch_bytes(edb::address_t address, const void *buf, size_t len) { Q_ASSERT(buf); Q_ASSERT(core_->process_ == this); Patch patch; patch.address = address; patch.orig_bytes.resize(len); patch.new_bytes = QByteArray(static_cast(buf), len); size_t read_ret = read_bytes(address, patch.orig_bytes.data(), len); if(read_ret != len) { return 0; } patches_.insert(address, patch); return write_bytes(address, buf, len); } //------------------------------------------------------------------------------ // Name: write_bytes // Desc: writes bytes from starting at
//------------------------------------------------------------------------------ std::size_t PlatformProcess::write_bytes(edb::address_t address, const void *buf, std::size_t len) { quint64 written = 0; Q_ASSERT(buf); Q_ASSERT(core_->process_ == this); if(len != 0) { if(rw_mem_file_) { seek_addr(*rw_mem_file_,address); written = rw_mem_file_->write(reinterpret_cast(buf), len); if(written == 0 || written == quint64(-1)) { return 0; } } else { // TODO write whole words at a time using ptrace_poke. for(std::size_t byteIndex=0;byteIndex(buf)+byteIndex), &ok); if(!ok) return written; ++written; } } } return written; } //------------------------------------------------------------------------------ // Name: read_pages // Desc: reads pages from the process starting at
// Note: buf's size must be >= count * core_->page_size() // Note: address should be page aligned. //------------------------------------------------------------------------------ std::size_t PlatformProcess::read_pages(edb::address_t address, void *buf, std::size_t count) const { Q_ASSERT(buf); Q_ASSERT(core_->process_ == this); return read_bytes(address, buf, count * core_->page_size()) / core_->page_size(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QDateTime PlatformProcess::start_time() const { QFileInfo info(QString("/proc/%1/stat").arg(pid_)); return info.created(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList PlatformProcess::arguments() const { QList ret; if(pid_ != 0) { const QString command_line_file(QString("/proc/%1/cmdline").arg(pid_)); QFile file(command_line_file); if(file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&file); QByteArray s; QChar ch; while(in.status() == QTextStream::Ok) { in >> ch; if(ch.isNull()) { if(!s.isEmpty()) { ret << s; } s.clear(); } else { s += ch; } } if(!s.isEmpty()) { ret << s; } } } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString PlatformProcess::current_working_directory() const { return edb::v1::symlink_target(QString("/proc/%1/cwd").arg(pid_)); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString PlatformProcess::executable() const { return edb::v1::symlink_target(QString("/proc/%1/exe").arg(pid_)); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::pid_t PlatformProcess::pid() const { return pid_; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ std::shared_ptr PlatformProcess::parent() const { struct user_stat user_stat; int n = get_user_stat(pid_, &user_stat); if(n >= 4) { return std::make_shared(core_, user_stat.ppid); } return nullptr; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PlatformProcess::code_address() const { struct user_stat user_stat; int n = get_user_stat(pid_, &user_stat); if(n >= 26) { return user_stat.startcode; } return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PlatformProcess::data_address() const { struct user_stat user_stat; int n = get_user_stat(pid_, &user_stat); if(n >= 27) { return user_stat.endcode + 1; // endcode == startdata ? } return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList> PlatformProcess::regions() const { static QList> regions; static size_t totalHash = 0; const QString map_file(QString("/proc/%1/maps").arg(pid_)); // hash the region file to see if it changed or not { std::ifstream mf(map_file.toStdString()); size_t newHash = 0; std::string line; while(std::getline(mf,line)) { boost::hash_combine(newHash, line); } if(totalHash == newHash) { return regions; } totalHash = newHash; regions.clear(); } // it changed, so let's process it QFile file(map_file); if(file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&file); QString line = in.readLine(); while(!line.isNull()) { if(std::shared_ptr region = process_map_line(line)) { regions.push_back(region); } line = in.readLine(); } } return regions; } //------------------------------------------------------------------------------ // Name: read_byte // Desc: the base implementation of reading a byte //------------------------------------------------------------------------------ quint8 PlatformProcess::read_byte_via_ptrace(edb::address_t address, bool *ok) const { // TODO(eteran): assert that we are paused Q_ASSERT(ok); Q_ASSERT(core_->process_ == this); *ok = false; // if this spot is unreadable, then just return 0xff, otherwise // continue as normal. // core_->page_size() - 1 will always be 0xf* because pagesizes // are always 0x10*, so the masking works // range of nBytesToNextPage is [1..n] where n=pagesize, and we have to adjust // if nByteToNextPage < wordsize const edb::address_t nBytesToNextPage = core_->page_size() - (address & (core_->page_size() - 1)); // Avoid crossing page boundary, since next page may be unreadable const edb::address_t addressShift = nBytesToNextPage < EDB_WORDSIZE ? EDB_WORDSIZE - nBytesToNextPage : 0; address -= addressShift; const long value = ptrace_peek(address, ok); if(*ok) { quint8 result; // We aren't interested in `value` as in number, it's just a buffer, so no endianness magic. // Just have to compensate for `addressShift` when reading it. std::memcpy(&result,reinterpret_cast(&value)+addressShift,sizeof result); return result; } return 0xff; } //------------------------------------------------------------------------------ // Name: write_byte // Desc: writes a single byte at a given address via ptrace API. // Note: assumes the this will not trample any breakpoints, must be handled // in calling code! //------------------------------------------------------------------------------ void PlatformProcess::write_byte_via_ptrace(edb::address_t address, quint8 value, bool *ok) { // TODO(eteran): assert that we are paused Q_ASSERT(ok); Q_ASSERT(core_->process_ == this); *ok = false; // core_->page_size() - 1 will always be 0xf* because pagesizes // are always 0x10*, so the masking works // range of nBytesToNextPage is [1..n] where n=pagesize, and we have to adjust // if nBytesToNextPage < wordsize const edb::address_t nBytesToNextPage = core_->page_size() - (address & (core_->page_size() - 1)); // Avoid crossing page boundary, since next page may be inaccessible const edb::address_t addressShift = nBytesToNextPage < EDB_WORDSIZE ? EDB_WORDSIZE - nBytesToNextPage : 0; address -= addressShift; long word = ptrace_peek(address, ok); if(!*ok) return; // We aren't interested in `value` as in number, it's just a buffer, so no endianness magic. // Just have to compensate for `addressShift` when writing it. std::memcpy(reinterpret_cast(&word)+addressShift,&value,sizeof value); *ok = ptrace_poke(address, word); } //------------------------------------------------------------------------------ // Name: ptrace_peek // Desc: // Note: this will fail on newer versions of linux if called from a // different thread than the one which attached to process //------------------------------------------------------------------------------ long PlatformProcess::ptrace_peek(edb::address_t address, bool *ok) const { Q_ASSERT(ok); Q_ASSERT(core_->process_ == this); if (EDB_IS_32_BIT && address > 0xffffffffULL) { // 32 bit ptrace can't handle such long addresses *ok = false; return 0; } errno = 0; // NOTE: on some Linux systems ptrace prototype has ellipsis instead of third and fourth arguments // Thus we can't just pass address as is on IA32 systems: it'd put 64 bit integer on stack and cause UB auto nativeAddress=reinterpret_cast(address.toUint()); const long v = ptrace(PTRACE_PEEKTEXT, pid_, nativeAddress, 0); set_ok(*ok, v); return v; } //------------------------------------------------------------------------------ // Name: ptrace_poke // Desc: //------------------------------------------------------------------------------ bool PlatformProcess::ptrace_poke(edb::address_t address, long value) { Q_ASSERT(core_->process_ == this); if (EDB_IS_32_BIT && address > 0xffffffffULL) { // 32 bit ptrace can't handle such long addresses return 0; } // NOTE: on some Linux systems ptrace prototype has ellipsis instead of third and fourth arguments // Thus we can't just pass address as is on IA32 systems: it'd put 64 bit integer on stack and cause UB auto nativeAddress=reinterpret_cast(address.toUint()); return ptrace(PTRACE_POKETEXT, pid_, nativeAddress, value) != -1; } //------------------------------------------------------------------------------ // Name: threads // Desc: //------------------------------------------------------------------------------ QList> PlatformProcess::threads() const { Q_ASSERT(core_->process_ == this); QList> threadList; for(auto &thread : core_->threads_) { threadList.push_back(thread); } return threadList; } //------------------------------------------------------------------------------ // Name: current_thread // Desc: //------------------------------------------------------------------------------ std::shared_ptr PlatformProcess::current_thread() const { Q_ASSERT(core_->process_ == this); auto it = core_->threads_.find(core_->active_thread_); if(it != core_->threads_.end()) { return it.value(); } return nullptr; } //------------------------------------------------------------------------------ // Name: set_current_thread // Desc: //------------------------------------------------------------------------------ void PlatformProcess::set_current_thread(IThread& thread) { core_->active_thread_=static_cast(&thread)->tid(); edb::v1::update_ui(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::uid_t PlatformProcess::uid() const { const QFileInfo info(QString("/proc/%1").arg(pid_)); return info.ownerId(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString PlatformProcess::user() const { if(const struct passwd *const pwd = ::getpwuid(uid())) { return pwd->pw_name; } return QString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString PlatformProcess::name() const { struct user_stat user_stat; const int n = get_user_stat(pid_, &user_stat); if(n >= 2) { return user_stat.comm; } return QString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList PlatformProcess::loaded_modules() const { if(edb::v1::debuggeeIs64Bit()) { return loaded_modules_(this, core_->binary_info_); } else if(edb::v1::debuggeeIs32Bit()) { return loaded_modules_(this, core_->binary_info_); } else { return QList(); } } //------------------------------------------------------------------------------ // Name: pause // Desc: stops *all* threads of a process //------------------------------------------------------------------------------ Status PlatformProcess::pause() { // belive it or not, I belive that this is sufficient for all threads // this is because in the debug event handler above, a SIGSTOP is sent // to all threads when any event arrives, so no need to explicitly do // it here. We just need any thread to stop. So we'll just target the // pid_ which will send it to any one of the threads in the process. if(::kill(pid_, SIGSTOP)==-1) { const char*const strError=strerror(errno); qWarning() << "Unable to pause process" << pid_ << ": kill(SIGSTOP) failed:" << strError; return Status(strError); } return Status::Ok; } //------------------------------------------------------------------------------ // Name: resume // Desc: resumes ALL threads //------------------------------------------------------------------------------ Status PlatformProcess::resume(edb::EVENT_STATUS status) { // TODO: assert that we are paused Q_ASSERT(core_->process_ == this); QString errorMessage; if(status != edb::DEBUG_STOP) { if(std::shared_ptr thread = current_thread()) { const auto resumeStatus=thread->resume(status); if(!resumeStatus) errorMessage+=QObject::tr("Failed to resume thread %1: %2\n").arg(thread->tid()).arg(resumeStatus.toString()); // resume the other threads passing the signal they originally reported had for(auto &other_thread : threads()) { if(core_->waited_threads_.contains(other_thread->tid())) { const auto resumeStatus=other_thread->resume(); if(!resumeStatus) errorMessage+=QObject::tr("Failed to resume thread %1: %2\n").arg(thread->tid()).arg(resumeStatus.toString()); } } } } if(errorMessage.isEmpty()) return Status::Ok; qWarning() << errorMessage.toStdString().c_str(); return Status("\n"+errorMessage); } //------------------------------------------------------------------------------ // Name: step // Desc: steps the currently active thread //------------------------------------------------------------------------------ Status PlatformProcess::step(edb::EVENT_STATUS status) { // TODO: assert that we are paused Q_ASSERT(core_->process_ == this); if(status != edb::DEBUG_STOP) { if(std::shared_ptr thread = current_thread()) { return thread->step(status); } } return Status::Ok; } //------------------------------------------------------------------------------ // Name: isPaused // Desc: returns true if ALL threads are currently in the debugger's wait list //------------------------------------------------------------------------------ bool PlatformProcess::isPaused() const { for(auto &thread : threads()) { if(!thread->isPaused()) { return false; } } return true; } //------------------------------------------------------------------------------ // Name: patches // Desc: returns any patches applied to this process //------------------------------------------------------------------------------ QMap PlatformProcess::patches() const { return patches_; } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/PlatformEvent.h0000644000175000017500000000370713273160654024457 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_EVENT_20121005_H_ #define PLATFORM_EVENT_20121005_H_ #include "IDebugEvent.h" #include #include // for the SIG* definitions namespace DebuggerCorePlugin { class PlatformEvent : public IDebugEvent { Q_DECLARE_TR_FUNCTIONS(PlatformEvent) friend class DebuggerCore; public: PlatformEvent(); private: PlatformEvent(const PlatformEvent &) = default; PlatformEvent& operator=(const PlatformEvent &) = default; public: virtual IDebugEvent *clone() const override; public: virtual Message error_description() const override; virtual REASON reason() const override; virtual TRAP_REASON trap_reason() const override; virtual bool exited() const override; virtual bool is_error() const override; virtual bool is_kill() const override; virtual bool is_stop() const override; virtual bool is_trap() const override; virtual bool stopped() const override; virtual bool terminated() const override; virtual edb::pid_t process() const override; virtual edb::tid_t thread() const override; virtual int code() const override; private: static IDebugEvent::Message createUnexpectedSignalMessage(const QString &name, int number); private: siginfo_t siginfo_; edb::pid_t pid_; edb::tid_t tid_; int status_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/PlatformRegion.h0000644000175000017500000000373113273160654024616 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_REGION_20120330_H_ #define PLATFORM_REGION_20120330_H_ #include "IRegion.h" #include #include namespace DebuggerCorePlugin { class PlatformRegion : public IRegion { Q_DECLARE_TR_FUNCTIONS(PlatformRegion) template friend class BackupInfo; public: PlatformRegion(edb::address_t start, edb::address_t end, edb::address_t base, const QString &name, permissions_t permissions); virtual ~PlatformRegion(); public: virtual IRegion *clone() const; public: virtual bool accessible() const; virtual bool readable() const; virtual bool writable() const; virtual bool executable() const; virtual edb::address_t size() const; public: virtual void set_permissions(bool read, bool write, bool execute); virtual void set_start(edb::address_t address); virtual void set_end(edb::address_t address); public: virtual edb::address_t start() const; virtual edb::address_t end() const; virtual edb::address_t base() const; virtual QString name() const; virtual permissions_t permissions() const; private: void set_permissions(bool read, bool write, bool execute, edb::address_t temp_address); private: edb::address_t start_; edb::address_t end_; edb::address_t base_; QString name_; permissions_t permissions_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/PlatformRegion.cpp0000644000175000017500000003047413273160654025155 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformRegion.h" #include "IDebugEventHandler.h" #include "IDebugger.h" #include "IProcess.h" #include "IThread.h" #include "MemoryRegions.h" #include "State.h" #include "edb.h" #include #include #include namespace DebuggerCorePlugin { namespace { //------------------------------------------------------------------------------ // Name: permissions_value // Desc: //------------------------------------------------------------------------------ IRegion::permissions_t permissions_value(bool read, bool write, bool execute) { IRegion::permissions_t perms = 0; if(read) perms |= PROT_READ; if(write) perms |= PROT_WRITE; if(execute) perms |= PROT_EXEC; return perms; } } template class BackupInfo : public IDebugEventHandler { public: BackupInfo(edb::address_t address, IRegion::permissions_t perms, PlatformRegion *region); ~BackupInfo(); private: Q_DISABLE_COPY(BackupInfo) public: IRegion::permissions_t perms() const { return premissions_; } bool locked() { return !lock_.testAndSetAcquire(0, 1); } public: bool backup(); bool restore(); public: virtual edb::EVENT_STATUS handle_event(const std::shared_ptr &event); public: QAtomicInt lock_; edb::address_t address_; IRegion::permissions_t premissions_; State state_; quint8 buffer_[N]; PlatformRegion *const region_; }; //------------------------------------------------------------------------------ // Name: BackupInfo // Desc: //------------------------------------------------------------------------------ template BackupInfo::BackupInfo(edb::address_t address, IRegion::permissions_t perms, PlatformRegion *region) : lock_(1), address_(address), premissions_(perms), region_(region) { edb::v1::add_debug_event_handler(this); } //------------------------------------------------------------------------------ // Name: BackupInfo // Desc: //------------------------------------------------------------------------------ template BackupInfo::~BackupInfo() { edb::v1::remove_debug_event_handler(this); } //------------------------------------------------------------------------------ // Name: backup // Desc: //------------------------------------------------------------------------------ template bool BackupInfo::backup() { if(IProcess *process = edb::v1::debugger_core->process()) { if(std::shared_ptr thread = process->current_thread()) { thread->get_state(&state_); } return process->read_bytes(address_, buffer_, N); } return false; } //------------------------------------------------------------------------------ // Name: restore // Desc: //------------------------------------------------------------------------------ template bool BackupInfo::restore() { if(IProcess *process = edb::v1::debugger_core->process()) { if(std::shared_ptr thread = process->current_thread()) { thread->set_state(state_); } return process->write_bytes(address_, buffer_, N); } return false; } //------------------------------------------------------------------------------ // Name: handle_event // Desc: //------------------------------------------------------------------------------ template edb::EVENT_STATUS BackupInfo::handle_event(const std::shared_ptr &event) { Q_UNUSED(event); lock_.testAndSetRelease(1, 0); // restore the original code and register state restore(); // update permissions mask region_->permissions_ = perms(); // really shouldn't matter since the return value isn't used at all // we simply want tot catch the event and set the lock to 0 return edb::DEBUG_STOP; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ PlatformRegion::PlatformRegion(edb::address_t start, edb::address_t end, edb::address_t base, const QString &name, permissions_t permissions) : start_(start), end_(end), base_(base), name_(name), permissions_(permissions) { } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ PlatformRegion::~PlatformRegion() { } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ IRegion *PlatformRegion::clone() const { return new PlatformRegion(start_, end_, base_, name_, permissions_); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PlatformRegion::accessible() const { return readable() || writable() || executable(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PlatformRegion::readable() const { return (permissions_ & PROT_READ) != 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PlatformRegion::writable() const { return (permissions_ & PROT_WRITE) != 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PlatformRegion::executable() const { return (permissions_ & PROT_EXEC) != 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PlatformRegion::size() const { return end_ - start_; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ void PlatformRegion::set_permissions(bool read, bool write, bool execute) { edb::address_t temp_address = 0; int count = 0; int ret = QMessageBox::Yes; const QList> ®ions = edb::v1::memory_regions().regions(); // search for an executable region to run our shell code for(const std::shared_ptr ®ion: regions) { if(region->executable()) { if(temp_address == 0) { temp_address = region->start(); } if(++count > 1) { break; } } } if(executable() && count == 1 && !execute) { ret = QMessageBox::question(0, tr("Removing Execute Permissions On Last Executable std::shared_ptr"), tr("You are about to remove execute permissions from the last executable region. Because of the need " "to run code in the process to change permissions, there will be no way to undo this. In addition, " "the process will no longer be able to run as it will have no execute permissions in any regions. " "Odds are this is not what you want to do." "Are you sure you want to remove execute permissions from this region?"), QMessageBox::Yes, QMessageBox::No); } if(ret == QMessageBox::Yes) { if(temp_address != 0) { set_permissions(read, write, execute, temp_address); } else { QMessageBox::critical( 0, tr("No Suitable Address Found"), tr("This feature relies on running shellcode in the debugged process, no executable memory region was found. Unfortunately, this means that no more region permission changes can be made (it also means that there is nothing the process can continue to do since it cannot execute at all).")); } } } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PlatformRegion::start() const { return start_; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PlatformRegion::end() const { return end_; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PlatformRegion::base() const { return base_; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString PlatformRegion::name() const { return name_; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ IRegion::permissions_t PlatformRegion::permissions() const { return permissions_; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ void PlatformRegion::set_permissions(bool read, bool write, bool execute, edb::address_t temp_address) { const permissions_t perms = permissions_value(read, write, execute); const edb::address_t len = size(); const edb::address_t addr = start(); // I wish there was a clean way to get the value of this system call for either target // but nothing obvious comes to mind. We may have to do something crazy // with macros, but for now, we just hard code it :-/ const edb::address_t syscallnum = edb::v1::debuggeeIs32Bit() ? 125 : 10; //__NR_mprotect; // start of nowhere near portable code const quint8 shellcode32[] = { "\xcd\x80" // int $0x80 "\xf4" // hlt }; const quint8 shellcode64[] = { "\x0f\x05" // syscall "\xf4" // hlt }; quint8 shellcode[3]; if(edb::v1::debuggeeIs32Bit()) { memcpy(shellcode, shellcode32, sizeof(shellcode)); } else { memcpy(shellcode, shellcode64, sizeof(shellcode)); } // end nowhere near portable code typedef BackupInfo BI; if(IProcess *process = edb::v1::debugger_core->process()) { if(std::shared_ptr thread = process->current_thread()) { try { BI backup_info(temp_address, perms, this); if(backup_info.backup()) { // write out our shellcode if(process->write_bytes(temp_address, shellcode, sizeof(shellcode))) { State state; thread->get_state(&state); state.set_instruction_pointer(temp_address); if(edb::v1::debuggeeIs32Bit()) { state.set_register("ecx", len); state.set_register("ebx", addr); state.set_register("edx", perms); state.set_register("eax", syscallnum); } else { state.set_register("rsi", len); state.set_register("rdi", addr); state.set_register("rdx", perms); state.set_register("rax", syscallnum); } thread->set_state(state); // run the system call instruction and wait for the trap thread->step(edb::DEBUG_CONTINUE); // we use a spinlock here because we want to be able to // process events while waiting while(backup_info.locked()) { QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); } } } } catch(const std::bad_alloc &) { QMessageBox::critical( 0, tr("Memory Allocation Error"), tr("Unable to satisfy memory allocation request for backup code.")); } } } } void PlatformRegion::set_start(edb::address_t address) { start_ = address; } void PlatformRegion::set_end(edb::address_t address) { end_ = address; } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/PlatformProcess.h0000644000175000017500000000661213273160654025012 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATOFORM_PROCESS_20150517_H_ #define PLATOFORM_PROCESS_20150517_H_ #include "IProcess.h" #include "Status.h" #include namespace DebuggerCorePlugin { class DebuggerCore; class PlatformProcess : public IProcess { friend class PlatformThread; public: PlatformProcess(DebuggerCore *core, edb::pid_t pid); virtual ~PlatformProcess(); private: PlatformProcess(const PlatformProcess &) = delete; PlatformProcess& operator=(const PlatformProcess &) = delete; public: virtual QDateTime start_time() const override; virtual QList arguments() const override; virtual QString current_working_directory() const override; virtual QString executable() const override; virtual edb::pid_t pid() const override; virtual std::shared_ptr parent() const override; virtual edb::address_t code_address() const override; virtual edb::address_t data_address() const override; virtual QList> regions() const override; virtual QList> threads() const override; virtual std::shared_ptr current_thread() const override; virtual void set_current_thread(IThread& thread) override; virtual edb::uid_t uid() const override; virtual QString user() const override; virtual QString name() const override; virtual QList loaded_modules() const override; public: virtual Status pause() override; virtual Status resume(edb::EVENT_STATUS status) override; virtual Status step(edb::EVENT_STATUS status) override; virtual bool isPaused() const override; public: virtual std::size_t write_bytes(edb::address_t address, const void *buf, size_t len) override; virtual std::size_t patch_bytes(edb::address_t address, const void *buf, size_t len) override; virtual std::size_t read_bytes(edb::address_t address, void *buf, size_t len) const override; virtual std::size_t read_pages(edb::address_t address, void *buf, size_t count) const override; virtual QMap patches() const override; private: bool ptrace_poke(edb::address_t address, long value); long ptrace_peek(edb::address_t address, bool *ok) const; quint8 read_byte_via_ptrace(edb::address_t address, bool *ok) const; void write_byte_via_ptrace(edb::address_t address, quint8 value, bool *ok); private: DebuggerCore* core_; edb::pid_t pid_; QFile* ro_mem_file_; QFile* rw_mem_file_; QMap patches_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/PlatformEvent.cpp0000644000175000017500000003020213273160654025000 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformEvent.h" #include "edb.h" namespace DebuggerCorePlugin { //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ PlatformEvent::PlatformEvent() : pid_(0), tid_(0), status_(0) { std::memset(&siginfo_, 0, sizeof(siginfo_t)); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent *PlatformEvent::clone() const { return new PlatformEvent(*this); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::Message PlatformEvent::createUnexpectedSignalMessage(const QString &name, int number) { return Message( tr("Unexpected Signal Encountered"), tr("

The debugged application encountered a %1 (%2).

").arg(name).arg(number), tr("% received").arg(name) ); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::Message PlatformEvent::error_description() const { Q_ASSERT(is_error()); auto fault_address = edb::address_t::fromZeroExtended(siginfo_.si_addr); std::size_t debuggeePtrSize=edb::v1::pointer_size(); bool fullAddressKnown=debuggeePtrSize<=sizeof(void*); const auto addressString=fault_address.toPointerString(fullAddressKnown); Message message; switch(code()) { case SIGSEGV: switch(siginfo_.si_code) { case SEGV_MAPERR: message=Message( tr("Illegal Access Fault"), tr("

The debugged application encountered a segmentation fault.
The address %1 does not appear to be mapped.

").arg(addressString), tr("SIGSEGV: SEGV_MAPERR: Accessed address %1 not mapped").arg(addressString) ); break; case SEGV_ACCERR: message=Message( tr("Illegal Access Fault"), tr("

The debugged application encountered a segmentation fault.
The address %1 could not be accessed.

").arg(addressString), tr("SIGSEGV: SEGV_ACCERR: Access to address %1 not permitted").arg(addressString) ); break; default: message=Message( tr("Illegal Access Fault"), tr("

The debugged application encountered a segmentation fault.
The instruction could not be executed.

"), tr("SIGSEGV: Segmentation fault") ); break; } break; case SIGILL: message=Message( tr("Illegal Instruction Fault"), tr("

The debugged application attempted to execute an illegal instruction.

"), tr("SIGILL: Illegal instruction") ); break; case SIGFPE: switch(siginfo_.si_code) { case FPE_INTDIV: message=Message( tr("Divide By Zero"), tr("

The debugged application tried to divide an integer value by an integer divisor of zero or encountered integer division overflow.

"), tr("SIGFPE: FPE_INTDIV: Integer division by zero or division overflow") ); break; case FPE_FLTDIV: message=Message( tr("Divide By Zero"), tr("

The debugged application tried to divide an floating-point value by a floating-point divisor of zero.

"), tr("SIGFPE: FPE_FLTDIV: Floating-point division by zero") ); break; case FPE_FLTOVF: message=Message( tr("Numeric Overflow"), tr("

The debugged application encountered a numeric overflow while performing a floating-point computation.

"), tr("SIGFPE: FPE_FLTOVF: Numeric overflow exception") ); break; case FPE_FLTUND: message=Message( tr("Numeric Underflow"), tr("

The debugged application encountered a numeric underflow while performing a floating-point computation.

"), tr("SIGFPE: FPE_FLTUND: Numeric underflow exception") ); break; case FPE_FLTRES: message=Message( tr("Inexact Result"), tr("

The debugged application encountered an inexact result of a floating-point computation it was performing.

"), tr("SIGFPE: FPE_FLTRES: Inexact result exception") ); break; case FPE_FLTINV: message=Message( tr("Invalid Operation"), tr("

The debugged application attempted to perform an invalid floating-point operation.

"), tr("SIGFPE: FPE_FLTINV: Invalid floating-point operation") ); break; default: message=Message( tr("Floating Point Exception"), tr("

The debugged application encountered a floating-point exception.

"), tr("SIGFPE: Floating-point exception") ); break; } break; case SIGABRT: message=Message( tr("Application Aborted"), tr("

The debugged application has aborted.

"), tr("SIGABRT: Application aborted") ); break; case SIGBUS: message=Message( tr("Bus Error"), tr("

The debugged application received a bus error. Typically, this means that it tried to read or write data that is misaligned.

"), tr("SIGBUS: Bus error") ); break; #ifdef SIGSTKFLT case SIGSTKFLT: message=Message( tr("Stack Fault"), tr("

The debugged application encountered a stack fault.

"), tr("SIGSTKFLT: Stack fault") ); break; #endif case SIGPIPE: message=Message( tr("Broken Pipe Fault"), tr("

The debugged application encountered a broken pipe fault.

"), tr("SIGPIPE: Pipe broken") ); break; #ifdef SIGHUP case SIGHUP: message=createUnexpectedSignalMessage("SIGHUP", SIGHUP); break; #endif #ifdef SIGINT case SIGINT: message=createUnexpectedSignalMessage("SIGINT", SIGINT); break; #endif #ifdef SIGQUIT case SIGQUIT: message=createUnexpectedSignalMessage("SIGQUIT", SIGQUIT); break; #endif #ifdef SIGTRAP case SIGTRAP: message=createUnexpectedSignalMessage("SIGTRAP", SIGTRAP); break; #endif #ifdef SIGKILL case SIGKILL: message=createUnexpectedSignalMessage("SIGKILL", SIGKILL); break; #endif #ifdef SIGUSR1 case SIGUSR1: message=createUnexpectedSignalMessage("SIGUSR1", SIGUSR1); break; #endif #ifdef SIGUSR2 case SIGUSR2: message=createUnexpectedSignalMessage("SIGUSR2", SIGUSR2); break; #endif #ifdef SIGALRM case SIGALRM: message=createUnexpectedSignalMessage("SIGALRM", SIGALRM); break; #endif #ifdef SIGTERM case SIGTERM: message=createUnexpectedSignalMessage("SIGTERM", SIGTERM); break; #endif #ifdef SIGCHLD case SIGCHLD: message=createUnexpectedSignalMessage("SIGCHLD", SIGCHLD); break; #endif #ifdef SIGCONT case SIGCONT: message=createUnexpectedSignalMessage("SIGCONT", SIGCONT); break; #endif #ifdef SIGSTOP case SIGSTOP: message=createUnexpectedSignalMessage("SIGSTOP", SIGSTOP); break; #endif #ifdef SIGTSTP case SIGTSTP: message=createUnexpectedSignalMessage("SIGTSTP", SIGTSTP); break; #endif #ifdef SIGTTIN case SIGTTIN: message=createUnexpectedSignalMessage("SIGTTIN", SIGTTIN); break; #endif #ifdef SIGTTOU case SIGTTOU: message=createUnexpectedSignalMessage("SIGTTOU", SIGTTOU); break; #endif #ifdef SIGURG case SIGURG: message=createUnexpectedSignalMessage("SIGURG", SIGURG); break; #endif #ifdef SIGXCPU case SIGXCPU: message=createUnexpectedSignalMessage("SIGXCPU", SIGXCPU); break; #endif #ifdef SIGXFSZ case SIGXFSZ: message=createUnexpectedSignalMessage("SIGXFSZ", SIGXFSZ); break; #endif #ifdef SIGVTALRM case SIGVTALRM: message=createUnexpectedSignalMessage("SIGVTALRM", SIGVTALRM); break; #endif #ifdef SIGPROF case SIGPROF: message=createUnexpectedSignalMessage("SIGPROF", SIGPROF); break; #endif #ifdef SIGWINCH case SIGWINCH: message=createUnexpectedSignalMessage("SIGWINCH", SIGWINCH); break; #endif #ifdef SIGIO case SIGIO: message=createUnexpectedSignalMessage("SIGIO", SIGIO); break; #endif default: return Message(); } message.message+="

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"; message.statusMessage+=". Shift+Run/Step to pass signal to the program"; return message; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::REASON PlatformEvent::reason() const { // this basically converts our value into a 'switchable' value for convenience if(stopped()) { return EVENT_STOPPED; } else if(terminated()) { return EVENT_TERMINATED; } else if(exited()) { return EVENT_EXITED; } else { return EVENT_UNKNOWN; } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::TRAP_REASON PlatformEvent::trap_reason() const { switch(siginfo_.si_code) { case TRAP_TRACE: return TRAP_STEPPING; default: return TRAP_BREAKPOINT; } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::exited() const { return WIFEXITED(status_) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_error() const { if(stopped()) { switch(code()) { case SIGTRAP: case SIGSTOP: return false; case SIGSEGV: case SIGILL: case SIGFPE: case SIGABRT: case SIGBUS: #ifdef SIGSTKFLT case SIGSTKFLT: #endif case SIGPIPE: return true; default: return false; } } else { return false; } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_kill() const { return stopped() && code() == SIGKILL; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_stop() const { return stopped() && code() == SIGSTOP; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_trap() const { return stopped() && code() == SIGTRAP; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::terminated() const { return WIFSIGNALED(status_) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::stopped() const { return WIFSTOPPED(status_) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ edb::pid_t PlatformEvent::process() const { return pid_; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ edb::tid_t PlatformEvent::thread() const { return tid_; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ int PlatformEvent::code() const { if(stopped()) { return WSTOPSIG(status_); } if(terminated()) { return WTERMSIG(status_); } if(exited()) { return WEXITSTATUS(status_); } return 0; } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/FeatureDetect.h0000644000175000017500000000156613273160654024416 0ustar eteraneteran/* Copyright (C) 2016 - 2016 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef FEATURE_DETECT_H_ #define FEATURE_DETECT_H_ namespace DebuggerCorePlugin { namespace feature { bool detect_proc_access(bool *read_broken, bool *write_broken); } } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/PlatformCommon.cpp0000644000175000017500000002147113273160654025157 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformCommon.h" #include #include #include #include #include namespace DebuggerCorePlugin { //------------------------------------------------------------------------------ // Name: resume_code // Desc: //------------------------------------------------------------------------------ int resume_code(int status) { if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP) { return 0; } if(WIFSIGNALED(status)) { return WTERMSIG(status); } if(WIFSTOPPED(status)) { return WSTOPSIG(status); } return 0; } //------------------------------------------------------------------------------ // Name: get_user_stat // Desc: gets the contents of /proc//stat and returns the number of elements // successfully parsed //------------------------------------------------------------------------------ int get_user_stat(const QString &path, struct user_stat *user_stat) { Q_ASSERT(user_stat); int r = -1; QFile file(path); if(file.open(QIODevice::ReadOnly)) { QTextStream in(&file); const QString line = in.readLine(); if(!line.isNull()) { #if 1 QRegExp regex(QLatin1String(R"(^(-?[0-9]+) \((.+)\) (.) (-?[0-9]+) (-?[0-9]+) (-?[0-9]+) (-?[0-9]+) (-?[0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) (-?[0-9]+) (-?[0-9]+) (-?[0-9]+) (-?[0-9]+) (-?[0-9]+) (-?[0-9]+) ([0-9]+) ([0-9]+) (-?[0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) (-?[0-9]+) (-?[0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) (-?[0-9]+))")); int n = regex.indexIn(line); if(n != -1) { const QStringList &fields = regex.capturedTexts(); switch(regex.captureCount()) { default: case 44: user_stat->cguest_time = fields[44].toLongLong(); /* fallthrough */ // "%lld" case 43: user_stat->guest_time = fields[43].toULongLong(); /* fallthrough */ // "%llu" case 42: user_stat->delayacct_blkio_ticks = fields[42].toULongLong(); /* fallthrough */ // "%llu" case 41: user_stat->policy = fields[41].toUInt(); /* fallthrough */ // "%u" case 40: user_stat->rt_priority = fields[40].toUInt(); /* fallthrough */ // "%u" case 39: user_stat->processor = fields[39].toInt(); /* fallthrough */ // "%d" case 38: user_stat->exit_signal = fields[38].toInt(); /* fallthrough */ // "%d" case 37: user_stat->cnswap = fields[37].toULongLong(); /* fallthrough */ // "%llu" case 36: user_stat->nswap = fields[36].toULongLong(); /* fallthrough */ // "%llu" case 35: user_stat->wchan = fields[35].toULongLong(); /* fallthrough */ // "%llu" case 34: user_stat->sigcatch = fields[34].toULongLong(); /* fallthrough */ // "%llu" case 33: user_stat->sigignore = fields[33].toULongLong(); /* fallthrough */ // "%llu" case 32: user_stat->blocked = fields[32].toULongLong(); /* fallthrough */ // "%llu" case 31: user_stat->signal = fields[31].toULongLong(); /* fallthrough */ // "%llu" case 30: user_stat->kstkeip = fields[30].toULongLong(); /* fallthrough */ // "%llu" case 29: user_stat->kstkesp = fields[29].toULongLong(); /* fallthrough */ // "%llu" case 28: user_stat->startstack = fields[28].toULongLong(); /* fallthrough */ // "%llu" case 27: user_stat->endcode = fields[27].toULongLong(); /* fallthrough */ // "%llu" case 26: user_stat->startcode = fields[26].toULongLong(); /* fallthrough */ // "%llu" case 25: user_stat->rsslim = fields[25].toULongLong(); /* fallthrough */ // "%llu" case 24: user_stat->rss = fields[24].toLongLong(); /* fallthrough */ // "%lld" case 23: user_stat->vsize = fields[23].toULongLong(); /* fallthrough */ // "%llu" case 22: user_stat->starttime = fields[22].toULongLong(); /* fallthrough */ // "%llu" case 21: user_stat->itrealvalue = fields[21].toLongLong(); /* fallthrough */ // "%lld" case 20: user_stat->num_threads = fields[20].toLongLong(); /* fallthrough */ // "%lld" case 19: user_stat->nice = fields[19].toLongLong(); /* fallthrough */ // "%lld" case 18: user_stat->priority = fields[18].toLongLong(); /* fallthrough */ // "%lld" case 17: user_stat->cstime = fields[17].toLongLong(); /* fallthrough */ // "%lld" case 16: user_stat->cutime = fields[16].toLongLong(); /* fallthrough */ // "%lld" case 15: user_stat->stime = fields[15].toULongLong(); /* fallthrough */ // "%llu" case 14: user_stat->utime = fields[14].toULongLong(); /* fallthrough */ // "%llu" case 13: user_stat->cmajflt = fields[13].toULongLong(); /* fallthrough */ // "%llu" case 12: user_stat->majflt = fields[12].toULongLong(); /* fallthrough */ // "%llu" case 11: user_stat->cminflt = fields[11].toULongLong(); /* fallthrough */ // "%llu" case 10: user_stat->minflt = fields[10].toULongLong(); /* fallthrough */ // "%llu" case 9: user_stat->flags = fields[9].toUInt(); /* fallthrough */ // "%u" case 8: user_stat->tpgid = fields[8].toInt(); /* fallthrough */ // "%d" case 7: user_stat->tty_nr = fields[7].toInt(); /* fallthrough */ // "%d" case 6: user_stat->session = fields[6].toInt(); /* fallthrough */ // "%d" case 5: user_stat->pgrp = fields[5].toInt(); /* fallthrough */ // "%d" case 4: user_stat->ppid = fields[4].toInt(); /* fallthrough */ // "%d" case 3: user_stat->state = fields[3][0].toLatin1(); /* fallthrough */ // "%c" case 2: snprintf(user_stat->comm, sizeof(user_stat->comm), "%s", qPrintable(fields[2])); /* fallthrough */ case 1: user_stat->pid = fields[1].toInt(); // "%d" break; case 0: qDebug() << "Warning: Failed to read any fields from /proc//stat"; } return regex.captureCount(); } #else char ch; r = sscanf(qPrintable(line), "%d %c%255[0-9a-zA-Z_- #~/\\.]%c %c %d %d %d %d %d %u %llu %llu %llu %llu %llu %llu %lld %lld %lld %lld %lld %lld %llu %llu %lld %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %d %d %u %u %llu %llu %lld", &user_stat->pid, &ch, // consume the ( user_stat->comm, &ch, // consume the ) &user_stat->state, &user_stat->ppid, &user_stat->pgrp, &user_stat->session, &user_stat->tty_nr, &user_stat->tpgid, &user_stat->flags, &user_stat->minflt, &user_stat->cminflt, &user_stat->majflt, &user_stat->cmajflt, &user_stat->utime, &user_stat->stime, &user_stat->cutime, &user_stat->cstime, &user_stat->priority, &user_stat->nice, &user_stat->num_threads, &user_stat->itrealvalue, &user_stat->starttime, &user_stat->vsize, &user_stat->rss, &user_stat->rsslim, &user_stat->startcode, &user_stat->endcode, &user_stat->startstack, &user_stat->kstkesp, &user_stat->kstkeip, &user_stat->signal, &user_stat->blocked, &user_stat->sigignore, &user_stat->sigcatch, &user_stat->wchan, &user_stat->nswap, &user_stat->cnswap, &user_stat->exit_signal, &user_stat->processor, &user_stat->rt_priority, &user_stat->policy, &user_stat->delayacct_blkio_ticks, &user_stat->guest_time, &user_stat->cguest_time); #endif } file.close(); } return r; } //------------------------------------------------------------------------------ // Name: get_user_stat // Desc: gets the contents of /proc//stat and returns the number of elements // successfully parsed //------------------------------------------------------------------------------ int get_user_stat(edb::pid_t pid, struct user_stat *user_stat) { return get_user_stat(QString("/proc/%1/stat").arg(pid), user_stat); } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/DialogMemoryAccess.h0000644000175000017500000000213513273160654025375 0ustar eteraneteran/* Copyright (C) 2016 - 2016 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DIALOG_MEMORY_ACCESS_20160930_H_ #define DIALOG_MEMORY_ACCESS_20160930_H_ #include namespace DebuggerCorePlugin { namespace Ui { class DialogMemoryAccess; } class DialogMemoryAccess : public QDialog { Q_OBJECT public: DialogMemoryAccess(QWidget *parent = 0); virtual ~DialogMemoryAccess(); public: bool warnNextTime() const; private: Ui::DialogMemoryAccess *const ui; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/PrStatus.h0000644000175000017500000000205713273160654023453 0ustar eteraneteran #ifndef PR_STATUS_H_ #define PR_STATUS_H_ #include struct PrStatus_X86 { uint32_t ebx; uint32_t ecx; uint32_t edx; uint32_t esi; uint32_t edi; uint32_t ebp; uint32_t eax; uint32_t ds; uint32_t es; uint32_t fs; uint32_t gs; uint32_t orig_eax; uint32_t eip; uint32_t cs; uint32_t eflags; uint32_t esp; uint32_t ss; }; static_assert(sizeof(PrStatus_X86) == 68, "PrStatus_X86 is messed up!"); struct PrStatus_X86_64 { uint64_t r15; uint64_t r14; uint64_t r13; uint64_t r12; uint64_t rbp; uint64_t rbx; uint64_t r11; uint64_t r10; uint64_t r9; uint64_t r8; uint64_t rax; uint64_t rcx; uint64_t rdx; uint64_t rsi; uint64_t rdi; uint64_t orig_rax; uint64_t rip; uint64_t cs; uint64_t rflags; uint64_t rsp; uint64_t ss; uint64_t fs_base; uint64_t gs_base; uint64_t ds; uint64_t es; uint64_t fs; uint64_t gs; }; static_assert(sizeof(PrStatus_X86_64) == 216, "PrStatus_X86_64 is messed up!"); struct PrStatus_ARM { uint32_t regs[18]; }; static_assert(sizeof(PrStatus_ARM) == 72, "PrStatus_ARM is messed up!"); #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/PlatformCommon.h0000644000175000017500000000536313273160654024626 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_COMMON_20151011_H_ #define PLATFORM_COMMON_20151011_H_ #include "edb.h" #include "OSTypes.h" class QString; namespace DebuggerCorePlugin { struct user_stat { /* 01 */ int pid; /* 02 */ char comm[256]; /* 03 */ char state; /* 04 */ int ppid; /* 05 */ int pgrp; /* 06 */ int session; /* 07 */ int tty_nr; /* 08 */ int tpgid; /* 09 */ unsigned flags; /* 10 */ unsigned long long minflt; /* 11 */ unsigned long long cminflt; /* 12 */ unsigned long long majflt; /* 13 */ unsigned long long cmajflt; /* 14 */ unsigned long long utime; /* 15 */ unsigned long long stime; /* 16 */ long long cutime; /* 17 */ long long cstime; /* 18 */ long long priority; /* 19 */ long long nice; /* 20 */ long long num_threads; /* 21 */ long long itrealvalue; /* 22 */ unsigned long long starttime; /* 23 */ unsigned long long vsize; /* 24 */ long long rss; /* 25 */ unsigned long long rsslim; /* 26 */ unsigned long long startcode; /* 27 */ unsigned long long endcode; /* 28 */ unsigned long long startstack; /* 29 */ unsigned long long kstkesp; /* 30 */ unsigned long long kstkeip; /* 31 */ unsigned long long signal; /* 32 */ unsigned long long blocked; /* 33 */ unsigned long long sigignore; /* 34 */ unsigned long long sigcatch; /* 35 */ unsigned long long wchan; /* 36 */ unsigned long long nswap; /* 37 */ unsigned long long cnswap; /* 38 */ int exit_signal; /* 39 */ int processor; /* 40 */ unsigned rt_priority; /* 41 */ unsigned policy; // Linux 2.6.18 /* 42 */ unsigned long long delayacct_blkio_ticks; // Linux 2.6.24 /* 43 */ unsigned long long guest_time; /* 44 */ long long cguest_time; // Linux 3.3 /* 45 */ unsigned long long start_data; /* 46 */ unsigned long long end_data; /* 47 */ unsigned long long start_brk; // Linux 3.5 /* 48 */ unsigned long long arg_start; /* 49 */ unsigned long long arg_end; /* 50 */ unsigned long long env_start; /* 51 */ unsigned long long env_end; /* 52 */ int exit_code; }; int get_user_stat(const QString &path, struct user_stat *user_stat); int get_user_stat(edb::pid_t pid, struct user_stat *user_stat); int resume_code(int status); } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/DialogMemoryAccess.cpp0000644000175000017500000000216713273160654025735 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "DialogMemoryAccess.h" #include "ui_DialogMemoryAccess.h" namespace DebuggerCorePlugin { DialogMemoryAccess::DialogMemoryAccess(QWidget *parent) : QDialog(parent), ui(new Ui::DialogMemoryAccess) { ui->setupUi(this); adjustSize(); setFixedSize(width(), height()); } DialogMemoryAccess::~DialogMemoryAccess() { delete ui; } bool DialogMemoryAccess::warnNextTime() const { return !ui->checkNeverShowAgain->isChecked(); } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/arch/0000755000175000017500000000000013273160654022426 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/arch/x86-generic/0000755000175000017500000000000013273160654024465 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/arch/x86-generic/PlatformThread.cpp0000644000175000017500000002441513273160654030113 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformThread.h" #include "DebuggerCore.h" #include "IProcess.h" #include "PlatformCommon.h" #include "PlatformState.h" #include #include "State.h" #ifndef _GNU_SOURCE #define _GNU_SOURCE /* or _BSD_SOURCE or _SVID_SOURCE */ #endif #include #include #include #include #include // doesn't always seem to be defined in the headers #ifndef PTRACE_GET_THREAD_AREA #define PTRACE_GET_THREAD_AREA static_cast<__ptrace_request>(25) #endif #ifndef PTRACE_SET_THREAD_AREA #define PTRACE_SET_THREAD_AREA static_cast<__ptrace_request>(26) #endif #ifndef PTRACE_GETSIGINFO #define PTRACE_GETSIGINFO static_cast<__ptrace_request>(0x4202) #endif #ifndef PTRACE_GETREGSET #define PTRACE_GETREGSET static_cast<__ptrace_request>(0x4204) #endif #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET static_cast<__ptrace_request>(0x4205) #endif namespace DebuggerCorePlugin { //------------------------------------------------------------------------------ // Name: fillSegmentBases // Desc: //------------------------------------------------------------------------------ void PlatformThread::fillSegmentBases(PlatformState* state) { struct user_desc desc = {}; for(size_t sregIndex = 0; sregIndex < state->seg_reg_count(); ++sregIndex) { const edb::seg_reg_t reg=state->x86.segRegs[sregIndex]; if(!reg) { continue; } bool fromGDT = !(reg & 0x04); // otherwise the selector picks descriptor from LDT if(!fromGDT) { continue; } if(ptrace(PTRACE_GET_THREAD_AREA, tid_, reg / LDT_ENTRY_SIZE, &desc) != -1) { state->x86.segRegBases[sregIndex] = desc.base_addr; state->x86.segRegBasesFilled[sregIndex] = true; } } for(size_t sregIndex = 0;sregIndex < state->seg_reg_count(); ++sregIndex) { const edb::seg_reg_t sreg = state->x86.segRegs[sregIndex]; if(sreg == core_->USER_CS_32 || sreg == core_->USER_CS_64 || sreg == core_->USER_SS || (state->is64Bit() && sregIndex < PlatformState::X86::FS)) { state->x86.segRegBases[sregIndex] = 0; state->x86.segRegBasesFilled[sregIndex] = true; } } } //------------------------------------------------------------------------------ // Name: fillStateFromPrStatus // Desc: //------------------------------------------------------------------------------ bool PlatformThread::fillStateFromPrStatus(PlatformState* state) { static bool prStatusSupported = true; if(!prStatusSupported) { return false; } PrStatus_X86_64 prstat64; iovec prstat_iov = {&prstat64, sizeof(prstat64)}; if(ptrace(PTRACE_GETREGSET, tid_, NT_PRSTATUS, &prstat_iov) != -1) { switch(prstat_iov.iov_len) { case sizeof(PrStatus_X86_64): state->fillFrom(prstat64); break; case sizeof(PrStatus_X86): // In this case the actual structure returned is PrStatus_X86, // so copy it to the correct container (reinterpret_cast would // cause UB in any case). Good compiler should be able to optimize this out. PrStatus_X86 prstat32; std::memcpy(&prstat32, &prstat64, sizeof(prstat32)); state->fillFrom(prstat32); break; default: prStatusSupported = false; qWarning() << "PTRACE_GETREGSET(NT_PRSTATUS) returned unexpected length " << prstat_iov.iov_len; return false; } } else { prStatusSupported = false; perror("PTRACE_GETREGSET(NT_PRSTATUS) failed"); return false; } fillSegmentBases(state); return true; } //------------------------------------------------------------------------------ // Name: fillStateFromSimpleRegs // Desc: //------------------------------------------------------------------------------ bool PlatformThread::fillStateFromSimpleRegs(PlatformState* state) { user_regs_struct regs; if(ptrace(PTRACE_GETREGS, tid_, 0, ®s) != -1) { state->fillFrom(regs); fillSegmentBases(state); return true; } else { perror("PTRACE_GETREGS failed"); return false; } } //------------------------------------------------------------------------------ // Name: get_state // Desc: //------------------------------------------------------------------------------ void PlatformThread::get_state(State *state) { // TODO: assert that we are paused core_->detectCPUMode(); if(auto state_impl = static_cast(state->impl_)) { // State must be cleared before filling to zero all presence flags, otherwise something // may remain not updated. Also, this way we'll mark all the unfilled values. state_impl->clear(); if(EDB_IS_64_BIT) { // 64-bit GETREGS call always returns 64-bit state, so use it fillStateFromSimpleRegs(state_impl); } else if(!fillStateFromPrStatus(state_impl)) { // if EDB is 32 bit, use GETREGSET so that we get 64-bit state for 64-bit debuggee fillStateFromSimpleRegs(state_impl); // failing that, try to just get what we can } // First try to get full XSTATE X86XState xstate; struct iovec iov = { &xstate, sizeof(xstate) }; long status = ptrace(PTRACE_GETREGSET, tid_, NT_X86_XSTATE, &iov); if(status == -1 || !state_impl->fillFrom(xstate,iov.iov_len)) { // No XSTATE available, get just floating point and SSE registers static bool getFPXRegsSupported = EDB_IS_32_BIT; UserFPXRegsStructX86 fpxregs; // This should be automatically optimized out on amd64. If not, not a big deal. // Avoiding conditional compilation to facilitate syntax error checking if(getFPXRegsSupported) { getFPXRegsSupported = (ptrace(PTRACE_GETFPXREGS, tid_, 0, &fpxregs) != -1); } if(getFPXRegsSupported) { state_impl->fillFrom(fpxregs); } else { // No GETFPXREGS: on x86 this means SSE is not supported // on x86_64 FPREGS already contain SSE state struct user_fpregs_struct fpregs; status = ptrace(PTRACE_GETFPREGS, tid_, 0, &fpregs); if(status != -1) { state_impl->fillFrom(fpregs); } else { perror("PTRACE_GETFPREGS failed"); } } } // debug registers for(std::size_t i = 0; i < 8; ++i) { state_impl->x86.dbgRegs[i] = get_debug_register(i); } } } //------------------------------------------------------------------------------ // Name: set_state // Desc: //------------------------------------------------------------------------------ void PlatformThread::set_state(const State &state) { // TODO: assert that we are paused if(auto state_impl = static_cast(state.impl_)) { bool setPrStatusDone = false; if(EDB_IS_32_BIT && state_impl->is64Bit()) { // Try to set 64-bit state PrStatus_X86_64 prstat64; state_impl->fillStruct(prstat64); struct iovec prstat_iov = { &prstat64, sizeof(prstat64) }; if(ptrace(PTRACE_SETREGSET, tid_, NT_PRSTATUS, &prstat_iov) != -1) { setPrStatusDone = true; } else { perror("PTRACE_SETREGSET failed"); } } // Fallback to setting 32-bit set if(!setPrStatusDone) { struct user_regs_struct regs; state_impl->fillStruct(regs); ptrace(PTRACE_SETREGS, tid_, 0, ®s); } // debug registers for(std::size_t i = 0;i < 8; ++i) { set_debug_register(i, state_impl->x86.dbgRegs[i]); } // hope for the best, adjust for reality static bool xsaveSupported = true; if(xsaveSupported) { X86XState xstate; const auto size = state_impl->fillStruct(xstate); struct iovec iov = { &xstate, size }; if(ptrace(PTRACE_SETREGSET, tid_, NT_X86_XSTATE, &iov) == -1) { xsaveSupported = false; } } // If xsave/xrstor appears unsupported, fallback to fxrstor // NOTE: it's not "else", it's an independent check for possibly modified flag if(!xsaveSupported) { static bool setFPXRegsSupported = EDB_IS_32_BIT; if(setFPXRegsSupported) { UserFPXRegsStructX86 fpxregs; state_impl->fillStruct(fpxregs); setFPXRegsSupported = (ptrace(PTRACE_SETFPXREGS, tid_, 0, &fpxregs) != -1); } if(!setFPXRegsSupported) { // No SETFPXREGS: on x86 this means SSE is not supported // on x86_64 FPREGS already contain SSE state // Just set fpregs then struct user_fpregs_struct fpregs; state_impl->fillStruct(fpregs); if(ptrace(PTRACE_SETFPREGS, tid_, 0, &fpregs) == -1) { perror("PTRACE_SETFPREGS failed"); } } } } } //------------------------------------------------------------------------------ // Name: get_debug_register // Desc: //------------------------------------------------------------------------------ unsigned long PlatformThread::get_debug_register(std::size_t n) { return ptrace(PTRACE_PEEKUSER, tid_, offsetof(struct user, u_debugreg[n]), 0); } //------------------------------------------------------------------------------ // Name: set_debug_register // Desc: //------------------------------------------------------------------------------ long PlatformThread::set_debug_register(std::size_t n, long value) { return ptrace(PTRACE_POKEUSER, tid_, offsetof(struct user, u_debugreg[n]), value); } //------------------------------------------------------------------------------ // Name: step // Desc: steps this thread one instruction, passing the signal that stopped it // (unless the signal was SIGSTOP) //------------------------------------------------------------------------------ Status PlatformThread::step() { return core_->ptrace_step(tid_, resume_code(status_)); } //------------------------------------------------------------------------------ // Name: step // Desc: steps this thread one instruction, passing the signal that stopped it // (unless the signal was SIGSTOP, or the passed status != DEBUG_EXCEPTION_NOT_HANDLED) //------------------------------------------------------------------------------ Status PlatformThread::step(edb::EVENT_STATUS status) { const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(status_) : 0; return core_->ptrace_step(tid_, code); } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/arch/x86-generic/PlatformState.cpp0000644000175000017500000013145613273160654027770 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformState.h" #include "FloatX.h" #include "Util.h" #include #include #include namespace DebuggerCorePlugin { constexpr const char *PlatformState::AVX::mxcsrName; constexpr const char *PlatformState::X86::IP64Name; constexpr const char *PlatformState::X86::IP32Name; constexpr const char *PlatformState::X86::IP16Name; constexpr const char *PlatformState::X86::origEAXName; constexpr const char *PlatformState::X86::origRAXName; constexpr const char *PlatformState::X86::flags64Name; constexpr const char *PlatformState::X86::flags32Name; constexpr const char *PlatformState::X86::flags16Name; const std::array PlatformState::X86::GPReg64Names = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }; const std::array PlatformState::X86::GPReg32Names = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }; const std::array PlatformState::X86::GPReg16Names = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }; const std::array PlatformState::X86::GPReg8LNames = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }; const std::array PlatformState::X86::GPReg8HNames = { "ah", "ch", "dh", "bh" }; const std::array PlatformState::X86::segRegNames = { "es", "cs", "ss", "ds", "fs", "gs" }; void PlatformState::fillFrom(const UserRegsStructX86 ®s) { // Don't touch higher parts to avoid zeroing out bad value mark std::memcpy(&x86.GPRegs[X86::EAX], ®s.eax, sizeof(regs.eax)); std::memcpy(&x86.GPRegs[X86::ECX], ®s.ecx, sizeof(regs.ecx)); std::memcpy(&x86.GPRegs[X86::EDX], ®s.edx, sizeof(regs.edx)); std::memcpy(&x86.GPRegs[X86::EBX], ®s.ebx, sizeof(regs.ebx)); std::memcpy(&x86.GPRegs[X86::ESP], ®s.esp, sizeof(regs.esp)); std::memcpy(&x86.GPRegs[X86::EBP], ®s.ebp, sizeof(regs.ebp)); std::memcpy(&x86.GPRegs[X86::ESI], ®s.esi, sizeof(regs.esi)); std::memcpy(&x86.GPRegs[X86::EDI], ®s.edi, sizeof(regs.edi)); std::memcpy(&x86.orig_ax, ®s.orig_eax, sizeof(regs.orig_eax)); std::memcpy(&x86.flags, ®s.eflags, sizeof(regs.eflags)); std::memcpy(&x86.IP, ®s.eip, sizeof(regs.eip)); x86.segRegs[X86::ES] = regs.xes; x86.segRegs[X86::CS] = regs.xcs; x86.segRegs[X86::SS] = regs.xss; x86.segRegs[X86::DS] = regs.xds; x86.segRegs[X86::FS] = regs.xfs; x86.segRegs[X86::GS] = regs.xgs; x86.gpr32Filled = true; } size_t PlatformState::X87::stackPointer() const { return (statusWord & 0x3800) >> 11; } size_t PlatformState::X87::RIndexToSTIndex(size_t n) const { n = (n + 8 - stackPointer()) % 8; return n; } size_t PlatformState::X87::STIndexToRIndex(size_t n) const { n = (n + stackPointer()) % 8; return n; } int PlatformState::X87::recreateTag(edb::value80 value) const { switch (floatType(value)) { case FloatValueClass::Zero: return TAG_ZERO; case FloatValueClass::Normal: return TAG_VALID; default: return TAG_SPECIAL; } } edb::value80 PlatformState::X87::st(size_t n) const { return R[STIndexToRIndex(n)]; } edb::value80 &PlatformState::X87::st(size_t n) { return R[STIndexToRIndex(n)]; } int PlatformState::X87::makeTag(size_t n, uint16_t twd) const { int minitag = (twd >> n) & 0x1; return minitag ? recreateTag(R[n]) : TAG_EMPTY; } int PlatformState::X87::tag(size_t n) const { return (tagWord >> (2 * n)) & 0x3; } edb::value16 PlatformState::X87::restoreTagWord(uint16_t twd) const { uint16_t tagWord = 0; for (size_t n = 0; n < MAX_FPU_REG_COUNT; ++n) { tagWord |= makeTag(n, twd) << (2 * n); } return edb::value16(tagWord); } std::uint16_t PlatformState::X87::reducedTagWord() const { // Algorithm is the same as in linux/arch/x86/kernel/i387.c: twd_i387_to_fxsr() // Transforming each pair of bits into 01 (valid) or 00 (empty) unsigned int result = ~tagWord; result = (result | (result >> 1)) & 0x5555; // 0102030405060708 // moving the valid bits to the lower byte result = (result | (result >> 1)) & 0x3333; // 0012003400560078 result = (result | (result >> 2)) & 0x0f0f; // 0000123400005678 result = (result | (result >> 4)) & 0x00ff; // 0000000012345678 return result; } void PlatformState::fillFrom(const UserFPRegsStructX86 ®s) { x87.statusWord = regs.swd; // should be first for RIndexToSTIndex() to work for (size_t n = 0; n < MAX_FPU_REG_COUNT; ++n) { x87.R[n] = edb::value80(regs.st_space, 10 * x87.RIndexToSTIndex(n)); } x87.controlWord = regs.cwd; x87.tagWord = regs.twd; // This is the true tag word, unlike in FPX regs and x86-64 FP regs structs x87.instPtrOffset = edb::address_t::fromZeroExtended(regs.fip); x87.dataPtrOffset = edb::address_t::fromZeroExtended(regs.foo); x87.instPtrSelector = regs.fcs; x87.dataPtrSelector = regs.fos; x87.opCode = 0; // not present in the given structure x87.filled = true; } void PlatformState::fillFrom(const UserFPXRegsStructX86 ®s) { x87.statusWord = regs.swd; // should be first for RIndexToSTIndex() to work for (size_t n = 0; n < MAX_FPU_REG_COUNT; ++n) { x87.R[n] = edb::value80(regs.st_space, 16 * x87.RIndexToSTIndex(n)); } x87.controlWord = regs.cwd; x87.tagWord = x87.restoreTagWord(regs.twd); x87.instPtrOffset = edb::address_t::fromZeroExtended(regs.fip); x87.dataPtrOffset = edb::address_t::fromZeroExtended(regs.foo); x87.instPtrSelector = regs.fcs; x87.dataPtrSelector = regs.fos; x87.opCode = regs.fop; x87.filled = true; x87.opCodeFilled = true; for (size_t n = 0; n < IA32_XMM_REG_COUNT; ++n) { avx.setXMM(n, edb::value128(regs.xmm_space, 16 * n)); } avx.mxcsr = regs.mxcsr; avx.xmmFilledIA32 = true; } void PlatformState::fillFrom(const UserRegsStructX86_64 ®s) { // On 32 bit OS this code would access beyond the length of the array, but it won't ever execute there assert(x86.GPRegs.size() == 16); x86.GPRegs[X86::RAX] = regs.rax; x86.GPRegs[X86::RCX] = regs.rcx; x86.GPRegs[X86::RDX] = regs.rdx; x86.GPRegs[X86::RBX] = regs.rbx; x86.GPRegs[X86::RSP] = regs.rsp; x86.GPRegs[X86::RBP] = regs.rbp; x86.GPRegs[X86::RSI] = regs.rsi; x86.GPRegs[X86::RDI] = regs.rdi; x86.GPRegs[X86::R8] = regs.r8; x86.GPRegs[X86::R9] = regs.r9; x86.GPRegs[X86::R10] = regs.r10; x86.GPRegs[X86::R11] = regs.r11; x86.GPRegs[X86::R12] = regs.r12; x86.GPRegs[X86::R13] = regs.r13; x86.GPRegs[X86::R14] = regs.r14; x86.GPRegs[X86::R15] = regs.r15; x86.orig_ax = regs.orig_rax; x86.flags = regs.eflags; x86.IP = regs.rip; x86.segRegs[X86::ES] = regs.es; x86.segRegs[X86::CS] = regs.cs; x86.segRegs[X86::SS] = regs.ss; x86.segRegs[X86::DS] = regs.ds; x86.segRegs[X86::FS] = regs.fs; x86.segRegs[X86::GS] = regs.gs; x86.gpr32Filled = true; x86.gpr64Filled = true; if (is64Bit()) { // 32-bit processes get always zeros here, which may be wrong or meaningless if (x86.segRegs[X86::FS] == 0) { x86.segRegBases[X86::FS] = regs.fs_base; x86.segRegBasesFilled[X86::FS] = true; } if (x86.segRegs[X86::GS] == 0) { x86.segRegBases[X86::GS] = regs.gs_base; x86.segRegBasesFilled[X86::GS] = true; } } } void PlatformState::fillFrom(const UserFPRegsStructX86_64 ®s) { x87.statusWord = regs.swd; // should be first for RIndexToSTIndex() to work for (size_t n = 0; n < MAX_FPU_REG_COUNT; ++n) { x87.R[n] = edb::value80(regs.st_space, 16 * x87.RIndexToSTIndex(n)); } x87.controlWord = regs.cwd; x87.tagWord = x87.restoreTagWord(regs.ftw); x87.instPtrOffset = regs.rip; x87.dataPtrOffset = regs.rdp; x87.instPtrSelector = 0; x87.dataPtrSelector = 0; x87.opCode = regs.fop; x87.filled = true; x87.opCodeFilled = true; for (size_t n = 0; n < MAX_XMM_REG_COUNT; ++n) { avx.setXMM(n, edb::value128(regs.xmm_space, 16 * n)); } avx.mxcsr = regs.mxcsr; avx.mxcsrMask = regs.mxcr_mask; avx.mxcsrMaskFilled = true; avx.xmmFilledIA32 = true; avx.xmmFilledAMD64 = true; } void PlatformState::fillFrom(const PrStatus_X86 ®s) { // Don't touch higher parts to avoid zeroing out bad value mark std::memcpy(&x86.GPRegs[X86::EAX], ®s.eax, sizeof(regs.eax)); std::memcpy(&x86.GPRegs[X86::ECX], ®s.ecx, sizeof(regs.ecx)); std::memcpy(&x86.GPRegs[X86::EDX], ®s.edx, sizeof(regs.edx)); std::memcpy(&x86.GPRegs[X86::EBX], ®s.ebx, sizeof(regs.ebx)); std::memcpy(&x86.GPRegs[X86::ESP], ®s.esp, sizeof(regs.esp)); std::memcpy(&x86.GPRegs[X86::EBP], ®s.ebp, sizeof(regs.ebp)); std::memcpy(&x86.GPRegs[X86::ESI], ®s.esi, sizeof(regs.esi)); std::memcpy(&x86.GPRegs[X86::EDI], ®s.edi, sizeof(regs.edi)); std::memcpy(&x86.orig_ax, ®s.orig_eax, sizeof(regs.orig_eax)); std::memcpy(&x86.flags, ®s.eflags, sizeof(regs.eflags)); std::memcpy(&x86.IP, ®s.eip, sizeof(regs.eip)); x86.segRegs[X86::ES] = regs.es; x86.segRegs[X86::CS] = regs.cs; x86.segRegs[X86::SS] = regs.ss; x86.segRegs[X86::DS] = regs.ds; x86.segRegs[X86::FS] = regs.fs; x86.segRegs[X86::GS] = regs.gs; x86.gpr32Filled = true; } void PlatformState::fillFrom(const PrStatus_X86_64 ®s) { x86.GPRegs[X86::RAX] = regs.rax; x86.GPRegs[X86::RCX] = regs.rcx; x86.GPRegs[X86::RDX] = regs.rdx; x86.GPRegs[X86::RBX] = regs.rbx; x86.GPRegs[X86::RSP] = regs.rsp; x86.GPRegs[X86::RBP] = regs.rbp; x86.GPRegs[X86::RSI] = regs.rsi; x86.GPRegs[X86::RDI] = regs.rdi; x86.GPRegs[X86::R8] = regs.r8; x86.GPRegs[X86::R9] = regs.r9; x86.GPRegs[X86::R10] = regs.r10; x86.GPRegs[X86::R11] = regs.r11; x86.GPRegs[X86::R12] = regs.r12; x86.GPRegs[X86::R13] = regs.r13; x86.GPRegs[X86::R14] = regs.r14; x86.GPRegs[X86::R15] = regs.r15; x86.orig_ax = regs.orig_rax; x86.flags = regs.rflags; x86.IP = regs.rip; x86.segRegs[X86::ES] = regs.es; x86.segRegs[X86::CS] = regs.cs; x86.segRegs[X86::SS] = regs.ss; x86.segRegs[X86::DS] = regs.ds; x86.segRegs[X86::FS] = regs.fs; x86.segRegs[X86::GS] = regs.gs; x86.gpr32Filled = true; x86.gpr64Filled = true; x86.segRegBases[X86::FS] = regs.fs_base; x86.segRegBasesFilled[X86::FS] = true; x86.segRegBases[X86::GS] = regs.gs_base; x86.segRegBasesFilled[X86::GS] = true; } bool PlatformState::fillFrom(const X86XState ®s, size_t sizeFromKernel) { if (sizeFromKernel < X86XState::XSAVE_NONEXTENDED_SIZE) { // Shouldn't ever happen. XSAVE area must at least have an XSAVE header. qDebug() << "Size of X86_XSTATE returned from the kernel appears less than expected: " << sizeFromKernel; return false; } avx.xcr0 = regs.xcr0; bool statePresentX87 = regs.xstate_bv & X86XState::FEATURE_X87; bool statePresentSSE = regs.xstate_bv & X86XState::FEATURE_SSE; bool statePresentAVX = regs.xstate_bv & X86XState::FEATURE_AVX; // Due to the lazy saving the feature bits may be unset in XSTATE_BV if the app // has not touched the corresponding registers yet. But once the registers are // touched, they are initialized to zero by the OS (not control/tag ones). To the app // it looks as if the registers have always been zero. Thus we should provide the same // illusion to the user. if (statePresentX87) { x87.statusWord = regs.swd; // should be first for RIndexToSTIndex() to work for (size_t n = 0; n < MAX_FPU_REG_COUNT; ++n) { x87.R[n] = edb::value80(regs.st_space, 16 * x87.RIndexToSTIndex(n)); } x87.controlWord = regs.cwd; x87.tagWord = x87.restoreTagWord(regs.twd); x87.instPtrOffset = regs.fioff; x87.dataPtrOffset = regs.fooff; if (is64Bit()) { std::memcpy(reinterpret_cast(&x87.instPtrOffset) + 4, ®s.fiseg, sizeof regs.fiseg); std::memcpy(reinterpret_cast(&x87.dataPtrOffset) + 4, ®s.foseg, sizeof regs.foseg); x87.instPtrSelector = 0; x87.dataPtrSelector = 0; } else { x87.instPtrSelector = regs.fiseg; x87.dataPtrSelector = regs.foseg; } x87.opCode = regs.fop; x87.filled = true; x87.opCodeFilled = true; } else { std::memset(&x87, 0, sizeof x87); x87.controlWord = regs.cwd; // this appears always present x87.tagWord = 0xffff; x87.filled = true; x87.opCodeFilled = true; } if (statePresentAVX) { for (size_t n = 0; n < MAX_YMM_REG_COUNT; ++n) { avx.setYMM(n, edb::value128(regs.xmm_space, 16 * n), edb::value128(regs.ymmh_space, 16 * n)); } avx.mxcsr = regs.mxcsr; avx.mxcsrMask = regs.mxcsr_mask; avx.mxcsrMaskFilled = true; avx.xmmFilledIA32 = true; avx.xmmFilledAMD64 = true; avx.ymmFilled = true; } else if (statePresentSSE) { // If AVX state management has been enabled by the OS, // the state may be not present due to lazy saving, // so initialize the space with zeros if (avx.xcr0 & X86XState::FEATURE_AVX) { for (size_t n = 0; n < MAX_YMM_REG_COUNT; ++n) { avx.setYMM(n, edb::value256::fromZeroExtended(0)); } avx.ymmFilled = true; } // Now we can fill in the XMM registers for (size_t n = 0; n < MAX_XMM_REG_COUNT; ++n) { avx.setXMM(n, edb::value128(regs.xmm_space, 16 * n)); } avx.mxcsr = regs.mxcsr; avx.mxcsrMask = regs.mxcsr_mask; avx.mxcsrMaskFilled = true; avx.xmmFilledIA32 = true; avx.xmmFilledAMD64 = true; } else { avx.mxcsr = regs.mxcsr; avx.mxcsrMask = regs.mxcsr_mask; avx.mxcsrMaskFilled = true; // Only fill the registers which are actually supported, leave invalidity marks intact for other parts if (avx.xcr0 & X86XState::FEATURE_AVX) { // If AVX state management has been enabled by the OS for (size_t n = 0; n < MAX_YMM_REG_COUNT; ++n) { avx.setYMM(n, edb::value256::fromZeroExtended(0)); } avx.xmmFilledIA32 = true; avx.xmmFilledAMD64 = true; avx.ymmFilled = true; } else if (avx.xcr0 & X86XState::FEATURE_SSE) { // If SSE state management has been enabled by the OS for (size_t n = 0; n < MAX_YMM_REG_COUNT; ++n) { avx.setYMM(n, edb::value256::fromZeroExtended(0)); } avx.xmmFilledIA32 = true; avx.xmmFilledAMD64 = true; } } return true; } void PlatformState::fillStruct(UserRegsStructX86 ®s) const { util::markMemory(®s, sizeof(regs)); if (x86.gpr32Filled) { regs.eax = x86.GPRegs[X86::EAX]; regs.ecx = x86.GPRegs[X86::ECX]; regs.edx = x86.GPRegs[X86::EDX]; regs.ebx = x86.GPRegs[X86::EBX]; regs.esp = x86.GPRegs[X86::ESP]; regs.ebp = x86.GPRegs[X86::EBP]; regs.esi = x86.GPRegs[X86::ESI]; regs.edi = x86.GPRegs[X86::EDI]; regs.xes = x86.segRegs[X86::ES]; regs.xcs = x86.segRegs[X86::CS]; regs.xss = x86.segRegs[X86::SS]; regs.xds = x86.segRegs[X86::DS]; regs.xfs = x86.segRegs[X86::FS]; regs.xgs = x86.segRegs[X86::GS]; regs.orig_eax = x86.orig_ax; regs.eflags = x86.flags; regs.eip = x86.IP; } } void PlatformState::fillStruct(UserRegsStructX86_64 ®s) const { // If 64-bit part is not filled in state, we'll set marked values if (x86.gpr64Filled || x86.gpr32Filled) { regs.rax = x86.GPRegs[X86::RAX]; regs.rcx = x86.GPRegs[X86::RCX]; regs.rdx = x86.GPRegs[X86::RDX]; regs.rbx = x86.GPRegs[X86::RBX]; regs.rsp = x86.GPRegs[X86::RSP]; regs.rbp = x86.GPRegs[X86::RBP]; regs.rsi = x86.GPRegs[X86::RSI]; regs.rdi = x86.GPRegs[X86::RDI]; regs.r8 = x86.GPRegs[X86::R8]; regs.r9 = x86.GPRegs[X86::R9]; regs.r10 = x86.GPRegs[X86::R10]; regs.r11 = x86.GPRegs[X86::R11]; regs.r12 = x86.GPRegs[X86::R12]; regs.r13 = x86.GPRegs[X86::R13]; regs.r14 = x86.GPRegs[X86::R14]; regs.r15 = x86.GPRegs[X86::R15]; regs.es = x86.segRegs[X86::ES]; regs.cs = x86.segRegs[X86::CS]; regs.ss = x86.segRegs[X86::SS]; regs.ds = x86.segRegs[X86::DS]; regs.fs = x86.segRegs[X86::FS]; regs.gs = x86.segRegs[X86::GS]; regs.fs_base = x86.segRegBases[X86::FS]; regs.gs_base = x86.segRegBases[X86::GS]; regs.orig_rax = x86.orig_ax; regs.eflags = x86.flags; regs.rip = x86.IP; } } void PlatformState::fillStruct(PrStatus_X86_64 ®s) const { // If 64-bit part is not filled in state, we'll set marked values if (x86.gpr64Filled || x86.gpr32Filled) { regs.rax = x86.GPRegs[X86::RAX]; regs.rcx = x86.GPRegs[X86::RCX]; regs.rdx = x86.GPRegs[X86::RDX]; regs.rbx = x86.GPRegs[X86::RBX]; regs.rsp = x86.GPRegs[X86::RSP]; regs.rbp = x86.GPRegs[X86::RBP]; regs.rsi = x86.GPRegs[X86::RSI]; regs.rdi = x86.GPRegs[X86::RDI]; regs.r8 = x86.GPRegs[X86::R8]; regs.r9 = x86.GPRegs[X86::R9]; regs.r10 = x86.GPRegs[X86::R10]; regs.r11 = x86.GPRegs[X86::R11]; regs.r12 = x86.GPRegs[X86::R12]; regs.r13 = x86.GPRegs[X86::R13]; regs.r14 = x86.GPRegs[X86::R14]; regs.r15 = x86.GPRegs[X86::R15]; regs.orig_rax = x86.orig_ax; regs.rflags = x86.flags; regs.rip = x86.IP; regs.es = x86.segRegs[X86::ES]; regs.cs = x86.segRegs[X86::CS]; regs.ss = x86.segRegs[X86::SS]; regs.ds = x86.segRegs[X86::DS]; regs.fs = x86.segRegs[X86::FS]; regs.gs = x86.segRegs[X86::GS]; regs.fs_base = x86.segRegBases[X86::FS]; regs.gs_base = x86.segRegBases[X86::GS]; } } void PlatformState::fillStruct(UserFPRegsStructX86 ®s) const { util::markMemory(®s, sizeof(regs)); if (x87.filled) { regs.swd = x87.statusWord; regs.cwd = x87.controlWord; regs.twd = x87.tagWord; regs.fip = x87.instPtrOffset; regs.foo = x87.dataPtrOffset; regs.fcs = x87.instPtrSelector; regs.fos = x87.dataPtrSelector; for (size_t n = 0; n < MAX_FPU_REG_COUNT; ++n) { std::memcpy(reinterpret_cast(regs.st_space) + 10 * x87.RIndexToSTIndex(n), &x87.R[n], sizeof(x87.R[n])); } } } void PlatformState::fillStruct(UserFPRegsStructX86_64 ®s) const { util::markMemory(®s, sizeof(regs)); if (x87.filled) { regs.swd = x87.statusWord; regs.cwd = x87.controlWord; regs.ftw = x87.reducedTagWord(); regs.rip = x87.instPtrOffset; regs.rdp = x87.dataPtrOffset; if (x87.opCodeFilled) { regs.fop = x87.opCode; } for (size_t n = 0; n < MAX_FPU_REG_COUNT; ++n) { std::memcpy(reinterpret_cast(regs.st_space) + 16 * x87.RIndexToSTIndex(n), &x87.R[n], sizeof(x87.R[n])); } if (avx.xmmFilledIA32 || avx.xmmFilledAMD64) { for (size_t n = 0; n < MAX_XMM_REG_COUNT; ++n) { std::memcpy(reinterpret_cast(regs.xmm_space) + 16 * n, &avx.zmmStorage[n], sizeof(edb::value128)); } regs.mxcsr = avx.mxcsr; } if (avx.mxcsrMaskFilled) { regs.mxcr_mask = avx.mxcsrMask; } } } void PlatformState::fillStruct(UserFPXRegsStructX86 ®s) const { util::markMemory(®s, sizeof regs); if (x87.filled) { regs.swd = x87.statusWord; regs.twd = x87.reducedTagWord(); regs.cwd = x87.controlWord; regs.fip = x87.instPtrOffset; regs.foo = x87.dataPtrOffset; regs.fcs = x87.instPtrSelector; regs.fos = x87.dataPtrSelector; regs.fop = x87.opCode; for (size_t n = 0; n < MAX_FPU_REG_COUNT; ++n) { std::memcpy(reinterpret_cast(®s.st_space) + 16 * x87.RIndexToSTIndex(n), &x87.R[n], sizeof x87.R[n]); } } if (avx.xmmFilledIA32) { regs.mxcsr = avx.mxcsr; for (size_t n = 0; n < IA32_XMM_REG_COUNT; ++n) { std::memcpy(reinterpret_cast(®s.xmm_space) + 16 * n, &avx.zmmStorage[n], sizeof(edb::value128)); } } } size_t PlatformState::fillStruct(X86XState ®s) const { util::markMemory(®s, sizeof regs); // Zero out reserved bytes; set xstate_bv to 0 std::memset(regs.xstate_hdr_bytes, 0, sizeof regs.xstate_hdr_bytes); regs.xcr0 = avx.xcr0; if (x87.filled) { regs.swd = x87.statusWord; regs.cwd = x87.controlWord; regs.twd = x87.reducedTagWord(); regs.fioff = x87.instPtrOffset; regs.fooff = x87.dataPtrOffset; if (is64Bit()) { std::memcpy(®s.fiseg, reinterpret_cast(&x87.instPtrOffset) + 4, 4); std::memcpy(®s.foseg, reinterpret_cast(&x87.dataPtrOffset) + 4, 4); } else { regs.fiseg = x87.instPtrSelector; regs.foseg = x87.dataPtrSelector; } regs.fop = x87.opCode; for (size_t n = 0; n < MAX_FPU_REG_COUNT; ++n) { std::memcpy(reinterpret_cast(®s.st_space) + 16 * x87.RIndexToSTIndex(n), &x87.R[n], sizeof x87.R[n]); } regs.xstate_bv |= X86XState::FEATURE_X87; } if (avx.xmmFilledIA32) { const auto nMax = avx.xmmFilledAMD64 ? AMD64_XMM_REG_COUNT : IA32_XMM_REG_COUNT; for (size_t n = 0; n < nMax; ++n) { std::memcpy(reinterpret_cast(®s.xmm_space) + 16 * n, &avx.zmmStorage[n], sizeof(edb::value128)); } regs.mxcsr = avx.mxcsr; regs.mxcsr_mask = avx.mxcsrMask; regs.xstate_bv |= X86XState::FEATURE_SSE; } if (avx.ymmFilled) { // In this case SSE state is already filled by the code writing XMMx&MXCSR registers for (size_t n = 0; n < MAX_YMM_REG_COUNT; ++n) { std::memcpy(reinterpret_cast(®s.ymmh_space) + 16 * n, reinterpret_cast(&avx.zmmStorage[n]) + sizeof(edb::value128), sizeof(edb::value128)); } regs.xstate_bv |= X86XState::FEATURE_AVX; } size_t size; if (regs.xstate_bv & X86XState::FEATURE_AVX) { size = X86XState::AVX_SIZE; } else if (regs.xstate_bv & (X86XState::FEATURE_X87 | X86XState::FEATURE_SSE)) { size = X86XState::SSE_SIZE; // minimum size: legacy state + xsave header } else { size = 0; } return size; } edb::value128 PlatformState::AVX::xmm(size_t index) const { return edb::value128(zmmStorage[index]); } edb::value256 PlatformState::AVX::ymm(size_t index) const { return edb::value256(zmmStorage[index]); } edb::value512 PlatformState::AVX::zmm(size_t index) const { return zmmStorage[index]; } void PlatformState::AVX::setXMM(size_t index, edb::value128 value) { // leave upper part unchanged. std::memcpy(&zmmStorage[index], &value, sizeof value); } void PlatformState::AVX::setYMM(size_t index, edb::value128 low, edb::value128 high) { // leave upper part unchanged. std::memcpy(reinterpret_cast(&zmmStorage[index]) + 0, &low, sizeof(low)); std::memcpy(reinterpret_cast(&zmmStorage[index]) + 16, &high, sizeof(high)); } void PlatformState::AVX::setYMM(size_t index, edb::value256 value) { // leave upper part unchanged. std::memcpy(&zmmStorage[index], &value, sizeof(value)); } void PlatformState::AVX::setZMM(size_t index, edb::value512 value) { zmmStorage[index] = value; } void PlatformState::X86::clear() { util::markMemory(this, sizeof(*this)); gpr32Filled = false; gpr64Filled = false; for (auto &base : segRegBasesFilled) { base = false; } } bool PlatformState::X86::empty() const { return !gpr32Filled; } void PlatformState::X87::clear() { util::markMemory(this, sizeof(*this)); filled = false; opCodeFilled = false; } bool PlatformState::X87::empty() const { return !filled; } void PlatformState::AVX::clear() { util::markMemory(this, sizeof(*this)); xmmFilledIA32 = false; xmmFilledAMD64 = false; ymmFilled = false; zmmFilled = false; } bool PlatformState::AVX::empty() const { return !xmmFilledIA32; } //------------------------------------------------------------------------------ // Name: PlatformState // Desc: //------------------------------------------------------------------------------ PlatformState::PlatformState() { clear(); } //------------------------------------------------------------------------------ // Name: PlatformState::clone // Desc: makes a copy of the state object //------------------------------------------------------------------------------ IState *PlatformState::clone() const { return new PlatformState(*this); } //------------------------------------------------------------------------------ // Name: flags_to_string // Desc: returns the flags in a string form appropriate for this platform //------------------------------------------------------------------------------ QString PlatformState::flags_to_string(edb::reg_t flags) const { char buf[32]; qsnprintf(buf, sizeof(buf), "%c %c %c %c %c %c %c %c %c", ((flags & 0x001) ? 'C' : 'c'), ((flags & 0x004) ? 'P' : 'p'), ((flags & 0x010) ? 'A' : 'a'), ((flags & 0x040) ? 'Z' : 'z'), ((flags & 0x080) ? 'S' : 's'), ((flags & 0x100) ? 'T' : 't'), ((flags & 0x200) ? 'I' : 'i'), ((flags & 0x400) ? 'D' : 'd'), ((flags & 0x800) ? 'O' : 'o')); return buf; } //------------------------------------------------------------------------------ // Name: flags_to_string // Desc: returns the flags in a string form appropriate for this platform //------------------------------------------------------------------------------ QString PlatformState::flags_to_string() const { return flags_to_string(flags()); } template Register findRegisterValue(const Names &names, const Regs ®s, const QString ®Name, Register::Type type, size_t maxNames, int shift = 0) { const auto end = names.begin() + maxNames; auto regNameFoundIter = std::find(names.begin(), end, regName); if (regNameFoundIter != end) { return make_Register(regName, regs[regNameFoundIter - names.begin()] >> shift, type); } else { return Register(); } } //------------------------------------------------------------------------------ // Name: value // Desc: returns a Register object which represents the register with the name // supplied //------------------------------------------------------------------------------ Register PlatformState::value(const QString ®) const { const QString regName = reg.toLower(); // TODO: make use of string_hash and switch-case construct to make things easier to understand // All register names are always less than 9 chars in length, so string_hash would work. Register found; // don't return valid Register with garbage value if (x86.gpr32Filled) { if (reg == x86.origRAXName && x86.gpr64Filled && is64Bit()) return make_Register<64>(x86.origRAXName, x86.orig_ax, Register::TYPE_GPR); if (reg == x86.origEAXName) return make_Register<32>(x86.origEAXName, x86.orig_ax, Register::TYPE_GPR); if (x86.gpr64Filled && is64Bit() && !!(found = findRegisterValue(x86.GPReg64Names, x86.GPRegs, regName, Register::TYPE_GPR, gpr64_count()))) return found; if (!!(found = findRegisterValue<32>(x86.GPReg32Names, x86.GPRegs, regName, Register::TYPE_GPR, gpr_count()))) return found; if (!!(found = findRegisterValue<16>(x86.GPReg16Names, x86.GPRegs, regName, Register::TYPE_GPR, gpr_count()))) return found; if (!!(found = findRegisterValue<8>(x86.GPReg8LNames, x86.GPRegs, regName, Register::TYPE_GPR, gpr_low_addressable_count()))) return found; if (!!(found = findRegisterValue<8>(x86.GPReg8HNames, x86.GPRegs, regName, Register::TYPE_GPR, gpr_high_addressable_count(), 8))) return found; if (!!(found = findRegisterValue(x86.segRegNames, x86.segRegs, regName, Register::TYPE_SEG, seg_reg_count()))) return found; if (regName.mid(1) == "s_base") { const QString segRegName = regName.mid(0, 2); const auto end = x86.segRegNames.end(); const auto regNameFoundIter = std::find(x86.segRegNames.begin(), end, segRegName); if (regNameFoundIter != end) { const size_t index = regNameFoundIter - x86.segRegNames.begin(); if (!x86.segRegBasesFilled[index]) { return Register(); } const auto value = x86.segRegBases[index]; if (is64Bit()) { return make_Register(regName, value, Register::TYPE_SEG); } else { return make_Register<32>(regName, value, Register::TYPE_SEG); } } } if (is64Bit() && regName == x86.flags64Name) return make_Register(x86.flags64Name, x86.flags, Register::TYPE_COND); if (regName == x86.flags32Name) return make_Register<32>(x86.flags32Name, x86.flags, Register::TYPE_COND); if (regName == x86.flags16Name) return make_Register<16>(x86.flags16Name, x86.flags, Register::TYPE_COND); if (is64Bit() && regName == x86.IP64Name) return make_Register(x86.IP64Name, x86.IP, Register::TYPE_IP); if (regName == x86.IP32Name) return make_Register<32>(x86.IP32Name, x86.IP, Register::TYPE_IP); if (regName == x86.IP16Name) return make_Register<16>(x86.IP16Name, x86.IP, Register::TYPE_IP); } if (x86.gpr32Filled) { QRegExp DRx("^dr([0-7])$"); if (DRx.indexIn(regName) != -1) { QChar digit = DRx.cap(1).at(0); assert(digit.isDigit()); char digitChar = digit.toLatin1(); size_t i = digitChar - '0'; assert(dbgIndexValid(i)); if (is64Bit() && x86.gpr64Filled) { return make_Register(regName, x86.dbgRegs[i], Register::TYPE_COND); } else { return make_Register<32>(regName, x86.dbgRegs[i], Register::TYPE_COND); } } } if (x87.filled) { QRegExp Rx("^r([0-7])$"); if (Rx.indexIn(regName) != -1) { QChar digit = Rx.cap(1).at(0); assert(digit.isDigit()); char digitChar = digit.toLatin1(); size_t i = digitChar - '0'; assert(fpuIndexValid(i)); return make_Register(regName, x87.R[i], Register::TYPE_FPU); } } if (x87.filled) { QRegExp STx("^st\\(?([0-7])\\)?$"); if (STx.indexIn(regName) != -1) { QChar digit = STx.cap(1).at(0); assert(digit.isDigit()); char digitChar = digit.toLatin1(); size_t i = digitChar - '0'; assert(fpuIndexValid(i)); return make_Register(regName, x87.st(i), Register::TYPE_FPU); } } if (x87.filled) { if (regName == "fip" || regName == "fdp") { const edb::address_t addr = regName == "fip" ? x87.instPtrOffset : x87.dataPtrOffset; if (is64Bit()) { return make_Register<64>(regName, addr, Register::TYPE_FPU); } else { return make_Register<32>(regName, addr, Register::TYPE_FPU); } } if (regName == "fis" || regName == "fds") { const edb::value16 val = regName == "fis" ? x87.instPtrSelector : x87.dataPtrSelector; return make_Register<16>(regName, val, Register::TYPE_FPU); } if (regName == "fopcode" || regName == "fop") { return make_Register<16>(regName, x87.opCode, Register::TYPE_FPU); } if (regName == "ftr" || regName == "ftw") { return make_Register<16>(regName, x87.tagWord, Register::TYPE_FPU); } if (regName == "fsr" || regName == "fsw") { return make_Register<16>(regName, x87.statusWord, Register::TYPE_FPU); } if (regName == "fcr" || regName == "fcw") { return make_Register<16>(regName, x87.controlWord, Register::TYPE_FPU); } } if (x87.filled) { QRegExp MMx("^mm([0-7])$"); if (MMx.indexIn(regName) != -1) { QChar digit = MMx.cap(1).at(0); assert(digit.isDigit()); char digitChar = digit.toLatin1(); size_t i = digitChar - '0'; assert(mmxIndexValid(i)); return make_Register(regName, x87.R[i].mantissa(), Register::TYPE_SIMD); } } if (avx.xmmFilledIA32) { QRegExp XMMx("^xmm([0-9]|1[0-5])$"); if (XMMx.indexIn(regName) != -1) { bool ok = false; size_t i = XMMx.cap(1).toUShort(&ok); assert(ok); if (i >= IA32_XMM_REG_COUNT && !avx.xmmFilledAMD64) { return Register(); } if (xmmIndexValid(i)) { // May be invalid but legitimate for a disassembler: e.g. XMM13 but 32 bit mode return make_Register(regName, avx.xmm(i), Register::TYPE_SIMD); } } } if (avx.ymmFilled) { QRegExp YMMx("^ymm([0-9]|1[0-5])$"); if (YMMx.indexIn(regName) != -1) { bool ok = false; size_t i = YMMx.cap(1).toUShort(&ok); assert(ok); if (ymmIndexValid(i)) { // May be invalid but legitimate for a disassembler: e.g. YMM13 but 32 bit mode return make_Register(regName, avx.ymm(i), Register::TYPE_SIMD); } } } if (avx.xmmFilledIA32 && regName == avx.mxcsrName) { return make_Register(avx.mxcsrName, avx.mxcsr, Register::TYPE_COND); } return Register(); } //------------------------------------------------------------------------------ // Name: instruction_pointer_register // Desc: //------------------------------------------------------------------------------ Register PlatformState::instruction_pointer_register() const { if (x86.gpr64Filled && is64Bit()) { return make_Register(x86.IP64Name, x86.IP, Register::TYPE_GPR); } else if (x86.gpr32Filled) { return make_Register<32>(x86.IP32Name, x86.IP, Register::TYPE_GPR); } return Register(); } //------------------------------------------------------------------------------ // Name: frame_pointer // Desc: returns what is conceptually the frame pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::frame_pointer() const { return gp_register(X86::RBP).valueAsAddress(); } //------------------------------------------------------------------------------ // Name: instruction_pointer // Desc: returns the instruction pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::instruction_pointer() const { return instruction_pointer_register().valueAsAddress(); } //------------------------------------------------------------------------------ // Name: stack_pointer // Desc: returns the stack pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::stack_pointer() const { return gp_register(X86::RSP).valueAsAddress(); } //------------------------------------------------------------------------------ // Name: debug_register // Desc: //------------------------------------------------------------------------------ edb::reg_t PlatformState::debug_register(size_t n) const { assert(dbgIndexValid(n)); return x86.dbgRegs[n]; } //------------------------------------------------------------------------------ // Name: flags_register // Desc: //------------------------------------------------------------------------------ Register PlatformState::flags_register() const { if (x86.gpr64Filled && is64Bit()) { return make_Register(x86.flags64Name, x86.flags, Register::TYPE_GPR); } else if (x86.gpr32Filled) { return make_Register<32>(x86.flags32Name, x86.flags, Register::TYPE_GPR); } return Register(); } //------------------------------------------------------------------------------ // Name: flags // Desc: //------------------------------------------------------------------------------ edb::reg_t PlatformState::flags() const { return flags_register().valueAsInteger(); } //------------------------------------------------------------------------------ // Name: fpu_stack_pointer // Desc: //------------------------------------------------------------------------------ int PlatformState::fpu_stack_pointer() const { return x87.stackPointer(); } //------------------------------------------------------------------------------ // Name: fpu_register // Desc: //------------------------------------------------------------------------------ edb::value80 PlatformState::fpu_register(size_t n) const { assert(fpuIndexValid(n)); if (!x87.filled) { edb::value80 v; const std::uint64_t mant = 0x0badbad1bad1bad1; const std::uint16_t exp = 0x0bad; std::memcpy(&v, &mant, sizeof mant); std::memcpy(reinterpret_cast(&v) + sizeof mant, &exp, sizeof exp); return v; } return x87.R[n]; } //------------------------------------------------------------------------------ // Name: fpu_register_is_empty // Desc: Returns true if Rn register is empty when treated in terms of FPU stack //------------------------------------------------------------------------------ bool PlatformState::fpu_register_is_empty(size_t n) const { return x87.tag(n) == X87::TAG_EMPTY; } //------------------------------------------------------------------------------ // Name: fpu_register_tag_string // Desc: //------------------------------------------------------------------------------ QString PlatformState::fpu_register_tag_string(size_t n) const { int tag = x87.tag(n); static const std::unordered_map names{ {X87::TAG_VALID, "Valid"}, {X87::TAG_ZERO, "Zero"}, {X87::TAG_SPECIAL, "Special"}, {X87::TAG_EMPTY, "Empty"} }; return names.at(tag); } edb::value16 PlatformState::fpu_control_word() const { return x87.controlWord; } edb::value16 PlatformState::fpu_status_word() const { return x87.statusWord; } edb::value16 PlatformState::fpu_tag_word() const { return x87.tagWord; } //------------------------------------------------------------------------------ // Name: adjust_stack // Desc: //------------------------------------------------------------------------------ void PlatformState::adjust_stack(int bytes) { x86.GPRegs[X86::RSP] += bytes; } //------------------------------------------------------------------------------ // Name: clear // Desc: //------------------------------------------------------------------------------ void PlatformState::clear() { x86.clear(); x87.clear(); avx.clear(); } //------------------------------------------------------------------------------ // Name: empty // Desc: //------------------------------------------------------------------------------ bool PlatformState::empty() const { return x86.empty() && x87.empty() && avx.empty(); } //------------------------------------------------------------------------------ // Name: set_debug_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_debug_register(size_t n, edb::reg_t value) { assert(dbgIndexValid(n)); x86.dbgRegs[n] = value; } //------------------------------------------------------------------------------ // Name: set_flags // Desc: //------------------------------------------------------------------------------ void PlatformState::set_flags(edb::reg_t flags) { x86.flags = flags; } //------------------------------------------------------------------------------ // Name: set_instruction_pointer // Desc: //------------------------------------------------------------------------------ void PlatformState::set_instruction_pointer(edb::address_t value) { x86.IP = value; x86.orig_ax = -1; } //------------------------------------------------------------------------------ // Name: gp_register // Desc: //------------------------------------------------------------------------------ Register PlatformState::gp_register(size_t n) const { if (gprIndexValid(n)) { if (x86.gpr64Filled && is64Bit()) { return make_Register(x86.GPReg64Names[n], x86.GPRegs[n], Register::TYPE_GPR); } else if (x86.gpr32Filled && n < IA32_GPR_COUNT) { return make_Register<32>(x86.GPReg32Names[n], x86.GPRegs[n], Register::TYPE_GPR); } } return Register(); } //------------------------------------------------------------------------------ // Name: set_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_register(const Register ®) { const QString regName = reg.name().toLower(); const auto gpr_end = GPRegNames().begin() + gpr_count(); const auto GPRegNameFoundIter = std::find(GPRegNames().begin(), gpr_end, regName); if (GPRegNameFoundIter != gpr_end) { size_t index = GPRegNameFoundIter - GPRegNames().begin(); x86.GPRegs[index] = reg.value(); return; } auto segRegNameFoundIter = std::find(x86.segRegNames.begin(), x86.segRegNames.end(), regName); if (segRegNameFoundIter != x86.segRegNames.end()) { size_t index = segRegNameFoundIter - x86.segRegNames.begin(); x86.segRegs[index] = reg.value(); return; } if (regName == IPName()) { x86.IP = reg.value(); return; } if (regName == flagsName()) { x86.flags = reg.value(); return; } if (regName == avx.mxcsrName) { avx.mxcsr = reg.value(); return; } { QRegExp MMx("^mm([0-7])$"); if (MMx.indexIn(regName) != -1) { QChar digit = MMx.cap(1).at(0); assert(digit.isDigit()); char digitChar = digit.toLatin1(); size_t i = digitChar - '0'; assert(mmxIndexValid(i)); const auto value = reg.value(); std::memcpy(&x87.R[i], &value, sizeof value); const uint16_t RiUpper = 0xffff; std::memcpy(reinterpret_cast(&x87.R[i]) + sizeof value, &RiUpper, sizeof RiUpper); return; } } { QRegExp Rx("^r([0-7])$"); if (Rx.indexIn(regName) != -1) { QChar digit = Rx.cap(1).at(0); assert(digit.isDigit()); char digitChar = digit.toLatin1(); size_t i = digitChar - '0'; assert(fpuIndexValid(i)); const auto value = reg.value(); std::memcpy(&x87.R[i], &value, sizeof value); return; } } { QRegExp Rx("^st\\(?([0-7])\\)?$"); if (Rx.indexIn(regName) != -1) { QChar digit = Rx.cap(1).at(0); assert(digit.isDigit()); char digitChar = digit.toLatin1(); size_t i = digitChar - '0'; assert(fpuIndexValid(i)); const auto value = reg.value(); std::memcpy(&x87.st(i), &value, sizeof value); return; } } { QRegExp XMMx("^xmm([12]?[0-9]|3[01])$"); if (XMMx.indexIn(regName) != -1) { const auto value = reg.value(); bool indexReadOK = false; size_t i = XMMx.cap(1).toInt(&indexReadOK); assert(indexReadOK && xmmIndexValid(i)); std::memcpy(&avx.zmmStorage[i], &value, sizeof value); return; } } { QRegExp YMMx("^ymm([12]?[0-9]|3[01])$"); if (YMMx.indexIn(regName) != -1) { const auto value = reg.value(); bool indexReadOK = false; size_t i = YMMx.cap(1).toInt(&indexReadOK); assert(indexReadOK && ymmIndexValid(i)); std::memcpy(&avx.zmmStorage[i], &value, sizeof value); return; } } if (regName == "ftr" || regName == "ftw") { x87.tagWord = reg.value(); return; } if (regName == "fsr" || regName == "fsw") { x87.statusWord = reg.value(); return; } if (regName == "fcr" || regName == "fcw") { x87.controlWord = reg.value(); return; } if (regName == "fis" || regName == "fds") { (regName == "fis" ? x87.instPtrSelector : x87.dataPtrSelector) = reg.value(); return; } if (regName == "fip" || regName == "fdp") { (regName == "fip" ? x87.instPtrOffset : x87.dataPtrOffset) = reg.valueAsAddress(); return; } if (regName == "fopcode" || regName == "fop") { x87.opCode = reg.value(); return; } { QRegExp DRx("^dr([0-7])$"); if (DRx.indexIn(regName) != -1) { QChar digit = DRx.cap(1).at(0); assert(digit.isDigit()); char digitChar = digit.toLatin1(); size_t i = digitChar - '0'; assert(dbgIndexValid(i)); x86.dbgRegs[i] = reg.valueAsAddress(); return; } } qDebug().nospace() << "fixme: set_register(0x" << qPrintable(reg.toHexString()) << "): didn't set register " << reg.name(); } //------------------------------------------------------------------------------ // Name: set_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_register(const QString &name, edb::reg_t value) { const QString regName = name.toLower(); set_register(make_Register<64>(regName, value, Register::TYPE_GPR)); } //------------------------------------------------------------------------------ // Name: mmx_register // Desc: //------------------------------------------------------------------------------ Register PlatformState::mmx_register(size_t n) const { if (!mmxIndexValid(n)) { return Register(); } edb::value64 value(x87.R[n].mantissa()); return make_Register(QString("mm%1").arg(n), value, Register::TYPE_SIMD); } //------------------------------------------------------------------------------ // Name: xmm_register // Desc: //------------------------------------------------------------------------------ Register PlatformState::xmm_register(size_t n) const { if (!xmmIndexValid(n) || !avx.xmmFilledIA32) { return Register(); } if (n >= IA32_XMM_REG_COUNT && !avx.xmmFilledAMD64) { return Register(); } edb::value128 value(avx.xmm(n)); return make_Register(QString("xmm%1").arg(n), value, Register::TYPE_SIMD); } //------------------------------------------------------------------------------ // Name: ymm_register // Desc: //------------------------------------------------------------------------------ Register PlatformState::ymm_register(size_t n) const { if (!ymmIndexValid(n) || !avx.ymmFilled) { return Register(); } edb::value256 value(avx.ymm(n)); return make_Register(QString("ymm%1").arg(n), value, Register::TYPE_SIMD); } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/arch/x86-generic/PlatformState.h0000644000175000017500000003631413273160654027432 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORMSTATE_20110330_H_ #define PLATFORMSTATE_20110330_H_ #include "IState.h" #include "Types.h" #include "PrStatus.h" #include "edb.h" #include #include namespace DebuggerCorePlugin { using std::size_t; static constexpr size_t IA32_GPR_COUNT = 8; static constexpr size_t IA32_GPR_LOW_ADDRESSABLE_COUNT = 4; // al,cl,dl,bl static constexpr size_t AMD64_GPR_COUNT = 16; static constexpr size_t AMD64_GPR_LOW_ADDRESSABLE_COUNT = 16; // all GPRs' low bytes are addressable in 64 bit mode static constexpr size_t IA32_XMM_REG_COUNT = IA32_GPR_COUNT; static constexpr size_t AMD64_XMM_REG_COUNT = AMD64_GPR_COUNT; static constexpr size_t IA32_YMM_REG_COUNT = IA32_GPR_COUNT; static constexpr size_t AMD64_YMM_REG_COUNT = AMD64_GPR_COUNT; static constexpr size_t IA32_ZMM_REG_COUNT = IA32_GPR_COUNT; static constexpr size_t AMD64_ZMM_REG_COUNT = 32; static constexpr size_t MAX_GPR_COUNT = AMD64_GPR_COUNT; static constexpr size_t MAX_GPR_LOW_ADDRESSABLE_COUNT = AMD64_GPR_LOW_ADDRESSABLE_COUNT; static constexpr size_t MAX_GPR_HIGH_ADDRESSABLE_COUNT = 4; // ah,ch,dh,bh static constexpr size_t MAX_DBG_REG_COUNT = 8; static constexpr size_t MAX_SEG_REG_COUNT = 6; static constexpr size_t MAX_FPU_REG_COUNT = 8; static constexpr size_t MAX_MMX_REG_COUNT = MAX_FPU_REG_COUNT; static constexpr size_t MAX_XMM_REG_COUNT = AMD64_XMM_REG_COUNT; static constexpr size_t MAX_YMM_REG_COUNT = AMD64_YMM_REG_COUNT; static constexpr size_t MAX_ZMM_REG_COUNT = AMD64_ZMM_REG_COUNT; #ifdef EDB_X86 typedef struct user_regs_struct UserRegsStructX86; typedef struct user_fpregs_struct UserFPRegsStructX86; typedef struct user_fpxregs_struct UserFPXRegsStructX86; // Dummies to avoid missing compile-time checks for conversion code. // Actual layout is irrelevant since the code is not going to be executed struct UserFPRegsStructX86_64 { uint16_t cwd; uint16_t swd; uint16_t ftw; uint16_t fop; // last instruction opcode uint64_t rip; // last instruction EIP uint64_t rdp; // last operand pointer uint32_t mxcsr; uint32_t mxcr_mask; uint32_t st_space[32]; uint32_t xmm_space[64]; uint32_t padding[24]; }; struct UserRegsStructX86_64 { uint64_t r15; uint64_t r14; uint64_t r13; uint64_t r12; uint64_t rbp; uint64_t rbx; uint64_t r11; uint64_t r10; uint64_t r9; uint64_t r8; uint64_t rax; uint64_t rcx; uint64_t rdx; uint64_t rsi; uint64_t rdi; uint64_t orig_rax; uint64_t rip; uint64_t cs; uint64_t eflags; uint64_t rsp; uint64_t ss; uint64_t fs_base; uint64_t gs_base; uint64_t ds; uint64_t es; uint64_t fs; uint64_t gs; }; #elif defined EDB_X86_64 typedef user_regs_struct UserRegsStructX86_64; typedef user_fpregs_struct UserFPRegsStructX86_64; // Dummies to avoid missing compile-time checks for conversion code // Actual layout is irrelevant since the code is not going to be executed struct UserRegsStructX86 { uint32_t ebx; uint32_t ecx; uint32_t edx; uint32_t esi; uint32_t edi; uint32_t ebp; uint32_t eax; uint32_t xds; uint32_t xes; uint32_t xfs; uint32_t xgs; uint32_t orig_eax; uint32_t eip; uint32_t xcs; uint32_t eflags; uint32_t esp; uint32_t xss; }; struct UserFPXRegsStructX86 { uint16_t cwd; uint16_t swd; uint16_t twd; uint16_t fop; // last instruction opcode uint32_t fip; // last instruction EIP uint32_t fcs; // last instruction CS uint32_t foo; // last operand offset uint32_t fos; // last operand selector uint32_t mxcsr; uint32_t reserved; uint32_t st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ uint32_t xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ uint32_t padding[56]; }; struct UserFPRegsStructX86 { uint32_t cwd; uint32_t swd; uint32_t twd; uint32_t fip; // last instruction EIP uint32_t fcs; // last instruction CS uint32_t foo; // last operand offset uint32_t fos; // last operand selector uint32_t st_space[20]; }; #endif // Masks for XCR0 feature enabled bits #define X86_XSTATE_X87_MASK X87_XSTATE_X87 #define X86_XSTATE_SSE_MASK (X87_XSTATE_X87 | X87_XSTATE_SSE) struct X86XState { uint16_t cwd; uint16_t swd; uint16_t twd; uint16_t fop; // last instruction opcode uint32_t fioff; // last instruction EIP uint32_t fiseg; // last instruction CS in 32 bit mode, high 32 bits of RIP in 64 bit mode uint32_t fooff; // last operand offset uint32_t foseg; // last operand selector in 32 bit mode, high 32 bits of FDP in 64 bit mode uint32_t mxcsr; uint32_t mxcsr_mask; // FIXME uint8_t st_space[16 * 8]; // 8 16-byte fields uint8_t xmm_space[16 * 16]; // 16 16-byte fields, regardless of XMM_REG_COUNT uint8_t padding[48]; union { uint64_t xcr0; uint8_t sw_usable_bytes[48]; }; union { uint64_t xstate_bv; uint8_t xstate_hdr_bytes[64]; }; uint8_t ymmh_space[16 * 16]; // The extended state feature bits enum FeatureBit : uint64_t { FEATURE_X87 = 1 << 0, FEATURE_SSE = 1 << 1, FEATURE_AVX = 1 << 2, // MPX adds two feature bits FEATURE_BNDREGS = 1 << 3, FEATURE_BNDCFG = 1 << 4, FEATURE_MPX = FEATURE_BNDREGS | FEATURE_BNDCFG, // AVX-512 adds three feature bits FEATURE_K = 1 << 5, FEATURE_ZMM_H = 1 << 6, FEATURE_ZMM = 1 << 7, FEATURE_AVX512 = FEATURE_K | FEATURE_ZMM_H | FEATURE_ZMM, }; // Possible sizes of X86_XSTATE static constexpr size_t XSAVE_NONEXTENDED_SIZE = 576; static constexpr size_t SSE_SIZE = XSAVE_NONEXTENDED_SIZE; static constexpr size_t AVX_SIZE = 832; static constexpr size_t BNDREGS_SIZE = 1024; static constexpr size_t BNDCFG_SIZE = 1088; static constexpr size_t AVX512_SIZE = 2688; static constexpr size_t MAX_SIZE = 2688; }; static_assert(std::is_standard_layout::value, "X86XState struct is supposed to have standard layout"); static_assert(offsetof(X86XState, st_space) == 32, "ST space should appear at offset 32"); static_assert(offsetof(X86XState, xmm_space) == 160, "XMM space should appear at offset 160"); static_assert(offsetof(X86XState, xcr0) == 464, "XCR0 should appear at offset 464"); static_assert(offsetof(X86XState, ymmh_space) == 576, "YMM_H space should appear at offset 576"); class PlatformState : public IState { friend class DebuggerCore; friend class PlatformThread; public: PlatformState(); public: virtual IState *clone() const; public: virtual QString flags_to_string() const; virtual QString flags_to_string(edb::reg_t flags) const; virtual Register value(const QString ®) const; virtual Register instruction_pointer_register() const; virtual Register flags_register() const; virtual edb::address_t frame_pointer() const; virtual edb::address_t instruction_pointer() const; virtual edb::address_t stack_pointer() const; virtual edb::reg_t debug_register(size_t n) const; virtual edb::reg_t flags() const; virtual int fpu_stack_pointer() const; virtual edb::value80 fpu_register(size_t n) const; virtual bool fpu_register_is_empty(size_t n) const; virtual QString fpu_register_tag_string(size_t n) const; virtual edb::value16 fpu_control_word() const; virtual edb::value16 fpu_status_word() const; virtual edb::value16 fpu_tag_word() const; virtual void adjust_stack(int bytes); virtual void clear(); virtual bool empty() const; virtual void set_debug_register(size_t n, edb::reg_t value); virtual void set_flags(edb::reg_t flags); virtual void set_instruction_pointer(edb::address_t value); virtual void set_register(const Register ®); virtual void set_register(const QString &name, edb::reg_t value); virtual Register mmx_register(size_t n) const; virtual Register xmm_register(size_t n) const; virtual Register ymm_register(size_t n) const; virtual Register gp_register(size_t n) const; bool is64Bit() const { return edb::v1::debuggeeIs64Bit(); } bool is32Bit() const { return edb::v1::debuggeeIs32Bit(); } size_t dbg_reg_count() const { return MAX_DBG_REG_COUNT; } size_t seg_reg_count() const { return MAX_SEG_REG_COUNT; } size_t fpu_reg_count() const { return MAX_FPU_REG_COUNT; } size_t mmx_reg_count() const { return MAX_MMX_REG_COUNT; } size_t xmm_reg_count() const { return is64Bit() ? AMD64_XMM_REG_COUNT : IA32_XMM_REG_COUNT; } size_t ymm_reg_count() const { return is64Bit() ? AMD64_YMM_REG_COUNT : IA32_YMM_REG_COUNT; } size_t zmm_reg_count() const { return is64Bit() ? AMD64_ZMM_REG_COUNT : IA32_ZMM_REG_COUNT; } size_t gpr64_count() const { return is64Bit() ? AMD64_GPR_COUNT : 0; } size_t gpr_count() const { return is64Bit() ? AMD64_GPR_COUNT : IA32_GPR_COUNT; } size_t gpr_low_addressable_count() const { return is64Bit() ? AMD64_GPR_LOW_ADDRESSABLE_COUNT : IA32_GPR_LOW_ADDRESSABLE_COUNT; } size_t gpr_high_addressable_count() const { return MAX_GPR_HIGH_ADDRESSABLE_COUNT; } const char *IPName() const { return is64Bit() ? x86.IP64Name : x86.IP32Name; } const char *flagsName() const { return is64Bit() ? x86.flags64Name : x86.flags32Name; } const std::array &GPRegNames() const { return is64Bit() ? x86.GPReg64Names : x86.GPReg32Names; } private: // The whole AVX* state. XMM and YMM registers are lower parts of ZMM ones. struct AVX { public: static constexpr const char *mxcsrName = "mxcsr"; public: std::array zmmStorage; edb::value32 mxcsr; edb::value32 mxcsrMask; edb::value64 xcr0; bool xmmFilledIA32 = false; bool xmmFilledAMD64 = false; // This can be false when filled from e.g. FPXregs bool ymmFilled = false; bool zmmFilled = false; bool mxcsrMaskFilled = false; public: void clear(); bool empty() const; edb::value128 xmm(size_t index) const; void setXMM(size_t index, edb::value128); edb::value256 ymm(size_t index) const; void setYMM(size_t index, edb::value256); void setYMM(size_t index, edb::value128 low, edb::value128 high); edb::value512 zmm(size_t index) const; void setZMM(size_t index, edb::value512); } avx; // x87 state struct X87 { public: enum Tag { TAG_VALID = 0, TAG_ZERO = 1, TAG_SPECIAL = 2, TAG_EMPTY = 3 }; public: std::array R; // Rx registers edb::address_t instPtrOffset; edb::address_t dataPtrOffset; edb::value16 instPtrSelector; edb::value16 dataPtrSelector; edb::value16 controlWord; edb::value16 statusWord; edb::value16 tagWord; edb::value16 opCode; bool filled = false; bool opCodeFilled = false; public: void clear(); bool empty() const; size_t stackPointer() const; // Convert from ST(n) index n to Rx index x size_t RIndexToSTIndex(size_t index) const; size_t STIndexToRIndex(size_t index) const; // Restore the full FPU Tag Word from the ptrace-filtered version edb::value16 restoreTagWord(uint16_t twd) const; std::uint16_t reducedTagWord() const; int tag(size_t n) const; edb::value80 st(size_t n) const; edb::value80 &st(size_t n); private: int recreateTag(const edb::value80 value) const; int makeTag(size_t n, uint16_t twd) const; } x87; // i386-inherited (and expanded on x86_64) state struct X86 { public: enum GPRIndex : size_t { EAX, RAX = EAX, ECX, RCX = ECX, EDX, RDX = EDX, EBX, RBX = EBX, ESP, RSP = ESP, EBP, RBP = EBP, ESI, RSI = ESI, EDI, RDI = EDI, R8, R9, R10, R11, R12, R13, R14, R15 }; enum SegRegIndex : size_t { ES, CS, SS, DS, FS, GS }; static constexpr const char *origEAXName = "orig_eax"; static constexpr const char *origRAXName = "orig_rax"; static constexpr const char *IP64Name = "rip"; static constexpr const char *IP32Name = "eip"; static constexpr const char *IP16Name = "ip"; static constexpr const char *flags64Name = "rflags"; static constexpr const char *flags32Name = "eflags"; static constexpr const char *flags16Name = "flags"; // gcc 4.8 fails to understand inline initialization of std::array, so define these the old way static const std::array GPReg64Names; static const std::array GPReg32Names; static const std::array GPReg16Names; static const std::array GPReg8LNames; static const std::array GPReg8HNames; static const std::array segRegNames; public: std::array GPRegs; std::array dbgRegs; edb::reg_t orig_ax; edb::reg_t flags; // whole flags register: EFLAGS/RFLAGS edb::address_t IP; // program counter: EIP/RIP std::array segRegs; std::array segRegBases; std::array segRegBasesFilled = {{false}}; bool gpr64Filled = false; bool gpr32Filled = false; public: void clear(); bool empty() const; } x86; bool dbgIndexValid(size_t n) const { return n < dbg_reg_count(); } bool gprIndexValid(size_t n) const { return n < gpr_count(); } bool fpuIndexValid(size_t n) const { return n < fpu_reg_count(); } bool mmxIndexValid(size_t n) const { return n < mmx_reg_count(); } bool xmmIndexValid(size_t n) const { return n < xmm_reg_count(); } bool ymmIndexValid(size_t n) const { return n < ymm_reg_count(); } bool zmmIndexValid(size_t n) const { return n < zmm_reg_count(); } void fillFrom(const UserRegsStructX86 ®s); void fillFrom(const UserRegsStructX86_64 ®s); void fillFrom(const PrStatus_X86 ®s); void fillFrom(const PrStatus_X86_64 ®s); void fillFrom(const UserFPRegsStructX86 ®s); void fillFrom(const UserFPRegsStructX86_64 ®s); void fillFrom(const UserFPXRegsStructX86 ®s); bool fillFrom(const X86XState ®s, size_t sizeFromKernel); void fillStruct(UserRegsStructX86 ®s) const; void fillStruct(UserRegsStructX86_64 ®s) const; void fillStruct(PrStatus_X86_64 ®s) const; void fillStruct(UserFPRegsStructX86 ®s) const; void fillStruct(UserFPRegsStructX86_64 ®s) const; void fillStruct(UserFPXRegsStructX86 ®s) const; size_t fillStruct(X86XState ®s) const; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/arch/arm-generic/0000755000175000017500000000000013273160654024617 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/arch/arm-generic/PlatformThread.cpp0000644000175000017500000003100013273160654030231 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com Copyright (C) 2017 Ruslan Kabatsayev b7.10110111@gmail.com 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, see . */ #include "PlatformThread.h" #include "DebuggerCore.h" #include "IProcess.h" #include "PlatformCommon.h" #include "PlatformState.h" #include #include "State.h" #include "Types.h" #include "ArchProcessor.h" #include "Breakpoint.h" #ifndef _GNU_SOURCE #define _GNU_SOURCE /* or _BSD_SOURCE or _SVID_SOURCE */ #endif #include #include #include #include // doesn't always seem to be defined in the headers #ifndef PTRACE_GET_THREAD_AREA #define PTRACE_GET_THREAD_AREA static_cast<__ptrace_request>(22) #endif #ifndef PTRACE_GETSIGINFO #define PTRACE_GETSIGINFO static_cast<__ptrace_request>(0x4202) #endif #ifndef PTRACE_GETREGSET #define PTRACE_GETREGSET static_cast<__ptrace_request>(0x4204) #endif #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET static_cast<__ptrace_request>(0x4205) #endif #ifndef PTRACE_GETWMMXREGS #define PTRACE_GETWMMXREGS static_cast<__ptrace_request>(18) #define PTRACE_SETWMMXREGS static_cast<__ptrace_request>(19) #endif #ifndef PTRACE_GETVFPREGS #define PTRACE_GETVFPREGS static_cast<__ptrace_request>(27) #define PTRACE_SETVFPREGS static_cast<__ptrace_request>(28) #endif #ifndef PTRACE_GETHBPREGS #define PTRACE_GETHBPREGS static_cast<__ptrace_request>(29) #define PTRACE_SETHBPREGS static_cast<__ptrace_request>(30) #endif namespace DebuggerCorePlugin { //------------------------------------------------------------------------------ // Name: fillStateFromPrStatus // Desc: //------------------------------------------------------------------------------ bool PlatformThread::fillStateFromPrStatus(PlatformState* state) { return false; } //------------------------------------------------------------------------------ // Name: fillStateFromSimpleRegs // Desc: //------------------------------------------------------------------------------ bool PlatformThread::fillStateFromSimpleRegs(PlatformState* state) { user_regs regs; if(ptrace(PTRACE_GETREGS, tid_, 0, ®s) != -1) { state->fillFrom(regs); return true; } else { perror("PTRACE_GETREGS failed"); return false; } } //------------------------------------------------------------------------------ // Name: fillStateFromVFPRegs // Desc: //------------------------------------------------------------------------------ bool PlatformThread::fillStateFromVFPRegs(PlatformState* state) { user_vfp fpr; if(ptrace(PTRACE_GETVFPREGS, tid_, 0, &fpr) != -1) { for(unsigned i=0;ifillFrom(fpr); return true; } else { perror("PTRACE_GETVFPREGS failed"); return false; } } //------------------------------------------------------------------------------ // Name: get_state // Desc: //------------------------------------------------------------------------------ void PlatformThread::get_state(State *state) { // TODO: assert that we are paused core_->detectCPUMode(); if(auto state_impl = static_cast(state->impl_)) { fillStateFromSimpleRegs(state_impl); fillStateFromVFPRegs(state_impl); } } //------------------------------------------------------------------------------ // Name: set_state // Desc: //------------------------------------------------------------------------------ void PlatformThread::set_state(const State &state) { // TODO: assert that we are paused if(auto state_impl = static_cast(state.impl_)) { user_regs regs; state_impl->fillStruct(regs); if(ptrace(PTRACE_SETREGS, tid_, 0, ®s) == -1) { perror("PTRACE_SETREGS failed"); } user_vfp fpr; state_impl->fillStruct(fpr); if(ptrace(PTRACE_SETVFPREGS, tid_, 0, &fpr) == -1) { perror("PTRACE_SETVFPREGS failed"); } } } //------------------------------------------------------------------------------ // Name: get_debug_register // Desc: //------------------------------------------------------------------------------ unsigned long PlatformThread::get_debug_register(std::size_t n) { return 0; } //------------------------------------------------------------------------------ // Name: set_debug_register // Desc: //------------------------------------------------------------------------------ long PlatformThread::set_debug_register(std::size_t n, long value) { return 0; } Status PlatformThread::doStep(const edb::tid_t tid, const long status) { const auto addrSize=4; // The code here is ARM32-specific anyway... State state; get_state(&state); if(state.empty()) return Status(QObject::tr("failed to get thread state.")); const auto pc=state.instruction_pointer(); const auto flags=state.flags(); enum { CPSR_Tbit = 1<<5, CPSR_ITbits72 = 1<<10, CPSR_ITmask72 = 0xfc00, CPSR_Jbit = 1<<24, CPSR_ITbits10 = 1<<25, CPSR_ITmask10 = 0x06000000, }; if(flags & CPSR_Jbit) return Status(QObject::tr("EDB doesn't yet support single-stepping in Jazelle state.")); if(flags&CPSR_Tbit && flags&(CPSR_ITmask10 | CPSR_ITmask72)) return Status(QObject::tr("EDB doesn't yet support single-stepping inside Thumb-2 IT-block.")); quint8 buffer[4]; if(const int size = edb::v1::get_instruction_bytes(pc, buffer)) { if(const auto insn=edb::Instruction(buffer, buffer + size, pc)) { const auto op=insn.operation(); edb::address_t addrAfterInsn=pc+insn.byte_size(); auto targetMode=core_->cpu_mode(); if(modifies_pc(insn) && edb::v1::arch_processor().is_executed(insn,state)) { if(op==ARM_INS_BXJ) return Status(QObject::tr("EDB doesn't yet support single-stepping into Jazelle state.")); const auto opCount=insn.operand_count(); if(opCount==0) return Status(QObject::tr("instruction %1 isn't supported yet.").arg(insn.mnemonic().c_str())); switch(op) { case ARM_INS_LDR: { const auto destOperand=insn.operand(0); if(!is_register(destOperand) || destOperand->reg!=ARM_REG_PC) return Status(QObject::tr("instruction %1 with non-PC destination isn't supported yet.").arg(insn.mnemonic().c_str())); const auto srcOperand=insn.operand(1); if(!is_expression(srcOperand)) return Status(QObject::tr("unexpected type of second operand of LDR instruction.")); const auto effAddrR=edb::v1::arch_processor().get_effective_address(insn, srcOperand, state); if(!effAddrR) return Status(effAddrR.errorMessage()); const auto effAddr=effAddrR.value(); if(process_->read_bytes(effAddr, &addrAfterInsn, addrSize)!=addrSize) return Status(QObject::tr("failed to read memory referred to by LDR operand (address %1).").arg(effAddr.toPointerString())); // FIXME: for ARMv5 or below (without "T" in the name) bits [1:0] are simply ignored, without any mode change if(addrAfterInsn&1) targetMode=IDebugger::CPUMode::Thumb; else targetMode=IDebugger::CPUMode::ARM32; switch(edb::v1::debugger_core->cpu_mode()) { case IDebugger::CPUMode::Thumb: addrAfterInsn&=-2; break; case IDebugger::CPUMode::ARM32: addrAfterInsn&=-4; break; default: return Status(QObject::tr("single-stepping LDR instruction in modes other than ARM or Thumb is not supported yet.")); } break; } case ARM_INS_POP: { int i=0; for(;ireg==ARM_REG_PC) { assert(operand->access==CS_AC_WRITE); const auto sp=state.gp_register(PlatformState::GPR::SP); if(!sp) return Status(QObject::tr("failed to get value of SP register")); if(process_->read_bytes(sp.valueAsAddress()+addrSize*i, &addrAfterInsn, addrSize)!=addrSize) return Status(QObject::tr("failed to read thread stack")); break; } } if(i==opCount) return Status(QObject::tr("internal EDB error: failed to locate PC in the instruction operand list")); break; } case ARM_INS_BX: case ARM_INS_BLX: case ARM_INS_B: case ARM_INS_BL: { if(opCount!=1) return Status(QObject::tr("unexpected form of instruction %1 with %2 operands.").arg(insn.mnemonic().c_str()).arg(opCount)); const auto& operand=insn.operand(0); assert(operand); if(is_immediate(operand)) { addrAfterInsn=edb::address_t(util::to_unsigned(operand->imm)); if(op==ARM_INS_BX || op==ARM_INS_BLX) { if(targetMode==IDebugger::CPUMode::ARM32) targetMode=IDebugger::CPUMode::Thumb; else targetMode=IDebugger::CPUMode::ARM32; } break; } else if(is_register(operand)) { if(operand->reg==ARM_REG_PC && (op==ARM_INS_BX || op==ARM_INS_BLX)) return Status(QObject::tr("unpredictable instruction")); // This may happen only with BX or BLX: B and BL require an immediate operand const auto result=edb::v1::arch_processor().get_effective_address(insn, operand, state); if(!result) return Status(result.errorMessage()); addrAfterInsn=result.value(); if(addrAfterInsn&1) targetMode=IDebugger::CPUMode::Thumb; else targetMode=IDebugger::CPUMode::ARM32; addrAfterInsn&=~1; if(addrAfterInsn&0x3 && targetMode!=IDebugger::CPUMode::Thumb) return Status(QObject::tr("won't try to set breakpoint at unaligned address")); break; } return Status(QObject::tr("bad operand for %1 instruction.").arg(insn.mnemonic().c_str())); } default: return Status(QObject::tr("instruction %1 modifies PC, but isn't a branch instruction known to EDB's single-stepper.").arg(insn.mnemonic().c_str())); } } if(singleStepBreakpoint) return Status(QObject::tr("internal EDB error: single-step breakpoint still present")); if(const auto oldBP=core_->find_breakpoint(addrAfterInsn)) { // TODO: EDB should support overlapping breakpoints if(!oldBP->enabled()) return Status(QObject::tr("a disabled breakpoint is present at address %1, can't set one for single step.").arg(addrAfterInsn.toPointerString())); } else { singleStepBreakpoint=core_->add_breakpoint(addrAfterInsn); if(!singleStepBreakpoint) return Status(QObject::tr("failed to set breakpoint at address %1.").arg(addrAfterInsn.toPointerString())); const auto bp=std::static_pointer_cast(singleStepBreakpoint); if(targetMode!=core_->cpu_mode()) { switch(targetMode) { case IDebugger::CPUMode::ARM32: bp->set_type(Breakpoint::TypeId::ARM32); break; case IDebugger::CPUMode::Thumb: bp->set_type(Breakpoint::TypeId::Thumb2Byte); break; } } singleStepBreakpoint->set_one_time(true); // TODO: don't forget to remove it once we've paused after this, even if the BP wasn't hit (e.g. due to an exception on current instruction) singleStepBreakpoint->set_internal(true); } return core_->ptrace_continue(tid, status); } return Status(QObject::tr("failed to disassemble instruction at address %1.").arg(pc.toPointerString())); } return Status(QObject::tr("failed to get instruction bytes at address %1.").arg(pc.toPointerString())); } //------------------------------------------------------------------------------ // Name: step // Desc: steps this thread one instruction, passing the signal that stopped it // (unless the signal was SIGSTOP) //------------------------------------------------------------------------------ Status PlatformThread::step() { return doStep(tid_, resume_code(status_)); } //------------------------------------------------------------------------------ // Name: step // Desc: steps this thread one instruction, passing the signal that stopped it // (unless the signal was SIGSTOP, or the passed status != DEBUG_EXCEPTION_NOT_HANDLED) //------------------------------------------------------------------------------ Status PlatformThread::step(edb::EVENT_STATUS status) { const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(status_) : 0; return doStep(tid_, code); } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/arch/arm-generic/PlatformState.cpp0000644000175000017500000001303713273160654030114 0ustar eteraneteran/* Copyright (C) 2017 Ruslan Kabatsayev b7.10110111@gmail.com 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, see . */ #include "PlatformState.h" namespace DebuggerCorePlugin { const std::array PlatformState::GPR::GPRegNames = { RegNameVariants{"r0" ,"a1" }, RegNameVariants{"r1" ,"a2" }, RegNameVariants{"r2" ,"a3" }, RegNameVariants{"r3" ,"a4" }, RegNameVariants{"r4" ,"v1" }, RegNameVariants{"r5" ,"v2" }, RegNameVariants{"r6" ,"v3" }, RegNameVariants{"r7" ,"v4" }, RegNameVariants{"r8" ,"v5" }, RegNameVariants{"r9" ,"sb", "v6"}, RegNameVariants{"r10","sl", "v7"}, RegNameVariants{"r11","fp", "v8"}, RegNameVariants{"r12","ip", "v6"}, RegNameVariants{"sp" ,"r13"}, RegNameVariants{"lr" ,"r14"}, RegNameVariants{"pc" ,"r15"} }; PlatformState::PlatformState() { clear(); } IState *PlatformState::clone() const { auto*const copy=new PlatformState(); copy->gpr=gpr; return copy; } QString PlatformState::flags_to_string() const { return "flags string"; // FIXME: stub } QString PlatformState::flags_to_string(edb::reg_t flags) const { return "flags string"; // FIXME: stub } auto PlatformState::findGPR(QString const& name) const -> decltype(gpr.GPRegNames.begin()) { return std::find_if(GPR::GPRegNames.begin(), GPR::GPRegNames.end(), [&name](GPR::RegNameVariants const& variants) { for(const char*const var : variants) if(var==name) return true; return false; }); } Register PlatformState::value(const QString ®) const { const auto name=reg.toLower(); if(name=="cpsr") return flags_register(); if(vfp.filled && name=="fpscr") return make_Register<32>("fpscr", vfp.fpscr, Register::TYPE_FPU); const auto gprFoundIt=findGPR(name); if(gprFoundIt!=GPR::GPRegNames.end()) return gp_register(gprFoundIt-GPR::GPRegNames.begin()); return Register(); } Register PlatformState::instruction_pointer_register() const { #ifdef EDB_ARM32 return gp_register(GPR::PC); #else return Register(); // FIXME: stub #endif } Register PlatformState::flags_register() const { #ifdef EDB_ARM32 if(!gpr.filled) return Register(); return make_Register<32>("cpsr", gpr.cpsr, Register::TYPE_GPR); #else return Register(); // FIXME: stub #endif } edb::address_t PlatformState::frame_pointer() const { return gpr.GPRegs[GPR::FP]; } edb::address_t PlatformState::instruction_pointer() const { return gpr.GPRegs[GPR::PC]; } edb::address_t PlatformState::stack_pointer() const { return gpr.GPRegs[GPR::SP]; } edb::reg_t PlatformState::debug_register(size_t n) const { return 0; // FIXME: stub } edb::reg_t PlatformState::flags() const { return gpr.cpsr; } void PlatformState::adjust_stack(int bytes) { // FIXME: stub } void PlatformState::clear() { gpr.clear(); } bool PlatformState::empty() const { return gpr.empty(); } bool PlatformState::GPR::empty() const { return !filled; } void PlatformState::GPR::clear() { util::markMemory(this, sizeof(*this)); filled=false; } void PlatformState::set_debug_register(size_t n, edb::reg_t value) { // FIXME: stub } void PlatformState::set_flags(edb::reg_t flags) { gpr.cpsr=flags; } void PlatformState::set_instruction_pointer(edb::address_t value) { gpr.GPRegs[GPR::PC]=value; } void PlatformState::set_register(const Register ®) { if(!reg) return; const auto name=reg.name().toLower(); if(name=="cpsr") { set_flags(reg.value()); return; } if(name=="fpscr") { vfp.fpscr=reg.value(); return; } const auto gprFoundIt=findGPR(name); if(gprFoundIt!=GPR::GPRegNames.end()) { const auto index=gprFoundIt-GPR::GPRegNames.begin(); assert(index<16); gpr.GPRegs[index]=reg.value(); return; } } void PlatformState::set_register(const QString &name, edb::reg_t value) { #ifdef EDB_ARM32 const QString regName = name.toLower(); set_register(make_Register<32>(regName, value, Register::TYPE_GPR)); // FIXME: this doesn't take into account any 64-bit registers - possibly FPU data? #endif } Register PlatformState::gp_register(size_t n) const { #ifdef EDB_ARM32 assert(n(gpr.GPRegNames[n].front(), gpr.GPRegs[n], Register::TYPE_GPR); #else return Register(); // FIXME: stub #endif } void PlatformState::fillFrom(user_regs const& regs) { for(unsigned i=0;i. */ #ifndef PLATFORM_STATE_20170806_H_ #define PLATFORM_STATE_20170806_H_ #include "IState.h" #include "Types.h" #include "PrStatus.h" #include "edb.h" #include #include #include namespace DebuggerCorePlugin { using std::size_t; static constexpr size_t GPR_COUNT=16; static constexpr size_t VFPR_COUNT=32; struct user_vfp { unsigned long long fpregs[32]; unsigned long fpscr; }; class PlatformState : public IState { friend class DebuggerCore; friend class PlatformThread; public: PlatformState(); public: IState *clone() const override; QString flags_to_string() const override; QString flags_to_string(edb::reg_t flags) const override; Register value(const QString ®) const override; Register instruction_pointer_register() const override; Register flags_register() const override; edb::address_t frame_pointer() const override; edb::address_t instruction_pointer() const override; edb::address_t stack_pointer() const override; edb::reg_t debug_register(size_t n) const override; edb::reg_t flags() const override; void adjust_stack(int bytes) override; void clear() override; bool empty() const override; void set_debug_register(size_t n, edb::reg_t value) override; void set_flags(edb::reg_t flags) override; void set_instruction_pointer(edb::address_t value) override; void set_register(const Register ®) override; void set_register(const QString &name, edb::reg_t value) override; Register gp_register(size_t n) const override; void fillFrom(user_regs const& regs); void fillFrom(user_vfp const& regs); void fillStruct(user_regs& regs) const; void fillStruct(user_vfp& regs) const; private: struct GPR { enum NamedGPRIndex : size_t { SB=9, // historical name, but still printed by modern disassemblers SL=10, // historical name, but still printed by modern disassemblers FP=11, // conventionally, but much like rBP on x86 IP=12, // conventionally, intra-procedure scratch register SP=13, LR=14, PC=15, }; using RegNameVariants=std::vector; static const std::array GPRegNames; bool filled=false; std::array GPRegs; edb::reg_t cpsr; public: void clear(); bool empty() const; } gpr; struct VFP { std::array d; edb::value32 fpscr; bool filled=false; } vfp; private: auto findGPR(QString const& name) const -> decltype(gpr.GPRegNames.begin()); }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/linux/DebuggerCore.cpp0000644000175000017500000010340513273160654024555 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ // TODO(eteran): research usage of process_vm_readv, process_vm_writev #include "DebuggerCore.h" #include "Configuration.h" #include "DialogMemoryAccess.h" #include "edb.h" #include "FeatureDetect.h" #include "MemoryRegions.h" #include "PlatformCommon.h" #include "PlatformEvent.h" #include "PlatformProcess.h" #include "PlatformRegion.h" #include "PlatformState.h" #include "PlatformThread.h" #include "State.h" #include "string_hash.h" #include #include #include #include #include #ifndef _GNU_SOURCE #define _GNU_SOURCE /* or _BSD_SOURCE or _SVID_SOURCE */ #endif #if defined(EDB_X86) || defined(EDB_X86_64) #include #endif #include #include #include #include // doesn't always seem to be defined in the headers #ifndef PTRACE_GETSIGINFO #define PTRACE_GETSIGINFO static_cast<__ptrace_request>(0x4202) #endif #ifndef PTRACE_EVENT_CLONE #define PTRACE_EVENT_CLONE 3 #endif #ifndef PTRACE_O_TRACECLONE #define PTRACE_O_TRACECLONE (1 << PTRACE_EVENT_CLONE) #endif #ifndef PTRACE_O_EXITKILL #define PTRACE_O_EXITKILL (1 << 20) #endif #ifndef PTRACE_O_TRACEEXIT #define PTRACE_O_TRACEEXIT (1 << PTRACE_EVENT_EXIT) #endif namespace DebuggerCorePlugin { namespace { const edb::address_t PageSize = 0x1000; //------------------------------------------------------------------------------ // Name: is_numeric // Desc: returns true if the string only contains decimal digits //------------------------------------------------------------------------------ bool is_numeric(const QString &s) { for(QChar ch: s) { if(!ch.isDigit()) { return false; } } return true; } //------------------------------------------------------------------------------ // Name: is_clone_event // Desc: //------------------------------------------------------------------------------ bool is_clone_event(int status) { return (status >> 8 == (SIGTRAP | (PTRACE_EVENT_CLONE << 8))); } //------------------------------------------------------------------------------ // Name: is_exit_trace_event // Desc: //------------------------------------------------------------------------------ bool is_exit_trace_event(int status) { return (status >> 8 == (SIGTRAP | (PTRACE_EVENT_EXIT << 8))); } #if defined(EDB_X86) || defined(EDB_X86_64) bool in64BitSegment() { bool edbIsIn64BitSegment; // Check that we're running in 64 bit segment: this can be in cases // of LP64 and ILP32 programming models, so we can't rely on sizeof(void*) asm(R"( .byte 0x33,0xc0 # XOR EAX,EAX .byte 0x48 # DEC EAX for 32 bit, REX prefix for 64 bit .byte 0xff,0xc0 # INC EAX for 32 bit, INC RAX due to REX.W in 64 bit )":"=a"(edbIsIn64BitSegment)); return edbIsIn64BitSegment; } bool os64Bit(bool edbIsIn64BitSegment) { bool osIs64Bit; if(edbIsIn64BitSegment) { osIs64Bit = true; } else { // We want to be really sure the OS is 32 bit, so we can't rely on such easy // to (even unintentionally) fake mechanisms as uname(2) (e.g. see setarch(8)) asm(R"(.intel_syntax noprefix mov eax,cs cmp ax,0x23 # this value is set for 32-bit processes on 64-bit kernel mov ah,0 # not sure this is really needed: usually the compiler will do # MOVZX EAX,AL, but we have to be certain the result is correct sete al .att_syntax # restore default syntax )":"=a"(osIs64Bit)); } return osIs64Bit; } #endif } //------------------------------------------------------------------------------ // Name: DebuggerCore // Desc: constructor //------------------------------------------------------------------------------ DebuggerCore::DebuggerCore() : process_(nullptr), pointer_size_(sizeof(void*)), #if defined(EDB_X86) || defined(EDB_X86_64) edbIsIn64BitSegment(in64BitSegment()), osIs64Bit(os64Bit(edbIsIn64BitSegment)), USER_CS_32(osIs64Bit ? 0x23 : 0x73), USER_CS_64(osIs64Bit ? 0x33 : 0xfff8), // RPL 0 can't appear in user segment registers, so 0xfff8 is safe USER_SS(osIs64Bit ? 0x2b : 0x7b), #endif lastMeansOfCapture(MeansOfCapture::NeverCaptured) { #if 0 #if defined(EDB_X86) || defined(EDB_X86_64) qDebug() << "EDB is in" << (edbIsIn64BitSegment ? "64" : "32") << "bit segment"; qDebug() << "OS is" << (osIs64Bit ? "64" : "32") << "bit"; #endif #endif proc_mem_write_broken_ = true; proc_mem_read_broken_ = true; feature::detect_proc_access(&proc_mem_read_broken_, &proc_mem_write_broken_); if(proc_mem_read_broken_ || proc_mem_write_broken_) { qDebug() << "Detect that read /proc//mem works = " << !proc_mem_read_broken_; qDebug() << "Detect that write /proc//mem works = " << !proc_mem_write_broken_; QSettings settings; const bool warn = settings.value("DebuggerCore/warn_on_broken_proc_mem.enabled", true).toBool(); if(warn) { auto dialog = new DialogMemoryAccess(0); dialog->exec(); settings.setValue("DebuggerCore/warn_on_broken_proc_mem.enabled", dialog->warnNextTime()); delete dialog; } } } //------------------------------------------------------------------------------ // Name: has_extension // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::has_extension(quint64 ext) const { Q_UNUSED(ext); #if defined(EDB_X86) || defined(EDB_X86_64) static constexpr auto mmxHash = edb::string_hash("MMX"); static constexpr auto xmmHash = edb::string_hash("XMM"); static constexpr auto ymmHash = edb::string_hash("YMM"); if(EDB_IS_64_BIT && (ext == xmmHash || ext == mmxHash)) { return true; } quint32 eax; quint32 ebx; quint32 ecx; quint32 edx; __cpuid(1, eax, ebx, ecx, edx); switch(ext) { case mmxHash: return (edx & bit_MMX); case xmmHash: return (edx & bit_SSE); case ymmHash: { // Check OSXSAVE and AVX feature flags if((ecx & 0x18000000) != 0x18000000) { return false; } // Get XCR0, must be exactly after OSXSAVE feature check, otherwise #UD __asm__ __volatile__("xgetbv" : "=a"(eax),"=d"(edx) : "c"(0)); // Check that the OS has enabled XMM and YMM state support if((eax & 0x6) != 0x6) { return false; } return true; } default: return false; } #endif return false; } //------------------------------------------------------------------------------ // Name: page_size // Desc: returns the size of a page on this system //------------------------------------------------------------------------------ edb::address_t DebuggerCore::page_size() const { return PageSize; } std::size_t DebuggerCore::pointer_size() const { return pointer_size_; } //------------------------------------------------------------------------------ // Name: ~DebuggerCore // Desc: destructor //------------------------------------------------------------------------------ DebuggerCore::~DebuggerCore() { end_debug_session(); } //------------------------------------------------------------------------------ // Name: ptrace_getsiginfo // Desc: //------------------------------------------------------------------------------ Status DebuggerCore::ptrace_getsiginfo(edb::tid_t tid, siginfo_t *siginfo) { Q_ASSERT(siginfo != 0); if(ptrace(PTRACE_GETSIGINFO, tid, 0, siginfo)==-1) { const char*const strError=strerror(errno); qWarning() << "Unable to get signal info for thread" << tid << ": PTRACE_GETSIGINFO failed:" << strError; return Status(strError); } return Status::Ok; } //------------------------------------------------------------------------------ // Name: ptrace_traceme // Desc: //------------------------------------------------------------------------------ long DebuggerCore::ptrace_traceme() { return ptrace(PTRACE_TRACEME, 0, 0, 0); } //------------------------------------------------------------------------------ // Name: ptrace_continue // Desc: //------------------------------------------------------------------------------ Status DebuggerCore::ptrace_continue(edb::tid_t tid, long status) { // TODO(eteran): perhaps address this at a higher layer? // I would like to not have these events show up // in the first place if we aren't stopped on this TID :-( if(waited_threads_.contains(tid)) { Q_ASSERT(tid != 0); if(ptrace(PTRACE_CONT, tid, 0, status)==-1) { const char*const strError=strerror(errno); qWarning() << "Unable to continue thread" << tid << ": PTRACE_CONT failed:" << strError; return Status(strError); } waited_threads_.remove(tid); return Status::Ok; } return Status(QObject::tr("ptrace_continue(): waited_threads_ doesn't contain tid %1").arg(tid)); } //------------------------------------------------------------------------------ // Name: ptrace_step // Desc: //------------------------------------------------------------------------------ Status DebuggerCore::ptrace_step(edb::tid_t tid, long status) { // TODO(eteran): perhaps address this at a higher layer? // I would like to not have these events show up // in the first place if we aren't stopped on this TID :-( if(waited_threads_.contains(tid)) { Q_ASSERT(tid != 0); if(ptrace(PTRACE_SINGLESTEP, tid, 0, status)==-1) { const char*const strError=strerror(errno); qWarning() << "Unable to step thread" << tid << ": PTRACE_SINGLESTEP failed:" << strError; return Status(strError); } waited_threads_.remove(tid); return Status::Ok; } return Status(QObject::tr("ptrace_step(): waited_threads_ doesn't contain tid %1").arg(tid)); } //------------------------------------------------------------------------------ // Name: ptrace_set_options // Desc: //------------------------------------------------------------------------------ Status DebuggerCore::ptrace_set_options(edb::tid_t tid, long options) { Q_ASSERT(waited_threads_.contains(tid)); Q_ASSERT(tid != 0); if(ptrace(PTRACE_SETOPTIONS, tid, 0, options)==-1) { const char*const strError=strerror(errno); qWarning() << "Unable to set ptrace options for thread" << tid << ": PTRACE_SETOPTIONS failed:" << strError; return Status(strError); } return Status::Ok; } //------------------------------------------------------------------------------ // Name: ptrace_get_event_message // Desc: //------------------------------------------------------------------------------ Status DebuggerCore::ptrace_get_event_message(edb::tid_t tid, unsigned long *message) { Q_ASSERT(waited_threads_.contains(tid)); Q_ASSERT(tid != 0); Q_ASSERT(message != 0); if(ptrace(PTRACE_GETEVENTMSG, tid, 0, message)==-1) { const char*const strError=strerror(errno); qWarning() << "Unable to get event message for thread" << tid << ": PTRACE_GETEVENTMSG failed:" << strError; return Status(strError); } return Status::Ok; } //------------------------------------------------------------------------------ // Name: desired_ptrace_options // Desc: //------------------------------------------------------------------------------ long DebuggerCore::ptraceOptions() const { // we want to trace clone (thread) creation events long options = PTRACE_O_TRACECLONE; // if applicable, we want an auto SIGKILL sent to the child // process and its threads switch(edb::v1::config().close_behavior) { case Configuration::Kill: options |= PTRACE_O_EXITKILL; break; case Configuration::KillIfLaunchedDetachIfAttached: if(last_means_of_capture() == MeansOfCapture::Launch) { options |= PTRACE_O_EXITKILL; } break; default: break; } #if 0 // TODO(eteran): research this option for issue #46 options |= PTRACE_O_TRACEEXIT; #endif return options; } //------------------------------------------------------------------------------ // Name: handle_thread_exit // Desc: //------------------------------------------------------------------------------ void DebuggerCore::handle_thread_exit(edb::tid_t tid, int status) { Q_UNUSED(status); threads_.remove(tid); waited_threads_.remove(tid); } //------------------------------------------------------------------------------ // Name: handle_event // Desc: //------------------------------------------------------------------------------ std::shared_ptr DebuggerCore::handle_event(edb::tid_t tid, int status) { // note that we have waited on this thread waited_threads_.insert(tid); // was it a thread exit event? if(WIFEXITED(status)) { handle_thread_exit(tid,status); // if this was the last thread, return true // so we report it to the user. // if this wasn't, then we should silently // procceed. if(!threads_.empty()) { return nullptr; } } if(is_exit_trace_event(status)) { } // was it a thread create event? if(is_clone_event(status)) { unsigned long new_tid; if(ptrace_get_event_message(tid, &new_tid)) { auto newThread = std::make_shared(this, process_, new_tid); newThread->status_ = 0; newThread->signal_status_ = PlatformThread::Stopped; threads_.insert(new_tid, newThread); int thread_status = 0; if(!waited_threads_.contains(new_tid)) { if(native::waitpid(new_tid, &thread_status, __WALL) > 0) { waited_threads_.insert(new_tid); } } // A new thread could exit before we have fully created it, no event then since it can't be the last thread if(WIFEXITED(thread_status)) { handle_thread_exit(tid,thread_status); return nullptr; } if(!WIFSTOPPED(thread_status) || WSTOPSIG(thread_status) != SIGSTOP) { qWarning("handle_event(): new thread [%d] received an event besides SIGSTOP: status=0x%x", static_cast(new_tid),thread_status); } newThread->status_ = thread_status; // copy the hardware debug registers from the current thread to the new thread if(process_) { if(auto thread = process_->current_thread()) { for(int i = 0; i < 8; ++i) { auto new_thread = std::static_pointer_cast(newThread); auto old_thread = std::static_pointer_cast(thread); new_thread->set_debug_register(i, old_thread->get_debug_register(i)); } } } // TODO(eteran): what the heck do we do if this isn't a SIGSTOP? newThread->resume(); } ptrace_continue(tid, 0); return nullptr; } // normal event auto e = std::make_shared(); e->pid_ = pid(); e->tid_ = tid; e->status_ = status; if(!ptrace_getsiginfo(tid, &e->siginfo_)) { // TODO: handle no info? } active_thread_ = tid; auto it = threads_.find(tid); if(it != threads_.end()) { it.value()->status_ = status; } stop_threads(); // Some breakpoint types result in SIGILL or SIGSEGV. We'll transform the // event into breakpoint event if such a breakpoint has triggered. if(it != threads_.end() && WIFSTOPPED(status)) { const auto signo=WSTOPSIG(status); if(signo==SIGILL || signo==SIGSEGV) { // no need to peekuser for SIGILL, but have to for SIGSEGV const auto address = signo==SIGILL ? edb::address_t::fromZeroExtended(e->siginfo_.si_addr) : (*it)->instruction_pointer(); if(edb::v1::find_triggered_breakpoint(address)) { e->status_=SIGTRAP<<8|0x7f; e->siginfo_.si_signo=SIGTRAP; e->siginfo_.si_code=TRAP_BRKPT; } } } #if defined EDB_ARM32 if(it != threads_.end()) { const auto& thread=*it; if(thread->singleStepBreakpoint) { remove_breakpoint(thread->singleStepBreakpoint->address()); thread->singleStepBreakpoint=nullptr; assert(e->siginfo_.si_signo==SIGTRAP); // signo must have already be converted to SIGTRAP if needed e->siginfo_.si_code=TRAP_TRACE; } } #endif return e; } //------------------------------------------------------------------------------ // Name: stop_threads // Desc: //------------------------------------------------------------------------------ Status DebuggerCore::stop_threads() { QString errorMessage; if(process_) { for(auto &thread: process_->threads()) { const edb::tid_t tid = thread->tid(); if(!waited_threads_.contains(tid)) { if(auto thread_ptr = std::static_pointer_cast(thread)) { const auto stopStatus=thread->stop(); if(!stopStatus) errorMessage+=QObject::tr("Failed to stop thread %1: %2\n").arg(tid).arg(stopStatus.toString()); int thread_status; if(native::waitpid(tid, &thread_status, __WALL) > 0) { waited_threads_.insert(tid); thread_ptr->status_ = thread_status; // A thread could have exited between previous waitpid and the latest one... if(WIFEXITED(thread_status)) { handle_thread_exit(tid, thread_status); } // ..., otherwise it must have stopped. else if(!WIFSTOPPED(thread_status) || WSTOPSIG(thread_status) != SIGSTOP) { qWarning("stop_threads(): paused thread [%d] received an event besides SIGSTOP: status=0x%x", tid,thread_status); } } } } } } if(errorMessage.isEmpty()) return Status::Ok; qWarning() << errorMessage.toStdString().c_str(); return Status("\n"+errorMessage); } //------------------------------------------------------------------------------ // Name: wait_debug_event // Desc: waits for a debug event, msecs is a timeout // it will return false if an error or timeout occurs //------------------------------------------------------------------------------ std::shared_ptr DebuggerCore::wait_debug_event(int msecs) { if(process_) { if(!native::wait_for_sigchld(msecs)) { for(auto &thread : process_->threads()) { int status; const edb::tid_t tid = native::waitpid(thread->tid(), &status, __WALL | WNOHANG); if(tid > 0) { return handle_event(tid, status); } } } } return nullptr; } //------------------------------------------------------------------------------ // Name: attach_thread // Desc: returns 0 if successful, errno if failed //------------------------------------------------------------------------------ int DebuggerCore::attach_thread(edb::tid_t tid) { if(ptrace(PTRACE_ATTACH, tid, 0, 0) == 0) { // I *think* that the PTRACE_O_TRACECLONE is only valid on // stopped threads int status; const auto ret = native::waitpid(tid, &status, __WALL); if(ret > 0) { auto newThread = std::make_shared(this, process_, tid); newThread->status_ = status; newThread->signal_status_ = PlatformThread::Stopped; threads_[tid] = newThread; waited_threads_.insert(tid); const long options = ptraceOptions(); const auto setoptStatus=ptrace_set_options(tid, options); if(!setoptStatus) { qDebug() << "[DebuggerCore] failed to set ptrace options: ["<< tid <<"]" << setoptStatus.toString(); } return 0; } else if(ret==-1) { return errno; } else { return -1; // unknown error } } else { return errno; } } //------------------------------------------------------------------------------ // Name: attach // Desc: //------------------------------------------------------------------------------ Status DebuggerCore::attach(edb::pid_t pid) { end_debug_session(); lastMeansOfCapture = MeansOfCapture::Attach; // create this, so the threads created can refer to it process_ = new PlatformProcess(this, pid); int lastErr = attach_thread(pid); // Fail early if we are going to if(lastErr) { delete process_; process_ = nullptr; return Status(std::strerror(lastErr)); } lastErr = -2; bool attached; do { attached = false; QDir proc_directory(QString("/proc/%1/task/").arg(pid)); for(const QString &s: proc_directory.entryList(QDir::NoDotAndDotDot | QDir::Dirs)) { // this can get tricky if the threads decide to spawn new threads // when we are attaching. I wish that linux had an atomic way to do this // all in one shot const edb::tid_t tid = s.toUInt(); if(!threads_.contains(tid)) { const auto errnum = attach_thread(tid); if(errnum == 0) attached = true; else lastErr = errnum; } } } while(attached); if(!threads_.empty()) { pid_ = pid; active_thread_ = pid; binary_info_ = edb::v1::get_binary_info(edb::v1::primary_code_region()); detectCPUMode(); return Status::Ok; } delete process_; process_ = nullptr; return Status(std::strerror(lastErr)); } //------------------------------------------------------------------------------ // Name: detach // Desc: //------------------------------------------------------------------------------ Status DebuggerCore::detach() { QString errorMessage; if(process_) { stop_threads(); clear_breakpoints(); for(auto &thread: process_->threads()) { if(ptrace(PTRACE_DETACH, thread->tid(), 0, 0)==-1) { const char*const strError=strerror(errno); errorMessage+=QObject::tr("Unable to detach from thread %1: PTRACE_DETACH failed: %2\n").arg(thread->tid()).arg(strError); } } delete process_; process_ = nullptr; reset(); } if(errorMessage.isEmpty()) return Status::Ok; qWarning() << errorMessage.toStdString().c_str(); return Status(errorMessage); } //------------------------------------------------------------------------------ // Name: kill // Desc: //------------------------------------------------------------------------------ void DebuggerCore::kill() { if(attached()) { clear_breakpoints(); ::kill(pid(), SIGKILL); pid_t ret; while((ret=native::waitpid(-1, 0, __WALL)) != pid() && ret!=-1); delete process_; process_ = nullptr; reset(); } } void DebuggerCore::detectCPUMode() { #if defined(EDB_X86) || defined(EDB_X86_64) const size_t offset=EDB_IS_64_BIT ? offsetof(UserRegsStructX86_64, cs) : offsetof(UserRegsStructX86, xcs); errno=0; const edb::seg_reg_t cs=ptrace(PTRACE_PEEKUSER, active_thread_, offset, 0); if(!errno) { if(cs==USER_CS_32) { if(pointer_size_==sizeof(quint64)) { qDebug() << "Debuggee is now 32 bit"; cpu_mode_=CPUMode::x86_32; CapstoneEDB::init(CapstoneEDB::Architecture::ARCH_X86); } pointer_size_=sizeof(quint32); return; } else if(cs==USER_CS_64) { if(pointer_size_==sizeof(quint32)) { qDebug() << "Debuggee is now 64 bit"; cpu_mode_=CPUMode::x86_64; CapstoneEDB::init(CapstoneEDB::Architecture::ARCH_AMD64); } pointer_size_=sizeof(quint64); return; } } #elif defined(EDB_ARM32) errno=0; const auto cpsr=ptrace(PTRACE_PEEKUSER, active_thread_, sizeof(long)*16, 0L); if(!errno) { const bool thumb=cpsr&0x20; if(thumb) { cpu_mode_=CPUMode::Thumb; CapstoneEDB::init(CapstoneEDB::Architecture::ARCH_ARM32_THUMB); } else { cpu_mode_=CPUMode::ARM32; CapstoneEDB::init(CapstoneEDB::Architecture::ARCH_ARM32_ARM); } } pointer_size_ = sizeof(quint32); #elif defined(EDB_ARM64) cpu_mode_=CPUMode::ARM64; CapstoneEDB::init(CapstoneEDB::Architecture::ARCH_ARM64); pointer_size_ = sizeof(quint64); #else #error "Unsupported Architecture" #endif } //------------------------------------------------------------------------------ // Name: get_state // Desc: //------------------------------------------------------------------------------ void DebuggerCore::get_state(State *state) { // TODO: assert that we are paused if(process_) { if(std::shared_ptr thread = process_->current_thread()) { thread->get_state(state); } } } //------------------------------------------------------------------------------ // Name: set_state // Desc: //------------------------------------------------------------------------------ void DebuggerCore::set_state(const State &state) { // TODO: assert that we are paused if(process_) { if(std::shared_ptr thread = process_->current_thread()) { thread->set_state(state); } } } //------------------------------------------------------------------------------ // Name: open // Desc: //------------------------------------------------------------------------------ Status DebuggerCore::open(const QString &path, const QString &cwd, const QList &args, const QString &tty) { end_debug_session(); lastMeansOfCapture = MeansOfCapture::Launch; static constexpr std::size_t sharedMemSize=4096; const auto sharedMem=static_cast(::mmap(nullptr,sharedMemSize,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0)); std::memset(sharedMem,0,sharedMemSize); switch(pid_t pid = fork()) { case 0: { // we are in the child now... // set ourselves (the child proc) up to be traced ptrace_traceme(); // redirect it's I/O if(!tty.isEmpty()) { FILE *const std_out = freopen(qPrintable(tty), "r+b", stdout); FILE *const std_in = freopen(qPrintable(tty), "r+b", stdin); FILE *const std_err = freopen(qPrintable(tty), "r+b", stderr); Q_UNUSED(std_out); Q_UNUSED(std_in); Q_UNUSED(std_err); } if(edb::v1::config().disableASLR) { const auto curPers = ::personality(UINT32_MAX); // This shouldn't fail, but let's at least perror if it does anyway if(curPers == -1) { perror("Failed to get current personality"); } else if(::personality(curPers | ADDR_NO_RANDOMIZE) == -1) { perror("Failed to disable ASLR"); } } if(edb::v1::config().disableLazyBinding && setenv("LD_BIND_NOW", "1",true) == -1) { perror("Failed to disable lazy binding"); } // do the actual exec const Status status = execute_process(path, cwd, args); #if defined __GNUG__ && __GNUC__ >= 5 || !defined __GNUG__ || defined __clang__ && __clang_major__*100+__clang_minor__>=306 static_assert(std::is_trivially_copyable::value,"Can't copy string of QChar to shared memory"); #endif QString error = status.toString(); std::memcpy(sharedMem, error.constData(), std::min(sizeof(QChar) * error.size(), sharedMemSize-sizeof(QChar)/*prevent overwriting of last null*/)); // we should never get here! abort(); break; } case -1: // error! for some reason we couldn't fork reset(); return Status(tr("Failed to fork")); default: // parent do { reset(); int status; const auto wpidRet = native::waitpid(pid, &status, __WALL); const QString childError(sharedMem); ::munmap(sharedMem, sharedMemSize); if(wpidRet == -1) { return Status(tr("waitpid() failed: %1").arg(std::strerror(errno))+(childError.isEmpty()?"" : tr(".\nError returned by child:\n%1.").arg(childError))); } if(WIFEXITED(status)) { return Status(tr("The child unexpectedly exited with code %1. Error returned by child:\n%2").arg(WEXITSTATUS(status)).arg(childError)); } if(WIFSIGNALED(status)) { return Status(tr("The child was unexpectedly killed by signal %1. Error returned by child:\n%2").arg(WTERMSIG(status)).arg(childError)); } // This happens when exec failed, but just in case it's something another return some description. if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGABRT) { return Status(childError.isEmpty() ? tr("The child unexpectedly aborted") : childError); } // the very first event should be a STOP of type SIGTRAP if(!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) { end_debug_session(); return Status(tr("First event after waitpid() should be a STOP of type SIGTRAP, but wasn't, instead status=0x%1") .arg(status,0,16)+(childError.isEmpty() ? "" : tr(".\nError returned by child:\n%1.").arg(childError))); } waited_threads_.insert(pid); const long options = ptraceOptions(); // enable following clones (threads) and other options we are concerned with const auto setoptStatus=ptrace_set_options(pid, options); if(!setoptStatus) { end_debug_session(); return Status(tr("[DebuggerCore] failed to set ptrace options: %1").arg(setoptStatus.toString())); } // create the process process_ = new PlatformProcess(this, pid); // the PID == primary TID auto newThread = std::make_shared(this, process_, pid); newThread->status_ = status; newThread->signal_status_ = PlatformThread::Stopped; threads_[pid] = newThread; pid_ = pid; active_thread_ = pid; binary_info_ = edb::v1::get_binary_info(edb::v1::primary_code_region()); detectCPUMode(); return Status::Ok; } while(0); break; } } //------------------------------------------------------------------------------ // Name: last_means_of_capture // Desc: Returns how the last process was captured to debug //------------------------------------------------------------------------------ DebuggerCore::MeansOfCapture DebuggerCore::last_means_of_capture() const { return lastMeansOfCapture; } //------------------------------------------------------------------------------ // Name: reset // Desc: //------------------------------------------------------------------------------ void DebuggerCore::reset() { threads_.clear(); waited_threads_.clear(); pid_ = 0; active_thread_ = 0; binary_info_ = nullptr; } //------------------------------------------------------------------------------ // Name: create_state // Desc: //------------------------------------------------------------------------------ IState *DebuggerCore::create_state() const { return new PlatformState; } //------------------------------------------------------------------------------ // Name: enumerate_processes // Desc: //------------------------------------------------------------------------------ QMap> DebuggerCore::enumerate_processes() const { QMap> ret; QDir proc_directory("/proc/"); QFileInfoList entries = proc_directory.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); for(const QFileInfo &info: entries) { const QString filename = info.fileName(); if(is_numeric(filename)) { const edb::pid_t pid = filename.toULong(); // NOTE(eteran): the const_cast is reasonable here. // While we don't want THIS function to mutate the DebuggerCore object // we do want the associated PlatformProcess to be able to trigger // non-const operations in the future, at least hypothetically. ret.insert(pid, std::make_shared(const_cast(this), pid)); } } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::pid_t DebuggerCore::parent_pid(edb::pid_t pid) const { struct user_stat user_stat; int n = get_user_stat(pid, &user_stat); if(n >= 4) { return user_stat.ppid; } return 0; } //------------------------------------------------------------------------------ // Name: // Desc: Returns EDB's native CPU type //------------------------------------------------------------------------------ quint64 DebuggerCore::cpu_type() const { #if defined EDB_X86 || defined EDB_X86_64 if(EDB_IS_32_BIT) return edb::string_hash("x86"); else return edb::string_hash("x86-64"); #elif defined EDB_ARM32 return edb::string_hash("arm"); #elif defined EDB_ARM64 return edb::string_hash("AArch64"); #else # error "What to return?" #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::format_pointer(edb::address_t address) const { return address.toPointerString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::stack_pointer() const { #if defined EDB_X86 || defined EDB_X86_64 if(edb::v1::debuggeeIs32Bit()) return "esp"; else return "rsp"; #elif defined EDB_ARM32 || defined EDB_ARM64 return "sp"; #else # error "What to return?" #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::frame_pointer() const { #if defined EDB_X86 || defined EDB_X86_64 if(edb::v1::debuggeeIs32Bit()) return "ebp"; else return "rbp"; #elif defined EDB_ARM32 || defined EDB_ARM64 return "fp"; #else # error "What to return?" #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::instruction_pointer() const { #if defined EDB_X86 || defined EDB_X86_64 if(edb::v1::debuggeeIs32Bit()) return "eip"; else return "rip"; #elif defined EDB_ARM32 || defined EDB_ARM64 return "pc"; #else # error "What to return?" #endif } //------------------------------------------------------------------------------ // Name: flag_register // Desc: Returns the name of the flag register as a QString. //------------------------------------------------------------------------------ QString DebuggerCore::flag_register() const { #if defined EDB_X86 || defined EDB_X86_64 if(edb::v1::debuggeeIs32Bit()) return "eflags"; else return "rflags"; #elif defined EDB_ARM32 || defined EDB_ARM64 return "cpsr"; #else # error "What to return?" #endif } //------------------------------------------------------------------------------ // Name: process // Desc: //------------------------------------------------------------------------------ IProcess *DebuggerCore::process() const { return process_; } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(DebuggerCore, DebuggerCore) #endif } edb-debugger-1.0.0/plugins/DebuggerCore/unix/openbsd/0000755000175000017500000000000013273160654022004 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/unix/openbsd/DebuggerCore.h0000644000175000017500000000613313273160654024515 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DEBUGGERCORE_20090529_H_ #define DEBUGGERCORE_20090529_H_ #include "DebuggerCoreUNIX.h" #include namespace DebuggerCore { class DebuggerCore : public DebuggerCoreUNIX { Q_OBJECT Q_INTERFACES(IDebugger) Q_CLASSINFO("author", "Evan Teran") Q_CLASSINFO("url", "http://www.codef00.com") public: DebuggerCore(); virtual ~DebuggerCore(); public: virtual edb::address_t page_size() const; virtual bool has_extension(quint64 ext) const; virtual std::shared_ptr wait_debug_event(int msecs); virtual bool attach(edb::pid_t pid); virtual void detach(); virtual void kill(); virtual void pause(); virtual void resume(edb::EVENT_STATUS status); virtual void step(edb::EVENT_STATUS status); virtual void get_state(State *state); virtual void set_state(const State &state); virtual bool open(const QString &path, const QString &cwd, const QList &args, const QString &tty); public: // thread support stuff (optional) virtual QList thread_ids() const { return threads_.keys(); } virtual edb::tid_t active_thread() const { return active_thread_; } virtual void set_active_thread(edb::tid_t); public: virtual QList> memory_regions() const; virtual edb::address_t process_code_address() const; virtual edb::address_t process_data_address() const; public: virtual IState *create_state() const; public: // process properties virtual QList process_args(edb::pid_t pid) const; virtual QString process_exe(edb::pid_t pid) const; virtual QString process_cwd(edb::pid_t pid) const; virtual edb::pid_t parent_pid(edb::pid_t pid) const; virtual QDateTime process_start(edb::pid_t pid) const; virtual quint64 cpu_type() const; private: virtual QMap enumerate_processes() const; virtual QList loaded_modules() const; public: virtual QString stack_pointer() const; virtual QString frame_pointer() const; virtual QString instruction_pointer() const; public: virtual QString format_pointer(edb::address_t address) const; private: virtual long read_data(edb::address_t address, bool *ok); virtual bool write_data(edb::address_t address, long value); private: struct thread_info { public: thread_info() : status(0) { } thread_info(int s) : status(s) { } int status; }; typedef QHash threadmap_t; edb::address_t page_size_; threadmap_t threads_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/openbsd/PlatformProcess.cpp0000644000175000017500000000133513273160654025635 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformProcess.h" edb-debugger-1.0.0/plugins/DebuggerCore/unix/openbsd/PlatformEvent.h0000644000175000017500000000311313273160654024741 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_EVENT_20121005_H_ #define PLATFORM_EVENT_20121005_H_ #include #include "IDebugEvent.h" namespace DebuggerCore { class PlatformEvent : IDebugEvent { Q_DECLARE_TR_FUNCTIONS(PlatformEvent) friend class DebuggerCore; public: PlatformEvent(); public: virtual PlatformEvent *clone() const; public: virtual Message error_description() const; virtual REASON reason() const; virtual TRAP_REASON trap_reason() const; virtual bool exited() const; virtual bool is_error() const; virtual bool is_kill() const; virtual bool is_stop() const; virtual bool is_trap() const; virtual bool terminated() const; virtual bool stopped() const; virtual edb::pid_t process() const; virtual edb::tid_t thread() const; virtual int code() const; private: int status; edb::pid_t pid; edb::tid_t tid; void * fault_address_; long fault_code_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/openbsd/PlatformRegion.h0000644000175000017500000000350013273160654025103 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_REGION_20120330_H_ #define PLATFORM_REGION_20120330_H_ #include "IRegion.h" #include #include namespace DebuggerCore { class PlatformRegion : public IRegion { Q_DECLARE_TR_FUNCTIONS(PlatformRegion) public: PlatformRegion(edb::address_t start, edb::address_t end, edb::address_t base, const QString &name, permissions_t permissions); virtual ~PlatformRegion(); public: virtual IRegion *clone() const; public: virtual bool accessible() const; virtual bool readable() const; virtual bool writable() const; virtual bool executable() const; virtual edb::address_t size() const; public: virtual void set_permissions(bool read, bool write, bool execute); virtual void set_start(edb::address_t address); virtual void set_end(edb::address_t address); public: virtual edb::address_t start() const; virtual edb::address_t end() const; virtual edb::address_t base() const; virtual QString name() const; virtual permissions_t permissions() const; private: edb::address_t start_; edb::address_t end_; edb::address_t base_; QString name_; permissions_t permissions_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/openbsd/PlatformRegion.cpp0000644000175000017500000000450713273160654025446 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformRegion.h" #include "MemoryRegions.h" #include "edb.h" #include "IDebugger.h" #include "State.h" #include "IDebugEventHandler.h" #include #include #include namespace DebuggerCore { PlatformRegion::PlatformRegion(edb::address_t start, edb::address_t end, edb::address_t base, const QString &name, permissions_t permissions) : start_(start), end_(end), base_(base), name_(name), permissions_(permissions) { } PlatformRegion::~PlatformRegion() { } IRegion *PlatformRegion::clone() const { return new PlatformRegion(start_, end_, base_, name_, permissions_); } bool PlatformRegion::accessible() const { return readable() || writable() || executable(); } bool PlatformRegion::readable() const { return (permissions_ & PROT_READ) != 0; } bool PlatformRegion::writable() const { return (permissions_ & PROT_WRITE) != 0; } bool PlatformRegion::executable() const { return (permissions_ & PROT_EXEC) != 0; } edb::address_t PlatformRegion::size() const { return end_ - start_; } void PlatformRegion::set_permissions(bool read, bool write, bool execute) { Q_UNUSED(read); Q_UNUSED(write); Q_UNUSED(execute); } edb::address_t PlatformRegion::start() const { return start_; } edb::address_t PlatformRegion::end() const { return end_; } edb::address_t PlatformRegion::base() const { return base_; } QString PlatformRegion::name() const { return name_; } IRegion::permissions_t PlatformRegion::permissions() const { return permissions_; } void PlatformRegion::set_start(edb::address_t address) { start_ = address; } void PlatformRegion::set_end(edb::address_t address) { end_ = address; } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/openbsd/PlatformProcess.h0000644000175000017500000000153113273160654025300 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATOFORM_PROCESS_20150517_H_ #define PLATOFORM_PROCESS_20150517_H_ #include "IProcess.h" class PlatformProcess : public IProcess { }; #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/openbsd/PlatformState.cpp0000644000175000017500000004644613273160654025313 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformState.h" namespace DebuggerCore { //------------------------------------------------------------------------------ // Name: PlatformState // Desc: //------------------------------------------------------------------------------ PlatformState::PlatformState() { memset(®s_, 0, sizeof(regs_)); memset(&fpregs_, 0, sizeof(fpregs_)); memset(&dr_, 0, sizeof(dr_)); fs_base = 0; gs_base = 0; } //------------------------------------------------------------------------------ // Name: PlatformState::clone // Desc: makes a copy of the state object //------------------------------------------------------------------------------ IState *PlatformState::clone() const { return new PlatformState(*this); } //------------------------------------------------------------------------------ // Name: flags_to_string // Desc: returns the flags in a string form appropriate for this platform //------------------------------------------------------------------------------ QString PlatformState::flags_to_string(edb::reg_t flags) const { char buf[14]; qsnprintf( buf, sizeof(buf), "%c %c %c %c %c %c %c", ((flags & 0x001) ? 'C' : 'c'), ((flags & 0x004) ? 'P' : 'p'), ((flags & 0x010) ? 'A' : 'a'), ((flags & 0x040) ? 'Z' : 'z'), ((flags & 0x080) ? 'S' : 's'), ((flags & 0x400) ? 'D' : 'd'), ((flags & 0x800) ? 'O' : 'o')); return buf; } //------------------------------------------------------------------------------ // Name: flags_to_string // Desc: returns the flags in a string form appropriate for this platform //------------------------------------------------------------------------------ QString PlatformState::flags_to_string() const { return flags_to_string(flags()); } //------------------------------------------------------------------------------ // Name: value // Desc: returns a Register object which represents the register with the name // supplied //------------------------------------------------------------------------------ Register PlatformState::value(const QString ®) const { const QString lreg = reg.toLower(); #if defined(EDB_X86) if(lreg == "eax") return Register("eax", regs_.r_eax, Register::TYPE_GPR); else if(lreg == "ebx") return Register("ebx", regs_.r_ebx, Register::TYPE_GPR); else if(lreg == "ecx") return Register("ecx", regs_.r_ecx, Register::TYPE_GPR); else if(lreg == "edx") return Register("edx", regs_.r_edx, Register::TYPE_GPR); else if(lreg == "ebp") return Register("ebp", regs_.r_ebp, Register::TYPE_GPR); else if(lreg == "esp") return Register("esp", regs_.r_esp, Register::TYPE_GPR); else if(lreg == "esi") return Register("esi", regs_.r_esi, Register::TYPE_GPR); else if(lreg == "edi") return Register("edi", regs_.r_edi, Register::TYPE_GPR); else if(lreg == "eip") return Register("eip", regs_.r_eip, Register::TYPE_IP); else if(lreg == "ax") return Register("ax", regs_.r_eax & 0xffff, Register::TYPE_GPR); else if(lreg == "bx") return Register("bx", regs_.r_ebx & 0xffff, Register::TYPE_GPR); else if(lreg == "cx") return Register("cx", regs_.r_ecx & 0xffff, Register::TYPE_GPR); else if(lreg == "dx") return Register("dx", regs_.r_edx & 0xffff, Register::TYPE_GPR); else if(lreg == "bp") return Register("bp", regs_.r_ebp & 0xffff, Register::TYPE_GPR); else if(lreg == "sp") return Register("sp", regs_.r_esp & 0xffff, Register::TYPE_GPR); else if(lreg == "si") return Register("si", regs_.r_esi & 0xffff, Register::TYPE_GPR); else if(lreg == "di") return Register("di", regs_.r_edi & 0xffff, Register::TYPE_GPR); else if(lreg == "al") return Register("al", regs_.r_eax & 0xff, Register::TYPE_GPR); else if(lreg == "bl") return Register("bl", regs_.r_ebx & 0xff, Register::TYPE_GPR); else if(lreg == "cl") return Register("cl", regs_.r_ecx & 0xff, Register::TYPE_GPR); else if(lreg == "dl") return Register("dl", regs_.r_edx & 0xff, Register::TYPE_GPR); else if(lreg == "ah") return Register("ah", (regs_.r_eax >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bh") return Register("bh", (regs_.r_ebx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "ch") return Register("ch", (regs_.r_ecx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dh") return Register("dh", (regs_.r_edx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "cs") return Register("cs", regs_.r_cs, Register::TYPE_SEG); else if(lreg == "ds") return Register("ds", regs_.r_ds, Register::TYPE_SEG); else if(lreg == "es") return Register("es", regs_.r_es, Register::TYPE_SEG); else if(lreg == "fs") return Register("fs", regs_.r_fs, Register::TYPE_SEG); else if(lreg == "gs") return Register("gs", regs_.r_gs, Register::TYPE_SEG); else if(lreg == "ss") return Register("ss", regs_.r_ss, Register::TYPE_SEG); else if(lreg == "fs_base") return Register("fs_base", fs_base, Register::TYPE_SEG); else if(lreg == "gs_base") return Register("gs_base", gs_base, Register::TYPE_SEG); else if(lreg == "eflags") return Register("eflags", regs_.r_eflags, Register::TYPE_COND); #elif defined(EDB_X86_64) if(lreg == "rax") return Register("rax", regs_.r_rax, Register::TYPE_GPR); else if(lreg == "rbx") return Register("rbx", regs_.r_rbx, Register::TYPE_GPR); else if(lreg == "rcx") return Register("rcx", regs_.r_rcx, Register::TYPE_GPR); else if(lreg == "rdx") return Register("rdx", regs_.r_rdx, Register::TYPE_GPR); else if(lreg == "rbp") return Register("rbp", regs_.r_rbp, Register::TYPE_GPR); else if(lreg == "rsp") return Register("rsp", regs_.r_rsp, Register::TYPE_GPR); else if(lreg == "rsi") return Register("rsi", regs_.r_rsi, Register::TYPE_GPR); else if(lreg == "rdi") return Register("rdi", regs_.r_rdi, Register::TYPE_GPR); else if(lreg == "rip") return Register("rip", regs_.r_rip, Register::TYPE_IP); else if(lreg == "r8") return Register("r8", regs_.r_r8, Register::TYPE_GPR); else if(lreg == "r9") return Register("r9", regs_.r_r9, Register::TYPE_GPR); else if(lreg == "r10") return Register("r10", regs_.r_r10, Register::TYPE_GPR); else if(lreg == "r11") return Register("r11", regs_.r_r11, Register::TYPE_GPR); else if(lreg == "r12") return Register("r12", regs_.r_r12, Register::TYPE_GPR); else if(lreg == "r13") return Register("r13", regs_.r_r13, Register::TYPE_GPR); else if(lreg == "r14") return Register("r14", regs_.r_r14, Register::TYPE_GPR); else if(lreg == "r15") return Register("r15", regs_.r_r15, Register::TYPE_GPR); else if(lreg == "eax") return Register("eax", regs_.r_rax & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ebx") return Register("ebx", regs_.r_rbx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ecx") return Register("ecx", regs_.r_rcx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "edx") return Register("edx", regs_.r_rdx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ebp") return Register("ebp", regs_.r_rbp & 0xffffffff, Register::TYPE_GPR); else if(lreg == "esp") return Register("esp", regs_.r_rsp & 0xffffffff, Register::TYPE_GPR); else if(lreg == "esi") return Register("esi", regs_.r_rsi & 0xffffffff, Register::TYPE_GPR); else if(lreg == "edi") return Register("edi", regs_.r_rdi & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r8d") return Register("r8d", regs_.r_r8 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r9d") return Register("r9d", regs_.r_r9 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r10d") return Register("r10d", regs_.r_r10 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r11d") return Register("r11d", regs_.r_r11 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r12d") return Register("r12d", regs_.r_r12 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r13d") return Register("r13d", regs_.r_r13 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r14d") return Register("r14d", regs_.r_r14 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r15d") return Register("r15d", regs_.r_r15 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ax") return Register("ax", regs_.r_rax & 0xffff, Register::TYPE_GPR); else if(lreg == "bx") return Register("bx", regs_.r_rbx & 0xffff, Register::TYPE_GPR); else if(lreg == "cx") return Register("cx", regs_.r_rcx & 0xffff, Register::TYPE_GPR); else if(lreg == "dx") return Register("dx", regs_.r_rdx & 0xffff, Register::TYPE_GPR); else if(lreg == "bp") return Register("bp", regs_.r_rbp & 0xffff, Register::TYPE_GPR); else if(lreg == "sp") return Register("sp", regs_.r_rsp & 0xffff, Register::TYPE_GPR); else if(lreg == "si") return Register("si", regs_.r_rsi & 0xffff, Register::TYPE_GPR); else if(lreg == "di") return Register("di", regs_.r_rdi & 0xffff, Register::TYPE_GPR); else if(lreg == "r8w") return Register("r8w", regs_.r_r8 & 0xffff, Register::TYPE_GPR); else if(lreg == "r9w") return Register("r9w", regs_.r_r9 & 0xffff, Register::TYPE_GPR); else if(lreg == "r10w") return Register("r10w", regs_.r_r10 & 0xffff, Register::TYPE_GPR); else if(lreg == "r11w") return Register("r11w", regs_.r_r11 & 0xffff, Register::TYPE_GPR); else if(lreg == "r12w") return Register("r12w", regs_.r_r12 & 0xffff, Register::TYPE_GPR); else if(lreg == "r13w") return Register("r13w", regs_.r_r13 & 0xffff, Register::TYPE_GPR); else if(lreg == "r14w") return Register("r14w", regs_.r_r14 & 0xffff, Register::TYPE_GPR); else if(lreg == "r15w") return Register("r15w", regs_.r_r15 & 0xffff, Register::TYPE_GPR); else if(lreg == "al") return Register("al", regs_.r_rax & 0xff, Register::TYPE_GPR); else if(lreg == "bl") return Register("bl", regs_.r_rbx & 0xff, Register::TYPE_GPR); else if(lreg == "cl") return Register("cl", regs_.r_rcx & 0xff, Register::TYPE_GPR); else if(lreg == "dl") return Register("dl", regs_.r_rdx & 0xff, Register::TYPE_GPR); else if(lreg == "ah") return Register("ah", (regs_.r_rax >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bh") return Register("bh", (regs_.r_rbx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "ch") return Register("ch", (regs_.r_rcx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dh") return Register("dh", (regs_.r_rdx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "spl") return Register("spl", (regs_.r_rsp >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bpl") return Register("bpl", (regs_.r_rbp >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "sil") return Register("sil", (regs_.r_rsi >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dil") return Register("dil", (regs_.r_rdi >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "r8b") return Register("r8b", regs_.r_r8 & 0xff, Register::TYPE_GPR); else if(lreg == "r9b") return Register("r9b", regs_.r_r9 & 0xff, Register::TYPE_GPR); else if(lreg == "r10b") return Register("r10b", regs_.r_r10 & 0xff, Register::TYPE_GPR); else if(lreg == "r11b") return Register("r11b", regs_.r_r11 & 0xff, Register::TYPE_GPR); else if(lreg == "r12b") return Register("r12b", regs_.r_r12 & 0xff, Register::TYPE_GPR); else if(lreg == "r13b") return Register("r13b", regs_.r_r13 & 0xff, Register::TYPE_GPR); else if(lreg == "r14b") return Register("r14b", regs_.r_r14 & 0xff, Register::TYPE_GPR); else if(lreg == "r15b") return Register("r15b", regs_.r_r15 & 0xff, Register::TYPE_GPR); else if(lreg == "cs") return Register("cs", regs_.r_cs, Register::TYPE_SEG); else if(lreg == "ds") return Register("ds", regs_.r_ds, Register::TYPE_SEG); else if(lreg == "es") return Register("es", regs_.r_es, Register::TYPE_SEG); else if(lreg == "fs") return Register("fs", regs_.r_fs, Register::TYPE_SEG); else if(lreg == "gs") return Register("gs", regs_.r_gs, Register::TYPE_SEG); else if(lreg == "ss") return Register("ss", regs_.r_ss, Register::TYPE_SEG); else if(lreg == "fs_base") return Register("fs_base", fs_base, Register::TYPE_SEG); else if(lreg == "gs_base") return Register("gs_base", gs_base, Register::TYPE_SEG); else if(lreg == "rflags") return Register("rflags", regs_.r_rflags, Register::TYPE_COND); #endif return Register(); } //------------------------------------------------------------------------------ // Name: frame_pointer // Desc: returns what is conceptually the frame pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::frame_pointer() const { #if defined(EDB_X86) return regs_.r_ebp; #elif defined(EDB_X86_64) return regs_.r_rbp; #endif } //------------------------------------------------------------------------------ // Name: instruction_pointer // Desc: returns the instruction pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::instruction_pointer() const { #if defined(EDB_X86) return regs_.r_eip; #elif defined(EDB_X86_64) return regs_.r_rip; #endif } //------------------------------------------------------------------------------ // Name: stack_pointer // Desc: returns the stack pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::stack_pointer() const { #if defined(EDB_X86) return regs_.r_esp; #elif defined(EDB_X86_64) return regs_.r_rsp; #endif } //------------------------------------------------------------------------------ // Name: debug_register // Desc: //------------------------------------------------------------------------------ edb::reg_t PlatformState::debug_register(int n) const { return dr_[n]; } //------------------------------------------------------------------------------ // Name: flags // Desc: //------------------------------------------------------------------------------ edb::reg_t PlatformState::flags() const { #if defined(EDB_X86) return regs_.r_eflags; #elif defined(EDB_X86_64) return regs_.r_rflags; #endif } //------------------------------------------------------------------------------ // Name: fpu_register // Desc: //------------------------------------------------------------------------------ long double PlatformState::fpu_register(int n) const { return reinterpret_cast(&fpregs_)[n]; } //------------------------------------------------------------------------------ // Name: adjust_stack // Desc: //------------------------------------------------------------------------------ void PlatformState::adjust_stack(int bytes) { #if defined(EDB_X86) regs_.r_esp += bytes; #elif defined(EDB_X86_64) regs_.r_rsp += bytes; #endif } //------------------------------------------------------------------------------ // Name: clear // Desc: //------------------------------------------------------------------------------ void PlatformState::clear() { memset(®s_, 0, sizeof(regs_)); memset(&fpregs_, 0, sizeof(fpregs_)); memset(&dr_, 0, sizeof(dr_)); #if defined(EDB_X86) fs_base = 0; gs_base = 0; #endif } //------------------------------------------------------------------------------ // Name: set_debug_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_debug_register(int n, edb::reg_t value) { dr_[n] = value; } //------------------------------------------------------------------------------ // Name: set_flags // Desc: //------------------------------------------------------------------------------ void PlatformState::set_flags(edb::reg_t flags) { #if defined(EDB_X86) regs_.r_eflags = flags; #elif defined(EDB_X86_64) regs_.r_rflags = flags; #endif } //------------------------------------------------------------------------------ // Name: set_instruction_pointer // Desc: //------------------------------------------------------------------------------ void PlatformState::set_instruction_pointer(edb::address_t value) { #if defined(EDB_X86) regs_.r_eip = value; #elif defined(EDB_X86_64) regs_.r_rip = value; #endif } //------------------------------------------------------------------------------ // Name: set_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_register(const QString &name, edb::reg_t value) { const QString lreg = name.toLower(); #if defined(EDB_X86) if(lreg == "eax") { regs_.r_eax = value; } else if(lreg == "ebx") { regs_.r_ebx = value; } else if(lreg == "ecx") { regs_.r_ecx = value; } else if(lreg == "edx") { regs_.r_edx = value; } else if(lreg == "ebp") { regs_.r_ebp = value; } else if(lreg == "esp") { regs_.r_esp = value; } else if(lreg == "esi") { regs_.r_esi = value; } else if(lreg == "edi") { regs_.r_edi = value; } else if(lreg == "eip") { regs_.r_eip = value; } else if(lreg == "cs") { regs_.r_cs = value; } else if(lreg == "ds") { regs_.r_ds = value; } else if(lreg == "es") { regs_.r_es = value; } else if(lreg == "fs") { regs_.r_fs = value; } else if(lreg == "gs") { regs_.r_gs = value; } else if(lreg == "ss") { regs_.r_ss = value; } else if(lreg == "eflags") { regs_.r_eflags = value; } #elif defined(EDB_X86_64) if(lreg == "rax") { regs_.r_rax = value; } else if(lreg == "rbx") { regs_.r_rbx = value; } else if(lreg == "rcx") { regs_.r_rcx = value; } else if(lreg == "rdx") { regs_.r_rdx = value; } else if(lreg == "rbp") { regs_.r_rbp = value; } else if(lreg == "rsp") { regs_.r_rsp = value; } else if(lreg == "rsi") { regs_.r_rsi = value; } else if(lreg == "rdi") { regs_.r_rdi = value; } else if(lreg == "r8") { regs_.r_r8 = value; } else if(lreg == "r9") { regs_.r_r9 = value; } else if(lreg == "r10") { regs_.r_r10 = value; } else if(lreg == "r11") { regs_.r_r11 = value; } else if(lreg == "r12") { regs_.r_r12 = value; } else if(lreg == "r13") { regs_.r_r13 = value; } else if(lreg == "r14") { regs_.r_r14 = value; } else if(lreg == "r15") { regs_.r_r15 = value; } else if(lreg == "rip") { regs_.r_rip = value; } else if(lreg == "cs") { regs_.r_cs = value; } else if(lreg == "ds") { regs_.r_ds = value; } else if(lreg == "es") { regs_.r_es = value; } else if(lreg == "fs") { regs_.r_fs = value; } else if(lreg == "gs") { regs_.r_gs = value; } else if(lreg == "ss") { regs_.r_ss = value; } else if(lreg == "rflags") { regs_.r_rflags = value; } #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ quint64 PlatformState::mmx_register(int n) const { Q_UNUSED(n); return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QByteArray PlatformState::xmm_register(int n) const { Q_UNUSED(n); return QByteArray(); } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/openbsd/PlatformState.h0000644000175000017500000000370613273160654024750 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORMSTATE_20110330_H_ #define PLATFORMSTATE_20110330_H_ #include "IState.h" #include "Types.h" #include #include namespace DebuggerCore { class PlatformState : public IState { friend class DebuggerCore; public: PlatformState(); public: virtual IState *clone() const; public: virtual QString flags_to_string() const; virtual QString flags_to_string(edb::reg_t flags) const; virtual Register value(const QString ®) const; virtual edb::address_t frame_pointer() const; virtual edb::address_t instruction_pointer() const; virtual edb::address_t stack_pointer() const; virtual edb::reg_t debug_register(int n) const; virtual edb::reg_t flags() const; virtual long double fpu_register(int n) const; virtual void adjust_stack(int bytes); virtual void clear(); virtual void set_debug_register(int n, edb::reg_t value); virtual void set_flags(edb::reg_t flags); virtual void set_instruction_pointer(edb::address_t value); virtual void set_register(const QString &name, edb::reg_t value); virtual quint64 mmx_register(int n) const; virtual QByteArray xmm_register(int n) const; private: struct reg regs_; struct fpreg fpregs_; edb::reg_t dr_[8]; edb::address_t fs_base; edb::address_t gs_base; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/openbsd/PlatformEvent.cpp0000644000175000017500000001734213273160654025305 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformEvent.h" #include "edb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for the SIG* definitions namespace DebuggerCore { //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ PlatformEvent::PlatformEvent() : status(0), pid(-1), tid(-1), fault_address_(0), fault_code_(0) { } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ PlatformEvent *PlatformEvent::clone() const { return new PlatformEvent(*this); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::Message PlatformEvent::error_description() const { Q_ASSERT(is_error()); auto fault_address = reinterpret_cast(fault_address_); switch(code()) { case SIGSEGV: return Message( tr("Illegal Access Fault"), tr( "

The debugged application encountered a segmentation fault.
The address 0x%1 could not be accessed.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

").arg(edb::v1::format_pointer(fault_address)) ); case SIGILL: return Message( tr("Illegal Instruction Fault"), tr( "

The debugged application attempted to execute an illegal instruction.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); case SIGFPE: switch(fault_code_) { case FPE_INTDIV: return Message( tr("Divide By Zero"), tr( "

The debugged application tried to divide an integer value by an integer divisor of zero.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); default: return Message( tr("Floating Point Exception"), tr( "

The debugged application encountered a floating-point exception.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); } case SIGABRT: return Message( tr("Application Aborted"), tr( "

The debugged application has aborted.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); case SIGBUS: return Message( tr("Bus Error"), tr( "

The debugged application tried to read or write data that is misaligned.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); #ifdef SIGSTKFLT case SIGSTKFLT: return Message( tr("Stack Fault"), tr( "

The debugged application encountered a stack fault.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); #endif case SIGPIPE: return Message( tr("Broken Pipe Fault"), tr( "

The debugged application encountered a broken pipe fault.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); default: return Message(); } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::REASON PlatformEvent:: reason() const { // this basically converts our value into a 'switchable' value for convenience if(stopped()) { return EVENT_STOPPED; } else if(terminated()) { return EVENT_TERMINATED; } else if(exited()) { return EVENT_EXITED; } else { return EVENT_UNKNOWN; } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::TRAP_REASON PlatformEvent::trap_reason() const { switch(fault_code_) { case TRAP_TRACE: return TRAP_STEPPING; default: return TRAP_BREAKPOINT; } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::exited() const { return WIFEXITED(status) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_error() const { if(stopped()) { switch(code()) { case SIGTRAP: case SIGSTOP: return false; case SIGSEGV: case SIGILL: case SIGFPE: case SIGABRT: case SIGBUS: #ifdef SIGSTKFLT case SIGSTKFLT: #endif case SIGPIPE: return true; default: return false; } } else { return false; } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_kill() const { return stopped() && code() == SIGKILL; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_stop() const { return stopped() && code() == SIGSTOP; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_trap() const { return stopped() && code() == SIGTRAP; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::terminated() const { return WIFSIGNALED(status) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::stopped() const { return WIFSTOPPED(status) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ edb::pid_t PlatformEvent::process() const { return pid; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ edb::tid_t PlatformEvent::thread() const { return tid; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ int PlatformEvent::code() const { if(stopped()) { return WSTOPSIG(status); } if(terminated()) { return WTERMSIG(status); } if(exited()) { return WEXITSTATUS(status); } return 0; } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/openbsd/DebuggerCore.cpp0000644000175000017500000005355313273160654025060 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "DebuggerCore.h" #include "PlatformEvent.h" #include "PlatformRegion.h" #include "PlatformState.h" #include "State.h" #include "string_hash.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __need_process #include #include namespace DebuggerCore { namespace { void SET_OK(bool &ok, long value) { ok = (value != -1) || (errno == 0); } int resume_code(int status) { if(WIFSIGNALED(status)) { return WTERMSIG(status); } else if(WIFSTOPPED(status)) { return WSTOPSIG(status); } return 0; } #if defined(OpenBSD) && (OpenBSD > 201205) //------------------------------------------------------------------------------ // Name: load_vmmap_entries // Desc: Download vmmap_entries from the kernel into our address space. // We fix up the addr tree while downloading. // Returns the size of the tree on success, or -1 on failure. // On failure, *rptr needs to be passed to unload_vmmap_entries to free // the lot. //------------------------------------------------------------------------------ ssize_t load_vmmap_entries(kvm_t *kd, u_long kptr, struct vm_map_entry **rptr, struct vm_map_entry *parent) { struct vm_map_entry *entry; u_long left_kptr; u_long right_kptr; ssize_t left_sz; ssize_t right_sz; if (kptr == 0) return 0; /* Need space. */ entry = (struct vm_map_entry *)malloc(sizeof(*entry)); if (entry == NULL) return -1; /* Download entry at kptr. */ if (!kvm_read(kd, kptr, (char *)entry, sizeof(*entry))) { free(entry); return -1; } /* * Update addr pointers to have sane values in this address space. * We save the kernel pointers in {left,right}_kptr, so we have them * available to download children. */ left_kptr = (u_long) RB_LEFT(entry, daddrs.addr_entry); right_kptr = (u_long) RB_RIGHT(entry, daddrs.addr_entry); RB_LEFT(entry, daddrs.addr_entry) = RB_RIGHT(entry, daddrs.addr_entry) = NULL; /* Fill in parent pointer. */ RB_PARENT(entry, daddrs.addr_entry) = parent; /* * Consistent state reached, fill in *rptr. */ *rptr = entry; /* * Download left, right. * On failure, our map is in a state that can be handled by * unload_vmmap_entries. */ left_sz = load_vmmap_entries(kd, left_kptr, &RB_LEFT(entry, daddrs.addr_entry), entry); if (left_sz == -1) return -1; right_sz = load_vmmap_entries(kd, right_kptr, &RB_RIGHT(entry, daddrs.addr_entry), entry); if (right_sz == -1) return -1; return 1 + left_sz + right_sz; } //------------------------------------------------------------------------------ // Name: // Desc: Free the vmmap entries in the given tree. //------------------------------------------------------------------------------ void unload_vmmap_entries(struct vm_map_entry *entry) { if (entry == NULL) return; unload_vmmap_entries(RB_LEFT(entry, daddrs.addr_entry)); unload_vmmap_entries(RB_RIGHT(entry, daddrs.addr_entry)); free(entry); } //------------------------------------------------------------------------------ // Name: // Desc: Don't implement address comparison. //------------------------------------------------------------------------------ int no_impl(void *p, void *q) { Q_UNUSED(p); Q_UNUSED(q); Q_ASSERT(0); /* Should not be called. */ return 0; } #endif } #if defined(OpenBSD) && (OpenBSD > 201205) RB_GENERATE(uvm_map_addr, vm_map_entry, daddrs.addr_entry, no_impl) #endif //------------------------------------------------------------------------------ // Name: DebuggerCore // Desc: constructor //------------------------------------------------------------------------------ DebuggerCore::DebuggerCore() { #if defined(_SC_PAGESIZE) page_size_ = sysconf(_SC_PAGESIZE); #elif defined(_SC_PAGE_SIZE) page_size_ = sysconf(_SC_PAGE_SIZE); #else page_size_ = PAGE_SIZE; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::has_extension(quint64 ext) const { return false; } //------------------------------------------------------------------------------ // Name: page_size // Desc: returns the size of a page on this system //------------------------------------------------------------------------------ edb::address_t DebuggerCore::page_size() const { return page_size_; } //------------------------------------------------------------------------------ // Name: ~DebuggerCore // Desc: //------------------------------------------------------------------------------ DebuggerCore::~DebuggerCore() { detach(); } //------------------------------------------------------------------------------ // Name: wait_debug_event // Desc: waits for a debug event, msecs is a timeout // it will return false if an error or timeout occurs //------------------------------------------------------------------------------ std::shared_ptr DebuggerCore::wait_debug_event(int msecs) { if(attached()) { int status; bool timeout; const edb::tid_t tid = native::waitpid_timeout(pid(), &status, 0, msecs, &timeout); if(!timeout) { if(tid > 0) { // normal event auto e = std::make_shared(); e->pid = pid(); e->tid = tid; e->status = status; char errbuf[_POSIX2_LINE_MAX]; if(kvm_t *const kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) { int rc; struct kinfo_proc *const kiproc = kvm_getprocs(kd, KERN_PROC_PID, pid(), sizeof(struct kinfo_proc), &rc); struct proc proc; kvm_read(kd, kiproc->p_paddr, &proc, sizeof(proc)); e->fault_code_ = proc.p_sicode; e->fault_address_ = proc.p_sigval.sival_ptr; //printf("ps_sig : %d\n", sigacts.ps_sig); //printf("ps_type : %d\n", sigacts.ps_type); kvm_close(kd); } else { e->fault_code_ = 0; e->fault_address_ = 0; } active_thread_ = tid; threads_[tid].status = status; return e; } } } return nullptr; } //------------------------------------------------------------------------------ // Name: read_data // Desc: //------------------------------------------------------------------------------ long DebuggerCore::read_data(edb::address_t address, bool *ok) { Q_ASSERT(ok); errno = 0; const long v = ptrace(PT_READ_D, pid(), reinterpret_cast(address), 0); SET_OK(*ok, v); return v; } //------------------------------------------------------------------------------ // Name: write_data // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::write_data(edb::address_t address, long value) { return ptrace(PT_WRITE_D, pid(), reinterpret_cast(address), value) != -1; } //------------------------------------------------------------------------------ // Name: attach // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::attach(edb::pid_t pid) { detach(); const long ret = ptrace(PT_ATTACH, pid, 0, 0); if(ret == 0) { pid_ = pid; active_thread_ = pid; threads_.clear(); threads_.insert(pid, thread_info()); // TODO: attach to all of the threads } return ret == 0; } //------------------------------------------------------------------------------ // Name: detach // Desc: //------------------------------------------------------------------------------ void DebuggerCore::detach() { if(attached()) { // TODO: do i need to stop each thread first, and wait for them? clear_breakpoints(); ptrace(PT_DETACH, pid(), 0, 0); pid_ = 0; threads_.clear(); } } //------------------------------------------------------------------------------ // Name: kill // Desc: //------------------------------------------------------------------------------ void DebuggerCore::kill() { if(attached()) { clear_breakpoints(); ptrace(PT_KILL, pid(), 0, 0); native::waitpid(pid(), 0, WAIT_ANY); pid_ = 0; threads_.clear(); } } //------------------------------------------------------------------------------ // Name: pause // Desc: stops *all* threads of a process //------------------------------------------------------------------------------ void DebuggerCore::pause() { if(attached()) { for(auto it = threads_.begin(); it != threads_.end(); ++it) { ::kill(it.key(), SIGSTOP); } } } //------------------------------------------------------------------------------ // Name: resume // Desc: //------------------------------------------------------------------------------ void DebuggerCore::resume(edb::EVENT_STATUS status) { // TODO: assert that we are paused if(attached()) { if(status != edb::DEBUG_STOP) { const edb::tid_t tid = active_thread(); const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(threads_[tid].status) : 0; ptrace(PT_CONTINUE, tid, reinterpret_cast(1), code); } } } //------------------------------------------------------------------------------ // Name: step // Desc: //------------------------------------------------------------------------------ void DebuggerCore::step(edb::EVENT_STATUS status) { // TODO: assert that we are paused if(attached()) { if(status != edb::DEBUG_STOP) { const edb::tid_t tid = active_thread(); const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(threads_[tid].status) : 0; ptrace(PT_STEP, tid, reinterpret_cast(1), code); } } } //------------------------------------------------------------------------------ // Name: get_state // Desc: //------------------------------------------------------------------------------ void DebuggerCore::get_state(State *state) { Q_ASSERT(state); // TODO: assert that we are paused auto state_impl = static_cast(state->impl_); if(attached()) { if(ptrace(PT_GETREGS, active_thread(), reinterpret_cast(&state_impl->regs_), 0) != -1) { // TODO state_impl->gs_base = 0; state_impl->fs_base = 0; } if(ptrace(PT_GETFPREGS, active_thread(), reinterpret_cast(&state_impl->fpregs_), 0) != -1) { } // TODO: Debug Registers } else { state->clear(); } } //------------------------------------------------------------------------------ // Name: set_state // Desc: //------------------------------------------------------------------------------ void DebuggerCore::set_state(const State &state) { // TODO: assert that we are paused auto state_impl = static_cast(state.impl_); if(attached()) { ptrace(PT_SETREGS, active_thread(), reinterpret_cast(&state_impl->regs_), 0); // TODO: FPU // TODO: Debug Registers } } //------------------------------------------------------------------------------ // Name: open // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::open(const QString &path, const QString &cwd, const QList &args, const QString &tty) { detach(); pid_t pid; switch(pid = fork()) { case 0: // we are in the child now... // set ourselves (the child proc) up to be traced ptrace(PT_TRACE_ME, 0, 0, 0); // redirect it's I/O if(!tty.isEmpty()) { FILE *const std_out = freopen(qPrintable(tty), "r+b", stdout); FILE *const std_in = freopen(qPrintable(tty), "r+b", stdin); FILE *const std_err = freopen(qPrintable(tty), "r+b", stderr); Q_UNUSED(std_out); Q_UNUSED(std_in); Q_UNUSED(std_err); } // do the actual exec execute_process(path, cwd, args); // we should never get here! abort(); break; case -1: // error! pid_ = 0; return false; default: // parent do { threads_.clear(); int status; if(native::waitpid(pid, &status, 0) == -1) { return false; } // the very first event should be a STOP of type SIGTRAP if(!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) { detach(); return false; } // setup the first event data for the primary thread threads_.insert(pid, thread_info()); pid_ = pid; active_thread_ = pid; threads_[pid].status = status; return true; } while(0); break; } } //------------------------------------------------------------------------------ // Name: set_active_thread // Desc: //------------------------------------------------------------------------------ void DebuggerCore::set_active_thread(edb::tid_t tid) { Q_ASSERT(threads_.contains(tid)); active_thread_ = tid; } //------------------------------------------------------------------------------ // Name: create_state // Desc: //------------------------------------------------------------------------------ IState *DebuggerCore::create_state() const { return new PlatformState; } //------------------------------------------------------------------------------ // Name: enumerate_processes // Desc: //------------------------------------------------------------------------------ QMap DebuggerCore::enumerate_processes() const { QMap ret; char ebuffer[_POSIX2_LINE_MAX]; int numprocs; if(kvm_t *const kaccess = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, ebuffer)) { if(struct kinfo_proc *const kprocaccess = kvm_getprocs(kaccess, KERN_PROC_ALL, 0, sizeof *kprocaccess, &numprocs)) { for(int i = 0; i < numprocs; ++i) { ProcessInfo procInfo; procInfo.pid = kprocaccess[i].p_pid; procInfo.uid = kprocaccess[i].p_uid; procInfo.name = kprocaccess[i].p_comm; ret.insert(procInfo.pid, procInfo); } } kvm_close(kaccess); } else { QMessageBox::warning(0, "Error Listing Processes", ebuffer); } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::process_exe(edb::pid_t pid) const { QString ret; char errbuf[_POSIX2_LINE_MAX]; if(kvm_t *kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) { char p_comm[KI_MAXCOMLEN] = ""; int rc; if(struct kinfo_proc *const proc = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &rc)) { memcpy(p_comm, proc->p_comm, sizeof(p_comm)); } kvm_close(kd); return p_comm; } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::process_cwd(edb::pid_t pid) const { // TODO: implement this return QString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::pid_t DebuggerCore::parent_pid(edb::pid_t pid) const { edb::pid_t ret = 0; char errbuf[_POSIX2_LINE_MAX]; if(kvm_t *kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) { int rc; struct kinfo_proc *const proc = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof *proc, &rc); ret = proc->p_ppid; kvm_close(kd); } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList> DebuggerCore::memory_regions() const { QList> regions; if(pid_ != 0) { char err_buf[_POSIX2_LINE_MAX]; if(kvm_t *const kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, err_buf)) { int rc; struct kinfo_proc *const proc = kvm_getprocs(kd, KERN_PROC_PID, pid_, sizeof *proc, &rc); Q_ASSERT(proc); struct vmspace vmsp; kvm_read(kd, proc->p_vmspace, &vmsp, sizeof vmsp); #if defined(OpenBSD) && (OpenBSD > 201205) uvm_map_addr root; RB_INIT(&root); if (load_vmmap_entries(kd, (u_long)RB_ROOT(&vmsp.vm_map.addr), &RB_ROOT(&root), NULL) == -1) goto do_unload; struct vm_map_entry *e; RB_FOREACH(e, uvm_map_addr, &root) { const edb::address_t start = e->start; const edb::address_t end = e->end; const edb::address_t base = e->offset; const QString name = QString(); const IRegion::permissions_t permissions = ((e->protection & VM_PROT_READ) ? PROT_READ : 0) | ((e->protection & VM_PROT_WRITE) ? PROT_WRITE : 0) | ((e->protection & VM_PROT_EXECUTE) ? PROT_EXEC : 0); regions.push_back(std::make_shared(start, end, base, name, permissions)); } do_unload: unload_vmmap_entries(RB_ROOT(&root)); #else struct vm_map_entry e; if(vmsp.vm_map.header.next != 0) { kvm_read(kd, (u_long)vmsp.vm_map.header.next, &e, sizeof(e)); while(e.next != vmsp.vm_map.header.next) { const edb::address_t start = e.start; const edb::address_t end = e.end; const edb::address_t base = e.offset; const QString name = QString(); const IRegion::permissions_t permissions = ((e.protection & VM_PROT_READ) ? PROT_READ : 0) | ((e.protection & VM_PROT_WRITE) ? PROT_WRITE : 0) | ((e.protection & VM_PROT_EXECUTE) ? PROT_EXEC : 0); regions.push_back(std::make_shared(start, end, base, name, permissions)); kvm_read(kd, (u_long)e.next, &e, sizeof(e)); } } #endif kvm_close(kd); } else { fprintf(stderr, "sync: %s\n", err_buf); return QList>(); } } return regions; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList DebuggerCore::process_args(edb::pid_t pid) const { QList ret; if(pid != 0) { // TODO: assert attached! char errbuf[_POSIX2_LINE_MAX]; if(kvm_t *kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) { int rc; if(struct kinfo_proc *const proc = kvm_getprocs(kd, KERN_PROC_PID, sizeof *proc, pid, &rc)) { char **argv = kvm_getargv(kd, proc, 0); char **p = argv; while(*p) { ret << *p++; } } kvm_close(kd); } } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t DebuggerCore::process_code_address() const { qDebug() << "TODO: implement DebuggerCore::process_code_address"; return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t DebuggerCore::process_data_address() const { qDebug() << "TODO: implement DebuggerCore::process_data_address"; return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList DebuggerCore::loaded_modules() const { QList modules; qDebug() << "TODO: implement DebuggerCore::loaded_modules"; return modules; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QDateTime DebuggerCore::process_start(edb::pid_t pid) const { qDebug() << "TODO: implement DebuggerCore::process_start"; return QDateTime(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ quint64 DebuggerCore::cpu_type() const { #ifdef EDB_X86 return edb::string_hash<'x', '8', '6'>::value; #elif defined(EDB_X86_64) return edb::string_hash<'x', '8', '6', '-', '6', '4'>::value; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::format_pointer(edb::address_t address) const { char buf[32]; #ifdef EDB_X86 qsnprintf(buf, sizeof(buf), "%08x", address); #elif defined(EDB_X86_64) qsnprintf(buf, sizeof(buf), "%016llx", address); #endif return buf; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::stack_pointer() const { #ifdef EDB_X86 return "esp"; #elif defined(EDB_X86_64) return "rsp"; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::frame_pointer() const { #ifdef EDB_X86 return "ebp"; #elif defined(EDB_X86_64) return "rbp"; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::instruction_pointer() const { #ifdef EDB_X86 return "eip"; #elif defined(EDB_X86_64) return "rip"; #endif } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(DebuggerCore, DebuggerCore) #endif } edb-debugger-1.0.0/plugins/DebuggerCore/unix/DebuggerCoreUNIX.h0000644000175000017500000000330513273160654023565 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DEBUGGERCOREUNIX_20090529_H_ #define DEBUGGERCOREUNIX_20090529_H_ #include "DebuggerCoreBase.h" #include class Status; namespace DebuggerCorePlugin { namespace native { int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); int select_ex(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, quint64 msecs); pid_t waitpid(pid_t pid, int *status, int options); ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); bool wait_for_sigchld(int msecs); } class DebuggerCoreUNIX : public DebuggerCoreBase { public: DebuggerCoreUNIX(); virtual ~DebuggerCoreUNIX() = default; protected: Status execute_process(const QString &path, const QString &cwd, const QList &args); public: virtual QMap exceptions() const; virtual QString exceptionName(qlonglong value); virtual qlonglong exceptionValue(const QString &name); }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/osx/0000755000175000017500000000000013273160654021163 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/unix/osx/DebuggerCore.h0000644000175000017500000000613313273160654023674 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DEBUGGERCORE_20090529_H_ #define DEBUGGERCORE_20090529_H_ #include "DebuggerCoreUNIX.h" #include namespace DebuggerCore { class DebuggerCore : public DebuggerCoreUNIX { Q_OBJECT Q_INTERFACES(IDebugger) Q_CLASSINFO("author", "Evan Teran") Q_CLASSINFO("url", "http://www.codef00.com") public: DebuggerCore(); virtual ~DebuggerCore(); public: virtual edb::address_t page_size() const; virtual bool has_extension(quint64 ext) const; virtual std::shared_ptr wait_debug_event(int msecs); virtual bool attach(edb::pid_t pid); virtual void detach(); virtual void kill(); virtual void pause(); virtual void resume(edb::EVENT_STATUS status); virtual void step(edb::EVENT_STATUS status); virtual void get_state(State *state); virtual void set_state(const State &state); virtual bool open(const QString &path, const QString &cwd, const QList &args, const QString &tty); public: // thread support stuff (optional) virtual QList thread_ids() const { return threads_.keys(); } virtual edb::tid_t active_thread() const { return active_thread_; } virtual void set_active_thread(edb::tid_t); public: virtual QList> memory_regions() const; virtual edb::address_t process_code_address() const; virtual edb::address_t process_data_address() const; public: // process properties virtual QList process_args(edb::pid_t pid) const; virtual QString process_exe(edb::pid_t pid) const; virtual QString process_cwd(edb::pid_t pid) const; virtual edb::pid_t parent_pid(edb::pid_t pid) const; virtual QDateTime process_start(edb::pid_t pid) const; virtual quint64 cpu_type() const; public: virtual IState *create_state() const; private: virtual QMap enumerate_processes() const; virtual QList loaded_modules() const; public: virtual QString stack_pointer() const; virtual QString frame_pointer() const; virtual QString instruction_pointer() const; public: virtual QString format_pointer(edb::address_t address) const; private: virtual long read_data(edb::address_t address, bool *ok); virtual bool write_data(edb::address_t address, long value); private: struct thread_info { public: thread_info() : status(0) { } thread_info(int s) : status(s) { } int status; }; typedef QHash threadmap_t; edb::address_t page_size_; threadmap_t threads_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/osx/PlatformProcess.cpp0000644000175000017500000000133513273160654025014 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformProcess.h" edb-debugger-1.0.0/plugins/DebuggerCore/unix/osx/PlatformEvent.h0000644000175000017500000000302613273160654024123 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_EVENT_20121005_H_ #define PLATFORM_EVENT_20121005_H_ #include #include "IDebugEvent.h" namespace DebuggerCore { class PlatformEvent : IDebugEvent { Q_DECLARE_TR_FUNCTIONS(PlatformEvent) friend class DebuggerCore; public: PlatformEvent(); public: virtual PlatformEvent *clone() const; public: virtual Message error_description() const; virtual REASON reason() const; virtual TRAP_REASON trap_reason() const; virtual bool exited() const; virtual bool is_error() const; virtual bool is_kill() const; virtual bool is_stop() const; virtual bool is_trap() const; virtual bool terminated() const; virtual bool stopped() const; virtual edb::pid_t process() const; virtual edb::tid_t thread() const; virtual int code() const; private: int status; edb::pid_t pid; edb::tid_t tid; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/osx/PlatformRegion.h0000644000175000017500000000350013273160654024262 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_REGION_20120330_H_ #define PLATFORM_REGION_20120330_H_ #include "IRegion.h" #include #include namespace DebuggerCore { class PlatformRegion : public IRegion { Q_DECLARE_TR_FUNCTIONS(PlatformRegion) public: PlatformRegion(edb::address_t start, edb::address_t end, edb::address_t base, const QString &name, permissions_t permissions); virtual ~PlatformRegion(); public: virtual IRegion *clone() const; public: virtual bool accessible() const; virtual bool readable() const; virtual bool writable() const; virtual bool executable() const; virtual edb::address_t size() const; public: virtual void set_permissions(bool read, bool write, bool execute); virtual void set_start(edb::address_t address); virtual void set_end(edb::address_t address); public: virtual edb::address_t start() const; virtual edb::address_t end() const; virtual edb::address_t base() const; virtual QString name() const; virtual permissions_t permissions() const; private: edb::address_t start_; edb::address_t end_; edb::address_t base_; QString name_; permissions_t permissions_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/osx/PlatformRegion.cpp0000644000175000017500000000450713273160654024625 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformRegion.h" #include "MemoryRegions.h" #include "edb.h" #include "IDebugger.h" #include "State.h" #include "IDebugEventHandler.h" #include #include #include namespace DebuggerCore { PlatformRegion::PlatformRegion(edb::address_t start, edb::address_t end, edb::address_t base, const QString &name, permissions_t permissions) : start_(start), end_(end), base_(base), name_(name), permissions_(permissions) { } PlatformRegion::~PlatformRegion() { } IRegion *PlatformRegion::clone() const { return new PlatformRegion(start_, end_, base_, name_, permissions_); } bool PlatformRegion::accessible() const { return readable() || writable() || executable(); } bool PlatformRegion::readable() const { return (permissions_ & PROT_READ) != 0; } bool PlatformRegion::writable() const { return (permissions_ & PROT_WRITE) != 0; } bool PlatformRegion::executable() const { return (permissions_ & PROT_EXEC) != 0; } edb::address_t PlatformRegion::size() const { return end_ - start_; } void PlatformRegion::set_permissions(bool read, bool write, bool execute) { Q_UNUSED(read); Q_UNUSED(write); Q_UNUSED(execute); } edb::address_t PlatformRegion::start() const { return start_; } edb::address_t PlatformRegion::end() const { return end_; } edb::address_t PlatformRegion::base() const { return base_; } QString PlatformRegion::name() const { return name_; } IRegion::permissions_t PlatformRegion::permissions() const { return permissions_; } void PlatformRegion::set_start(edb::address_t address) { start_ = address; } void PlatformRegion::set_end(edb::address_t address) { end_ = address; } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/osx/PlatformProcess.h0000644000175000017500000000153213273160654024460 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATOFORM_PROCESS_20150517_H_ #define PLATOFORM_PROCESS_20150517_H_ #include "IProcess.h" class PlatformProcess : public IProcess { }; #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/osx/PlatformState.cpp0000644000175000017500000005424713273160654024470 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformState.h" #if __DARWIN_UNIX03 #define REG(x) __ ## x #else #define REG(x) x #endif namespace DebuggerCore { //------------------------------------------------------------------------------ // Name: PlatformState // Desc: //------------------------------------------------------------------------------ PlatformState::PlatformState() { memset(&thread_state_, 0, sizeof(thread_state_)); memset(&float_state_, 0, sizeof(float_state_)); memset(&debug_state_, 0, sizeof(debug_state_)); memset(&exception_state_, 0, sizeof(exception_state_)); } //------------------------------------------------------------------------------ // Name: PlatformState::clone // Desc: makes a copy of the state object //------------------------------------------------------------------------------ IState *PlatformState::clone() const { return new PlatformState(*this); } //------------------------------------------------------------------------------ // Name: flags_to_string // Desc: returns the flags in a string form appropriate for this platform //------------------------------------------------------------------------------ QString PlatformState::flags_to_string(edb::reg_t flags) const { char buf[14]; qsnprintf( buf, sizeof(buf), "%c %c %c %c %c %c %c", ((flags & 0x001) ? 'C' : 'c'), ((flags & 0x004) ? 'P' : 'p'), ((flags & 0x010) ? 'A' : 'a'), ((flags & 0x040) ? 'Z' : 'z'), ((flags & 0x080) ? 'S' : 's'), ((flags & 0x400) ? 'D' : 'd'), ((flags & 0x800) ? 'O' : 'o')); return buf; } //------------------------------------------------------------------------------ // Name: flags_to_string // Desc: returns the flags in a string form appropriate for this platform //------------------------------------------------------------------------------ QString PlatformState::flags_to_string() const { return flags_to_string(flags()); } //------------------------------------------------------------------------------ // Name: value // Desc: returns a Register object which represents the register with the name // supplied //------------------------------------------------------------------------------ Register PlatformState::value(const QString ®) const { const QString lreg = reg.toLower(); #if defined(EDB_X86) if(lreg == "eax") return Register("eax", thread_state_.REG(eax), Register::TYPE_GPR); else if(lreg == "ebx") return Register("ebx", thread_state_.REG(ebx), Register::TYPE_GPR); else if(lreg == "ecx") return Register("ecx", thread_state_.REG(ecx), Register::TYPE_GPR); else if(lreg == "edx") return Register("edx", thread_state_.REG(edx), Register::TYPE_GPR); else if(lreg == "ebp") return Register("ebp", thread_state_.REG(ebp), Register::TYPE_GPR); else if(lreg == "esp") return Register("esp", thread_state_.REG(esp), Register::TYPE_GPR); else if(lreg == "esi") return Register("esi", thread_state_.REG(esi), Register::TYPE_GPR); else if(lreg == "edi") return Register("edi", thread_state_.REG(edi), Register::TYPE_GPR); else if(lreg == "eip") return Register("eip", thread_state_.REG(eip), Register::TYPE_IP); else if(lreg == "ax") return Register("ax", thread_state_.REG(eax) & 0xffff, Register::TYPE_GPR); else if(lreg == "bx") return Register("bx", thread_state_.REG(ebx) & 0xffff, Register::TYPE_GPR); else if(lreg == "cx") return Register("cx", thread_state_.REG(ecx) & 0xffff, Register::TYPE_GPR); else if(lreg == "dx") return Register("dx", thread_state_.REG(edx) & 0xffff, Register::TYPE_GPR); else if(lreg == "bp") return Register("bp", thread_state_.REG(ebp) & 0xffff, Register::TYPE_GPR); else if(lreg == "sp") return Register("sp", thread_state_.REG(esp) & 0xffff, Register::TYPE_GPR); else if(lreg == "si") return Register("si", thread_state_.REG(esi) & 0xffff, Register::TYPE_GPR); else if(lreg == "di") return Register("di", thread_state_.REG(edi) & 0xffff, Register::TYPE_GPR); else if(lreg == "al") return Register("al", thread_state_.REG(eax) & 0xff, Register::TYPE_GPR); else if(lreg == "bl") return Register("bl", thread_state_.REG(ebx) & 0xff, Register::TYPE_GPR); else if(lreg == "cl") return Register("cl", thread_state_.REG(ecx) & 0xff, Register::TYPE_GPR); else if(lreg == "dl") return Register("dl", thread_state_.REG(edx) & 0xff, Register::TYPE_GPR); else if(lreg == "ah") return Register("ah", (thread_state_.REG(eax) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bh") return Register("bh", (thread_state_.REG(ebx) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "ch") return Register("ch", (thread_state_.REG(ecx) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dh") return Register("dh", (thread_state_.REG(edx) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "cs") return Register("cs", thread_state_.REG(cs), Register::TYPE_SEG); else if(lreg == "ds") return Register("ds", thread_state_.REG(ds), Register::TYPE_SEG); else if(lreg == "es") return Register("es", thread_state_.REG(es), Register::TYPE_SEG); else if(lreg == "fs") return Register("fs", thread_state_.REG(fs), Register::TYPE_SEG); else if(lreg == "gs") return Register("gs", thread_state_.REG(gs), Register::TYPE_SEG); else if(lreg == "ss") return Register("ss", thread_state_.REG(ss), Register::TYPE_SEG); else if(lreg == "fs_base") return Register("fs_base", 0 /* TODO fs_base */, Register::TYPE_SEG); else if(lreg == "gs_base") return Register("gs_base", 0 /* TODO gs_base */, Register::TYPE_SEG); else if(lreg == "eflags") return Register("eflags", thread_state_.REG(eflags), Register::TYPE_COND); #elif defined(EDB_X86_64) if(lreg == "rax") return Register("rax", thread_state_.REG(rax), Register::TYPE_GPR); else if(lreg == "rbx") return Register("rbx", thread_state_.REG(rbx), Register::TYPE_GPR); else if(lreg == "rcx") return Register("rcx", thread_state_.REG(rcx), Register::TYPE_GPR); else if(lreg == "rdx") return Register("rdx", thread_state_.REG(rdx), Register::TYPE_GPR); else if(lreg == "rbp") return Register("rbp", thread_state_.REG(rbp), Register::TYPE_GPR); else if(lreg == "rsp") return Register("rsp", thread_state_.REG(rsp), Register::TYPE_GPR); else if(lreg == "rsi") return Register("rsi", thread_state_.REG(rsi), Register::TYPE_GPR); else if(lreg == "rdi") return Register("rdi", thread_state_.REG(rdi), Register::TYPE_GPR); else if(lreg == "rip") return Register("rip", thread_state_.REG(rip), Register::TYPE_IP); else if(lreg == "r8") return Register("r8", thread_state_.REG(r8), Register::TYPE_GPR); else if(lreg == "r9") return Register("r9", thread_state_.REG(r9), Register::TYPE_GPR); else if(lreg == "r10") return Register("r10", thread_state_.REG(r10), Register::TYPE_GPR); else if(lreg == "r11") return Register("r11", thread_state_.REG(r11), Register::TYPE_GPR); else if(lreg == "r12") return Register("r12", thread_state_.REG(r12), Register::TYPE_GPR); else if(lreg == "r13") return Register("r13", thread_state_.REG(r13), Register::TYPE_GPR); else if(lreg == "r14") return Register("r14", thread_state_.REG(r14), Register::TYPE_GPR); else if(lreg == "r15") return Register("r15", thread_state_.REG(r15), Register::TYPE_GPR); else if(lreg == "eax") return Register("eax", thread_state_.REG(rax) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ebx") return Register("ebx", thread_state_.REG(rbx) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ecx") return Register("ecx", thread_state_.REG(rcx) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "edx") return Register("edx", thread_state_.REG(rdx) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ebp") return Register("ebp", thread_state_.REG(rbp) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "esp") return Register("esp", thread_state_.REG(rsp) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "esi") return Register("esi", thread_state_.REG(rsi) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "edi") return Register("edi", thread_state_.REG(rdi) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r8d") return Register("r8d", thread_state_.REG(r8) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r9d") return Register("r9d", thread_state_.REG(r9) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r10d") return Register("r10d", thread_state_.REG(r10) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r11d") return Register("r11d", thread_state_.REG(r11) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r12d") return Register("r12d", thread_state_.REG(r12) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r13d") return Register("r13d", thread_state_.REG(r13) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r14d") return Register("r14d", thread_state_.REG(r14) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r15d") return Register("r15d", thread_state_.REG(r15) & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ax") return Register("ax", thread_state_.REG(rax) & 0xffff, Register::TYPE_GPR); else if(lreg == "bx") return Register("bx", thread_state_.REG(rbx) & 0xffff, Register::TYPE_GPR); else if(lreg == "cx") return Register("cx", thread_state_.REG(rcx) & 0xffff, Register::TYPE_GPR); else if(lreg == "dx") return Register("dx", thread_state_.REG(rdx) & 0xffff, Register::TYPE_GPR); else if(lreg == "bp") return Register("bp", thread_state_.REG(rbp) & 0xffff, Register::TYPE_GPR); else if(lreg == "sp") return Register("sp", thread_state_.REG(rsp) & 0xffff, Register::TYPE_GPR); else if(lreg == "si") return Register("si", thread_state_.REG(rsi) & 0xffff, Register::TYPE_GPR); else if(lreg == "di") return Register("di", thread_state_.REG(rdi) & 0xffff, Register::TYPE_GPR); else if(lreg == "r8w") return Register("r8w", thread_state_.REG(r8) & 0xffff, Register::TYPE_GPR); else if(lreg == "r9w") return Register("r9w", thread_state_.REG(r9) & 0xffff, Register::TYPE_GPR); else if(lreg == "r10w") return Register("r10w", thread_state_.REG(r10) & 0xffff, Register::TYPE_GPR); else if(lreg == "r11w") return Register("r11w", thread_state_.REG(r11) & 0xffff, Register::TYPE_GPR); else if(lreg == "r12w") return Register("r12w", thread_state_.REG(r12) & 0xffff, Register::TYPE_GPR); else if(lreg == "r13w") return Register("r13w", thread_state_.REG(r13) & 0xffff, Register::TYPE_GPR); else if(lreg == "r14w") return Register("r14w", thread_state_.REG(r14) & 0xffff, Register::TYPE_GPR); else if(lreg == "r15w") return Register("r15w", thread_state_.REG(r15) & 0xffff, Register::TYPE_GPR); else if(lreg == "al") return Register("al", thread_state_.REG(rax) & 0xff, Register::TYPE_GPR); else if(lreg == "bl") return Register("bl", thread_state_.REG(rbx) & 0xff, Register::TYPE_GPR); else if(lreg == "cl") return Register("cl", thread_state_.REG(rcx) & 0xff, Register::TYPE_GPR); else if(lreg == "dl") return Register("dl", thread_state_.REG(rdx) & 0xff, Register::TYPE_GPR); else if(lreg == "ah") return Register("ah", (thread_state_.REG(rax) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bh") return Register("bh", (thread_state_.REG(rbx) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "ch") return Register("ch", (thread_state_.REG(rcx) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dh") return Register("dh", (thread_state_.REG(rdx) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "spl") return Register("spl", (thread_state_.REG(rsp) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bpl") return Register("bpl", (thread_state_.REG(rbp) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "sil") return Register("sil", (thread_state_.REG(rsi) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dil") return Register("dil", (thread_state_.REG(rdi) >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "r8b") return Register("r8b", thread_state_.REG(r8) & 0xff, Register::TYPE_GPR); else if(lreg == "r9b") return Register("r9b", thread_state_.REG(r9) & 0xff, Register::TYPE_GPR); else if(lreg == "r10b") return Register("r10b", thread_state_.REG(r10) & 0xff, Register::TYPE_GPR); else if(lreg == "r11b") return Register("r11b", thread_state_.REG(r11) & 0xff, Register::TYPE_GPR); else if(lreg == "r12b") return Register("r12b", thread_state_.REG(r12) & 0xff, Register::TYPE_GPR); else if(lreg == "r13b") return Register("r13b", thread_state_.REG(r13) & 0xff, Register::TYPE_GPR); else if(lreg == "r14b") return Register("r14b", thread_state_.REG(r14) & 0xff, Register::TYPE_GPR); else if(lreg == "r15b") return Register("r15b", thread_state_.REG(r15) & 0xff, Register::TYPE_GPR); else if(lreg == "cs") return Register("cs", thread_state_.REG(cs), Register::TYPE_SEG); else if(lreg == "fs") return Register("fs", thread_state_.REG(fs), Register::TYPE_SEG); else if(lreg == "gs") return Register("gs", thread_state_.REG(gs), Register::TYPE_SEG); else if(lreg == "fs_base") return Register("fs_base", 0 /* TODO fs_base */, Register::TYPE_SEG); else if(lreg == "gs_base") return Register("gs_base", 0 /* TODO gs_base */, Register::TYPE_SEG); else if(lreg == "rflags") return Register("rflags", thread_state_.REG(rflags), Register::TYPE_COND); #endif return Register(); } //------------------------------------------------------------------------------ // Name: frame_pointer // Desc: returns what is conceptually the frame pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::frame_pointer() const { #if defined(EDB_X86) return thread_state_.REG(ebp); #elif defined(EDB_X86_64) return thread_state_.REG(rbp); #endif } //------------------------------------------------------------------------------ // Name: instruction_pointer // Desc: returns the instruction pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::instruction_pointer() const { #if defined(EDB_X86) return thread_state_.REG(eip); #elif defined(EDB_X86_64) return thread_state_.REG(rip); #endif } //------------------------------------------------------------------------------ // Name: stack_pointer // Desc: returns the stack pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::stack_pointer() const { #if defined(EDB_X86) return thread_state_.REG(esp); #elif defined(EDB_X86_64) return thread_state_.REG(rsp); #endif } //------------------------------------------------------------------------------ // Name: debug_register // Desc: //------------------------------------------------------------------------------ edb::reg_t PlatformState::debug_register(int n) const { switch(n) { case 0: return debug_state_.REG(dr0); case 1: return debug_state_.REG(dr1); case 2: return debug_state_.REG(dr2); case 3: return debug_state_.REG(dr3); case 4: return debug_state_.REG(dr4); case 5: return debug_state_.REG(dr5); case 6: return debug_state_.REG(dr6); case 7: return debug_state_.REG(dr7); } return 0; } //------------------------------------------------------------------------------ // Name: flags // Desc: //------------------------------------------------------------------------------ edb::reg_t PlatformState::flags() const { #if defined(EDB_X86) return thread_state_.REG(eflags); #elif defined(EDB_X86_64) return thread_state_.REG(rflags); #endif } //------------------------------------------------------------------------------ // Name: fpu_register // Desc: //------------------------------------------------------------------------------ long double PlatformState::fpu_register(int n) const { /* switch(n) { case 0: return static_cast(float_state_.REG(fpu_stmm0).REG(mmst_reg)); case 1: return static_cast(float_state_.REG(fpu_stmm1).REG(mmst_reg)); case 2: return static_cast(float_state_.REG(fpu_stmm2).REG(mmst_reg)); case 3: return static_cast(float_state_.REG(fpu_stmm3).REG(mmst_reg)); case 4: return static_cast(float_state_.REG(fpu_stmm4).REG(mmst_reg)); case 5: return static_cast(float_state_.REG(fpu_stmm5).REG(mmst_reg)); case 6: return static_cast(float_state_.REG(fpu_stmm6).REG(mmst_reg)); case 7: return static_cast(float_state_.REG(fpu_stmm7).REG(mmst_reg)); } */ return 0.0; } //------------------------------------------------------------------------------ // Name: adjust_stack // Desc: //------------------------------------------------------------------------------ void PlatformState::adjust_stack(int bytes) { #if defined(EDB_X86) thread_state_.REG(esp) += bytes; #elif defined(EDB_X86_64) thread_state_.REG(rsp) += bytes; #endif } //------------------------------------------------------------------------------ // Name: clear // Desc: //------------------------------------------------------------------------------ void PlatformState::clear() { memset(&thread_state_, 0, sizeof(thread_state_)); memset(&float_state_, 0, sizeof(float_state_)); memset(&debug_state_, 0, sizeof(debug_state_)); memset(&exception_state_, 0, sizeof(exception_state_)); } //------------------------------------------------------------------------------ // Name: set_debug_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_debug_register(int n, edb::reg_t value) { switch(n) { case 0: debug_state_.REG(dr0) = value; break; case 1: debug_state_.REG(dr1) = value; break; case 2: debug_state_.REG(dr2) = value; break; case 3: debug_state_.REG(dr3) = value; break; case 4: debug_state_.REG(dr4) = value; break; case 5: debug_state_.REG(dr5) = value; break; case 6: debug_state_.REG(dr6) = value; break; case 7: debug_state_.REG(dr7) = value; break; default: break; } } //------------------------------------------------------------------------------ // Name: set_flags // Desc: //------------------------------------------------------------------------------ void PlatformState::set_flags(edb::reg_t flags) { #if defined(EDB_X86) thread_state_.REG(eflags) = flags; #elif defined(EDB_X86_64) thread_state_.REG(rflags) = flags; #endif } //------------------------------------------------------------------------------ // Name: set_instruction_pointer // Desc: //------------------------------------------------------------------------------ void PlatformState::set_instruction_pointer(edb::address_t value) { #if defined(EDB_X86) thread_state_.REG(eip) = value; #elif defined(EDB_X86_64) thread_state_.REG(rip) = value; #endif } //------------------------------------------------------------------------------ // Name: set_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_register(const QString &name, edb::reg_t value) { const QString lreg = name.toLower(); #if defined(EDB_X86) if(lreg == "eax") { thread_state_.REG(eax) = value; } else if(lreg == "ebx") { thread_state_.REG(ebx) = value; } else if(lreg == "ecx") { thread_state_.REG(ecx) = value; } else if(lreg == "edx") { thread_state_.REG(edx) = value; } else if(lreg == "ebp") { thread_state_.REG(ebp) = value; } else if(lreg == "esp") { thread_state_.REG(esp) = value; } else if(lreg == "esi") { thread_state_.REG(esi) = value; } else if(lreg == "edi") { thread_state_.REG(edi) = value; } else if(lreg == "eip") { thread_state_.REG(eip) = value; } else if(lreg == "cs") { thread_state_.REG(cs) = value; } else if(lreg == "ds") { thread_state_.REG(ds) = value; } else if(lreg == "es") { thread_state_.REG(es) = value; } else if(lreg == "fs") { thread_state_.REG(fs) = value; } else if(lreg == "gs") { thread_state_.REG(gs) = value; } else if(lreg == "ss") { thread_state_.REG(ss) = value; } else if(lreg == "eflags") { thread_state_.REG(eflags) = value; } #elif defined(EDB_X86_64) if(lreg == "rax") { thread_state_.REG(rax) = value; } else if(lreg == "rbx") { thread_state_.REG(rbx) = value; } else if(lreg == "rcx") { thread_state_.REG(rcx) = value; } else if(lreg == "rdx") { thread_state_.REG(rdx) = value; } else if(lreg == "rbp") { thread_state_.REG(rbp) = value; } else if(lreg == "rsp") { thread_state_.REG(rsp) = value; } else if(lreg == "rsi") { thread_state_.REG(rsi) = value; } else if(lreg == "rdi") { thread_state_.REG(rdi) = value; } else if(lreg == "r8") { thread_state_.REG(r8) = value; } else if(lreg == "r9") { thread_state_.REG(r9) = value; } else if(lreg == "r10") { thread_state_.REG(r10) = value; } else if(lreg == "r11") { thread_state_.REG(r11) = value; } else if(lreg == "r12") { thread_state_.REG(r12) = value; } else if(lreg == "r13") { thread_state_.REG(r13) = value; } else if(lreg == "r14") { thread_state_.REG(r14) = value; } else if(lreg == "r15") { thread_state_.REG(r15) = value; } else if(lreg == "rip") { thread_state_.REG(rip) = value; } else if(lreg == "cs") { thread_state_.REG(cs) = value; } else if(lreg == "fs") { thread_state_.REG(fs) = value; } else if(lreg == "gs") { thread_state_.REG(gs) = value; } else if(lreg == "rflags") { thread_state_.REG(rflags) = value; } #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ quint64 PlatformState::mmx_register(int n) const { Q_UNUSED(n); return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QByteArray PlatformState::xmm_register(int n) const { Q_UNUSED(n); return QByteArray(); } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/osx/PlatformState.h0000644000175000017500000000430113273160654024117 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORMSTATE_20110330_H_ #define PLATFORMSTATE_20110330_H_ #include "IState.h" #include "Types.h" #include #include namespace DebuggerCore { class PlatformState : public IState { friend class DebuggerCore; public: PlatformState(); public: virtual IState *clone() const; public: virtual QString flags_to_string() const; virtual QString flags_to_string(edb::reg_t flags) const; virtual Register value(const QString ®) const; virtual edb::address_t frame_pointer() const; virtual edb::address_t instruction_pointer() const; virtual edb::address_t stack_pointer() const; virtual edb::reg_t debug_register(int n) const; virtual edb::reg_t flags() const; virtual long double fpu_register(int n) const; virtual void adjust_stack(int bytes); virtual void clear(); virtual void set_debug_register(int n, edb::reg_t value); virtual void set_flags(edb::reg_t flags); virtual void set_instruction_pointer(edb::address_t value); virtual void set_register(const QString &name, edb::reg_t value); virtual quint64 mmx_register(int n) const; virtual QByteArray xmm_register(int n) const; private: #if defined(EDB_X86) x86_thread_state32_t thread_state_; x86_float_state32_t float_state_; x86_debug_state32_t debug_state_; x86_exception_state32_t exception_state_; #elif defined(EDB_X86_64) x86_thread_state64_t thread_state_; x86_float_state64_t float_state_; x86_debug_state64_t debug_state_; x86_exception_state64_t exception_state_; #endif }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/unix/osx/PlatformEvent.cpp0000644000175000017500000001673513273160654024471 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformEvent.h" #include "edb.h" #include #include #include #include #include #include // for the SIG* definitions namespace DebuggerCore { //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ PlatformEvent::PlatformEvent() : status(0), pid(-1), tid(-1) { } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ PlatformEvent *PlatformEvent::clone() const { return new PlatformEvent(*this); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::Message PlatformEvent::error_description() const { Q_ASSERT(is_error()); // TODO: figure out the fault address const edb::address_t fault_address = 0; switch(code()) { case SIGSEGV: return Message( tr("Illegal Access Fault"), tr( "

The debugged application encountered a segmentation fault.
The address 0x%1 could not be accessed.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

").arg(edb::v1::format_pointer(fault_address)) ); case SIGILL: return Message( tr("Illegal Instruction Fault"), tr( "

The debugged application attempted to execute an illegal instruction.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); case SIGFPE: // TODO: figure out the fault code for FPU stuff switch(0) { case FPE_INTDIV: return Message( tr("Divide By Zero"), tr( "

The debugged application tried to divide an integer value by an integer divisor of zero.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); default: return Message( tr("Floating Point Exception"), tr( "

The debugged application encountered a floating-point exception.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); } case SIGABRT: return Message( tr("Application Aborted"), tr( "

The debugged application has aborted.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); case SIGBUS: return Message( tr("Bus Error"), tr( "

The debugged application tried to read or write data that is misaligned.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); #ifdef SIGSTKFLT case SIGSTKFLT: return Message( tr("Stack Fault"), tr( "

The debugged application encountered a stack fault.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); #endif case SIGPIPE: return Message( tr("Broken Pipe Fault"), tr( "

The debugged application encountered a broken pipe fault.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

") ); default: return Message(); } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::REASON PlatformEvent:: reason() const { // this basically converts our value into a 'switchable' value for convenience if(stopped()) { return EVENT_STOPPED; } else if(terminated()) { return EVENT_TERMINATED; } else if(exited()) { return EVENT_EXITED; } else { return EVENT_UNKNOWN; } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ IDebugEvent::TRAP_REASON PlatformEvent::trap_reason() const { // TODO: figure out how to detect if it is a step return TRAP_BREAKPOINT; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::exited() const { return WIFEXITED(status) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_error() const { if(stopped()) { switch(code()) { case SIGTRAP: case SIGSTOP: return false; case SIGSEGV: case SIGILL: case SIGFPE: case SIGABRT: case SIGBUS: #ifdef SIGSTKFLT case SIGSTKFLT: #endif case SIGPIPE: return true; default: return false; } } else { return false; } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_kill() const { return stopped() && code() == SIGKILL; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_stop() const { return stopped() && code() == SIGSTOP; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::is_trap() const { return stopped() && code() == SIGTRAP; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::terminated() const { return WIFSIGNALED(status) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool PlatformEvent::stopped() const { return WIFSTOPPED(status) != 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ edb::pid_t PlatformEvent::process() const { return pid; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ edb::tid_t PlatformEvent::thread() const { return tid; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ int PlatformEvent::code() const { if(stopped()) { return WSTOPSIG(status); } if(terminated()) { return WTERMSIG(status); } if(exited()) { return WEXITSTATUS(status); } return 0; } } edb-debugger-1.0.0/plugins/DebuggerCore/unix/osx/DebuggerCore.cpp0000644000175000017500000006047313273160654024236 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "DebuggerCore.h" #include "PlatformEvent.h" #include "PlatformRegion.h" #include "PlatformState.h" #include "State.h" #include "string_hash.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DebuggerCore { namespace { int resume_code(int status) { if(WIFSIGNALED(status)) { return WTERMSIG(status); } else if(WIFSTOPPED(status)) { return WSTOPSIG(status); } return 0; } } //------------------------------------------------------------------------------ // Name: DebuggerCore // Desc: constructor //------------------------------------------------------------------------------ DebuggerCore::DebuggerCore() { page_size_ = 0x1000; } //------------------------------------------------------------------------------ // Name: ~DebuggerCore // Desc: //------------------------------------------------------------------------------ DebuggerCore::~DebuggerCore() { detach(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::has_extension(quint64 ext) const { return false; } //------------------------------------------------------------------------------ // Name: page_size // Desc: returns the size of a page on this system //------------------------------------------------------------------------------ edb::address_t DebuggerCore::page_size() const { return page_size_; } //------------------------------------------------------------------------------ // Name: wait_debug_event // Desc: waits for a debug event, secs is a timeout (but is not yet respected) // ok will be set to false if the timeout expires //------------------------------------------------------------------------------ std::shared_ptr DebuggerCore::wait_debug_event(int msecs) { if(attached()) { int status; bool timeout; const edb::tid_t tid = native::waitpid_timeout(pid(), &status, 0, msecs, &timeout); if(!timeout) { if(tid > 0) { // normal event auto e = std::make_shared(); e->pid = pid(); e->tid = tid; e->status = status; active_thread_ = tid; threads_[tid].status = status; return e; } } } return nullptr; } //------------------------------------------------------------------------------ // Name: read_data // Desc: //------------------------------------------------------------------------------ long DebuggerCore::read_data(edb::address_t address, bool *ok) { Q_ASSERT(ok); mach_port_t task; kern_return_t err = task_for_pid(mach_task_self(), pid(), &task); if(err != KERN_SUCCESS) { qDebug("task_for_pid() failed with %x [%d]", err, pid()); *ok = false; return -1; } long x; vm_size_t size; *ok = vm_read_overwrite(task, address, sizeof(long), (vm_address_t)&x, &size) == 0; return x; } //------------------------------------------------------------------------------ // Name: write_data // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::write_data(edb::address_t address, long value) { return ptrace(PT_WRITE_D, pid(), (char *)address, value) != -1; } //------------------------------------------------------------------------------ // Name: attach // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::attach(edb::pid_t pid) { detach(); const long ret = ptrace(PT_ATTACH, pid, 0, 0); if(ret == 0) { pid_ = pid; active_thread_ = pid; threads_.clear(); threads_.insert(pid, thread_info()); // TODO: attach to all of the threads } return ret == 0; } //------------------------------------------------------------------------------ // Name: detach // Desc: //------------------------------------------------------------------------------ void DebuggerCore::detach() { if(attached()) { // TODO: do i need to stop each thread first, and wait for them? clear_breakpoints(); for(auto it = threads_.begin(); it != threads_.end(); ++it) { ptrace(PT_DETACH, it.key(), 0, 0); } pid_ = 0; threads_.clear(); } } //------------------------------------------------------------------------------ // Name: kill // Desc: //------------------------------------------------------------------------------ void DebuggerCore::kill() { if(attached()) { clear_breakpoints(); ptrace(PT_KILL, pid(), 0, 0); native::waitpid(pid(), 0, WAIT_ANY); pid_ = 0; threads_.clear(); } } //------------------------------------------------------------------------------ // Name: pause // Desc: stops *all* threads of a process //------------------------------------------------------------------------------ void DebuggerCore::pause() { if(attached()) { for(auto it = threads_.begin(); it != threads_.end(); ++it) { ::kill(it.key(), SIGSTOP); } } } //------------------------------------------------------------------------------ // Name: resume // Desc: //------------------------------------------------------------------------------ void DebuggerCore::resume(edb::EVENT_STATUS status) { // TODO: assert that we are paused if(attached()) { if(status != edb::DEBUG_STOP) { const edb::tid_t tid = active_thread(); const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(threads_[tid].status) : 0; ptrace(PT_CONTINUE, tid, reinterpret_cast(1), code); } } } //------------------------------------------------------------------------------ // Name: step // Desc: //------------------------------------------------------------------------------ void DebuggerCore::step(edb::EVENT_STATUS status) { // TODO: assert that we are paused if(attached()) { if(status != edb::DEBUG_STOP) { const edb::tid_t tid = active_thread(); const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(threads_[tid].status) : 0; ptrace(PT_STEP, tid, reinterpret_cast(1), code); } } } //------------------------------------------------------------------------------ // Name: get_state // Desc: //------------------------------------------------------------------------------ void DebuggerCore::get_state(State *state) { Q_ASSERT(state); // TODO: assert that we are paused auto state_impl = static_cast(state->impl_); if(attached()) { /* Get the mach task for the target process */ mach_port_t task; kern_return_t err = task_for_pid(mach_task_self(), pid(), &task); if(err != KERN_SUCCESS) { qDebug("task_for_pid() failed with %x [%d]", err, pid()); return; } /* Suspend the target process */ err = task_suspend(task); if(err != KERN_SUCCESS) { qDebug("task_suspend() failed"); return; } /* Get all threads in the specified task */ thread_act_port_array_t thread_list; mach_msg_type_number_t thread_count; err = task_threads(task, &thread_list, &thread_count); if(err != KERN_SUCCESS) { qDebug("task_threads() failed"); err = task_resume(task); if(err != KERN_SUCCESS) { qDebug("task_resume() failed"); } } Q_ASSERT(thread_count > 0); #ifdef EDB_X86 mach_msg_type_number_t state_count = x86_THREAD_STATE32_COUNT; const thread_state_flavor_t flavor = x86_THREAD_STATE32; const thread_state_flavor_t debug_flavor = x86_DEBUG_STATE32; const thread_state_flavor_t fpu_flavor = x86_FLOAT_STATE32; const thread_state_flavor_t exception_flavor = x86_EXCEPTION_STATE32; #elif defined(EDB_X86_64) mach_msg_type_number_t state_count = x86_THREAD_STATE64_COUNT; const thread_state_flavor_t flavor = x86_THREAD_STATE64; const thread_state_flavor_t debug_flavor = x86_DEBUG_STATE64; const thread_state_flavor_t fpu_flavor = x86_FLOAT_STATE64; const thread_state_flavor_t exception_flavor = x86_EXCEPTION_STATE64; #endif // TODO Get all threads, not just the first one. err = thread_get_state( thread_list[0], flavor, (thread_state_t)&state_impl->thread_state_, &state_count); if(err != KERN_SUCCESS) { qDebug("thread_get_state() failed with %.08x", err); err = task_resume(task); if(err != KERN_SUCCESS) { qDebug("task_resume() failed"); } return; } err = thread_get_state( thread_list[0], debug_flavor, (thread_state_t)&state_impl->debug_state_, &state_count); if(err != KERN_SUCCESS) { qDebug("thread_get_state() failed with %.08x", err); err = task_resume(task); if(err != KERN_SUCCESS) { qDebug("task_resume() failed"); } return; } err = thread_get_state( thread_list[0], fpu_flavor, (thread_state_t)&state_impl->float_state_, &state_count); if(err != KERN_SUCCESS) { qDebug("thread_get_state() failed with %.08x", err); err = task_resume(task); if(err != KERN_SUCCESS) { qDebug("task_resume() failed"); } return; } err = thread_get_state( thread_list[0], exception_flavor, (thread_state_t)&state_impl->exception_state_, &state_count); if(err != KERN_SUCCESS) { qDebug("thread_get_state() failed with %.08x", err); err = task_resume(task); if(err != KERN_SUCCESS) { qDebug("task_resume() failed"); } return; } } else { state->clear(); } } //------------------------------------------------------------------------------ // Name: set_state // Desc: //------------------------------------------------------------------------------ void DebuggerCore::set_state(const State &state) { // TODO: assert that we are paused auto state_impl = static_cast(state.impl_); if(attached()) { /* Get the mach task for the target process */ mach_port_t task; kern_return_t err = task_for_pid(mach_task_self(), pid(), &task); if(err != KERN_SUCCESS) { qDebug("task_for_pid() failed with %x [%d]", err, pid()); return; } /* Suspend the target process */ err = task_suspend(task); if(err != KERN_SUCCESS) { qDebug("task_suspend() failed"); } /* Get all threads in the specified task */ thread_act_port_array_t thread_list; mach_msg_type_number_t thread_count; err = task_threads(task, &thread_list, &thread_count); if(err != KERN_SUCCESS) { qDebug("task_threads() failed"); err = task_resume(task); if(err != KERN_SUCCESS) { qDebug("task_resume() failed"); } } Q_ASSERT(thread_count > 0); #ifdef EDB_X86 mach_msg_type_number_t state_count = x86_THREAD_STATE32_COUNT; const thread_state_flavor_t flavor = x86_THREAD_STATE32; const thread_state_flavor_t debug_flavor = x86_DEBUG_STATE32; //const thread_state_flavor_t fpu_flavor = x86_FLOAT_STATE32; //const thread_state_flavor_t exception_flavor = x86_EXCEPTION_STATE32; #elif defined(EDB_X86_64) mach_msg_type_number_t state_count = x86_THREAD_STATE64_COUNT; const thread_state_flavor_t flavor = x86_THREAD_STATE64; const thread_state_flavor_t debug_flavor = x86_DEBUG_STATE64; //const thread_state_flavor_t fpu_flavor = x86_FLOAT_STATE64; //const thread_state_flavor_t exception_flavor = x86_EXCEPTION_STATE64; #endif // TODO Set for specific thread, not first one err = thread_set_state( thread_list[0], flavor, (thread_state_t)&state_impl->thread_state_, state_count); if(err != KERN_SUCCESS) { qDebug("thread_set_state() failed with %.08x", err); err = task_resume(task); if(err != KERN_SUCCESS) { qDebug("task_resume() failed"); } return; } err = thread_set_state( thread_list[0], debug_flavor, (thread_state_t)&state_impl->debug_state_, state_count); if(err != KERN_SUCCESS) { qDebug("thread_set_state() failed with %.08x", err); err = task_resume(task); if(err != KERN_SUCCESS) { qDebug("task_resume() failed"); } return; } } } //------------------------------------------------------------------------------ // Name: open // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::open(const QString &path, const QString &cwd, const QList &args, const QString &tty) { detach(); pid_t pid; switch(pid = fork()) { case 0: // we are in the child now... // set ourselves (the child proc) up to be traced ptrace(PT_TRACE_ME, 0, 0, 0); // redirect it's I/O if(!tty.isEmpty()) { FILE *const std_out = freopen(qPrintable(tty), "r+b", stdout); FILE *const std_in = freopen(qPrintable(tty), "r+b", stdin); FILE *const std_err = freopen(qPrintable(tty), "r+b", stderr); Q_UNUSED(std_out); Q_UNUSED(std_in); Q_UNUSED(std_err); } // do the actual exec execute_process(path, cwd, args); // we should never get here! abort(); break; case -1: // error! pid_ = 0; return false; default: // parent do { threads_.clear(); int status; if(native::waitpid(pid, &status, 0) == -1) { return false; } // the very first event should be a STOP of type SIGTRAP if(!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) { detach(); return false; } // setup the first event data for the primary thread threads_.insert(pid, thread_info()); pid_ = pid; active_thread_ = pid; threads_[pid].status = status; return true; } while(0); break; } } //------------------------------------------------------------------------------ // Name: set_active_thread // Desc: //------------------------------------------------------------------------------ void DebuggerCore::set_active_thread(edb::tid_t tid) { Q_ASSERT(threads_.contains(tid)); active_thread_ = tid; } //------------------------------------------------------------------------------ // Name: create_state // Desc: //------------------------------------------------------------------------------ IState *DebuggerCore::create_state() const { return new PlatformState; } //------------------------------------------------------------------------------ // Name: enumerate_processes // Desc: //------------------------------------------------------------------------------ QMap DebuggerCore::enumerate_processes() const { QMap ret; static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; size_t length = 0; sysctl(const_cast(name), (sizeof(name) / sizeof(*name)) - 1, 0, &length, 0, 0); auto proc_info = static_cast(malloc(length)); sysctl(const_cast(name), (sizeof(name) / sizeof(*name)) - 1, proc_info, &length, 0, 0); size_t count = length / sizeof(struct kinfo_proc); for(size_t i = 0; i < count; ++i) { ProcessInfo procInfo; procInfo.pid = proc_info[i].kp_proc.p_pid; procInfo.uid = proc_info[i].kp_eproc.e_ucred.cr_uid; procInfo.name = proc_info[i].kp_proc.p_comm; ret.insert(procInfo.pid, procInfo); } free(proc_info); return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::process_exe(edb::pid_t pid) const { // TODO: implement this return QString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::process_cwd(edb::pid_t pid) const { // TODO: implement this return QString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::pid_t DebuggerCore::parent_pid(edb::pid_t pid) const { // TODO: implement this return -1; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList> DebuggerCore::memory_regions() const { #if 0 static const char * inheritance_strings[] = { "SHARE", "COPY", "NONE", "DONATE_COPY", }; static const char * behavior_strings[] = { "DEFAULT", "RANDOM", "SEQUENTIAL", "RESQNTL", "WILLNEED", "DONTNEED", }; #endif QList> regions; if(pid_ != 0) { task_t the_task; kern_return_t kr = task_for_pid(mach_task_self(), pid_, &the_task); if(kr != KERN_SUCCESS) { qDebug("task_for_pid failed"); return QList>(); } vm_size_t vmsize; vm_address_t address; vm_region_basic_info_data_64_t info; mach_msg_type_number_t info_count; vm_region_flavor_t flavor; memory_object_name_t object; kr = KERN_SUCCESS; address = 0; do { flavor = VM_REGION_BASIC_INFO_64; info_count = VM_REGION_BASIC_INFO_COUNT_64; kr = vm_region_64(the_task, &address, &vmsize, flavor, (vm_region_info_64_t)&info, &info_count, &object); if(kr == KERN_SUCCESS) { const edb::address_t start = address; const edb::address_t end = address + vmsize; const edb::address_t base = address; const QString name = QString(); const IRegion::permissions_t permissions = ((info.protection & VM_PROT_READ) ? PROT_READ : 0) | ((info.protection & VM_PROT_WRITE) ? PROT_WRITE : 0) | ((info.protection & VM_PROT_EXECUTE) ? PROT_EXEC : 0); regions.push_back(std::make_shared(start, end, base, name, permissions)); /* printf("%016llx-%016llx %8uK %c%c%c/%c%c%c %11s %6s %10s uwir=%hu sub=%u\n", address, (address + vmsize), (vmsize >> 10), (info.protection & VM_PROT_READ) ? 'r' : '-', (info.protection & VM_PROT_WRITE) ? 'w' : '-', (info.protection & VM_PROT_EXECUTE) ? 'x' : '-', (info.max_protection & VM_PROT_READ) ? 'r' : '-', (info.max_protection & VM_PROT_WRITE) ? 'w' : '-', (info.max_protection & VM_PROT_EXECUTE) ? 'x' : '-', inheritance_strings[info.inheritance], (info.shared) ? "shared" : "-", behavior_strings[info.behavior], info.user_wired_count, info.reserved); */ address += vmsize; } else if(kr != KERN_INVALID_ADDRESS) { if(the_task != MACH_PORT_NULL) { mach_port_deallocate(mach_task_self(), the_task); } return QList>(); } } while(kr != KERN_INVALID_ADDRESS); if(the_task != MACH_PORT_NULL) { mach_port_deallocate(mach_task_self(), the_task); } } return regions; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList DebuggerCore::process_args(edb::pid_t pid) const { QList ret; if(pid != 0) { // TODO: assert attached! qDebug() << "TODO: implement edb::v1::get_process_args"; } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t DebuggerCore::process_code_address() const { qDebug() << "TODO: implement DebuggerCore::process_code_address"; return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t DebuggerCore::process_data_address() const { qDebug() << "TODO: implement DebuggerCore::process_data_address"; return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList DebuggerCore::loaded_modules() const { QList modules; qDebug() << "TODO: implement DebuggerCore::loaded_modules"; return modules; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QDateTime DebuggerCore::process_start(edb::pid_t pid) const { qDebug() << "TODO: implement DebuggerCore::process_start"; return QDateTime(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ quint64 DebuggerCore::cpu_type() const { #ifdef EDB_X86 return edb::string_hash<'x', '8', '6'>::value; #elif defined(EDB_X86_64) return edb::string_hash<'x', '8', '6', '-', '6', '4'>::value; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::format_pointer(edb::address_t address) const { char buf[32]; #ifdef EDB_X86 qsnprintf(buf, sizeof(buf), "%08x", address); #elif defined(EDB_X86_64) qsnprintf(buf, sizeof(buf), "%016llx", address); #endif return buf; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::stack_pointer() const { #ifdef EDB_X86 return "esp"; #elif defined(EDB_X86_64) return "rsp"; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::frame_pointer() const { #ifdef EDB_X86 return "ebp"; #elif defined(EDB_X86_64) return "rbp"; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::instruction_pointer() const { #ifdef EDB_X86 return "eip"; #elif defined(EDB_X86_64) return "rip"; #endif } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(DebuggerCore, DebuggerCore) #endif } edb-debugger-1.0.0/plugins/DebuggerCore/unix/DebuggerCoreUNIX.cpp0000644000175000017500000002546013273160654024126 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ // this code is common to all unix variants (linux/bsd/osx) #include "DebuggerCoreUNIX.h" #include "edb.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_LINUX #include // being very conservative for now, technically this could be // as low as 2.6.22 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) #define USE_SIGTIMEDWAIT #endif #endif namespace DebuggerCorePlugin { namespace { struct Exception { qlonglong value; const char *const name; } Exceptions[] = { #ifdef SIGABRT { SIGABRT, "SIGABRT" }, #endif #ifdef SIGALRM { SIGALRM, "SIGALRM" }, #endif #ifdef SIGVTALRM { SIGVTALRM, "SIGVTALRM" }, #endif #ifdef SIGPROF { SIGPROF, "SIGPROF" }, #endif #ifdef SIGBUS { SIGBUS, "SIGBUS" }, #endif #ifdef SIGCHLD { SIGCHLD, "SIGCHLD" }, #endif #ifdef SIGCONT { SIGCONT, "SIGCONT" }, #endif #ifdef SIGFPE { SIGFPE, "SIGFPE" }, #endif #ifdef SIGHUP { SIGHUP, "SIGHUP" }, #endif #ifdef SIGILL { SIGILL, "SIGILL" }, #endif #ifdef SIGINT { SIGINT, "SIGINT" }, #endif #ifdef SIGKILL { SIGKILL, "SIGKILL" }, #endif #ifdef SIGPIPE { SIGPIPE, "SIGPIPE" }, #endif #ifdef SIGQUIT { SIGQUIT, "SIGQUIT" }, #endif #ifdef SIGSEGV { SIGSEGV, "SIGSEGV" }, #endif #ifdef SIGSTOP { SIGSTOP, "SIGSTOP" }, #endif #ifdef SIGTERM { SIGTERM, "SIGTERM" }, #endif #ifdef SIGTSTP { SIGTSTP, "SIGTSTP" }, #endif #ifdef SIGTTIN { SIGTTIN, "SIGTTIN" }, #endif #ifdef SIGTTOU { SIGTTOU, "SIGTTOU" }, #endif #ifdef SIGUSR1 { SIGUSR1, "SIGUSR1" }, #endif #ifdef SIGUSR2 { SIGUSR2, "SIGUSR2" }, #endif #ifdef SIGPOLL { SIGPOLL, "SIGPOLL" }, #endif #ifdef SIGSYS { SIGSYS, "SIGSYS" }, #endif #ifdef SIGTRAP { SIGTRAP, "SIGTRAP" }, #endif #ifdef SIGURG { SIGURG, "SIGURG" }, #endif #ifdef SIGXCPU { SIGXCPU, "SIGXCPU" }, #endif #ifdef SIGXFSZ { SIGXFSZ, "SIGXFSZ" }, #endif #ifdef SIGRTMIN { SIGRTMIN, "SIGRTMIN" }, #endif #ifdef SIGRTMAX { SIGRTMAX, "SIGRTMAX" }, #endif #ifdef SIGIO { SIGIO, "SIGIO" }, #endif #ifdef SIGSTKFLT { SIGSTKFLT, "SIGSTKFLT" }, #endif #ifdef SIGWINCH { SIGWINCH, "SIGWINCH" }, #endif }; } #if !defined(USE_SIGTIMEDWAIT) namespace { int selfpipe[2]; struct sigaction old_action; //------------------------------------------------------------------------------ // Name: sigchld_handler // Desc: //------------------------------------------------------------------------------ void sigchld_handler(int sig, siginfo_t *info, void *p) { if(sig == SIGCHLD) { native::write(selfpipe[1], " ", sizeof(char)); } // load as volatile volatile struct sigaction *vsa = &old_action; if (old_action.sa_flags & SA_SIGINFO) { void (*oldAction)(int, siginfo_t *, void *) = vsa->sa_sigaction; if (oldAction) { oldAction(sig, info, p); } } else { void (*oldAction)(int) = vsa->sa_handler; if (oldAction && oldAction != SIG_IGN) { oldAction(sig); } } } } #endif //------------------------------------------------------------------------------ // Name: read // Desc: read, but handles being interrupted //------------------------------------------------------------------------------ ssize_t native::read(int fd, void *buf, size_t count) { ssize_t ret; do { ret = ::read(fd, buf, count); } while(ret == -1 && errno == EINTR); return ret; } //------------------------------------------------------------------------------ // Name: write // Desc: write, but handles being interrupted //------------------------------------------------------------------------------ ssize_t native::write(int fd, const void *buf, size_t count) { ssize_t ret; do { ret = ::write(fd, buf, count); } while(ret == -1 && errno == EINTR); return ret; } //------------------------------------------------------------------------------ // Name: select // Desc: select but handles being interrupted //------------------------------------------------------------------------------ int native::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int ret; do { ret = ::select(nfds, readfds, writefds, exceptfds, timeout); } while(ret == -1 && errno == EINTR); return ret; } //------------------------------------------------------------------------------ // Name: waitpid // Desc: waitpid, but handles being interrupted //------------------------------------------------------------------------------ pid_t native::waitpid(pid_t pid, int *status, int options) { pid_t ret; do { ret = ::waitpid(pid, status, options); } while(ret == -1 && errno == EINTR); return ret; } //------------------------------------------------------------------------------ // Name: select_ex // Desc: similar to select but has the timeout specified as an unsigned quantity of msecs // Note: msecs == 0 means wait forever. //------------------------------------------------------------------------------ int native::select_ex(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, quint64 msecs) { if(msecs != 0) { struct timeval tv; tv.tv_sec = (msecs / 1000); tv.tv_usec = (msecs % 1000) * 1000; return native::select(nfds, readfds, writefds, exceptfds, &tv); } else { return native::select(nfds, readfds, writefds, exceptfds, NULL); } } //------------------------------------------------------------------------------ // Name: wait_for_sigchld // Desc: //------------------------------------------------------------------------------ bool native::wait_for_sigchld(int msecs) { #if !defined(USE_SIGTIMEDWAIT) fd_set rfds; FD_ZERO(&rfds); FD_SET(selfpipe[0], &rfds); if(native::select_ex(selfpipe[0] + 1, &rfds, 0, 0, msecs) == 0) { return true; } char ch; if(native::read(selfpipe[0], &ch, sizeof(char)) == -1) { return true; } return false; #else sigset_t mask; siginfo_t info; struct timespec ts; ts.tv_sec = (msecs / 1000); ts.tv_nsec = (msecs % 1000) * 1000000; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); return sigtimedwait(&mask, &info, &ts) == SIGCHLD; #endif } //------------------------------------------------------------------------------ // Name: DebuggerCoreUNIX // Desc: //------------------------------------------------------------------------------ DebuggerCoreUNIX::DebuggerCoreUNIX() { #if !defined(USE_SIGTIMEDWAIT) #if QT_VERSION >= 0x050000 // HACK(eteran): so, the first time we create a QProcess, it will hook SIGCHLD // unfortunately, in Qt5 it doesn't seem to call our handler // so we do this to force it to hook BEFORE we do, letting us // get the first crack at the signal, then we call the one that // Qt installed. auto p = new QProcess(0); p->start("/bin/true"); #endif // create a pipe and make it non-blocking int r = ::pipe(selfpipe); Q_UNUSED(r); ::fcntl(selfpipe[0], F_SETFL, ::fcntl(selfpipe[0], F_GETFL) | O_NONBLOCK); ::fcntl(selfpipe[1], F_SETFL, ::fcntl(selfpipe[1], F_GETFL) | O_NONBLOCK); // setup a signal handler struct sigaction new_action = {}; new_action.sa_sigaction = sigchld_handler; new_action.sa_flags = SA_RESTART | SA_SIGINFO; sigemptyset(&new_action.sa_mask); sigaction(SIGCHLD, &new_action, &old_action); #else // TODO(eteran): the man pages mention blocking the signal was want to catch // but I'm not sure if it is necessary for this use case... #endif } //------------------------------------------------------------------------------ // Name: execute_process // Desc: tries to execute the process, returns error string on error //------------------------------------------------------------------------------ Status DebuggerCoreUNIX::execute_process(const QString &path, const QString &cwd, const QList &args) { QString errorString = "internal error"; // change to the desired working directory if(::chdir(qPrintable(cwd)) == 0) { // allocate space for all the arguments auto argv_pointers = new char *[args.count() + 2]; char **p = argv_pointers; *p = new char[path.length() + 1]; std::strcpy(*p, qPrintable(path)); ++p; for(int i = 0; i < args.count(); ++i) { const QByteArray s(args[i]); *p = new char[s.length() + 1]; std::strcpy(*p, s.constData()); ++p; } *p = nullptr; // NOTE: it's a bad idea to use execvp and similar functions searching in // $PATH. At least on Linux, if the file is corrupted/unsupported, they // instead appear to launch shell const int ret = execv(argv_pointers[0], argv_pointers); // should be no need to cleanup, the process which allocated all that // space no longer exists! // if we get here...execv failed! if(ret == -1) { errorString = QObject::tr("execv() failed: %1").arg(strerror(errno)); p = argv_pointers; while(*p) { delete [] *p++; } delete [] argv_pointers; } } // frankly, any return is technically an error I think // this is only executed from a fork return Status(errorString); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCoreUNIX::exceptionName(qlonglong value) { for(Exception e : Exceptions) { if(value == e.value) { return e.name; } } return QString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ qlonglong DebuggerCoreUNIX::exceptionValue(const QString &name) { for(Exception e : Exceptions) { if(name == e.name) { return e.value; } } return -1; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QMap DebuggerCoreUNIX::exceptions() const { QMap exceptions; for(Exception e : Exceptions) { exceptions[e.value] = e.name; } return exceptions; } } edb-debugger-1.0.0/plugins/DebuggerCore/win32/0000755000175000017500000000000013273160654020331 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/win32/DebuggerCore.h0000644000175000017500000001062213273160654023040 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DEBUGGERCORE_20090529_H_ #define DEBUGGERCORE_20090529_H_ #include "DebuggerCoreBase.h" #include "IRegion.h" #include "Module.h" #include namespace DebuggerCorePlugin { class DebuggerCore : public DebuggerCoreBase { Q_OBJECT #if QT_VERSION >= 0x050000 Q_PLUGIN_METADATA(IID "edb.IDebugger/1.0") #endif Q_INTERFACES(IDebugger) Q_CLASSINFO("author", "Evan Teran") Q_CLASSINFO("url", "http://www.codef00.com") public: DebuggerCore(); virtual ~DebuggerCore(); public: virtual bool has_extension(quint64 ext) const; virtual edb::address_t page_size() const; virtual std::size_t pointer_size() const { return sizeof(void*); }; virtual std::shared_ptr wait_debug_event(int msecs); virtual Status attach(edb::pid_t pid); virtual Status detach(); virtual void kill(); virtual void pause(); virtual void resume(edb::EVENT_STATUS status); virtual void step(edb::EVENT_STATUS status); virtual void get_state(State *state); virtual void set_state(const State &state); virtual Status open(const QString &path, const QString &cwd, const QList &args, const QString &tty); virtual MeansOfCapture last_means_of_capture() const { qDebug("TODO: Implement DebuggerCore::last_means_of_capture"); return MeansOfCapture::NeverCaptured; }; virtual bool read_pages(edb::address_t address, void *buf, std::size_t count); virtual bool read_bytes(edb::address_t address, void *buf, std::size_t len); virtual bool write_bytes(edb::address_t address, const void *buf, std::size_t len); virtual int sys_pointer_size() const; virtual QMap exceptions() const; virtual QString exceptionName(qlonglong value) { qDebug("TODO: Implement DebuggerCore::exceptionName"); return ""; }; virtual qlonglong exceptionValue(const QString &name) { qDebug("TODO: Implement DebuggerCore::exceptionValue"); return 0; } public: // thread support stuff (optional) virtual QList thread_ids() const { return threads_.toList(); } virtual edb::tid_t active_thread() const { return active_thread_; } virtual void set_active_thread(edb::tid_t tid) { Q_ASSERT(threads_.contains(tid)); active_thread_ = tid; } public: virtual QList> memory_regions() const; virtual edb::address_t process_code_address() const; virtual edb::address_t process_data_address() const; public: // process properties virtual QList process_args(edb::pid_t pid) const; virtual QString process_exe(edb::pid_t pid) const; virtual QString process_cwd(edb::pid_t pid) const; virtual edb::pid_t parent_pid(edb::pid_t pid) const; virtual QDateTime process_start(edb::pid_t pid) const; virtual quint64 cpu_type() const; virtual CPUMode cpu_mode() const { qDebug("TODO: Implement DebuggerCore::cpu_mode"); return CPUMode::Unknown; }; public: virtual IState *create_state() const; private: virtual QMap > enumerate_processes() const; virtual QList loaded_modules() const; public: virtual QString stack_pointer() const; virtual QString frame_pointer() const; virtual QString instruction_pointer() const; virtual QString flag_register() const { qDebug("TODO: Implement DebuggerCore::flag_register"); return ""; }; public: virtual QString format_pointer(edb::address_t address) const; public: virtual IProcess *process() const { qDebug("TODO: Implement DebuggerCore::process"); return nullptr; }; public: // NOTE: win32 only stuff here! edb::address_t start_address; edb::address_t image_base; private: bool attached() { return DebuggerCoreBase::attached() && process_handle_ != 0; } private: edb::address_t page_size_; HANDLE process_handle_; QSet threads_; edb::tid_t active_thread_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/win32/PlatformProcess.cpp0000644000175000017500000000422213273160654024160 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformProcess.h" namespace DebuggerCorePlugin { PlatformProcess::PlatformProcess(const PROCESSENTRY32& pe) { _pid = pe.th32ProcessID; _name = QString::fromWCharArray(pe.szExeFile); if (HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, _pid)) { BOOL wow64 = FALSE; typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); if (fnIsWow64Process && fnIsWow64Process(hProc, &wow64) && wow64) { _name += " *32"; } HANDLE hToken; if (OpenProcessToken(hProc, TOKEN_QUERY, &hToken)) { DWORD needed; GetTokenInformation(hToken, TokenOwner, NULL, 0, &needed); if (auto owner = static_cast(malloc(needed))) { if (GetTokenInformation(hToken, TokenOwner, owner, needed, &needed)) { WCHAR user[MAX_PATH]; WCHAR domain[MAX_PATH]; DWORD user_sz = MAX_PATH; DWORD domain_sz = MAX_PATH; SID_NAME_USE snu; if (LookupAccountSid(NULL, owner->Owner, user, &user_sz, domain, &domain_sz, &snu) && snu == SidTypeUser) { _user = QString::fromWCharArray(user); } } free(owner); } CloseHandle(hToken); } CloseHandle(hProc); } } edb::pid_t PlatformProcess::pid() const { return _pid; } QString PlatformProcess::name() const { return _name; } QString PlatformProcess::user() const { return _user; } } edb-debugger-1.0.0/plugins/DebuggerCore/win32/PlatformEvent.h0000644000175000017500000000300113273160654023262 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_EVENT_20121005_H_ #define PLATFORM_EVENT_20121005_H_ #include #include "IDebugEvent.h" namespace DebuggerCorePlugin { class PlatformEvent : public IDebugEvent { Q_DECLARE_TR_FUNCTIONS(PlatformEvent) friend class DebuggerCore; public: PlatformEvent(); public: virtual PlatformEvent *clone() const; public: virtual Message error_description() const; virtual REASON reason() const; virtual TRAP_REASON trap_reason() const; virtual bool exited() const; virtual bool is_error() const; virtual bool is_kill() const; virtual bool is_stop() const; virtual bool is_trap() const; virtual bool terminated() const; virtual bool stopped() const; virtual edb::pid_t process() const; virtual edb::tid_t thread() const; virtual int code() const; private: DEBUG_EVENT event; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/win32/PlatformRegion.h0000644000175000017500000000356513273160654023443 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORM_REGION_20120330_H_ #define PLATFORM_REGION_20120330_H_ #include "IRegion.h" #include #include namespace DebuggerCorePlugin { class PlatformRegion : public IRegion { Q_DECLARE_TR_FUNCTIONS(PlatformRegion) template friend class BackupInfo; public: PlatformRegion(edb::address_t start, edb::address_t end, edb::address_t base, const QString &name, permissions_t permissions); virtual ~PlatformRegion(); public: virtual IRegion *clone() const; public: virtual bool accessible() const; virtual bool readable() const; virtual bool writable() const; virtual bool executable() const; virtual edb::address_t size() const; public: virtual void set_permissions(bool read, bool write, bool execute); virtual void set_start(edb::address_t address); virtual void set_end(edb::address_t address); public: virtual edb::address_t start() const; virtual edb::address_t end() const; virtual edb::address_t base() const; virtual QString name() const; virtual permissions_t permissions() const; private: edb::address_t start_; edb::address_t end_; edb::address_t base_; QString name_; permissions_t permissions_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/win32/PlatformRegion.cpp0000644000175000017500000000753013273160654023772 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformRegion.h" #include "MemoryRegions.h" #include "edb.h" #include "IDebugger.h" #include "IProcess.h" #include "State.h" #include "IDebugEventHandler.h" #include namespace DebuggerCorePlugin { namespace { const IRegion::permissions_t KNOWN_PERMISSIONS = (PAGE_NOACCESS | PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); } PlatformRegion::PlatformRegion(edb::address_t start, edb::address_t end, edb::address_t base, const QString &name, permissions_t permissions) : start_(start), end_(end), base_(base), name_(name), permissions_(permissions) { } PlatformRegion::~PlatformRegion() { } IRegion *PlatformRegion::clone() const { return new PlatformRegion(start_, end_, base_, name_, permissions_); } bool PlatformRegion::accessible() const { return readable() || writable() || executable(); } bool PlatformRegion::readable() const { switch(permissions_ & KNOWN_PERMISSIONS) { // ignore modifiers case PAGE_EXECUTE_READ: case PAGE_EXECUTE_READWRITE: case PAGE_READONLY: case PAGE_READWRITE: return true; default: return false; } } bool PlatformRegion::writable() const { switch(permissions_ & KNOWN_PERMISSIONS) { // ignore modifiers case PAGE_EXECUTE_READWRITE: case PAGE_EXECUTE_WRITECOPY: case PAGE_READWRITE: case PAGE_WRITECOPY: return true; default: return false; } } bool PlatformRegion::executable() const { switch(permissions_ & KNOWN_PERMISSIONS) { // ignore modifiers case PAGE_EXECUTE: case PAGE_EXECUTE_READ: case PAGE_EXECUTE_READWRITE: case PAGE_EXECUTE_WRITECOPY: return true; default: return false; } } edb::address_t PlatformRegion::size() const { return end_ - start_; } void PlatformRegion::set_permissions(bool read, bool write, bool execute) { if(HANDLE ph = OpenProcess(PROCESS_VM_OPERATION, FALSE, edb::v1::debugger_core->process()->pid())) { DWORD prot = PAGE_NOACCESS; switch((static_cast(read) << 2) | (static_cast(write) << 1) | (static_cast(execute) << 0)) { case 0x0: prot = PAGE_NOACCESS; break; case 0x1: prot = PAGE_EXECUTE; break; case 0x2: prot = PAGE_WRITECOPY; break; case 0x3: prot = PAGE_EXECUTE_WRITECOPY; break; case 0x4: prot = PAGE_READONLY; break; case 0x5: prot = PAGE_EXECUTE_READ; break; case 0x6: prot = PAGE_READWRITE; break; case 0x7: prot = PAGE_EXECUTE_READWRITE; break; } prot |= permissions_ & ~KNOWN_PERMISSIONS; // keep modifiers DWORD prev_prot; if(VirtualProtectEx(ph, reinterpret_cast(start().toUint()), size(), prot, &prev_prot)) { permissions_ = prot; } CloseHandle(ph); } } edb::address_t PlatformRegion::start() const { return start_; } edb::address_t PlatformRegion::end() const { return end_; } edb::address_t PlatformRegion::base() const { return base_; } QString PlatformRegion::name() const { return name_; } IRegion::permissions_t PlatformRegion::permissions() const { return permissions_; } void PlatformRegion::set_start(edb::address_t address) { start_ = address; } void PlatformRegion::set_end(edb::address_t address) { end_ = address; } } edb-debugger-1.0.0/plugins/DebuggerCore/win32/PlatformProcess.h0000644000175000017500000001137213273160654023631 0ustar eteraneteran/* Copyright (C) 2015 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATOFORM_PROCESS_20150517_H_ #define PLATOFORM_PROCESS_20150517_H_ #include "IProcess.h" #include "Module.h" #include #include namespace DebuggerCorePlugin { class PlatformProcess : public IProcess { public: PlatformProcess(const PROCESSENTRY32& pe); public: // legal to call when not attached virtual QDateTime start_time() const { qDebug("TODO: implement PlatformProcess::start_time"); return QDateTime(); }; virtual QList arguments() const { qDebug("TODO: implement PlatformProcess::arguments"); return QList(); }; virtual QString current_working_directory() const { qDebug("TODO: implement PlatformProcess::current_working_directory"); return ""; }; virtual QString executable() const { qDebug("TODO: implement PlatformProcess::executable"); return ""; }; virtual edb::pid_t pid() const; virtual std::shared_ptr parent() const { qDebug("TODO: implement PlatformProcess::parent"); return std::shared_ptr(); }; virtual edb::address_t code_address() const { qDebug("TODO: implement PlatformProcess::code_address"); return edb::address_t(); }; virtual edb::address_t data_address() const { qDebug("TODO: implement PlatformProcess::data_address"); return edb::address_t(); }; virtual QList> regions() const { qDebug("TODO: implement PlatformProcess::regions"); return QList>(); }; virtual edb::uid_t uid() const { qDebug("TODO: implement PlatformProcess::uid"); return edb::uid_t(); }; virtual QString user() const; virtual QString name() const; virtual QList loaded_modules() const { qDebug("TODO: implement PlatformProcess::loaded_modules"); return QList(); }; public: // only legal to call when attached virtual QList> threads() const { qDebug("TODO: implement PlatformProcess::threads"); return QList>(); }; virtual std::shared_ptr current_thread() const { qDebug("TODO: implement PlatformProcess::current_thread"); return std::shared_ptr(); }; virtual void set_current_thread(IThread& thread) { qDebug("TODO: implement PlatformProcess::set_current_thread"); }; virtual std::size_t write_bytes(edb::address_t address, const void *buf, size_t len) { qDebug("TODO: implement PlatformProcess::write_bytes"); return 0; }; virtual std::size_t patch_bytes(edb::address_t address, const void *buf, size_t len) { qDebug("TODO: implement PlatformProcess::patch_bytes"); return 0; }; virtual std::size_t read_bytes(edb::address_t address, void *buf, size_t len) const { qDebug("TODO: implement PlatformProcess::read_bytes"); return 0; }; virtual std::size_t read_pages(edb::address_t address, void *buf, size_t count) const { qDebug("TODO: implement PlatformProcess::read_pages"); return 0; }; virtual Status pause() { qDebug("TODO: implement PlatformProcess::pause"); return Status("Not implemented"); }; virtual Status resume(edb::EVENT_STATUS status) { qDebug("TODO: implement PlatformProcess::resume"); return Status("Not implemented"); }; virtual Status step(edb::EVENT_STATUS status) { qDebug("TODO: implement PlatformProcess::step"); return Status("Not implemented"); }; virtual bool isPaused() const { qDebug("TODO: implement PlatformProcess::isPaused"); return true; }; virtual QMap patches() const { qDebug("TODO: implement PlatformProcess::patches"); return QMap(); }; private: edb::pid_t _pid; QString _name; QString _user; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/win32/PlatformState.cpp0000644000175000017500000005617513273160654023640 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformState.h" #include "edb.h" #include #include namespace DebuggerCorePlugin { namespace { // little-endian! double read_float80(const uint8_t buffer[10]) { //80 bit floating point value according to IEEE-754: //1 bit sign, 15 bit exponent, 64 bit mantissa const uint16_t SIGNBIT = 1 << 15; const uint16_t EXP_BIAS = (1 << 14) - 1; // 2^(n-1) - 1 = 16383 const uint16_t SPECIALEXP = (1 << 15) - 1; // all bits set const uint64_t HIGHBIT = (uint64_t)1 << 63; const uint64_t QUIETBIT = (uint64_t)1 << 62; // Extract sign, exponent and mantissa uint16_t exponent = *((uint16_t*)&buffer[8]); uint64_t mantissa = *((uint64_t*)&buffer[0]); double sign = (exponent & SIGNBIT) ? -1.0 : 1.0; exponent &= ~SIGNBIT; // Check for undefined values if((!exponent && (mantissa & HIGHBIT)) || (exponent && !(mantissa & HIGHBIT))) { return std::numeric_limits::quiet_NaN(); } // Check for special values (infinity, NaN) if(exponent == 0) { if(mantissa == 0) { return sign * 0.0; } else { // denormalized } } else if(exponent == SPECIALEXP) { if(!(mantissa & ~HIGHBIT)) { return sign * std::numeric_limits::infinity(); } else { if(mantissa & QUIETBIT) { return std::numeric_limits::quiet_NaN(); } else { return std::numeric_limits::signaling_NaN(); } } } //value = (-1)^s * (m / 2^63) * 2^(e - 16383) double significand = ((double)mantissa / ((uint64_t)1 << 63)); return sign * ldexp(significand, exponent - EXP_BIAS); } } //------------------------------------------------------------------------------ // Name: PlatformState // Desc: //------------------------------------------------------------------------------ PlatformState::PlatformState() { memset(&context_, 0, sizeof(context_)); fs_base_ = 0; gs_base_ = 0; } //------------------------------------------------------------------------------ // Name: PlatformState::clone // Desc: makes a copy of the state object //------------------------------------------------------------------------------ IState *PlatformState::clone() const { return new PlatformState(*this); } //------------------------------------------------------------------------------ // Name: flags_to_string // Desc: returns the flags in a string form appropriate for this platform //------------------------------------------------------------------------------ QString PlatformState::flags_to_string(edb::reg_t flags) const { char buf[14]; qsnprintf( buf, sizeof(buf), "%c %c %c %c %c %c %c", ((flags & 0x001) ? 'C' : 'c'), ((flags & 0x004) ? 'P' : 'p'), ((flags & 0x010) ? 'A' : 'a'), ((flags & 0x040) ? 'Z' : 'z'), ((flags & 0x080) ? 'S' : 's'), ((flags & 0x400) ? 'D' : 'd'), ((flags & 0x800) ? 'O' : 'o')); return buf; } //------------------------------------------------------------------------------ // Name: flags_to_string // Desc: returns the flags in a string form appropriate for this platform //------------------------------------------------------------------------------ QString PlatformState::flags_to_string() const { return flags_to_string(flags()); } //------------------------------------------------------------------------------ // Name: value // Desc: returns a Register object which represents the register with the name // supplied //------------------------------------------------------------------------------ Register PlatformState::value(const QString ®) const { const QString lreg = reg.toLower(); #if defined(EDB_X86) if(lreg == "eax") return make_Register("eax", context_.Eax, Register::TYPE_GPR); else if(lreg == "ebx") return make_Register("ebx", context_.Ebx, Register::TYPE_GPR); else if(lreg == "ecx") return make_Register("ecx", context_.Ecx, Register::TYPE_GPR); else if(lreg == "edx") return make_Register("edx", context_.Edx, Register::TYPE_GPR); else if(lreg == "ebp") return make_Register("ebp", context_.Ebp, Register::TYPE_GPR); else if(lreg == "esp") return make_Register("esp", context_.Esp, Register::TYPE_GPR); else if(lreg == "esi") return make_Register("esi", context_.Esi, Register::TYPE_GPR); else if(lreg == "edi") return make_Register("edi", context_.Edi, Register::TYPE_GPR); else if(lreg == "eip") return make_Register("eip", context_.Eip, Register::TYPE_IP); else if(lreg == "ax") return make_Register("ax", context_.Eax & 0xffff, Register::TYPE_GPR); else if(lreg == "bx") return make_Register("bx", context_.Ebx & 0xffff, Register::TYPE_GPR); else if(lreg == "cx") return make_Register("cx", context_.Ecx & 0xffff, Register::TYPE_GPR); else if(lreg == "dx") return make_Register("dx", context_.Edx & 0xffff, Register::TYPE_GPR); else if(lreg == "bp") return make_Register("bp", context_.Ebp & 0xffff, Register::TYPE_GPR); else if(lreg == "sp") return make_Register("sp", context_.Esp & 0xffff, Register::TYPE_GPR); else if(lreg == "si") return make_Register("si", context_.Esi & 0xffff, Register::TYPE_GPR); else if(lreg == "di") return make_Register("di", context_.Edi & 0xffff, Register::TYPE_GPR); else if(lreg == "al") return make_Register("al", context_.Eax & 0xff, Register::TYPE_GPR); else if(lreg == "bl") return make_Register("bl", context_.Ebx & 0xff, Register::TYPE_GPR); else if(lreg == "cl") return make_Register("cl", context_.Ecx & 0xff, Register::TYPE_GPR); else if(lreg == "dl") return make_Register("dl", context_.Edx & 0xff, Register::TYPE_GPR); else if(lreg == "ah") return make_Register("ah", (context_.Eax >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bh") return make_Register("bh", (context_.Ebx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "ch") return make_Register("ch", (context_.Ecx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dh") return make_Register("dh", (context_.Edx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "cs") return make_Register("cs", context_.SegCs, Register::TYPE_SEG); else if(lreg == "ds") return make_Register("ds", context_.SegDs, Register::TYPE_SEG); else if(lreg == "es") return make_Register("es", context_.SegEs, Register::TYPE_SEG); else if(lreg == "fs") return make_Register("fs", context_.SegFs, Register::TYPE_SEG); else if(lreg == "gs") return make_Register("gs", context_.SegGs, Register::TYPE_SEG); else if(lreg == "ss") return make_Register("ss", context_.SegSs, Register::TYPE_SEG); else if(lreg == "fs_base") return make_Register("fs_base", fs_base_, Register::TYPE_SEG); else if(lreg == "gs_base") return make_Register("gs_base", gs_base_, Register::TYPE_SEG); else if(lreg == "eflags") return make_Register("eflags", context_.EFlags, Register::TYPE_COND); #elif defined(EDB_X86_64) if(lreg == "rax") return make_Register("rax", context_.Rax, Register::TYPE_GPR); else if(lreg == "rbx") return make_Register("rbx", context_.Rbx, Register::TYPE_GPR); else if(lreg == "rcx") return make_Register("rcx", context_.Rcx, Register::TYPE_GPR); else if(lreg == "rdx") return make_Register("rdx", context_.Rdx, Register::TYPE_GPR); else if(lreg == "rbp") return make_Register("rbp", context_.Rbp, Register::TYPE_GPR); else if(lreg == "rsp") return make_Register("rsp", context_.Rsp, Register::TYPE_GPR); else if(lreg == "rsi") return make_Register("rsi", context_.Rsi, Register::TYPE_GPR); else if(lreg == "rdi") return make_Register("rdi", context_.Rdi, Register::TYPE_GPR); else if(lreg == "rip") return make_Register("rip", context_.Rip, Register::TYPE_IP); else if(lreg == "r8") return make_Register("r8", context_.R8, Register::TYPE_GPR); else if(lreg == "r9") return make_Register("r9", context_.R9, Register::TYPE_GPR); else if(lreg == "r10") return make_Register("r10", context_.R10, Register::TYPE_GPR); else if(lreg == "r11") return make_Register("r11", context_.R11, Register::TYPE_GPR); else if(lreg == "r12") return make_Register("r12", context_.R12, Register::TYPE_GPR); else if(lreg == "r13") return make_Register("r13", context_.R13, Register::TYPE_GPR); else if(lreg == "r14") return make_Register("r14", context_.R14, Register::TYPE_GPR); else if(lreg == "r15") return make_Register("r15", context_.R15, Register::TYPE_GPR); else if(lreg == "eax") return make_Register("eax", context_.Rax & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ebx") return make_Register("ebx", context_.Rbx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ecx") return make_Register("ecx", context_.Rcx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "edx") return make_Register("edx", context_.Rdx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ebp") return make_Register("ebp", context_.Rbp & 0xffffffff, Register::TYPE_GPR); else if(lreg == "esp") return make_Register("esp", context_.Rsp & 0xffffffff, Register::TYPE_GPR); else if(lreg == "esi") return make_Register("esi", context_.Rsi & 0xffffffff, Register::TYPE_GPR); else if(lreg == "edi") return make_Register("edi", context_.Rdi & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r8d") return make_Register("r8d", context_.R8 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r9d") return make_Register("r9d", context_.R9 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r10d") return make_Register("r10d", context_.R10 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r11d") return make_Register("r11d", context_.R11 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r12d") return make_Register("r12d", context_.R12 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r13d") return make_Register("r13d", context_.R13 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r14d") return make_Register("r14d", context_.R14 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r15d") return make_Register("r15d", context_.R15 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ax") return make_Register("ax", context_.Rax & 0xffff, Register::TYPE_GPR); else if(lreg == "bx") return make_Register("bx", context_.Rbx & 0xffff, Register::TYPE_GPR); else if(lreg == "cx") return make_Register("cx", context_.Rcx & 0xffff, Register::TYPE_GPR); else if(lreg == "dx") return make_Register("dx", context_.Rdx & 0xffff, Register::TYPE_GPR); else if(lreg == "bp") return make_Register("bp", context_.Rbp & 0xffff, Register::TYPE_GPR); else if(lreg == "sp") return make_Register("sp", context_.Rsp & 0xffff, Register::TYPE_GPR); else if(lreg == "si") return make_Register("si", context_.Rsi & 0xffff, Register::TYPE_GPR); else if(lreg == "di") return make_Register("di", context_.Rdi & 0xffff, Register::TYPE_GPR); else if(lreg == "r8w") return make_Register("r8w", context_.R8 & 0xffff, Register::TYPE_GPR); else if(lreg == "r9w") return make_Register("r9w", context_.R9 & 0xffff, Register::TYPE_GPR); else if(lreg == "r10w") return make_Register("r10w", context_.R10 & 0xffff, Register::TYPE_GPR); else if(lreg == "r11w") return make_Register("r11w", context_.R11 & 0xffff, Register::TYPE_GPR); else if(lreg == "r12w") return make_Register("r12w", context_.R12 & 0xffff, Register::TYPE_GPR); else if(lreg == "r13w") return make_Register("r13w", context_.R13 & 0xffff, Register::TYPE_GPR); else if(lreg == "r14w") return make_Register("r14w", context_.R14 & 0xffff, Register::TYPE_GPR); else if(lreg == "r15w") return make_Register("r15w", context_.R15 & 0xffff, Register::TYPE_GPR); else if(lreg == "al") return make_Register("al", context_.Rax & 0xff, Register::TYPE_GPR); else if(lreg == "bl") return make_Register("bl", context_.Rbx & 0xff, Register::TYPE_GPR); else if(lreg == "cl") return make_Register("cl", context_.Rcx & 0xff, Register::TYPE_GPR); else if(lreg == "dl") return make_Register("dl", context_.Rdx & 0xff, Register::TYPE_GPR); else if(lreg == "ah") return make_Register("ah", (context_.Rax >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bh") return make_Register("bh", (context_.Rbx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "ch") return make_Register("ch", (context_.Rcx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dh") return make_Register("dh", (context_.Rdx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "spl") return make_Register("spl", (context_.Rsp >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bpl") return make_Register("bpl", (context_.Rbp >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "sil") return make_Register("sil", (context_.Rsi >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dil") return make_Register("dil", (context_.Rdi >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "r8b") return make_Register("r8b", context_.R8 & 0xff, Register::TYPE_GPR); else if(lreg == "r9b") return make_Register("r9b", context_.R9 & 0xff, Register::TYPE_GPR); else if(lreg == "r10b") return make_Register("r10b", context_.R10 & 0xff, Register::TYPE_GPR); else if(lreg == "r11b") return make_Register("r11b", context_.R11 & 0xff, Register::TYPE_GPR); else if(lreg == "r12b") return make_Register("r12b", context_.R12 & 0xff, Register::TYPE_GPR); else if(lreg == "r13b") return make_Register("r13b", context_.R13 & 0xff, Register::TYPE_GPR); else if(lreg == "r14b") return make_Register("r14b", context_.R14 & 0xff, Register::TYPE_GPR); else if(lreg == "r15b") return make_Register("r15b", context_.R15 & 0xff, Register::TYPE_GPR); else if(lreg == "cs") return make_Register("cs", context_.SegCs, Register::TYPE_SEG); else if(lreg == "ds") return make_Register("ds", context_.SegDs, Register::TYPE_SEG); else if(lreg == "es") return make_Register("es", context_.SegEs, Register::TYPE_SEG); else if(lreg == "fs") return make_Register("fs", context_.SegFs, Register::TYPE_SEG); else if(lreg == "gs") return make_Register("gs", context_.SegGs, Register::TYPE_SEG); else if(lreg == "ss") return make_Register("ss", context_.SegSs, Register::TYPE_SEG); else if(lreg == "fs_base") return make_Register("fs_base", fs_base_, Register::TYPE_SEG); else if(lreg == "gs_base") return make_Register("gs_base", gs_base_, Register::TYPE_SEG); else if(lreg == "rflags") return make_Register("rflags", context_.EFlags, Register::TYPE_COND); #endif return Register(); } //------------------------------------------------------------------------------ // Name: frame_pointer // Desc: returns what is conceptually the frame pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::frame_pointer() const { #if defined(EDB_X86) return context_.Ebp; #elif defined(EDB_X86_64) return context_.Rbp; #endif } //------------------------------------------------------------------------------ // Name: instruction_pointer // Desc: returns the instruction pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::instruction_pointer() const { #if defined(EDB_X86) return context_.Eip; #elif defined(EDB_X86_64) return context_.Rip; #endif } //------------------------------------------------------------------------------ // Name: stack_pointer // Desc: returns the stack pointer for this platform //------------------------------------------------------------------------------ edb::address_t PlatformState::stack_pointer() const { #if defined(EDB_X86) return context_.Esp; #elif defined(EDB_X86_64) return context_.Rsp; #endif } //------------------------------------------------------------------------------ // Name: debug_register // Desc: //------------------------------------------------------------------------------ edb::reg_t PlatformState::debug_register(size_t n) const { switch(n) { case 0: return context_.Dr0; case 1: return context_.Dr1; case 2: return context_.Dr2; case 3: return context_.Dr3; case 6: return context_.Dr6; case 7: return context_.Dr7; } return 0; } //------------------------------------------------------------------------------ // Name: flags // Desc: //------------------------------------------------------------------------------ edb::reg_t PlatformState::flags() const { #if defined(EDB_X86) return context_.EFlags; #elif defined(EDB_X86_64) return context_.EFlags; #endif } //------------------------------------------------------------------------------ // Name: fpu_register // Desc: //------------------------------------------------------------------------------ long double PlatformState::fpu_register(int n) const { double ret = 0.0; if(n >= 0 && n <= 7) { #if defined(EDB_X86) auto p = reinterpret_cast(&context_.FloatSave.RegisterArea[n*10]); if(sizeof(long double) == 10) { // can we check this at compile time? ret = *(reinterpret_cast(p)); } else { ret = read_float80(p); } #elif defined(EDB_X86_64) auto p = reinterpret_cast(&context_.FltSave.FloatRegisters[n]); if(sizeof(long double) == 10) { ret = *(reinterpret_cast(p)); } else { ret = read_float80(p); } #endif } return ret; } //------------------------------------------------------------------------------ // Name: mmx_register // Desc: //------------------------------------------------------------------------------ quint64 PlatformState::mmx_register(int n) const { quint64 ret = 0; if(n >= 0 && n <= 7) { #if defined(EDB_X86) // MMX registers are an alias to the lower 64-bits of the FPU regs auto p = reinterpret_cast(&context_.FloatSave.RegisterArea[n*10]); ret = *p; // little endian! #elif defined(EDB_X86_64) auto p = reinterpret_cast(&context_.FltSave.FloatRegisters[n]); ret = *p; #endif } return ret; } //------------------------------------------------------------------------------ // Name: xmm_register // Desc: //------------------------------------------------------------------------------ QByteArray PlatformState::xmm_register(int n) const { QByteArray ret(16, 0); #if defined(EDB_X86) if(n >= 0 && n <= 7) { auto p = reinterpret_cast(&context_.ExtendedRegisters[(10+n)*16]); ret = QByteArray(p, 16); std::reverse(ret.begin(), ret.end()); //little endian! } #elif defined(EDB_X86_64) if(n >= 0 && n <= 15) { auto p = reinterpret_cast(&context_.FltSave.XmmRegisters[n]); ret = QByteArray(p, sizeof(M128A)); std::reverse(ret.begin(), ret.end()); } #endif return ret; } //------------------------------------------------------------------------------ // Name: adjust_stack // Desc: //------------------------------------------------------------------------------ void PlatformState::adjust_stack(int bytes) { #if defined(EDB_X86) context_.Esp += bytes; #elif defined(EDB_X86_64) context_.Rsp += bytes; #endif } //------------------------------------------------------------------------------ // Name: clear // Desc: //------------------------------------------------------------------------------ void PlatformState::clear() { memset(&context_, 0, sizeof(context_)); fs_base_ = 0; gs_base_ = 0; } //------------------------------------------------------------------------------ // Name: set_debug_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_debug_register(size_t n, edb::reg_t value) { switch(n) { case 0: context_.Dr0 = value; break; case 1: context_.Dr1 = value; break; case 2: context_.Dr2 = value; break; case 3: context_.Dr3 = value; break; case 6: context_.Dr6 = value; break; case 7: context_.Dr7 = value; break; default: break; } } //------------------------------------------------------------------------------ // Name: set_flags // Desc: //------------------------------------------------------------------------------ void PlatformState::set_flags(edb::reg_t flags) { #if defined(EDB_X86) context_.EFlags = flags; #elif defined(EDB_X86_64) context_.EFlags = flags; #endif } //------------------------------------------------------------------------------ // Name: set_instruction_pointer // Desc: //------------------------------------------------------------------------------ void PlatformState::set_instruction_pointer(edb::address_t value) { #if defined(EDB_X86) context_.Eip = value; #elif defined(EDB_X86_64) context_.Rip = value; #endif } //------------------------------------------------------------------------------ // Name: set_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_register(const QString &name, edb::reg_t value) { const QString lreg = name.toLower(); #if defined(EDB_X86) if(lreg == "eax") { context_.Eax = value; } else if(lreg == "ebx") { context_.Ebx = value; } else if(lreg == "ecx") { context_.Ecx = value; } else if(lreg == "edx") { context_.Edx = value; } else if(lreg == "ebp") { context_.Ebp = value; } else if(lreg == "esp") { context_.Esp = value; } else if(lreg == "esi") { context_.Esi = value; } else if(lreg == "edi") { context_.Edi = value; } else if(lreg == "eip") { context_.Eip = value; } else if(lreg == "cs") { context_.SegCs = value; } else if(lreg == "ds") { context_.SegDs = value; } else if(lreg == "es") { context_.SegEs = value; } else if(lreg == "fs") { context_.SegFs = value; } else if(lreg == "gs") { context_.SegGs = value; } else if(lreg == "ss") { context_.SegSs = value; } else if(lreg == "eflags") { context_.EFlags = value; } #elif defined(EDB_X86_64) if(lreg == "rax") { context_.Rax = value; } else if(lreg == "rbx") { context_.Rbx = value; } else if(lreg == "rcx") { context_.Rcx = value; } else if(lreg == "rdx") { context_.Rdx = value; } else if(lreg == "rbp") { context_.Rbp = value; } else if(lreg == "rsp") { context_.Rsp = value; } else if(lreg == "rsi") { context_.Rsi = value; } else if(lreg == "rdi") { context_.Rdi = value; } else if(lreg == "r8") { context_.R8 = value; } else if(lreg == "r9") { context_.R9 = value; } else if(lreg == "r10") { context_.R10 = value; } else if(lreg == "r11") { context_.R11 = value; } else if(lreg == "r12") { context_.R12 = value; } else if(lreg == "r13") { context_.R13 = value; } else if(lreg == "r14") { context_.R14 = value; } else if(lreg == "r15") { context_.R15 = value; } else if(lreg == "rip") { context_.Rip = value; } else if(lreg == "cs") { context_.SegCs = value; } else if(lreg == "ds") { context_.SegDs = value; } else if(lreg == "es") { context_.SegEs = value; } else if(lreg == "fs") { context_.SegFs = value; } else if(lreg == "gs") { context_.SegGs = value; } else if(lreg == "ss") { context_.SegSs = value; } else if(lreg == "rflags") { context_.EFlags = value; } #endif } } edb-debugger-1.0.0/plugins/DebuggerCore/win32/PlatformState.h0000644000175000017500000000742713273160654023301 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef PLATFORMSTATE_20110330_H_ #define PLATFORMSTATE_20110330_H_ #include "IState.h" #include "Types.h" #include namespace DebuggerCorePlugin { class PlatformState : public IState { friend class DebuggerCore; public: PlatformState(); public: virtual IState *clone() const; public: virtual QString flags_to_string() const; virtual QString flags_to_string(edb::reg_t flags) const; virtual Register value(const QString ®) const; virtual Register instruction_pointer_register() const { qDebug("TODO: implement PlatformState::instruction_pointer_register"); return Register(); }; virtual Register flags_register() const { qDebug("TODO: implement PlatformState::flags_register"); return Register(); }; virtual edb::address_t frame_pointer() const; virtual edb::address_t instruction_pointer() const; virtual edb::address_t stack_pointer() const; virtual edb::reg_t debug_register(size_t n) const; virtual edb::reg_t flags() const; virtual long double fpu_register(int n) const; virtual quint64 mmx_register(int n) const; virtual QByteArray xmm_register(int n) const; virtual void adjust_stack(int bytes); virtual void clear(); virtual bool empty() const { qDebug("TODO: implement PlatformState::empty"); return true; }; virtual void set_debug_register(size_t n, edb::reg_t value); virtual void set_flags(edb::reg_t flags); virtual void set_instruction_pointer(edb::address_t value); virtual void set_register(const QString &name, edb::reg_t value); virtual void set_register(const Register ®) { qDebug("TODO: implement PlatformState::set_register"); }; virtual Register mmx_register(size_t n) const { qDebug("TODO: implement PlatformState::mmx_register"); return Register(); } virtual Register xmm_register(size_t n) const { qDebug("TODO: implement PlatformState::xmm_register"); return Register(); }; virtual Register ymm_register(size_t n) const { qDebug("TODO: implement PlatformState::ymm_register"); return Register(); }; virtual Register gp_register(size_t n) const { qDebug("TODO: implement PlatformState::gp_register"); return Register(); }; virtual int fpu_stack_pointer() const { qDebug("TODO: implement PlatformState::fpu_stack_pointer"); return 0; }; virtual edb::value80 fpu_register(size_t n) const { qDebug("TODO: implement PlatformState::fpu_register"); return edb::value80(); }; virtual bool fpu_register_is_empty(size_t n) const { qDebug("TODO: implement PlatformState::fpu_register_is_empty"); return true; }; virtual QString fpu_register_tag_string(size_t n) const { qDebug("TODO: implement PlatformState::fpu_register_tag_string"); return ""; }; virtual edb::value16 fpu_control_word() const { qDebug("TODO: implement PlatformState::fpu_control_word"); return edb::value16(); }; virtual edb::value16 fpu_status_word() const { qDebug("TODO: implement PlatformState::fpu_status_word"); return edb::value16(); }; virtual edb::value16 fpu_tag_word() const { qDebug("TODO: implement PlatformState::fpu_tag_word"); return edb::value16(); }; private: CONTEXT context_; edb::address_t fs_base_; edb::address_t gs_base_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/win32/PlatformEvent.cpp0000644000175000017500000003173613273160654023635 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "PlatformEvent.h" #include "edb.h" namespace DebuggerCorePlugin { //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ PlatformEvent::PlatformEvent() : event(DEBUG_EVENT()) { } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ PlatformEvent *PlatformEvent::clone() const { return new PlatformEvent(*this); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ IDebugEvent::Message PlatformEvent::error_description() const { Q_ASSERT(is_error()); auto fault_address = static_cast(-1); if(event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { fault_address = (edb::address_t)(event.u.Exception.ExceptionRecord.ExceptionInformation[1]); } switch(code()) { case EXCEPTION_ACCESS_VIOLATION: return Message( tr("Illegal Access Fault"), tr( "

The debugged application encountered a segmentation fault.
The address 0x%1 could not be accessed.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

").arg(edb::v1::format_pointer(fault_address)), tr("EXCEPTION_ACCESS_VIOLATION") ); case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return Message( tr("Array Bounds Error"), tr( "

The debugged application tried to access an out of bounds array element.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

").arg(edb::v1::format_pointer(fault_address)), tr("EXCEPTION_ARRAY_BOUNDS_EXCEEDED") ); case EXCEPTION_DATATYPE_MISALIGNMENT: return Message( tr("Bus Error"), tr( "

The debugged application tried to read or write data that is misaligned.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_DATATYPE_MISALIGNMENT") ); case EXCEPTION_FLT_DENORMAL_OPERAND: return Message( tr("Floating Point Exception"), tr( "

One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_FLT_DENORMAL_OPERAND") ); case EXCEPTION_FLT_DIVIDE_BY_ZERO: return Message( tr("Floating Point Exception"), tr( "

The debugged application tried to divide a floating-point value by a floating-point divisor of zero.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_FLT_DIVIDE_BY_ZERO") ); case EXCEPTION_FLT_INEXACT_RESULT: return Message( tr("Floating Point Exception"), tr( "

The result of a floating-point operation cannot be represented exactly as a decimal fraction.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPITION_FLT_INEXACT_RESULT") ); case EXCEPTION_FLT_INVALID_OPERATION: return Message( tr("Floating Point Exception"), tr( "

The application attempted an invalid floating point operation.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_FLT_INVALID_OPERATION") ); case EXCEPTION_FLT_OVERFLOW: return Message( tr("Floating Point Exception"), tr( "

The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_FLT_OVERFLOW") ); case EXCEPTION_FLT_STACK_CHECK: return Message( tr("Floating Point Exception"), tr( "

The stack overflowed or underflowed as the result of a floating-point operation.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_FLT_STACK_CHECK") ); case EXCEPTION_FLT_UNDERFLOW: return Message( tr("Floating Point Exception"), tr( "

The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_FLT_UNDERFLOW") ); case EXCEPTION_ILLEGAL_INSTRUCTION: return Message( tr("Illegal Instruction Fault"), tr( "

The debugged application attempted to execute an illegal instruction.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_ILLEGAL_INSTRUCTION") ); case EXCEPTION_IN_PAGE_ERROR: return Message( tr("Page Error"), tr( "

The debugged application tried to access a page that was not present, and the system was unable to load the page.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_IN_PAGE_ERROR") ); case EXCEPTION_INT_DIVIDE_BY_ZERO: return Message( tr("Divide By Zero"), tr( "

The debugged application tried to divide an integer value by an integer divisor of zero.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_INT_DIVIDE_BY_ZERO") ); case EXCEPTION_INT_OVERFLOW: return Message( tr("Integer Overflow"), tr( "

The result of an integer operation caused a carry out of the most significant bit of the result.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_INT_OVERFLOW") ); case EXCEPTION_INVALID_DISPOSITION: return Message( tr("Invalid Disposition"), tr( "

An exception handler returned an invalid disposition to the exception dispatcher.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_INVALID_DISPOSITION") ); case EXCEPTION_NONCONTINUABLE_EXCEPTION: return Message( tr("Non-Continuable Exception"), tr( "

The debugged application tried to continue execution after a non-continuable exception occurred.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_NONCONTINUABLE_EXCEPTION") ); case EXCEPTION_PRIV_INSTRUCTION: return Message( tr("Privileged Instruction"), tr( "

The debugged application tried to execute an instruction whose operation is not allowed in the current machine mode.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_PRIV_INSTRUCTION") ); case EXCEPTION_STACK_OVERFLOW: return Message( tr("Stack Overflow"), tr( "

The debugged application has exhausted its stack.

" "

If you would like to pass this exception to the application press Shift+[F7/F8/F9]

"), tr("EXCEPTION_STACK_OVERFLOW") ); default: return Message(); } } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ IDebugEvent::REASON PlatformEvent::reason() const { switch(event.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: if(event.u.Exception.ExceptionRecord.ExceptionFlags == EXCEPTION_NONCONTINUABLE) { return EVENT_TERMINATED; } else { return EVENT_STOPPED; } case EXIT_PROCESS_DEBUG_EVENT: return EVENT_EXITED; /* case CREATE_THREAD_DEBUG_EVENT: case CREATE_PROCESS_DEBUG_EVENT: case EXIT_THREAD_DEBUG_EVENT: case LOAD_DLL_DEBUG_EVENT: case UNLOAD_DLL_DEBUG_EVENT: case OUTPUT_DEBUG_STRING_EVENT: case RIP_EVENT: */ default: return EVENT_UNKNOWN; } } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ IDebugEvent::TRAP_REASON PlatformEvent::trap_reason() const { switch(event.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: switch(event.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_BREAKPOINT: return TRAP_BREAKPOINT; case EXCEPTION_SINGLE_STEP: return TRAP_STEPPING; } } return TRAP_BREAKPOINT; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PlatformEvent::exited() const { return reason() == EVENT_EXITED; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PlatformEvent::is_error() const { switch(event.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: switch(event.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: case EXCEPTION_DATATYPE_MISALIGNMENT: case EXCEPTION_FLT_DENORMAL_OPERAND: case EXCEPTION_FLT_DIVIDE_BY_ZERO: case EXCEPTION_FLT_INEXACT_RESULT: case EXCEPTION_FLT_INVALID_OPERATION: case EXCEPTION_FLT_OVERFLOW: case EXCEPTION_FLT_STACK_CHECK: case EXCEPTION_FLT_UNDERFLOW: case EXCEPTION_ILLEGAL_INSTRUCTION: case EXCEPTION_INT_DIVIDE_BY_ZERO: case EXCEPTION_INT_OVERFLOW: case EXCEPTION_INVALID_DISPOSITION: case EXCEPTION_IN_PAGE_ERROR: case EXCEPTION_NONCONTINUABLE_EXCEPTION: case EXCEPTION_PRIV_INSTRUCTION: case EXCEPTION_STACK_OVERFLOW: return true; case EXCEPTION_BREAKPOINT: case EXCEPTION_SINGLE_STEP: return false; } /* case CREATE_THREAD_DEBUG_EVENT: case CREATE_PROCESS_DEBUG_EVENT: case EXIT_THREAD_DEBUG_EVENT: case EXIT_PROCESS_DEBUG_EVENT: case LOAD_DLL_DEBUG_EVENT: case UNLOAD_DLL_DEBUG_EVENT: case OUTPUT_DEBUG_STRING_EVENT: case RIP_EVENT: */ default: return false; } } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PlatformEvent::is_kill() const { return false; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PlatformEvent::is_stop() const { return !is_trap(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PlatformEvent::is_trap() const { if(stopped()) { switch(event.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_SINGLE_STEP: case EXCEPTION_BREAKPOINT: return true; default: return false; } } return false; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PlatformEvent::terminated() const { return reason() == EVENT_TERMINATED; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PlatformEvent::stopped() const { return reason() == EVENT_STOPPED; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::pid_t PlatformEvent::process() const { return event.dwProcessId; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::tid_t PlatformEvent::thread() const { return event.dwThreadId; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ int PlatformEvent::code() const { if(stopped()) { return event.u.Exception.ExceptionRecord.ExceptionCode; } if(terminated()) { return event.u.Exception.ExceptionRecord.ExceptionCode; } if(exited()) { return event.u.ExitProcess.dwExitCode; } return 0; } } edb-debugger-1.0.0/plugins/DebuggerCore/win32/DebuggerCore.cpp0000644000175000017500000007145413273160654023405 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "DebuggerCore.h" #include "edb.h" #include "MemoryRegions.h" #include "PlatformEvent.h" #include "PlatformProcess.h" #include "PlatformRegion.h" #include "PlatformState.h" #include "State.h" #include "string_hash.h" #include #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma comment(lib, "Advapi32.lib") #pragma comment(lib, "Psapi.lib") #endif namespace DebuggerCorePlugin { typedef struct _LSA_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING; typedef struct _PEB_LDR_DATA { BYTE Reserved1[8]; PVOID Reserved2[3]; LIST_ENTRY InMemoryOrderModuleList; } PEB_LDR_DATA, *PPEB_LDR_DATA; typedef struct _RTL_USER_PROCESS_PARAMETERS { BYTE Reserved1[16]; PVOID Reserved2[10]; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; typedef VOID (NTAPI *PPS_POST_PROCESS_INIT_ROUTINE)(VOID); #ifdef Q_OS_WIN64 typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[21]; PPEB_LDR_DATA LoaderData; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved3[520]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved4[136]; ULONG SessionId; } PEB, *PPEB; #else typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved4[104]; PVOID Reserved5[52]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved6[128]; PVOID Reserved7[1]; ULONG SessionId; } PEB, *PPEB; #endif typedef struct _PROCESS_BASIC_INFORMATION { PVOID Reserved1; PPEB PebBaseAddress; PVOID Reserved2[2]; ULONG_PTR UniqueProcessId; PVOID Reserved3; } PROCESS_BASIC_INFORMATION; typedef enum _PROCESSINFOCLASS { ProcessBasicInformation = 0, ProcessDebugPort = 7, ProcessWow64Information = 26, ProcessImageFileName = 27 } PROCESSINFOCLASS; namespace { typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); LPFN_ISWOW64PROCESS fnIsWow64Process; class Win32Thread { public: Win32Thread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId) { handle_ = OpenThread(dwDesiredAccess, bInheritHandle, dwThreadId); } ~Win32Thread() { if(handle_) { CloseHandle(handle_); } } public: BOOL GetThreadContext(LPCONTEXT lpContext) { return ::GetThreadContext(handle_, lpContext); } BOOL SetThreadContext(const CONTEXT *lpContext) { return ::SetThreadContext(handle_, lpContext); } BOOL GetThreadSelectorEntry(DWORD dwSelector, LPLDT_ENTRY lpSelectorEntry) { return ::GetThreadSelectorEntry(handle_, dwSelector, lpSelectorEntry); } public: operator void*() const { return reinterpret_cast(handle_ != 0); } private: HANDLE handle_; }; /* * Required to debug and adjust the memory of a process owned by another account. * OpenProcess quote (MSDN): * "If the caller has enabled the SeDebugPrivilege privilege, the requested access * is granted regardless of the contents of the security descriptor." * Needed to open system processes (user SYSTEM) * * NOTE: You need to be admin to enable this privilege * NOTE: You need to have the 'Debug programs' privilege set for the current user, * if the privilege is not present it can't be enabled! * NOTE: Detectable by antidebug code (changes debuggee privileges too) */ bool set_debug_privilege(HANDLE process, bool set) { HANDLE token; bool ok = false; //process must have PROCESS_QUERY_INFORMATION if(OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES, &token)) { LUID luid; if(LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = set ? SE_PRIVILEGE_ENABLED : 0; ok = AdjustTokenPrivileges(token, false, &tp, NULL, NULL, NULL); } CloseHandle(token); } return ok; } } //------------------------------------------------------------------------------ // Name: DebuggerCore // Desc: constructor //------------------------------------------------------------------------------ DebuggerCore::DebuggerCore() : start_address(0), image_base(0), page_size_(0), process_handle_(0) { DebugSetProcessKillOnExit(false); SYSTEM_INFO sys_info; GetSystemInfo(&sys_info); page_size_ = sys_info.dwPageSize; set_debug_privilege(GetCurrentProcess(), true); // gogo magic powers } //------------------------------------------------------------------------------ // Name: ~DebuggerCore // Desc: //------------------------------------------------------------------------------ DebuggerCore::~DebuggerCore() { detach(); set_debug_privilege(GetCurrentProcess(), false); } //------------------------------------------------------------------------------ // Name: page_size // Desc: returns the size of a page on this system //------------------------------------------------------------------------------ edb::address_t DebuggerCore::page_size() const { return page_size_; } //------------------------------------------------------------------------------ // Name: has_extension // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::has_extension(quint64 ext) const { #if !defined(EDB_X86_64) switch(ext) { case edb::string_hash("MMX"): return IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE); case edb::string_hash("XMM"): return IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE); default: return false; } #else switch(ext) { case edb::string_hash("MMX"): case edb::string_hash("XMM"): return true; default: return false; } #endif } //------------------------------------------------------------------------------ // Name: wait_debug_event // Desc: waits for a debug event, secs is a timeout (but is not yet respected) // ok will be set to false if the timeout expires //------------------------------------------------------------------------------ std::shared_ptr DebuggerCore::wait_debug_event(int msecs) { if(attached()) { DEBUG_EVENT de; while(WaitForDebugEvent(&de, msecs == 0 ? INFINITE : msecs)) { Q_ASSERT(pid_ == de.dwProcessId); active_thread_ = de.dwThreadId; bool propagate = false; switch(de.dwDebugEventCode) { case CREATE_THREAD_DEBUG_EVENT: threads_.insert(active_thread_); break; case EXIT_THREAD_DEBUG_EVENT: threads_.remove(active_thread_); break; case CREATE_PROCESS_DEBUG_EVENT: CloseHandle(de.u.CreateProcessInfo.hFile); start_address = edb::address_t::fromZeroExtended(de.u.CreateProcessInfo.lpStartAddress); image_base = edb::address_t::fromZeroExtended(de.u.CreateProcessInfo.lpBaseOfImage); break; case LOAD_DLL_DEBUG_EVENT: CloseHandle(de.u.LoadDll.hFile); break; case EXIT_PROCESS_DEBUG_EVENT: CloseHandle(process_handle_); process_handle_ = 0; pid_ = 0; start_address = 0; image_base = 0; // handle_event_exited returns DEBUG_STOP, which in turn keeps the debugger from resuming the process // However, this is needed to close all internal handles etc. and finish the debugging session // So we do it manually here resume(edb::DEBUG_CONTINUE); propagate = true; break; case EXCEPTION_DEBUG_EVENT: propagate = true; break; default: break; } if(propagate) { // normal event auto e = std::make_shared(); e->event = de; return e; } resume(edb::DEBUG_EXCEPTION_NOT_HANDLED); } } return nullptr; } //------------------------------------------------------------------------------ // Name: read_pages // Desc: reads pages from the process starting at
// Note: buf's size must be >= count * page_size() // Note: address MUST be page aligned. //------------------------------------------------------------------------------ bool DebuggerCore::read_pages(edb::address_t address, void *buf, std::size_t count) { Q_ASSERT(address % page_size() == 0); return read_bytes(address, buf, page_size() * count); } //------------------------------------------------------------------------------ // Name: read_bytes // Desc: reads bytes into starting at
// Note: if the read failed, the part of the buffer that could not be read will // be filled with 0xff bytes //------------------------------------------------------------------------------ bool DebuggerCore::read_bytes(edb::address_t address, void *buf, std::size_t len) { Q_ASSERT(buf); if(attached()) { if(len == 0) { return true; } memset(buf, 0xff, len); SIZE_T bytes_read = 0; if(ReadProcessMemory(process_handle_, reinterpret_cast(address.toUint()), buf, len, &bytes_read)) { for(const std::shared_ptr &bp: breakpoints_) { if(bp->address() >= address && bp->address() < address + bytes_read) { reinterpret_cast(buf)[bp->address() - address] = bp->original_bytes()[0]; } } return true; } } return false; } //------------------------------------------------------------------------------ // Name: write_bytes // Desc: writes bytes from starting at
//------------------------------------------------------------------------------ bool DebuggerCore::write_bytes(edb::address_t address, const void *buf, std::size_t len) { Q_ASSERT(buf); if(attached()) { if(len == 0) { return true; } SIZE_T bytes_written = 0; return WriteProcessMemory(process_handle_, reinterpret_cast(address.toUint()), buf, len, &bytes_written); } return false; } //------------------------------------------------------------------------------ // Name: attach // Desc: //------------------------------------------------------------------------------ Status DebuggerCore::attach(edb::pid_t pid) { detach(); // These should be all the permissions we need const DWORD ACCESS = PROCESS_TERMINATE | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME; if(HANDLE ph = OpenProcess(ACCESS, false, pid)) { if(DebugActiveProcess(pid)) { process_handle_ = ph; pid_ = pid; return Status::Ok; } else { CloseHandle(ph); } } return Status("Error DebuggerCore::attach"); } //------------------------------------------------------------------------------ // Name: detach // Desc: //------------------------------------------------------------------------------ Status DebuggerCore::detach() { if(attached()) { clear_breakpoints(); // Make sure exceptions etc. are passed ContinueDebugEvent(pid(), active_thread(), DBG_CONTINUE); DebugActiveProcessStop(pid()); CloseHandle(process_handle_); process_handle_ = 0; pid_ = 0; start_address = 0; image_base = 0; threads_.clear(); } return Status::Ok; } //------------------------------------------------------------------------------ // Name: kill // Desc: //------------------------------------------------------------------------------ void DebuggerCore::kill() { if(attached()) { TerminateProcess(process_handle_, -1); detach(); } } //------------------------------------------------------------------------------ // Name: pause // Desc: stops *all* threads of a process //------------------------------------------------------------------------------ void DebuggerCore::pause() { if(attached()) { DebugBreakProcess(process_handle_); } } //------------------------------------------------------------------------------ // Name: resume // Desc: //------------------------------------------------------------------------------ void DebuggerCore::resume(edb::EVENT_STATUS status) { // TODO: assert that we are paused if(attached()) { if(status != edb::DEBUG_STOP) { // TODO: does this resume *all* threads? // it does! (unless you manually paused one using SuspendThread) ContinueDebugEvent( pid(), active_thread(), (status == edb::DEBUG_CONTINUE) ? (DBG_CONTINUE) : (DBG_EXCEPTION_NOT_HANDLED)); } } } //------------------------------------------------------------------------------ // Name: step // Desc: //------------------------------------------------------------------------------ void DebuggerCore::step(edb::EVENT_STATUS status) { // TODO: assert that we are paused if(attached()) { if(status != edb::DEBUG_STOP) { Win32Thread thread(THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, FALSE, active_thread()); if(thread) { CONTEXT context; context.ContextFlags = CONTEXT_CONTROL; thread.GetThreadContext(&context); context.EFlags |= (1 << 8); // set the trap flag thread.SetThreadContext(&context); resume(status); /* ContinueDebugEvent( pid(), active_thread(), (status == edb::DEBUG_CONTINUE) ? (DBG_CONTINUE) : (DBG_EXCEPTION_NOT_HANDLED)); */ } } } } //------------------------------------------------------------------------------ // Name: get_state // Desc: //------------------------------------------------------------------------------ void DebuggerCore::get_state(State *state) { // TODO: assert that we are paused Q_ASSERT(state); auto state_impl = static_cast(state->impl_); if(attached() && state_impl) { Win32Thread thread(THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT, FALSE, active_thread()); if(thread) { state_impl->context_.ContextFlags = CONTEXT_ALL; //CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT; thread.GetThreadContext(&state_impl->context_); state_impl->gs_base_ = 0; state_impl->fs_base_ = 0; // GetThreadSelectorEntry always returns false on x64 // on x64 gs_base == TEB, maybe we can use that somehow #if !defined(EDB_X86_64) LDT_ENTRY ldt_entry; if(thread.GetThreadSelectorEntry(state_impl->context_.SegGs, &ldt_entry)) { state_impl->gs_base_ = ldt_entry.BaseLow | (ldt_entry.HighWord.Bits.BaseMid << 16) | (ldt_entry.HighWord.Bits.BaseHi << 24); } if(thread.GetThreadSelectorEntry(state_impl->context_.SegFs, &ldt_entry)) { state_impl->fs_base_ = ldt_entry.BaseLow | (ldt_entry.HighWord.Bits.BaseMid << 16) | (ldt_entry.HighWord.Bits.BaseHi << 24); } #endif } } else { state->clear(); } } //------------------------------------------------------------------------------ // Name: set_state // Desc: //------------------------------------------------------------------------------ void DebuggerCore::set_state(const State &state) { // TODO: assert that we are paused auto state_impl = static_cast(state.impl_); if(attached()) { state_impl->context_.ContextFlags = CONTEXT_ALL; //CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT; Win32Thread thread(THREAD_SET_CONTEXT, FALSE, active_thread()); if(thread) { thread.SetThreadContext(&state_impl->context_); } } } //------------------------------------------------------------------------------ // Name: open // Desc: // TODO: Don't inherit security descriptors from this process (default values) // Is this even possible? //------------------------------------------------------------------------------ Status DebuggerCore::open(const QString &path, const QString &cwd, const QList &args, const QString &tty) { Q_UNUSED(tty); Q_ASSERT(!path.isEmpty()); bool ok = false; detach(); // default to process's directory QString tcwd; if(cwd.isEmpty()) { tcwd = QFileInfo(path).canonicalPath(); } else { tcwd = cwd; } STARTUPINFO startup_info = { 0 }; PROCESS_INFORMATION process_info = { 0 }; const DWORD CREATE_FLAGS = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE; wchar_t *const env_block = GetEnvironmentStringsW(); // Set up command line QString command_str = '\"' + QFileInfo(path).canonicalPath() + '\"'; // argv[0] = full path (explorer style) if(!args.isEmpty()) { for(QByteArray arg: args) { command_str += " "; command_str += arg; } } // CreateProcessW wants a writable copy of the command line :< auto command_path = new wchar_t[command_str.length() + sizeof(wchar_t)]; wcscpy_s(command_path, command_str.length() + 1, reinterpret_cast(command_str.utf16())); if(CreateProcessW( reinterpret_cast(path.utf16()), // exe command_path, // commandline NULL, // default security attributes NULL, // default thread security too FALSE, // inherit handles CREATE_FLAGS, env_block, // environment data reinterpret_cast(tcwd.utf16()), // working directory &startup_info, &process_info)) { pid_ = process_info.dwProcessId; active_thread_ = process_info.dwThreadId; process_handle_ = process_info.hProcess; // has PROCESS_ALL_ACCESS CloseHandle(process_info.hThread); // We don't need the thread handle set_debug_privilege(process_handle_, false); ok = true; } delete[] command_path; FreeEnvironmentStringsW(env_block); if (ok) { return Status::Ok; } else { return Status("Error DebuggerCore::open"); } } //------------------------------------------------------------------------------ // Name: create_state // Desc: //------------------------------------------------------------------------------ IState *DebuggerCore::create_state() const { return new PlatformState; } //------------------------------------------------------------------------------ // Name: sys_pointer_size // Desc: returns the size of a pointer on this arch //------------------------------------------------------------------------------ int DebuggerCore::sys_pointer_size() const { return sizeof(void *); } //------------------------------------------------------------------------------ // Name: enumerate_processes // Desc: //------------------------------------------------------------------------------ QMap > DebuggerCore::enumerate_processes() const { QMap > ret; HANDLE handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(handle != INVALID_HANDLE_VALUE) { // resolve the "IsWow64Process" function since it may or may not exist fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); PROCESSENTRY32 lppe; std::memset(&lppe, 0, sizeof(lppe)); lppe.dwSize = sizeof(lppe); if(Process32First(handle, &lppe)) { do { std::shared_ptr pi = std::make_shared(lppe); ret.insert(pi->pid(), pi); std::memset(&lppe, 0, sizeof(lppe)); lppe.dwSize = sizeof(lppe); } while(Process32Next(handle, &lppe)); } CloseHandle(handle); } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::process_exe(edb::pid_t pid) const { QString ret; // These functions don't work immediately after CreateProcess but only // after basic initialization, usually after the system breakpoint // The same applies to psapi/toolhelp, maybe using NtQueryXxxxxx is the way to go typedef BOOL (WINAPI *QueryFullProcessImageNameWPtr)( HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize ); HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); QueryFullProcessImageNameWPtr QueryFullProcessImageNameWFunc = (QueryFullProcessImageNameWPtr)GetProcAddress(kernel32, "QueryFullProcessImageNameW"); wchar_t name[MAX_PATH] = L""; if(QueryFullProcessImageNameWFunc/* && LOBYTE(GetVersion()) >= 6*/) { // Vista and up const DWORD ACCESS = PROCESS_QUERY_LIMITED_INFORMATION; if(HANDLE ph = OpenProcess(ACCESS, false, pid)) { DWORD size = _countof(name); if(QueryFullProcessImageNameWFunc(ph, 0, name, &size)) { ret = QString::fromWCharArray(name); } CloseHandle(ph); } } else { // Attempting to get an unknown privilege will fail unless we have // debug privilege set, so 2 calls to OpenProcess // (PROCESS_QUERY_LIMITED_INFORMATION is Vista and up) const DWORD ACCESS = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; if(HANDLE ph = OpenProcess(ACCESS, false, pid)) { if(GetModuleFileNameExW(ph, NULL, name, _countof(name))) { ret = QString::fromWCharArray(name); } CloseHandle(ph); } } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::process_cwd(edb::pid_t pid) const { Q_UNUSED(pid); // TODO: implement this return QString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::pid_t DebuggerCore::parent_pid(edb::pid_t pid) const { edb::pid_t parent = 1; // 1?? HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid); if(hProcessSnap != INVALID_HANDLE_VALUE) { PROCESSENTRY32W pe32; pe32.dwSize = sizeof(pe32); if(Process32FirstW(hProcessSnap, &pe32)) { do { if(pid == pe32.th32ProcessID) { parent = pe32.th32ParentProcessID; break; } } while(Process32NextW(hProcessSnap, &pe32)); } CloseHandle(hProcessSnap); } return parent; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList> DebuggerCore::memory_regions() const { QList> regions; if(pid_ != 0) { if(HANDLE ph = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid_)) { edb::address_t addr = 0; auto last_base = reinterpret_cast(-1); Q_FOREVER { MEMORY_BASIC_INFORMATION info; VirtualQueryEx(ph, reinterpret_cast(addr.toUint()), &info, sizeof(info)); if(last_base == info.BaseAddress) { break; } last_base = info.BaseAddress; if(info.State == MEM_COMMIT) { const auto start = edb::address_t::fromZeroExtended(info.BaseAddress); const auto end = edb::address_t::fromZeroExtended(info.BaseAddress) + info.RegionSize; const auto base = edb::address_t::fromZeroExtended(info.AllocationBase); const QString name = QString(); const IRegion::permissions_t permissions = info.Protect; // let std::shared_ptr handle permissions and modifiers if(info.Type == MEM_IMAGE) { // set region.name to the module name } // get stack addresses, PEB, TEB, etc. and set name accordingly regions.push_back(std::make_shared(start, end, base, name, permissions)); } addr += info.RegionSize; } CloseHandle(ph); } } return regions; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList DebuggerCore::process_args(edb::pid_t pid) const { QList ret; if(pid != 0) { typedef NTSTATUS (*WINAPI ZwQueryInformationProcessPtr)( HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength ); HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); ZwQueryInformationProcessPtr ZwQueryInformationProcessFunc = (ZwQueryInformationProcessPtr)GetProcAddress(ntdll, "NtQueryInformationProcess"); PROCESS_BASIC_INFORMATION ProcessInfo; if(ZwQueryInformationProcessFunc) { if(HANDLE ph = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid_)) { ULONG l; NTSTATUS r = ZwQueryInformationProcessFunc(ph, ProcessBasicInformation, &ProcessInfo, sizeof(PROCESS_BASIC_INFORMATION), &l); CloseHandle(ph); } } } return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t DebuggerCore::process_code_address() const { qDebug() << "TODO: implement DebuggerCore::process_code_address"; return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t DebuggerCore::process_data_address() const { qDebug() << "TODO: implement DebuggerCore::process_data_address"; return 0; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QMap DebuggerCore::exceptions() const { QMap exceptions; return exceptions; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QList DebuggerCore::loaded_modules() const { QList ret; HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid()); if(hModuleSnap != INVALID_HANDLE_VALUE) { MODULEENTRY32 me32; me32.dwSize = sizeof(me32); if(Module32First(hModuleSnap, &me32)) { do { Module module; module.base_address = edb::address_t::fromZeroExtended(me32.modBaseAddr); module.name = QString::fromWCharArray(me32.szModule); ret.push_back(module); } while(Module32Next(hModuleSnap, &me32)); } } CloseHandle(hModuleSnap); return ret; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QDateTime DebuggerCore::process_start(edb::pid_t pid) const { qDebug() << "TODO: implement DebuggerCore::process_start"; return QDateTime(); } //------------------------------------------------------------------------------ // Name: cpu_type // Desc: //------------------------------------------------------------------------------ quint64 DebuggerCore::cpu_type() const { #ifdef EDB_X86 return edb::string_hash("x86"); #elif defined(EDB_X86_64) return edb::string_hash("x86-64"); #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::format_pointer(edb::address_t address) const { char buf[32]; #ifdef EDB_X86 qsnprintf(buf, sizeof(buf), "%08x", address); #elif defined(EDB_X86_64) qsnprintf(buf, sizeof(buf), "%016llx", address); #endif return buf; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::stack_pointer() const { #ifdef EDB_X86 return "esp"; #elif defined(EDB_X86_64) return "rsp"; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::frame_pointer() const { #ifdef EDB_X86 return "ebp"; #elif defined(EDB_X86_64) return "rbp"; #endif } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::instruction_pointer() const { #ifdef EDB_X86 return "eip"; #elif defined(EDB_X86_64) return "rip"; #endif } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(DebuggerCore, DebuggerCore) #endif } edb-debugger-1.0.0/plugins/DebuggerCore/DebuggerCoreBase.cpp0000644000175000017500000001453013273160654023226 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "DebuggerCoreBase.h" #include "Breakpoint.h" #include "Configuration.h" #include "edb.h" #include namespace DebuggerCorePlugin { //------------------------------------------------------------------------------ // Name: DebuggerCoreBase // Desc: constructor //------------------------------------------------------------------------------ DebuggerCoreBase::DebuggerCoreBase() : pid_(0) { } //------------------------------------------------------------------------------ // Name: ~DebuggerCoreBase // Desc: destructor //------------------------------------------------------------------------------ DebuggerCoreBase::~DebuggerCoreBase() { } //------------------------------------------------------------------------------ // Name: clear_breakpoints // Desc: removes all breakpoints //------------------------------------------------------------------------------ void DebuggerCoreBase::clear_breakpoints() { if(attached()) { breakpoints_.clear(); } } //------------------------------------------------------------------------------ // Name: add_breakpoint // Desc: creates a new breakpoint // (only if there isn't already one at the given address) //------------------------------------------------------------------------------ std::shared_ptr DebuggerCoreBase::add_breakpoint(edb::address_t address) { try { if(attached()) { if(!find_breakpoint(address)) { auto bp = std::make_shared(address); breakpoints_[address] = bp; return bp; } } return nullptr; } catch(const breakpoint_creation_error &e) { qDebug() << "Failed to create breakpoint"; return nullptr; } } //------------------------------------------------------------------------------ // Name: find_breakpoint // Desc: returns the breakpoint at the given address or std::shared_ptr() //------------------------------------------------------------------------------ std::shared_ptr DebuggerCoreBase::find_breakpoint(edb::address_t address) { if(attached()) { auto it = breakpoints_.find(address); if(it != breakpoints_.end()) { return it.value(); } } return nullptr; } //------------------------------------------------------------------------------ // Name: find_breakpoint // Desc: similarly to find_breakpoint, finds a breakpoint near given address. But // unlike find_breakpoint, this function looks for a breakpoint which ends // up at this address after being triggered, instead of just starting there. //------------------------------------------------------------------------------ std::shared_ptr DebuggerCoreBase::find_triggered_breakpoint(edb::address_t address) { if(attached()) { for(const auto size : Breakpoint::possible_rewind_sizes()) { const auto bpAddr=address-size; const auto bp=find_breakpoint(bpAddr); if(bp && bp->address()==bpAddr) return bp; } } return nullptr; } //------------------------------------------------------------------------------ // Name: remove_breakpoint // Desc: removes the breakpoint at the given address, this is a no-op if there // is no breakpoint present. // Note: if another part of the code has a reference to the BP, it will not // actually be removed until it releases the reference. //------------------------------------------------------------------------------ void DebuggerCoreBase::remove_breakpoint(edb::address_t address) { // TODO(eteran): assert paused if(attached()) { auto it = breakpoints_.find(address); if(it != breakpoints_.end()) { breakpoints_.erase(it); } } } //------------------------------------------------------------------------------ // Name: end_debug_session // Desc: Ends debug session, detaching from or killing debuggee according to // user preferences //------------------------------------------------------------------------------ void DebuggerCoreBase::end_debug_session() { if(attached()) { switch(edb::v1::config().close_behavior) { case Configuration::Detach: detach(); break; case Configuration::Kill: kill(); break; case Configuration::KillIfLaunchedDetachIfAttached: if(last_means_of_capture() == MeansOfCapture::Launch) { kill(); } else { detach(); } break; } } } //------------------------------------------------------------------------------ // Name: backup_breakpoints // Desc: returns a copy of the BP list, these count as references to the BPs // preventing full removal until this list is destructed. //------------------------------------------------------------------------------ DebuggerCoreBase::BreakpointList DebuggerCoreBase::backup_breakpoints() const { return breakpoints_; } //------------------------------------------------------------------------------ // Name: open // Desc: executes the given program //------------------------------------------------------------------------------ Status DebuggerCoreBase::open(const QString &path, const QString &cwd, const QList &args) { return open(path, cwd, args, QString()); } //------------------------------------------------------------------------------ // Name: pid // Desc: returns the pid of the currently debugged process (0 if not attached) //------------------------------------------------------------------------------ edb::pid_t DebuggerCoreBase::pid() const { return pid_; } //------------------------------------------------------------------------------ // Name: attached // Desc: //------------------------------------------------------------------------------ bool DebuggerCoreBase::attached() const { return pid() != 0; } auto DebuggerCoreBase::supported_breakpoint_types() const -> std::vector { return Breakpoint::supported_types(); } } edb-debugger-1.0.0/plugins/DebuggerCore/CMakeLists.txt0000644000175000017500000000726013273160654022134 0ustar eteraneterancmake_minimum_required (VERSION 2.8) include("GNUInstallDirs") set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) include("${PROJECT_SOURCE_DIR}/cmake/EnableCXX11.cmake") set(PluginName "DebuggerCore") include_directories(${CMAKE_CURRENT_SOURCE_DIR}) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(UI_FILES unix/linux/DialogMemoryAccess.ui ) endif() if(Qt5Core_FOUND) find_package(Qt5 5.0.0 REQUIRED Widgets) qt5_wrap_ui(UI_H ${UI_FILES}) else(Qt5Core_FOUND) find_package(Qt4 4.6.0 QUIET REQUIRED QtCore QtGui) include(${QT_USE_FILE}) qt4_wrap_ui(UI_H ${UI_FILES}) endif() set(DebuggerCore_SRCS DebuggerCoreBase.cpp DebuggerCoreBase.h ) if(UNIX) include_directories( "unix" ) set(DebuggerCore_SRCS ${DebuggerCore_SRCS} unix/DebuggerCoreUNIX.cpp unix/DebuggerCoreUNIX.h ) endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") include_directories( "unix/linux" ) set(DebuggerCore_SRCS ${DebuggerCore_SRCS} unix/linux/DebuggerCore.cpp unix/linux/DebuggerCore.h unix/linux/PlatformCommon.cpp unix/linux/PlatformCommon.h unix/linux/PlatformEvent.cpp unix/linux/PlatformEvent.h unix/linux/PlatformProcess.cpp unix/linux/PlatformProcess.h unix/linux/PlatformRegion.cpp unix/linux/PlatformRegion.h unix/linux/PlatformThread.cpp unix/linux/PlatformThread.h unix/linux/FeatureDetect.cpp unix/linux/FeatureDetect.h unix/linux/DialogMemoryAccess.cpp unix/linux/DialogMemoryAccess.h ${UI_H} ) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") include_directories( "win32" ) set(DebuggerCore_SRCS ${DebuggerCore_SRCS} win32/DebuggerCore.cpp win32/DebuggerCore.h win32/PlatformEvent.cpp win32/PlatformEvent.h win32/PlatformProcess.cpp win32/PlatformProcess.h win32/PlatformRegion.cpp win32/PlatformRegion.h win32/PlatformState.cpp win32/PlatformState.h ${UI_H} ) endif() if((${CMAKE_SYSTEM_PROCESSOR} MATCHES "i[3456]86") OR (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") OR (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64")) include_directories("arch/x86-generic") set(DebuggerCore_SRCS ${DebuggerCore_SRCS} arch/x86-generic/Breakpoint.cpp arch/x86-generic/Breakpoint.h ) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") include_directories("unix/linux/arch/x86-generic") set(DebuggerCore_SRCS ${DebuggerCore_SRCS} unix/linux/arch/x86-generic/PlatformState.cpp unix/linux/arch/x86-generic/PlatformState.h unix/linux/arch/x86-generic/PlatformThread.cpp ) endif() endif() if((${CMAKE_SYSTEM_PROCESSOR} MATCHES "armv[0-9]+")) include_directories("arch/arm-generic") set(DebuggerCore_SRCS ${DebuggerCore_SRCS} arch/arm-generic/Breakpoint.cpp arch/arm-generic/Breakpoint.h ) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") include_directories("unix/linux/arch/arm-generic") set(DebuggerCore_SRCS ${DebuggerCore_SRCS} unix/linux/arch/arm-generic/PlatformState.cpp unix/linux/arch/arm-generic/PlatformState.h unix/linux/arch/arm-generic/PlatformThread.cpp ) endif() endif() add_library(${PluginName} SHARED ${DebuggerCore_SRCS} ) if(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt5::Widgets) else(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt4::QtGui) endif() add_definitions(-DQT_PLUGIN) target_link_libraries(${PluginName} edb) set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}) set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}) install (TARGETS ${PluginName} DESTINATION ${CMAKE_INSTALL_LIBDIR}/edb) edb-debugger-1.0.0/plugins/DebuggerCore/DebuggerCoreBase.h0000644000175000017500000000406413273160654022674 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DEBUGGERCOREBASE_20090529_H_ #define DEBUGGERCOREBASE_20090529_H_ #include "IDebugger.h" class Status; namespace DebuggerCorePlugin { class DebuggerCoreBase : public QObject, public IDebugger { public: DebuggerCoreBase(); virtual ~DebuggerCoreBase() override; public: virtual Status open(const QString &path, const QString &cwd, const QList &args) override; virtual Status open(const QString &path, const QString &cwd, const QList &args, const QString &tty) override = 0; enum class MeansOfCapture { NeverCaptured, Attach, Launch }; virtual MeansOfCapture last_means_of_capture() const = 0; public: virtual BreakpointList backup_breakpoints() const override; virtual std::shared_ptr add_breakpoint(edb::address_t address) override; virtual std::shared_ptr find_breakpoint(edb::address_t address) override; virtual std::shared_ptr find_triggered_breakpoint(edb::address_t address) override; virtual void clear_breakpoints() override; virtual void remove_breakpoint(edb::address_t address) override; virtual void end_debug_session() override; virtual std::vector supported_breakpoint_types() const override; public: virtual edb::pid_t pid() const; protected: bool attached() const; protected: edb::pid_t pid_; BreakpointList breakpoints_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/arch/0000755000175000017500000000000013273160654020304 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/arch/x86-generic/0000755000175000017500000000000013273160654022343 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/arch/x86-generic/Breakpoint.h0000644000175000017500000000476713273160654024630 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef X86BREAKPOINT_20060720_H_ #define X86BREAKPOINT_20060720_H_ #include "IBreakpoint.h" #include "Util.h" #include namespace DebuggerCorePlugin { class Breakpoint : public IBreakpoint { public: enum class TypeId { Automatic = static_cast(IBreakpoint::TypeId::Automatic), INT3, INT1, HLT, CLI, STI, INSB, INSD, OUTSB, OUTSD, UD2, UD0, TYPE_COUNT }; using Type=util::AbstractEnumData; public: Breakpoint(edb::address_t address); virtual ~Breakpoint(); public: virtual edb::address_t address() const override { return address_; } virtual quint64 hit_count() const override { return hit_count_; } virtual bool enabled() const override { return enabled_; } virtual bool one_time() const override { return one_time_; } virtual bool internal() const override { return internal_; } virtual size_t size() const override { return original_bytes_.size(); } virtual const quint8* original_bytes() const override { return &original_bytes_[0]; } virtual IBreakpoint::TypeId type() const override { return type_; } virtual size_t rewind_size() const override; static std::vector supported_types(); static std::vector possible_rewind_sizes(); public: virtual bool enable() override; virtual bool disable() override; virtual void hit() override; virtual void set_one_time(bool value) override; virtual void set_internal(bool value) override; virtual void set_type(IBreakpoint::TypeId type) override; void set_type(TypeId type); private: std::vector original_bytes_; edb::address_t address_; quint64 hit_count_; bool enabled_ ; bool one_time_; bool internal_; Type type_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/arch/x86-generic/Breakpoint.cpp0000644000175000017500000001465013273160654025153 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "Breakpoint.h" #include "IDebugger.h" #include "IProcess.h" #include "edb.h" #include "Configuration.h" namespace DebuggerCorePlugin { namespace { const std::vector BreakpointInstructionINT3 = {0xcc}; const std::vector BreakpointInstructionINT1 = {0xf1}; const std::vector BreakpointInstructionHLT = {0xf4}; const std::vector BreakpointInstructionCLI = {0xfa}; const std::vector BreakpointInstructionSTI = {0xfb}; const std::vector BreakpointInstructionINSB = {0x6c}; const std::vector BreakpointInstructionINSD = {0x6d}; const std::vector BreakpointInstructionOUTSB = {0x6e}; const std::vector BreakpointInstructionOUTSD = {0x6f}; const std::vector BreakpointInstructionUD2 = {0x0f, 0x0b}; const std::vector BreakpointInstructionUD0 = {0x0f, 0xff}; } //------------------------------------------------------------------------------ // Name: Breakpoint // Desc: constructor //------------------------------------------------------------------------------ Breakpoint::Breakpoint(edb::address_t address) : address_(address), hit_count_(0), enabled_(false), one_time_(false), internal_(false), type_(edb::v1::config().default_breakpoint_type) { if(!enable()) { throw breakpoint_creation_error(); } } auto Breakpoint::supported_types() -> std::vector { std::vector types = { BreakpointType{Type{TypeId::Automatic},QObject::tr("Automatic")}, BreakpointType{Type{TypeId::INT3 },QObject::tr("INT3")}, BreakpointType{Type{TypeId::INT1 },QObject::tr("INT1 (ICEBP)")}, BreakpointType{Type{TypeId::HLT },QObject::tr("HLT")}, BreakpointType{Type{TypeId::CLI },QObject::tr("CLI")}, BreakpointType{Type{TypeId::STI },QObject::tr("STI")}, BreakpointType{Type{TypeId::INSB },QObject::tr("INSB")}, BreakpointType{Type{TypeId::INSD },QObject::tr("INSD")}, BreakpointType{Type{TypeId::OUTSB },QObject::tr("OUTSB")}, BreakpointType{Type{TypeId::OUTSD },QObject::tr("OUTSD")}, BreakpointType{Type{TypeId::UD2 },QObject::tr("UD2 (2-byte)")}, BreakpointType{Type{TypeId::UD0 },QObject::tr("UD0 (2-byte)")}, }; return types; } void Breakpoint::set_type(TypeId type) { disable(); type_=type; if(!enable()) { throw breakpoint_creation_error(); } } void Breakpoint::set_type(IBreakpoint::TypeId type) { disable(); if(Type{type}>=TypeId::TYPE_COUNT) throw breakpoint_creation_error(); set_type(type); } //------------------------------------------------------------------------------ // Name: ~Breakpoint // Desc: //------------------------------------------------------------------------------ Breakpoint::~Breakpoint() { disable(); } //------------------------------------------------------------------------------ // Name: enable // Desc: //------------------------------------------------------------------------------ bool Breakpoint::enable() { if(!enabled()) { if(IProcess *process = edb::v1::debugger_core->process()) { std::vector prev(2); if(process->read_bytes(address(), &prev[0], prev.size())) { original_bytes_ = prev; const std::vector* bpBytes=nullptr; switch(TypeId{type_}) { case TypeId::Automatic: case TypeId::INT3: bpBytes=&BreakpointInstructionINT3; break; case TypeId::INT1: bpBytes=&BreakpointInstructionINT1; break; case TypeId::HLT: bpBytes=&BreakpointInstructionHLT; break; case TypeId::CLI: bpBytes=&BreakpointInstructionCLI; break; case TypeId::STI: bpBytes=&BreakpointInstructionSTI; break; case TypeId::INSB: bpBytes=&BreakpointInstructionINSB; break; case TypeId::INSD: bpBytes=&BreakpointInstructionINSD; break; case TypeId::OUTSB: bpBytes=&BreakpointInstructionOUTSB; break; case TypeId::OUTSD: bpBytes=&BreakpointInstructionOUTSD; break; case TypeId::UD2: bpBytes=&BreakpointInstructionUD2; break; case TypeId::UD0: bpBytes=&BreakpointInstructionUD0; break; default: return false; } assert(bpBytes); assert(original_bytes_.size() >= bpBytes->size()); original_bytes_.resize(bpBytes->size()); if(process->write_bytes(address(), bpBytes->data(), bpBytes->size())) { enabled_ = true; return true; } } } } return false; } //------------------------------------------------------------------------------ // Name: disable // Desc: //------------------------------------------------------------------------------ bool Breakpoint::disable() { if(enabled()) { if(IProcess *process = edb::v1::debugger_core->process()) { if(process->write_bytes(address(), &original_bytes_[0], original_bytes_.size())) { enabled_ = false; return true; } } } return false; } //------------------------------------------------------------------------------ // Name: hit // Desc: //------------------------------------------------------------------------------ void Breakpoint::hit() { ++hit_count_; } //------------------------------------------------------------------------------ // Name: set_one_time // Desc: //------------------------------------------------------------------------------ void Breakpoint::set_one_time(bool value) { one_time_ = value; } //------------------------------------------------------------------------------ // Name: set_internal // Desc: //------------------------------------------------------------------------------ void Breakpoint::set_internal(bool value) { internal_ = value; } size_t Breakpoint::rewind_size() const { // TODO: make the logic more complete for multibyte breakpoints as well as for // those resulting in #GP, #UD etc. instead of the usual #BP. return 1; } std::vector Breakpoint::possible_rewind_sizes() { return {1,0,2}; // e.g. int3/int1, cli/sti/hlt/etc., int 0x1/int 0x3 } } edb-debugger-1.0.0/plugins/DebuggerCore/arch/arm-generic/0000755000175000017500000000000013273160654022475 5ustar eteraneteranedb-debugger-1.0.0/plugins/DebuggerCore/arch/arm-generic/Breakpoint.h0000644000175000017500000000473413273160654024754 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef BREAKPOINT_20060720_H_ #define BREAKPOINT_20060720_H_ #include "IBreakpoint.h" #include "Util.h" #include namespace DebuggerCorePlugin { class Breakpoint : public IBreakpoint { public: enum class TypeId { Automatic=IBreakpoint::TypeId::Automatic, ARM32, Thumb2Byte, Thumb4Byte, UniversalThumbARM32, ARM32BKPT, ThumbBKPT, TYPE_COUNT }; using Type=util::AbstractEnumData; public: Breakpoint(edb::address_t address); virtual ~Breakpoint(); public: virtual edb::address_t address() const override { return address_; } virtual quint64 hit_count() const override { return hit_count_; } virtual bool enabled() const override { return enabled_; } virtual bool one_time() const override { return one_time_; } virtual bool internal() const override { return internal_; } virtual size_t size() const override { return original_bytes_.size(); } virtual const quint8* original_bytes() const override { return &original_bytes_[0]; } virtual IBreakpoint::TypeId type() const override { return type_; } virtual size_t rewind_size() const override; static std::vector supported_types(); static std::vector possible_rewind_sizes(); public: virtual bool enable() override; virtual bool disable() override; virtual void hit() override; virtual void set_one_time(bool value) override; virtual void set_internal(bool value) override; virtual void set_type(IBreakpoint::TypeId type) override; void set_type(TypeId type); private: std::vector original_bytes_; edb::address_t address_; quint64 hit_count_; bool enabled_ ; bool one_time_; bool internal_; Type type_; }; } #endif edb-debugger-1.0.0/plugins/DebuggerCore/arch/arm-generic/Breakpoint.cpp0000644000175000017500000001531513273160654025304 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "Breakpoint.h" #include "IDebugger.h" #include "IProcess.h" #include "edb.h" #include "Configuration.h" namespace DebuggerCorePlugin { namespace { const std::vector BreakpointInstructionARM_LE = { 0xf0, 0x01, 0xf0, 0xe7 }; // udf #0x10 const std::vector BreakpointInstructionThumb_LE = { 0x01, 0xde }; // udf #1 // We have to sometimes use a 32-bit Thumb-2 breakpoint. For explanation how to // correctly use it see GDB's thumb_get_next_pcs_raw function and comments // around arm_linux_thumb2_le_breakpoint array. const std::vector BreakpointInstructionThumb2_LE = { 0xf0, 0xf7, 0x00, 0xa0 }; // udf.w #0 // This one generates SIGILL both in ARM32 and Thumb mode. In ARM23 mode it's decoded as UDF 0xDDE0, while // in Thumb it's a sequence `1: UDF 0xF0; B 1b`, which does stop the process even if it lands in the // middle (on the second half-word), although the signal still occurs at the first half-word. const std::vector BreakpointInstructionUniversalThumbARM_LE = { 0xf0, 0xde, 0xfd, 0xe7 }; const std::vector BreakpointInstructionThumbBKPT_LE = { 0x00, 0xbe }; // bkpt #0 const std::vector BreakpointInstructionARM32BKPT_LE = { 0x70, 0x00, 0x20, 0xe1 }; // bkpt #0 } //------------------------------------------------------------------------------ // Name: Breakpoint // Desc: constructor //------------------------------------------------------------------------------ Breakpoint::Breakpoint(edb::address_t address) : address_(address), hit_count_(0), enabled_(false), one_time_(false), internal_(false), type_(edb::v1::config().default_breakpoint_type) { if(!enable()) { throw breakpoint_creation_error(); } } auto Breakpoint::supported_types() -> std::vector { std::vector types = { BreakpointType{Type{TypeId::Automatic },QObject::tr("Automatic")}, BreakpointType{Type{TypeId::ARM32 },QObject::tr("Always ARM32 UDF")}, BreakpointType{Type{TypeId::Thumb2Byte },QObject::tr("Always Thumb UDF")}, BreakpointType{Type{TypeId::Thumb4Byte },QObject::tr("Always Thumb2 UDF.W")}, BreakpointType{Type{TypeId::UniversalThumbARM32},QObject::tr("Universal ARM/Thumb UDF(+B .-2)")}, BreakpointType{Type{TypeId::ARM32BKPT },QObject::tr("ARM32 BKPT (may be slow)")}, BreakpointType{Type{TypeId::ThumbBKPT },QObject::tr("Thumb BKPT (may be slow)")}, }; return types; } void Breakpoint::set_type(TypeId type) { disable(); type_=type; if(!enable()) { throw breakpoint_creation_error(); } } void Breakpoint::set_type(IBreakpoint::TypeId type) { disable(); if(Type{type}>=TypeId::TYPE_COUNT) throw breakpoint_creation_error(); set_type(type); } //------------------------------------------------------------------------------ // Name: ~Breakpoint // Desc: //------------------------------------------------------------------------------ Breakpoint::~Breakpoint() { disable(); } //------------------------------------------------------------------------------ // Name: enable // Desc: //------------------------------------------------------------------------------ bool Breakpoint::enable() { if(!enabled()) { if(IProcess *process = edb::v1::debugger_core->process()) { std::vector prev(4); prev.resize(process->read_bytes(address(), &prev[0], prev.size())); if(prev.size()) { original_bytes_ = prev; const std::vector* bpBytes=nullptr; switch(TypeId{type_}) { case TypeId::Automatic: if(edb::v1::debugger_core->cpu_mode()==IDebugger::CPUMode::Thumb) { bpBytes=&BreakpointInstructionThumb_LE; } else { bpBytes=&BreakpointInstructionARM_LE; } break; case TypeId::ARM32: bpBytes=&BreakpointInstructionARM_LE; break; case TypeId::Thumb2Byte: bpBytes=&BreakpointInstructionThumb_LE; break; case TypeId::Thumb4Byte: bpBytes=&BreakpointInstructionThumb2_LE; break; case TypeId::UniversalThumbARM32: bpBytes=&BreakpointInstructionUniversalThumbARM_LE; break; case TypeId::ARM32BKPT: bpBytes=&BreakpointInstructionARM32BKPT_LE; break; case TypeId::ThumbBKPT: bpBytes=&BreakpointInstructionThumbBKPT_LE; break; } assert(bpBytes); assert(original_bytes_.size() >= bpBytes->size()); original_bytes_.resize(bpBytes->size()); // FIXME: we don't check whether this breakpoint will overlap any of the existing breakpoints if(process->write_bytes(address(), bpBytes->data(), bpBytes->size())) { enabled_ = true; return true; } } } } return false; } //------------------------------------------------------------------------------ // Name: disable // Desc: //------------------------------------------------------------------------------ bool Breakpoint::disable() { if(enabled()) { if(IProcess *process = edb::v1::debugger_core->process()) { if(process->write_bytes(address(), &original_bytes_[0], original_bytes_.size())) { enabled_ = false; return true; } } } return false; } //------------------------------------------------------------------------------ // Name: hit // Desc: //------------------------------------------------------------------------------ void Breakpoint::hit() { ++hit_count_; } //------------------------------------------------------------------------------ // Name: set_one_time // Desc: //------------------------------------------------------------------------------ void Breakpoint::set_one_time(bool value) { one_time_ = value; } //------------------------------------------------------------------------------ // Name: set_internal // Desc: //------------------------------------------------------------------------------ void Breakpoint::set_internal(bool value) { internal_ = value; } size_t Breakpoint::rewind_size() const { // We are currently using undefined instructions as breakpoints. They result in // faults, so don't let instruction pointer past them. return 0; } std::vector Breakpoint::possible_rewind_sizes() { return {0}; // Even BKPT stops before the instruction, let alone UDF } } edb-debugger-1.0.0/plugins/SymbolViewer/0000755000175000017500000000000013273160654017461 5ustar eteraneteranedb-debugger-1.0.0/plugins/SymbolViewer/SymbolViewer.h0000644000175000017500000000243613273160654022266 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef SYMBOLVIEWER_20080812_H_ #define SYMBOLVIEWER_20080812_H_ #include "IPlugin.h" class QMenu; class QDialog; namespace SymbolViewerPlugin { class SymbolViewer : public QObject, public IPlugin { Q_OBJECT Q_INTERFACES(IPlugin) #if QT_VERSION >= 0x050000 Q_PLUGIN_METADATA(IID "edb.IPlugin/1.0") #endif Q_CLASSINFO("author", "Evan Teran") Q_CLASSINFO("url", "http://www.codef00.com") public: SymbolViewer(); virtual ~SymbolViewer(); public: virtual QMenu *menu(QWidget *parent = 0); public Q_SLOTS: void show_menu(); private: QMenu * menu_; QPointer dialog_; }; } #endif edb-debugger-1.0.0/plugins/SymbolViewer/SymbolViewer.cpp0000644000175000017500000000416413273160654022621 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "SymbolViewer.h" #include "DialogSymbolViewer.h" #include "edb.h" #include namespace SymbolViewerPlugin { //------------------------------------------------------------------------------ // Name: SymbolViewer // Desc: //------------------------------------------------------------------------------ SymbolViewer::SymbolViewer() : menu_(0), dialog_(0) { } //------------------------------------------------------------------------------ // Name: ~SymbolViewer // Desc: //------------------------------------------------------------------------------ SymbolViewer::~SymbolViewer() { delete dialog_; } //------------------------------------------------------------------------------ // Name: menu // Desc: //------------------------------------------------------------------------------ QMenu *SymbolViewer::menu(QWidget *parent) { Q_ASSERT(parent); if(!menu_) { menu_ = new QMenu(tr("SymbolViewer"), parent); menu_->addAction(tr("&Symbol Viewer"), this, SLOT(show_menu()), QKeySequence(tr("Ctrl+Alt+S"))); } return menu_; } //------------------------------------------------------------------------------ // Name: show_menu // Desc: //------------------------------------------------------------------------------ void SymbolViewer::show_menu() { if(!dialog_) { dialog_ = new DialogSymbolViewer(edb::v1::debugger_ui); } dialog_->show(); } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(SymbolViewer, SymbolViewer) #endif } edb-debugger-1.0.0/plugins/SymbolViewer/DialogSymbolViewer.h0000644000175000017500000000315613273160654023406 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DIALOGSYMBOLVIEWER_20080812_H_ #define DIALOGSYMBOLVIEWER_20080812_H_ #include #include "Types.h" class QModelIndex; class QPoint; class QSortFilterProxyModel; class QStringListModel; namespace SymbolViewerPlugin { namespace Ui { class DialogSymbolViewer; } class DialogSymbolViewer : public QDialog { Q_OBJECT public: DialogSymbolViewer(QWidget *parent = 0); virtual ~DialogSymbolViewer(); public Q_SLOTS: void on_listView_doubleClicked(const QModelIndex &index); void on_listView_customContextMenuRequested(const QPoint &pos); void on_btnRefresh_clicked(); private Q_SLOTS: void mnuFollowInDump(); void mnuFollowInDumpNewTab(); void mnuFollowInStack(); void mnuFollowInCPU(); private: virtual void showEvent(QShowEvent *event); private: void do_find(); private: Ui::DialogSymbolViewer *const ui; QStringListModel * model_; QSortFilterProxyModel * filter_model_; }; } #endif edb-debugger-1.0.0/plugins/SymbolViewer/CMakeLists.txt0000644000175000017500000000175713273160654022233 0ustar eteraneterancmake_minimum_required (VERSION 2.8) include("GNUInstallDirs") set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) include("${PROJECT_SOURCE_DIR}/cmake/EnableCXX11.cmake") set(PluginName "SymbolViewer") set(UI_FILES DialogSymbolViewer.ui) if(Qt5Core_FOUND) find_package(Qt5 5.0.0 REQUIRED Widgets) qt5_wrap_ui(UI_H ${UI_FILES}) else(Qt5Core_FOUND) find_package(Qt4 4.6.0 QUIET REQUIRED QtCore QtGui) include(${QT_USE_FILE}) qt4_wrap_ui(UI_H ${UI_FILES}) endif() # we put the header files from the include directory here # too so automoc can "just work" add_library(${PluginName} SHARED DialogSymbolViewer.cpp DialogSymbolViewer.h SymbolViewer.cpp SymbolViewer.h ${UI_H} ) if(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt5::Widgets) else(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt4::QtGui) endif() set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}) install (TARGETS ${PluginName} DESTINATION ${CMAKE_INSTALL_LIBDIR}/edb) edb-debugger-1.0.0/plugins/SymbolViewer/DialogSymbolViewer.cpp0000644000175000017500000001465613273160654023750 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "DialogSymbolViewer.h" #include "Configuration.h" #include "IDebugger.h" #include "ISymbolManager.h" #include "Symbol.h" #include "Util.h" #include "edb.h" #include #include #include #include "ui_DialogSymbolViewer.h" namespace SymbolViewerPlugin { //------------------------------------------------------------------------------ // Name: DialogSymbolViewer // Desc: //------------------------------------------------------------------------------ DialogSymbolViewer::DialogSymbolViewer(QWidget *parent) : QDialog(parent), ui(new Ui::DialogSymbolViewer) { ui->setupUi(this); ui->listView->setContextMenuPolicy(Qt::CustomContextMenu); model_ = new QStringListModel(this); filter_model_ = new QSortFilterProxyModel(this); filter_model_->setFilterKeyColumn(0); filter_model_->setSourceModel(model_); ui->listView->setModel(filter_model_); ui->listView->setUniformItemSizes(true); connect(ui->txtSearch, SIGNAL(textChanged(const QString &)), filter_model_, SLOT(setFilterFixedString(const QString &))); } //------------------------------------------------------------------------------ // Name: ~DialogSymbolViewer // Desc: //------------------------------------------------------------------------------ DialogSymbolViewer::~DialogSymbolViewer() { delete ui; } //------------------------------------------------------------------------------ // Name: on_listView_doubleClicked // Desc: follows the found item in the data view //------------------------------------------------------------------------------ void DialogSymbolViewer::on_listView_doubleClicked(const QModelIndex &index) { const QString s = index.data().toString(); if(const Result addr = edb::v1::string_to_address(s.split(":")[0])) { const std::shared_ptr sym = edb::v1::symbol_manager().find(*addr); if(sym && sym->is_code()) { edb::v1::jump_to_address(*addr); } else { edb::v1::dump_data(*addr, false); } } } //------------------------------------------------------------------------------ // Name: on_listView_customContextMenuRequested // Desc: //------------------------------------------------------------------------------ void DialogSymbolViewer::on_listView_customContextMenuRequested(const QPoint &pos) { const QModelIndex index = ui->listView->indexAt(pos); if(index.isValid()) { const QString s = index.data().toString(); if(const Result addr = edb::v1::string_to_address(s.split(":")[0])) { QMenu menu; QAction *const action1 = menu.addAction(tr("&Follow In Disassembly"), this, SLOT(mnuFollowInCPU())); QAction *const action2 = menu.addAction(tr("&Follow In Dump"), this, SLOT(mnuFollowInDump())); QAction *const action3 = menu.addAction(tr("&Follow In Dump (New Tab)"), this, SLOT(mnuFollowInDumpNewTab())); QAction *const action4 = menu.addAction(tr("&Follow In Stack"), this, SLOT(mnuFollowInStack())); action1->setData(*addr); action2->setData(*addr); action3->setData(*addr); action4->setData(*addr); menu.exec(ui->listView->mapToGlobal(pos)); } } } //------------------------------------------------------------------------------ // Name: mnuFollowInDump // Desc: //------------------------------------------------------------------------------ void DialogSymbolViewer::mnuFollowInDump() { if(auto action = qobject_cast(sender())) { const edb::address_t address = action->data().toULongLong(); edb::v1::dump_data(address, false); } } //------------------------------------------------------------------------------ // Name: mnuFollowInDumpNewTab // Desc: //------------------------------------------------------------------------------ void DialogSymbolViewer::mnuFollowInDumpNewTab() { if(auto action = qobject_cast(sender())) { const edb::address_t address = action->data().toULongLong(); edb::v1::dump_data(address, true); } } //------------------------------------------------------------------------------ // Name: mnuFollowInStack // Desc: //------------------------------------------------------------------------------ void DialogSymbolViewer::mnuFollowInStack() { if(auto action = qobject_cast(sender())) { const edb::address_t address = action->data().toULongLong(); edb::v1::dump_stack(address, false); } } //------------------------------------------------------------------------------ // Name: mnuFollowInCPU // Desc: //------------------------------------------------------------------------------ void DialogSymbolViewer::mnuFollowInCPU() { if(auto action = qobject_cast(sender())) { const edb::address_t address = action->data().toULongLong(); edb::v1::jump_to_address(address); } } //------------------------------------------------------------------------------ // Name: do_find // Desc: //------------------------------------------------------------------------------ void DialogSymbolViewer::do_find() { QStringList results; const QList> symbols = edb::v1::symbol_manager().symbols(); for(const std::shared_ptr &sym: symbols) { results << QString("%1: %2").arg(edb::v1::format_pointer(sym->address), sym->name); } model_->setStringList(results); } //------------------------------------------------------------------------------ // Name: on_btnRefresh_clicked // Desc: //------------------------------------------------------------------------------ void DialogSymbolViewer::on_btnRefresh_clicked() { ui->btnRefresh->setEnabled(false); do_find(); ui->btnRefresh->setEnabled(true); } //------------------------------------------------------------------------------ // Name: showEvent // Desc: //------------------------------------------------------------------------------ void DialogSymbolViewer::showEvent(QShowEvent *) { on_btnRefresh_clicked(); } } edb-debugger-1.0.0/plugins/SymbolViewer/DialogSymbolViewer.ui0000644000175000017500000000613713273160654023576 0ustar eteraneteran Evan Teran SymbolViewerPlugin::DialogSymbolViewer 0 0 652 521 Symbols Loaded Symbols: Filter Monospace QAbstractItemView::NoEditTriggers false true 6 &Close false &Help Qt::Horizontal 361 29 &Refresh btnClose clicked() DialogSymbolViewer reject() 61 458 265 468 edb-debugger-1.0.0/plugins/References/0000755000175000017500000000000013273160654017113 5ustar eteraneteranedb-debugger-1.0.0/plugins/References/DialogReferences.cpp0000644000175000017500000001406513273160654023026 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "DialogReferences.h" #include "IDebugger.h" #include "MemoryRegions.h" #include "Util.h" #include "edb.h" #include #include #include "ui_DialogReferences.h" namespace ReferencesPlugin { enum Role { TypeRole = Qt::UserRole + 0, AddressRole = Qt::UserRole + 1 }; //------------------------------------------------------------------------------ // Name: DialogReferences // Desc: constructor //------------------------------------------------------------------------------ DialogReferences::DialogReferences(QWidget *parent) : QDialog(parent), ui(new Ui::DialogReferences) { ui->setupUi(this); connect(this, SIGNAL(updateProgress(int)), ui->progressBar, SLOT(setValue(int))); } //------------------------------------------------------------------------------ // Name: ~DialogReferences // Desc: //------------------------------------------------------------------------------ DialogReferences::~DialogReferences() { delete ui; } //------------------------------------------------------------------------------ // Name: showEvent // Desc: //------------------------------------------------------------------------------ void DialogReferences::showEvent(QShowEvent *) { ui->listWidget->clear(); ui->progressBar->setValue(0); } //------------------------------------------------------------------------------ // Name: do_find // Desc: //------------------------------------------------------------------------------ void DialogReferences::do_find() { bool ok = false; edb::address_t address; const edb::address_t page_size = edb::v1::debugger_core->page_size(); const QString text = ui->txtAddress->text(); if(!text.isEmpty()) { ok = edb::v1::eval_expression(text, &address); } if(ok) { edb::v1::memory_regions().sync(); const QList> regions = edb::v1::memory_regions().regions(); int i = 0; for(const std::shared_ptr ®ion: regions) { // a short circut for speading things up if(region->accessible() || !ui->chkSkipNoAccess->isChecked()) { const edb::address_t page_count = region->size() / page_size; const QVector pages = edb::v1::read_pages(region->start(), page_count); if(!pages.isEmpty()) { const quint8 *p = &pages[0]; const quint8 *const pages_end = &pages[0] + region->size(); while(p != pages_end) { if(pages_end - p < edb::v1::pointer_size()) { break; } const edb::address_t addr = p - &pages[0] + region->start(); edb::address_t test_address(0); memcpy(&test_address, p, edb::v1::pointer_size()); if(test_address == address) { auto item = new QListWidgetItem(edb::v1::format_pointer(addr)); item->setData(TypeRole, 'D'); item->setData(AddressRole, addr); ui->listWidget->addItem(item); } edb::Instruction inst(p, pages_end, addr); if(inst) { switch(inst.operation()) { case X86_INS_MOV: // instructions of the form: mov [ADDR], 0xNNNNNNNN Q_ASSERT(inst.operand_count() == 2); if(is_expression(inst[0])) { if(is_immediate(inst[1]) && static_cast(inst[1]->imm) == address) { auto item = new QListWidgetItem(edb::v1::format_pointer(addr)); item->setData(TypeRole, 'C'); item->setData(AddressRole, addr); ui->listWidget->addItem(item); } } break; case X86_INS_PUSH: // instructions of the form: push 0xNNNNNNNN Q_ASSERT(inst.operand_count() == 1); if(is_immediate(inst[0]) && static_cast(inst[0]->imm) == address) { auto item = new QListWidgetItem(edb::v1::format_pointer(addr)); item->setData(TypeRole, 'C'); item->setData(AddressRole, addr); ui->listWidget->addItem(item); } break; default: if(is_jump(inst) || is_call(inst)) { if(is_immediate(inst[0])) { if(static_cast(inst[0]->imm) == address) { auto item = new QListWidgetItem(edb::v1::format_pointer(addr)); item->setData(TypeRole, 'C'); item->setData(AddressRole, addr); ui->listWidget->addItem(item); } } } break; } } Q_EMIT updateProgress(util::percentage(i, regions.size(), p - &pages[0], region->size())); ++p; } } } else { Q_EMIT updateProgress(util::percentage(i, regions.size())); } ++i; } } } //------------------------------------------------------------------------------ // Name: on_btnFind_clicked // Desc: find button event handler //------------------------------------------------------------------------------ void DialogReferences::on_btnFind_clicked() { ui->btnFind->setEnabled(false); ui->progressBar->setValue(0); ui->listWidget->clear(); do_find(); ui->progressBar->setValue(100); ui->btnFind->setEnabled(true); } //------------------------------------------------------------------------------ // Name: on_listWidget_itemDoubleClicked // Desc: follows the found item in the data view //------------------------------------------------------------------------------ void DialogReferences::on_listWidget_itemDoubleClicked(QListWidgetItem *item) { const edb::address_t addr = item->data(AddressRole).toULongLong(); if(item->data(TypeRole).toChar() == 'D') { edb::v1::dump_data(addr, false); } else { edb::v1::jump_to_address(addr); } } } edb-debugger-1.0.0/plugins/References/CMakeLists.txt0000644000175000017500000000174313273160654021660 0ustar eteraneterancmake_minimum_required (VERSION 2.8) include("GNUInstallDirs") set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) include("${PROJECT_SOURCE_DIR}/cmake/EnableCXX11.cmake") set(PluginName "References") set(UI_FILES DialogReferences.ui) if(Qt5Core_FOUND) find_package(Qt5 5.0.0 REQUIRED Widgets) qt5_wrap_ui(UI_H ${UI_FILES}) else(Qt5Core_FOUND) find_package(Qt4 4.6.0 QUIET REQUIRED QtCore QtGui) include(${QT_USE_FILE}) qt4_wrap_ui(UI_H ${UI_FILES}) endif() # we put the header files from the include directory here # too so automoc can "just work" add_library(${PluginName} SHARED DialogReferences.cpp DialogReferences.h References.cpp References.h ${UI_H} ) if(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt5::Widgets) else(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt4::QtGui) endif() set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}) install (TARGETS ${PluginName} DESTINATION ${CMAKE_INSTALL_LIBDIR}/edb) edb-debugger-1.0.0/plugins/References/References.cpp0000644000175000017500000000413513273160654021703 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "References.h" #include "DialogReferences.h" #include "edb.h" #include namespace ReferencesPlugin { //------------------------------------------------------------------------------ // Name: References // Desc: //------------------------------------------------------------------------------ References::References() : menu_(0), dialog_(0) { } //------------------------------------------------------------------------------ // Name: ~References // Desc: //------------------------------------------------------------------------------ References::~References() { delete dialog_; } //------------------------------------------------------------------------------ // Name: menu // Desc: //------------------------------------------------------------------------------ QMenu *References::menu(QWidget *parent) { Q_ASSERT(parent); if(!menu_) { menu_ = new QMenu(tr("Reference Searcher"), parent); menu_->addAction(tr("&Reference Search"), this, SLOT(show_menu()), QKeySequence(tr("Ctrl+R"))); } return menu_; } //------------------------------------------------------------------------------ // Name: show_menu // Desc: //------------------------------------------------------------------------------ void References::show_menu() { if(!dialog_) { dialog_ = new DialogReferences(edb::v1::debugger_ui); } dialog_->show(); } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(References, References) #endif } edb-debugger-1.0.0/plugins/References/References.h0000644000175000017500000000242113273160654021344 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef REFERENCES_20060430_H_ #define REFERENCES_20060430_H_ #include "IPlugin.h" class QMenu; class QDialog; namespace ReferencesPlugin { class References : public QObject, public IPlugin { Q_OBJECT Q_INTERFACES(IPlugin) #if QT_VERSION >= 0x050000 Q_PLUGIN_METADATA(IID "edb.IPlugin/1.0") #endif Q_CLASSINFO("author", "Evan Teran") Q_CLASSINFO("url", "http://www.codef00.com") public: References(); virtual ~References(); public: virtual QMenu *menu(QWidget *parent = 0); public Q_SLOTS: void show_menu(); private: QMenu *menu_; QPointer dialog_; }; } #endif edb-debugger-1.0.0/plugins/References/DialogReferences.h0000644000175000017500000000250713273160654022471 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #ifndef DIALOGREFERENCES_20061101_H_ #define DIALOGREFERENCES_20061101_H_ #include #include "Types.h" #include "IRegion.h" class QListWidgetItem; namespace ReferencesPlugin { namespace Ui { class DialogReferences; } class DialogReferences : public QDialog { Q_OBJECT public: DialogReferences(QWidget *parent = 0); virtual ~DialogReferences(); public Q_SLOTS: void on_btnFind_clicked(); void on_listWidget_itemDoubleClicked(QListWidgetItem *item); Q_SIGNALS: void updateProgress(int); private: virtual void showEvent(QShowEvent *event); private: void do_find(); private: Ui::DialogReferences *const ui; }; } #endif edb-debugger-1.0.0/plugins/References/DialogReferences.ui0000644000175000017500000000664413273160654022665 0ustar eteraneteran Evan Teran ReferencesPlugin::DialogReferences 0 0 281 305 References Search Find References To This Address: Results: Monospace true Skip Regions With No Access Rights &Close false &Help Qt::Horizontal 20 40 &Find true 0 Qt::Horizontal txtAddress listWidget chkSkipNoAccess btnClose btnHelp btnFind btnClose clicked() DialogReferences reject() 61 458 265 468 edb-debugger-1.0.0/plugins/ODbgRegisterView/0000755000175000017500000000000013273160654020205 5ustar eteraneteranedb-debugger-1.0.0/plugins/ODbgRegisterView/ODbgRV_x86Common.h0000644000175000017500000000161513273160654023322 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef X86_COMMON_H_20170817 #define X86_COMMON_H_20170817 constexpr unsigned FPU_TAG_EMPTY = 3; static constexpr auto FSR_NAME = "FSR"; static constexpr auto FCR_NAME = "FCR"; static constexpr auto FTR_NAME = "FTR"; #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/FieldWidget.h0000644000175000017500000000276313273160654022555 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef FIELD_WIDGET_H_20170818 #define FIELD_WIDGET_H_20170818 #include #include namespace ODbgRegisterView { class ODBRegView; class RegisterGroup; class FieldWidget : public QLabel { Q_OBJECT void init(int fieldWidth); protected: QPersistentModelIndex index; int fieldWidth_; ODBRegView * regView() const; RegisterGroup *group() const; public: FieldWidget(int fieldWidth, QModelIndex const &index, QWidget *parent = nullptr); FieldWidget(int fieldWidth, QString const &fixedText, QWidget *parent = nullptr); FieldWidget(QString const &fixedText, QWidget *parent = nullptr); virtual QString text() const; int lineNumber() const; int columnNumber() const; int fieldWidth() const; public Q_SLOTS: virtual void adjustToData(); }; } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/Plugin.h0000644000175000017500000000334413273160654021620 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef ODBG_REGISTER_VIEW_PLUGIN_H_20151230 #define ODBG_REGISTER_VIEW_PLUGIN_H_20151230 #include "IPlugin.h" #include namespace ODbgRegisterView { class ODBRegView; class Plugin : public QObject, public IPlugin { Q_OBJECT Q_INTERFACES(IPlugin) #if QT_VERSION >= 0x050000 Q_PLUGIN_METADATA(IID "edb.IPlugin/1.0") #endif Q_CLASSINFO("author", "Ruslan Kabatsayev") Q_CLASSINFO("email", "b7.10110111@gmail.com") public: Plugin(); virtual QMenu *menu(QWidget *parent = 0) override; virtual QList cpu_context_menu() override; private: void setupDocks(); void createRegisterView(QString const &settingsGroup); void renumerateDocks() const; private Q_SLOTS: void createRegisterView(); void saveState() const; void expandRSUp(bool checked) const; void expandRSDown(bool checked) const; void expandLSUp(bool checked) const; void expandLSDown(bool checked) const; void removeDock(QWidget *); private: QMenu * menu_; std::vector registerViews_; std::vector menuDeleteRegViewActions_; }; } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/GPREdit.h0000644000175000017500000000256013273160654021617 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include namespace ODbgRegisterView { class GPREdit : public QLineEdit { Q_OBJECT public: enum class Format { Hex, Signed, Unsigned, Character }; public: GPREdit(std::size_t offsetInInteger, std::size_t integerSize, Format format, QWidget *parent = nullptr); public: void setGPRValue(std::uint64_t gprValue); void updateGPRValue(std::uint64_t &gpr) const; virtual QSize minimumSizeHint() const override { return sizeHint(); } virtual QSize sizeHint() const override; private: void setupFormat(Format newFormat); private: int naturalWidthInChars; std::size_t integerSize; std::size_t offsetInInteger; Format format; std::uint64_t signBit; }; } edb-debugger-1.0.0/plugins/ODbgRegisterView/Float80Edit.cpp0000644000175000017500000000250613273160654022737 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "Float80Edit.h" #include "FloatX.h" #include namespace ODbgRegisterView { Float80Edit::Float80Edit(QWidget *parent) : QLineEdit(parent) { setValidator(new FloatXValidator(this)); } void Float80Edit::setValue(edb::value80 input) { setText(formatFloat(input)); } QSize Float80Edit::sizeHint() const { const auto baseHint = QLineEdit::sizeHint(); // Default size hint gives space for about 15-20 chars. We need about 30. return QSize(baseHint.width() * 2, baseHint.height()).expandedTo(QApplication::globalStrut()); } void Float80Edit::focusOutEvent(QFocusEvent *e) { QLineEdit::focusOutEvent(e); Q_EMIT defocussed(); } } edb-debugger-1.0.0/plugins/ODbgRegisterView/x86Groups.cpp0000644000175000017500000007111113273160654022537 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "x86Groups.h" #include "ODbgRV_Util.h" #include "ODbgRV_x86Common.h" #include #include namespace ODbgRegisterView { namespace { const BitFieldDescription fpuTagDescription = { 7, { "valid", "zero", "special", "empty" }, { QObject::tr("Tag as used"), "", "", QObject::tr("Tag as empty") }, [](unsigned a, unsigned b) { return a == 3 || b == 3 ? a == b : true; } }; const BitFieldDescription roundControlDescription = { 4, { "NEAR", "DOWN", " UP", "ZERO" }, { QObject::tr("Round to nearest"), QObject::tr("Round down"), QObject::tr("Round up"), QObject::tr("Round toward zero") } }; const BitFieldDescription precisionControlDescription = { 2, { "24", "??", "53", "64" }, { QObject::tr("Set 24-bit precision"), "", QObject::tr("Set 53-bit precision"), QObject::tr("Set 64-bit precision") } }; const BitFieldDescription debugRWDescription = { 5, { "EXEC", "WRITE", " IO", " R/W" }, { QObject::tr("Break on execution"), QObject::tr("Break on data write"), "", QObject::tr("Break on data read/write") } }; const BitFieldDescription debugLenDescription = { 1, { "1", "2", "8", "4" }, { QObject::tr("Set 1-byte length"), QObject::tr("Set 2-byte length"), QObject::tr("Set 8-byte length"), QObject::tr("Set 4-byte length") } }; } void addRoundingMode(RegisterGroup *const group, QModelIndex const &index, int const row, int const column) { assert(index.isValid()); const auto rndValueField = new MultiBitFieldWidget(index, roundControlDescription, group); group->insert(row, column, rndValueField); rndValueField->setToolTip(QObject::tr("Rounding mode")); } void addPrecisionMode(RegisterGroup *const group, QModelIndex const &index, int const row, int const column) { assert(index.isValid()); const auto precValueField = new MultiBitFieldWidget(index, precisionControlDescription, group); group->insert(row, column, precValueField); precValueField->setToolTip(QObject::tr("Precision mode: effective mantissa length")); } void addPUOZDI(RegisterGroup *const group, QModelIndex const &excRegIndex, QModelIndex const &maskRegIndex, int const startRow, int const startColumn) { QString const exceptions = "PUOZDI"; std::unordered_map excNames = { {'P', QObject::tr("Precision")}, {'U', QObject::tr("Underflow")}, {'O', QObject::tr("Overflow")}, {'Z', QObject::tr("Zero Divide")}, {'D', QObject::tr("Denormalized Operand")}, {'I', QObject::tr("Invalid Operation")} }; for (int exN = 0; exN < exceptions.length(); ++exN) { QString const ex = exceptions[exN]; const auto exAbbrev = ex + "E"; const auto maskAbbrev = ex + "M"; const auto excIndex = VALID_INDEX(findModelRegister(excRegIndex, exAbbrev)); const auto maskIndex = VALID_INDEX(findModelRegister(maskRegIndex, maskAbbrev)); const int column = startColumn + exN * 2; const auto nameField = new FieldWidget(ex, group); group->insert(startRow, column, nameField); const auto excValueField = new ValueField(1, getValueIndex(excIndex), group); group->insert(startRow + 1, column, excValueField); const auto maskValueField = new ValueField(1, getValueIndex(maskIndex), group); group->insert(startRow + 2, column, maskValueField); const auto excName = excNames.at(ex[0].toLatin1()); nameField->setToolTip(excName); excValueField->setToolTip(excName + ' ' + QObject::tr("Exception") + " (" + exAbbrev + ")"); maskValueField->setToolTip(excName + ' ' + QObject::tr("Exception Mask") + " (" + maskAbbrev + ")"); } } RegisterGroup *createEFL(RegisterViewModelBase::Model *model, QWidget *parent) { const auto catIndex = findModelCategory(model, "General Status"); if (!catIndex.isValid()) return nullptr; auto nameIndex = findModelRegister(catIndex, "RFLAGS"); if (!nameIndex.isValid()) nameIndex = findModelRegister(catIndex, "EFLAGS"); if (!nameIndex.isValid()) return nullptr; const auto group = new RegisterGroup("EFL", parent); const int nameWidth = 3; int column = 0; group->insert(0, column, new FieldWidget("EFL", group)); const auto valueWidth = 8; const auto valueIndex = nameIndex.sibling(nameIndex.row(), MODEL_VALUE_COLUMN); column += nameWidth + 1; group->insert(0, column, new ValueField(valueWidth, valueIndex, group, [](QString const &v) { return v.right(8); })); const auto commentIndex = nameIndex.sibling(nameIndex.row(), MODEL_COMMENT_COLUMN); column += valueWidth + 1; group->insert(0, column, new FieldWidget(0, commentIndex, group)); return group; } RegisterGroup *createExpandedEFL(RegisterViewModelBase::Model *model, QWidget *parent) { const auto catIndex = findModelCategory(model, "General Status"); if (!catIndex.isValid()) return nullptr; auto regNameIndex = findModelRegister(catIndex, "RFLAGS"); if (!regNameIndex.isValid()) regNameIndex = findModelRegister(catIndex, "EFLAGS"); if (!regNameIndex.isValid()) return nullptr; const auto group = new RegisterGroup(QObject::tr("Expanded EFL"), parent); static const std::unordered_map flagTooltips = { {'C', QObject::tr("Carry flag") + " (CF)"}, {'P', QObject::tr("Parity flag") + " (PF)"}, {'A', QObject::tr("Auxiliary carry flag") + " (AF)"}, {'Z', QObject::tr("Zero flag") + " (ZF)"}, {'S', QObject::tr("Sign flag") + " (SF)"}, {'T', QObject::tr("Trap flag") + " (TF)"}, {'D', QObject::tr("Direction flag") + " (DF)"}, {'O', QObject::tr("Overflow flag") + " (OF)"}, }; for (int row = 0, groupRow = 0; row < model->rowCount(regNameIndex); ++row) { const auto flagNameIndex = model->index(row, MODEL_NAME_COLUMN, regNameIndex); const auto flagValueIndex = model->index(row, MODEL_VALUE_COLUMN, regNameIndex); const auto flagName = model->data(flagNameIndex).toString().toUpper(); if (flagName.length() != 2 || flagName[1] != 'F') continue; static const int flagNameWidth = 1; static const int valueWidth = 1; const char name = flagName[0].toLatin1(); switch (name) { case 'C': case 'P': case 'A': case 'Z': case 'S': case 'T': case 'D': case 'O': { const auto nameField = new FieldWidget(QChar(name), group); group->insert(groupRow, 0, nameField); const auto valueField = new ValueField(valueWidth, flagValueIndex, group); group->insert(groupRow, flagNameWidth + 1, valueField); ++groupRow; const auto tooltipStr = flagTooltips.at(name); nameField->setToolTip(tooltipStr); valueField->setToolTip(tooltipStr); break; } default: continue; } } return group; } RegisterGroup *createFPUData(RegisterViewModelBase::Model *model, QWidget *parent) { using RegisterViewModelBase::Model; const auto catIndex = findModelCategory(model, "FPU"); if (!catIndex.isValid()) { return nullptr; } const auto tagsIndex = findModelRegister(catIndex, FTR_NAME); if (!tagsIndex.isValid()) { qWarning() << "Warning: failed to find FTR in the model, refusing to continue making FPUData group"; return nullptr; } const auto group = new RegisterGroup(QObject::tr("FPU Data Registers"), parent); static const int FPU_REG_COUNT = 8; static const int nameWidth = 3; static const int tagWidth = 7; const auto fsrIndex = VALID_INDEX(findModelRegister(catIndex, FSR_NAME)); const QPersistentModelIndex topIndex = VALID_INDEX(findModelRegister(fsrIndex, "TOP", MODEL_VALUE_COLUMN)); for (int row = 0; row < FPU_REG_COUNT; ++row) { int column = 0; const auto nameIndex = model->index(row, MODEL_NAME_COLUMN, catIndex); { const auto STiFormatter = [row, topIndex]() { const auto topByteArray = topIndex.data(Model::RawValueRole).toByteArray(); if (topByteArray.isEmpty()) return QString("R%1").arg(row); const auto top = topByteArray[0]; assert(top >= 0); Q_ASSERT(top < 8); const auto stI = (row + 8 - top) % 8; return QString("ST%1").arg(stI); }; const auto field = new VolatileNameField(nameWidth, STiFormatter, group); QObject::connect(model, SIGNAL(dataChanged(QModelIndex const &, QModelIndex const &)), field, SLOT(adjustToData())); group->insert(row, column, field); column += nameWidth + 1; } const auto tagValueIndex = VALID_INDEX(model->index(row, MODEL_VALUE_COLUMN, tagsIndex)); group->insert(row, column, new MultiBitFieldWidget(tagValueIndex, fpuTagDescription, group)); column += tagWidth + 1; const auto regValueIndex = nameIndex.sibling(nameIndex.row(), MODEL_VALUE_COLUMN); const int regValueWidth = regValueIndex.data(Model::FixedLengthRole).toInt(); assert(regValueWidth > 0); const auto regCommentIndex = model->index(row, MODEL_COMMENT_COLUMN, catIndex); new FPUValueField(regValueWidth, regValueIndex, tagValueIndex, group, new FieldWidget(0, regCommentIndex, group), row, column); } return group; } RegisterGroup *createFPUWords(RegisterViewModelBase::Model *model, QWidget *parent) { const auto catIndex = findModelCategory(model, "FPU"); if (!catIndex.isValid()) return nullptr; const auto group = new RegisterGroup(QObject::tr("FPU Status&&Control Registers"), parent); group->appendNameValueComment(findModelRegister(catIndex, FTR_NAME), QObject::tr("FPU Tag Register"), false); const int fsrRow = 1; const auto fsrIndex = findModelRegister(catIndex, FSR_NAME); group->appendNameValueComment(fsrIndex, QObject::tr("FPU Status Register"), false); const int fcrRow = 2; const auto fcrIndex = findModelRegister(catIndex, FCR_NAME); group->appendNameValueComment(fcrIndex, QObject::tr("FPU Control Register"), false); const int wordNameWidth = 3, wordValWidth = 4; const int condPrecLabelColumn = wordNameWidth + 1 + wordValWidth + 1 + 1; const int condPrecLabelWidth = 4; group->insert(fsrRow, condPrecLabelColumn, new FieldWidget("Cond", group)); group->insert(fcrRow, condPrecLabelColumn, new FieldWidget("Prec", group)); const int condPrecValColumn = condPrecLabelColumn + condPrecLabelWidth + 1; const int roundModeWidth = 4, precModeWidth = 2; const int roundModeColumn = condPrecValColumn; const int precModeColumn = roundModeColumn + roundModeWidth + 1; // This must be inserted before precision&rounding value fields, since they overlap this label group->insert(fcrRow, precModeColumn - 1, new FieldWidget(",", group)); for (int condN = 3; condN >= 0; --condN) { const auto name = QString("C%1").arg(condN); const auto condNNameIndex = VALID_INDEX(findModelRegister(fsrIndex, name)); const auto condNIndex = VALID_INDEX(condNNameIndex.sibling(condNNameIndex.row(), MODEL_VALUE_COLUMN)); const int column = condPrecValColumn + 2 * (3 - condN); const auto nameField = new FieldWidget(QString("%1").arg(condN), group); group->insert(fsrRow - 1, column, nameField); const auto valueField = new ValueField(1, condNIndex, group); group->insert(fsrRow, column, valueField); nameField->setToolTip(name); valueField->setToolTip(name); } addRoundingMode(group, findModelRegister(fcrIndex, "RC", MODEL_VALUE_COLUMN), fcrRow, roundModeColumn); addPrecisionMode(group, findModelRegister(fcrIndex, "PC", MODEL_VALUE_COLUMN), fcrRow, precModeColumn); const int errMaskColumn = precModeColumn + precModeWidth + 2; const int errLabelWidth = 3; group->insert(fsrRow, errMaskColumn, new FieldWidget("Err", group)); group->insert(fcrRow, errMaskColumn, new FieldWidget("Mask", group)); const int ESColumn = errMaskColumn + errLabelWidth + 1; const int SFColumn = ESColumn + 2; const auto ESNameField = new FieldWidget("E", group); group->insert(fsrRow - 1, ESColumn, ESNameField); const auto SFNameField = new FieldWidget("S", group); group->insert(fsrRow - 1, SFColumn, SFNameField); const auto ESValueField = new ValueField(1, findModelRegister(fsrIndex, "ES", MODEL_VALUE_COLUMN), group); group->insert(fsrRow, ESColumn, ESValueField); const auto SFValueField = new ValueField(1, findModelRegister(fsrIndex, "SF", MODEL_VALUE_COLUMN), group); group->insert(fsrRow, SFColumn, SFValueField); { const auto ESTooltip = QObject::tr("Error Summary Status") + " (ES)"; ESNameField->setToolTip(ESTooltip); ESValueField->setToolTip(ESTooltip); } { const auto SFTooltip = QObject::tr("Stack Fault") + " (SF)"; SFNameField->setToolTip(SFTooltip); SFValueField->setToolTip(SFTooltip); } const int PEPMColumn = SFColumn + 2; addPUOZDI(group, fsrIndex, fcrIndex, fsrRow - 1, PEPMColumn); const int PUOZDIWidth = 6 * 2 - 1; group->insert(fsrRow, PEPMColumn + PUOZDIWidth + 1, new FieldWidget(0, getCommentIndex(fsrIndex), group)); return group; } // Checks that FOP is in not in compatibility mode, i.e. is updated only on unmasked exception // This function would return false for e.g. Pentium III or Atom, but returns true since Pentium 4. // This can be made return false for such CPUs by setting bit 2 in IA32_MISC_ENABLE MSR. bool FOPIsIncompatible() { char fenv[28]; asm volatile("fldz\n" "fstp %%st(0)\n" "fstenv %0\n" : "=m"(fenv)::"%st"); std::uint16_t fop; std::memcpy(&fop, fenv + 18, sizeof fop); return fop == 0; } RegisterGroup *createFPULastOp(RegisterViewModelBase::Model *model, QWidget *parent) { using RegisterViewModelBase::Model; const auto catIndex = findModelCategory(model, "FPU"); if (!catIndex.isValid()) return nullptr; const auto FIPIndex = findModelRegister(catIndex, "FIP", MODEL_VALUE_COLUMN); if (!FIPIndex.isValid()) return nullptr; const auto FDPIndex = findModelRegister(catIndex, "FDP", MODEL_VALUE_COLUMN); if (!FDPIndex.isValid()) return nullptr; const auto group = new RegisterGroup(QObject::tr("FPU Last Operation Registers"), parent); enum { lastInsnRow, lastDataRow, lastOpcodeRow }; const QString lastInsnLabel = "Last insn"; const QString lastDataLabel = "Last data"; const QString lastOpcodeLabel = "Last opcode"; const auto lastInsnLabelField = new FieldWidget(lastInsnLabel, group); group->insert(lastInsnRow, 0, lastInsnLabelField); const auto lastDataLabelField = new FieldWidget(lastDataLabel, group); group->insert(lastDataRow, 0, lastDataLabelField); const auto lastOpcodeLabelField = new FieldWidget(lastOpcodeLabel, group); group->insert(lastOpcodeRow, 0, lastOpcodeLabelField); lastInsnLabelField->setToolTip(QObject::tr("Last FPU instruction address")); lastDataLabelField->setToolTip(QObject::tr("Last FPU memory operand address")); // FIS & FDS are not maintained in 64-bit mode; Linux64 always saves state from // 64-bit mode, losing the values for 32-bit apps even if the CPU doesn't deprecate them // We'll show zero offsets in 32 bit mode for consistency with 32-bit kernels // In 64-bit mode, since segments are not maintained, we'll just show offsets const auto FIPwidth = FDPIndex.data(Model::FixedLengthRole).toInt(); const auto segWidth = FIPwidth == 8 /*8chars=>32bit*/ ? 4 : 0; const auto segColumn = lastInsnLabel.length() + 1; if (segWidth) { // these two must be inserted first, because seg & offset value fields overlap these labels group->insert(lastInsnRow, segColumn + segWidth, new FieldWidget(":", group)); group->insert(lastDataRow, segColumn + segWidth, new FieldWidget(":", group)); const auto FISField = new ValueField(segWidth, findModelRegister(catIndex, "FIS", MODEL_VALUE_COLUMN), group); group->insert(lastInsnRow, segColumn, FISField); const auto FDSField = new ValueField(segWidth, findModelRegister(catIndex, "FDS", MODEL_VALUE_COLUMN), group); group->insert(lastDataRow, segColumn, FDSField); FISField->setToolTip(QObject::tr("Last FPU instruction selector")); FDSField->setToolTip(QObject::tr("Last FPU memory operand selector")); } const auto offsetWidth = FIPIndex.data(Model::FixedLengthRole).toInt(); assert(offsetWidth > 0); const auto offsetColumn = segColumn + segWidth + (segWidth ? 1 : 0); const auto FIPValueField = new ValueField(offsetWidth, FIPIndex, group); group->insert(lastInsnRow, offsetColumn, FIPValueField); const auto FDPValueField = new ValueField(offsetWidth, FDPIndex, group); group->insert(lastDataRow, offsetColumn, FDPValueField); FIPValueField->setToolTip(QObject::tr("Last FPU instruction offset")); FDPValueField->setToolTip(QObject::tr("Last FPU memory operand offset")); QPersistentModelIndex const FOPIndex = findModelRegister(catIndex, "FOP", MODEL_VALUE_COLUMN); QPersistentModelIndex const FSRIndex = findModelRegister(catIndex, FSR_NAME, MODEL_VALUE_COLUMN); QPersistentModelIndex const FCRIndex = findModelRegister(catIndex, FCR_NAME, MODEL_VALUE_COLUMN); bool fopRarelyUpdated = FOPIsIncompatible(); const auto FOPFormatter = [FOPIndex, FSRIndex, FCRIndex, FIPIndex, fopRarelyUpdated](QString const &str) -> QString { if (str.isEmpty() || str[0] == '?') return str; const auto rawFCR = FCRIndex.data(Model::RawValueRole).toByteArray(); assert(rawFCR.size() <= long(sizeof(edb::value16))); if (rawFCR.isEmpty()) return str; edb::value16 fcr(0); std::memcpy(&fcr, rawFCR.constData(), rawFCR.size()); const auto rawFSR = FSRIndex.data(Model::RawValueRole).toByteArray(); assert(rawFSR.size() <= long(sizeof(edb::value16))); if (rawFSR.isEmpty()) return str; edb::value16 fsr(0); std::memcpy(&fsr, rawFSR.constData(), rawFSR.size()); const auto rawFOP = FOPIndex.data(Model::RawValueRole).toByteArray(); edb::value16 fop(0); assert(rawFOP.size() <= long(sizeof(edb::value16))); if (rawFOP.isEmpty()) return str; if (rawFOP.size() != sizeof(edb::value16)) return QString("????"); std::memcpy(&fop, rawFOP.constData(), rawFOP.size()); const auto rawFIP = FIPIndex.data(Model::RawValueRole).toByteArray(); if (rawFIP.isEmpty()) return str; edb::address_t fip(0); assert(rawFIP.size() <= long(sizeof fip)); std::memcpy(&fip, rawFIP.constData(), rawFIP.size()); const auto excMask = fcr & 0x3f; const auto excActive = fsr & 0x3f; const auto excActiveUnmasked = excActive & ~excMask; if (fop == 0 && ((fopRarelyUpdated && !excActiveUnmasked) || fip == 0)) return QString("00 00"); return edb::value8(0xd8 + rawFOP[1]).toHexString() + ' ' + edb::value8(rawFOP[0]).toHexString(); }; const auto FOPValueField = new ValueField(5, FOPIndex, group, FOPFormatter); group->insert(lastOpcodeRow, lastOpcodeLabel.length() + 1, FOPValueField); static const auto FOPTooltip = QObject::tr("Last FPU opcode"); lastOpcodeLabelField->setToolTip(FOPTooltip); FOPValueField->setToolTip(FOPTooltip); return group; } RegisterGroup *createDebugGroup(RegisterViewModelBase::Model *model, QWidget *parent) { using RegisterViewModelBase::Model; const auto catIndex = findModelCategory(model, "Debug"); if (!catIndex.isValid()) return nullptr; const auto group = new RegisterGroup(QObject::tr("Debug Registers"), parent); const auto dr6Index = VALID_INDEX(findModelRegister(catIndex, "DR6")); const auto dr7Index = VALID_INDEX(findModelRegister(catIndex, "DR7")); const auto nameWidth = 3; const auto valueWidth = getValueIndex(dr6Index).data(Model::FixedLengthRole).toInt(); assert(valueWidth > 0); int row = 0; const auto bitsSpacing = 1; const auto BTooltip = QObject::tr("Breakpoint Condition Detected"); const auto LTooltip = QObject::tr("Local Breakpoint Enable"); const auto GTooltip = QObject::tr("Global Breakpoint Enable"); const auto typeTooltip = QObject::tr("Breakpoint condition"); const auto lenTooltip = QObject::tr("Data breakpoint length"); const auto lenDecodedStr = QObject::tr(" (bytes count from %1)"); { int column = nameWidth + 1 + valueWidth + 2; const auto BLabelField = new FieldWidget("B", group); BLabelField->setToolTip(BTooltip + " (B0..B3)"); group->insert(row, column, BLabelField); column += bitsSpacing + 1; const auto LLabelField = new FieldWidget("L", group); LLabelField->setToolTip(LTooltip + " (L0..L3)"); group->insert(row, column, LLabelField); column += bitsSpacing + 1; const auto GLabelField = new FieldWidget("G", group); GLabelField->setToolTip(GTooltip + " (G0..G3)"); group->insert(row, column, GLabelField); column += bitsSpacing + 1; const auto typeLabelField = new FieldWidget("Type", group); typeLabelField->setToolTip(typeTooltip + " (R/W0..R/W3)"); group->insert(row, column, typeLabelField); column += bitsSpacing + 4; const auto lenLabelField = new FieldWidget("Len", group); lenLabelField->setToolTip(lenTooltip + lenDecodedStr.arg("LEN0..LEN3")); group->insert(row, column, lenLabelField); column += bitsSpacing + 3; ++row; } for (int drI = 0; drI < 4; ++drI, ++row) { const auto name = QString("DR%1").arg(drI); const auto DRiValueIndex = VALID_INDEX(findModelRegister(catIndex, name, MODEL_VALUE_COLUMN)); int column = 0; group->insert(row, column, new FieldWidget(name, group)); column += nameWidth + 1; group->insert(row, column, new ValueField(valueWidth, DRiValueIndex, group)); column += valueWidth + 2; { const auto BiName = QString("B%1").arg(drI); const auto BiIndex = VALID_INDEX(findModelRegister(dr6Index, BiName, MODEL_VALUE_COLUMN)); const auto BiValueField = new ValueField(1, BiIndex, group); BiValueField->setToolTip(BTooltip + " (" + BiName + ")"); group->insert(row, column, BiValueField); column += bitsSpacing + 1; } { const auto LiName = QString("L%1").arg(drI); const auto LiIndex = VALID_INDEX(findModelRegister(dr7Index, LiName, MODEL_VALUE_COLUMN)); const auto LiValueField = new ValueField(1, LiIndex, group); LiValueField->setToolTip(LTooltip + " (" + LiName + ")"); group->insert(row, column, LiValueField); column += bitsSpacing + 1; } { const auto GiName = QString("G%1").arg(drI); const auto GiIndex = VALID_INDEX(findModelRegister(dr7Index, GiName, MODEL_VALUE_COLUMN)); const auto GiValueField = new ValueField(1, GiIndex, group); GiValueField->setToolTip(GTooltip + " (" + GiName + ")"); group->insert(row, column, GiValueField); column += bitsSpacing + 1; } { const auto RWiName = QString("R/W%1").arg(drI); const QPersistentModelIndex RWiIndex = VALID_INDEX(findModelRegister(dr7Index, RWiName, MODEL_VALUE_COLUMN)); const auto width = 5; const auto RWiValueField = new MultiBitFieldWidget(RWiIndex, debugRWDescription, group); RWiValueField->setToolTip(typeTooltip + " (" + RWiName + ")"); group->insert(row, column, RWiValueField); column += bitsSpacing + width; } { const auto LENiName = QString("LEN%1").arg(drI); const QPersistentModelIndex LENiIndex = VALID_INDEX(findModelRegister(dr7Index, LENiName, MODEL_VALUE_COLUMN)); const auto LENiValueField = new MultiBitFieldWidget(LENiIndex, debugLenDescription, group); LENiValueField->setToolTip(lenTooltip + lenDecodedStr.arg(LENiName)); group->insert(row, column, LENiValueField); } } { int column = 0; group->insert(row, column, new FieldWidget("DR6", group)); column += nameWidth + 1; group->insert(row, column, new ValueField(valueWidth, getValueIndex(dr6Index), group)); column += valueWidth + 2; const QString bsName = "BS"; const auto bsWidth = bsName.length(); const auto BSNameField = new FieldWidget(bsName, group); const auto BSTooltip = QObject::tr("Single Step") + " (BS)"; BSNameField->setToolTip(BSTooltip); group->insert(row, column, BSNameField); column += bsWidth + 1; const auto bsIndex = findModelRegister(dr6Index, bsName, MODEL_VALUE_COLUMN); const auto BSValueField = new ValueField(1, bsIndex, group); BSValueField->setToolTip(BSTooltip); group->insert(row, column, BSValueField); ++row; } { int column = 0; group->insert(row, column, new FieldWidget("DR7", group)); column += nameWidth + 1; group->insert(row, column, new ValueField(valueWidth, getValueIndex(dr7Index), group)); column += valueWidth + 2; { const QString leName = "LE"; const auto leWidth = leName.length(); const auto LENameField = new FieldWidget(leName, group); const auto LETooltip = QObject::tr("Local Exact Breakpoint Enable"); LENameField->setToolTip(LETooltip); group->insert(row, column, LENameField); column += leWidth + 1; const auto leIndex = findModelRegister(dr7Index, leName, MODEL_VALUE_COLUMN); const auto leValueWidth = 1; const auto LEValueField = new ValueField(leValueWidth, leIndex, group); LEValueField->setToolTip(LETooltip); group->insert(row, column, LEValueField); column += leValueWidth + 1; } { const QString geName = "GE"; const auto geWidth = geName.length(); const auto GENameField = new FieldWidget(geName, group); const auto GETooltip = QObject::tr("Global Exact Breakpoint Enable"); GENameField->setToolTip(GETooltip); group->insert(row, column, GENameField); column += geWidth + 1; const auto geIndex = findModelRegister(dr7Index, geName, MODEL_VALUE_COLUMN); const auto geValueWidth = 1; const auto GEValueField = new ValueField(geValueWidth, geIndex, group); GEValueField->setToolTip(GETooltip); group->insert(row, column, GEValueField); column += geValueWidth + 1; } } return group; } RegisterGroup *createMXCSR(RegisterViewModelBase::Model *model, QWidget *parent) { using namespace RegisterViewModelBase; const auto catIndex = findModelCategory(model, "SSE"); if (!catIndex.isValid()) return nullptr; const auto group = new RegisterGroup("MXCSR", parent); const QString mxcsrName = "MXCSR"; int column = 0; const int mxcsrRow = 1, fzRow = mxcsrRow, dazRow = mxcsrRow, excRow = mxcsrRow; const int rndRow = fzRow + 1, maskRow = rndRow; group->insert(mxcsrRow, column, new FieldWidget(mxcsrName, group)); column += mxcsrName.length() + 1; const auto mxcsrIndex = findModelRegister(catIndex, "MXCSR", MODEL_VALUE_COLUMN); const auto mxcsrValueWidth = mxcsrIndex.data(Model::FixedLengthRole).toInt(); assert(mxcsrValueWidth > 0); group->insert(mxcsrRow, column, new ValueField(mxcsrValueWidth, mxcsrIndex, group)); column += mxcsrValueWidth + 2; // XXX: Sacrificing understandability of DAZ->DZ to align PUOZDI with FPU's. // Also FZ value is one char away from DAZ name, which is also no good. // Maybe following OllyDbg example here isn't a good idea. const QString fzName = "FZ", dazName = "DZ"; const auto fzColumn = column; const auto fzNameField = new FieldWidget(fzName, group); group->insert(fzRow, fzColumn, fzNameField); column += fzName.length() + 1; const auto fzIndex = findModelRegister(mxcsrIndex, "FZ", MODEL_VALUE_COLUMN); const auto fzValueWidth = 1; const auto fzValueField = new ValueField(fzValueWidth, fzIndex, group); group->insert(fzRow, column, fzValueField); column += fzValueWidth + 1; const auto dazNameField = new FieldWidget(dazName, group); group->insert(dazRow, column, dazNameField); column += dazName.length() + 1; const auto dazIndex = findModelRegister(mxcsrIndex, "DAZ", MODEL_VALUE_COLUMN); const auto dazValueWidth = 1; const auto dazValueField = new ValueField(dazValueWidth, dazIndex, group); group->insert(dazRow, column, dazValueField); column += dazValueWidth + 2; const QString excName = "Err"; group->insert(excRow, column, new FieldWidget(excName, group)); const QString maskName = "Mask"; group->insert(maskRow, column, new FieldWidget(maskName, group)); column += maskName.length() + 1; addPUOZDI(group, mxcsrIndex, mxcsrIndex, excRow - 1, column); const auto rndNameColumn = fzColumn; const QString rndName = "Rnd"; group->insert(rndRow, rndNameColumn, new FieldWidget(rndName, group)); const auto rndColumn = rndNameColumn + rndName.length() + 1; addRoundingMode(group, findModelRegister(mxcsrIndex, "RC", MODEL_VALUE_COLUMN), rndRow, rndColumn); { const auto fzTooltip = QObject::tr("Flush Denormals To Zero") + " (FTZ)"; fzNameField->setToolTip(fzTooltip); fzValueField->setToolTip(fzTooltip); } { const auto dazTooltip = QObject::tr("Denormals Are Zeros") + " (DAZ)"; dazNameField->setToolTip(dazTooltip); dazValueField->setToolTip(dazTooltip); } return group; } } edb-debugger-1.0.0/plugins/ODbgRegisterView/DialogEditFPU.h0000644000175000017500000000275213273160654022744 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef DIALOG_EDIT_FPU_H_20151031 #define DIALOG_EDIT_FPU_H_20151031 #include "Register.h" #include #include namespace ODbgRegisterView { class Float80Edit; class DialogEditFPU : public QDialog { Q_OBJECT public: DialogEditFPU(QWidget *parent = nullptr); Register value() const; void set_value(const Register ®); private Q_SLOTS: void onHexEdited(const QString &); void onFloatEdited(const QString &); void updateFloatEntry(); void updateHexEntry(); protected: bool eventFilter(QObject*, QEvent*) override; private: static_assert(sizeof(long double) >= 10, "This class will only work with true 80-bit long double"); Register reg; edb::value80 value_; ODbgRegisterView::Float80Edit *const floatEntry; QLineEdit *const hexEntry; }; } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/EntryGridKeyUpDownEventFilter.cpp0000644000175000017500000000357013273160654026603 0ustar eteraneteran#include "EntryGridKeyUpDownEventFilter.h" #include #include #include #include #include #include namespace ODbgRegisterView { bool entryGridKeyUpDownEventFilter(QWidget* parent, QObject* obj, QEvent* event) { auto*const entry=qobject_cast(obj); if(!entry) return false; if(event->type()!=QEvent::KeyPress) return false; auto*const keyEvent=static_cast(event); const auto key=keyEvent->key(); if(key!=Qt::Key_Up && key!=Qt::Key_Down) return false; // subtraction of 1 from x prevents selection of entry to the right-top/bottom instead directly top/bottom const auto pos=entry->pos()-QPoint(1,0); const auto children=parent->findChildren(); // Find the neighbors above/below the current entry std::vector neighbors; for(auto*const child : children) { if(!child->isVisible()) continue; if(key==Qt::Key_Up && child->y() >= pos.y()) continue; if(key==Qt::Key_Down && child->y() <= pos.y()) continue; neighbors.emplace_back(child); } if(neighbors.empty()) return false; // Bring the vertically closest neighbors to the front const auto y=pos.y(); std::sort(neighbors.begin(),neighbors.end(), [y](QLineEdit*a,QLineEdit*b) { return std::abs(y - a->y()) < std::abs(y - b->y()); }); const auto verticallyClosestY=neighbors.front()->y(); // Remove those too far vertically, so that they don't interfere with later calculations neighbors.erase(std::remove_if(neighbors.begin(),neighbors.end(),[verticallyClosestY](QLineEdit*e) { return e->y()!=verticallyClosestY; }),neighbors.end()); assert(!neighbors.empty()); const auto x=pos.x(); const auto bestNeighbor=*std::min_element(neighbors.begin(),neighbors.end(), [x](QLineEdit*a,QLineEdit*b) { return std::abs(x - a->x()) < std::abs(x - b->x()); }); bestNeighbor->setFocus(Qt::TabFocusReason); return true; } } edb-debugger-1.0.0/plugins/ODbgRegisterView/Plugin.cpp0000644000175000017500000002002013273160654022141 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "Plugin.h" #include "ArchProcessor.h" #include "RegisterView.h" #include "edb.h" #include #include #include #include #include #include #include namespace ODbgRegisterView { namespace { const auto pluginName = QLatin1String("ODbgRegisterView"); const auto dockName = QObject::tr("Registers"); const auto dockNameSuffixTemplate = QString(" <%1>"); const auto dockObjectNameTemplate = QString(pluginName + "-%1"); const auto VIEW = QLatin1String("views"); } Plugin::Plugin() : QObject(0), menu_(0) { connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(saveState())); } void Plugin::setupDocks() { QSettings settings; settings.beginGroup(pluginName); if (settings.value(VIEW + "/size").isValid()) { const int size = settings.beginReadArray(VIEW); for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); createRegisterView(settings.group()); } } else { createRegisterView(); } } void Plugin::saveState() const { QSettings settings; const int size = registerViews_.size(); const auto arrayKey = pluginName + "/" + VIEW; settings.remove(arrayKey); settings.beginWriteArray(arrayKey, size); for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); registerViews_[i]->saveState(settings.group()); } } void Plugin::createRegisterView() { createRegisterView(""); } void Plugin::createRegisterView(QString const &settingsGroup) { if (auto *const mainWindow = qobject_cast(edb::v1::debugger_ui)) { const auto regView = new ODBRegView(settingsGroup, mainWindow); registerViews_.emplace_back(regView); regView->setModel(&edb::v1::arch_processor().get_register_view_model()); const QString suffix = registerViews_.size() > 1 ? dockNameSuffixTemplate.arg(registerViews_.size()) : ""; auto *const regViewDockWidget = new QDockWidget(dockName + suffix, mainWindow); const auto viewNumber = registerViews_.size(); regViewDockWidget->setObjectName(dockObjectNameTemplate.arg(viewNumber)); regViewDockWidget->setWidget(regView); mainWindow->addDockWidget(Qt::RightDockWidgetArea, regViewDockWidget); QList dockWidgets = mainWindow->findChildren(); for (QDockWidget *widget : dockWidgets) { if (widget != regViewDockWidget) { if (mainWindow->dockWidgetArea(widget) == Qt::RightDockWidgetArea) { mainWindow->tabifyDockWidget(widget, regViewDockWidget); // place the new doc widget OVER the one we tabbed with // register view is important... regViewDockWidget->show(); regViewDockWidget->raise(); break; } } } Q_ASSERT(menu_); const auto removeDockAction = new QAction(tr("Remove %1").arg(regViewDockWidget->windowTitle()), menu_); const auto removeDockMapper = new QSignalMapper(menu_); removeDockMapper->setMapping(removeDockAction, regViewDockWidget); connect(removeDockAction, SIGNAL(triggered()), removeDockMapper, SLOT(map())); connect(removeDockMapper, SIGNAL(mapped(QWidget *)), this, SLOT(removeDock(QWidget *))); menuDeleteRegViewActions_.emplace_back(removeDockAction); menu_->addAction(removeDockAction); } } void Plugin::renumerateDocks() const { for (std::size_t i = 0; i < registerViews_.size(); ++i) { const auto view = registerViews_[i]; Q_ASSERT(dynamic_cast(view->parentWidget())); const auto dock = view->parentWidget(); dock->setObjectName(dockObjectNameTemplate.arg(i + 1)); dock->setWindowTitle(dockName + (i ? dockNameSuffixTemplate.arg(i + 1) : "")); } } void Plugin::removeDock(QWidget *whatToRemove) { Q_ASSERT(dynamic_cast(whatToRemove)); const auto dockToRemove = static_cast(whatToRemove); auto & views(registerViews_); const auto viewIter = std::find(views.begin(), views.end(), dockToRemove->widget()); const auto viewIndex = viewIter - views.begin(); const auto action = menuDeleteRegViewActions_[viewIndex]; whatToRemove->deleteLater(); action->deleteLater(); menu_->removeAction(action); views.erase(viewIter); menuDeleteRegViewActions_.erase(viewIndex + menuDeleteRegViewActions_.begin()); renumerateDocks(); } void Plugin::expandLSDown(bool checked) const { if (const auto mainWindow = qobject_cast(edb::v1::debugger_ui)) { mainWindow->setCorner(Qt::BottomLeftCorner, checked ? Qt::LeftDockWidgetArea : Qt::BottomDockWidgetArea); } } void Plugin::expandRSDown(bool checked) const { if (const auto mainWindow = qobject_cast(edb::v1::debugger_ui)) { mainWindow->setCorner(Qt::BottomRightCorner, checked ? Qt::RightDockWidgetArea : Qt::BottomDockWidgetArea); } } void Plugin::expandLSUp(bool checked) const { if (const auto mainWindow = qobject_cast(edb::v1::debugger_ui)) { mainWindow->setCorner(Qt::TopLeftCorner, checked ? Qt::LeftDockWidgetArea : Qt::TopDockWidgetArea); } } void Plugin::expandRSUp(bool checked) const { if (const auto mainWindow = qobject_cast(edb::v1::debugger_ui)) { mainWindow->setCorner(Qt::TopRightCorner, checked ? Qt::RightDockWidgetArea : Qt::TopDockWidgetArea); } } QMenu *Plugin::menu(QWidget *parent) { if (!menu_) { menu_ = new QMenu(tr("OllyDbg-like Register View"), parent); { const auto newRegisterView = new QAction(tr("New Register View"), menu_); connect(newRegisterView, SIGNAL(triggered()), this, SLOT(createRegisterView())); menu_->addAction(newRegisterView); } // FIXME: setChecked calls currently don't really work, since at this stage mainWindow hasn't yet restored its state if (auto *const mainWindow = qobject_cast(edb::v1::debugger_ui)) { { const auto expandLeftSideUp = new QAction(tr("Expand Left-Hand Side Dock Up"), menu_); expandLeftSideUp->setCheckable(true); expandLeftSideUp->setChecked(mainWindow->corner(Qt::TopLeftCorner) == Qt::LeftDockWidgetArea); connect(expandLeftSideUp, SIGNAL(toggled(bool)), this, SLOT(expandLSUp(bool))); menu_->addAction(expandLeftSideUp); } { const auto expandLeftSideDown = new QAction(tr("Expand Left-Hand Side Dock Down"), menu_); expandLeftSideDown->setCheckable(true); expandLeftSideDown->setChecked(mainWindow->corner(Qt::BottomLeftCorner) == Qt::LeftDockWidgetArea); connect(expandLeftSideDown, SIGNAL(toggled(bool)), this, SLOT(expandLSDown(bool))); menu_->addAction(expandLeftSideDown); } { const auto expandRightSideUp = new QAction(tr("Expand Right-Hand Side Dock Up"), menu_); expandRightSideUp->setCheckable(true); expandRightSideUp->setChecked(mainWindow->corner(Qt::TopRightCorner) == Qt::RightDockWidgetArea); connect(expandRightSideUp, SIGNAL(toggled(bool)), this, SLOT(expandRSUp(bool))); menu_->addAction(expandRightSideUp); } { const auto expandRightSideDown = new QAction(tr("Expand Right-Hand Side Dock Down"), menu_); expandRightSideDown->setCheckable(true); expandRightSideDown->setChecked(mainWindow->corner(Qt::BottomRightCorner) == Qt::RightDockWidgetArea); connect(expandRightSideDown, SIGNAL(toggled(bool)), this, SLOT(expandRSDown(bool))); menu_->addAction(expandRightSideDown); } menu_->addSeparator(); } setupDocks(); } return menu_; } QList Plugin::cpu_context_menu() { QList ret; return ret; } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(ODbgRegisterView, Plugin) #endif } edb-debugger-1.0.0/plugins/ODbgRegisterView/DialogEditSIMDRegister.cpp0000644000175000017500000004227413273160654025111 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "DialogEditSIMDRegister.h" #include "FloatX.h" #include "QLongValidator.h" #include "QULongValidator.h" #include "NumberEdit.h" #include #include #include #include #include #include #include #include #include #include #include #include "EntryGridKeyUpDownEventFilter.h" namespace ODbgRegisterView { template void DialogEditSIMDRegister::setupEntries(const QString &label, std::array &entries, int row, const char *slot, int naturalWidthInChars) { auto contentsGrid = qobject_cast(layout()); contentsGrid->addWidget(new QLabel(label, this), row, ENTRIES_FIRST_COL - 1); for (std::size_t entryIndex = 0; entryIndex < numEntries; ++entryIndex) { auto & entry = entries[entryIndex]; const int bytesPerEntry = numBytes / numEntries; entry = new NumberEdit(ENTRIES_FIRST_COL + bytesPerEntry * (numEntries - 1 - entryIndex), bytesPerEntry, this); entry->setNaturalWidthInChars(naturalWidthInChars); connect(entry, SIGNAL(textEdited(const QString &)), this, slot); entry->installEventFilter(this); } } DialogEditSIMDRegister::DialogEditSIMDRegister(QWidget *parent) : QDialog(parent), byteHexValidator(new QRegExpValidator(QRegExp("[0-9a-fA-F]{0,2}"), this)), wordHexValidator(new QRegExpValidator(QRegExp("[0-9a-fA-F]{0,4}"), this)), dwordHexValidator(new QRegExpValidator(QRegExp("[0-9a-fA-F]{0,8}"), this)), qwordHexValidator(new QRegExpValidator(QRegExp("[0-9a-fA-F]{0,16}"), this)), byteSignedValidator(new QLongValidator(INT8_MIN, INT8_MAX, this)), wordSignedValidator(new QLongValidator(INT16_MIN, INT16_MAX, this)), dwordSignedValidator(new QLongValidator(INT32_MIN, INT32_MAX, this)), qwordSignedValidator(new QLongValidator(INT64_MIN, INT64_MAX, this)), byteUnsignedValidator(new QULongValidator(0, UINT8_MAX, this)), wordUnsignedValidator(new QULongValidator(0, UINT16_MAX, this)), dwordUnsignedValidator(new QULongValidator(0, UINT32_MAX, this)), qwordUnsignedValidator(new QULongValidator(0, UINT64_MAX, this)), float32Validator(new FloatXValidator(this)), float64Validator(new FloatXValidator(this)), intMode(NumberDisplayMode::Hex) { setWindowTitle(tr("Edit SIMD Register")); setModal(true); const auto allContentsGrid = new QGridLayout(this); for (int byteIndex = 0; byteIndex < numBytes; ++byteIndex) { columnLabels[byteIndex] = new QLabel(std::to_string(byteIndex).c_str(), this); columnLabels[byteIndex]->setAlignment(Qt::AlignCenter); allContentsGrid->addWidget(columnLabels[byteIndex], BYTE_INDICES_ROW, ENTRIES_FIRST_COL + numBytes - 1 - byteIndex); } setupEntries(tr("Byte"), bytes, BYTES_ROW, SLOT(onByteEdited()), 4); setupEntries(tr("Word"), words, WORDS_ROW, SLOT(onWordEdited()), 6); setupEntries(tr("Doubleword"), dwords, DWORDS_ROW, SLOT(onDwordEdited()), 11); setupEntries(tr("Quadword"), qwords, QWORDS_ROW, SLOT(onQwordEdited()), 21); setupEntries(tr("float32"), floats32, FLOATS32_ROW, SLOT(onFloat32Edited()), 14); setupEntries(tr("float64"), floats64, FLOATS64_ROW, SLOT(onFloat64Edited()), 24); for (const auto &entry : floats32) { entry->setValidator(float32Validator); } for (const auto &entry : floats64) { entry->setValidator(float64Validator); } hexSignOKCancelLayout = new QHBoxLayout(); { const auto hexSignRadiosLayout = new QVBoxLayout(); radioHex = new QRadioButton(tr("Hexadecimal"), this); connect(radioHex, SIGNAL(toggled(bool)), this, SLOT(onHexToggled(bool))); radioHex->setChecked(true); // must be after connecting of toggled() hexSignRadiosLayout->addWidget(radioHex); radioSigned = new QRadioButton(tr("Signed"), this); connect(radioSigned, SIGNAL(toggled(bool)), this, SLOT(onSignedToggled(bool))); hexSignRadiosLayout->addWidget(radioSigned); radioUnsigned = new QRadioButton(tr("Unsigned"), this); connect(radioUnsigned, SIGNAL(toggled(bool)), this, SLOT(onUnsignedToggled(bool))); hexSignRadiosLayout->addWidget(radioUnsigned); hexSignOKCancelLayout->addLayout(hexSignRadiosLayout); } { const auto okCancelLayout = new QVBoxLayout(); okCancelLayout->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); okCancel = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok, Qt::Horizontal, this); connect(okCancel, SIGNAL(accepted()), this, SLOT(accept())); connect(okCancel, SIGNAL(rejected()), this, SLOT(reject())); okCancelLayout->addWidget(okCancel); hexSignOKCancelLayout->addLayout(okCancelLayout); } resetLayout(); for (int byte = numBytes - 1; byte > 0; --byte) { setTabOrder(bytes[byte], bytes[byte - 1]); } setTabOrder(bytes.back(), words.front()); for (int word = numBytes / 2 - 1; word > 0; --word) { setTabOrder(words[word], words[word - 1]); } setTabOrder(words.back(), dwords.front()); for (int dword = numBytes / 4 - 1; dword > 0; --dword) { setTabOrder(dwords[dword], dwords[dword - 1]); } setTabOrder(dwords.back(), qwords.front()); for (int qword = numBytes / 8 - 1; qword > 0; --qword) { setTabOrder(qwords[qword], qwords[qword - 1]); } setTabOrder(qwords.back(), floats32.front()); for (int float32 = numBytes / 4 - 1; float32 > 0; --float32) { setTabOrder(floats32[float32], floats32[float32 - 1]); } setTabOrder(floats32.back(), floats64.front()); for (int float64 = numBytes / 8 - 1; float64 > 0; --float64) { setTabOrder(floats64[float64], floats64[float64 - 1]); } setTabOrder(floats64.front(), radioHex); setTabOrder(radioHex, radioSigned); setTabOrder(radioSigned, radioUnsigned); setTabOrder(radioUnsigned, okCancel); } template void DialogEditSIMDRegister::updateFloatEntries(const std::array &entries, NumberEdit *notUpdated) { for (std::size_t i = 0; i < entries.size(); ++i) { if (entries[i] == notUpdated) { continue; } T value; std::memcpy(&value, &value_[i * sizeof(value)], sizeof(value)); entries[i]->setText(formatFloat(value)); } } template void DialogEditSIMDRegister::updateIntegralEntries(const std::array &entries, NumberEdit *notUpdated) { for (std::size_t i = 0; i < entries.size(); ++i) { if (entries[i] == notUpdated) { continue; } T value; std::memcpy(&value, &value_[i * sizeof(value)], sizeof(value)); formatInteger(entries[i], value); } } void DialogEditSIMDRegister::updateAllEntriesExcept(NumberEdit *notUpdated) { updateIntegralEntries(bytes, notUpdated); updateIntegralEntries(words, notUpdated); updateIntegralEntries(dwords, notUpdated); updateIntegralEntries(qwords, notUpdated); updateFloatEntries(floats32, notUpdated); updateFloatEntries(floats64, notUpdated); } void DialogEditSIMDRegister::resetLayout() { auto layout = qobject_cast(this->layout()); for (int col = ENTRIES_FIRST_COL; col < TOTAL_COLS; ++col) { int i = numBytes - 1 - (col - ENTRIES_FIRST_COL); columnLabels[i]->show(); const auto &byte = bytes[i]; layout->addWidget(byte, BYTES_ROW, byte->column(), 1, byte->colSpan()); byte->show(); const auto &word = words[i / 2]; layout->addWidget(word, WORDS_ROW, word->column(), 1, word->colSpan()); word->show(); const auto &dword = dwords[i / 4]; layout->addWidget(dword, DWORDS_ROW, dword->column(), 1, dword->colSpan()); dword->show(); const auto &qword = qwords[i / 8]; layout->addWidget(qword, QWORDS_ROW, qword->column(), 1, qword->colSpan()); qword->show(); const auto &float32 = floats32[i / 4]; layout->addWidget(float32, FLOATS32_ROW, float32->column(), 1, float32->colSpan()); float32->show(); const auto &float64 = floats64[i / 8]; layout->addWidget(float64, FLOATS64_ROW, float64->column(), 1, float64->colSpan()); float64->show(); } for (int row = ENTRIES_FIRST_ROW; row < ROW_AFTER_ENTRIES; ++row) layout->itemAtPosition(row, LABELS_COL)->widget()->show(); layout->removeItem(hexSignOKCancelLayout); hexSignOKCancelLayout->setParent(nullptr); layout->addLayout(hexSignOKCancelLayout, ROW_AFTER_ENTRIES, ENTRIES_FIRST_COL, 1, numBytes); } void DialogEditSIMDRegister::hideColumns(EntriesCols afterLastToHide) { auto layout = qobject_cast(this->layout()); for (int col = ENTRIES_FIRST_COL; col < afterLastToHide; ++col) { int i = numBytes - 1 - (col - ENTRIES_FIRST_COL); Q_ASSERT(0 < i && std::size_t(i) < bytes.size()); columnLabels[i]->hide(); // Spanned entries shouldn't just be hidden. If they are still in the grid, // then we get extra spacing between invisible columns, which is unwanted. // So we have to also remove them from the layout. layout->removeWidget(bytes[i]); bytes[i]->hide(); layout->removeWidget(words[i / 2]); words[i / 2]->hide(); layout->removeWidget(dwords[i / 4]); dwords[i / 4]->hide(); layout->removeWidget(qwords[i / 8]); qwords[i / 8]->hide(); layout->removeWidget(floats32[i / 4]); floats32[i / 4]->hide(); layout->removeWidget(floats64[i / 8]); floats64[i / 8]->hide(); } layout->removeItem(hexSignOKCancelLayout); hexSignOKCancelLayout->setParent(nullptr); layout->addLayout(hexSignOKCancelLayout, ROW_AFTER_ENTRIES, afterLastToHide, 1, TOTAL_COLS - afterLastToHide); } void DialogEditSIMDRegister::hideRows(EntriesRows rowToHide) { auto layout = qobject_cast(this->layout()); for (int col = 0; col < TOTAL_COLS; ++col) { const auto item = layout->itemAtPosition(rowToHide, col); if (item && item->widget()) { item->widget()->hide(); } } } bool DialogEditSIMDRegister::eventFilter(QObject* obj, QEvent* event) { return entryGridKeyUpDownEventFilter(this,obj,event); } void DialogEditSIMDRegister::set_value(const Register &newReg) { resetLayout(); assert(newReg.bitSize() <= 8 * sizeof value_); reg = newReg; util::markMemory(&value_, value_.size()); if (QRegExp("mm[0-7]").exactMatch(reg.name())) { const auto value = reg.value(); std::memcpy(&value_, &value, sizeof value); hideColumns(MMX_FIRST_COL); // MMX registers are never used in float computations, so hide useless rows hideRows(FLOATS32_ROW); hideRows(FLOATS64_ROW); } else if (QRegExp("xmm[0-9]+").exactMatch(reg.name())) { const auto value = reg.value(); std::memcpy(&value_, &value, sizeof value); hideColumns(XMM_FIRST_COL); } else if (QRegExp("ymm[0-9]+").exactMatch(reg.name())) { const auto value = reg.value(); std::memcpy(&value_, &value, sizeof value); hideColumns(YMM_FIRST_COL); } else qCritical() << "DialogEditSIMDRegister::set_value(" << reg.name() << "): register type unsupported"; setWindowTitle(tr("Modify %1").arg(reg.name().toUpper())); updateAllEntriesExcept(nullptr); } void DialogEditSIMDRegister::set_current_element(RegisterViewModelBase::Model::ElementSize size, NumberDisplayMode format, int elementIndex) { using namespace RegisterViewModelBase; if (format != intMode && format != NumberDisplayMode::Float) { switch (format) { case NumberDisplayMode::Hex: radioHex->setChecked(true); break; case NumberDisplayMode::Signed: radioSigned->setChecked(true); break; case NumberDisplayMode::Unsigned: radioUnsigned->setChecked(true); break; case NumberDisplayMode::Float: break; // silence the compiler, we'll never get here } } NumberEdit *edit = bytes[0]; if (format == NumberDisplayMode::Float) { edit = floats32[0]; if (size == Model::ElementSize::DWORD) edit = floats32[elementIndex]; else if (size == Model::ElementSize::QWORD) edit = floats64[elementIndex]; } else { switch (size) { case Model::ElementSize::BYTE: edit = bytes[elementIndex]; break; case Model::ElementSize::WORD: edit = words[elementIndex]; break; case Model::ElementSize::DWORD: edit = dwords[elementIndex]; break; case Model::ElementSize::QWORD: edit = qwords[elementIndex]; break; default: EDB_PRINT_AND_DIE("Unexpected size ", static_cast(size)); } } edit->setFocus(Qt::OtherFocusReason); } std::uint64_t DialogEditSIMDRegister::readInteger(const NumberEdit *const edit) const { bool ok; switch (intMode) { case NumberDisplayMode::Hex: return edit->text().toULongLong(&ok, 16); break; case NumberDisplayMode::Signed: return edit->text().toLongLong(&ok); break; case NumberDisplayMode::Unsigned: return edit->text().toULongLong(&ok); break; default: Q_ASSERT("Unexpected integer display mode" && 0); return 0xbadbadbadbadbad1; } } template void DialogEditSIMDRegister::formatInteger(NumberEdit *const edit, Integer integer) const { switch (intMode) { case NumberDisplayMode::Hex: edit->setText(QString("%1").arg(integer, 2 * sizeof integer, 16, QChar('0'))); break; case NumberDisplayMode::Signed: typedef typename std::remove_reference::type Int; typedef typename std::make_signed::type Signed; edit->setText(QString("%1").arg(static_cast(integer))); break; case NumberDisplayMode::Unsigned: edit->setText(QString("%1").arg(integer)); break; default: Q_ASSERT("Unexpected integer display mode" && 0); return; } } template void DialogEditSIMDRegister::onIntegerEdited(QObject *sender, const std::array &elements) { const auto changedElementEdit = qobject_cast(sender); std::size_t elementIndex = std::find(elements.begin(), elements.end(), changedElementEdit) - elements.begin(); Integer value = readInteger(elements[elementIndex]); std::memcpy(&value_[elementIndex * sizeof(value)], &value, sizeof(value)); updateAllEntriesExcept(elements[elementIndex]); } template void DialogEditSIMDRegister::onFloatEdited(QObject *sender, const std::array &elements) { const auto changedFloatEdit = qobject_cast(sender); std::size_t floatIndex = std::find(elements.begin(), elements.end(), changedFloatEdit) - elements.begin(); bool ok = false; auto value = readFloat(elements[floatIndex]->text(), ok); if (ok) { std::memcpy(&value_[floatIndex * sizeof(value)], &value, sizeof(value)); updateAllEntriesExcept(elements[floatIndex]); } } void DialogEditSIMDRegister::onByteEdited() { onIntegerEdited(sender(), bytes); } void DialogEditSIMDRegister::onWordEdited() { onIntegerEdited(sender(), words); } void DialogEditSIMDRegister::onDwordEdited() { onIntegerEdited(sender(), dwords); } void DialogEditSIMDRegister::onQwordEdited() { onIntegerEdited(sender(), qwords); } void DialogEditSIMDRegister::onFloat32Edited() { onFloatEdited(sender(), floats32); } void DialogEditSIMDRegister::onFloat64Edited() { onFloatEdited(sender(), floats64); } void DialogEditSIMDRegister::onHexToggled(bool checked) { if ((checked && intMode != NumberDisplayMode::Hex) || !bytes.front()->validator()) { intMode = NumberDisplayMode::Hex; for (const auto &byte : bytes) byte->setValidator(byteHexValidator); for (const auto &word : words) word->setValidator(wordHexValidator); for (const auto &dword : dwords) dword->setValidator(dwordHexValidator); for (const auto &qword : qwords) qword->setValidator(qwordHexValidator); updateAllEntriesExcept(nullptr); } } void DialogEditSIMDRegister::onSignedToggled(bool checked) { if ((checked && intMode != NumberDisplayMode::Signed) || !bytes.front()->validator()) { intMode = NumberDisplayMode::Signed; for (const auto &byte : bytes) byte->setValidator(byteSignedValidator); for (const auto &word : words) word->setValidator(wordSignedValidator); for (const auto &dword : dwords) dword->setValidator(dwordSignedValidator); for (const auto &qword : qwords) qword->setValidator(qwordSignedValidator); updateAllEntriesExcept(nullptr); } } void DialogEditSIMDRegister::onUnsignedToggled(bool checked) { if ((checked && intMode != NumberDisplayMode::Unsigned) || !bytes.front()->validator()) { intMode = NumberDisplayMode::Unsigned; for (const auto &byte : bytes) byte->setValidator(byteUnsignedValidator); for (const auto &word : words) word->setValidator(wordUnsignedValidator); for (const auto &dword : dwords) dword->setValidator(dwordUnsignedValidator); for (const auto &qword : qwords) qword->setValidator(qwordUnsignedValidator); updateAllEntriesExcept(nullptr); } } Register DialogEditSIMDRegister::value() const { Register out(reg); out.setValueFrom(value_); return out; } } edb-debugger-1.0.0/plugins/ODbgRegisterView/ValueField.h0000644000175000017500000000536413273160654022406 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef VALUE_FIELD_H_20170818 #define VALUE_FIELD_H_20170818 #include "FieldWidget.h" #include "RegisterViewModelBase.h" #include class QAction; class QMouseEvent; namespace ODbgRegisterView { class ValueField : public FieldWidget { Q_OBJECT private: bool selected_ = false; bool hovered_ = false; std::function valueFormatter; // For GPR QAction *setToZeroAction = nullptr; QAction *setToOneAction = nullptr; protected: QList menuItems; private: void init(); QColor fgColorForChangedField() const; void editNormalReg(QModelIndex const &indexToEdit, QModelIndex const &clickedIndex) const; protected: RegisterViewModelBase::Model *model() const; bool changed() const; void enterEvent(QEvent *) override; void leaveEvent(QEvent *) override; void mousePressEvent(QMouseEvent *event) override; void mouseDoubleClickEvent(QMouseEvent *event) override; void paintEvent(QPaintEvent *event) override; ValueField *bestNeighbor(std::function const &firstIsBetter) const; public: ValueField(int fieldWidth, QModelIndex const &index, QWidget *parent = nullptr, std::function const &valueFormatter = [](QString const &s) { return s; }); ValueField *up() const; ValueField *down() const; ValueField *left() const; ValueField *right() const; bool isSelected() const; void showMenu(QPoint const &position); QString text() const override; QModelIndex regIndex() const; public Q_SLOTS: void defaultAction(); #if defined EDB_X86 || defined EDB_X86_64 void pushFPUStack(); void popFPUStack(); #endif void adjustToData() override; void select(); void unselect(); virtual void updatePalette(); void copyToClipboard() const; void setZero(); void setToOne(); void increment(); void decrement(); void invert(); Q_SIGNALS: void selected(); }; } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/NumberEdit.cpp0000644000175000017500000000215113273160654022746 0ustar eteraneteran #include "NumberEdit.h" #include namespace ODbgRegisterView { NumberEdit::NumberEdit(int column, int colSpan, QWidget *parent) : QLineEdit(parent), column_(column), colSpan_(colSpan) { } NumberEdit::~NumberEdit() { } int NumberEdit::column() const { return column_; } int NumberEdit::colSpan() const { return colSpan_; } void NumberEdit::setNaturalWidthInChars(int nChars) { naturalWidthInChars = nChars; } QSize NumberEdit::minimumSizeHint() const { return sizeHint(); } QSize NumberEdit::sizeHint() const { const auto baseHint = QLineEdit::sizeHint(); // taking long enough reference char to make enough room even in presence of inner shadows like in Oxygen style const auto charWidth = QFontMetrics(font()).width(QLatin1Char('w')); const auto textMargins = this->textMargins(); const auto contentsMargins = this->contentsMargins(); int customWidth = charWidth * naturalWidthInChars + textMargins.left() + contentsMargins.left() + textMargins.right() + contentsMargins.right(); return QSize(customWidth, baseHint.height()).expandedTo(QApplication::globalStrut()); } } edb-debugger-1.0.0/plugins/ODbgRegisterView/DialogEditGPR.h0000644000175000017500000000435113273160654022737 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef DIALOG_EDIT_GPR_H_20151011 #define DIALOG_EDIT_GPR_H_20151011 #include "Register.h" #include #include #include #include #include namespace ODbgRegisterView { class GPREdit; class DialogEditGPR : public QDialog { Q_OBJECT public: DialogEditGPR(QWidget *parent = nullptr); public: Register value() const; void set_value(const Register ®); private Q_SLOTS: void onTextEdited(const QString &); private: enum Column { FORMAT_LABELS_COL, FIRST_ENTRY_COL, GPR64_COL = FIRST_ENTRY_COL, GPR32_COL, GPR16_COL, GPR8H_COL, GPR8L_COL, TOTAL_COLS, ENTRY_COLS = TOTAL_COLS - 1, CHAR_COLS = 2 }; enum Row { GPR_LABELS_ROW, FIRST_ENTRY_ROW, HEX_ROW = FIRST_ENTRY_ROW, SIGNED_ROW, UNSIGNED_ROW, LAST_FULL_LENGTH_ROW = UNSIGNED_ROW, CHAR_ROW, ROW_AFTER_ENTRIES, FULL_LENGTH_ROWS = LAST_FULL_LENGTH_ROW - FIRST_ENTRY_ROW + 1, ENTRY_ROWS = ROW_AFTER_ENTRIES - FIRST_ENTRY_ROW }; protected: bool eventFilter(QObject*, QEvent*) override; private: void updateAllEntriesExcept(GPREdit *notUpdated); void hideColumn(Column col); void hideRow(Row row); void setupEntriesAndLabels(); void resetLayout(); QLabel *&columnLabel(Column col); QLabel *&rowLabel(Row row); GPREdit *&entry(Row row, Column col); void setupFocus(); private: std::array labels = {{0}}; std::array entries = {{0}}; std::uint64_t value_; std::size_t bitSize_ = 0; Register reg; }; } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/CMakeLists.txt0000644000175000017500000000257213273160654022753 0ustar eteraneterancmake_minimum_required (VERSION 2.8) include("GNUInstallDirs") set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) include("${PROJECT_SOURCE_DIR}/cmake/EnableCXX11.cmake") set(PluginName "ODbgRegisterView") if(Qt5Core_FOUND) find_package(Qt5 5.0.0 REQUIRED Widgets) else(Qt5Core_FOUND) find_package(Qt4 4.6.0 QUIET REQUIRED QtCore QtGui) include(${QT_USE_FILE}) endif() set(PluginSources DialogEditGPR.cpp GPREdit.cpp Plugin.cpp Plugin.h RegisterView.cpp RegisterView.h ValueField.cpp FieldWidget.cpp DialogEditSIMDRegister.cpp NumberEdit.cpp EntryGridKeyUpDownEventFilter.cpp ) if((${CMAKE_SYSTEM_PROCESSOR} MATCHES "i[3456]86") OR (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")) set(PluginSources ${PluginSources} x86Groups.cpp x86FPUValueField.cpp Float80Edit.cpp DialogEditFPU.cpp ) endif() if((${CMAKE_SYSTEM_PROCESSOR} MATCHES "armv[0-9]+")) set(PluginSources ${PluginSources} armGroups.cpp ) endif() # we put the header files from the include directory here # too so automoc can "just work" add_library(${PluginName} SHARED ${PluginSources}) if(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt5::Widgets) else(Qt5Core_FOUND) target_link_libraries(${PluginName} Qt4::QtGui) endif() set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}) install (TARGETS ${PluginName} DESTINATION ${CMAKE_INSTALL_LIBDIR}/edb) edb-debugger-1.0.0/plugins/ODbgRegisterView/RegisterView.h0000644000175000017500000001567513273160654023013 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef ODBG_REGISTER_VIEW_H_20151230 #define ODBG_REGISTER_VIEW_H_20151230 #include "RegisterViewModelBase.h" #include "ValueField.h" #include #include #include #include #include namespace ODbgRegisterView { class DialogEditSIMDRegister; class DialogEditGPR; class DialogEditFPU; class RegisterGroup; class ODBRegView : public QScrollArea { Q_OBJECT public: struct RegisterGroupType { enum T { #if defined EDB_X86 || defined EDB_X86_64 GPR, rIP, ExpandedEFL, Segment, EFL, FPUData, FPUWords, FPULastOp, Debug, MMX, SSEData, AVXData, MXCSR, #elif defined EDB_ARM32 GPR, CPSR, ExpandedCPSR, FPSCR, #else # error "Not implemented" #endif NUM_GROUPS } value; RegisterGroupType(T v) : value(v) { } explicit RegisterGroupType(int v) : value(static_cast(v)) { } operator T() const { return value; } }; private: std::vector visibleGroupTypes; QList menuItems; DialogEditGPR * dialogEditGPR; DialogEditSIMDRegister * dialogEditSIMDReg; DialogEditFPU * dialogEditFPU; RegisterGroup *makeGroup(RegisterGroupType type); public: ODBRegView(QString const &settings, QWidget *parent = nullptr); void setModel(RegisterViewModelBase::Model *model); QList valueFields() const; QList fields() const; void showMenu(QPoint const &position, QList const &additionalItems = {}) const; void saveState(QString const &settings) const; void groupHidden(RegisterGroup *group); DialogEditGPR * gprEditDialog() const; DialogEditSIMDRegister *simdEditDialog() const; DialogEditFPU * fpuEditDialog() const; void selectAField(); private: ValueField *selectedField() const; void updateFieldsPalette(); void keyPressEvent(QKeyEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void updateFont(); private: QList groups; private Q_SLOTS: void fieldSelected(); void modelReset(); void modelUpdated(); void copyAllRegisters(); void copyRegisterToClipboard() const; void settingsUpdated(); private: RegisterViewModelBase::Model *model_ = nullptr; }; class Canvas : public QWidget { Q_OBJECT public: Canvas(QWidget *parent = nullptr); protected: void mousePressEvent(QMouseEvent *event) override; }; class VolatileNameField : public FieldWidget { Q_OBJECT private: std::function valueFormatter; public: VolatileNameField(int fieldWidth, std::function const &valueFormatter, QWidget *parent = nullptr); QString text() const override; }; #if defined EDB_X86 || defined EDB_X86_64 class FPUValueField : public ValueField { Q_OBJECT private: int showAsRawActionIndex; int showAsFloatActionIndex; FieldWidget *commentWidget; int row; int column; QPersistentModelIndex tagValueIndex; bool groupDigits = false; public: // Will add itself and commentWidget to the group and renew their positions as needed FPUValueField(int fieldWidth, QModelIndex const ®ValueIndex, QModelIndex const &tagValueIndex, RegisterGroup *group, FieldWidget *commentWidget, int row, int column); public Q_SLOTS: void showFPUAsRaw(); void showFPUAsFloat(); void displayFormatChanged(); void updatePalette() override; }; #endif struct BitFieldDescription { int textWidth; std::vector valueNames; std::vector setValueTexts; std::function const valueEqualComparator; BitFieldDescription(int textWidth, std::vector const &valueNames, std::vector const &setValueTexts, std::function const &valueEqualComparator = [](unsigned a, unsigned b) { return a == b; }); }; class BitFieldFormatter { public: BitFieldFormatter(BitFieldDescription const &bfd); QString operator()(QString const &text); private: std::vector valueNames; }; class MultiBitFieldWidget : public ValueField { Q_OBJECT public: MultiBitFieldWidget(QModelIndex const &index, BitFieldDescription const &bfd, QWidget *parent = nullptr); public Q_SLOTS: void setValue(int value); void adjustToData() override; private: QList valueActions; std::function equal; }; class SIMDValueManager : public QObject { Q_OBJECT private: QPersistentModelIndex regIndex; int lineInGroup; QList elements; QList menuItems; NumberDisplayMode intMode; enum MenuItemNumbers { VIEW_AS_BYTES, VIEW_AS_WORDS, VIEW_AS_DWORDS, VIEW_AS_QWORDS, VIEW_AS_FLOAT32, VIEW_AS_FLOAT64, VIEW_INT_AS_HEX, VIEW_INT_AS_SIGNED, VIEW_INT_AS_UNSIGNED, MENU_ITEMS_COUNT }; using Model = RegisterViewModelBase::Model; Model * model() const; RegisterGroup * group() const; Model::ElementSize currentSize() const; NumberDisplayMode currentFormat() const; void setupMenu(); void updateMenu(); void fillGroupMenu(); public: SIMDValueManager(int lineInGroup, QModelIndex const &nameIndex, RegisterGroup *parent = nullptr); public Q_SLOTS: void displayFormatChanged(); private Q_SLOTS: void showAsInt(int size); void showAsFloat(int size); void setIntFormat(int format); }; class RegisterGroup : public QWidget { Q_OBJECT friend SIMDValueManager; private: QList menuItems; QString name; int lineAfterLastField() const; ODBRegView *regView() const; public: RegisterGroup(QString const &name, QWidget *parent = nullptr); QList fields() const; QList valueFields() const; void setIndices(QList const &indices); void insert(int line, int column, FieldWidget *widget); // Insert, but without moving to its place void insert(FieldWidget *widget); void setupPositionAndSize(int line, int column, FieldWidget *widget); void appendNameValueComment(QModelIndex const &nameIndex, QString const &tooltip = "", bool insertComment = true); void showMenu(QPoint const &position, QList const &additionalItems = {}) const; QMargins getFieldMargins() const; protected: void mousePressEvent(QMouseEvent *event) override; public Q_SLOTS: void adjustWidth(); void hideAndReport(); }; } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/ODbgRV_Common.h0000644000175000017500000000211413273160654022747 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef ODBG_REGISTER_VIEW_COMMON_H_20170817 #define ODBG_REGISTER_VIEW_COMMON_H_20170817 #include namespace ODbgRegisterView { const QKeySequence copyFieldShortcut(Qt::CTRL | Qt::Key_C); const Qt::Key setToZeroKey = Qt::Key_Z; const Qt::Key decrementKey = Qt::Key_Minus; const Qt::Key incrementKey = Qt::Key_Plus; static constexpr auto GPRCategoryName = "General Purpose"; } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/GPREdit.cpp0000644000175000017500000001162713273160654022156 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "GPREdit.h" #include "QLongValidator.h" #include "QULongValidator.h" #include #include #include #include namespace ODbgRegisterView { namespace { const QRegExpValidator byteHexValidator(QRegExp("[0-9a-fA-F]{0,2}")); const QRegExpValidator wordHexValidator(QRegExp("[0-9a-fA-F]{0,4}")); const QRegExpValidator dwordHexValidator(QRegExp("[0-9a-fA-F]{0,8}")); const QRegExpValidator qwordHexValidator(QRegExp("[0-9a-fA-F]{0,16}")); const QLongValidator byteSignedValidator(INT8_MIN, INT8_MAX); const QLongValidator wordSignedValidator(INT16_MIN, INT16_MAX); const QLongValidator dwordSignedValidator(INT32_MIN, INT32_MAX); const QLongValidator qwordSignedValidator(INT64_MIN, INT64_MAX); const QULongValidator byteUnsignedValidator(0, UINT8_MAX); const QULongValidator wordUnsignedValidator(0, UINT16_MAX); const QULongValidator dwordUnsignedValidator(0, UINT32_MAX); const QULongValidator qwordUnsignedValidator(0, UINT64_MAX); const std::map hexValidators = { {1, &byteHexValidator}, {2, &wordHexValidator}, {4, &dwordHexValidator}, {8, &qwordHexValidator} }; const std::map signedValidators = { {1, &byteSignedValidator}, {2, &wordSignedValidator}, {4, &dwordSignedValidator}, {8, &qwordSignedValidator} }; const std::map unsignedValidators = { {1, &byteUnsignedValidator}, {2, &wordUnsignedValidator}, {4, &dwordUnsignedValidator}, {8, &qwordUnsignedValidator} }; } void GPREdit::setupFormat(Format newFormat) { format = newFormat; switch (format) { case Format::Hex: setValidator(hexValidators.at(integerSize)); naturalWidthInChars = 2 * integerSize; break; case Format::Signed: setValidator(signedValidators.at(integerSize)); naturalWidthInChars = 1 + std::lround(integerSize * std::log10(256.)); break; case Format::Unsigned: setValidator(unsignedValidators.at(integerSize)); naturalWidthInChars = std::lround(integerSize * std::log10(256.)); break; case Format::Character: setMaxLength(1); break; default: Q_ASSERT("Unexpected format value" && 0); } } GPREdit::GPREdit(std::size_t offsetInInteger, std::size_t integerSize, Format newFormat, QWidget *parent) : QLineEdit(parent), naturalWidthInChars(2 * integerSize), integerSize(integerSize), offsetInInteger(offsetInInteger) { setupFormat(newFormat); } void GPREdit::setGPRValue(std::uint64_t gprValue) { std::uint64_t value(0); signBit = format == Format::Signed ? 1ull << (8 * integerSize - 1) : 0; if ((gprValue >> 8 * offsetInInteger) & signBit) value = -1; std::memcpy(&value, reinterpret_cast(&gprValue) + offsetInInteger, integerSize); switch (format) { case Format::Hex: setText(QString("%1").arg(value, naturalWidthInChars, 16, QChar('0'))); break; case Format::Signed: setText(QString("%1").arg(static_cast(value))); break; case Format::Unsigned: setText(QString("%1").arg(value)); break; case Format::Character: setText(QChar(static_cast(value))); break; } } void GPREdit::updateGPRValue(std::uint64_t &gpr) const { bool ok; std::uint64_t value; switch (format) { case Format::Hex: value = text().toULongLong(&ok, 16); break; case Format::Signed: value = text().toLongLong(&ok); break; case Format::Unsigned: value = text().toULongLong(&ok); break; case Format::Character: value = text().toStdString()[0]; break; default: Q_ASSERT("Unexpected format value" && 0); } std::memcpy(reinterpret_cast(&gpr) + offsetInInteger, &value, integerSize); } QSize GPREdit::sizeHint() const { const auto baseHint = QLineEdit::sizeHint(); // taking long enough reference char to make enough room even in presence of inner shadows like in Oxygen style const auto charWidth = QFontMetrics(font()).width(QLatin1Char('w')); const auto textMargins = this->textMargins(); const auto contentsMargins = this->contentsMargins(); int customWidth = charWidth * naturalWidthInChars + textMargins.left() + contentsMargins.left() + textMargins.right() + contentsMargins.right() + 1 * charWidth; // additional char to make edit field not too tight return QSize(customWidth, baseHint.height()).expandedTo(QApplication::globalStrut()); } } edb-debugger-1.0.0/plugins/ODbgRegisterView/DialogEditGPR.cpp0000644000175000017500000002220613273160654023271 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "DialogEditGPR.h" #include "GPREdit.h" #include #include #include #include #include #include #include #include "EntryGridKeyUpDownEventFilter.h" namespace ODbgRegisterView { DialogEditGPR::DialogEditGPR(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Modify Register")); setModal(true); const auto allContentsGrid = new QGridLayout(); // Register name labels for (std::size_t c = 0; c < ENTRY_COLS; ++c) { auto &label = columnLabel(static_cast(FIRST_ENTRY_COL + c)); label = new QLabel(this); label->setAlignment(Qt::AlignCenter); allContentsGrid->addWidget(label, GPR_LABELS_ROW, FIRST_ENTRY_COL + c); } { static const auto formatNames = util::make_array(tr("Hexadecimal"), tr("Signed"), tr("Unsigned"), tr("Character")); // Format labels for (std::size_t f = 0; f < formatNames.size(); ++f) { auto &label = rowLabel(static_cast(FIRST_ENTRY_ROW + f)); label = new QLabel(formatNames[f], this); allContentsGrid->addWidget(label, FIRST_ENTRY_ROW + f, FORMAT_LABELS_COL); } } // All entries but char { static const auto offsetsInInteger = util::make_array(0u, 0u, 0u, 1u, 0u); static const auto integerSizes = util::make_array(8u, 4u, 2u, 1u, 1u); static_assert(std::tuple_size::value == DialogEditGPR::ENTRY_COLS, "integerSizes length doesn't equal ENTRY_COLS"); static_assert(std::tuple_size::value == DialogEditGPR::ENTRY_COLS, "offsetsInInteger length doesn't equal ENTRY_COLS"); static const auto formats = util::make_array(GPREdit::Format::Hex, GPREdit::Format::Signed, GPREdit::Format::Unsigned); for (std::size_t f = 0; f < formats.size(); ++f) { for (std::size_t c = 0; c < ENTRY_COLS; ++c) { auto &entry = this->entry(static_cast(FIRST_ENTRY_ROW + f), static_cast(FIRST_ENTRY_COL + c)); entry = new GPREdit(offsetsInInteger[c], integerSizes[c], formats[f], this); connect(entry, SIGNAL(textEdited(const QString &)), this, SLOT(onTextEdited(const QString &))); entry->installEventFilter(this); allContentsGrid->addWidget(entry, FIRST_ENTRY_ROW + f, FIRST_ENTRY_COL + c); } } } // High byte char { auto &charHigh = entry(CHAR_ROW, GPR8H_COL); charHigh = new GPREdit(1, 1, GPREdit::Format::Character, this); connect(charHigh, SIGNAL(textEdited(const QString &)), this, SLOT(onTextEdited(const QString &))); charHigh->installEventFilter(this); allContentsGrid->addWidget(charHigh, CHAR_ROW, GPR8H_COL); } // Low byte char { auto &charLow = entry(CHAR_ROW, GPR8L_COL); charLow = new GPREdit(0, 1, GPREdit::Format::Character, this); connect(charLow, SIGNAL(textEdited(const QString &)), this, SLOT(onTextEdited(const QString &))); charLow->installEventFilter(this); allContentsGrid->addWidget(charLow, CHAR_ROW, GPR8L_COL); } resetLayout(); const auto okCancel = new QDialogButtonBox(this); okCancel->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); connect(okCancel, SIGNAL(accepted()), this, SLOT(accept())); connect(okCancel, SIGNAL(rejected()), this, SLOT(reject())); const auto dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(allContentsGrid); dialogLayout->addWidget(okCancel); for (std::size_t entry = 1; entry < entries.size(); ++entry) { setTabOrder(entries[entry - 1], entries[entry]); } } GPREdit *&DialogEditGPR::entry(DialogEditGPR::Row row, DialogEditGPR::Column col) { if (row < ENTRY_ROWS) return entries.at((row - FIRST_ENTRY_ROW) * ENTRY_COLS + (col - FIRST_ENTRY_COL)); if (col == GPR8H_COL) return *(entries.end() - 2); if (col == GPR8L_COL) return entries.back(); Q_ASSERT("Invalid row&col specified" && 0); return entries.front(); // silence the compiler } void DialogEditGPR::updateAllEntriesExcept(GPREdit *notUpdated) { for (auto entry : entries) { if (entry != notUpdated && !entry->isHidden()) { entry->setGPRValue(value_); } } } QLabel *&DialogEditGPR::columnLabel(DialogEditGPR::Column col) { return labels.at(col - FIRST_ENTRY_COL); } QLabel *&DialogEditGPR::rowLabel(DialogEditGPR::Row row) { return labels.at(ENTRY_COLS + row - FIRST_ENTRY_ROW); } void DialogEditGPR::hideColumn(DialogEditGPR::Column col) { Row fMax = col == GPR8L_COL || col == GPR8H_COL ? ENTRY_ROWS : FULL_LENGTH_ROWS; for (std::size_t f = 0; f < fMax; ++f) { entry(static_cast(FIRST_ENTRY_ROW + f), col)->hide(); } columnLabel(col)->hide(); } void DialogEditGPR::hideRow(Row row) { rowLabel(row)->hide(); if (row == CHAR_ROW) { entry(row, GPR8L_COL)->hide(); entry(row, GPR8H_COL)->hide(); } else { for (std::size_t c = 0; c < FULL_LENGTH_ROWS; ++c) { entry(row, static_cast(FIRST_ENTRY_COL + c))->hide(); } } } void DialogEditGPR::resetLayout() { for (auto entry : entries) { entry->show(); } for (auto label : labels) { label->show(); } static const auto colLabelStrings = util::make_array("R?X", "E?X", "?X", "?H", "?L"); static_assert(std::tuple_size::value == ENTRY_COLS, "Number of labels not equal to number of entry columns"); for (std::size_t c = 0; c < ENTRY_COLS; ++c) { columnLabel(static_cast(GPR64_COL + c))->setText(colLabelStrings[c]); } } void DialogEditGPR::setupEntriesAndLabels() { resetLayout(); switch (bitSize_) { case 8: hideColumn(GPR8H_COL); hideColumn(GPR16_COL); /* fallthrough */ case 16: hideColumn(GPR32_COL); /* fallthrough */ case 32: hideColumn(GPR64_COL); /* fallthrough */ case 64: break; default: Q_ASSERT("Unsupported bitSize" && 0); } const QString regName = reg.name().toUpper(); if (bitSize_ == 64) columnLabel(GPR64_COL)->setText(regName); else if (bitSize_ == 32) columnLabel(GPR32_COL)->setText(regName); else if (bitSize_ == 16) columnLabel(GPR16_COL)->setText(regName); else columnLabel(GPR8L_COL)->setText(regName); static const auto x86GPRsWithHighBytesAddressable = util::make_array("EAX", "ECX", "EDX", "EBX", "RAX", "RCX", "RDX", "RBX"); static const auto x86GPRsWithHighBytesNotAddressable = util::make_array("ESP", "EBP", "ESI", "EDI", "RSP", "RBP", "RSI", "RDI"); static const auto upperGPRs64 = util::make_array("R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"); bool x86GPR = false; bool upperGPR64 = false; using util::contains; if (contains(x86GPRsWithHighBytesNotAddressable, regName)) { x86GPR = true; hideColumn(GPR8H_COL); if (bitSize_ == 32) { hideColumn(GPR8L_COL); // In 32 bit mode low bytes also can't be addressed hideRow(CHAR_ROW); } } else if (contains(x86GPRsWithHighBytesAddressable, regName)) { x86GPR = true; } else if (contains(upperGPRs64, regName)) { upperGPR64 = true; } if (x86GPR) { if (bitSize_ == 64) { columnLabel(GPR32_COL)->setText("E" + regName.mid(1)); } columnLabel(GPR16_COL)->setText(regName.mid(1)); columnLabel(GPR8H_COL)->setText(regName.mid(1, 1) + "H"); if (bitSize_ == 64 && !contains(x86GPRsWithHighBytesAddressable, regName)) { columnLabel(GPR8L_COL)->setText(regName.mid(1) + "L"); } else { columnLabel(GPR8L_COL)->setText(regName.mid(1, 1) + "L"); } } else if (upperGPR64) { columnLabel(GPR32_COL)->setText(regName + "D"); columnLabel(GPR16_COL)->setText(regName + "W"); columnLabel(GPR8L_COL)->setText(regName + "B"); hideColumn(GPR8H_COL); } else { // These have hex only format hideColumn(GPR8H_COL); if (bitSize_ != 8) { hideColumn(GPR8L_COL); } if (bitSize_ != 16) { hideColumn(GPR16_COL); } if (bitSize_ != 32) { hideColumn(GPR32_COL); } hideRow(SIGNED_ROW); hideRow(UNSIGNED_ROW); hideRow(CHAR_ROW); } } void DialogEditGPR::setupFocus() { for (auto entry : entries) { if (!entry->isHidden()) { entry->setFocus(Qt::OtherFocusReason); break; } } } bool DialogEditGPR::eventFilter(QObject* obj, QEvent* event) { return entryGridKeyUpDownEventFilter(this,obj,event); } void DialogEditGPR::set_value(const Register &newReg) { reg = newReg; value_ = reg.valueAsInteger(); bitSize_ = reg.bitSize(); setupEntriesAndLabels(); setWindowTitle(tr("Modify %1").arg(reg.name().toUpper())); updateAllEntriesExcept(nullptr); setupFocus(); } Register DialogEditGPR::value() const { Register ret(reg); ret.setScalarValue(value_); return ret; } void DialogEditGPR::onTextEdited(const QString &) { GPREdit *edit = dynamic_cast(sender()); edit->updateGPRValue(value_); updateAllEntriesExcept(edit); } } edb-debugger-1.0.0/plugins/ODbgRegisterView/DialogEditFPU.cpp0000644000175000017500000001226613273160654023300 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "DialogEditFPU.h" #include "Float80Edit.h" #include #include #include #include #include #include #include #include #include #include #include #include "EntryGridKeyUpDownEventFilter.h" namespace ODbgRegisterView { namespace { long double readFloat(const QString &strInput, bool &ok) { ok = false; const QString str(strInput.toLower().trimmed()); if(const auto value=util::fullStringToFloat(str.toStdString())) { ok = true; return *value; } // OK, so either it is invalid/unfinished, or it's some special value // We still do want the user to be able to enter common special values long double value; static std::array positiveInf{0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f}; static std::array negativeInf{0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0xff}; static std::array positiveSNaN{0, 0, 0, 0, 0, 0, 0, 0x90, 0xff, 0x7f}; static std::array negativeSNaN{0, 0, 0, 0, 0, 0, 0, 0x90, 0xff, 0xff}; // Indefinite values are used for QNaN static std::array positiveQNaN{0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f}; static std::array negativeQNaN{0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0xff}; if (str == "+snan" || str == "snan") std::memcpy(&value, &positiveSNaN, sizeof value); else if (str == "-snan") std::memcpy(&value, &negativeSNaN, sizeof value); else if (str == "+qnan" || str == "qnan" || str == "nan") std::memcpy(&value, &positiveQNaN, sizeof value); else if (str == "-qnan") std::memcpy(&value, &negativeQNaN, sizeof value); else if (str == "+inf" || str == "inf") std::memcpy(&value, &positiveInf, sizeof value); else if (str == "-inf") std::memcpy(&value, &negativeInf, sizeof value); else return 0; ok = true; return value; } } DialogEditFPU::DialogEditFPU(QWidget *parent) : QDialog(parent), floatEntry(new ODbgRegisterView::Float80Edit(this)), hexEntry(new QLineEdit(this)) { setWindowTitle(tr("Modify Register")); setModal(true); const auto allContentsGrid = new QGridLayout(); allContentsGrid->addWidget(new QLabel(tr("Float"), this), 0, 0); allContentsGrid->addWidget(new QLabel(tr("Hex"), this), 1, 0); allContentsGrid->addWidget(floatEntry, 0, 1); allContentsGrid->addWidget(hexEntry, 1, 1); connect(floatEntry, SIGNAL(textEdited(const QString &)), this, SLOT(onFloatEdited(const QString &))); connect(hexEntry, SIGNAL(textEdited(const QString &)), this, SLOT(onHexEdited(const QString &))); hexEntry->setValidator(new QRegExpValidator(QRegExp("[0-9a-fA-F ]{,20}"), this)); connect(floatEntry, SIGNAL(defocussed()), this, SLOT(updateFloatEntry())); hexEntry->installEventFilter(this); floatEntry->installEventFilter(this); const auto okCancel = new QDialogButtonBox(this); okCancel->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); connect(okCancel, SIGNAL(accepted()), this, SLOT(accept())); connect(okCancel, SIGNAL(rejected()), this, SLOT(reject())); const auto dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(allContentsGrid); dialogLayout->addWidget(okCancel); setTabOrder(floatEntry, hexEntry); setTabOrder(hexEntry, okCancel); } void DialogEditFPU::updateFloatEntry() { floatEntry->setValue(value_); } void DialogEditFPU::updateHexEntry() { hexEntry->setText(value_.toHexString()); } bool DialogEditFPU::eventFilter(QObject* obj, QEvent* event) { return entryGridKeyUpDownEventFilter(this,obj,event); } void DialogEditFPU::set_value(const Register &newReg) { reg = newReg; value_ = reg.value(); updateFloatEntry(); updateHexEntry(); setWindowTitle(tr("Modify %1").arg(reg.name().toUpper())); floatEntry->setFocus(Qt::OtherFocusReason); } Register DialogEditFPU::value() const { Register ret(reg); ret.setValueFrom(value_); return ret; } void DialogEditFPU::onHexEdited(const QString &input) { QString readable(input.trimmed()); readable.replace(' ', ""); while (readable.size() < 20) { readable = '0' + readable; } const auto byteArray = QByteArray::fromHex(readable.toLatin1()); auto source = byteArray.constData(); auto dest = reinterpret_cast(&value_); for (std::size_t i = 0; i < sizeof value_; ++i) { dest[i] = source[sizeof value_ - i - 1]; } updateFloatEntry(); } void DialogEditFPU::onFloatEdited(const QString &str) { bool ok; const auto value = readFloat(str, ok); if (ok) { value_ = edb::value80(value); } updateHexEntry(); } } edb-debugger-1.0.0/plugins/ODbgRegisterView/NumberEdit.h0000644000175000017500000000225013273160654022413 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include namespace ODbgRegisterView { class NumberEdit : public QLineEdit { Q_OBJECT public: NumberEdit(int column, int colSpan, QWidget *parent = nullptr); virtual ~NumberEdit() override; public: int column() const; int colSpan() const; void setNaturalWidthInChars(int nChars); public: virtual QSize minimumSizeHint() const override; virtual QSize sizeHint() const override; private: int naturalWidthInChars = 17; // default roughly as in QLineEdit int column_; int colSpan_; }; } edb-debugger-1.0.0/plugins/ODbgRegisterView/armGroups.h0000644000175000017500000000211413273160654022333 0ustar eteraneteran/* Copyright (C) 2017 Ruslan Kabatsayev 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, see . */ #ifndef ODBG_REGISTER_VIEW_ARM_GROUPS_H_20170819 #define ODBG_REGISTER_VIEW_ARM_GROUPS_H_20170819 #include "RegisterView.h" namespace ODbgRegisterView { RegisterGroup *createCPSR(RegisterViewModelBase::Model *model, QWidget *parent); RegisterGroup *createExpandedCPSR(RegisterViewModelBase::Model *model, QWidget *parent); RegisterGroup *createFPSCR(RegisterViewModelBase::Model *model, QWidget *parent); } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/x86FPUValueField.cpp0000644000175000017500000000731413273160654023657 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "RegisterView.h" #include "ODbgRV_Util.h" #include "ODbgRV_x86Common.h" namespace ODbgRegisterView { FPUValueField::FPUValueField(int fieldWidth, QModelIndex const ®ValueIndex, QModelIndex const &tagValueIndex, RegisterGroup *group, FieldWidget *commentWidget, int row, int column) : ValueField(fieldWidth, regValueIndex, group, [this](QString const &str) { if (str.length() != 20) return str; if (groupDigits) return str.left(4) + " " + str.mid(4, 8) + " " + str.right(8); return str; }), commentWidget(commentWidget), row(row), column(column), tagValueIndex(tagValueIndex) { Q_ASSERT(group); Q_ASSERT(commentWidget); showAsRawActionIndex = menuItems.size(); menuItems.push_back(newAction(tr("View FPU as raw values"), this, this, SLOT(showFPUAsRaw()))); showAsFloatActionIndex = menuItems.size(); menuItems.push_back(newAction(tr("View FPU as floats"), this, this, SLOT(showFPUAsFloat()))); group->insert(row, column, this); group->insert(commentWidget); // will be moved to its column in the next line group->setupPositionAndSize(row, 0, commentWidget); displayFormatChanged(); connect(index.model(), SIGNAL(FPUDisplayFormatChanged()), this, SLOT(displayFormatChanged())); } void FPUValueField::showFPUAsRaw() { model()->setChosenFPUFormat(index.parent(), NumberDisplayMode::Hex); } void FPUValueField::showFPUAsFloat() { model()->setChosenFPUFormat(index.parent(), NumberDisplayMode::Float); } void FPUValueField::displayFormatChanged() { using RegisterViewModelBase::Model; const auto format = static_cast(VALID_VARIANT(index.parent().data(Model::ChosenFPUFormatRole)).toInt()); switch (format) { case NumberDisplayMode::Hex: menuItems[showAsRawActionIndex]->setVisible(false); menuItems[showAsFloatActionIndex]->setVisible(true); break; case NumberDisplayMode::Float: menuItems[showAsRawActionIndex]->setVisible(true); menuItems[showAsFloatActionIndex]->setVisible(false); break; default: menuItems[showAsRawActionIndex]->setVisible(true); menuItems[showAsFloatActionIndex]->setVisible(true); break; } const auto margins = group()->getFieldMargins(); fieldWidth_ = VALID_VARIANT(index.data(Model::FixedLengthRole)).toInt(); Q_ASSERT(fieldWidth_ > 0); if (format == NumberDisplayMode::Hex) { groupDigits = true; fieldWidth_ += 2; // add some room for spaces between groups } else groupDigits = false; const auto charWidth = letterSize(font()).width(); setFixedWidth(charWidth * fieldWidth_ + margins.left() + margins.right()); commentWidget->move(x() + maximumWidth(), commentWidget->y()); } void FPUValueField::updatePalette() { if (!changed() && tagValueIndex.data().toUInt() == FPU_TAG_EMPTY) { auto palette = group()->palette(); palette.setColor(foregroundRole(), palette.color(QPalette::Disabled, QPalette::Text)); setPalette(palette); QLabel::update(); } else ValueField::updatePalette(); } } edb-debugger-1.0.0/plugins/ODbgRegisterView/Float80Edit.h0000644000175000017500000000212713273160654022403 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef FLOAT_80_EDIT_H_20151031 #define FLOAT_80_EDIT_H_20151031 #include "Types.h" #include namespace ODbgRegisterView { class Float80Edit : public QLineEdit { Q_OBJECT public: Float80Edit(QWidget *parent = 0); void setValue(edb::value80 input); public: virtual QSize sizeHint() const override; protected: virtual void focusOutEvent(QFocusEvent *e) override; Q_SIGNALS: void defocussed(); }; } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/EntryGridKeyUpDownEventFilter.h0000644000175000017500000000042513273160654026244 0ustar eteraneteran#ifndef ENTRY_GRID_KEY_UP_DOWN_EVENT_FILTER_H_20170705 #define ENTRY_GRID_KEY_UP_DOWN_EVENT_FILTER_H_20170705 class QWidget; class QObject; class QEvent; namespace ODbgRegisterView { bool entryGridKeyUpDownEventFilter(QWidget* parent, QObject* obj, QEvent* event); } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/RegisterView.cpp0000644000175000017500000010233613273160654023335 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "RegisterView.h" #include "ODbgRV_Util.h" #include "ODbgRV_Common.h" #if defined EDB_X86 || defined EDB_X86_64 # include "x86Groups.h" # include "ODbgRV_x86Common.h" # include "DialogEditFPU.h" #elif defined EDB_ARM32 # include "armGroups.h" #endif #include "Configuration.h" #include "DialogEditGPR.h" #include "DialogEditSIMDRegister.h" #include "RegisterViewModelBase.h" #include "State.h" #include "edb.h" #include #include #include #include #include #include #include #include #include #include #include namespace ODbgRegisterView { namespace { // TODO: rFLAGS menu: Set Condition (O,P,NAE etc. - see ODB) // TODO: FSR: Set Condition: G,L,E,Unordered // TODO: Add option to show FPU in STi mode, both ST-ordered and R-ordered (physically) // TODO: Update register comments after editing values // TODO: Add a way to add back register group to RegView // TODO: all TODOs scattered around sources // TODO: "Undo" action, which returns to the state after last stopping of debuggee (visible only if register has been modified by the user) constexpr auto registerGroupTypeNames = util::make_array( #if defined EDB_X86 || defined EDB_X86_64 "GPR", "rIP", "ExpandedEFL", "Segment", "EFL", "FPUData", "FPUWords", "FPULastOp", "Debug", "MMX", "SSEData", "AVXData", "MXCSR" #elif defined EDB_ARM32 "GPR", "CPSR", "ExpandedCPSR", "FPSCR" #else # error "Not implemented" #endif ); static_assert(registerGroupTypeNames.size() == ODBRegView::RegisterGroupType::NUM_GROUPS, "Mismatch between number of register group types and names"); const auto SETTINGS_GROUPS_ARRAY_NODE = QLatin1String("visibleGroups"); } // ------------------------- BitFieldFormatter impl ------------------------------ BitFieldFormatter::BitFieldFormatter(BitFieldDescription const &bfd) : valueNames(bfd.valueNames) { } QString BitFieldFormatter::operator()(QString const &str) { assert(str.length()); if (str.isEmpty()) return str; // for release builds have defined behavior if (str[0] == '?') return "????"; bool parseOK = false; const int value = str.toInt(&parseOK); if (!parseOK) return "????"; assert(0 <= value); assert(std::size_t(value) < valueNames.size()); return valueNames[value]; } // ----------------------- BitFieldDescription impl ------------------------- BitFieldDescription::BitFieldDescription(int textWidth, std::vector const &valueNames, std::vector const &setValueTexts, std::function const &valueEqualComparator) : textWidth(textWidth), valueNames(valueNames), setValueTexts(setValueTexts), valueEqualComparator(valueEqualComparator) { } VolatileNameField::VolatileNameField(int fieldWidth, std::function const &valueFormatter, QWidget *parent) : FieldWidget(fieldWidth, "", parent), valueFormatter(valueFormatter) { } QString VolatileNameField::text() const { return valueFormatter(); } // -------------------------------- MultiBitFieldWidget impl --------------------------- MultiBitFieldWidget::MultiBitFieldWidget(QModelIndex const &index, BitFieldDescription const &bfd, QWidget *parent) : ValueField(bfd.textWidth, index, parent, BitFieldFormatter(bfd)), equal(bfd.valueEqualComparator) { const auto mapper = new QSignalMapper(this); connect(mapper, SIGNAL(mapped(int)), this, SLOT(setValue(int))); menuItems.push_front(newActionSeparator(this)); for (std::size_t i = bfd.valueNames.size(); i-- > 0;) { const auto &text = bfd.setValueTexts[i]; if (!text.isEmpty()) { menuItems.push_front(newAction(text, this, mapper, i)); valueActions.push_front(menuItems.front()); } else valueActions.push_front(nullptr); } } void MultiBitFieldWidget::setValue(int value) { using namespace RegisterViewModelBase; // TODO: Model: make it possible to set bit field itself, without manipulating parent directly // I.e. set value without knowing field offset, then setData(fieldIndex,word) const auto regIndex = index.parent().sibling(index.parent().row(), MODEL_VALUE_COLUMN); auto byteArr = regIndex.data(Model::RawValueRole).toByteArray(); if (byteArr.isEmpty()) return; std::uint64_t word(0); std::memcpy(&word, byteArr.constData(), byteArr.size()); const auto mask = (1ull << (VALID_VARIANT(index.data(Model::BitFieldLengthRole)).toInt() - 1)) * 2 - 1; const auto offset = VALID_VARIANT(index.data(Model::BitFieldOffsetRole)).toInt(); word = (word & ~(mask << offset)) | (std::uint64_t(value) << offset); std::memcpy(byteArr.data(), &word, byteArr.size()); model()->setData(regIndex, byteArr, Model::RawValueRole); } void MultiBitFieldWidget::adjustToData() { ValueField::adjustToData(); const auto byteArr = index.data(RegisterViewModelBase::Model::RawValueRole).toByteArray(); std::uint64_t word(0); assert(unsigned(byteArr.size()) <= sizeof word); std::memcpy(&word, byteArr.constData(), byteArr.size()); for (int value = 0; value < valueActions.size(); ++value) { const auto action = valueActions[value]; if (!action) continue; if (byteArr.isEmpty() || equal(word, value)) action->setVisible(false); else action->setVisible(true); } } // -------------------------------- RegisterGroup impl ---------------------------- RegisterGroup::RegisterGroup(QString const &name, QWidget *parent) : QWidget(parent), name(name) { setObjectName("RegisterGroup_" + name); { menuItems.push_back(newActionSeparator(this)); menuItems.push_back(newAction(tr("Hide %1", "register group").arg(name), this, this, SLOT(hideAndReport()))); } } void RegisterGroup::hideAndReport() { hide(); regView()->groupHidden(this); } void RegisterGroup::showMenu(QPoint const &position, QList const &additionalItems) const { return regView()->showMenu(position, additionalItems + menuItems); } void RegisterGroup::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::RightButton) showMenu(event->globalPos(), menuItems); else event->ignore(); } ODBRegView *RegisterGroup::regView() const { return checked_cast(parent() // canvas ->parent() // viewport ->parent() // regview ); } QMargins RegisterGroup::getFieldMargins() const { const auto charSize = letterSize(font()); const auto charWidth = charSize.width(); // extra space for highlighting rectangle, so that single-digit fields are easier to target const auto marginLeft = charWidth / 2; const auto marginRight = charWidth - marginLeft; return {marginLeft, 0, marginRight, 0}; } void RegisterGroup::insert(FieldWidget *const widget) { if (const auto value = qobject_cast(widget)) { connect(value, SIGNAL(selected()), regView(), SLOT(fieldSelected())); } } void RegisterGroup::insert(int const line, int const column, FieldWidget *const widget) { insert(widget); setupPositionAndSize(line, column, widget); widget->show(); } void RegisterGroup::setupPositionAndSize(int const line, int const column, FieldWidget *const widget) { widget->adjustToData(); const auto margins = getFieldMargins(); const auto charSize = letterSize(font()); QPoint position(charSize.width() * column, charSize.height() * line); position -= QPoint(margins.left(), 0); QSize size(widget->size()); size += QSize(margins.left() + margins.right(), 0); widget->setMinimumSize(size); widget->move(position); // FIXME: why are e.g. regnames like FSR truncated without the -1? widget->setContentsMargins({margins.left(), margins.top(), margins.right() - 1, margins.bottom()}); const auto potentialNewWidth = widget->pos().x() + widget->width(); const auto potentialNewHeight = widget->pos().y() + widget->height(); const auto oldMinSize = minimumSize(); if (potentialNewWidth > oldMinSize.width() || potentialNewHeight > oldMinSize.height()) { setMinimumSize(std::max(potentialNewWidth, oldMinSize.width()), std::max(potentialNewHeight, oldMinSize.height())); } } int RegisterGroup::lineAfterLastField() const { const auto fields = this->fields(); const auto bottomField = std::max_element(fields.begin(), fields.end(), [](FieldWidget *l, FieldWidget *r) { return l->pos().y() < r->pos().y(); }); return bottomField == fields.end() ? 0 : (*bottomField)->pos().y() / (*bottomField)->height() + 1; } void RegisterGroup::appendNameValueComment(QModelIndex const &nameIndex, QString const &tooltip, bool insertComment) { assert(nameIndex.isValid()); using namespace RegisterViewModelBase; const auto nameWidth = nameIndex.data(Model::FixedLengthRole).toInt(); assert(nameWidth > 0); const auto valueIndex = nameIndex.sibling(nameIndex.row(), Model::VALUE_COLUMN); const auto valueWidth = valueIndex.data(Model::FixedLengthRole).toInt(); assert(valueWidth > 0); const int line = lineAfterLastField(); int column = 0; const auto nameField = new FieldWidget(nameWidth, nameIndex.data().toString(), this); insert(line, column, nameField); column += nameWidth + 1; const auto valueField = new ValueField(valueWidth, valueIndex, this); insert(line, column, valueField); if (!tooltip.isEmpty()) { nameField->setToolTip(tooltip); valueField->setToolTip(tooltip); } if (insertComment) { column += valueWidth + 1; const auto commentIndex = nameIndex.sibling(nameIndex.row(), Model::COMMENT_COLUMN); insert(line, column, new FieldWidget(0, commentIndex, this)); } } QList RegisterGroup::fields() const { const auto children = this->children(); QList fields; for (const auto child : children) { const auto field = qobject_cast(child); if (field) fields.append(field); } return fields; } QList RegisterGroup::valueFields() const { QList allValues; Q_FOREACH(const auto field, fields()) { const auto value = qobject_cast(field); if (value) allValues.push_back(value); } return allValues; } // ------------------------------- Canvas impl ---------------------------------------- Canvas::Canvas(QWidget *parent) : QWidget(parent) { setObjectName("RegViewCanvas"); const auto canvasLayout = new QVBoxLayout(this); canvasLayout->setSpacing(letterSize(parent->font()).height() / 2); canvasLayout->setContentsMargins(parent->contentsMargins()); canvasLayout->setAlignment(Qt::AlignTop); setLayout(canvasLayout); setBackgroundRole(QPalette::Base); setAutoFillBackground(true); } void Canvas::mousePressEvent(QMouseEvent *event) { event->ignore(); } // -------------------------------- ODBRegView impl ---------------------------------------- void ODBRegView::mousePressEvent(QMouseEvent *event) { if (event->type() != QEvent::MouseButtonPress) return; if (event->button() == Qt::RightButton) { showMenu(event->globalPos()); return; } if (event->button() == Qt::LeftButton) { Q_FOREACH(const auto field, valueFields()) { field->unselect(); } } } void ODBRegView::updateFont() { QFont font; if(!font.fromString(edb::v1::config().registers_font)) { font = QFont("Monospace"); font.setStyleHint(QFont::TypeWriter); } setFont(font); } void ODBRegView::fieldSelected() { Q_FOREACH(const auto field, valueFields()) if (sender() != field) field->unselect(); ensureWidgetVisible(static_cast(sender()), 0, 0); } void ODBRegView::showMenu(QPoint const &position, QList const &additionalItems) const { QMenu menu; auto items = additionalItems + menuItems; if (model_->activeIndex().isValid()) { QList debuggerActions; QMetaObject::invokeMethod(edb::v1::debugger_ui, "getCurrentRegisterContextMenuItems", Qt::DirectConnection, Q_RETURN_ARG(QList, debuggerActions)); items.push_back(nullptr); items.append(debuggerActions); } for (const auto action : items) if (action) menu.addAction(action); else menu.addSeparator(); menu.exec(position); } void RegisterGroup::adjustWidth() { int widthNeeded = 0; Q_FOREACH(const auto field, fields()) { const auto widthToRequire = field->pos().x() + field->width(); if (widthToRequire > widthNeeded) widthNeeded = widthToRequire; } setMinimumWidth(widthNeeded); } ODBRegView::RegisterGroupType findGroup(QString const &str) { const auto &names = registerGroupTypeNames; const auto foundIt = std::find(names.begin(), names.end(), str); if (foundIt == names.end()) return ODBRegView::RegisterGroupType::NUM_GROUPS; return ODBRegView::RegisterGroupType(foundIt - names.begin()); } void ODBRegView::settingsUpdated() { // this slot is now triggered whenever the settings dialog is closed, // so it's a good spot to update the fonts and anything else which // may be affected by user config updateFont(); modelReset(); } ODBRegView::ODBRegView(QString const &settingsGroup, QWidget *parent) : QScrollArea(parent), dialogEditGPR(new DialogEditGPR(this)), dialogEditSIMDReg(new DialogEditSIMDRegister(this)), #if defined EDB_X86 || defined EDB_X86_64 dialogEditFPU(new DialogEditFPU(this)) #else dialogEditFPU(nullptr) #endif { setObjectName("ODBRegView"); connect(&edb::v1::config(), SIGNAL(settingsUpdated()), this, SLOT(settingsUpdated())); updateFont(); const auto canvas = new Canvas(this); setWidget(canvas); setWidgetResizable(true); { const auto sep = new QAction(this); sep->setSeparator(true); menuItems.push_back(sep); menuItems.push_back(newAction(tr("Copy all registers"), this, this, SLOT(copyAllRegisters()))); } QSettings settings; settings.beginGroup(settingsGroup); const auto groupListV = settings.value(SETTINGS_GROUPS_ARRAY_NODE); if (settings.group().isEmpty() || !groupListV.isValid()) { visibleGroupTypes = { #if defined EDB_X86 || defined EDB_X86_64 RegisterGroupType::GPR, RegisterGroupType::rIP, RegisterGroupType::ExpandedEFL, RegisterGroupType::Segment, RegisterGroupType::EFL, RegisterGroupType::FPUData, RegisterGroupType::FPUWords, RegisterGroupType::FPULastOp, RegisterGroupType::Debug, RegisterGroupType::MMX, RegisterGroupType::SSEData, RegisterGroupType::AVXData, RegisterGroupType::MXCSR, #elif defined EDB_ARM32 RegisterGroupType::GPR, RegisterGroupType::CPSR, RegisterGroupType::ExpandedCPSR, RegisterGroupType::FPSCR, #else # error "Not implemented" #endif }; } else { Q_FOREACH(const auto &grp, groupListV.toStringList()) { const auto group = findGroup(grp); if (group >= RegisterGroupType::NUM_GROUPS) { qWarning() << qPrintable(QString("Warning: failed to understand group %1").arg(group)); continue; } visibleGroupTypes.emplace_back(group); } } connect(new QShortcut(copyFieldShortcut, this, 0, 0, Qt::WidgetShortcut), SIGNAL(activated()), this, SLOT(copyRegisterToClipboard())); } void ODBRegView::copyRegisterToClipboard() const { const auto selected = selectedField(); if (selected) selected->copyToClipboard(); } DialogEditGPR *ODBRegView::gprEditDialog() const { return dialogEditGPR; } DialogEditSIMDRegister *ODBRegView::simdEditDialog() const { return dialogEditSIMDReg; } DialogEditFPU *ODBRegView::fpuEditDialog() const { return dialogEditFPU; } void ODBRegView::copyAllRegisters() { auto allFields = fields(); std::sort(allFields.begin(), allFields.end(), [](FieldWidget const *const f1, FieldWidget const *const f2) { const auto f1Pos = fieldPos(f1); const auto f2Pos = fieldPos(f2); if (f1Pos.y() < f2Pos.y()) return true; if (f1Pos.y() > f2Pos.y()) return false; return f1Pos.x() < f2Pos.x(); }); QString text; int textLine = 0; int textColumn = 0; for (const auto field : allFields) { while (field->lineNumber() > textLine) { ++textLine; textColumn = 0; text = text.trimmed() + '\n'; } while (field->columnNumber() > textColumn) { ++textColumn; text += ' '; } const QString fieldText = field->text(); if (field->alignment() == Qt::AlignRight) { const int fwidth = field->fieldWidth(); const int spaceWidth = fwidth - fieldText.length(); text += QString(spaceWidth, ' '); textColumn += spaceWidth; } text += fieldText; textColumn += fieldText.length(); } QApplication::clipboard()->setText(text.trimmed()); } void ODBRegView::groupHidden(RegisterGroup *group) { using namespace std; assert(util::contains(groups, group)); const auto groupPtrIter = std::find(groups.begin(), groups.end(), group); auto & groupPtr = *groupPtrIter; groupPtr->deleteLater(); groupPtr = nullptr; auto & types(visibleGroupTypes); const int groupType = groupPtrIter - groups.begin(); types.erase(remove_if(types.begin(), types.end(), [=](int type) { return type == groupType; }), types.end()); } void ODBRegView::saveState(QString const &settingsGroup) const { QSettings settings; settings.beginGroup(settingsGroup); settings.remove(SETTINGS_GROUPS_ARRAY_NODE); QStringList groupTypes; for (auto type : visibleGroupTypes) groupTypes << registerGroupTypeNames[type]; settings.setValue(SETTINGS_GROUPS_ARRAY_NODE, groupTypes); } void ODBRegView::setModel(RegisterViewModelBase::Model *model) { model_ = model; connect(model, SIGNAL(modelReset()), this, SLOT(modelReset())); connect(model, SIGNAL(dataChanged(QModelIndex const &, QModelIndex const &)), this, SLOT(modelUpdated())); modelReset(); } RegisterGroup *createSIMDGroup(RegisterViewModelBase::Model *model, QWidget *parent, QString const &catName, QString const ®NamePrefix) { const auto catIndex = findModelCategory(model, catName); if (!catIndex.isValid()) return nullptr; const auto group = new RegisterGroup(catName, parent); for (int row = 0; row < model->rowCount(catIndex); ++row) { const auto nameIndex = VALID_INDEX(model->index(row, MODEL_NAME_COLUMN, catIndex)); const auto name = regNamePrefix + QString("%1").arg(row); if (!VALID_VARIANT(nameIndex.data()).toString().toUpper().startsWith(regNamePrefix)) { if (row == 0) return nullptr; // don't want empty groups break; } group->insert(row, 0, new FieldWidget(name, group)); new SIMDValueManager(row, nameIndex, group); } // This signal must be handled by group _after_ all `SIMDValueManager`s handle their connection to this signal QObject::connect(model, SIGNAL(SIMDDisplayFormatChanged()), group, SLOT(adjustWidth()), Qt::QueuedConnection); return group; } RegisterGroup *ODBRegView::makeGroup(RegisterGroupType type) { if (!model_->rowCount()) return nullptr; std::vector nameValCommentIndices; using RegisterViewModelBase::Model; QString groupName; switch (type) { case RegisterGroupType::GPR: { groupName = tr("GPRs"); const auto catIndex = findModelCategory(model_, GPRCategoryName); if (!catIndex.isValid()) break; for (int row = 0; row < model_->rowCount(catIndex); ++row) nameValCommentIndices.emplace_back(model_->index(row, MODEL_NAME_COLUMN, catIndex)); break; } #if defined EDB_X86 || defined EDB_X86_64 case RegisterGroupType::EFL: return createEFL(model_, widget()); case RegisterGroupType::ExpandedEFL: return createExpandedEFL(model_, widget()); case RegisterGroupType::FPUData: return createFPUData(model_, widget()); case RegisterGroupType::FPUWords: return createFPUWords(model_, widget()); case RegisterGroupType::FPULastOp: return createFPULastOp(model_, widget()); case RegisterGroupType::Debug: return createDebugGroup(model_, widget()); case RegisterGroupType::MXCSR: return createMXCSR(model_, widget()); case RegisterGroupType::MMX: return createSIMDGroup(model_, widget(), "MMX", "MM"); case RegisterGroupType::SSEData: return createSIMDGroup(model_, widget(), "SSE", "XMM"); case RegisterGroupType::AVXData: return createSIMDGroup(model_, widget(), "AVX", "YMM"); case RegisterGroupType::Segment: { groupName = tr("Segment Registers"); const auto catIndex = findModelCategory(model_, "Segment"); if (!catIndex.isValid()) break; for (int row = 0; row < model_->rowCount(catIndex); ++row) nameValCommentIndices.emplace_back(model_->index(row, MODEL_NAME_COLUMN, catIndex)); break; } case RegisterGroupType::rIP: { groupName = tr("Instruction Pointer"); const auto catIndex = findModelCategory(model_, "General Status"); if (!catIndex.isValid()) break; nameValCommentIndices.emplace_back(findModelRegister(catIndex, "RIP")); nameValCommentIndices.emplace_back(findModelRegister(catIndex, "EIP")); break; } #elif defined EDB_ARM32 case RegisterGroupType::CPSR: return createCPSR(model_, widget()); case RegisterGroupType::ExpandedCPSR: return createExpandedCPSR(model_, widget()); case RegisterGroupType::FPSCR: return createFPSCR(model_, widget()); #endif default: qWarning() << "Warning: unexpected register group type requested in" << Q_FUNC_INFO; return nullptr; } nameValCommentIndices.erase(std::remove_if(nameValCommentIndices.begin(), nameValCommentIndices.end(), [](QModelIndex const &index) { return !index.isValid(); }), nameValCommentIndices.end()); if (nameValCommentIndices.empty()) { qWarning() << "Warning: failed to get any useful register indices for regGroupType" << static_cast(type); return nullptr; } const auto group = new RegisterGroup(groupName, widget()); for (const auto &index : nameValCommentIndices) { group->appendNameValueComment(index); } return group; } void ODBRegView::modelReset() { widget()->hide(); // prevent flicker while groups are added to/removed from the layout // not all groups may be in the layout, so delete them individually Q_FOREACH(const auto group, groups) { if (group) { group->deleteLater(); } } groups.clear(); const auto layout = static_cast(widget()->layout()); // layout contains not only groups, so delete all items too while (const auto item = layout->takeAt(0)) { delete item; } const auto flagsAndSegments = new QHBoxLayout(); // (3/2+1/2)-letter — Total of 2-letter spacing. Fourth half-letter is from flag values extension. // Segment extensions at LHS of the widget don't influence minimumSize request, so no need to take // them into account. flagsAndSegments->setSpacing(letterSize(this->font()).width() * 3 / 2); flagsAndSegments->setContentsMargins(QMargins()); flagsAndSegments->setAlignment(Qt::AlignLeft); bool flagsAndSegsInserted = false; for (int groupType_ = 0; groupType_ < RegisterGroupType::NUM_GROUPS; ++groupType_) { const auto groupType = RegisterGroupType{groupType_}; if (util::contains(visibleGroupTypes, groupType)) { const auto group = makeGroup(groupType); groups.push_back(group); if (!group) continue; #if defined EDB_X86 || defined EDB_X86_64 if (groupType == RegisterGroupType::Segment || groupType == RegisterGroupType::ExpandedEFL) { flagsAndSegments->addWidget(group); if (!flagsAndSegsInserted) { layout->addLayout(flagsAndSegments); flagsAndSegsInserted = true; } } else #endif layout->addWidget(group); } else groups.push_back(nullptr); } widget()->show(); } void ODBRegView::modelUpdated() { Q_FOREACH(const auto field, fields()) { field->adjustToData(); } Q_FOREACH(const auto group, groups) { if (group) { group->adjustWidth(); } } } QList ODBRegView::fields() const { QList allFields; for (const auto group : groups) { if (group) { allFields.append(group->fields()); } } return allFields; } QList ODBRegView::valueFields() const { QList allValues; for (const auto group : groups) { if (group) { allValues.append(group->valueFields()); } } return allValues; } void ODBRegView::updateFieldsPalette() { Q_FOREACH(const auto field, valueFields()) field->updatePalette(); } ValueField *ODBRegView::selectedField() const { Q_FOREACH(const auto field, valueFields()) { if (field->isSelected()) { return field; } } return nullptr; } SIMDValueManager::SIMDValueManager(int lineInGroup, QModelIndex const &nameIndex, RegisterGroup *parent) : QObject(parent), regIndex(nameIndex), lineInGroup(lineInGroup), intMode(NumberDisplayMode::Hex) { setupMenu(); assert(nameIndex.isValid()); connect(nameIndex.model(), SIGNAL(SIMDDisplayFormatChanged()), this, SLOT(displayFormatChanged())); displayFormatChanged(); } void SIMDValueManager::fillGroupMenu() { const auto group = this->group(); group->menuItems.push_back(newActionSeparator(this)); group->menuItems.push_back(menuItems[VIEW_AS_BYTES]); group->menuItems.push_back(menuItems[VIEW_AS_WORDS]); group->menuItems.push_back(menuItems[VIEW_AS_DWORDS]); group->menuItems.push_back(menuItems[VIEW_AS_QWORDS]); group->menuItems.push_back(newActionSeparator(this)); group->menuItems.push_back(menuItems[VIEW_AS_FLOAT32]); group->menuItems.push_back(menuItems[VIEW_AS_FLOAT64]); group->menuItems.push_back(newActionSeparator(this)); group->menuItems.push_back(menuItems[VIEW_INT_AS_HEX]); group->menuItems.push_back(menuItems[VIEW_INT_AS_SIGNED]); group->menuItems.push_back(menuItems[VIEW_INT_AS_UNSIGNED]); } auto SIMDValueManager::model() const -> Model * { const auto model = static_cast(regIndex.model()); // The model is not supposed to have been created as const object, // and our manipulations won't invalidate the index. // Thus cast the const away. return const_cast(model); } void SIMDValueManager::showAsInt(int const size_) { const auto size = static_cast(size_); model()->setChosenSIMDSize(regIndex.parent(), size); model()->setChosenSIMDFormat(regIndex.parent(), intMode); } void SIMDValueManager::showAsFloat(int const size) { model()->setChosenSIMDFormat(regIndex.parent(), NumberDisplayMode::Float); switch (size) { case sizeof(edb::value32): model()->setChosenSIMDSize(regIndex.parent(), Model::ElementSize::DWORD); break; case sizeof(edb::value64): model()->setChosenSIMDSize(regIndex.parent(), Model::ElementSize::QWORD); break; default: EDB_PRINT_AND_DIE("Unexpected size: ", size); } } void SIMDValueManager::setIntFormat(int format_) { const auto format = static_cast(format_); model()->setChosenSIMDFormat(regIndex.parent(), format); } void SIMDValueManager::setupMenu() { const auto group = this->group(); const auto validFormats = VALID_VARIANT(regIndex.parent().data(Model::ValidSIMDFormatsRole)).value>(); // Setup menu if we're the first value field creator if (group->valueFields().isEmpty()) { const auto intSizeMapper = new QSignalMapper(this); connect(intSizeMapper, SIGNAL(mapped(int)), this, SLOT(showAsInt(int))); menuItems.push_back(newAction(tr("View %1 as bytes").arg(group->name), group, intSizeMapper, Model::ElementSize::BYTE)); menuItems.push_back(newAction(tr("View %1 as words").arg(group->name), group, intSizeMapper, Model::ElementSize::WORD)); menuItems.push_back(newAction(tr("View %1 as doublewords").arg(group->name), group, intSizeMapper, Model::ElementSize::DWORD)); menuItems.push_back(newAction(tr("View %1 as quadwords").arg(group->name), group, intSizeMapper, Model::ElementSize::QWORD)); if (util::contains(validFormats, NumberDisplayMode::Float)) { const auto floatMapper = new QSignalMapper(this); connect(floatMapper, SIGNAL(mapped(int)), this, SLOT(showAsFloat(int))); menuItems.push_back(newAction(tr("View %1 as 32-bit floats").arg(group->name), group, floatMapper, Model::ElementSize::DWORD)); menuItems.push_back(newAction(tr("View %1 as 64-bit floats").arg(group->name), group, floatMapper, Model::ElementSize::QWORD)); } else { // create empty elements to leave further items with correct indices menuItems.push_back(newActionSeparator(this)); menuItems.push_back(newActionSeparator(this)); } const auto intMapper = new QSignalMapper(this); connect(intMapper, SIGNAL(mapped(int)), this, SLOT(setIntFormat(int))); menuItems.push_back(newAction(tr("View %1 integers as hex").arg(group->name), group, intMapper, static_cast(NumberDisplayMode::Hex))); menuItems.push_back(newAction(tr("View %1 integers as signed").arg(group->name), group, intMapper, static_cast(NumberDisplayMode::Signed))); menuItems.push_back(newAction(tr("View %1 integers as unsigned").arg(group->name), group, intMapper, static_cast(NumberDisplayMode::Unsigned))); fillGroupMenu(); } } void SIMDValueManager::updateMenu() { if (menuItems.isEmpty()) return; Q_FOREACH(auto item, menuItems) item->setVisible(true); using RegisterViewModelBase::Model; switch (currentSize()) { case Model::ElementSize::BYTE: menuItems[VIEW_AS_BYTES]->setVisible(false); break; case Model::ElementSize::WORD: menuItems[VIEW_AS_WORDS]->setVisible(false); break; case Model::ElementSize::DWORD: if (currentFormat() != NumberDisplayMode::Float) menuItems[VIEW_AS_DWORDS]->setVisible(false); else menuItems[VIEW_AS_FLOAT32]->setVisible(false); break; case Model::ElementSize::QWORD: if (currentFormat() != NumberDisplayMode::Float) menuItems[VIEW_AS_QWORDS]->setVisible(false); else menuItems[VIEW_AS_FLOAT64]->setVisible(false); break; default: EDB_PRINT_AND_DIE("Unexpected current size: ", currentSize()); } switch (currentFormat()) { case NumberDisplayMode::Float: menuItems[VIEW_INT_AS_HEX]->setVisible(false); menuItems[VIEW_INT_AS_SIGNED]->setVisible(false); menuItems[VIEW_INT_AS_UNSIGNED]->setVisible(false); break; case NumberDisplayMode::Hex: menuItems[VIEW_INT_AS_HEX]->setVisible(false); break; case NumberDisplayMode::Signed: menuItems[VIEW_INT_AS_SIGNED]->setVisible(false); break; case NumberDisplayMode::Unsigned: menuItems[VIEW_INT_AS_UNSIGNED]->setVisible(false); break; } } RegisterGroup *SIMDValueManager::group() const { return checked_cast(parent()); } void SIMDValueManager::displayFormatChanged() { const auto newFormat = currentFormat(); if (newFormat != NumberDisplayMode::Float) { intMode = newFormat; } Q_FOREACH(const auto elem, elements) { elem->deleteLater(); } elements.clear(); using RegisterViewModelBase::Model; const auto model = regIndex.model(); const int sizeRow = VALID_VARIANT(regIndex.parent().data(Model::ChosenSIMDSizeRowRole)).toInt(); QModelIndex sizeIndex = model->index(sizeRow, MODEL_NAME_COLUMN, regIndex); const auto elemCount = model->rowCount(sizeIndex); const auto regNameWidth = VALID_VARIANT(regIndex.data(Model::FixedLengthRole)).toInt(); int column = regNameWidth + 1; const auto elemWidth = VALID_VARIANT(model->index(0, MODEL_VALUE_COLUMN, sizeIndex).data(Model::FixedLengthRole)).toInt(); for (int elemN = elemCount - 1; elemN >= 0; --elemN) { const auto elemIndex = model->index(elemN, MODEL_VALUE_COLUMN, sizeIndex); const auto field = new ValueField(elemWidth, elemIndex, group()); elements.push_back(field); field->setAlignment(Qt::AlignRight); group()->insert(lineInGroup, column, field); column += elemWidth + 1; } updateMenu(); } RegisterViewModelBase::Model::ElementSize SIMDValueManager::currentSize() const { using RegisterViewModelBase::Model; const int size = VALID_VARIANT(regIndex.parent().data(Model::ChosenSIMDSizeRole)).toInt(); return static_cast(size); } NumberDisplayMode SIMDValueManager::currentFormat() const { using RegisterViewModelBase::Model; const int size = VALID_VARIANT(regIndex.parent().data(Model::ChosenSIMDFormatRole)).toInt(); return static_cast(size); } void ODBRegView::selectAField() { const auto fields = valueFields(); if (!fields.isEmpty()) { fields.front()->select(); } } void ODBRegView::keyPressEvent(QKeyEvent *event) { const auto selected = selectedField(); switch (event->key()) { case Qt::Key_Up: if (selected && selected->up()) { selected->up()->select(); return; } if (!selected) selectAField(); break; case Qt::Key_Down: if (selected && selected->down()) { selected->down()->select(); return; } if (!selected) selectAField(); break; case Qt::Key_Left: if (selected && selected->left()) { selected->left()->select(); return; } if (!selected) selectAField(); break; case Qt::Key_Right: if (selected && selected->right()) { selected->right()->select(); return; } if (!selected) selectAField(); break; case Qt::Key_Enter: case Qt::Key_Return: if (selected) { selected->defaultAction(); return; } break; case Qt::Key_Menu: if (selected) selected->showMenu(selected->mapToGlobal(selected->rect().bottomLeft())); else showMenu(mapToGlobal(QPoint())); break; case setToZeroKey: if (selected) { selected->setZero(); return; } break; case incrementKey: if (selected) { selected->increment(); return; } break; case decrementKey: if (selected) { selected->decrement(); return; } break; } QScrollArea::keyPressEvent(event); } } edb-debugger-1.0.0/plugins/ODbgRegisterView/armGroups.cpp0000644000175000017500000003521413273160654022675 0ustar eteraneteran/* Copyright (C) 2017 Ruslan Kabatsayev 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, see . */ #include "armGroups.h" #include "ODbgRV_Util.h" #include #include namespace ODbgRegisterView { namespace { const BitFieldDescription itBaseCondDescription = { 2, { "EQ", "HS", "MI", "VS", "HI", "GE", "GT", "AL" }, { QObject::tr("Set EQ"), QObject::tr("Set HS"), QObject::tr("Set MI"), QObject::tr("Set VS"), QObject::tr("Set HI"), QObject::tr("Set GE"), QObject::tr("Set GT"), QObject::tr("Set AL") } }; const BitFieldDescription fpscrSTRDescription = { 3, { " 1 ", "D=1", "D=2", " 2 " }, { QObject::tr("Set stride to 1"), "", "", QObject::tr("Set stride to 2") } }; const BitFieldDescription fpscrLENDescription = { 1, { // FPSCR[18:16] = LEN-1, while we want to show LEN value itself "1", "2", "3", "4", "5", "6", "7", "8" }, { // FIXME: this is ugly. Maybe edit it as a number? QObject::tr("Set LEN to 1"), QObject::tr("Set LEN to 2"), QObject::tr("Set LEN to 3"), QObject::tr("Set LEN to 4"), QObject::tr("Set LEN to 5"), QObject::tr("Set LEN to 6"), QObject::tr("Set LEN to 7"), QObject::tr("Set LEN to 8") } }; const BitFieldDescription roundControlDescription = { 4, { "NEAR", "DOWN", " UP", "ZERO" }, { QObject::tr("Round to nearest"), QObject::tr("Round down"), QObject::tr("Round up"), QObject::tr("Round toward zero") } }; } RegisterGroup *createCPSR(RegisterViewModelBase::Model *model, QWidget *parent) { const auto catIndex = findModelCategory(model, "General Status"); if (!catIndex.isValid()) return nullptr; auto nameIndex = findModelRegister(catIndex, "CPSR"); if (!nameIndex.isValid()) return nullptr; const auto group = new RegisterGroup("CPS", parent); const int nameWidth = 3; int column = 0; group->insert(0, column, new FieldWidget("CPS", group)); const auto valueWidth = 8; const auto valueIndex = nameIndex.sibling(nameIndex.row(), MODEL_VALUE_COLUMN); column += nameWidth + 1; group->insert(0, column, new ValueField(valueWidth, valueIndex, group, [](QString const &v) { return v.right(8); })); const auto commentIndex = nameIndex.sibling(nameIndex.row(), MODEL_COMMENT_COLUMN); column += valueWidth + 1; group->insert(0, column, new FieldWidget(0, commentIndex, group)); return group; } RegisterGroup *createExpandedCPSR(RegisterViewModelBase::Model *model, QWidget *parent) { using namespace RegisterViewModelBase; const auto catIndex = findModelCategory(model, "General Status"); if (!catIndex.isValid()) return nullptr; auto regNameIndex = findModelRegister(catIndex, "CPSR"); if (!regNameIndex.isValid()) return nullptr; const auto group = new RegisterGroup(QObject::tr("Expanded CPSR"), parent); static const std::unordered_map flagTooltips = { {'N', QObject::tr("Negative result flag")}, {'Z', QObject::tr("Zero result flag")}, {'C', QObject::tr("Carry flag")}, {'V', QObject::tr("Overflow flag")}, {'Q', QObject::tr("Sticky saturation/overflow flag")}, {'J', QObject::tr("Jazelle state flag")}, {'E', QObject::tr("Big endian state flag")}, {'T', QObject::tr("Thumb state flag")}, }; // NOTE: NZCV is intended to align with corresponding name/value fields in FPSCR for (int row = 0, groupCol = 28; row < model->rowCount(regNameIndex); ++row) { const auto flagNameIndex = model->index(row, MODEL_NAME_COLUMN, regNameIndex); const auto flagValueIndex = model->index(row, MODEL_VALUE_COLUMN, regNameIndex); const auto flagName = model->data(flagNameIndex).toString().toUpper(); if (flagName.length() != 1) continue; static const int flagNameWidth = 1; static const int valueWidth = 1; const char name = flagName[0].toLatin1(); switch (name) { case 'N': case 'Z': case 'C': case 'V': case 'Q': case 'J': case 'E': case 'T': { const auto nameField = new FieldWidget(QChar(name), group); group->insert(0, groupCol, nameField); const auto valueField = new ValueField(valueWidth, flagValueIndex, group); group->insert(1, groupCol, valueField); groupCol-=2; const auto tooltipStr = flagTooltips.at(name); nameField->setToolTip(tooltipStr); valueField->setToolTip(tooltipStr); break; } default: continue; } } { const auto geNameField = new FieldWidget(QLatin1String("GE"), group); geNameField->setToolTip(QObject::tr("Greater than or Equal flags")); group->insert(1, 0, geNameField); for(int geIndex=3; geIndex>-1; --geIndex) { const int groupCol=5+2*(3-geIndex); const auto tooltipStr=QString("GE%1").arg(geIndex); { const auto nameField = new FieldWidget(QString::number(geIndex), group); group->insert(0, groupCol, nameField); nameField->setToolTip(tooltipStr); } const auto indexInModel=findModelRegister(regNameIndex, QString("GE%1").arg(geIndex)); if(!indexInModel.isValid()) continue; const auto valueIndex=indexInModel.sibling(indexInModel.row(), MODEL_VALUE_COLUMN); if(!valueIndex.isValid()) continue; const auto valueField = new ValueField(1, valueIndex, group); group->insert(1, groupCol, valueField); valueField->setToolTip(tooltipStr); } } { int column=0; enum { labelRow=2, valueRow }; { const auto itNameField = new FieldWidget(QLatin1String("IT"), group); itNameField->setToolTip(QObject::tr("If-Then block state")); group->insert(valueRow, column, itNameField); column+=3; } { // Using textual names for instructions numbering to avoid confusion between base-0 and base-1 counting static const QString tooltips[]= { QObject::tr("Lowest bit of IT-block condition for first instruction"), QObject::tr("Lowest bit of IT-block condition for second instruction"), QObject::tr("Lowest bit of IT-block condition for third instruction"), QObject::tr("Lowest bit of IT-block condition for fourth instruction"), QObject::tr("Flag marking active four-instruction IT-block"), }; for(int i=4; i>=0; --i, column+=2) { const auto nameIndex=findModelRegister(regNameIndex, QString("IT%1").arg(i)); const auto valueIndex=nameIndex.sibling(nameIndex.row(), MODEL_VALUE_COLUMN); if(!valueIndex.isValid()) continue; const auto valueField=new ValueField(1, valueIndex, group); group->insert(valueRow, column, valueField); const auto tooltip = tooltips[4-i]; valueField->setToolTip(tooltip); const auto nameField=new FieldWidget(QString::number(i), group); group->insert(labelRow, column, nameField); nameField->setToolTip(tooltip); } } { const auto itBaseCondNameIndex=findModelRegister(regNameIndex, QString("ITbcond").toUpper()); const auto itBaseCondValueIndex=itBaseCondNameIndex.sibling(itBaseCondNameIndex.row(), MODEL_VALUE_COLUMN); if(itBaseCondValueIndex.isValid()) { const auto itBaseCondField=new MultiBitFieldWidget(itBaseCondValueIndex, itBaseCondDescription, group); group->insert(valueRow, column, itBaseCondField); const auto tooltip=QObject::tr("IT base condition"); itBaseCondField->setToolTip(tooltip); const auto labelField=new FieldWidget("BC", group); group->insert(labelRow, column, labelField); labelField->setToolTip(tooltip); } else qWarning() << "Failed to find IT base condition index in the model"; column+=3; } } return group; } void addDXUOZI(RegisterGroup *const group, QModelIndex const &fpscrIndex, int const startRow, int const startColumn) { static const QString exceptions = "DXUOZI"; static const std::unordered_map> excNames = { {'D', {"ID", QObject::tr("Input Denormal")}}, {'X', {"IX", QObject::tr("Inexact")}}, {'U', {"UF", QObject::tr("Underflow")}}, {'O', {"OF", QObject::tr("Overflow")}}, {'Z', {"DZ", QObject::tr("Zero Divide")}}, {'I', {"IO", QObject::tr("Invalid Operation")}} }; for (int exN = 0; exN < exceptions.length(); ++exN) { const QString ex = exceptions[exN]; const auto excAbbrevStart = excNames.at(ex[0].toLatin1()).first; const auto exAbbrev = excAbbrevStart + "C"; const auto enabAbbrev = excAbbrevStart + "E"; const auto excIndex = VALID_INDEX(findModelRegister(fpscrIndex, exAbbrev)); const auto enabIndex = VALID_INDEX(findModelRegister(fpscrIndex, enabAbbrev)); const int column = startColumn + exN * 2; const auto nameField = new FieldWidget(ex, group); group->insert(startRow, column, nameField); const auto excValueField = new ValueField(1, getValueIndex(excIndex), group); group->insert(startRow + 1, column, excValueField); const auto enabValueField = new ValueField(1, getValueIndex(enabIndex), group); group->insert(startRow + 2, column, enabValueField); const auto excName = excNames.at(ex[0].toLatin1()).second; nameField->setToolTip(excName); excValueField->setToolTip(excName + ' ' + QObject::tr("Exception flag") + " (" + exAbbrev + ")"); enabValueField->setToolTip(excName + ' ' + QObject::tr("Exception Enable flag") + " (" + enabAbbrev + ")"); } } RegisterGroup *createFPSCR(RegisterViewModelBase::Model *model, QWidget *parent) { using namespace RegisterViewModelBase; const auto catIndex = findModelCategory(model, "VFP"); if (!catIndex.isValid()) return nullptr; const auto group = new RegisterGroup("FSC", parent); const QString fpscrName = "FSC"; const int fpscrRow = 0, nzcvLabelRow = fpscrRow; const int nzcvRow = fpscrRow, nzcvValueRow = nzcvRow + 1; int column = 0; const auto fpscrLabelField = new FieldWidget(fpscrName, group); fpscrLabelField->setToolTip(QObject::tr("Floating-point status and control register")+" (FPSCR)"); group->insert(fpscrRow, column, fpscrLabelField); column += fpscrName.length() + 1; const auto fpscrIndex = findModelRegister(catIndex, "FPSCR", MODEL_VALUE_COLUMN); const auto fpscrValueWidth = fpscrIndex.data(Model::FixedLengthRole).toInt(); assert(fpscrValueWidth > 0); group->insert(fpscrRow, column, new ValueField(fpscrValueWidth, fpscrIndex, group)); column += fpscrValueWidth + 2; { static const std::unordered_map nzcvDescriptions = { {'N', QObject::tr("LessThan flag")}, {'Z', QObject::tr("Equal operands flag")}, {'C', QObject::tr("GreaterThen/Equal/Unordered operands flag")}, {'V', QObject::tr("Unordered operands flag")} }; static const QString nzcv="NZCV"; for (int i = 0; i < nzcv.length(); ++i) { const auto flag = nzcv[i]; const auto flagIndex = VALID_INDEX(findModelRegister(fpscrIndex, flag, MODEL_VALUE_COLUMN)); const auto nameField = new FieldWidget(flag, group); group->insert(nzcvRow, column, nameField); const auto flagValueField = new ValueField(1, getValueIndex(flagIndex), group); group->insert(nzcvValueRow, column, flagValueField); const auto descr = nzcvDescriptions.at(flag.toLatin1()); nameField->setToolTip(descr); flagValueField->setToolTip(descr); column += 2; } } column += 1; const auto excRow = fpscrRow + 1, enabRow = excRow + 1; group->insert(excRow , column, new FieldWidget("Err", group)); group->insert(enabRow, column, new FieldWidget("Enab", group)); column += 5; addDXUOZI(group, fpscrIndex, fpscrRow, column); { const int DXUOZIWidth = 6 * 2 - 1; group->insert(nzcvValueRow, column + DXUOZIWidth + 1, new FieldWidget(0, getCommentIndex(fpscrIndex), group)); } const QString dnName = "DN", fzName = "FZ", strName = "STR", lenName = "LEN"; { column = fpscrName.length() - 1; const auto strNameField = new FieldWidget(strName, group); const auto strRow = excRow; group->insert(strRow, column, strNameField); const auto strIndex = findModelRegister(fpscrIndex, "STR", MODEL_VALUE_COLUMN); const auto strValueField = new MultiBitFieldWidget(strIndex, fpscrSTRDescription, group); column += strName.length(); group->insert(strRow, column, strValueField); const auto strTooltip = QObject::tr("Stride (distance between successive values in a vector)"); strNameField->setToolTip(strTooltip); strValueField->setToolTip(strTooltip); column += 3; } { const auto fzNameField = new FieldWidget(fzName, group); const auto fzRow = excRow; group->insert(fzRow, column, fzNameField); const auto fzIndex = findModelRegister(fpscrIndex, "FZ", MODEL_VALUE_COLUMN); const auto fzValueWidth = 1; const auto fzValueField = new ValueField(fzValueWidth, fzIndex, group); column += fzName.length() + 1; group->insert(fzRow, column, fzValueField); const auto fzTooltip = QObject::tr("Flush Denormals To Zero"); fzNameField->setToolTip(fzTooltip); fzValueField->setToolTip(fzTooltip); } { column = fpscrName.length() - 1; const auto lenNameField = new FieldWidget(lenName, group); const auto lenRow = enabRow; group->insert(lenRow, column, lenNameField); const auto lenIndex = findModelRegister(fpscrIndex, "LEN-1", MODEL_VALUE_COLUMN); const auto lenValueField = new MultiBitFieldWidget(lenIndex, fpscrLENDescription, group); column += lenName.length() + 1; group->insert(lenRow, column, lenValueField); const auto lenTooltip = QObject::tr("Number of registers used by each vector"); lenNameField->setToolTip(lenTooltip); lenValueField->setToolTip(lenTooltip); column += 2; } { const auto dnNameField = new FieldWidget(dnName, group); const auto dnRow = enabRow; group->insert(dnRow, column, dnNameField); const auto dnIndex = findModelRegister(fpscrIndex, "DN", MODEL_VALUE_COLUMN); const auto dnValueWidth = 1; const auto dnValueField = new ValueField(dnValueWidth, dnIndex, group); column += dnName.length() + 1; group->insert(dnRow, column, dnValueField); const auto dnTooltip = QObject::tr("Enable default NaN mode"); dnNameField->setToolTip(dnTooltip); dnValueField->setToolTip(dnTooltip); column += 2; } { column += 1; const QString rndName = "Rnd"; const auto rndRow = enabRow; group->insert(rndRow, column, new FieldWidget(rndName, group)); column += rndName.length() + 1; const auto rndValueField = new MultiBitFieldWidget( findModelRegister(fpscrIndex, "RC", MODEL_VALUE_COLUMN), roundControlDescription, group); group->insert(rndRow, column, rndValueField); rndValueField->setToolTip(QObject::tr("Rounding mode")); } return group; } } edb-debugger-1.0.0/plugins/ODbgRegisterView/ValueField.cpp0000644000175000017500000003272213273160654022737 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "ValueField.h" #include "ODbgRV_Common.h" #include "ODbgRV_Util.h" #if defined EDB_X86 || defined EDB_X86_64 # include "ODbgRV_x86Common.h" # include "DialogEditFPU.h" #endif #include "DialogEditGPR.h" #include "DialogEditSIMDRegister.h" #include #include #include #include #include #include #include namespace ODbgRegisterView { QStyle *flatStyle = nullptr; ValueField::ValueField(int const fieldWidth, QModelIndex const &index, QWidget *const parent, std::function const &valueFormatter) : FieldWidget(fieldWidth, index, parent), valueFormatter(valueFormatter) { setObjectName("ValueField"); setDisabled(false); setMouseTracking(true); // Set some known style to avoid e.g. Oxygen's label transition animations, which // break updating of colors such as "register changed" when single-stepping frequently #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #define FLAT_STYLE_NAME "fusion" #else #define FLAT_STYLE_NAME "plastique" #endif if (!flatStyle) flatStyle = QStyleFactory::create(FLAT_STYLE_NAME); assert(flatStyle); setStyle(flatStyle); using namespace RegisterViewModelBase; if (index.data(Model::IsNormalRegisterRole).toBool() || index.data(Model::IsSIMDElementRole).toBool()) { menuItems.push_back(newAction(trUtf8("&Modify…"), this, this, SLOT(defaultAction()))); menuItems.back()->setShortcut(QKeySequence(Qt::Key_Enter)); } else if (index.data(Model::IsBitFieldRole).toBool() && index.data(Model::BitFieldLengthRole).toInt() == 1) { menuItems.push_back(newAction(tr("&Toggle"), this, this, SLOT(defaultAction()))); menuItems.back()->setShortcut(QKeySequence(Qt::Key_Enter)); } menuItems.push_back(newAction(tr("&Copy to clipboard"), this, this, SLOT(copyToClipboard()))); menuItems.back()->setShortcut(copyFieldShortcut); #if defined EDB_X86 || defined EDB_X86_64 if (index.sibling(index.row(), MODEL_NAME_COLUMN).data().toString() == FSR_NAME) { menuItems.push_back(newAction(tr("P&ush FPU stack"), this, this, SLOT(pushFPUStack()))); menuItems.push_back(newAction(tr("P&op FPU stack"), this, this, SLOT(popFPUStack()))); } #endif if (index.parent().data().toString() == GPRCategoryName) { // These should be above others, so prepending instead of appending menuItems.push_front(newAction(tr("In&vert"), this, this, SLOT(invert()))); menuItems.push_front(setToOneAction = newAction(tr("Set to &1"), this, this, SLOT(setToOne()))); menuItems.push_front(setToZeroAction = newAction(tr("&Zero"), this, this, SLOT(setZero()))); menuItems.front()->setShortcut(QKeySequence(setToZeroKey)); menuItems.push_front(newAction(tr("&Decrement"), this, this, SLOT(decrement()))); menuItems.front()->setShortcut(QKeySequence(decrementKey)); menuItems.push_front(newAction(tr("&Increment"), this, this, SLOT(increment()))); menuItems.front()->setShortcut(QKeySequence(incrementKey)); } } RegisterViewModelBase::Model *ValueField::model() const { using namespace RegisterViewModelBase; const auto model = static_cast(index.model()); // The model is not supposed to have been created as const object, // and our manipulations won't invalidate the index. // Thus cast the const away. return const_cast(model); } ValueField *ValueField::bestNeighbor(std::function const &firstIsBetter) const { ValueField *result = nullptr; Q_FOREACH(const auto neighbor, regView()->valueFields()) { if (neighbor->isVisible() && firstIsBetter(fieldPos(neighbor), result, fieldPos(this))) result = neighbor; } return result; } ValueField *ValueField::up() const { return bestNeighbor([](QPoint const &nPos, ValueField const *up, QPoint const &fPos) { return nPos.y() < fPos.y() && (!up || distSqr(nPos, fPos) < distSqr(fieldPos(up), fPos)); } ); } ValueField *ValueField::down() const { return bestNeighbor([](QPoint const &nPos, ValueField const *down, QPoint const &fPos) { return nPos.y() > fPos.y() && (!down || distSqr(nPos, fPos) < distSqr(fieldPos(down), fPos)); } ); } ValueField *ValueField::left() const { return bestNeighbor([](QPoint const &nPos, ValueField const *left, QPoint const &fPos) { return nPos.y() == fPos.y() && nPos.x() < fPos.x() && (!left || left->x() < nPos.x()); } ); } ValueField *ValueField::right() const { return bestNeighbor([](QPoint const &nPos, ValueField const *right, QPoint const &fPos) { return nPos.y() == fPos.y() && nPos.x() > fPos.x() && (!right || right->x() > nPos.x()); } ); } QString ValueField::text() const { return valueFormatter(FieldWidget::text()); } bool ValueField::changed() const { if (!index.isValid()) return true; return VALID_VARIANT(index.data(RegisterViewModelBase::Model::RegisterChangedRole)).toBool(); } QColor ValueField::fgColorForChangedField() const { return Qt::red; // TODO: read from user palette } bool ValueField::isSelected() const { return selected_; } void ValueField::editNormalReg(QModelIndex const &indexToEdit, QModelIndex const &clickedIndex) const { using namespace RegisterViewModelBase; const auto rV = model()->data(indexToEdit, Model::ValueAsRegisterRole); if (!rV.isValid()) return; auto r = rV.value(); if (!r) return; if ((r.type() != Register::TYPE_SIMD) && r.bitSize() <= 64) { const auto gprEdit = regView()->gprEditDialog(); gprEdit->set_value(r); if (gprEdit->exec() == QDialog::Accepted) { r = gprEdit->value(); model()->setData(indexToEdit, QVariant::fromValue(r), Model::ValueAsRegisterRole); } } else if (r.type() == Register::TYPE_SIMD) { const auto simdEdit = regView()->simdEditDialog(); simdEdit->set_value(r); const int size = VALID_VARIANT(indexToEdit.parent().data(Model::ChosenSIMDSizeRole)).toInt(); const int format = VALID_VARIANT(indexToEdit.parent().data(Model::ChosenSIMDFormatRole)).toInt(); const int elementIndex = clickedIndex.row(); simdEdit->set_current_element(static_cast(size), static_cast(format), elementIndex); if (simdEdit->exec() == QDialog::Accepted) { r = simdEdit->value(); model()->setData(indexToEdit, QVariant::fromValue(r), Model::ValueAsRegisterRole); } } #if defined EDB_X86 || defined EDB_X86_64 else if (r.type() == Register::TYPE_FPU) { const auto fpuEdit = regView()->fpuEditDialog(); fpuEdit->set_value(r); if (fpuEdit->exec() == QDialog::Accepted) { r = fpuEdit->value(); model()->setData(indexToEdit, QVariant::fromValue(r), Model::ValueAsRegisterRole); } } #endif } QModelIndex ValueField::regIndex() const { using namespace RegisterViewModelBase; if (index.data(Model::IsBitFieldRole).toBool()) return index; if (index.data(Model::IsNormalRegisterRole).toBool()) return index.sibling(index.row(), MODEL_NAME_COLUMN); return {}; } void ValueField::defaultAction() { using namespace RegisterViewModelBase; if (index.data(Model::IsBitFieldRole).toBool() && index.data(Model::BitFieldLengthRole).toInt() == 1) { // toggle // TODO: Model: make it possible to set bit field itself, without manipulating parent directly // I.e. set value without knowing field offset, then setData(fieldIndex,word) const auto regIndex = index.parent().sibling(index.parent().row(), MODEL_VALUE_COLUMN); auto byteArr = regIndex.data(Model::RawValueRole).toByteArray(); if (byteArr.isEmpty()) return; std::uint64_t word(0); std::memcpy(&word, byteArr.constData(), byteArr.size()); const auto offset = VALID_VARIANT(index.data(Model::BitFieldOffsetRole)).toInt(); word ^= 1ull << offset; std::memcpy(byteArr.data(), &word, byteArr.size()); model()->setData(regIndex, byteArr, Model::RawValueRole); } else if (index.data(Model::IsNormalRegisterRole).toBool()) editNormalReg(index, index); else if (index.data(Model::IsSIMDElementRole).toBool()) editNormalReg(index.parent().parent(), index); else if (index.parent().data(Model::IsFPURegisterRole).toBool()) editNormalReg(index.parent(), index); } void ValueField::adjustToData() { if (index.parent().data().toString() == GPRCategoryName) { using RegisterViewModelBase::Model; auto byteArr = index.data(Model::RawValueRole).toByteArray(); if (byteArr.isEmpty()) return; std::uint64_t value(0); assert(byteArr.size() <= int(sizeof value)); std::memcpy(&value, byteArr.constData(), byteArr.size()); setToOneAction->setVisible(value != 1u); setToZeroAction->setVisible(value != 0u); } FieldWidget::adjustToData(); updatePalette(); } void ValueField::updatePalette() { if (changed()) { auto palette = this->palette(); const QColor changedFGColor = fgColorForChangedField(); palette.setColor(foregroundRole(), changedFGColor); palette.setColor(QPalette::HighlightedText, changedFGColor); setPalette(palette); } else setPalette(QApplication::palette()); QLabel::update(); } void ValueField::enterEvent(QEvent *) { hovered_ = true; updatePalette(); } void ValueField::leaveEvent(QEvent *) { hovered_ = false; updatePalette(); } void ValueField::select() { if (selected_) return; selected_ = true; model()->setActiveIndex(regIndex()); Q_EMIT selected(); updatePalette(); } void ValueField::showMenu(QPoint const &position) { group()->showMenu(position, menuItems); } void ValueField::mousePressEvent(QMouseEvent *event) { if (event->button() & (Qt::LeftButton | Qt::RightButton)) select(); if (event->button() == Qt::RightButton && event->type() != QEvent::MouseButtonDblClick) showMenu(event->globalPos()); } void ValueField::unselect() { if (!selected_) return; selected_ = false; updatePalette(); } void ValueField::mouseDoubleClickEvent(QMouseEvent *event) { mousePressEvent(event); defaultAction(); } void ValueField::paintEvent(QPaintEvent *) { const auto regView = this->regView(); QPainter painter(this); #if QT_VERSION >= 0x050000 QStyleOptionViewItem option; #else QStyleOptionViewItemV4 option; #endif option.rect = rect(); option.showDecorationSelected = true; option.text = text(); option.font = font(); option.palette = palette(); option.textElideMode = Qt::ElideNone; option.state |= QStyle::State_Enabled; option.displayAlignment = alignment(); if (selected_) option.state |= QStyle::State_Selected; if (hovered_) option.state |= QStyle::State_MouseOver; if (regView->hasFocus()) option.state |= QStyle::State_Active; QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &option, &painter); } namespace { void addToTOP(RegisterViewModelBase::Model *model, QModelIndex const &fsrIndex, std::int16_t delta) { using namespace RegisterViewModelBase; // TODO: Model: make it possible to set bit field itself, without manipulating parent directly // I.e. set value without knowing field offset, then setData(fieldIndex,word) auto byteArr = fsrIndex.data(Model::RawValueRole).toByteArray(); if (byteArr.isEmpty()) return; std::uint16_t word(0); assert(byteArr.size() == sizeof word); std::memcpy(&word, byteArr.constData(), byteArr.size()); const auto value = (word >> 11) & 7; word = (word & ~0x3800) | (((value + delta) & 7) << 11); std::memcpy(byteArr.data(), &word, byteArr.size()); model->setData(fsrIndex, byteArr, Model::RawValueRole); } } #if defined EDB_X86 || defined EDB_X86_64 void ValueField::pushFPUStack() { assert(index.sibling(index.row(), MODEL_NAME_COLUMN).data().toString() == FSR_NAME); addToTOP(model(), index, -1); } void ValueField::popFPUStack() { assert(index.sibling(index.row(), MODEL_NAME_COLUMN).data().toString() == FSR_NAME); addToTOP(model(), index, +1); } #endif void ValueField::copyToClipboard() const { QApplication::clipboard()->setText(text()); } namespace { template void changeGPR(QModelIndex const &index, RegisterViewModelBase::Model *const model, Op const &change) { if (index.parent().data().toString() != GPRCategoryName) return; using RegisterViewModelBase::Model; auto byteArr = index.data(Model::RawValueRole).toByteArray(); if (byteArr.isEmpty()) return; std::uint64_t value(0); assert(byteArr.size() <= int(sizeof value)); std::memcpy(&value, byteArr.constData(), byteArr.size()); value = change(value); std::memcpy(byteArr.data(), &value, byteArr.size()); model->setData(index, byteArr, Model::RawValueRole); } } void ValueField::decrement() { changeGPR(index, model(), [](std::uint64_t v) { return v - 1; }); } void ValueField::increment() { changeGPR(index, model(), [](std::uint64_t v) { return v + 1; }); } void ValueField::invert() { changeGPR(index, model(), [](std::uint64_t v) { return ~v; }); } void ValueField::setZero() { changeGPR(index, model(), [](int) { return 0; }); } void ValueField::setToOne() { changeGPR(index, model(), [](int) { return 1; }); } } edb-debugger-1.0.0/plugins/ODbgRegisterView/x86Groups.h0000644000175000017500000000264013273160654022205 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef ODBG_REGISTER_VIEW_X86_GROUPS_H_20170817 #define ODBG_REGISTER_VIEW_X86_GROUPS_H_20170817 #include "RegisterView.h" namespace ODbgRegisterView { RegisterGroup *createEFL(RegisterViewModelBase::Model *model, QWidget *parent); RegisterGroup *createExpandedEFL(RegisterViewModelBase::Model *model, QWidget *parent); RegisterGroup *createFPUData(RegisterViewModelBase::Model *model, QWidget *parent); RegisterGroup *createFPUWords(RegisterViewModelBase::Model *model, QWidget *parent); RegisterGroup *createFPULastOp(RegisterViewModelBase::Model *model, QWidget *parent); RegisterGroup *createDebugGroup(RegisterViewModelBase::Model *model, QWidget *parent); RegisterGroup *createMXCSR(RegisterViewModelBase::Model *model, QWidget *parent); } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/ODbgRV_Util.h0000644000175000017500000001064713273160654022446 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef ODBG_REG_VIEW_UTIL_H_20170817 #define ODBG_REG_VIEW_UTIL_H_20170817 #include "RegisterView.h" #include #include namespace ODbgRegisterView { static constexpr int MODEL_NAME_COLUMN = RegisterViewModelBase::Model::NAME_COLUMN; static constexpr int MODEL_VALUE_COLUMN = RegisterViewModelBase::Model::VALUE_COLUMN; static constexpr int MODEL_COMMENT_COLUMN = RegisterViewModelBase::Model::COMMENT_COLUMN; template T VALID_VARIANT(T variant) { static_assert(std::is_same::type, const QVariant>::value, "Wrong type passed to VALID_VARIANT"); assert((variant).isValid()); return variant; } template T VALID_INDEX(T index) { static_assert( std::is_same::type, const QModelIndex>::value || std::is_same::type, const QPersistentModelIndex>::value, "Wrong type passed to VALID_INDEX" ); assert(index.isValid()); return index; } template T *checked_cast(P p) { assert(dynamic_cast(p)); return static_cast(p); } template T sqr(T v) { return v * v; } inline QPoint fieldPos(const FieldWidget *const field) { // NOTE: mapToGlobal() is VERY slow, don't use it. Here we map to canvas, it's enough for all fields. return field->mapTo(field->parentWidget()->parentWidget(), QPoint()); } // Square of Euclidean distance between two points inline int distSqr(QPoint const &w1, QPoint const &w2) { return sqr(w1.x() - w2.x()) + sqr(w1.y() - w2.y()); } inline QSize letterSize(QFont const &font) { const QFontMetrics fontMetrics(font); const int width = fontMetrics.width('w'); const int height = fontMetrics.height(); return QSize(width, height); } inline QAction *newActionSeparator(QObject *parent) { const auto sep = new QAction(parent); sep->setSeparator(true); return sep; } inline QAction *newAction(QString const &text, QObject *parent, QObject *signalReceiver, const char *slot) { const auto action = new QAction(text, parent); QObject::connect(action, SIGNAL(triggered()), signalReceiver, slot); return action; } inline QAction *newAction(QString const &text, QObject *parent, QSignalMapper *mapper, int mapping) { const auto action = newAction(text, parent, mapper, SLOT(map())); mapper->setMapping(action, mapping); return action; } // TODO: switch from string-based search to enum-based one (add a new Role to model data) inline QModelIndex findModelCategory(RegisterViewModelBase::Model const *const model, QString const &catToFind) { for (int row = 0; row < model->rowCount(); ++row) { const auto cat = model->index(row, 0).data(MODEL_NAME_COLUMN); if (cat.isValid() && cat.toString() == catToFind) return model->index(row, 0); } return QModelIndex(); } // TODO: switch from string-based search to enum-based one (add a new Role to model data) inline QModelIndex findModelRegister(QModelIndex categoryIndex, QString const ®ToFind, int column = MODEL_NAME_COLUMN) { const auto model = categoryIndex.model(); for (int row = 0; row < model->rowCount(categoryIndex); ++row) { const auto regIndex = model->index(row, MODEL_NAME_COLUMN, categoryIndex); const auto name = model->data(regIndex).toString(); if (name.toUpper() == regToFind) { if (column == MODEL_NAME_COLUMN) return regIndex; return regIndex.sibling(regIndex.row(), column); } } return QModelIndex(); } inline QModelIndex getCommentIndex(QModelIndex const &nameIndex) { assert(nameIndex.isValid()); return nameIndex.sibling(nameIndex.row(), MODEL_COMMENT_COLUMN); } inline QModelIndex getValueIndex(QModelIndex const &nameIndex) { assert(nameIndex.isValid()); return nameIndex.sibling(nameIndex.row(), MODEL_VALUE_COLUMN); } } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/DialogEditSIMDRegister.h0000644000175000017500000001046713273160654024555 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #ifndef DIALOG_EDIT_MMX_H_20151010 #define DIALOG_EDIT_MMX_H_20151010 #include "Register.h" #include "RegisterViewModelBase.h" #include "Util.h" #include #include #include #include #include #include class QHBoxLayout; class QLongValidator; class QRadioButton; class QRegExpValidator; class QULongValidator; class QValidator; namespace ODbgRegisterView { class NumberEdit; class DialogEditSIMDRegister : public QDialog { Q_OBJECT private: static constexpr int numBytes = 256 / 8; enum EntriesRows { BYTE_INDICES_ROW, BYTES_ROW, ENTRIES_FIRST_ROW = BYTES_ROW, WORDS_ROW, DWORDS_ROW, QWORDS_ROW, FLOATS32_ROW, FLOATS64_ROW, ROW_AFTER_ENTRIES }; enum EntriesCols { LABELS_COL, ENTRIES_FIRST_COL, YMM_FIRST_COL = ENTRIES_FIRST_COL, XMM_FIRST_COL = YMM_FIRST_COL + 16, MMX_FIRST_COL = XMM_FIRST_COL + 8, TOTAL_COLS = MMX_FIRST_COL + 8 }; public: DialogEditSIMDRegister(QWidget *parent = nullptr); void set_value(const Register &value); void set_current_element(RegisterViewModelBase::Model::ElementSize size, NumberDisplayMode format, int elementIndex); Register value() const; protected: bool eventFilter(QObject*, QEvent*) override; private: template void setupEntries(const QString &label, std::array &entries, int row, const char *slot, int naturalWidthInChars); std::uint64_t readInteger(const NumberEdit *edit) const; template void formatInteger(NumberEdit *edit, Integer integer) const; void updateAllEntriesExcept(NumberEdit *notUpdated); void hideColumns(EntriesCols preLast); void hideRows(EntriesRows rowToHide); void resetLayout(); private: template void onIntegerEdited(QObject *sender, const std::array &elements); template void onFloatEdited(QObject *sender, const std::array &elements); template void updateIntegralEntries(const std::array &entries, NumberEdit *notUpdated); template void updateFloatEntries(const std::array &entries, NumberEdit *notUpdated); private Q_SLOTS : void onByteEdited(); void onWordEdited(); void onDwordEdited(); void onQwordEdited(); void onFloat32Edited(); void onFloat64Edited(); void onHexToggled(bool checked); void onSignedToggled(bool checked); void onUnsignedToggled(bool checked); private: QHBoxLayout * hexSignOKCancelLayout; QDialogButtonBox *okCancel; QRadioButton * radioHex; QRadioButton * radioSigned; QRadioButton * radioUnsigned; std::array floats64; std::array floats32; std::array qwords; std::array dwords; std::array words; std::array bytes; std::array columnLabels; QRegExpValidator *byteHexValidator; QRegExpValidator *wordHexValidator; QRegExpValidator *dwordHexValidator; QRegExpValidator *qwordHexValidator; QLongValidator *byteSignedValidator; QLongValidator *wordSignedValidator; QLongValidator *dwordSignedValidator; QLongValidator *qwordSignedValidator; QULongValidator *byteUnsignedValidator; QULongValidator *wordUnsignedValidator; QULongValidator *dwordUnsignedValidator; QULongValidator *qwordUnsignedValidator; QValidator *float32Validator; QValidator *float64Validator; NumberDisplayMode intMode; std::array value_; Register reg; }; } #endif edb-debugger-1.0.0/plugins/ODbgRegisterView/FieldWidget.cpp0000644000175000017500000000523313273160654023103 0ustar eteraneteran/* Copyright (C) 2015 Ruslan Kabatsayev 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, see . */ #include "RegisterView.h" #include "ODbgRV_Util.h" namespace ODbgRegisterView { QString FieldWidget::text() const { if (!index.isValid() && !this->isEnabled()) return QLabel::text(); const auto text = index.data(); if (!text.isValid()) return QString(width() / letterSize(font()).width() - 1, QChar('?')); return text.toString(); } int FieldWidget::lineNumber() const { const auto charSize = letterSize(font()); return fieldPos(this).y() / charSize.height(); } int FieldWidget::columnNumber() const { const auto charSize = letterSize(font()); return fieldPos(this).x() / charSize.width(); } void FieldWidget::init(int const fieldWidth) { setObjectName("FieldWidget"); const auto charSize = letterSize(font()); setFixedHeight(charSize.height()); if (fieldWidth > 0) setFixedWidth(fieldWidth * charSize.width()); setDisabled(true); } FieldWidget::FieldWidget(int const fieldWidth, QModelIndex const &index, QWidget *const parent) : QLabel("Fw???", parent), index(index), fieldWidth_(fieldWidth) { init(fieldWidth); } FieldWidget::FieldWidget(int const fieldWidth, QString const &fixedText, QWidget *const parent) : QLabel(fixedText, parent), fieldWidth_(fieldWidth) { init(fieldWidth); // NOTE: fieldWidth!=fixedText.length() in general } FieldWidget::FieldWidget(QString const &fixedText, QWidget *const parent) : QLabel(fixedText, parent), fieldWidth_(fixedText.length()) { init(fixedText.length()); } int FieldWidget::fieldWidth() const { return fieldWidth_; } void FieldWidget::adjustToData() { QLabel::setText(text()); adjustSize(); } ODBRegView *FieldWidget::regView() const { const auto parent = parentWidget() // group ->parentWidget() // canvas ->parentWidget() // viewport ->parentWidget(); // regview return checked_cast(parent); } RegisterGroup *FieldWidget::group() const { return checked_cast(parentWidget()); } } edb-debugger-1.0.0/plugins/Analyzer/0000755000175000017500000000000013273160654016617 5ustar eteraneteranedb-debugger-1.0.0/plugins/Analyzer/DialogXRefs.h0000644000175000017500000000102313273160654021133 0ustar eteraneteran #ifndef DIALOG_XREFS_H_ #define DIALOG_XREFS_H_ #include #include #include "edb.h" class QListWidgetItem; namespace AnalyzerPlugin { namespace Ui { class DialogXRefs; } class DialogXRefs : public QDialog { Q_OBJECT public: DialogXRefs(QWidget *parent = 0); virtual ~DialogXRefs(); public Q_SLOTS: void on_listReferences_itemDoubleClicked(QListWidgetItem *item); public: void addReference(const QPair &reference); private: Ui::DialogXRefs *const ui; }; } #endif edb-debugger-1.0.0/plugins/Analyzer/AnalyzerWidget.h0000644000175000017500000000223513273160654021723 0ustar eteraneteran/* Copyright (C) 2013 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include #include namespace AnalyzerPlugin { class AnalyzerWidget : public QWidget { Q_OBJECT public: AnalyzerWidget(QWidget *parent = 0, Qt::WindowFlags f = 0); protected: virtual void paintEvent(QPaintEvent *event); virtual void mousePressEvent(QMouseEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event); virtual void mouseMoveEvent(QMouseEvent *event); private: bool mouse_pressed_; QPixmap* cache_; int cache_num_funcs_; }; } edb-debugger-1.0.0/plugins/Analyzer/Analyzer.cpp0000644000175000017500000007442513273160654021124 0ustar eteraneteran/* Copyright (C) 2006 - 2015 Evan Teran evan.teran@gmail.com 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, see . */ #include "Analyzer.h" #include "AnalyzerWidget.h" #include "Configuration.h" #include "DialogXRefs.h" #include "Function.h" #include "IBinary.h" #include "IDebugger.h" #include "IProcess.h" #include "ISymbolManager.h" #include "IThread.h" #include "Instruction.h" #include "MemoryRegions.h" #include "OptionsPage.h" #include "Prototype.h" #include "SpecifiedFunctions.h" #include "State.h" #include "Util.h" #include "edb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x050000 #ifdef QT_CONCURRENT_LIB #include #endif #elif QT_VERSION >= 0x040800 #include #ifndef QT_NO_CONCURRENT #define QT_CONCURRENT_LIB #endif #endif namespace AnalyzerPlugin { namespace { const int MIN_REFCOUNT = 2; //------------------------------------------------------------------------------ // Name: module_entry_point // Desc: //------------------------------------------------------------------------------ edb::address_t module_entry_point(const std::shared_ptr ®ion) { edb::address_t entry = 0; if(auto binary_info = edb::v1::get_binary_info(region)) { entry = binary_info->entry_point(); } return entry; } } //------------------------------------------------------------------------------ // Name: Analyzer // Desc: //------------------------------------------------------------------------------ Analyzer::Analyzer() : menu_(0), analyzer_widget_(0) { } //------------------------------------------------------------------------------ // Name: options_page // Desc: //------------------------------------------------------------------------------ QWidget *Analyzer::options_page() { return new OptionsPage; } //------------------------------------------------------------------------------ // Name: menu // Desc: //------------------------------------------------------------------------------ QMenu *Analyzer::menu(QWidget *parent) { Q_ASSERT(parent); if(!menu_) { menu_ = new QMenu(tr("Analyzer"), parent); menu_->addAction(tr("Show &Specified Functions"), this, SLOT(show_specified())); if(edb::v1::debugger_core) { menu_->addAction(tr("&Analyze %1's Region").arg(edb::v1::debugger_core->instruction_pointer().toUpper()), this, SLOT(do_ip_analysis()), QKeySequence(tr("Ctrl+A"))); } menu_->addAction(tr("&Analyze Viewed Region"), this, SLOT(do_view_analysis()), QKeySequence(tr("Ctrl+Shift+A"))); // if we are dealing with a main window (and we are...) // add the dock object if(auto main_window = qobject_cast(edb::v1::debugger_ui)) { analyzer_widget_ = new AnalyzerWidget; // make the toolbar widget and _name_ it, it is important to name it so // that it's state is saved in the GUI info auto toolbar = new QToolBar(tr("Region Analysis"), main_window); toolbar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea); toolbar->setObjectName(QString::fromUtf8("Region Analysis")); toolbar->addWidget(analyzer_widget_); // add it to the dock main_window->addToolBar(Qt::TopToolBarArea, toolbar); // make the menu and add the show/hide toggle for the widget menu_->addAction(toolbar->toggleViewAction()); } } return menu_; } //------------------------------------------------------------------------------ // Name: private_init // Desc: //------------------------------------------------------------------------------ void Analyzer::private_init() { edb::v1::set_analyzer(this); } //------------------------------------------------------------------------------ // Name: show_specified // Desc: //------------------------------------------------------------------------------ void Analyzer::show_specified() { static auto dialog = new SpecifiedFunctions(edb::v1::debugger_ui); dialog->show(); } //------------------------------------------------------------------------------ // Name: do_ip_analysis // Desc: //------------------------------------------------------------------------------ void Analyzer::do_ip_analysis() { if(IProcess *process = edb::v1::debugger_core->process()) { if(std::shared_ptr thread = process->current_thread()) { State state; thread->get_state(&state); const edb::address_t address = state.instruction_pointer(); if(std::shared_ptr region = edb::v1::memory_regions().find_region(address)) { do_analysis(region); } } } } //------------------------------------------------------------------------------ // Name: do_view_analysis // Desc: //------------------------------------------------------------------------------ void Analyzer::do_view_analysis() { do_analysis(edb::v1::current_cpu_view_region()); } //------------------------------------------------------------------------------ // Name: mark_function_start // Desc: //------------------------------------------------------------------------------ void Analyzer::mark_function_start() { const edb::address_t address = edb::v1::cpu_selected_address(); if(std::shared_ptr region = edb::v1::memory_regions().find_region(address)) { qDebug("Added %s to the list of known functions", qPrintable(address.toPointerString())); specified_functions_.insert(address); invalidate_dynamic_analysis(region); } } //------------------------------------------------------------------------------ // Name: mark_function_start // Desc: //------------------------------------------------------------------------------ void Analyzer::show_xrefs() { const edb::address_t address = edb::v1::cpu_selected_address(); auto dialog = new DialogXRefs(edb::v1::debugger_ui); for(const RegionData &data : analysis_info_) { for(const BasicBlock &bb : data.basic_blocks) { QVector> refs = bb.refs(); for(auto it = refs.begin(); it != refs.end(); ++it) { if(it->second == address) { dialog->addReference(*it); } } } } dialog->setWindowTitle(tr("X-Refs For %1").arg(address.toPointerString())); dialog->show(); } //------------------------------------------------------------------------------ // Name: goto_function_start // Desc: //------------------------------------------------------------------------------ void Analyzer::goto_function_start() { const edb::address_t address = edb::v1::cpu_selected_address(); Function function; if(find_containing_function(address, &function)) { edb::v1::jump_to_address(function.entry_address()); return; } QMessageBox::critical( 0, tr("Goto Function Start"), tr("The selected instruction is not inside of a known function. Have you run an analysis of this region?")); } //------------------------------------------------------------------------------ // Name: goto_function_end // Desc: //------------------------------------------------------------------------------ void Analyzer::goto_function_end() { const edb::address_t address = edb::v1::cpu_selected_address(); Function function; if(find_containing_function(address, &function)) { edb::v1::jump_to_address(function.last_instruction()); return; } QMessageBox::critical( 0, tr("Goto Function End"), tr("The selected instruction is not inside of a known function. Have you run an analysis of this region?")); } //------------------------------------------------------------------------------ // Name: cpu_context_menu // Desc: //------------------------------------------------------------------------------ QList Analyzer::cpu_context_menu() { QList ret; auto action_find = new QAction(tr("Analyze Here"), this); auto action_goto_function_start = new QAction(tr("Goto Function Start"), this); auto action_goto_function_end = new QAction(tr("Goto Function End"), this); auto action_mark_function_start = new QAction(tr("Mark As Function Start"), this); auto action_xrefs = new QAction(tr("Show X-Refs"), this); connect(action_find, SIGNAL(triggered()), this, SLOT(do_view_analysis())); connect(action_goto_function_start, SIGNAL(triggered()), this, SLOT(goto_function_start())); connect(action_goto_function_end, SIGNAL(triggered()), this, SLOT(goto_function_end())); connect(action_mark_function_start, SIGNAL(triggered()), this, SLOT(mark_function_start())); connect(action_xrefs, SIGNAL(triggered()), this, SLOT(show_xrefs())); ret << action_find << action_goto_function_start << action_goto_function_end << action_mark_function_start << action_xrefs; return ret; } //------------------------------------------------------------------------------ // Name: do_analysis // Desc: //------------------------------------------------------------------------------ void Analyzer::do_analysis(const std::shared_ptr ®ion) { if(region && region->size() != 0) { QProgressDialog progress(tr("Performing Analysis"), 0, 0, 100, edb::v1::debugger_ui); connect(this, SIGNAL(update_progress(int)), &progress, SLOT(setValue(int))); progress.show(); progress.setValue(0); analyze(region); edb::v1::repaint_cpu_view(); } } //------------------------------------------------------------------------------ // Name: bonus_main // Desc: //------------------------------------------------------------------------------ void Analyzer::bonus_main(RegionData *data) const { Q_ASSERT(data); const QString s = edb::v1::debugger_core->process()->executable(); if(!s.isEmpty()) { if(const edb::address_t main = edb::v1::locate_main_function()) { if(data->region->contains(main)) { data->known_functions.insert(main); } } } } //------------------------------------------------------------------------------ // Name: bonus_symbols // Desc: //------------------------------------------------------------------------------ void Analyzer::bonus_symbols(RegionData *data) { Q_ASSERT(data); // give bonus if we have a symbol for the address const QList> symbols = edb::v1::symbol_manager().symbols(); for(const std::shared_ptr &sym: symbols) { const edb::address_t addr = sym->address; if(data->region->contains(addr) && sym->is_code()) { qDebug("[Analyzer] adding: %s <%s>", qPrintable(sym->name), qPrintable(addr.toPointerString())); data->known_functions.insert(addr); } } } //------------------------------------------------------------------------------ // Name: bonus_marked_functions // Desc: //------------------------------------------------------------------------------ void Analyzer::bonus_marked_functions(RegionData *data) { Q_ASSERT(data); Q_FOREACH(const edb::address_t addr, specified_functions_) { if(data->region->contains(addr)) { qDebug("[Analyzer] adding user marked function: <%s>", qPrintable(addr.toPointerString())); data->known_functions.insert(addr); } } } //------------------------------------------------------------------------------ // Name: is_thunk // Desc: basically returns true if the first instruction of the function is a // jmp //------------------------------------------------------------------------------ bool Analyzer::is_thunk(edb::address_t address) const { quint8 buf[edb::Instruction::MAX_SIZE]; if(const int buf_size = edb::v1::get_instruction_bytes(address, buf)) { const edb::Instruction inst(buf, buf + buf_size, address); return is_unconditional_jump(inst); } return false; } //------------------------------------------------------------------------------ // Name: set_function_types_helper // Desc: //------------------------------------------------------------------------------ void Analyzer::set_function_types_helper(Function &function) const { if(is_thunk(function.entry_address())) { function.set_type(Function::FUNCTION_THUNK); } else { function.set_type(Function::FUNCTION_STANDARD); } } //------------------------------------------------------------------------------ // Name: set_function_types // Desc: //------------------------------------------------------------------------------ void Analyzer::set_function_types(FunctionMap *results) { Q_ASSERT(results); // give bonus if we have a symbol for the address #if QT_VERSION >= 0x040800 && defined(QT_CONCURRENT_LIB) QtConcurrent::blockingMap(*results, [this](Function &function) { set_function_types_helper(function); }); #else std::for_each(results->begin(), results->end(), [this](Function &function) { set_function_types_helper(function); }); #endif } //------------------------------------------------------------------------------ // Name: ident_header // Desc: //------------------------------------------------------------------------------ void Analyzer::ident_header(Analyzer::RegionData *data) { Q_UNUSED(data); } //------------------------------------------------------------------------------ // Name: analyze // Desc: //------------------------------------------------------------------------------ void Analyzer::collect_functions(Analyzer::RegionData *data) { Q_ASSERT(data); // results QHash basic_blocks; FunctionMap functions; // push all known functions onto a stack QStack known_functions; Q_FOREACH(const edb::address_t function, data->known_functions) { known_functions.push(function); } // push all fuzzy function too... Q_FOREACH(const edb::address_t function, data->fuzzy_functions) { known_functions.push(function); } // process all functions that are known while(!known_functions.empty()) { const edb::address_t function_address = known_functions.pop(); if(!functions.contains(function_address)) { QStack blocks; blocks.push(function_address); Function func; // process are basic blocks that are known while(!blocks.empty()) { const edb::address_t block_address = blocks.pop(); edb::address_t address = block_address; BasicBlock block; if(!basic_blocks.contains(block_address)) { while(data->region->contains(address)) { quint8 buffer[edb::Instruction::MAX_SIZE]; const int buf_size = edb::v1::get_instruction_bytes(address, buffer); if(buf_size == 0) { break; } auto inst = std::make_shared(buffer, buffer + buf_size, address); if(!inst->valid()) { break; } block.push_back(inst); if(is_call(*inst)) { // note the destination and move on // we special case some simple things. // also this is an opportunity to find call tables. const auto op = inst->operand(0); if(is_immediate(op)) { const edb::address_t ea = op->imm; // skip over ones which are: "call