edb-debugger-0.9.21/0000755000175000017500000000000012773030073013437 5ustar eteraneteranedb-debugger-0.9.21/travis_install_capstone.sh0000755000175000017500000000030012773027761020733 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-0.9.21/BUGS0000644000175000017500000000014512773027761014134 0ustar eteraneteranThis file has been superseded by the issue tracker at: https://github.com/eteran/edb-debugger/issues edb-debugger-0.9.21/symbols/0000755000175000017500000000000012773027761015141 5ustar eteraneteranedb-debugger-0.9.21/symbols/.gitignore0000644000175000017500000000001612773027761017126 0ustar eteraneteran* !.gitignore edb-debugger-0.9.21/edb.desktop0000644000175000017500000000023612773027761015577 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-0.9.21/COPYING0000644000175000017500000004325412773027761014514 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-0.9.21/qmake/0000755000175000017500000000000012773027761014547 5ustar eteraneteranedb-debugger-0.9.21/qmake/clean-objects.pri0000644000175000017500000000116012773027761017772 0ustar eteraneteran unix { CONFIG(debug, debug|release) { DEFINES += QT_SHAREDPOINTER_TRACK_POINTERS OBJECTS_DIR = $${OUT_PWD}/.debug-shared/obj MOC_DIR = $${OUT_PWD}/.debug-shared/moc RCC_DIR = $${OUT_PWD}/.debug-shared/rcc UI_DIR = $${OUT_PWD}/.debug-shared/uic } CONFIG(release, debug|release) { OBJECTS_DIR = $${OUT_PWD}/.release-shared/obj MOC_DIR = $${OUT_PWD}/.release-shared/moc RCC_DIR = $${OUT_PWD}/.release-shared/rcc UI_DIR = $${OUT_PWD}/.release-shared/uic } } unix { QMAKE_DISTCLEAN += -r \ $${OUT_PWD}/.debug-shared/ \ $${OUT_PWD}/.release-shared/ } edb-debugger-0.9.21/qmake/qt5-gui.pri0000644000175000017500000000006712773027761016561 0ustar eteraneterangreaterThan(QT_MAJOR_VERSION, 4) { QT += widgets } edb-debugger-0.9.21/qmake/c++11.pri0000644000175000017500000000016612773027761016000 0ustar eteraneterangreaterThan(QT_MAJOR_VERSION, 4) { CONFIG += c++11 } else { *-g++* | *-clang* { QMAKE_CXXFLAGS += -std=c++11 } } edb-debugger-0.9.21/plugins/0000755000175000017500000000000012773027761015132 5ustar eteraneteranedb-debugger-0.9.21/plugins/BinaryInfo/0000755000175000017500000000000012773027761017172 5ustar eteraneteranedb-debugger-0.9.21/plugins/BinaryInfo/BinaryInfo.pro0000644000175000017500000000045112773027761021754 0ustar eteraneteran include(../plugins.pri) # Input HEADERS += symbols.h demangle.h BinaryInfo.h ELF32.h ELF64.h PE32.h elf_binary.h pe_binary.h DialogHeader.h OptionsPage.h FORMS += DialogHeader.ui OptionsPage.ui SOURCES += symbols.cpp BinaryInfo.cpp ELF32.cpp ELF64.cpp PE32.cpp DialogHeader.cpp OptionsPage.cpp edb-debugger-0.9.21/plugins/BinaryInfo/ELF64.cpp0000644000175000017500000001445012773027761020462 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 "ELF64.h" #include "ByteShiftArray.h" #include "IDebugger.h" #include "Util.h" #include "edb.h" #include "string_hash.h" #include #include #include #include #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) #include #endif namespace BinaryInfo { //------------------------------------------------------------------------------ // Name: ELF64 // Desc: constructor //------------------------------------------------------------------------------ ELF64::ELF64(const IRegion::pointer ®ion) : region_(region), header_(0) { } //------------------------------------------------------------------------------ // Name: ~ELF64 // Desc: deconstructor //------------------------------------------------------------------------------ ELF64::~ELF64() { delete header_; } //------------------------------------------------------------------------------ // Name: validate_header // Desc: returns true if this file matches this particular info class //------------------------------------------------------------------------------ bool ELF64::validate_header() { read_header(); if(header_) { if(std::memcmp(header_->e_ident, ELFMAG, SELFMAG) == 0) { return header_->e_ident[EI_CLASS] == ELFCLASS64; } } return false; } //------------------------------------------------------------------------------ // Name: nativ // Desc: returns true if this binary is native to the arch edb was built for //------------------------------------------------------------------------------ bool ELF64::native() const { return edb::v1::debugger_core->cpu_type() == edb::string_hash("x86-64"); } //------------------------------------------------------------------------------ // Name: entry_point // Desc: returns the entry point if any of the binary //------------------------------------------------------------------------------ edb::address_t ELF64::entry_point() { read_header(); if(header_) { return header_->e_entry; } return 0; } //------------------------------------------------------------------------------ // Name: read_header // Desc: reads in enough of the file to get the header //------------------------------------------------------------------------------ void ELF64::read_header() { if(!header_) { if(IProcess *process = edb::v1::debugger_core->process()) { if(region_) { header_ = new elf64_header; if(!process->read_bytes(region_->start(), header_, sizeof(elf64_header))) { std::memset(header_, 0, sizeof(elf64_header)); } } } } } //------------------------------------------------------------------------------ // Name: header_size // Desc: returns the number of bytes in this executable's header //------------------------------------------------------------------------------ size_t ELF64::header_size() const { return sizeof(elf64_header); } //------------------------------------------------------------------------------ // Name: debug_pointer // Desc: attempts to locate the ELF debug pointer in the target process and // returns it, 0 of not found //------------------------------------------------------------------------------ edb::address_t ELF64::debug_pointer() { read_header(); if(region_) { 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" //------------------------------------------------------------------------------ edb::address_t ELF64::calculate_main() { edb::address_t entry_point = this->entry_point(); ByteShiftArray ba(13); 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() >= 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 auto address = *reinterpret_cast(ba.data() + 3) & 0xffffffff; // 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; } //------------------------------------------------------------------------------ // Name: header // Desc: returns a copy of the file header or NULL if the region wasn't a valid, // known binary type //------------------------------------------------------------------------------ const void *ELF64::header() const { return header_; } } edb-debugger-0.9.21/plugins/BinaryInfo/pe_binary.h0000644000175000017500000001106312773027761021314 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 BinaryInfo { 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-0.9.21/plugins/BinaryInfo/DialogHeader.h0000644000175000017500000000235612773027761021661 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 BinaryInfo { 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-0.9.21/plugins/BinaryInfo/BinaryInfo.h0000644000175000017500000000307012773027761021403 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 BinaryInfo { 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(); virtual QWidget* options_page() override; public: virtual QMenu *menu(QWidget *parent = 0); virtual QString extra_arguments() const; virtual ArgumentStatus parse_arguments(QStringList &args); public: virtual bool generate_symbol_file(const QString &filename, const QString &symbol_file); public Q_SLOTS: void explore_header(); private: QMenu *menu_; }; } #endif edb-debugger-0.9.21/plugins/BinaryInfo/ELF32.h0000644000175000017500000000242612773027761020122 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 BinaryInfo { class ELF32 : public IBinary { public: ELF32(const IRegion::pointer ®ion); virtual ~ELF32(); public: virtual bool native() const; virtual bool validate_header(); 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; private: void read_header(); private: IRegion::pointer region_; elf32_header * header_; }; } #endif edb-debugger-0.9.21/plugins/BinaryInfo/ELF32.cpp0000644000175000017500000001432112773027761020452 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 "ELF32.h" #include "ByteShiftArray.h" #include "IDebugger.h" #include "Util.h" #include "edb.h" #include "string_hash.h" #include #include #include #include #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) #include #endif namespace BinaryInfo { //------------------------------------------------------------------------------ // Name: ELF32 // Desc: constructor //------------------------------------------------------------------------------ ELF32::ELF32(const IRegion::pointer ®ion) : region_(region), header_(0) { } //------------------------------------------------------------------------------ // Name: ~ELF32 // Desc: deconstructor //------------------------------------------------------------------------------ ELF32::~ELF32() { delete header_; } //------------------------------------------------------------------------------ // Name: validate_header // Desc: returns true if this file matches this particular info class //------------------------------------------------------------------------------ bool ELF32::validate_header() { read_header(); if(header_) { if(std::memcmp(header_->e_ident, ELFMAG, SELFMAG) == 0) { return header_->e_ident[EI_CLASS] == ELFCLASS32; } } return false; } //------------------------------------------------------------------------------ // Name: nativ // Desc: returns true if this binary is native to the arch edb was built for //------------------------------------------------------------------------------ bool ELF32::native() const { return edb::v1::debugger_core->cpu_type() == edb::string_hash("x86"); } //------------------------------------------------------------------------------ // Name: entry_point // Desc: returns the entry point if any of the binary //------------------------------------------------------------------------------ edb::address_t ELF32::entry_point() { read_header(); if(header_) { return header_->e_entry; } return 0; } //------------------------------------------------------------------------------ // Name: read_header // Desc: reads in enough of the file to get the header //------------------------------------------------------------------------------ void ELF32::read_header() { if(!header_) { if(IProcess *process = edb::v1::debugger_core->process()) { if(region_) { header_ = new elf32_header; if(!process->read_bytes(region_->start(), header_, sizeof(elf32_header))) { std::memset(header_, 0, sizeof(elf32_header)); } } } } } //------------------------------------------------------------------------------ // Name: header_size // Desc: returns the number of bytes in this executable's header //------------------------------------------------------------------------------ size_t ELF32::header_size() const { return sizeof(elf32_header); } //------------------------------------------------------------------------------ // Name: debug_pointer // Desc: attempts to locate the ELF debug pointer in the target process and // returns it, 0 of not found //------------------------------------------------------------------------------ edb::address_t ELF32::debug_pointer() { read_header(); if(region_) { 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" //------------------------------------------------------------------------------ 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; } //------------------------------------------------------------------------------ // Name: header // Desc: returns a copy of the file header or NULL if the region wasn't a valid, // known binary type //------------------------------------------------------------------------------ const void *ELF32::header() const { return header_; } } edb-debugger-0.9.21/plugins/BinaryInfo/OptionsPage.cpp0000644000175000017500000000357612773027761022141 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 BinaryInfo { 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-0.9.21/plugins/BinaryInfo/DialogHeader.cpp0000644000175000017500000004445012773027761022215 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 "ELF32.h" #include "ELF64.h" #include "MemoryRegions.h" #include "PE32.h" #include #include #include "ui_DialogHeader.h" namespace BinaryInfo { 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-0.9.21/plugins/BinaryInfo/CMakeLists.txt0000644000175000017500000000220112773027761021725 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 ELF32.cpp ELF32.h ELF64.cpp ELF64.h 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-0.9.21/plugins/BinaryInfo/elf_binary.h0000644000175000017500000022370212773027761021463 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 BinaryInfo { #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-0.9.21/plugins/BinaryInfo/PE32.h0000644000175000017500000000232712773027761020020 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 BinaryInfo { class PE32 : public IBinary { public: PE32(const IRegion::pointer ®ion); virtual ~PE32(); public: virtual bool native() const; virtual bool validate_header(); 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; private: IRegion::pointer region_; }; } #endif edb-debugger-0.9.21/plugins/BinaryInfo/symbols.h0000644000175000017500000000161412773027761021035 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 BinaryInfo { bool generate_symbols(const QString &filename, std::ostream &os = std::cout); } #endif edb-debugger-0.9.21/plugins/BinaryInfo/DialogHeader.ui0000644000175000017500000000755612773027761022056 0ustar eteraneteran Evan Teran BinaryInfo::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-0.9.21/plugins/BinaryInfo/symbols.cpp0000644000175000017500000004317412773027761021377 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 BinaryInfo { 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()).arg(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()).arg(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); 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); 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); 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-0.9.21/plugins/BinaryInfo/PE32.cpp0000644000175000017500000000561612773027761020357 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 "string_hash.h" #include "pe_binary.h" namespace BinaryInfo { //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ PE32::PE32(const IRegion::pointer ®ion) : region_(region) { } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ PE32::~PE32() { } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ bool PE32::validate_header() { return false; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ edb::address_t PE32::entry_point() { return 0; } //------------------------------------------------------------------------------ // 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 0; } //------------------------------------------------------------------------------ // 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-0.9.21/plugins/BinaryInfo/OptionsPage.ui0000644000175000017500000000303612773027761021763 0ustar eteraneteran BinaryInfo::OptionsPage 0 0 334 323 BinaryInfo Plugin Demangle auto-generated symbols Debug Info Directory txtDebugDir ... Qt::Vertical 20 262 edb-debugger-0.9.21/plugins/BinaryInfo/demangle.h0000644000175000017500000000126612773027761021124 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) { 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-0.9.21/plugins/BinaryInfo/OptionsPage.h0000644000175000017500000000230312773027761021571 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 BinaryInfo { 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-0.9.21/plugins/BinaryInfo/elf/0000755000175000017500000000000012773027761017740 5ustar eteraneteranedb-debugger-0.9.21/plugins/BinaryInfo/elf/elf_phdr.h0000644000175000017500000001313412773027761021676 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-0.9.21/plugins/BinaryInfo/elf/elf_types.h0000644000175000017500000000407612773027761022112 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-0.9.21/plugins/BinaryInfo/elf/elf_verdef.h0000644000175000017500000000463012773027761022215 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-0.9.21/plugins/BinaryInfo/elf/elf_auxv.h0000644000175000017500000000776312773027761021737 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-0.9.21/plugins/BinaryInfo/elf/elf_rel.h0000644000175000017500000000267212773027761021530 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-0.9.21/plugins/BinaryInfo/elf/elf_nhdr.h0000644000175000017500000000552312773027761021677 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-0.9.21/plugins/BinaryInfo/elf/elf_rela.h0000644000175000017500000000325712773027761021671 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-0.9.21/plugins/BinaryInfo/elf/elf_syminfo.h0000644000175000017500000001066412773027761022432 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-0.9.21/plugins/BinaryInfo/elf/elf_move.h0000644000175000017500000000337012773027761021710 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-0.9.21/plugins/BinaryInfo/elf/elf_header.h0000644000175000017500000002232012773027761022166 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 }; struct elf32_header { 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_header { 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 */ }; /* 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 #endif edb-debugger-0.9.21/plugins/BinaryInfo/elf/elf_vernaux.h0000644000175000017500000000321312773027761022426 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-0.9.21/plugins/BinaryInfo/elf/elf_verneed.h0000644000175000017500000000346012773027761022372 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-0.9.21/plugins/BinaryInfo/elf/elf_sym.h0000644000175000017500000000302112773027761021543 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-0.9.21/plugins/BinaryInfo/elf/elf_verdaux.h0000644000175000017500000000235112773027761022416 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-0.9.21/plugins/BinaryInfo/elf/elf_dyn.h0000644000175000017500000002052112773027761021531 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-0.9.21/plugins/BinaryInfo/elf/elf_shdr.h0000644000175000017500000001363412773027761021706 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-0.9.21/plugins/BinaryInfo/BinaryInfo.cpp0000644000175000017500000001126112773027761021737 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 "ELF32.h" #include "ELF64.h" #include "IBinary.h" #include "ISymbolManager.h" #include "PE32.h" #include "edb.h" #include "symbols.h" #include "OptionsPage.h" #include #include #include #include namespace BinaryInfo { namespace { //------------------------------------------------------------------------------ // Name: create_binary_info_elf32 // Desc: //------------------------------------------------------------------------------ std::unique_ptr create_binary_info_elf32(const IRegion::pointer ®ion) { return std::unique_ptr(new ELF32(region)); } //------------------------------------------------------------------------------ // Name: create_binary_info_elf64 // Desc: //------------------------------------------------------------------------------ std::unique_ptr create_binary_info_elf64(const IRegion::pointer ®ion) { return std::unique_ptr(new ELF64(region)); } //------------------------------------------------------------------------------ // Name: create_binary_info_pe32 // Desc: //------------------------------------------------------------------------------ std::unique_ptr create_binary_info_pe32(const IRegion::pointer ®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-0.9.21/plugins/BinaryInfo/ELF64.h0000644000175000017500000000242712773027761020130 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 ELF64_20070718_H_ #define ELF64_20070718_H_ #include "IBinary.h" #include "elf_binary.h" namespace BinaryInfo { class ELF64 : public IBinary { public: ELF64(const IRegion::pointer ®ion); virtual ~ELF64(); public: virtual bool native() const; virtual bool validate_header(); 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; private: void read_header(); private: IRegion::pointer region_; elf64_header * header_; }; } #endif edb-debugger-0.9.21/plugins/BreakpointManager/0000755000175000017500000000000012773027761020523 5ustar eteraneteranedb-debugger-0.9.21/plugins/BreakpointManager/BreakpointManager.pro0000644000175000017500000000025212773027761024635 0ustar eteraneteran include(../plugins.pri) # Input HEADERS += BreakpointManager.h DialogBreakpoints.h FORMS += DialogBreakpoints.ui SOURCES += BreakpointManager.cpp DialogBreakpoints.cpp edb-debugger-0.9.21/plugins/BreakpointManager/DialogBreakpoints.ui0000644000175000017500000001104012773027761024457 0ustar eteraneteran Evan Teran BreakpointManager::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-0.9.21/plugins/BreakpointManager/DialogBreakpoints.cpp0000644000175000017500000002703412773027761024636 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 "edb.h" #include "MemoryRegions.h" #include #include #include #include #include #include #include #include #include #include "ui_DialogBreakpoints.h" namespace BreakpointManager { //------------------------------------------------------------------------------ // 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 IBreakpoint::pointer &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 quint8 orig_byte = bp->original_byte(); const bool onetime = bp->one_time(); const QString symname = edb::v1::find_function_symbol(address, QString(), 0); const QString bytes = edb::v1::format_bytes(orig_byte); 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 Symbol::pointer ¤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(); if(line.isNull()) { 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(); IRegion::pointer 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 IBreakpoint::pointer 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 IBreakpoint::pointer 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-0.9.21/plugins/BreakpointManager/BreakpointManager.h0000644000175000017500000000245612773027761024274 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 BreakpointManager { 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_; QDialog * dialog_; }; } #endif edb-debugger-0.9.21/plugins/BreakpointManager/CMakeLists.txt0000644000175000017500000000177312773027761023273 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-0.9.21/plugins/BreakpointManager/BreakpointManager.cpp0000644000175000017500000000427712773027761024632 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 BreakpointManager { //------------------------------------------------------------------------------ // 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-0.9.21/plugins/BreakpointManager/DialogBreakpoints.h0000644000175000017500000000261112773027761024275 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 BreakpointManager { 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-0.9.21/plugins/DebuggerCore/0000755000175000017500000000000012773027761017467 5ustar eteraneteranedb-debugger-0.9.21/plugins/DebuggerCore/unix/0000755000175000017500000000000012773027761020452 5ustar eteraneteranedb-debugger-0.9.21/plugins/DebuggerCore/unix/freebsd/0000755000175000017500000000000012773027761022064 5ustar eteraneteranedb-debugger-0.9.21/plugins/DebuggerCore/unix/freebsd/DebuggerCore.h0000644000175000017500000000611212773027761024572 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 IDebugEvent::const_pointer 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-0.9.21/plugins/DebuggerCore/unix/freebsd/PlatformProcess.cpp0000644000175000017500000000133512773027761025715 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-0.9.21/plugins/DebuggerCore/unix/freebsd/PlatformEvent.h0000644000175000017500000000311512773027761025023 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-0.9.21/plugins/DebuggerCore/unix/freebsd/PlatformRegion.h0000644000175000017500000000350212773027761025165 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-0.9.21/plugins/DebuggerCore/unix/freebsd/PlatformRegion.cpp0000644000175000017500000000450712773027761025526 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-0.9.21/plugins/DebuggerCore/unix/freebsd/PlatformProcess.h0000644000175000017500000000153112773027761025360 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-0.9.21/plugins/DebuggerCore/unix/freebsd/PlatformState.cpp0000644000175000017500000004644512773027761025372 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-0.9.21/plugins/DebuggerCore/unix/freebsd/PlatformState.h0000644000175000017500000000370512773027761025027 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-0.9.21/plugins/DebuggerCore/unix/freebsd/PlatformEvent.cpp0000644000175000017500000001731112773027761025361 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-0.9.21/plugins/DebuggerCore/unix/freebsd/DebuggerCore.cpp0000644000175000017500000004161612773027761025135 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 //------------------------------------------------------------------------------ IDebugEvent::const_pointer 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-0.9.21/plugins/DebuggerCore/unix/linux/0000755000175000017500000000000012773027761021611 5ustar eteraneteranedb-debugger-0.9.21/plugins/DebuggerCore/unix/linux/PlatformThread.cpp0000644000175000017500000003524012773027761025235 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 "PlatformState.h" #include "PlatformCommon.h" #include "IProcess.h" #include "DebuggerCore.h" #include "State.h" #include #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 DebuggerCore { //------------------------------------------------------------------------------ // Name: fillSegmentBases // Desc: //------------------------------------------------------------------------------ void PlatformThread::fillSegmentBases(PlatformState* state) { struct user_desc desc; std::memset(&desc, 0, sizeof(desc)); for(size_t sregIndex=0;sregIndexseg_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;sregIndexseg_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() && sregIndexx86.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) { if(prstat_iov.iov_len==sizeof(prstat64)) { state->fillFrom(prstat64); } else if(prstat_iov.iov_len==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); } else { 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: 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 { 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: step // Desc: steps this thread one instruction, passing the signal that stopped it // (unless the signal was SIGSTOP) //------------------------------------------------------------------------------ void PlatformThread::step() { 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) //------------------------------------------------------------------------------ void PlatformThread::step(edb::EVENT_STATUS status) { const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(status_) : 0; core_->ptrace_step(tid_, code); } //------------------------------------------------------------------------------ // Name: resume // Desc: resumes this thread, passing the signal that stopped it // (unless the signal was SIGSTOP) //------------------------------------------------------------------------------ void PlatformThread::resume() { 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) //------------------------------------------------------------------------------ void PlatformThread::resume(edb::EVENT_STATUS status) { const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(status_) : 0; core_->ptrace_continue(tid_, code); } //------------------------------------------------------------------------------ // Name: get_state // Desc: //------------------------------------------------------------------------------ void PlatformThread::get_state(State *state) { // TODO: assert that we are paused core_->detectDebuggeeBitness(); 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) fillStateFromSimpleRegs(state_impl); // 64-bit GETREGS call always returns 64-bit state, so use it 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 long ptraceStatus=0; // First try to get full XSTATE X86XState xstate; iovec iov={&xstate,sizeof(xstate)}; ptraceStatus=ptrace(PTRACE_GETREGSET, tid_, NT_X86_XSTATE, &iov); if(ptraceStatus==-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 ? true : false); 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 user_fpregs_struct fpregs; if((ptraceStatus=ptrace(PTRACE_GETFPREGS, tid_, 0, &fpregs))!=-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); 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) { 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]); static bool xsaveSupported=true; // hope for the best, adjust for reality if(xsaveSupported) { X86XState xstate; const auto size=state_impl->fillStruct(xstate); 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 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: stop // Desc: //------------------------------------------------------------------------------ void PlatformThread::stop() { syscall(SYS_tgkill, process_->pid(), tid_, SIGSTOP); // TODO(eteran): should this just be this? //::kill(tid_, SIGSTOP); } } edb-debugger-0.9.21/plugins/DebuggerCore/unix/linux/PlatformThread.h0000644000175000017500000000453512773027761024705 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 class IProcess; namespace DebuggerCore { class DebuggerCore; class PlatformState; class PlatformThread : public IThread { Q_DECLARE_TR_FUNCTIONS(PlatformThread) friend class DebuggerCore; public: typedef std::shared_ptr pointer; 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 void step() override; virtual void step(edb::EVENT_STATUS status) override; virtual void resume() override; virtual void resume(edb::EVENT_STATUS status) override; virtual void stop() override; private: void fillSegmentBases(PlatformState* state); bool fillStateFromPrStatus(PlatformState* state); bool fillStateFromSimpleRegs(PlatformState* state); 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_; }; } #endif edb-debugger-0.9.21/plugins/DebuggerCore/unix/linux/DebuggerCore.h0000644000175000017500000000672212773027761024326 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 "PlatformState.h" #include "PlatformThread.h" #include #include #include #include /* For SYS_xxx definitions */ #include class IBinary; namespace DebuggerCore { 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; public: DebuggerCore(); virtual ~DebuggerCore(); public: virtual std::size_t pointer_size() const override; virtual edb::address_t page_size() const; virtual bool has_extension(quint64 ext) const; virtual IDebugEvent::const_pointer wait_debug_event(int msecs); virtual QString attach(edb::pid_t pid) override; virtual void detach(); virtual void kill(); virtual void get_state(State *state); virtual void set_state(const State &state); virtual QString open(const QString &path, const QString &cwd, const QList &args, const QString &tty) override; virtual MeansOfCapture last_means_of_capture() override; public: virtual edb::pid_t parent_pid(edb::pid_t pid) const; public: virtual IState *create_state() const; public: virtual quint64 cpu_type() const; private: virtual QMap enumerate_processes() const; public: virtual QString stack_pointer() const; virtual QString frame_pointer() const; virtual QString instruction_pointer() const; virtual QString flag_register() const; public: virtual QString format_pointer(edb::address_t address) const; public: virtual IProcess *process() const; private: long ptrace_getsiginfo(edb::tid_t tid, siginfo_t *siginfo); long ptrace_continue(edb::tid_t tid, long status); long ptrace_step(edb::tid_t tid, long status); long ptrace_set_options(edb::tid_t tid, long options); long ptrace_get_event_message(edb::tid_t tid, unsigned long *message); long ptrace_traceme(); private: void reset(); void stop_threads(); IDebugEvent::const_pointer handle_event(edb::tid_t tid, int status); int attach_thread(edb::tid_t tid); void detectDebuggeeBitness(); 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_; 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; MeansOfCapture lastMeansOfCapture=MeansOfCapture::NeverCaptured; }; } #endif edb-debugger-0.9.21/plugins/DebuggerCore/unix/linux/PlatformProcess.cpp0000644000175000017500000005507112773027761025450 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 "PlatformCommon.h" #include "PlatformRegion.h" #include "MemoryRegions.h" #include "edb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include // auto-generated #include "procPidMemWrites.h" namespace DebuggerCore { namespace { // Used as size of ptrace word #define EDB_WORDSIZE sizeof(long) namespace BinaryInfo { // Bitness-templated version of struct r_debug defined in link.h template struct r_debug { int r_version; Addr r_map; // struct link_map* Addr r_brk; enum { RT_CONSISTENT, RT_ADD, RT_DELETE } r_state; Addr r_ldbase; }; // Bitness-templated version of struct link_map defined in link.h template struct link_map { Addr l_addr; Addr l_name; // char* Addr l_ld; // ElfW(Dyn)* Addr l_next, l_prev; // struct link_map* }; } void set_ok(bool &ok, long value) { ok = (value != -1) || (errno == 0); } //------------------------------------------------------------------------------ // Name: process_map_line // Desc: parses the data from a line of a memory map file //------------------------------------------------------------------------------ IRegion::pointer 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 = line.split(" ", QString::SkipEmptyParts); 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_) { BinaryInfo::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) { BinaryInfo::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 IRegion::pointer ®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) { } //------------------------------------------------------------------------------ // Name: ~PlatformProcess // Desc: //------------------------------------------------------------------------------ PlatformProcess::~PlatformProcess() { } //------------------------------------------------------------------------------ // 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); if(len != 0) { // small reads take the fast path if(len == 1) { auto it = core_->breakpoints_.find(address); if(it != core_->breakpoints_.end()) { *reinterpret_cast(buf) = (*it)->original_byte(); return 1; } bool ok; quint8 x = read_byte(address, &ok); if(ok) { *reinterpret_cast(buf) = x; return 1; } return 0; } QFile memory_file(QString("/proc/%1/mem").arg(pid_)); if(memory_file.open(QIODevice::ReadOnly)) { seek_addr(memory_file,address); read = memory_file.read(reinterpret_cast(buf), len); if(read == 0 || read == quint64(-1)) return 0; for(const IBreakpoint::pointer &bp: core_->breakpoints_) { if(bp->address() >= address && bp->address() < (address + read)) { // show the original bytes in the buffer.. reinterpret_cast(buf)[bp->address() - address] = bp->original_byte(); } } memory_file.close(); } } return read; } //------------------------------------------------------------------------------ // 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) { // small writes take the fast path if(len == 1) { bool ok; write_byte(address, *reinterpret_cast(buf), &ok); return ok ? 1 : 0; } QFile memory_file(QString("/proc/%1/mem").arg(pid_)); // NOTE: If buffered, it may not report any write errors, behaving as if it succeeded if(!PROC_PID_MEM_WRITE_BROKEN && memory_file.open(QIODevice::WriteOnly|QIODevice::Unbuffered)) { seek_addr(memory_file,address); written = memory_file.write(reinterpret_cast(buf), len); if(written == 0 || written == quint64(-1)) { return 0; } memory_file.close(); } else { 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 == '\0') { 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: //------------------------------------------------------------------------------ IProcess::pointer 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(IRegion::pointer 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(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 = read_data(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 // Note: assumes the this will not trample any breakpoints, must be handled // in calling code! //------------------------------------------------------------------------------ void PlatformProcess::write_byte(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 = read_data(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 = write_data(address, word); } //------------------------------------------------------------------------------ // Name: read_data // 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::read_data(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, try reading /proc/$PID/mem // FIXME: this is slow. Try keeping the file open, not reopening it on each read. QFile memory_file(QString("/proc/%1/mem").arg(pid_)); if(memory_file.open(QIODevice::ReadOnly)) { seek_addr(memory_file,address); long value; if(memory_file.read(reinterpret_cast(&value), sizeof(long))==sizeof(long)) { *ok=true; return value; } } 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: write_data // Desc: //------------------------------------------------------------------------------ bool PlatformProcess::write_data(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 QFile memory_file(QString("/proc/%1/mem").arg(pid_)); if(memory_file.open(QIODevice::WriteOnly|QIODevice::Unbuffered)) { // If buffered, it may not report any errors as if it succeeded seek_addr(memory_file,address); if(memory_file.write(reinterpret_cast(&value), sizeof(long))==sizeof(long)) return true; } return false; } // 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: //------------------------------------------------------------------------------ IThread::pointer 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 IThread::pointer(); } //------------------------------------------------------------------------------ // 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 //------------------------------------------------------------------------------ void 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. ::kill(pid_, SIGSTOP); } //------------------------------------------------------------------------------ // Name: resume // Desc: resumes ALL threads //------------------------------------------------------------------------------ void PlatformProcess::resume(edb::EVENT_STATUS status) { // TODO: assert that we are paused Q_ASSERT(core_->process_ == this); if(status != edb::DEBUG_STOP) { if(IThread::pointer thread = current_thread()) { thread->resume(status); // resume the other threads passing the signal they originally reported had for(auto &other_thread : threads()) { if(core_->waited_threads_.contains(other_thread->tid())) { other_thread->resume(); } } } } } //------------------------------------------------------------------------------ // Name: step // Desc: steps the currently active thread //------------------------------------------------------------------------------ void PlatformProcess::step(edb::EVENT_STATUS status) { // TODO: assert that we are paused Q_ASSERT(core_->process_ == this); if(status != edb::DEBUG_STOP) { if(IThread::pointer thread = current_thread()) { thread->step(status); } } } } edb-debugger-0.9.21/plugins/DebuggerCore/unix/linux/PlatformEvent.h0000644000175000017500000000370212773027761024552 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 DebuggerCore { 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-0.9.21/plugins/DebuggerCore/unix/linux/PlatformRegion.h0000644000175000017500000000373012773027761024715 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) 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-0.9.21/plugins/DebuggerCore/unix/linux/PlatformRegion.cpp0000644000175000017500000003014112773027761025244 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 { 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); 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 IDebugEvent::const_pointer &event); public: QAtomicInt lock_; edb::address_t address_; IRegion::permissions_t premissions_; State state_; quint8 buffer_[N]; PlatformRegion *const region_; public: IDebugEventHandler *event_handler_; }; //------------------------------------------------------------------------------ // Name: BackupInfo // Desc: //------------------------------------------------------------------------------ template BackupInfo::BackupInfo(edb::address_t address, IRegion::permissions_t perms, PlatformRegion *region) : lock_(1), address_(address), premissions_(perms), region_(region), event_handler_(0) { } //------------------------------------------------------------------------------ // Name: backup // Desc: //------------------------------------------------------------------------------ template bool BackupInfo::backup() { if(IProcess *process = edb::v1::debugger_core->process()) { if(IThread::pointer 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(IThread::pointer 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 IDebugEvent::const_pointer &event) { Q_UNUSED(event); lock_.testAndSetRelease(1, 0); // restore the original code and register state restore(); // update permissions mask region_->permissions_ = perms(); // restore the event handler edb::v1::set_debug_event_handler(event_handler_); // 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 IRegion::pointer ®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 IRegion::pointer"), 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(IThread::pointer 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); backup_info.event_handler_ = edb::v1::set_debug_event_handler(&backup_info); // 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-0.9.21/plugins/DebuggerCore/unix/linux/PlatformProcess.h0000644000175000017500000000524112773027761025107 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" namespace DebuggerCore { 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; virtual QList arguments() const; virtual QString current_working_directory() const; virtual QString executable() const; virtual edb::pid_t pid() const; virtual IProcess::pointer parent() const; virtual edb::address_t code_address() const; virtual edb::address_t data_address() const; virtual QList regions() const; virtual QList threads() const; virtual IThread::pointer current_thread() const; virtual edb::uid_t uid() const; virtual QString user() const; virtual QString name() const; virtual QList loaded_modules() const; public: virtual void pause(); virtual void resume(edb::EVENT_STATUS status); virtual void step(edb::EVENT_STATUS status); public: virtual std::size_t write_bytes(edb::address_t address, const void *buf, size_t len); virtual std::size_t read_bytes(edb::address_t address, void *buf, size_t len) const; virtual std::size_t read_pages(edb::address_t address, void *buf, size_t count) const; private: bool write_data(edb::address_t address, long value); long read_data(edb::address_t address, bool *ok) const; void write_byte(edb::address_t address, quint8 value, bool *ok); quint8 read_byte(edb::address_t address, bool *ok) const; private: DebuggerCore* core_; edb::pid_t pid_; }; } #endif edb-debugger-0.9.21/plugins/DebuggerCore/unix/linux/PlatformState.cpp0000644000175000017500000012462312773027761025112 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 "Util.h" #include "FloatX.h" #include #include #include namespace DebuggerCore { 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& regs) { // 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; } std::size_t PlatformState::X87::stackPointer() const { return (statusWord&0x3800)>>11; } std::size_t PlatformState::X87::RIndexToSTIndex(std::size_t n) const { n=(n+8-stackPointer()) % 8; return n; } std::size_t PlatformState::X87::STIndexToRIndex(std::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(std::size_t n) const { return R[STIndexToRIndex(n)]; } edb::value80& PlatformState::X87::st(std::size_t n) { return R[STIndexToRIndex(n)]; } int PlatformState::X87::makeTag(std::size_t n, uint16_t twd) const { int minitag=(twd>>n)&0x1; return minitag ? recreateTag(R[n]) : TAG_EMPTY; } int PlatformState::X87::tag(std::size_t n) const { return (tagWord>>(2*n)) & 0x3; } edb::value16 PlatformState::X87::restoreTagWord(uint16_t twd) const { uint16_t tagWord=0; for(std::size_t n=0;n>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& regs) { x87.statusWord=regs.swd; // should be first for RIndexToSTIndex() to work for(std::size_t n=0;n(&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(std::size_t n=0;n(regs.st_space)+10*x87.RIndexToSTIndex(n),&x87.R[n],sizeof(x87.R[n])); } } void PlatformState::fillStruct(UserFPRegsStructX86_64& regs) 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(std::size_t n=0;n(regs.st_space)+16*x87.RIndexToSTIndex(n),&x87.R[n],sizeof(x87.R[n])); if(avx.xmmFilledIA32||avx.xmmFilledAMD64) { for(std::size_t n=0;n(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& regs) 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(std::size_t n=0;n(®s.st_space)+16*x87.RIndexToSTIndex(n),&x87.R[n],sizeof x87.R[n]); } if(avx.xmmFilledIA32) { regs.mxcsr=avx.mxcsr; for(std::size_t n=0;n(®s.xmm_space)+16*n,&avx.zmmStorage[n],sizeof(edb::value128)); } } size_t PlatformState::fillStruct(X86XState& regs) 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(®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(®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(®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(std::size_t index) const { return edb::value128(zmmStorage[index]); } edb::value256 PlatformState::AVX::ymm(std::size_t index) const { return edb::value256(zmmStorage[index]); } edb::value512 PlatformState::AVX::zmm(std::size_t index) const { return zmmStorage[index]; } void PlatformState::AVX::setXMM(std::size_t index, edb::value128 value) { // leave upper part unchanged. std::memcpy(&zmmStorage[index],&value,sizeof value); } void PlatformState::AVX::setYMM(std::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(std::size_t index, edb::value256 value) { // leave upper part unchanged. std::memcpy(&zmmStorage[index],&value,sizeof value); } void PlatformState::AVX::setZMM(std::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& regs, const QString& regName, 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; if(x86.gpr32Filled) // don't return valid Register with garbage value { 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(); std::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(); std::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(); std::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(); std::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; std::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; std::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 stack_pointer(); } //------------------------------------------------------------------------------ // 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(std::size_t n) const { return x87.tag(n)==X87::TAG_EMPTY; } //------------------------------------------------------------------------------ // Name: fpu_register_tag_string // Desc: //------------------------------------------------------------------------------ QString PlatformState::fpu_register_tag_string(std::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(x86.GPReg32Names[n], x86.GPRegs[n], Register::TYPE_GPR); } return Register(); } //------------------------------------------------------------------------------ // Name: set_register // Desc: //------------------------------------------------------------------------------ void PlatformState::set_register(const Register& reg) { const QString regName = reg.name().toLower(); const auto gpr_end=GPRegNames().begin()+gpr_count(); auto GPRegNameFoundIter=std::find(GPRegNames().begin(), gpr_end, regName); if(GPRegNameFoundIter!=gpr_end) { std::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()) { std::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(); std::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(); std::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(); std::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; std::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; std::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(); std::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-0.9.21/plugins/DebuggerCore/unix/linux/PlatformState.h0000644000175000017500000003606012773027761024554 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 #include "edb.h" namespace DebuggerCore { 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 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!"); // 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 std::size_t XSAVE_NONEXTENDED_SIZE=576; static constexpr std::size_t SSE_SIZE=XSAVE_NONEXTENDED_SIZE; static constexpr std::size_t AVX_SIZE=832; static constexpr std::size_t BNDREGS_SIZE=1024; static constexpr std::size_t BNDCFG_SIZE=1088; static constexpr std::size_t AVX512_SIZE=2688; static constexpr std::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(std::size_t n) const; virtual QString fpu_register_tag_string(std::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& reg); 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 { 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; 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); static constexpr const char* mxcsrName="mxcsr"; } avx; // x87 state struct X87 { 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; void clear(); bool empty() const; std::size_t stackPointer() const; // Convert from ST(n) index n to Rx index x std::size_t RIndexToSTIndex(std::size_t index) const; std::size_t STIndexToRIndex(std::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(std::size_t n) const; edb::value80 st(std::size_t n) const; edb::value80& st(std::size_t n); enum Tag { TAG_VALID=0, TAG_ZERO=1, TAG_SPECIAL=2, TAG_EMPTY=3 }; private: int recreateTag(const edb::value80 value) const; int makeTag(std::size_t n, uint16_t twd) const; } x87; // i386-inherited (and expanded on x86_64) state struct X86 { 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; void clear(); bool empty() const; enum GPRIndex : std::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 : std::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; } x86; bool dbgIndexValid(size_t n) const { return n. */ #include "PlatformEvent.h" #include "edb.h" namespace DebuggerCore { //------------------------------------------------------------------------------ // 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-0.9.21/plugins/DebuggerCore/unix/linux/detect/0000755000175000017500000000000012773027761023061 5ustar eteraneteranedb-debugger-0.9.21/plugins/DebuggerCore/unix/linux/detect/proc-pid-mem-write.cpp0000644000175000017500000001132312773027761027206 0ustar eteraneteran #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include enum Method { Detected, UserSet, TestFailed }; // 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; } }; static const char *headerName = nullptr; bool headerUpToDate(std::string const &line) { std::ifstream file(headerName); if (!file) return false; // Try to read one char more than the line has to check that actual size of file is correct std::string fileStr(line.length() + 1, 0); if (file.readsome(&fileStr[0], fileStr.length()) != signed(line.length())) return false; fileStr.resize(line.length()); return fileStr == line; } void writeHeader(bool broken, Method method) { std::ostringstream line; line << "#define PROC_PID_MEM_WRITE_BROKEN " << std::boolalpha << broken; switch(method) { case Detected: line << " /* Method = Detected */"; break; case UserSet: line << " /* Method = User Set */"; break; case TestFailed: line << " /* Method = Failed To Test */"; break; } line << "\n"; if (headerUpToDate(line.str())) { return; } std::ofstream file(headerName); file << line.str(); } void killChild(int pid, std::string const &progName) { if (kill(pid, SIGKILL) == -1) { perror((progName + ": warning: failed to kill child").c_str()); } } bool detectAndWriteHeader(std::string progName) { switch (pid_t pid = fork()) { case 0: if (ptrace(PTRACE_TRACEME) < 0) { perror((progName + ": child: PTRACE_TRACEME failed").c_str()); abort(); } execl(progName.c_str(), progName.c_str(), "/dev/null", "--child", nullptr); perror((progName + "child: execl() returned").c_str()); abort(); case -1: perror("fork"); return false; default: { int status; if (waitpid(pid, &status, __WALL) == -1) { perror((progName + ": parent: waitpid failed").c_str()); killChild(pid, progName); return false; } if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) { std::cerr << progName << ": unexpected status returned by waitpid: 0x" << std::hex << status << "\n"; killChild(pid, progName); return false; } File file("/proc/" + std::to_string(pid) + "/mem"); if (!file) { perror((progName + ": failed to open memory file").c_str()); killChild(pid, progName); return false; } const auto pageAlignMask = ~(sysconf(_SC_PAGESIZE) - 1); const auto addr = reinterpret_cast(&detectAndWriteHeader) & pageAlignMask; file.seekp(addr); if (!file) { perror((progName + ": failed to seek to address to read").c_str()); killChild(pid, progName); return false; } int buf = 0x12345678; { file.read(&buf, sizeof(buf)); if (!file) { perror((progName + ": failed to read data from child's memory, won't even try to write").c_str()); killChild(pid, progName); return false; } } file.seekp(addr); if (!file) { perror((progName + ": failed to seek to address to write").c_str()); killChild(pid, progName); return false; } { file.write(&buf, sizeof(buf)); if (!file) { writeHeader(true, Detected); } else { writeHeader(false, Detected); } } killChild(pid, progName); return true; } } } int main(int argc, char **argv) { if (argc == 3) { if(strcmp(argv[2], "--child") == 0) { for (;;) { sleep(10); } abort(); } else if(strcmp(argv[2], "--assume-bad") == 0) { headerName = argv[1]; writeHeader(true, UserSet); return 0; } else if(strcmp(argv[2], "--assume-good") == 0) { headerName = argv[1]; writeHeader(false, UserSet); return 0; } } if (argc != 2) { std::cerr << "Usage: " << argv[0] << " headerFileName.h [--assume-bad|--assume-good]\n"; return 1; } headerName = argv[1]; if (!detectAndWriteHeader(argv[0])) { std::cerr << "Warning: failed to detect whether write to /proc/PID/mem is broken. Assuming it's not.\n"; writeHeader(false, TestFailed); } } edb-debugger-0.9.21/plugins/DebuggerCore/unix/linux/PlatformCommon.cpp0000644000175000017500000000722312773027761025256 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 namespace DebuggerCore { //------------------------------------------------------------------------------ // 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()) { 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); } 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-0.9.21/plugins/DebuggerCore/unix/linux/PlatformCommon.h0000644000175000017500000000533012773027761024720 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" class QString; namespace DebuggerCore { 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-0.9.21/plugins/DebuggerCore/unix/linux/DebuggerCore.cpp0000644000175000017500000006524512773027761024666 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 "edb.h" #include "Configuration.h" #include "MemoryRegions.h" #include "PlatformEvent.h" #include "PlatformRegion.h" #include "PlatformState.h" #include "PlatformProcess.h" #include "PlatformCommon.h" #include "State.h" #include "string_hash.h" #include #include #include #include #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_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 namespace DebuggerCore { 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) { if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { return (((status >> 16) & 0xffff) == PTRACE_EVENT_CLONE); } return false; } 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; } } //------------------------------------------------------------------------------ // Name: DebuggerCore // Desc: constructor //------------------------------------------------------------------------------ DebuggerCore::DebuggerCore() : binary_info_(nullptr), process_(0), pointer_size_(sizeof(void*)), 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) { qDebug() << "EDB is in" << (edbIsIn64BitSegment?"64":"32") << "bit segment"; qDebug() << "OS is" << (osIs64Bit?"64":"32") << "bit"; } //------------------------------------------------------------------------------ // Name: has_extension // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::has_extension(quint64 ext) const { const auto mmxHash=edb::string_hash("MMX"); const auto xmmHash=edb::string_hash("XMM"); const 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; } 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: //------------------------------------------------------------------------------ long DebuggerCore::ptrace_getsiginfo(edb::tid_t tid, siginfo_t *siginfo) { Q_ASSERT(siginfo != 0); return ptrace(PTRACE_GETSIGINFO, tid, 0, siginfo); } //------------------------------------------------------------------------------ // Name: ptrace_traceme // Desc: //------------------------------------------------------------------------------ long DebuggerCore::ptrace_traceme() { return ptrace(PTRACE_TRACEME, 0, 0, 0); } //------------------------------------------------------------------------------ // Name: ptrace_continue // Desc: //------------------------------------------------------------------------------ long 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(waited_threads_.contains(tid)); Q_ASSERT(tid != 0); waited_threads_.remove(tid); return ptrace(PTRACE_CONT, tid, 0, status); } return -1; } //------------------------------------------------------------------------------ // Name: ptrace_step // Desc: //------------------------------------------------------------------------------ long 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(waited_threads_.contains(tid)); Q_ASSERT(tid != 0); waited_threads_.remove(tid); return ptrace(PTRACE_SINGLESTEP, tid, 0, status); } return -1; } //------------------------------------------------------------------------------ // Name: ptrace_set_options // Desc: //------------------------------------------------------------------------------ long DebuggerCore::ptrace_set_options(edb::tid_t tid, long options) { Q_ASSERT(waited_threads_.contains(tid)); Q_ASSERT(tid != 0); return ptrace(PTRACE_SETOPTIONS, tid, 0, options); } //------------------------------------------------------------------------------ // Name: ptrace_get_event_message // Desc: //------------------------------------------------------------------------------ long 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); return ptrace(PTRACE_GETEVENTMSG, tid, 0, message); } //------------------------------------------------------------------------------ // Name: handle_event // Desc: //------------------------------------------------------------------------------ IDebugEvent::const_pointer 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)) { threads_.remove(tid); waited_threads_.remove(tid); // 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; } } // was it a thread create event? if(is_clone_event(status)) { unsigned long new_tid; if(ptrace_get_event_message(tid, &new_tid) != -1) { 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); } } if(!WIFSTOPPED(thread_status) || WSTOPSIG(thread_status) != SIGSTOP) { qDebug("handle_event(): [warning] 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_) == -1) { // TODO: handle no info? } active_thread_ = tid; auto it = threads_.find(tid); if(it != threads_.end()) { it.value()->status_ = status; } stop_threads(); return e; } //------------------------------------------------------------------------------ // Name: stop_threads // Desc: //------------------------------------------------------------------------------ void DebuggerCore::stop_threads() { 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)) { thread->stop(); int thread_status; if(native::waitpid(tid, &thread_status, __WALL) > 0) { waited_threads_.insert(tid); thread_ptr->status_ = thread_status; if(!WIFSTOPPED(thread_status) || WSTOPSIG(thread_status) != SIGSTOP) { qDebug("stop_threads(): [warning] paused thread [%d] received an event besides SIGSTOP: status=0x%x", tid,thread_status); } } } } } } } //------------------------------------------------------------------------------ // Name: wait_debug_event // Desc: waits for a debug event, msecs is a timeout // it will return false if an error or timeout occurs //------------------------------------------------------------------------------ IDebugEvent::const_pointer 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); if(ptrace_set_options(tid, PTRACE_O_TRACECLONE) == -1) { qDebug("[DebuggerCore] failed to set PTRACE_O_TRACECLONE: [%d] %s", tid, strerror(errno)); } if(edb::v1::config().close_behavior==Configuration::Kill || (edb::v1::config().close_behavior==Configuration::KillIfLaunchedDetachIfAttached && last_means_of_capture()==MeansOfCapture::Launch)) { if(ptrace_set_options(tid, PTRACE_O_EXITKILL) == -1) { qDebug("[DebuggerCore] failed to set PTRACE_O_EXITKILL: [%d] %s", tid, strerror(errno)); } } return 0; } else if(ret==-1) { return errno; } else return -1; // unknown error } else return errno; } //------------------------------------------------------------------------------ // Name: attach // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::attach(edb::pid_t pid) { static const QString statusOK{}; 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) return 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()); detectDebuggeeBitness(); return statusOK; } else { delete process_; process_ = nullptr; } return std::strerror(lastErr); } //------------------------------------------------------------------------------ // Name: detach // Desc: //------------------------------------------------------------------------------ void DebuggerCore::detach() { if(process_) { stop_threads(); clear_breakpoints(); for(auto thread: process_->threads()) { ptrace(PTRACE_DETACH, thread->tid(), 0, 0); } delete process_; process_ = nullptr; reset(); } } //------------------------------------------------------------------------------ // Name: kill // Desc: //------------------------------------------------------------------------------ void DebuggerCore::kill() { if(attached()) { clear_breakpoints(); ::kill(pid(), SIGKILL); // TODO: do i need to actually do this wait? native::waitpid(pid(), 0, __WALL); delete process_; process_ = 0; reset(); } } void DebuggerCore::detectDebuggeeBitness() { 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"; CapstoneEDB::init(false); } pointer_size_=sizeof(quint32); return; } else if(cs==USER_CS_64) { if(pointer_size_==sizeof(quint32)) { qDebug() << "Debuggee is now 64 bit"; CapstoneEDB::init(true); } pointer_size_=sizeof(quint64); return; } } } //------------------------------------------------------------------------------ // Name: get_state // Desc: //------------------------------------------------------------------------------ void DebuggerCore::get_state(State *state) { // TODO: assert that we are paused if(process_) { if(IThread::pointer 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(IThread::pointer thread = process_->current_thread()) { thread->set_state(state); } } } //------------------------------------------------------------------------------ // Name: open // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::open(const QString &path, const QString &cwd, const QList &args, const QString &tty) { static const QString statusOK{}; 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 QString error=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 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 QObject::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 QObject::tr("waitpid() failed: %1").arg(std::strerror(errno))+(childError.isEmpty()?"":QObject::tr(".\nError returned by child:\n%1.").arg(childError)); if(WIFEXITED(status)) return QObject::tr("The child unexpectedly exited with code %1. Error returned by child:\n%2").arg(WEXITSTATUS(status)).arg(childError); if(WIFSIGNALED(status)) return QObject::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 childError.isEmpty() ? QObject::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 QObject::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()?"":QObject::tr(".\nError returned by child:\n%1.").arg(childError)); } waited_threads_.insert(pid); // enable following clones (threads) if(ptrace_set_options(pid, PTRACE_O_TRACECLONE) == -1) { const auto strerr=strerror(errno); // NOTE: must be called before end_debug_session, otherwise errno can change end_debug_session(); return QObject::tr("[DebuggerCore] failed to set PTRACE_O_TRACECLONE: %1").arg(strerr); } #ifdef PTRACE_O_EXITKILL if(ptrace_set_options(pid, PTRACE_O_EXITKILL) == -1) { const auto strerr=strerror(errno); // NOTE: must be called before any other syscall, otherwise errno can change // Don't consider the error fatal: the option is only supported since Linux 3.8 qDebug() << "[DebuggerCore] failed to set PTRACE_O_EXITKILL:" << strerr; } #endif // setup the first event data for the primary thread waited_threads_.insert(pid); // 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()); detectDebuggeeBitness(); return statusOK; } 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() { 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(EDB_IS_32_BIT) return edb::string_hash("x86"); else return edb::string_hash("x86-64"); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::format_pointer(edb::address_t address) const { return address.toPointerString(); } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::stack_pointer() const { if(edb::v1::debuggeeIs32Bit()) return "esp"; else return "rsp"; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::frame_pointer() const { if(edb::v1::debuggeeIs32Bit()) return "ebp"; else return "rbp"; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QString DebuggerCore::instruction_pointer() const { if(edb::v1::debuggeeIs32Bit()) return "eip"; else return "rip"; } //------------------------------------------------------------------------------ // Name: flag_register // Desc: Returns the name of the flag register as a QString. //------------------------------------------------------------------------------ QString DebuggerCore::flag_register() const { if(edb::v1::debuggeeIs32Bit()) return "eflags"; else return "rflags"; } //------------------------------------------------------------------------------ // Name: process // Desc: //------------------------------------------------------------------------------ IProcess *DebuggerCore::process() const { return process_; } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(DebuggerCore, DebuggerCore) #endif } edb-debugger-0.9.21/plugins/DebuggerCore/unix/openbsd/0000755000175000017500000000000012773027761022104 5ustar eteraneteranedb-debugger-0.9.21/plugins/DebuggerCore/unix/openbsd/DebuggerCore.h0000644000175000017500000000611312773027761024613 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 IDebugEvent::const_pointer 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-0.9.21/plugins/DebuggerCore/unix/openbsd/PlatformProcess.cpp0000644000175000017500000000133512773027761025735 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-0.9.21/plugins/DebuggerCore/unix/openbsd/PlatformEvent.h0000644000175000017500000000311512773027761025043 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-0.9.21/plugins/DebuggerCore/unix/openbsd/PlatformRegion.h0000644000175000017500000000350412773027761025207 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-0.9.21/plugins/DebuggerCore/unix/openbsd/PlatformRegion.cpp0000644000175000017500000000450712773027761025546 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-0.9.21/plugins/DebuggerCore/unix/openbsd/PlatformProcess.h0000644000175000017500000000153112773027761025400 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-0.9.21/plugins/DebuggerCore/unix/openbsd/PlatformState.cpp0000644000175000017500000004644612773027761025413 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-0.9.21/plugins/DebuggerCore/unix/openbsd/PlatformState.h0000644000175000017500000000370612773027761025050 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-0.9.21/plugins/DebuggerCore/unix/openbsd/PlatformEvent.cpp0000644000175000017500000001734212773027761025405 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-0.9.21/plugins/DebuggerCore/unix/openbsd/DebuggerCore.cpp0000644000175000017500000005351312773027761025154 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 //------------------------------------------------------------------------------ IDebugEvent::const_pointer 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-0.9.21/plugins/DebuggerCore/unix/DebuggerCoreUNIX.h0000644000175000017500000000304312773027761023664 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 #include namespace DebuggerCore { 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() {} protected: QString execute_process(const QString &path, const QString &cwd, const QList &args); public: virtual QMap exceptions() const; }; } #endif edb-debugger-0.9.21/plugins/DebuggerCore/unix/osx/0000755000175000017500000000000012773027761021263 5ustar eteraneteranedb-debugger-0.9.21/plugins/DebuggerCore/unix/osx/DebuggerCore.h0000644000175000017500000000611312773027761023772 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 IDebugEvent::const_pointer 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-0.9.21/plugins/DebuggerCore/unix/osx/PlatformProcess.cpp0000644000175000017500000000133512773027761025114 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-0.9.21/plugins/DebuggerCore/unix/osx/PlatformEvent.h0000644000175000017500000000302712773027761024224 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-0.9.21/plugins/DebuggerCore/unix/osx/PlatformRegion.h0000644000175000017500000000350312773027761024365 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-0.9.21/plugins/DebuggerCore/unix/osx/PlatformRegion.cpp0000644000175000017500000000450712773027761024725 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-0.9.21/plugins/DebuggerCore/unix/osx/PlatformProcess.h0000644000175000017500000000153212773027761024560 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-0.9.21/plugins/DebuggerCore/unix/osx/PlatformState.cpp0000644000175000017500000005424712773027761024570 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-0.9.21/plugins/DebuggerCore/unix/osx/PlatformState.h0000644000175000017500000000430112773027761024217 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-0.9.21/plugins/DebuggerCore/unix/osx/PlatformEvent.cpp0000644000175000017500000001673512773027761024571 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-0.9.21/plugins/DebuggerCore/unix/osx/DebuggerCore.cpp0000644000175000017500000006042312773027761024331 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 //------------------------------------------------------------------------------ IDebugEvent::const_pointer 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-0.9.21/plugins/DebuggerCore/unix/DebuggerCoreUNIX.cpp0000644000175000017500000002402212773027761024217 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 #ifdef __linux__ #include // being very conservative for now, technicall this could be // as low as 2.6.22 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) #define USE_SIGTIMEDWAIT #endif #endif namespace DebuggerCore { #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 if it is necessary for this use case... #endif } //------------------------------------------------------------------------------ // Name: execute_process // Desc: tries to execute the process, returns error string on error //------------------------------------------------------------------------------ QString 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 = 0; // 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; } } return errorString; } //------------------------------------------------------------------------------ // Name: // Desc: //------------------------------------------------------------------------------ QMap DebuggerCoreUNIX::exceptions() const { QMap exceptions; #ifdef SIGABRT exceptions[SIGABRT] = "SIGABRT"; #endif #ifdef SIGALRM exceptions[SIGALRM] = "SIGALRM"; #endif #ifdef SIGVTALRM exceptions[SIGVTALRM] = "SIGVTALRM"; #endif #ifdef SIGPROF exceptions[SIGPROF] = "SIGPROF"; #endif #ifdef SIGBUS exceptions[SIGBUS] = "SIGBUS"; #endif #ifdef SIGCHLD exceptions[SIGCHLD] = "SIGCHLD"; #endif #ifdef SIGCONT exceptions[SIGCONT] = "SIGCONT"; #endif #ifdef SIGFPE exceptions[SIGFPE] = "SIGFPE"; #endif #ifdef SIGHUP exceptions[SIGHUP] = "SIGHUP"; #endif #ifdef SIGILL exceptions[SIGILL] = "SIGILL"; #endif #ifdef SIGINT exceptions[SIGINT] = "SIGINT"; #endif #ifdef SIGKILL exceptions[SIGKILL] = "SIGKILL"; #endif #ifdef SIGPIPE exceptions[SIGPIPE] = "SIGPIPE"; #endif #ifdef SIGQUIT exceptions[SIGQUIT] = "SIGQUIT"; #endif #ifdef SIGSEGV exceptions[SIGSEGV] = "SIGSEGV"; #endif #ifdef SIGSTOP exceptions[SIGSTOP] = "SIGSTOP"; #endif #ifdef SIGTERM exceptions[SIGTERM] = "SIGTERM"; #endif #ifdef SIGTSTP exceptions[SIGTSTP] = "SIGTSTP"; #endif #ifdef SIGTTIN exceptions[SIGTTIN] = "SIGTTIN"; #endif #ifdef SIGTTOU exceptions[SIGTTOU] = "SIGTTOU"; #endif #ifdef SIGUSR1 exceptions[SIGUSR1] = "SIGUSR1"; #endif #ifdef SIGUSR2 exceptions[SIGUSR2] = "SIGUSR2"; #endif #ifdef SIGPOLL exceptions[SIGPOLL] = "SIGPOLL"; #endif #ifdef SIGSYS exceptions[SIGSYS] = "SIGSYS"; #endif #ifdef SIGTRAP exceptions[SIGTRAP] = "SIGTRAP"; #endif #ifdef SIGURG exceptions[SIGURG] = "SIGURG"; #endif #ifdef SIGXCPU exceptions[SIGXCPU] = "SIGXCPU"; #endif #ifdef SIGXFSZ exceptions[SIGXFSZ] = "SIGXFSZ"; #endif #ifdef SIGRTMIN exceptions[SIGRTMIN] = "SIGRTMIN"; #endif #ifdef SIGRTMAX exceptions[SIGRTMAX] = "SIGRTMAX"; #endif #ifdef SIGIO exceptions[SIGIO] = "SIGIO"; #endif #ifdef SIGSTKFLT exceptions[SIGSTKFLT] = "SIGSTKFLT"; #endif #ifdef SIGWINCH exceptions[SIGWINCH] = "SIGWINCH"; #endif return exceptions; } } edb-debugger-0.9.21/plugins/DebuggerCore/win32/0000755000175000017500000000000012773027761020431 5ustar eteraneteranedb-debugger-0.9.21/plugins/DebuggerCore/win32/DebuggerCore.h0000644000175000017500000000661512773027761023147 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 namespace DebuggerCore { class DebuggerCore : public DebuggerCoreBase { Q_OBJECT 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 IDebugEvent::const_pointer 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); 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; 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; 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; 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_; }; } #endif edb-debugger-0.9.21/plugins/DebuggerCore/win32/PlatformProcess.cpp0000644000175000017500000000133612773027761024263 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-0.9.21/plugins/DebuggerCore/win32/PlatformEvent.h0000644000175000017500000000276612773027761023403 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: DEBUG_EVENT event; }; } #endif edb-debugger-0.9.21/plugins/DebuggerCore/win32/PlatformRegion.h0000644000175000017500000000356412773027761023542 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) 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-0.9.21/plugins/DebuggerCore/win32/PlatformRegion.cpp0000644000175000017500000000745212773027761024075 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 namespace DebuggerCore { 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->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()), 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-0.9.21/plugins/DebuggerCore/win32/PlatformProcess.h0000644000175000017500000000153212773027761023726 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-0.9.21/plugins/DebuggerCore/win32/PlatformState.cpp0000644000175000017500000005510112773027761023724 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 DebuggerCore { 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 Register("eax", context_.Eax, Register::TYPE_GPR); else if(lreg == "ebx") return Register("ebx", context_.Ebx, Register::TYPE_GPR); else if(lreg == "ecx") return Register("ecx", context_.Ecx, Register::TYPE_GPR); else if(lreg == "edx") return Register("edx", context_.Edx, Register::TYPE_GPR); else if(lreg == "ebp") return Register("ebp", context_.Ebp, Register::TYPE_GPR); else if(lreg == "esp") return Register("esp", context_.Esp, Register::TYPE_GPR); else if(lreg == "esi") return Register("esi", context_.Esi, Register::TYPE_GPR); else if(lreg == "edi") return Register("edi", context_.Edi, Register::TYPE_GPR); else if(lreg == "eip") return Register("eip", context_.Eip, Register::TYPE_IP); else if(lreg == "ax") return Register("ax", context_.Eax & 0xffff, Register::TYPE_GPR); else if(lreg == "bx") return Register("bx", context_.Ebx & 0xffff, Register::TYPE_GPR); else if(lreg == "cx") return Register("cx", context_.Ecx & 0xffff, Register::TYPE_GPR); else if(lreg == "dx") return Register("dx", context_.Edx & 0xffff, Register::TYPE_GPR); else if(lreg == "bp") return Register("bp", context_.Ebp & 0xffff, Register::TYPE_GPR); else if(lreg == "sp") return Register("sp", context_.Esp & 0xffff, Register::TYPE_GPR); else if(lreg == "si") return Register("si", context_.Esi & 0xffff, Register::TYPE_GPR); else if(lreg == "di") return Register("di", context_.Edi & 0xffff, Register::TYPE_GPR); else if(lreg == "al") return Register("al", context_.Eax & 0xff, Register::TYPE_GPR); else if(lreg == "bl") return Register("bl", context_.Ebx & 0xff, Register::TYPE_GPR); else if(lreg == "cl") return Register("cl", context_.Ecx & 0xff, Register::TYPE_GPR); else if(lreg == "dl") return Register("dl", context_.Edx & 0xff, Register::TYPE_GPR); else if(lreg == "ah") return Register("ah", (context_.Eax >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bh") return Register("bh", (context_.Ebx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "ch") return Register("ch", (context_.Ecx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dh") return Register("dh", (context_.Edx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "cs") return Register("cs", context_.SegCs, Register::TYPE_SEG); else if(lreg == "ds") return Register("ds", context_.SegDs, Register::TYPE_SEG); else if(lreg == "es") return Register("es", context_.SegEs, Register::TYPE_SEG); else if(lreg == "fs") return Register("fs", context_.SegFs, Register::TYPE_SEG); else if(lreg == "gs") return Register("gs", context_.SegGs, Register::TYPE_SEG); else if(lreg == "ss") return Register("ss", context_.SegSs, 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", context_.EFlags, Register::TYPE_COND); #elif defined(EDB_X86_64) if(lreg == "rax") return Register("rax", context_.Rax, Register::TYPE_GPR); else if(lreg == "rbx") return Register("rbx", context_.Rbx, Register::TYPE_GPR); else if(lreg == "rcx") return Register("rcx", context_.Rcx, Register::TYPE_GPR); else if(lreg == "rdx") return Register("rdx", context_.Rdx, Register::TYPE_GPR); else if(lreg == "rbp") return Register("rbp", context_.Rbp, Register::TYPE_GPR); else if(lreg == "rsp") return Register("rsp", context_.Rsp, Register::TYPE_GPR); else if(lreg == "rsi") return Register("rsi", context_.Rsi, Register::TYPE_GPR); else if(lreg == "rdi") return Register("rdi", context_.Rdi, Register::TYPE_GPR); else if(lreg == "rip") return Register("rip", context_.Rip, Register::TYPE_IP); else if(lreg == "r8") return Register("r8", context_.R8, Register::TYPE_GPR); else if(lreg == "r9") return Register("r9", context_.R9, Register::TYPE_GPR); else if(lreg == "r10") return Register("r10", context_.R10, Register::TYPE_GPR); else if(lreg == "r11") return Register("r11", context_.R11, Register::TYPE_GPR); else if(lreg == "r12") return Register("r12", context_.R12, Register::TYPE_GPR); else if(lreg == "r13") return Register("r13", context_.R13, Register::TYPE_GPR); else if(lreg == "r14") return Register("r14", context_.R14, Register::TYPE_GPR); else if(lreg == "r15") return Register("r15", context_.R15, Register::TYPE_GPR); else if(lreg == "eax") return Register("eax", context_.Rax & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ebx") return Register("ebx", context_.Rbx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ecx") return Register("ecx", context_.Rcx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "edx") return Register("edx", context_.Rdx & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ebp") return Register("ebp", context_.Rbp & 0xffffffff, Register::TYPE_GPR); else if(lreg == "esp") return Register("esp", context_.Rsp & 0xffffffff, Register::TYPE_GPR); else if(lreg == "esi") return Register("esi", context_.Rsi & 0xffffffff, Register::TYPE_GPR); else if(lreg == "edi") return Register("edi", context_.Rdi & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r8d") return Register("r8d", context_.R8 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r9d") return Register("r9d", context_.R9 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r10d") return Register("r10d", context_.R10 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r11d") return Register("r11d", context_.R11 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r12d") return Register("r12d", context_.R12 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r13d") return Register("r13d", context_.R13 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r14d") return Register("r14d", context_.R14 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "r15d") return Register("r15d", context_.R15 & 0xffffffff, Register::TYPE_GPR); else if(lreg == "ax") return Register("ax", context_.Rax & 0xffff, Register::TYPE_GPR); else if(lreg == "bx") return Register("bx", context_.Rbx & 0xffff, Register::TYPE_GPR); else if(lreg == "cx") return Register("cx", context_.Rcx & 0xffff, Register::TYPE_GPR); else if(lreg == "dx") return Register("dx", context_.Rdx & 0xffff, Register::TYPE_GPR); else if(lreg == "bp") return Register("bp", context_.Rbp & 0xffff, Register::TYPE_GPR); else if(lreg == "sp") return Register("sp", context_.Rsp & 0xffff, Register::TYPE_GPR); else if(lreg == "si") return Register("si", context_.Rsi & 0xffff, Register::TYPE_GPR); else if(lreg == "di") return Register("di", context_.Rdi & 0xffff, Register::TYPE_GPR); else if(lreg == "r8w") return Register("r8w", context_.R8 & 0xffff, Register::TYPE_GPR); else if(lreg == "r9w") return Register("r9w", context_.R9 & 0xffff, Register::TYPE_GPR); else if(lreg == "r10w") return Register("r10w", context_.R10 & 0xffff, Register::TYPE_GPR); else if(lreg == "r11w") return Register("r11w", context_.R11 & 0xffff, Register::TYPE_GPR); else if(lreg == "r12w") return Register("r12w", context_.R12 & 0xffff, Register::TYPE_GPR); else if(lreg == "r13w") return Register("r13w", context_.R13 & 0xffff, Register::TYPE_GPR); else if(lreg == "r14w") return Register("r14w", context_.R14 & 0xffff, Register::TYPE_GPR); else if(lreg == "r15w") return Register("r15w", context_.R15 & 0xffff, Register::TYPE_GPR); else if(lreg == "al") return Register("al", context_.Rax & 0xff, Register::TYPE_GPR); else if(lreg == "bl") return Register("bl", context_.Rbx & 0xff, Register::TYPE_GPR); else if(lreg == "cl") return Register("cl", context_.Rcx & 0xff, Register::TYPE_GPR); else if(lreg == "dl") return Register("dl", context_.Rdx & 0xff, Register::TYPE_GPR); else if(lreg == "ah") return Register("ah", (context_.Rax >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bh") return Register("bh", (context_.Rbx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "ch") return Register("ch", (context_.Rcx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dh") return Register("dh", (context_.Rdx >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "spl") return Register("spl", (context_.Rsp >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "bpl") return Register("bpl", (context_.Rbp >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "sil") return Register("sil", (context_.Rsi >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "dil") return Register("dil", (context_.Rdi >> 8) & 0xff, Register::TYPE_GPR); else if(lreg == "r8b") return Register("r8b", context_.R8 & 0xff, Register::TYPE_GPR); else if(lreg == "r9b") return Register("r9b", context_.R9 & 0xff, Register::TYPE_GPR); else if(lreg == "r10b") return Register("r10b", context_.R10 & 0xff, Register::TYPE_GPR); else if(lreg == "r11b") return Register("r11b", context_.R11 & 0xff, Register::TYPE_GPR); else if(lreg == "r12b") return Register("r12b", context_.R12 & 0xff, Register::TYPE_GPR); else if(lreg == "r13b") return Register("r13b", context_.R13 & 0xff, Register::TYPE_GPR); else if(lreg == "r14b") return Register("r14b", context_.R14 & 0xff, Register::TYPE_GPR); else if(lreg == "r15b") return Register("r15b", context_.R15 & 0xff, Register::TYPE_GPR); else if(lreg == "cs") return Register("cs", context_.SegCs, Register::TYPE_SEG); else if(lreg == "ds") return Register("ds", context_.SegDs, Register::TYPE_SEG); else if(lreg == "es") return Register("es", context_.SegEs, Register::TYPE_SEG); else if(lreg == "fs") return Register("fs", context_.SegFs, Register::TYPE_SEG); else if(lreg == "gs") return Register("gs", context_.SegGs, Register::TYPE_SEG); else if(lreg == "ss") return Register("ss", context_.SegSs, 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", 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(int 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(int 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-0.9.21/plugins/DebuggerCore/win32/PlatformState.h0000644000175000017500000000357612773027761023402 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 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 quint64 mmx_register(int n) const; virtual QByteArray xmm_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); private: CONTEXT context_; edb::address_t fs_base_; edb::address_t gs_base_; }; } #endif edb-debugger-0.9.21/plugins/DebuggerCore/win32/PlatformEvent.cpp0000644000175000017500000003045012773027761023725 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 DebuggerCore { //------------------------------------------------------------------------------ // 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)) ); 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)) ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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]

") ); 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-0.9.21/plugins/DebuggerCore/win32/DebuggerCore.cpp0000644000175000017500000007305412773027761023503 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 "PlatformRegion.h" #include "PlatformState.h" #include "State.h" #include "string_hash.h" #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma comment(lib, "Advapi32.lib") #pragma comment(lib, "Psapi.lib") #endif namespace DebuggerCore { 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_; }; QString get_user_token(HANDLE hProcess) { QString ret; HANDLE hToken; if(!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) { return ret; } 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) { ret = QString::fromWCharArray(user); } } free(owner); } CloseHandle(hToken); return ret; } /* * 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<'M', 'M', 'X'>::value: return IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE); case edb::string_hash<'X', 'M', 'M'>::value: return IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE); default: return false; } #else switch(ext) { case edb::string_hash<'M', 'M', 'X'>::value: case edb::string_hash<'X', 'M', 'M'>::value: 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 //------------------------------------------------------------------------------ IDebugEvent::const_pointer 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 = reinterpret_cast(de.u.CreateProcessInfo.lpStartAddress); image_base = reinterpret_cast(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), buf, len, &bytes_read)) { for(const IBreakpoint::pointer &bp: breakpoints_) { if(bp->address() >= address && bp->address() < address + bytes_read) { reinterpret_cast(buf)[bp->address() - address] = bp->original_byte(); } } 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), buf, len, &bytes_written); } return false; } //------------------------------------------------------------------------------ // Name: attach // Desc: //------------------------------------------------------------------------------ bool 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 true; } else { CloseHandle(ph); } } return false; } //------------------------------------------------------------------------------ // Name: detach // Desc: //------------------------------------------------------------------------------ void 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(); } } //------------------------------------------------------------------------------ // 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? //------------------------------------------------------------------------------ bool 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, command_str.utf16()); if(CreateProcessW( path.utf16(), // exe command_path, // commandline NULL, // default security attributes NULL, // default thread security too FALSE, // inherit handles CREATE_FLAGS, env_block, // environment data 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); return ok; } //------------------------------------------------------------------------------ // 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 { ProcessInfo pi; pi.pid = lppe.th32ProcessID; pi.uid = 0; // TODO pi.name = QString::fromWCharArray(lppe.szExeFile); if(HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, lppe.th32ProcessID)) { BOOL wow64 = FALSE; if(fnIsWow64Process && fnIsWow64Process(hProc, &wow64) && wow64) { pi.name += " *32"; } pi.user = get_user_token(hProc); CloseHandle(hProc); } 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), &info, sizeof(info)); if(last_base == info.BaseAddress) { break; } last_base = info.BaseAddress; if(info.State == MEM_COMMIT) { const auto start = reinterpret_cast(info.BaseAddress); const auto end = reinterpret_cast(info.BaseAddress) + info.RegionSize; const auto base = reinterpret_cast(info.AllocationBase); const QString name = QString(); const IRegion::permissions_t permissions = info.Protect; // let IRegion::pointer 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 = reinterpret_cast(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<'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-0.9.21/plugins/DebuggerCore/DebuggerCore.pro0000644000175000017500000000316312773027761022551 0ustar eteraneteran include(../plugins.pri) unix { VPATH += unix INCLUDEPATH += unix SOURCES += DebuggerCoreUNIX.cpp HEADERS += DebuggerCoreUNIX.h linux-* { VPATH += unix/linux INCLUDEPATH += unix/linux # Add detector of broken writes to /proc/pid/mem checkProcPidMemWrites.target = $$OUT_PWD/procPidMemWrites.h checkProcPidMemWritesOutFile = $$OUT_PWD/proc-pid-mem-write checkProcPidMemWrites.commands += $$QMAKE_CXX $$QMAKE_CXXFLAGS $$QMAKE_LFLAGS -std=c++11 $$PWD/unix/linux/detect/proc-pid-mem-write.cpp -o $$checkProcPidMemWritesOutFile && \ $$OUT_PWD/proc-pid-mem-write $$checkProcPidMemWrites.target checkProcPidMemWrites.depends += $$PWD/unix/linux/detect/proc-pid-mem-write.cpp # and its clean target procPidMemWriteClean.commands = rm -f $$checkProcPidMemWrites.target $$checkProcPidMemWritesOutFile clean.depends = procPidMemWriteClean PRE_TARGETDEPS += $$checkProcPidMemWrites.target QMAKE_EXTRA_TARGETS += checkProcPidMemWrites procPidMemWriteClean clean } openbsd-* { VPATH += unix/openbsd INCLUDEPATH += unix/openbsd } freebsd-*{ VPATH += unix/freebsd INCLUDEPATH += unix/freebsd } macx { VPATH += unix/osx INCLUDEPATH += unix/osx } } win32 { VPATH += win32 . INCLUDEPATH += win32 . } HEADERS += PlatformProcess.h PlatformEvent.h PlatformState.h PlatformRegion.h DebuggerCoreBase.h DebuggerCore.h Breakpoint.h PlatformCommon.h PlatformThread.h SOURCES += PlatformProcess.cpp PlatformEvent.cpp PlatformState.cpp PlatformRegion.cpp DebuggerCoreBase.cpp DebuggerCore.cpp Breakpoint.cpp PlatformCommon.cpp PlatformThread.cpp edb-debugger-0.9.21/plugins/DebuggerCore/DebuggerCoreBase.cpp0000644000175000017500000001271512773027761023331 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 DebuggerCore { //------------------------------------------------------------------------------ // 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) //------------------------------------------------------------------------------ IBreakpoint::pointer DebuggerCoreBase::add_breakpoint(edb::address_t address) { try { if(attached()) { if(!find_breakpoint(address)) { IBreakpoint::pointer bp(new Breakpoint(address)); breakpoints_[address] = bp; return bp; } } return IBreakpoint::pointer(); } catch(const breakpoint_creation_error &e) { qDebug() << "Failed to create breakpoint"; return IBreakpoint::pointer(); } } //------------------------------------------------------------------------------ // Name: find_breakpoint // Desc: returns the breakpoint at the given address or IBreakpoint::pointer() //------------------------------------------------------------------------------ IBreakpoint::pointer DebuggerCoreBase::find_breakpoint(edb::address_t address) { if(attached()) { auto it = breakpoints_.find(address); if(it != breakpoints_.end()) { return it.value(); } } return IBreakpoint::pointer(); } //------------------------------------------------------------------------------ // 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 //------------------------------------------------------------------------------ QString 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; } } edb-debugger-0.9.21/plugins/DebuggerCore/CMakeLists.txt0000644000175000017500000000513212773027761022230 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(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(DebuggerCore_SRCS Breakpoint.cpp Breakpoint.h 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" ) if (NOT ASSUME_PROC_PID_MEM_WRITE_BROKEN) SET(ASSUME_PROC_PID_MEM_WRITE_BROKEN "Detect" CACHE STRING "How to detect whether or not writes through /proc//mem work") SET_PROPERTY(CACHE ASSUME_PROC_PID_MEM_WRITE_BROKEN PROPERTY STRINGS Detect Yes No) endif() if(${ASSUME_PROC_PID_MEM_WRITE_BROKEN} STREQUAL "Yes") set(PROC_TEST_FLAG "--assume-bad") endif() if(${ASSUME_PROC_PID_MEM_WRITE_BROKEN} STREQUAL "No") set(PROC_TEST_FLAG "--assume-good") endif() if(${ASSUME_PROC_PID_MEM_WRITE_BROKEN} STREQUAL "Detect") set(PROC_TEST_FLAG "") endif() # Tool for detecting broken proc//mem writes add_executable(proc-pid-mem-write unix/linux/detect/proc-pid-mem-write.cpp) add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/procPidMemWrites.h COMMAND ${PROJECT_BINARY_DIR}/proc-pid-mem-write ${CMAKE_CURRENT_BINARY_DIR}/procPidMemWrites.h ${PROC_TEST_FLAG} DEPENDS proc-pid-mem-write ) set(DebuggerCore_SRCS ${DebuggerCore_SRCS} ${PROJECT_BINARY_DIR}/procPidMemWrites.h 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/PlatformState.cpp unix/linux/PlatformState.h unix/linux/PlatformThread.cpp unix/linux/PlatformThread.h ) 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() set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}) set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}) install (TARGETS ${PluginName} DESTINATION ${CMAKE_INSTALL_LIBDIR}/edb) edb-debugger-0.9.21/plugins/DebuggerCore/Breakpoint.h0000644000175000017500000000320612773027761021737 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" namespace DebuggerCore { class Breakpoint : public IBreakpoint { public: Breakpoint(edb::address_t address); virtual ~Breakpoint(); public: virtual edb::address_t address() const { return address_; } virtual quint64 hit_count() const { return hit_count_; } virtual bool enabled() const { return enabled_; } virtual bool one_time() const { return one_time_; } virtual bool internal() const { return internal_; } virtual quint8 original_byte() const { return original_byte_; } public: virtual bool enable(); virtual bool disable(); virtual void hit(); virtual void set_one_time(bool value); virtual void set_internal(bool value); private: quint8 original_byte_; edb::address_t address_; quint64 hit_count_; bool enabled_ ; bool one_time_; bool internal_; }; } #endif edb-debugger-0.9.21/plugins/DebuggerCore/DebuggerCoreBase.h0000644000175000017500000000340712773027761022774 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" namespace DebuggerCore { class DebuggerCoreBase : public QObject, public IDebugger { public: DebuggerCoreBase(); virtual ~DebuggerCoreBase(); public: virtual QString open(const QString &path, const QString &cwd, const QList &args) override; virtual QString open(const QString &path, const QString &cwd, const QList &args, const QString &tty) = 0; enum class MeansOfCapture { NeverCaptured, Attach, Launch }; virtual MeansOfCapture last_means_of_capture() = 0; public: virtual BreakpointList backup_breakpoints() const; virtual IBreakpoint::pointer add_breakpoint(edb::address_t address); virtual IBreakpoint::pointer find_breakpoint(edb::address_t address); virtual void clear_breakpoints(); virtual void remove_breakpoint(edb::address_t address); virtual void end_debug_session() override; public: virtual edb::pid_t pid() const; protected: bool attached() const; protected: edb::pid_t pid_; BreakpointList breakpoints_; }; } #endif edb-debugger-0.9.21/plugins/DebuggerCore/Breakpoint.cpp0000644000175000017500000000622712773027761022300 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 "edb.h" namespace DebuggerCore { namespace { const quint8 BreakpointInstruction = 0xcc; } //------------------------------------------------------------------------------ // Name: Breakpoint // Desc: constructor //------------------------------------------------------------------------------ Breakpoint::Breakpoint(edb::address_t address) : original_byte_(0xff), address_(address), hit_count_(0), enabled_(false), one_time_(false), internal_(false) { if(!enable()) { throw breakpoint_creation_error(); } } //------------------------------------------------------------------------------ // Name: ~Breakpoint // Desc: //------------------------------------------------------------------------------ Breakpoint::~Breakpoint() { disable(); } //------------------------------------------------------------------------------ // Name: enable // Desc: //------------------------------------------------------------------------------ bool Breakpoint::enable() { if(!enabled()) { if(IProcess *process = edb::v1::debugger_core->process()) { quint8 prev[1]; if(process->read_bytes(address(), prev, 1)) { original_byte_ = prev[0]; if(process->write_bytes(address(), &BreakpointInstruction, 1)) { 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_byte_, 1)) { 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; } } edb-debugger-0.9.21/plugins/SymbolViewer/0000755000175000017500000000000012773027761017561 5ustar eteraneteranedb-debugger-0.9.21/plugins/SymbolViewer/SymbolViewer.h0000644000175000017500000000242012773027761022357 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 SymbolViewer { 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_; QDialog * dialog_; }; } #endif edb-debugger-0.9.21/plugins/SymbolViewer/SymbolViewer.cpp0000644000175000017500000000415612773027761022722 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 SymbolViewer { //------------------------------------------------------------------------------ // 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-0.9.21/plugins/SymbolViewer/DialogSymbolViewer.h0000644000175000017500000000315012773027761023500 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 SymbolViewer { 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-0.9.21/plugins/SymbolViewer/CMakeLists.txt0000644000175000017500000000175712773027761022333 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-0.9.21/plugins/SymbolViewer/SymbolViewer.pro0000644000175000017500000000024612773027761022734 0ustar eteraneteran include(../plugins.pri) # Input HEADERS += DialogSymbolViewer.h SymbolViewer.h FORMS += DialogSymbolViewer.ui SOURCES += DialogSymbolViewer.cpp SymbolViewer.cpp edb-debugger-0.9.21/plugins/SymbolViewer/DialogSymbolViewer.cpp0000644000175000017500000001462112773027761024040 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 "Util.h" #include "edb.h" #include #include #include #include "ui_DialogSymbolViewer.h" namespace SymbolViewer { //------------------------------------------------------------------------------ // 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 Symbol::pointer 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; QString temp; const QList symbols = edb::v1::symbol_manager().symbols(); for(const Symbol::pointer &sym: symbols) { results << QString("%1: %2").arg(edb::v1::format_pointer(sym->address)).arg(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-0.9.21/plugins/SymbolViewer/DialogSymbolViewer.ui0000644000175000017500000000613112773027761023670 0ustar eteraneteran Evan Teran SymbolViewer::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-0.9.21/plugins/plugins-x86.pri0000644000175000017500000000020612773027761017750 0ustar eteraneteraninclude(../common.pri) target.path = $$PREFIX/lib/edb/ INCLUDEPATH += $$LEVEL/include INCLUDEPATH += $$LEVEL/include/arch/x86-generic edb-debugger-0.9.21/plugins/plugins.pro0000644000175000017500000000060312773027761017334 0ustar eteraneteranTEMPLATE = subdirs # Directories SUBDIRS += \ Analyzer \ Assembler \ BinaryInfo \ BinarySearcher \ Bookmarks \ ODbgRegisterView \ BreakpointManager \ CheckVersion \ DebuggerCore \ DumpState \ FunctionFinder \ HardwareBreakpoints \ OpcodeSearcher \ ProcessProperties \ ROPTool \ References \ SymbolViewer \ Backtrace unix { !macx { SUBDIRS += HeapAnalyzer } } edb-debugger-0.9.21/plugins/References/0000755000175000017500000000000012773027761017213 5ustar eteraneteranedb-debugger-0.9.21/plugins/References/References.pro0000644000175000017500000000023112773027761022012 0ustar eteraneteran include(../plugins.pri) # Input HEADERS += References.h DialogReferences.h FORMS += DialogReferences.ui SOURCES += References.cpp DialogReferences.cpp edb-debugger-0.9.21/plugins/References/DialogReferences.cpp0000644000175000017500000001445512773027761023131 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 References { 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 IRegion::pointer ®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 edb::Instruction::Operation::X86_INS_MOV: // instructions of the form: mov [ADDR], 0xNNNNNNNN Q_ASSERT(inst.operand_count() == 2); if(inst.operands()[0].general_type() == edb::Operand::TYPE_EXPRESSION) { if(inst.operands()[1].general_type() == edb::Operand::TYPE_IMMEDIATE && static_cast(inst.operands()[1].immediate()) == address) { auto item = new QListWidgetItem(edb::v1::format_pointer(addr)); item->setData(TypeRole, 'C'); item->setData(AddressRole, addr); ui->listWidget->addItem(item); } } break; case edb::Instruction::Operation::X86_INS_PUSH: // instructions of the form: push 0xNNNNNNNN Q_ASSERT(inst.operand_count() == 1); if(inst.operands()[0].general_type() == edb::Operand::TYPE_IMMEDIATE && static_cast(inst.operands()[0].immediate()) == 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(inst.operands()[0].general_type() == edb::Operand::TYPE_REL) { if(inst.operands()[0].relative_target() == 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-0.9.21/plugins/References/CMakeLists.txt0000644000175000017500000000174312773027761021760 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-0.9.21/plugins/References/References.cpp0000644000175000017500000000412712773027761022004 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 References { //------------------------------------------------------------------------------ // 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-0.9.21/plugins/References/References.h0000644000175000017500000000240212773027761021443 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 References { 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_; QDialog *dialog_; }; } #endif edb-debugger-0.9.21/plugins/References/DialogReferences.h0000644000175000017500000000250112773027761022563 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 References { 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-0.9.21/plugins/References/DialogReferences.ui0000644000175000017500000000663612773027761022766 0ustar eteraneteran Evan Teran References::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-0.9.21/plugins/ODbgRegisterView/0000755000175000017500000000000012773027761020305 5ustar eteraneteranedb-debugger-0.9.21/plugins/ODbgRegisterView/Plugin.h0000644000175000017500000000337112773027761021720 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 class QMainWindow; class QDockWidget; class QSettings; 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") void setupDocks(); public: Plugin(); virtual QMenu* menu(QWidget* parent = 0) override; virtual QList cpu_context_menu() override; private: QMenu* menu_; std::vector registerViews_; std::vector menuDeleteRegViewActions_; 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*); }; } #endif edb-debugger-0.9.21/plugins/ODbgRegisterView/GPREdit.h0000644000175000017500000000113512773027761021714 0ustar eteraneteran#include class GPREdit : public QLineEdit { public: enum class Format { Hex, Signed, Unsigned, Character }; public: GPREdit(std::size_t offsetInInteger, std::size_t integerSize, Format format, QWidget* parent=nullptr); void setGPRValue(std::uint64_t gprValue); void updateGPRValue(std::uint64_t& gpr) const; QSize minimumSizeHint() const override { return sizeHint(); } QSize sizeHint() const override; private: void setupFormat(Format newFormat); int naturalWidthInChars; std::size_t integerSize; std::size_t offsetInInteger; Format format; std::uint64_t signBit; }; edb-debugger-0.9.21/plugins/ODbgRegisterView/Float80Edit.cpp0000644000175000017500000000121512773027761023033 0ustar eteraneteran#include "Float80Edit.h" #include "FloatX.h" #include #include 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-0.9.21/plugins/ODbgRegisterView/DialogEditFPU.h0000644000175000017500000000123412773027761023036 0ustar eteraneteran#ifndef DIALOG_EDIT_FPU_H_20151031 #define DIALOG_EDIT_FPU_H_20151031 #include #include #include "Register.h" class Float80Edit; class DialogEditFPU : public QDialog { Q_OBJECT static_assert(sizeof(long double)>=10,"This class will only work with true 80-bit long double"); Register reg; edb::value80 value_; Float80Edit* const floatEntry; QLineEdit* const hexEntry; public: DialogEditFPU(QWidget* parent=nullptr); Register value() const; void set_value(const Register& reg); private Q_SLOTS: void onHexEdited(const QString&); void onFloatEdited(const QString&); void updateFloatEntry(); void updateHexEntry(); }; #endif edb-debugger-0.9.21/plugins/ODbgRegisterView/Plugin.cpp0000644000175000017500000001660012773027761022252 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 "edb.h" #include #include #include #include #include #include "RegisterView.h" #include "ArchProcessor.h" #include namespace ODbgRegisterView { Plugin::Plugin() : QObject(0), menu_(0) { connect(QCoreApplication::instance(),SIGNAL(aboutToQuit()),this,SLOT(saveState())); } const QString pluginName="ODbgRegisterView"; const QString dockName=QObject::tr("Registers"); const QString dockNameSuffixTemplate=" <%1>"; const QString dockObjectNameTemplate=QString(pluginName+"-%1"); const QString VIEW="views"; void Plugin::setupDocks() { QSettings settings; settings.beginGroup(pluginName); if(settings.value(VIEW+"/size").isValid()) { const int size=settings.beginReadArray(VIEW); for(int i=0;isaveState(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); if(QDockWidget* registersDock = mainWindow->findChild("registersDock")) mainWindow->tabifyDockWidget(registersDock, regViewDockWidget); 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(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(auto* const mainWindow = qobject_cast(edb::v1::debugger_ui)) mainWindow->setCorner(Qt::BottomLeftCorner,checked ? Qt::LeftDockWidgetArea : Qt::BottomDockWidgetArea); } void Plugin::expandRSDown(bool checked) const { if(auto* const mainWindow = qobject_cast(edb::v1::debugger_ui)) mainWindow->setCorner(Qt::BottomRightCorner,checked ? Qt::RightDockWidgetArea : Qt::BottomDockWidgetArea); } void Plugin::expandLSUp(bool checked) const { if(auto* const mainWindow = qobject_cast(edb::v1::debugger_ui)) mainWindow->setCorner(Qt::TopLeftCorner,checked ? Qt::LeftDockWidgetArea : Qt::TopDockWidgetArea); } void Plugin::expandRSUp(bool checked) const { if(auto* const 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("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-0.9.21/plugins/ODbgRegisterView/DialogEditSIMDRegister.cpp0000644000175000017500000004115012773027761025201 0ustar eteraneteran#include "DialogEditSIMDRegister.h" #include #include #include #include #include #include "QULongValidator.h" #include "QLongValidator.h" #include "FloatX.h" #include #include #include class NumberEdit : public QLineEdit { int naturalWidthInChars=17; // default roughly as in QLineEdit int column_; int colSpan_; public: NumberEdit(int column, int colSpan, QWidget* parent=nullptr) : QLineEdit(parent), column_(column), colSpan_(colSpan) { } int column() const { return column_; } int colSpan() const { return colSpan_; } void setNaturalWidthInChars(int nChars) { naturalWidthInChars=nChars; } QSize minimumSizeHint() const override { return sizeHint(); } QSize sizeHint() const override { 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()); } }; template void DialogEditSIMDRegister::setupEntries(const QString& label, std::array& entries, int row, const char* slot, int naturalWidthInChars) { QGridLayout& contentsGrid = dynamic_cast(*layout()); contentsGrid.addWidget(new QLabel(label,this), row, ENTRIES_FIRST_COL-1); for(std::size_t entryIndex=0;entryIndexsetNaturalWidthInChars(naturalWidthInChars); connect(entry,SIGNAL(textEdited(const QString&)),this,slot); } } 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;byteIndexsetAlignment(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/4-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/4-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;isetText(formatFloat(value)); } } template void DialogEditSIMDRegister::updateIntegralEntries(const std::array& entries,NumberEdit* notUpdated) { for(std::size_t i=0;i(bytes,notUpdated); updateIntegralEntries(words,notUpdated); updateIntegralEntries(dwords,notUpdated); updateIntegralEntries(qwords,notUpdated); updateFloatEntries(floats32,notUpdated); updateFloatEntries(floats64,notUpdated); } void DialogEditSIMDRegister::resetLayout() { QGridLayout* layout = dynamic_cast(this->layout()); for(int col=ENTRIES_FIRST_COL;colshow(); 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;rowitemAtPosition(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) { QGridLayout* layout = dynamic_cast(this->layout()); for(int col=ENTRIES_FIRST_COL;colhide(); // 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) { QGridLayout* layout = dynamic_cast(this->layout()); for(int col=0;colitemAtPosition(rowToHide,col); if(item && item->widget()) item->widget()->hide(); } } 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=dynamic_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=dynamic_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-0.9.21/plugins/ODbgRegisterView/DialogEditGPR.h0000644000175000017500000000303212773027761023032 0ustar eteraneteran#ifndef DIALOG_EDIT_GPR_H_20151011 #define DIALOG_EDIT_GPR_H_20151011 #include #include #include #include #include #include #include #include #include #include #include #include #include "Register.h" class GPREdit; class DialogEditGPR : public QDialog { Q_OBJECT 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 }; std::array labels={{0}}; std::array entries={{0}}; std::uint64_t value_; std::size_t bitSize_=0; Register reg; 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(); public: DialogEditGPR(QWidget* parent=nullptr); Register value() const; void set_value(const Register& reg); private Q_SLOTS: void onTextEdited(const QString&); }; #endif edb-debugger-0.9.21/plugins/ODbgRegisterView/CMakeLists.txt0000644000175000017500000000171412773027761023050 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() # we put the header files from the include directory here # too so automoc can "just work" add_library(${PluginName} SHARED DialogEditFPU.cpp DialogEditGPR.cpp Float80Edit.cpp GPREdit.cpp Plugin.cpp Plugin.h RegisterView.cpp RegisterView.h DialogEditSIMDRegister.cpp ) 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-0.9.21/plugins/ODbgRegisterView/RegisterView.h0000644000175000017500000002122412773027761023076 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 #include #include #include #include #include #include #include "RegisterViewModelBase.h" class QSettings; class DialogEditGPR; class DialogEditSIMDRegister; class DialogEditFPU; namespace ODbgRegisterView { class RegisterGroup; class FieldWidget; class ValueField; class ODBRegView : public QScrollArea { Q_OBJECT RegisterViewModelBase::Model* model_=nullptr; public: struct RegisterGroupType { enum T { GPR, rIP, ExpandedEFL, Segment, EFL, FPUData, FPUWords, FPULastOp, Debug, MMX, SSEData, AVXData, MXCSR, 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,QListconst& 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; QList groups; private Q_SLOTS: void fieldSelected(); void modelReset(); void modelUpdated(); void copyAllRegisters(); void copyRegisterToClipboard() const; }; class Canvas : public QWidget { public: Canvas(QWidget* parent=nullptr); protected: void mousePressEvent(QMouseEvent* event) override; }; 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(); }; class VolatileNameField : public FieldWidget { std::function valueFormatter; public: VolatileNameField(int fieldWidth, std::function const& valueFormatter,QWidget* parent=nullptr); QString text() const override; }; class ValueField : public FieldWidget { Q_OBJECT 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::functionconst& 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(); void pushFPUStack(); void popFPUStack(); 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(); }; class FPUValueField : public ValueField { Q_OBJECT 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& regValueIndex, QModelIndex const& tagValueIndex, RegisterGroup* group, FieldWidget* commentWidget, int row, int column ); public Q_SLOTS: void showFPUAsRaw(); void showFPUAsFloat(); void displayFormatChanged(); void updatePalette() override; }; struct BitFieldDescription { int textWidth; std::vector valueNames; std::vector setValueTexts; std::functionconst valueEqualComparator; BitFieldDescription(int textWidth, std::vectorconst& valueNames, std::vectorconst& setValueTexts, std::functionconst& valueEqualComparator=[](unsigned a,unsigned b){return a==b;}); }; class BitFieldFormatter { std::vector valueNames; public: BitFieldFormatter(BitFieldDescription const& bfd); QString operator()(QString const& text); }; class MultiBitFieldWidget : public ValueField { Q_OBJECT QList valueActions; std::function equal; public: MultiBitFieldWidget( QModelIndex const& index, BitFieldDescription const& bfd, QWidget* parent=nullptr); public Q_SLOTS: void setValue(int value); void adjustToData() override; }; class SIMDValueManager : public QObject { Q_OBJECT 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 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,QListconst& additionalItems={}) const; QMargins getFieldMargins() const; protected: void mousePressEvent(QMouseEvent* event) override; public Q_SLOTS: void adjustWidth(); void hideAndReport(); friend SIMDValueManager; }; } #endif edb-debugger-0.9.21/plugins/ODbgRegisterView/GPREdit.cpp0000644000175000017500000001004512773027761022247 0ustar eteraneteran#include "GPREdit.h" #include #include #include #include #include "QLongValidator.h" #include "QULongValidator.h" 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-0.9.21/plugins/ODbgRegisterView/DialogEditGPR.cpp0000644000175000017500000001737112773027761023400 0ustar eteraneteran#include "DialogEditGPR.h" #include #include #include #include #include #include #include #include #include #include "GPREdit.h" 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(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(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;fentry(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&))); 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&))); 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&))); 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;entryisHidden()) 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(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(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(GPR64_COL+c))->setText(colLabelStrings[c]); } void DialogEditGPR::setupEntriesAndLabels() { resetLayout(); switch(bitSize_) { case 8: hideColumn(GPR8H_COL); hideColumn(GPR16_COL); case 16: hideColumn(GPR32_COL); case 32: hideColumn(GPR64_COL); 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, 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; } } 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-0.9.21/plugins/ODbgRegisterView/DialogEditFPU.cpp0000644000175000017500000001016012773027761023367 0ustar eteraneteran#include "DialogEditFPU.h" #include "Float80Edit.h" #include #include #include #include #include #include #include #include #include #include #include #include DialogEditFPU::DialogEditFPU(QWidget* parent) : QDialog(parent), floatEntry(new 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())); 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()); } 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> value; if(stream) { // Check that no trailing chars are left char c; stream >> c; if(!stream) { 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 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; } } void DialogEditFPU::onFloatEdited(const QString& str) { bool ok; const auto value=readFloat(str,ok); if(ok) value_=edb::value80(value); updateHexEntry(); } edb-debugger-0.9.21/plugins/ODbgRegisterView/Float80Edit.h0000644000175000017500000000055712773027761022510 0ustar eteraneteran#ifndef FLOAT_80_EDIT_H_20151031 #define FLOAT_80_EDIT_H_20151031 #include #include "Types.h" class Float80Edit : public QLineEdit { Q_OBJECT public: Float80Edit(QWidget* parent=0); void setValue(edb::value80 input); QSize sizeHint() const override; protected: void focusOutEvent(QFocusEvent* e) override; Q_SIGNALS: void defocussed(); }; #endif edb-debugger-0.9.21/plugins/ODbgRegisterView/RegisterView.cpp0000644000175000017500000023267112773027761023443 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "RegisterViewModelBase.h" #include "edb.h" #include "Configuration.h" #include "State.h" #include "DialogEditGPR.h" #include "DialogEditSIMDRegister.h" #include "DialogEditFPU.h" #include #define VALID_VARIANT(VARIANT) ([]{static_assert(std::is_same::type,const QVariant>::value,"Wrong type passed to VALID_VARIANT");}(),\ assert((VARIANT).isValid()),(VARIANT)) #define VALID_INDEX(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()),(INDEX)) #define CHECKED_CAST(TYPE,PARENT) (assert(dynamic_cast(PARENT)),static_cast(PARENT)) namespace ODbgRegisterView { // 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) const constexpr auto registerGroupTypeNames=util::make_array( "GPR", "rIP", "ExpandedEFL", "Segment", "EFL", "FPUData", "FPUWords", "FPULastOp", "Debug", "MMX", "SSEData", "AVXData", "MXCSR" ); static_assert(registerGroupTypeNames.size()==ODBRegView::RegisterGroupType::NUM_GROUPS, "Mismatch between number of register group types and names"); const QString SETTINGS_GROUPS_ARRAY_NODE="visibleGroups"; static const int MODEL_NAME_COLUMN=RegisterViewModelBase::Model::NAME_COLUMN; static const int MODEL_VALUE_COLUMN=RegisterViewModelBase::Model::VALUE_COLUMN; static const int MODEL_COMMENT_COLUMN=RegisterViewModelBase::Model::COMMENT_COLUMN; static const char* FSR_NAME="FSR"; static const char* FCR_NAME="FCR"; static const char* FTR_NAME="FTR"; static const char* GPRCategoryName="General Purpose"; 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; template inline 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); } QAction* newActionSeparator(QObject* parent) { const auto sep=new QAction(parent); sep->setSeparator(true); return sep; } 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; } 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; } static QStyle* flatStyle=nullptr; // ------------------------- 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)const& valueNames, std::vector const&setValueTexts, std::functionconst& valueEqualComparator) : textWidth(textWidth), valueNames(valueNames), setValueTexts(setValueTexts), valueEqualComparator(valueEqualComparator) { } static 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;}}; static const constexpr unsigned FPU_TAG_EMPTY=3; static 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")}}; static 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")}}; static 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")}}; static 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")}}; // --------------------- FieldWidget impl ---------------------------------- 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 { auto* const parent=parentWidget() // group ->parentWidget() // canvas ->parentWidget() // viewport ->parentWidget(); // regview assert(dynamic_cast(parent)); return static_cast(parent); } RegisterGroup* FieldWidget::group() const { return CHECKED_CAST(RegisterGroup,parentWidget()); } VolatileNameField::VolatileNameField(int fieldWidth, std::function const& valueFormatter, QWidget* parent) : FieldWidget(fieldWidth,"",parent), valueFormatter(valueFormatter) { } QString VolatileNameField::text() const { return valueFormatter(); } // --------------------- ValueField impl ---------------------------------- 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(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()))); } 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::functionconst& firstIsBetter) const { ValueField* result=nullptr; for(auto* const 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()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); } } 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); } } } 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<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*) { auto*const regView=this->regView(); QPainter painter(this); QStyleOptionViewItemV4 option; 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); } 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); } 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); } void ValueField::copyToClipboard() const { QApplication::clipboard()->setText(text()); } 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;}); } // -------------------------------- FPUValueField impl --------------------------------- FPUValueField::FPUValueField(int fieldWidth, QModelIndex const& regValueIndex, 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(); } // -------------------------------- 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<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;valuesetVisible(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, QListconst& 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(ODBRegView, 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(auto* const value=dynamic_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()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(auto* const child : children) { const auto field=dynamic_cast(child); if(field) fields.append(field); } return fields; } QList RegisterGroup::valueFields() const { QList allValues; for(auto* const field : fields()) { auto* const value=dynamic_cast(field); if(value) allValues.push_back(value); } return allValues; } // ------------------------------- Canvas impl ---------------------------------------- Canvas::Canvas(QWidget* parent) : QWidget(parent) { setObjectName("RegViewCanvas"); auto* const 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) for(auto* const field : valueFields()) field->unselect(); } void ODBRegView::fieldSelected() { for(auto* const field : valueFields()) if(sender()!=field) field->unselect(); ensureWidgetVisible(static_cast(sender()),0,0); } void ODBRegView::showMenu(QPoint const& position, QListconst& 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; for(auto* const 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()); } ODBRegView::ODBRegView(QString const& settingsGroup, QWidget* parent) : QScrollArea(parent), dialogEditGPR(new DialogEditGPR(this)), dialogEditSIMDReg(new DialogEditSIMDRegister(this)), dialogEditFPU(new DialogEditFPU(this)) { setObjectName("ODBRegView"); { // TODO: get some signal to change font on the fly // NOTE: on getting this signal all the fields must be resized and moved QFont font; if(!font.fromString(edb::v1::config().registers_font)) { font=QFont("Monospace"); font.setStyleHint(QFont::TypeWriter); } setFont(font); } auto* const 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={ 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 }; } else { for(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 { auto* const 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 false; return f1Pos.x()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(); } namespace { // TODO: switch from string-based search to enum-based one (add a new Role to model data) QModelIndex findModelCategory(RegisterViewModelBase::Model const*const model, QString const& catToFind) { for(int row=0;rowrowCount();++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) QModelIndex findModelRegister(QModelIndex categoryIndex, QString const& regToFind, int column=MODEL_NAME_COLUMN) { auto* const model=categoryIndex.model(); for(int row=0;rowrowCount(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(); } QModelIndex getCommentIndex(QModelIndex const& nameIndex) { assert(nameIndex.isValid()); return nameIndex.sibling(nameIndex.row(),MODEL_COMMENT_COLUMN); } QModelIndex getValueIndex(QModelIndex const& nameIndex) { assert(nameIndex.isValid()); return nameIndex.sibling(nameIndex.row(),MODEL_VALUE_COLUMN); } 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;exNinsert(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; auto* const 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; auto* const 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;rowrowCount(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; } auto* const 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;rowindex(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; auto* const 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; auto* const 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; auto* const 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; auto* const 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; } RegisterGroup* createSIMDGroup(RegisterViewModelBase::Model* model,QWidget* parent,QString const& catName,QString const& regNamePrefix) { const auto catIndex=findModelCategory(model,catName); if(!catIndex.isValid()) return nullptr; auto* const group=new RegisterGroup(catName,parent); for(int row=0;rowrowCount(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::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::GPR: { groupName=tr("GPRs"); const auto catIndex=findModelCategory(model_,GPRCategoryName); if(!catIndex.isValid()) break; for(int row=0;rowrowCount(catIndex);++row) nameValCommentIndices.emplace_back(model_->index(row,MODEL_NAME_COLUMN,catIndex)); break; } case RegisterGroupType::Segment: { groupName=tr("Segment Registers"); const auto catIndex=findModelCategory(model_,"Segment"); if(!catIndex.isValid()) break; for(int row=0;rowrowCount(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; } 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; } auto* const 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 for(auto* const group : groups) if(group) group->deleteLater(); groups.clear(); auto* const layout=static_cast(widget()->layout()); // layout contains not only groups, so delete all items too while(auto* const item=layout->takeAt(0)) delete item; auto* const 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_addWidget(group); if(!flagsAndSegsInserted) { layout->addLayout(flagsAndSegments); flagsAndSegsInserted=true; } } else layout->addWidget(group); } else groups.push_back(nullptr); } widget()->show(); } void ODBRegView::modelUpdated() { for(auto* const field : fields()) field->adjustToData(); for(auto* const group : groups) if(group) group->adjustWidth(); } QList ODBRegView::fields() const { QList allFields; for(auto* const group : groups) if(group) allFields.append(group->fields()); return allFields; } QList ODBRegView::valueFields() const { QList allValues; for(auto* const group : groups) if(group) allValues.append(group->valueFields()); return allValues; } void ODBRegView::updateFieldsPalette() { for(auto* const field : valueFields()) field->updatePalette(); } ValueField* ODBRegView::selectedField() const { for(auto* const 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; for(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 { assert(dynamic_cast(parent())); return static_cast(parent()); } void SIMDValueManager::displayFormatChanged() { const auto newFormat=currentFormat(); if(newFormat!=NumberDisplayMode::Float) intMode=newFormat; for(auto* const 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) { auto* const 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-0.9.21/plugins/ODbgRegisterView/ODbgRegisterView.pro0000644000175000017500000000042212773027761024200 0ustar eteraneteran include(../plugins.pri) HEADERS += DialogEditFPU.h DialogEditGPR.h DialogEditSIMDRegister.h Float80Edit.h GPREdit.h Plugin.h RegisterView.h SOURCES += DialogEditFPU.cpp DialogEditSIMDRegister.cpp GPREdit.cpp RegisterView.cpp DialogEditGPR.cpp Float80Edit.cpp Plugin.cpp edb-debugger-0.9.21/plugins/ODbgRegisterView/DialogEditSIMDRegister.h0000644000175000017500000000700312773027761024645 0ustar eteraneteran#ifndef DIALOG_EDIT_MMX_H_20151010 #define DIALOG_EDIT_MMX_H_20151010 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Util.h" #include "RegisterViewModelBase.h" class QRegExpValidator; class QULongValidator; class QLongValidator; class QValidator; class NumberEdit; class DialogEditSIMDRegister : public QDialog { Q_OBJECT static constexpr const 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 }; 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; 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(); 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; 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 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); }; #endif edb-debugger-0.9.21/plugins/Analyzer/0000755000175000017500000000000012773027761016717 5ustar eteraneteranedb-debugger-0.9.21/plugins/Analyzer/AnalyzerWidget.h0000644000175000017500000000213512773027761022022 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 namespace Analyzer { 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_; }; } edb-debugger-0.9.21/plugins/Analyzer/Analyzer.cpp0000644000175000017500000006464412773027761021226 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 "OptionsPage.h" #include "AnalyzerWidget.h" #include "SpecifiedFunctions.h" #include "IBinary.h" #include "IDebugger.h" #include "ISymbolManager.h" #include "Instruction.h" #include "MemoryRegions.h" #include "State.h" #include "Util.h" #include "edb.h" #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 Analyzer { namespace { const int MIN_REFCOUNT = 2; //------------------------------------------------------------------------------ // Name: module_entry_point // Desc: //------------------------------------------------------------------------------ edb::address_t module_entry_point(const IRegion::pointer ®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(IThread::pointer thread = process->current_thread()) { State state; thread->get_state(&state); const edb::address_t address = state.instruction_pointer(); if(IRegion::pointer 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(IRegion::pointer 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: 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); 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())); ret << action_find << action_goto_function_start << action_goto_function_end << action_mark_function_start; return ret; } //------------------------------------------------------------------------------ // Name: do_analysis // Desc: //------------------------------------------------------------------------------ void Analyzer::do_analysis(const IRegion::pointer ®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 Symbol::pointer &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); for(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; QHash functions; // push all known functions onto a stack QStack known_functions; for(const edb::address_t function: data->known_functions) { known_functions.push(function); } // push all fuzzy function too... for(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(function_address); // 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; } const edb::Instruction inst(buffer, buffer + buf_size, address); if(!inst) { break; } block.push_back(std::make_shared(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 edb::Operand &op = inst.operands()[0]; if(op.general_type() == edb::Operand::TYPE_REL) { const edb::address_t ea = op.relative_target(); // skip over ones which are: "call