commit 7ed1cee873cda8bd4d521a8de9b0a34c1387f324 Author: Maschell Date: Mon Apr 27 13:32:37 2020 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..808d449 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +/*.elf +/*.cbp +/build +*.rpx +*.bin +*.cscope_file_list +*.layout diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..23cb790 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + 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. + + {description} + Copyright (C) {year} {fullname} + + 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. + + {signature of Ty Coon}, 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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fecd272 --- /dev/null +++ b/Makefile @@ -0,0 +1,216 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPRO") +endif +export PATH := $(DEVKITPPC)/bin:$(PORTLIBS)/bin:$(PATH) +export PORTLIBS := $(DEVKITPRO)/portlibs/ppc + +GCC_VER := $(shell $(DEVKITPPC)/bin/powerpc-eabi-gcc -dumpversion) + +PREFIX := powerpc-eabi- + +export AS := $(PREFIX)as +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := payload +BUILD := build +BUILD_DBG := $(TARGET)_dbg +SOURCES := src \ + src/module \ + src/utils + +DATA := data + +INCLUDES := src + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +CFLAGS := -std=gnu11 -mcpu=750 -meabi -mhard-float -ffast-math \ + -O2 -Wall -Wextra -Wno-unused-parameter -Wno-strict-aliasing $(INCLUDE) +CXXFLAGS := -std=gnu++11 -mcpu=750 -meabi -mhard-float -ffast-math \ + -O2 -Wall -Wextra -Wno-unused-parameter -Wno-strict-aliasing $(INCLUDE) +ASFLAGS := -mregnames +LDFLAGS := -nostartfiles -Wl,--gc-sections + +#--------------------------------------------------------------------------------- +Q := @ +MAKEFLAGS += --no-print-directory +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CURDIR) \ + $(DEVKITPPC)/lib \ + $(DEVKITPRO)/wut \ + $(DEVKITPPC)/lib/gcc/powerpc-eabi/$(GCC_VER) + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- +export PROJECTDIR := $(CURDIR) +export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +export DEPSDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) \ + $(PNGFILES:.png=.png.o) $(addsuffix .o,$(BINFILES)) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) -I$(LIBOGC_INC) \ + -I$(PORTLIBS)/include -I$(PORTLIBS)/include/freetype2 + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) -L$(PORTLIBS)/lib + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean install + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).bin $(BUILD_DBG).elf + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .jpg extension +#--------------------------------------------------------------------------------- +%.elf: link.ld $(OFILES) + @echo "linking ... $(TARGET).elf" + $(Q)$(LD) -n -T $^ $(LDFLAGS) -o ../$(BUILD_DBG).elf $(LIBPATHS) $(LIBS) + $(Q)$(OBJCOPY) -S -R .comment -R .gnu.attributes ../$(BUILD_DBG).elf $@ + $(Q)$(OBJCOPY) -O binary -R .comment -R .gnu.attributes ../$(BUILD_DBG).elf $@.bin + +#--------------------------------------------------------------------------------- +%.a: +#--------------------------------------------------------------------------------- + @echo $(notdir $@) + @rm -f $@ + @$(AR) -rc $@ $^ + +#--------------------------------------------------------------------------------- +%.o: %.cpp + @echo $(notdir $<) + @$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.o: %.c + @echo $(notdir $<) + @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.o: %.S + @echo $(notdir $<) + @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.png.o : %.png + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.jpg.o : %.jpg + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.ttf.o : %.ttf + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.bin.o : %.bin + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.wav.o : %.wav + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.mp3.o : %.mp3 + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.ogg.o : %.ogg + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) +#--------------------------------------------------------------------------------- +%.tga.o : %.tga + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/README.md b/README.md new file mode 100644 index 0000000..18119cd --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# CustomRPXLoader +This custom loader for `.rpx` files which can be used with any `payload.elf` loader. (For example [https://github.com/wiiu-env/PayloadFromRPX](https://github.com/wiiu-env/PayloadFromRPX) or [JsTypeHax](https://github.com/wiiu-env/JsTypeHax)) + +## Usage +Place the `payload.elf` in the `sd:/wiiu` folder of your sd card and run a exploit which loads `payload.elf`, this will load the `sd:/wiiu/payload.rpx`into memory and execute it. The maximum size of the `payload.rpx` depends on the size of this loader, but should > 7Mib. + +## Building + +For building you just need [wut](https://github.com/devkitPro/wut/) installed, then use the `make` command. + +## Credits +- Maschell +- orboditilt +- Copy pasted the solution for using wut header in .elf files from [RetroArch](https://github.com/libretro/RetroArch) +- Copy pasted resolving the ElfRelocations from [decaf](https://github.com/decaf-emu/decaf-emu) +- Copy pasted SD mounting code + devoptabs from [libutils](https://github.com/Maschell/libutils) \ No newline at end of file diff --git a/src/ElfUtils.cpp b/src/ElfUtils.cpp new file mode 100644 index 0000000..c761dba --- /dev/null +++ b/src/ElfUtils.cpp @@ -0,0 +1,158 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include "utils/logger.h" + +#include "elfio/elfio.hpp" +#include "ElfUtils.h" + +// See https://github.com/decaf-emu/decaf-emu/blob/43366a34e7b55ab9d19b2444aeb0ccd46ac77dea/src/libdecaf/src/cafe/loader/cafe_loader_reloc.cpp#L144 +bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampolin_entry_t * trampolin_data, uint32_t trampolin_data_length, RelocationType reloc_type) { + if(type == R_PPC_NONE) { + return true; + } + auto target = destination + offset; + auto value = symbol_addr + addend; + + + auto relValue = value - static_cast(target); + + switch (type) { + case R_PPC_NONE: + break; + case R_PPC_ADDR32: + *((uint32_t *)(target)) = value; + break; + case R_PPC_ADDR16_LO: + *((uint16_t *)(target)) = static_cast(value & 0xFFFF); + break; + case R_PPC_ADDR16_HI: + *((uint16_t *)(target)) = static_cast(value >> 16); + break; + case R_PPC_ADDR16_HA: + *((uint16_t *)(target)) = static_cast((value + 0x8000) >> 16); + break; + case R_PPC_DTPMOD32: + DEBUG_FUNCTION_LINE("################IMPLEMENT ME\n"); + //*((int32_t *)(target)) = tlsModuleIndex; + break; + case R_PPC_DTPREL32: + *((uint32_t *)(target)) = value; + break; + case R_PPC_GHS_REL16_HA: + *((uint16_t *)(target)) = static_cast((relValue + 0x8000) >> 16); + break; + case R_PPC_GHS_REL16_HI: + *((uint16_t *)(target)) = static_cast(relValue >> 16); + break; + case R_PPC_GHS_REL16_LO: + *((uint16_t *)(target)) = static_cast(relValue & 0xFFFF); + break; + case R_PPC_REL14: { + auto distance = static_cast(value) - static_cast(target); + if (distance > 0x7FFC || distance < -0x7FFC) { + DEBUG_FUNCTION_LINE("***14-bit relative branch cannot hit target.\n"); + return false; + } + + if (distance & 3) { + DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.\n", -470040); + return false; + } + + if ((distance >= 0 && (distance & 0xFFFF8000)) || + (distance < 0 && ((distance & 0xFFFF8000) != 0xFFFF8000))) { + DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 17 bits before shift must all be the same.\n", -470040); + return false; + } + + *(int32_t *)target = (*(int32_t *)target & 0xFFBF0003) | (distance & 0x0000fffc); + break; + } + case R_PPC_REL24: { + // if (isWeakSymbol && !symbolValue) { + // symbolValue = static_cast(target); + // value = symbolValue + addend; + // } + auto distance = static_cast(value) - static_cast(target); + if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) { + if(trampolin_data == NULL) { + DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampolin isn't provided\n"); + DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance); + return false; + } else { + relocation_trampolin_entry_t * freeSlot = NULL; + for(uint32_t i = 0; i < trampolin_data_length; i++) { + // We want to override "old" relocations of imports + // Pending relocations have the status RELOC_TRAMP_IMPORT_IN_PROGRESS. + // When all relocations are done successfully, they will be turned into RELOC_TRAMP_IMPORT_DONE + // so they can be overridden/updated/reused on the next application launch. + // + // Relocations that won't change will have the status RELOC_TRAMP_FIXED and are set to free when the module is unloaded. + if(trampolin_data[i].status == RELOC_TRAMP_FREE || + trampolin_data[i].status == RELOC_TRAMP_IMPORT_DONE) { + freeSlot = &(trampolin_data[i]); + break; + } + } + if(freeSlot != NULL) { + DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampolin data list is full\n"); + DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance); + return false; + } + if(target - (uint32_t)&(freeSlot->trampolin[0]) > 0x1FFFFFC) { + DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer).\n"); + DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance); + return false; + } + + freeSlot->trampolin[0] = 0x3D600000 | ((((uint32_t) value) >> 16) & 0x0000FFFF); // lis r11, real_addr@h + freeSlot->trampolin[1] = 0x616B0000 | (((uint32_t) value) & 0x0000ffff); // ori r11, r11, real_addr@l + freeSlot->trampolin[2] = 0x7D6903A6; // mtctr r11 + freeSlot->trampolin[3] = 0x4E800420; // bctr + DCFlushRange((void*)freeSlot->trampolin, sizeof(freeSlot->trampolin)); + ICInvalidateRange((unsigned char*)freeSlot->trampolin, sizeof(freeSlot->trampolin)); + + if(reloc_type == RELOC_TYPE_FIXED) { + freeSlot->status = RELOC_TRAMP_FIXED; + } else { + // Relocations for the imports may be overridden + freeSlot->status = RELOC_TRAMP_IMPORT_IN_PROGRESS; + } + uint32_t symbolValue = (uint32_t)&(freeSlot->trampolin[0]); + value = symbolValue + addend; + distance = static_cast(value) - static_cast(target); + DEBUG_FUNCTION_LINE("Created tramp\n"); + } + } + + if (distance & 3) { + DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.\n", -470022); + return false; + } + + if (distance < 0 && (distance & 0xFE000000) != 0xFE000000) { + DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).\n", -470040); + return false; + } + + if (distance >= 0 && (distance & 0xFE000000)) { + DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).\n", -470040); + return false; + } + + *(int32_t *)target = (*(int32_t *)target & 0xfc000003) | (distance & 0x03fffffc); + break; + } + default: + DEBUG_FUNCTION_LINE("***ERROR: Unsupported Relocation_Add Type (%08X):\n", type); + return false; + } + return true; +} diff --git a/src/ElfUtils.h b/src/ElfUtils.h new file mode 100644 index 0000000..c6b011e --- /dev/null +++ b/src/ElfUtils.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include "common/relocation_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t LoadFileToMem(const char *relativefilepath, char **fileOut, uint32_t * sizeOut); +uint32_t load_loader_elf_from_sd(unsigned char* baseAddress, const char* relativePath); +uint32_t load_loader_elf(unsigned char* baseAddress, char * elf_data, uint32_t fileSize); + +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 +#define R_PPC_ADDR16_LO 4 +#define R_PPC_ADDR16_HI 5 +#define R_PPC_ADDR16_HA 6 +#define R_PPC_REL24 10 +#define R_PPC_REL14 11 +#define R_PPC_DTPMOD32 68 +#define R_PPC_DTPREL32 78 +#define R_PPC_EMB_SDA21 109 +#define R_PPC_EMB_RELSDA 116 +#define R_PPC_DIAB_SDA21_LO 180 +#define R_PPC_DIAB_SDA21_HI 181 +#define R_PPC_DIAB_SDA21_HA 182 +#define R_PPC_DIAB_RELSDA_LO 183 +#define R_PPC_DIAB_RELSDA_HI 184 +#define R_PPC_DIAB_RELSDA_HA 185 +#define R_PPC_GHS_REL16_HA 251 +#define R_PPC_GHS_REL16_HI 252 +#define R_PPC_GHS_REL16_LO 253 + +// Masks for manipulating Power PC relocation targets +#define PPC_WORD32 0xFFFFFFFF +#define PPC_WORD30 0xFFFFFFFC +#define PPC_LOW24 0x03FFFFFC +#define PPC_LOW14 0x0020FFFC +#define PPC_HALF16 0xFFFF + +#ifdef __cplusplus +} +#endif + +class ElfUtils { + +public: + static bool elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampolin_entry_t * trampolin_data, uint32_t trampolin_data_length, RelocationType reloc_type); +}; diff --git a/src/common/dynamic_linking_defines.h b/src/common/dynamic_linking_defines.h new file mode 100644 index 0000000..2a87d80 --- /dev/null +++ b/src/common/dynamic_linking_defines.h @@ -0,0 +1,61 @@ +/**************************************************************************** + * Copyright (C) 2018 Maschell + * + * 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 3 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 . + ****************************************************************************/ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DYN_LINK_FUNCTION_NAME_LENGTH 351 +#define DYN_LINK_IMPORT_NAME_LENGTH 50 + +#define DYN_LINK_FUNCTION_LIST_LENGTH 500 +#define DYN_LINK_IMPORT_LIST_LENGTH 50 + +#define DYN_LINK_TRAMPOLIN_LIST_LENGTH DYN_LINK_FUNCTION_LIST_LENGTH + +typedef struct _dyn_linking_function_t { + char functionName[DYN_LINK_FUNCTION_NAME_LENGTH+1]; + void * address; +} dyn_linking_function_t; + +typedef struct _dyn_linking_import_t { + char importName[DYN_LINK_IMPORT_NAME_LENGTH+1]; + bool isData = false; +} dyn_linking_import_t; + +typedef struct _dyn_linking_relocation_entry_t { + dyn_linking_function_t* functionEntry = NULL; + dyn_linking_import_t* importEntry = NULL; + void * destination = NULL; + char type; + size_t offset; + int32_t addend; +} dyn_linking_relocation_entry_t; + +typedef struct _dyn_linking_relocation_data_t { + dyn_linking_function_t functions[DYN_LINK_FUNCTION_LIST_LENGTH]; + dyn_linking_import_t imports[DYN_LINK_IMPORT_LIST_LENGTH]; +} dyn_linking_relocation_data_t; + +#ifdef __cplusplus +} +#endif diff --git a/src/common/module_defines.h b/src/common/module_defines.h new file mode 100644 index 0000000..f14e5df --- /dev/null +++ b/src/common/module_defines.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * Copyright (C) 2018-2019 Maschell + * + * 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 3 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 . + ****************************************************************************/ + +#pragma once + +#include +#include +#include "dynamic_linking_defines.h" +#include "relocation_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAXIMUM_MODULE_PATH_NAME_LENGTH 256 +#define MAXIMUM_MODULE_NAME_LENGTH 51 + +#define DYN_LINK_RELOCATION_LIST_LENGTH 500 + +struct module_information_single_t { + char path[MAXIMUM_MODULE_PATH_NAME_LENGTH] = ""; // Path where the module is stored + dyn_linking_relocation_entry_t linking_entries[DYN_LINK_RELOCATION_LIST_LENGTH]; + int32_t priority; // Priority of this module + uint32_t bssAddr; + uint32_t bssSize; + uint32_t sbssAddr; + uint32_t sbssSize; + uint32_t entrypoint; +}; + +#define MAXIMUM_MODULES 8 + +struct module_information_t { + int32_t number_used_modules = 0; // Number of used function. Maximum is MAXIMUM_MODULES + dyn_linking_relocation_data_t linking_data; + relocation_trampolin_entry_t trampolines[DYN_LINK_TRAMPOLIN_LIST_LENGTH]; + module_information_single_t module_data[MAXIMUM_MODULES]; +}; + +#ifdef __cplusplus +} +#endif diff --git a/src/common/relocation_defines.h b/src/common/relocation_defines.h new file mode 100644 index 0000000..e1d7051 --- /dev/null +++ b/src/common/relocation_defines.h @@ -0,0 +1,19 @@ +#pragma once +#include + +typedef enum RelocationTrampolinStatus{ + RELOC_TRAMP_FREE = 0, + RELOC_TRAMP_FIXED = 1, + RELOC_TRAMP_IMPORT_IN_PROGRESS = 2, + RELOC_TRAMP_IMPORT_DONE = 3, +} RelocationTrampolinStatus; + +typedef enum RelocationType{ + RELOC_TYPE_FIXED = 0, + RELOC_TYPE_IMPORT = 1 +} RelocationType; + +typedef struct relocation_trampolin_entry_t { + uint32_t trampolin[4]; + RelocationTrampolinStatus status = RELOC_TRAMP_FREE; +} relocation_trampolin_entry_t; diff --git a/src/dynamic.c b/src/dynamic.c new file mode 100644 index 0000000..f125518 --- /dev/null +++ b/src/dynamic.c @@ -0,0 +1,37 @@ +#include +#include + +#define IMPORT(name) void* addr_##name +#define IMPORT_BEGIN(lib) +#define IMPORT_END() +#include "imports.h" + +#undef IMPORT +#undef IMPORT_BEGIN +#undef IMPORT_END + +#define IMPORT(name) do{if(OSDynLoad_FindExport(handle, 0, #name, &addr_##name) < 0)OSFatal("Function " # name " is NULL");} while(0) +#define IMPORT_BEGIN(lib) OSDynLoad_Acquire(#lib ".rpl", &handle) +/* #define IMPORT_END() OSDynLoad_Release(handle) */ +#define IMPORT_END() + +#define EXPORT_VAR(type, var) type var __attribute__((section(".data"))); + +EXPORT_VAR(uint32_t *, pMEMAllocFromDefaultHeapEx); +EXPORT_VAR(uint32_t *, pMEMAllocFromDefaultHeap); +EXPORT_VAR(uint32_t *, pMEMFreeToDefaultHeap); + + +void InitFunctionPointers(void) { + OSDynLoad_Module handle; + addr_OSDynLoad_Acquire = (void*) 0x0102A3B4; + addr_OSDynLoad_FindExport = (void*) 0x0102B828; + + OSDynLoad_Acquire("coreinit.rpl", &handle); + OSDynLoad_FindExport(handle, 1, "MEMAllocFromDefaultHeapEx", (void**) &pMEMAllocFromDefaultHeapEx); + OSDynLoad_FindExport(handle, 1, "MEMAllocFromDefaultHeap", (void**) &pMEMAllocFromDefaultHeap); + OSDynLoad_FindExport(handle, 1, "MEMFreeToDefaultHeap", (void**) &pMEMFreeToDefaultHeap); + +#include "imports.h" + +} diff --git a/src/dynamic.h b/src/dynamic.h new file mode 100644 index 0000000..be625d1 --- /dev/null +++ b/src/dynamic.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void InitFunctionPointers(void); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/elfio/elf_types.hpp b/src/elfio/elf_types.hpp new file mode 100644 index 0000000..63d025a --- /dev/null +++ b/src/elfio/elf_types.hpp @@ -0,0 +1,851 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFTYPES_H +#define ELFTYPES_H + +#ifndef ELFIO_NO_OWN_TYPES + #if !defined(ELFIO_NO_CSTDINT) && !defined(ELFIO_NO_INTTYPES) + #include + #else + typedef unsigned char uint8_t; + typedef signed char int8_t; + typedef unsigned short uint16_t; + typedef signed short int16_t; + #ifdef _MSC_VER + typedef unsigned __int32 uint32_t; + typedef signed __int32 int32_t; + typedef unsigned __int64 uint64_t; + typedef signed __int64 int64_t; + #else + typedef unsigned int uint32_t; + typedef signed int int32_t; + typedef unsigned long long uint64_t; + typedef signed long long int64_t; + #endif // _MSC_VER + #endif // ELFIO_NO_CSTDINT +#endif // ELFIO_NO_OWN_TYPES + +namespace ELFIO { + +// Attention! Platform depended definitions. +typedef uint16_t Elf_Half; +typedef uint32_t Elf_Word; +typedef int32_t Elf_Sword; +typedef uint64_t Elf_Xword; +typedef int64_t Elf_Sxword; + +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; + +#define Elf32_Half Elf_Half +#define Elf64_Half Elf_Half +#define Elf32_Word Elf_Word +#define Elf64_Word Elf_Word +#define Elf32_Sword Elf_Sword +#define Elf64_Sword Elf_Sword + +/////////////////////// +// ELF Header Constants + +// File type +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOOS 0xFE00 +#define ET_HIOS 0xFEFF +#define ET_LOPROC 0xFF00 +#define ET_HIPROC 0xFFFF + + +#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_486 6 // Intel 80486// Reserved for future use +#define EM_860 7 // Intel 80860 +#define EM_MIPS 8 // MIPS R3000 (officially, big-endian only) +#define EM_S370 9 // IBM System/370 +#define EM_MIPS_RS3_LE 10 // MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated +#define EM_res011 11 // Reserved +#define EM_res012 12 // Reserved +#define EM_res013 13 // Reserved +#define EM_res014 14 // Reserved +#define EM_PARISC 15 // HPPA +#define EM_res016 16 // Reserved +#define EM_VPP550 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 // 64-bit PowerPC +#define EM_S390 22 // IBM S/390 +#define EM_SPU 23 // Sony/Toshiba/IBM SPU +#define EM_res024 24 // Reserved +#define EM_res025 25 // Reserved +#define EM_res026 26 // Reserved +#define EM_res027 27 // Reserved +#define EM_res028 28 // Reserved +#define EM_res029 29 // Reserved +#define EM_res030 30 // Reserved +#define EM_res031 31 // Reserved +#define EM_res032 32 // Reserved +#define EM_res033 33 // Reserved +#define EM_res034 34 // Reserved +#define EM_res035 35 // Reserved +#define EM_V800 36 // NEC V800 series +#define EM_FR20 37 // Fujitsu FR20 +#define EM_RH32 38 // TRW RH32 +#define EM_MCORE 39 // Motorola M*Core // May also be taken by Fujitsu MMA +#define EM_RCE 39 // Old name for MCore +#define EM_ARM 40 // ARM +#define EM_OLD_ALPHA 41 // Digital Alpha +#define EM_SH 42 // Renesas (formerly Hitachi) / SuperH SH +#define EM_SPARCV9 43 // SPARC v9 64-bit +#define EM_TRICORE 44 // Siemens Tricore embedded processor +#define EM_ARC 45 // ARC Cores +#define EM_H8_300 46 // Renesas (formerly Hitachi) H8/300 +#define EM_H8_300H 47 // Renesas (formerly Hitachi) H8/300H +#define EM_H8S 48 // Renesas (formerly Hitachi) H8S +#define EM_H8_500 49 // Renesas (formerly Hitachi) H8/500 +#define EM_IA_64 50 // Intel IA-64 Processor +#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 Multimedia Accelerator +#define EM_PCP 55 // Siemens PCP +#define EM_NCPU 56 // Sony nCPU embedded RISC processor +#define EM_NDR1 57 // Denso NDR1 microprocesspr +#define EM_STARCORE 58 // Motorola Star*Core processor +#define EM_ME16 59 // Toyota ME16 processor +#define EM_ST100 60 // STMicroelectronics ST100 processor +#define EM_TINYJ 61 // Advanced Logic Corp. TinyJ embedded processor +#define EM_X86_64 62 // Advanced Micro Devices X86-64 processor +#define EM_PDSP 63 // Sony DSP Processor +#define EM_PDP10 64 // Digital Equipment Corp. PDP-10 +#define EM_PDP11 65 // Digital Equipment Corp. PDP-11 +#define EM_FX66 66 // Siemens FX66 microcontroller +#define EM_ST9PLUS 67 // STMicroelectronics ST9+ 8/16 bit microcontroller +#define EM_ST7 68 // STMicroelectronics ST7 8-bit microcontroller +#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 cpu +#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 cpu +#define EM_FIREPATH 78 // Element 14 64-bit DSP processor +#define EM_ZSP 79 // LSI Logic's 16-bit DSP processor +#define EM_MMIX 80 // Donald Knuth's educational 64-bit processor +#define EM_HUANY 81 // Harvard's machine-independent format +#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 // Renesas M32R (formerly 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_VIDEOCORE 95 // Alphamosaic VideoCore processor +#define EM_TMM_GPP 96 // Thompson Multimedia General Purpose Processor +#define EM_NS32K 97 // National Semiconductor 32000 series +#define EM_TPC 98 // Tenor Network TPC processor +#define EM_SNP1K 99 // Trebia SNP 1000 processor +#define EM_ST200 100 // STMicroelectronics ST200 microcontroller +#define EM_IP2K 101 // Ubicom IP2022 micro controller +#define EM_MAX 102 // MAX Processor +#define EM_CR 103 // National Semiconductor CompactRISC +#define EM_F2MC16 104 // Fujitsu F2MC16 +#define EM_MSP430 105 // TI msp430 micro controller +#define EM_BLACKFIN 106 // ADI Blackfin +#define EM_SE_C33 107 // S1C33 Family of Seiko Epson processors +#define EM_SEP 108 // Sharp embedded microprocessor +#define EM_ARCA 109 // Arca RISC Microprocessor +#define EM_UNICORE 110 // Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University +#define EM_EXCESS 111 // eXcess: 16/32/64-bit configurable embedded CPU +#define EM_DXP 112 // Icera Semiconductor Inc. Deep Execution Processor +#define EM_ALTERA_NIOS2 113 // Altera Nios II soft-core processor +#define EM_CRX 114 // National Semiconductor CRX +#define EM_XGATE 115 // Motorola XGATE embedded processor +#define EM_C166 116 // Infineon C16x/XC16x processor +#define EM_M16C 117 // Renesas M16C series microprocessors +#define EM_DSPIC30F 118 // Microchip Technology dsPIC30F Digital Signal Controller +#define EM_CE 119 // Freescale Communication Engine RISC core +#define EM_M32C 120 // Renesas M32C series microprocessors +#define EM_res121 121 // Reserved +#define EM_res122 122 // Reserved +#define EM_res123 123 // Reserved +#define EM_res124 124 // Reserved +#define EM_res125 125 // Reserved +#define EM_res126 126 // Reserved +#define EM_res127 127 // Reserved +#define EM_res128 128 // Reserved +#define EM_res129 129 // Reserved +#define EM_res130 130 // Reserved +#define EM_TSK3000 131 // Altium TSK3000 core +#define EM_RS08 132 // Freescale RS08 embedded processor +#define EM_res133 133 // Reserved +#define EM_ECOG2 134 // Cyan Technology eCOG2 microprocessor +#define EM_SCORE 135 // Sunplus Score +#define EM_SCORE7 135 // Sunplus S+core7 RISC processor +#define EM_DSP24 136 // New Japan Radio (NJR) 24-bit DSP Processor +#define EM_VIDEOCORE3 137 // Broadcom VideoCore III processor +#define EM_LATTICEMICO32 138 // RISC processor for Lattice FPGA architecture +#define EM_SE_C17 139 // Seiko Epson C17 family +#define EM_TI_C6000 140 // Texas Instruments TMS320C6000 DSP family +#define EM_TI_C2000 141 // Texas Instruments TMS320C2000 DSP family +#define EM_TI_C5500 142 // Texas Instruments TMS320C55x DSP family +#define EM_res143 143 // Reserved +#define EM_res144 144 // Reserved +#define EM_res145 145 // Reserved +#define EM_res146 146 // Reserved +#define EM_res147 147 // Reserved +#define EM_res148 148 // Reserved +#define EM_res149 149 // Reserved +#define EM_res150 150 // Reserved +#define EM_res151 151 // Reserved +#define EM_res152 152 // Reserved +#define EM_res153 153 // Reserved +#define EM_res154 154 // Reserved +#define EM_res155 155 // Reserved +#define EM_res156 156 // Reserved +#define EM_res157 157 // Reserved +#define EM_res158 158 // Reserved +#define EM_res159 159 // Reserved +#define EM_MMDSP_PLUS 160 // STMicroelectronics 64bit VLIW Data Signal Processor +#define EM_CYPRESS_M8C 161 // Cypress M8C microprocessor +#define EM_R32C 162 // Renesas R32C series microprocessors +#define EM_TRIMEDIA 163 // NXP Semiconductors TriMedia architecture family +#define EM_QDSP6 164 // QUALCOMM DSP6 Processor +#define EM_8051 165 // Intel 8051 and variants +#define EM_STXP7X 166 // STMicroelectronics STxP7x family +#define EM_NDS32 167 // Andes Technology compact code size embedded RISC processor family +#define EM_ECOG1 168 // Cyan Technology eCOG1X family +#define EM_ECOG1X 168 // Cyan Technology eCOG1X family +#define EM_MAXQ30 169 // Dallas Semiconductor MAXQ30 Core Micro-controllers +#define EM_XIMO16 170 // New Japan Radio (NJR) 16-bit DSP Processor +#define EM_MANIK 171 // M2000 Reconfigurable RISC Microprocessor +#define EM_CRAYNV2 172 // Cray Inc. NV2 vector architecture +#define EM_RX 173 // Renesas RX family +#define EM_METAG 174 // Imagination Technologies META processor architecture +#define EM_MCST_ELBRUS 175 // MCST Elbrus general purpose hardware architecture +#define EM_ECOG16 176 // Cyan Technology eCOG16 family +#define EM_CR16 177 // National Semiconductor CompactRISC 16-bit processor +#define EM_ETPU 178 // Freescale Extended Time Processing Unit +#define EM_SLE9X 179 // Infineon Technologies SLE9X core +#define EM_L1OM 180 // Intel L1OM +#define EM_INTEL181 181 // Reserved by Intel +#define EM_INTEL182 182 // Reserved by Intel +#define EM_res183 183 // Reserved by ARM +#define EM_res184 184 // Reserved by ARM +#define EM_AVR32 185 // Atmel Corporation 32-bit microprocessor family +#define EM_STM8 186 // STMicroeletronics STM8 8-bit microcontroller +#define EM_TILE64 187 // Tilera TILE64 multicore architecture family +#define EM_TILEPRO 188 // Tilera TILEPro multicore architecture family +#define EM_MICROBLAZE 189 // Xilinx MicroBlaze 32-bit RISC soft processor core +#define EM_CUDA 190 // NVIDIA CUDA architecture +#define EM_TILEGX 191 // Tilera TILE-Gx multicore architecture family +#define EM_CLOUDSHIELD 192 // CloudShield architecture family +#define EM_COREA_1ST 193 // KIPO-KAIST Core-A 1st generation processor family +#define EM_COREA_2ND 194 // KIPO-KAIST Core-A 2nd generation processor family +#define EM_ARC_COMPACT2 195 // Synopsys ARCompact V2 +#define EM_OPEN8 196 // Open8 8-bit RISC soft processor core +#define EM_RL78 197 // Renesas RL78 family +#define EM_VIDEOCORE5 198 // Broadcom VideoCore V processor +#define EM_78KOR 199 // Renesas 78KOR family +#define EM_56800EX 200 // Freescale 56800EX Digital Signal Controller (DSC) +#define EM_BA1 201 // Beyond BA1 CPU architecture +#define EM_BA2 202 // Beyond BA2 CPU architecture +#define EM_XCORE 203 // XMOS xCORE processor family +#define EM_MCHP_PIC 204 // Microchip 8-bit PIC(r) family +#define EM_INTEL205 205 // Reserved by Intel +#define EM_INTEL206 206 // Reserved by Intel +#define EM_INTEL207 207 // Reserved by Intel +#define EM_INTEL208 208 // Reserved by Intel +#define EM_INTEL209 209 // Reserved by Intel +#define EM_KM32 210 // KM211 KM32 32-bit processor +#define EM_KMX32 211 // KM211 KMX32 32-bit processor +#define EM_KMX16 212 // KM211 KMX16 16-bit processor +#define EM_KMX8 213 // KM211 KMX8 8-bit processor +#define EM_KVARC 214 // KM211 KVARC processor +#define EM_CDP 215 // Paneve CDP architecture family +#define EM_COGE 216 // Cognitive Smart Memory Processor +#define EM_COOL 217 // iCelero CoolEngine +#define EM_NORC 218 // Nanoradio Optimized RISC +#define EM_CSR_KALIMBA 219 // CSR Kalimba architecture family +#define EM_Z80 220 // Zilog Z80 +#define EM_VISIUM 221 // Controls and Data Services VISIUMcore processor +#define EM_FT32 222 // FTDI Chip FT32 high performance 32-bit RISC architecture +#define EM_MOXIE 223 // Moxie processor family +#define EM_AMDGPU 224 // AMD GPU architecture +#define EM_RISCV 243 // RISC-V +#define EM_LANAI 244 // Lanai processor +#define EM_CEVA 245 // CEVA Processor Architecture Family +#define EM_CEVA_X2 246 // CEVA X2 Processor Family +#define EM_BPF 247 // Linux BPF – in-kernel virtual machine + +// File version +#define EV_NONE 0 +#define EV_CURRENT 1 + +// Identification index +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_ABIVERSION 8 +#define EI_PAD 9 +#define EI_NIDENT 16 + +// Magic number +#define ELFMAG0 0x7F +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +// File class +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +// Encoding +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +// OS extensions +#define ELFOSABI_NONE 0 // No extensions or unspecified +#define ELFOSABI_HPUX 1 // Hewlett-Packard HP-UX +#define ELFOSABI_NETBSD 2 // NetBSD +#define ELFOSABI_LINUX 3 // Linux +#define ELFOSABI_SOLARIS 6 // Sun Solaris +#define ELFOSABI_AIX 7 // AIX +#define ELFOSABI_IRIX 8 // IRIX +#define ELFOSABI_FREEBSD 9 // FreeBSD +#define ELFOSABI_TRU64 10 // Compaq TRU64 UNIX +#define ELFOSABI_MODESTO 11 // Novell Modesto +#define ELFOSABI_OPENBSD 12 // Open BSD +#define ELFOSABI_OPENVMS 13 // Open VMS +#define ELFOSABI_NSK 14 // Hewlett-Packard Non-Stop Kernel +#define ELFOSABI_AROS 15 // Amiga Research OS +#define ELFOSABI_FENIXOS 16 // The FenixOS highly scalable multi-core OS +// 64-255 Architecture-specific value range +#define ELFOSABI_AMDGPU_HSA 64 // AMDGPU OS for HSA compatible compute + // kernels. +#define ELFOSABI_AMDGPU_PAL 65 // AMDGPU OS for AMD PAL compatible graphics + // shaders and compute kernels. +#define ELFOSABI_AMDGPU_MESA3D 66 // AMDGPU OS for Mesa3D compatible graphics + // shaders and compute kernels. + + +// AMDGPU specific e_flags +#define EF_AMDGPU_MACH 0x0ff // AMDGPU processor selection mask. +#define EF_AMDGPU_XNACK 0x100 // Indicates if the XNACK target feature is + // enabled for all code contained in the ELF. +// AMDGPU processors +#define EF_AMDGPU_MACH_NONE 0x000 // Unspecified processor. +#define EF_AMDGPU_MACH_R600_R600 0x001 +#define EF_AMDGPU_MACH_R600_R630 0x002 +#define EF_AMDGPU_MACH_R600_RS880 0x003 +#define EF_AMDGPU_MACH_R600_RV670 0x004 +#define EF_AMDGPU_MACH_R600_RV710 0x005 +#define EF_AMDGPU_MACH_R600_RV730 0x006 +#define EF_AMDGPU_MACH_R600_RV770 0x007 +#define EF_AMDGPU_MACH_R600_CEDAR 0x008 +#define EF_AMDGPU_MACH_R600_CYPRESS 0x009 +#define EF_AMDGPU_MACH_R600_JUNIPER 0x00a +#define EF_AMDGPU_MACH_R600_REDWOOD 0x00b +#define EF_AMDGPU_MACH_R600_SUMO 0x00c +#define EF_AMDGPU_MACH_R600_BARTS 0x00d +#define EF_AMDGPU_MACH_R600_CAICOS 0x00e +#define EF_AMDGPU_MACH_R600_CAYMAN 0x00f +#define EF_AMDGPU_MACH_R600_TURKS 0x010 +#define EF_AMDGPU_MACH_R600_RESERVED_FIRST 0x011 +#define EF_AMDGPU_MACH_R600_RESERVED_LAST 0x01f +#define EF_AMDGPU_MACH_R600_FIRST EF_AMDGPU_MACH_R600_R600 +#define EF_AMDGPU_MACH_R600_LAST EF_AMDGPU_MACH_R600_TURKS +#define EF_AMDGPU_MACH_AMDGCN_GFX600 0x020 +#define EF_AMDGPU_MACH_AMDGCN_GFX601 0x021 +#define EF_AMDGPU_MACH_AMDGCN_GFX700 0x022 +#define EF_AMDGPU_MACH_AMDGCN_GFX701 0x023 +#define EF_AMDGPU_MACH_AMDGCN_GFX702 0x024 +#define EF_AMDGPU_MACH_AMDGCN_GFX703 0x025 +#define EF_AMDGPU_MACH_AMDGCN_GFX704 0x026 +#define EF_AMDGPU_MACH_AMDGCN_GFX801 0x028 +#define EF_AMDGPU_MACH_AMDGCN_GFX802 0x029 +#define EF_AMDGPU_MACH_AMDGCN_GFX803 0x02a +#define EF_AMDGPU_MACH_AMDGCN_GFX810 0x02b +#define EF_AMDGPU_MACH_AMDGCN_GFX900 0x02c +#define EF_AMDGPU_MACH_AMDGCN_GFX902 0x02d +#define EF_AMDGPU_MACH_AMDGCN_GFX904 0x02e +#define EF_AMDGPU_MACH_AMDGCN_GFX906 0x02f +#define EF_AMDGPU_MACH_AMDGCN_RESERVED0 0x027 +#define EF_AMDGPU_MACH_AMDGCN_RESERVED1 0x030 +#define EF_AMDGPU_MACH_AMDGCN_FIRST EF_AMDGPU_MACH_AMDGCN_GFX600 +#define EF_AMDGPU_MACH_AMDGCN_LAST EF_AMDGPU_MACH_AMDGCN_GFX906 + +///////////////////// +// Sections constants + +// Section indexes +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xFF00 +#define SHN_LOPROC 0xFF00 +#define SHN_HIPROC 0xFF1F +#define SHN_LOOS 0xFF20 +#define SHN_HIOS 0xFF3F +#define SHN_ABS 0xFFF1 +#define SHN_COMMON 0xFFF2 +#define SHN_XINDEX 0xFFFF +#define SHN_HIRESERVE 0xFFFF + +// Section types +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_LOOS 0x60000000 +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7FFFFFFF +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xFFFFFFFF + +// Section attribute flags +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MERGE 0x10 +#define SHF_STRINGS 0x20 +#define SHF_INFO_LINK 0x40 +#define SHF_LINK_ORDER 0x80 +#define SHF_OS_NONCONFORMING 0x100 +#define SHF_GROUP 0x200 +#define SHF_TLS 0x400 +#define SHF_MASKOS 0x0ff00000 +#define SHF_MASKPROC 0xF0000000 + +// Section group flags +#define GRP_COMDAT 0x1 +#define GRP_MASKOS 0x0ff00000 +#define GRP_MASKPROC 0xf0000000 + +// Symbol binding +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOOS 10 +#define STB_HIOS 12 +#define STB_MULTIDEF 13 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +// Note types +#define NT_AMDGPU_METADATA 1 +#define NT_AMD_AMDGPU_HSA_METADATA 10 +#define NT_AMD_AMDGPU_ISA 11 +#define NT_AMD_AMDGPU_PAL_METADATA 12 + +// Symbol types +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 +#define STT_LOOS 10 +#define STT_AMDGPU_HSA_KERNEL 10 +#define STT_HIOS 12 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +// Symbol visibility +#define STV_DEFAULT 0 +#define STV_INTERNAL 1 +#define STV_HIDDEN 2 +#define STV_PROTECTED 3 + +// Undefined name +#define STN_UNDEF 0 + +// Relocation types +#define R_386_NONE 0 +#define R_X86_64_NONE 0 +#define R_AMDGPU_NONE 0 +#define R_386_32 1 +#define R_X86_64_64 1 +#define R_AMDGPU_ABS32_LO 1 +#define R_386_PC32 2 +#define R_X86_64_PC32 2 +#define R_AMDGPU_ABS32_HI 2 +#define R_386_GOT32 3 +#define R_X86_64_GOT32 3 +#define R_AMDGPU_ABS64 3 +#define R_386_PLT32 4 +#define R_X86_64_PLT32 4 +#define R_AMDGPU_REL32 4 +#define R_386_COPY 5 +#define R_X86_64_COPY 5 +#define R_AMDGPU_REL64 5 +#define R_386_GLOB_DAT 6 +#define R_X86_64_GLOB_DAT 6 +#define R_AMDGPU_ABS32 6 +#define R_386_JMP_SLOT 7 +#define R_X86_64_JUMP_SLOT 7 +#define R_AMDGPU_GOTPCREL 7 +#define R_386_RELATIVE 8 +#define R_X86_64_RELATIVE 8 +#define R_AMDGPU_GOTPCREL32_LO 8 +#define R_386_GOTOFF 9 +#define R_X86_64_GOTPCREL 9 +#define R_AMDGPU_GOTPCREL32_HI 9 +#define R_386_GOTPC 10 +#define R_X86_64_32 10 +#define R_AMDGPU_REL32_LO 10 +#define R_386_32PLT 11 +#define R_X86_64_32S 11 +#define R_AMDGPU_REL32_HI 11 +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_AMDGPU_RELATIVE64 13 +#define R_386_TLS_TPOFF 14 +#define R_X86_64_8 14 +#define R_386_TLS_IE 15 +#define R_X86_64_PC8 15 +#define R_386_TLS_GOTIE 16 +#define R_X86_64_DTPMOD64 16 +#define R_386_TLS_LE 17 +#define R_X86_64_DTPOFF64 17 +#define R_386_TLS_GD 18 +#define R_X86_64_TPOFF64 18 +#define R_386_TLS_LDM 19 +#define R_X86_64_TLSGD 19 +#define R_386_16 20 +#define R_X86_64_TLSLD 20 +#define R_386_PC16 21 +#define R_X86_64_DTPOFF32 21 +#define R_386_8 22 +#define R_X86_64_GOTTPOFF 22 +#define R_386_PC8 23 +#define R_X86_64_TPOFF32 23 +#define R_386_TLS_GD_32 24 +#define R_X86_64_PC64 24 +#define R_386_TLS_GD_PUSH 25 +#define R_X86_64_GOTOFF64 25 +#define R_386_TLS_GD_CALL 26 +#define R_X86_64_GOTPC32 26 +#define R_386_TLS_GD_POP 27 +#define R_X86_64_GOT64 27 +#define R_386_TLS_LDM_32 28 +#define R_X86_64_GOTPCREL64 28 +#define R_386_TLS_LDM_PUSH 29 +#define R_X86_64_GOTPC64 29 +#define R_386_TLS_LDM_CALL 30 +#define R_X86_64_GOTPLT64 30 +#define R_386_TLS_LDM_POP 31 +#define R_X86_64_PLTOFF64 31 +#define R_386_TLS_LDO_32 32 +#define R_386_TLS_IE_32 33 +#define R_386_TLS_LE_32 34 +#define R_X86_64_GOTPC32_TLSDESC 34 +#define R_386_TLS_DTPMOD32 35 +#define R_X86_64_TLSDESC_CALL 35 +#define R_386_TLS_DTPOFF32 36 +#define R_X86_64_TLSDESC 36 +#define R_386_TLS_TPOFF32 37 +#define R_X86_64_IRELATIVE 37 +#define R_386_SIZE32 38 +#define R_386_TLS_GOTDESC 39 +#define R_386_TLS_DESC_CALL 40 +#define R_386_TLS_DESC 41 +#define R_386_IRELATIVE 42 +#define R_386_GOT32X 43 +#define R_X86_64_GNU_VTINHERIT 250 +#define R_X86_64_GNU_VTENTRY 251 + +// Segment types +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 +#define PT_LOOS 0x60000000 +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF + +// Segment flags +#define PF_X 1 // Execute +#define PF_W 2 // Write +#define PF_R 4 // Read +#define PF_MASKOS 0x0ff00000 // Unspecified +#define PF_MASKPROC 0xf0000000 // Unspecified + +// Dynamic Array Tags +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_BIND_NOW 24 +#define DT_INIT_ARRAY 25 +#define DT_FINI_ARRAY 26 +#define DT_INIT_ARRAYSZ 27 +#define DT_FINI_ARRAYSZ 28 +#define DT_RUNPATH 29 +#define DT_FLAGS 30 +#define DT_ENCODING 32 +#define DT_PREINIT_ARRAY 32 +#define DT_PREINIT_ARRAYSZ 33 +#define DT_MAXPOSTAGS 34 +#define DT_LOOS 0x6000000D +#define DT_HIOS 0x6ffff000 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7FFFFFFF + +// DT_FLAGS values +#define DF_ORIGIN 0x1 +#define DF_SYMBOLIC 0x2 +#define DF_TEXTREL 0x4 +#define DF_BIND_NOW 0x8 +#define DF_STATIC_TLS 0x10 + + +// ELF file header +struct Elf32_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf_Half e_type; + Elf_Half e_machine; + Elf_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf_Word e_flags; + Elf_Half e_ehsize; + Elf_Half e_phentsize; + Elf_Half e_phnum; + Elf_Half e_shentsize; + Elf_Half e_shnum; + Elf_Half e_shstrndx; +}; + +struct Elf64_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf_Half e_type; + Elf_Half e_machine; + Elf_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf_Word e_flags; + Elf_Half e_ehsize; + Elf_Half e_phentsize; + Elf_Half e_phnum; + Elf_Half e_shentsize; + Elf_Half e_shnum; + Elf_Half e_shstrndx; +}; + + +// Section header +struct Elf32_Shdr { + Elf_Word sh_name; + Elf_Word sh_type; + Elf_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf_Word sh_size; + Elf_Word sh_link; + Elf_Word sh_info; + Elf_Word sh_addralign; + Elf_Word sh_entsize; +}; + +struct Elf64_Shdr { + Elf_Word sh_name; + Elf_Word sh_type; + Elf_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf_Xword sh_size; + Elf_Word sh_link; + Elf_Word sh_info; + Elf_Xword sh_addralign; + Elf_Xword sh_entsize; +}; + + +// Segment header +struct Elf32_Phdr { + Elf_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf_Word p_filesz; + Elf_Word p_memsz; + Elf_Word p_flags; + Elf_Word p_align; +}; + +struct Elf64_Phdr { + Elf_Word p_type; + Elf_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf_Xword p_filesz; + Elf_Xword p_memsz; + Elf_Xword p_align; +}; + + +// Symbol table entry +struct Elf32_Sym { + Elf_Word st_name; + Elf32_Addr st_value; + Elf_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf_Half st_shndx; +}; + +struct Elf64_Sym { + Elf_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf_Half st_shndx; + Elf64_Addr st_value; + Elf_Xword st_size; +}; + + +#define ELF_ST_BIND(i) ((i)>>4) +#define ELF_ST_TYPE(i) ((i)&0xf) +#define ELF_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +#define ELF_ST_VISIBILITY(o) ((o)&0x3) + + +// Relocation entries +struct Elf32_Rel { + Elf32_Addr r_offset; + Elf_Word r_info; +}; + +struct Elf32_Rela { + Elf32_Addr r_offset; + Elf_Word r_info; + Elf_Sword r_addend; +}; + +struct Elf64_Rel { + Elf64_Addr r_offset; + Elf_Xword r_info; +}; + +struct Elf64_Rela { + Elf64_Addr r_offset; + Elf_Xword r_info; + Elf_Sxword r_addend; +}; + + +#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t)) + +#define ELF64_R_SYM(i) ((i)>>32) +#define ELF64_R_TYPE(i) ((i)&0xffffffffL) +#define ELF64_R_INFO(s,t) ((((int64_t)(s))<<32)+((t)&0xffffffffL)) + +// Dynamic structure +struct Elf32_Dyn { + Elf_Sword d_tag; + union { + Elf_Word d_val; + Elf32_Addr d_ptr; + } d_un; +}; + +struct Elf64_Dyn { + Elf_Sxword d_tag; + union { + Elf_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +}; + +} // namespace ELFIO + +#endif // ELFTYPES_H diff --git a/src/elfio/elfio.hpp b/src/elfio/elfio.hpp new file mode 100644 index 0000000..f997b5d --- /dev/null +++ b/src/elfio/elfio.hpp @@ -0,0 +1,955 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_HPP +#define ELFIO_HPP + +#ifdef _MSC_VER +#pragma warning ( push ) +#pragma warning(disable:4996) +#pragma warning(disable:4355) +#pragma warning(disable:4244) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \ +TYPE \ +get_##FNAME() const \ +{ \ + return header? header->get_##FNAME() : 0; \ +} + +#define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ +TYPE \ +get_##FNAME() const \ +{ \ + return header? header->get_##FNAME() : 0; \ +} \ +void \ +set_##FNAME( TYPE val ) \ +{ \ + if (header) { \ + header->set_##FNAME( val ); \ + } \ +} \ + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class elfio +{ + public: +//------------------------------------------------------------------------------ + elfio() : sections( this ), segments( this ) + { + header = 0; + current_file_pos = 0; + create( ELFCLASS32, ELFDATA2LSB ); + } + +//------------------------------------------------------------------------------ + ~elfio() + { + clean(); + } + +//------------------------------------------------------------------------------ + void create( unsigned char file_class, unsigned char encoding ) + { + clean(); + convertor.setup( encoding ); + header = create_header( file_class, encoding ); + create_mandatory_sections(); + } + +//------------------------------------------------------------------------------ + bool load( const std::string& file_name ) + { + std::ifstream stream; + stream.open( file_name.c_str(), std::ios::in | std::ios::binary ); + if ( !stream ) { + return false; + } + + return load(stream); + } + +//------------------------------------------------------------------------------ + bool load( std::istream &stream ) + { + clean(); + + unsigned char e_ident[EI_NIDENT]; + // Read ELF file signature + stream.read( reinterpret_cast( &e_ident ), sizeof( e_ident ) ); + + // Is it ELF file? + if ( stream.gcount() != sizeof( e_ident ) || + e_ident[EI_MAG0] != ELFMAG0 || + e_ident[EI_MAG1] != ELFMAG1 || + e_ident[EI_MAG2] != ELFMAG2 || + e_ident[EI_MAG3] != ELFMAG3 ) { + return false; + } + + if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) && + ( e_ident[EI_CLASS] != ELFCLASS32 )) { + return false; + } + + convertor.setup( e_ident[EI_DATA] ); + header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] ); + if ( 0 == header ) { + return false; + } + if ( !header->load( stream ) ) { + return false; + } + + load_sections( stream ); + bool is_still_good = load_segments( stream ); + return is_still_good; + } + +//------------------------------------------------------------------------------ + bool save( const std::string& file_name ) + { + std::ofstream stream; + stream.open( file_name.c_str(), std::ios::out | std::ios::binary ); + if ( !stream ) { + return false; + } + + return save(stream); + } + +//------------------------------------------------------------------------------ + bool save( std::ostream &stream ) + { + if ( !stream || !header) { + return false; + } + + bool is_still_good = true; + // Define layout specific header fields + // The position of the segment table is fixed after the header. + // The position of the section table is variable and needs to be fixed + // before saving. + header->set_segments_num( segments.size() ); + header->set_segments_offset( segments.size() ? header->get_header_size() : 0 ); + header->set_sections_num( sections.size() ); + header->set_sections_offset( 0 ); + + // Layout the first section right after the segment table + current_file_pos = header->get_header_size() + + header->get_segment_entry_size() * header->get_segments_num(); + + calc_segment_alignment(); + + is_still_good = layout_segments_and_their_sections(); + is_still_good = is_still_good && layout_sections_without_segments(); + is_still_good = is_still_good && layout_section_table(); + + is_still_good = is_still_good && save_header( stream ); + is_still_good = is_still_good && save_sections( stream ); + is_still_good = is_still_good && save_segments( stream ); + + return is_still_good; + } + +//------------------------------------------------------------------------------ + // ELF header access functions + ELFIO_HEADER_ACCESS_GET( unsigned char, class ); + ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version ); + ELFIO_HEADER_ACCESS_GET( unsigned char, encoding ); + ELFIO_HEADER_ACCESS_GET( Elf_Word, version ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size ); + + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi ); + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index ); + +//------------------------------------------------------------------------------ + const endianess_convertor& get_convertor() const + { + return convertor; + } + +//------------------------------------------------------------------------------ + Elf_Xword get_default_entry_size( Elf_Word section_type ) const + { + switch( section_type ) { + case SHT_RELA: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rela ); + } + else { + return sizeof( Elf32_Rela ); + } + case SHT_REL: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rel ); + } + else { + return sizeof( Elf32_Rel ); + } + case SHT_SYMTAB: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Sym ); + } + else { + return sizeof( Elf32_Sym ); + } + case SHT_DYNAMIC: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Dyn ); + } + else { + return sizeof( Elf32_Dyn ); + } + default: + return 0; + } + } + +//------------------------------------------------------------------------------ + private: + bool is_offset_in_section( Elf64_Off offset, const section* sec ) const { + return offset >= sec->get_offset() && offset < sec->get_offset()+sec->get_size(); + } + +//------------------------------------------------------------------------------ + public: + + //! returns an empty string if no problems are detected, + //! or a string containing an error message if problems are found + std::string validate() const { + + // check for overlapping sections in the file + for ( int i = 0; i < sections.size(); ++i) { + for ( int j = i+1; j < sections.size(); ++j ) { + const section* a = sections[i]; + const section* b = sections[j]; + if ( !(a->get_type() & SHT_NOBITS) + && !(b->get_type() & SHT_NOBITS) + && (a->get_size() > 0) + && (b->get_size() > 0) + && (a->get_offset() > 0) + && (b->get_offset() > 0)) { + if ( is_offset_in_section( a->get_offset(), b ) + || is_offset_in_section( a->get_offset()+a->get_size()-1, b ) + || is_offset_in_section( b->get_offset(), a ) + || is_offset_in_section( b->get_offset()+b->get_size()-1, a )) { + return "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file"; + } + } + } + } + + // more checks to be added here... + + return ""; + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void clean() + { + delete header; + header = 0; + + std::vector::const_iterator it; + for ( it = sections_.begin(); it != sections_.end(); ++it ) { + delete *it; + } + sections_.clear(); + + std::vector::const_iterator it1; + for ( it1 = segments_.begin(); it1 != segments_.end(); ++it1 ) { + delete *it1; + } + segments_.clear(); + } + +//------------------------------------------------------------------------------ + elf_header* create_header( unsigned char file_class, unsigned char encoding ) + { + elf_header* new_header = 0; + + if ( file_class == ELFCLASS64 ) { + new_header = new elf_header_impl< Elf64_Ehdr >( &convertor, + encoding ); + } + else if ( file_class == ELFCLASS32 ) { + new_header = new elf_header_impl< Elf32_Ehdr >( &convertor, + encoding ); + } + else { + return 0; + } + + return new_header; + } + +//------------------------------------------------------------------------------ + section* create_section() + { + section* new_section; + unsigned char file_class = get_class(); + + if ( file_class == ELFCLASS64 ) { + new_section = new section_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + new_section = new section_impl( &convertor ); + } + else { + return 0; + } + + new_section->set_index( (Elf_Half)sections_.size() ); + sections_.push_back( new_section ); + + return new_section; + } + + +//------------------------------------------------------------------------------ + segment* create_segment() + { + segment* new_segment; + unsigned char file_class = header->get_class(); + + if ( file_class == ELFCLASS64 ) { + new_segment = new segment_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + new_segment = new segment_impl( &convertor ); + } + else { + return 0; + } + + new_segment->set_index( (Elf_Half)segments_.size() ); + segments_.push_back( new_segment ); + + return new_segment; + } + +//------------------------------------------------------------------------------ + void create_mandatory_sections() + { + // Create null section without calling to 'add_section' as no string + // section containing section names exists yet + section* sec0 = create_section(); + sec0->set_index( 0 ); + sec0->set_name( "" ); + sec0->set_name_string_offset( 0 ); + + set_section_name_str_index( 1 ); + section* shstrtab = sections.add( ".shstrtab" ); + shstrtab->set_type( SHT_STRTAB ); + shstrtab->set_addr_align( 1 ); + } + +//------------------------------------------------------------------------------ + Elf_Half load_sections( std::istream& stream ) + { + Elf_Half entry_size = header->get_section_entry_size(); + Elf_Half num = header->get_sections_num(); + Elf64_Off offset = header->get_sections_offset(); + + for ( Elf_Half i = 0; i < num; ++i ) { + section* sec = create_section(); + sec->load( stream, (std::streamoff)offset + i * entry_size ); + sec->set_index( i ); + // To mark that the section is not permitted to reassign address + // during layout calculation + sec->set_address( sec->get_address() ); + } + + Elf_Half shstrndx = get_section_name_str_index(); + + if ( SHN_UNDEF != shstrndx ) { + string_section_accessor str_reader( sections[shstrndx] ); + for ( Elf_Half i = 0; i < num; ++i ) { + Elf_Word section_offset = sections[i]->get_name_string_offset(); + const char* p = str_reader.get_string( section_offset ); + if ( p != 0 ) { + sections[i]->set_name( p ); + } + } + } + + return num; + } + +//------------------------------------------------------------------------------ + //! Checks whether the addresses of the section entirely fall within the given segment. + //! It doesn't matter if the addresses are memory addresses, or file offsets, + //! they just need to be in the same address space + bool is_sect_in_seg ( Elf64_Off sect_begin, Elf_Xword sect_size, Elf64_Off seg_begin, Elf64_Off seg_end ) { + return seg_begin <= sect_begin + && sect_begin + sect_size <= seg_end + && sect_begin < seg_end; // this is important criteria when sect_size == 0 + // Example: seg_begin=10, seg_end=12 (-> covering the bytes 10 and 11) + // sect_begin=12, sect_size=0 -> shall return false! + } + +//------------------------------------------------------------------------------ + bool load_segments( std::istream& stream ) + { + Elf_Half entry_size = header->get_segment_entry_size(); + Elf_Half num = header->get_segments_num(); + Elf64_Off offset = header->get_segments_offset(); + + for ( Elf_Half i = 0; i < num; ++i ) { + segment* seg; + unsigned char file_class = header->get_class(); + + if ( file_class == ELFCLASS64 ) { + seg = new segment_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + seg = new segment_impl( &convertor ); + } + else { + return false; + } + + seg->load( stream, (std::streamoff)offset + i * entry_size ); + seg->set_index( i ); + + // Add sections to the segments (similar to readelfs algorithm) + Elf64_Off segBaseOffset = seg->get_offset(); + Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size(); + Elf64_Off segVBaseAddr = seg->get_virtual_address(); + Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size(); + for( Elf_Half j = 0; j < sections.size(); ++j ) { + const section* psec = sections[j]; + + // SHF_ALLOC sections are matched based on the virtual address + // otherwise the file offset is matched + if( psec->get_flags() & SHF_ALLOC + ? is_sect_in_seg( psec->get_address(), psec->get_size(), segVBaseAddr, segVEndAddr ) + : is_sect_in_seg( psec->get_offset(), psec->get_size(), segBaseOffset, segEndOffset )) { + // Alignment of segment shall not be updated, to preserve original value + // It will be re-calculated on saving. + seg->add_section_index( psec->get_index(), 0 ); + } + } + + // Add section into the segments' container + segments_.push_back( seg ); + } + + return true; + } + +//------------------------------------------------------------------------------ + bool save_header( std::ostream& stream ) + { + return header->save( stream ); + } + +//------------------------------------------------------------------------------ + bool save_sections( std::ostream& stream ) + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + section *sec = sections_.at(i); + + std::streampos headerPosition = + (std::streamoff)header->get_sections_offset() + + header->get_section_entry_size() * sec->get_index(); + + sec->save(stream,headerPosition,sec->get_offset()); + } + return true; + } + +//------------------------------------------------------------------------------ + bool save_segments( std::ostream& stream ) + { + for ( unsigned int i = 0; i < segments_.size(); ++i ) { + segment *seg = segments_.at(i); + + std::streampos headerPosition = header->get_segments_offset() + + header->get_segment_entry_size()*seg->get_index(); + + seg->save( stream, headerPosition, seg->get_offset() ); + } + return true; + } + +//------------------------------------------------------------------------------ + bool is_section_without_segment( unsigned int section_index ) + { + bool found = false; + + for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { + for ( unsigned int k = 0; + !found && ( k < segments[j]->get_sections_num() ); + ++k ) { + found = segments[j]->get_section_index_at( k ) == section_index; + } + } + + return !found; + } + +//------------------------------------------------------------------------------ + bool is_subsequence_of( segment* seg1, segment* seg2 ) + { + // Return 'true' if sections of seg1 are a subset of sections in seg2 + const std::vector& sections1 = seg1->get_sections(); + const std::vector& sections2 = seg2->get_sections(); + + bool found = false; + if ( sections1.size() < sections2.size() ) { + found = std::includes( sections2.begin(), sections2.end(), + sections1.begin(), sections1.end() ); + } + + return found; + } + +//------------------------------------------------------------------------------ + std::vector get_ordered_segments( ) + { + std::vector res; + std::deque worklist; + + res.reserve(segments.size()); + std::copy( segments_.begin(), segments_.end(), + std::back_inserter( worklist )) ; + + // Bring the segments which start at address 0 to the front + size_t nextSlot = 0; + for( size_t i = 0; i < worklist.size(); ++i ) { + if( i != nextSlot && worklist[i]->is_offset_initialized() + && worklist[i]->get_offset() == 0 ) { + if (worklist[nextSlot]->get_offset() == 0) { + ++nextSlot; + } + std::swap(worklist[i],worklist[nextSlot]); + ++nextSlot; + } + } + + while ( !worklist.empty() ) { + segment *seg = worklist.front(); + worklist.pop_front(); + + size_t i = 0; + for ( ; i < worklist.size(); ++i ) { + if ( is_subsequence_of( seg, worklist[i] ) ) { + break; + } + } + + if ( i < worklist.size() ) + worklist.push_back(seg); + else + res.push_back(seg); + } + + return res; + } + + +//------------------------------------------------------------------------------ + bool layout_sections_without_segments( ) + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + if ( is_section_without_segment( i ) ) { + section *sec = sections_[i]; + + Elf_Xword section_align = sec->get_addr_align(); + if ( section_align > 1 && current_file_pos % section_align != 0 ) { + current_file_pos += section_align - + current_file_pos % section_align; + } + + if ( 0 != sec->get_index() ) + sec->set_offset(current_file_pos); + + if ( SHT_NOBITS != sec->get_type() && + SHT_NULL != sec->get_type() ) { + current_file_pos += sec->get_size(); + } + } + } + + return true; + } + + +//------------------------------------------------------------------------------ + void calc_segment_alignment( ) + { + for( std::vector::iterator s = segments_.begin(); s != segments_.end(); ++s ) { + segment* seg = *s; + for ( int i = 0; i < seg->get_sections_num(); ++i ) { + section* sect = sections_[ seg->get_section_index_at(i) ]; + if ( sect->get_addr_align() > seg->get_align() ) { + seg->set_align( sect->get_addr_align() ); + } + } + } + } + +//------------------------------------------------------------------------------ + bool layout_segments_and_their_sections( ) + { + std::vector worklist; + std::vector section_generated(sections.size(),false); + + // Get segments in a order in where segments which contain a + // sub sequence of other segments are located at the end + worklist = get_ordered_segments(); + + for ( unsigned int i = 0; i < worklist.size(); ++i ) { + Elf_Xword segment_memory = 0; + Elf_Xword segment_filesize = 0; + Elf_Xword seg_start_pos = current_file_pos; + segment* seg = worklist[i]; + + // Special case: PHDR segment + // This segment contains the program headers but no sections + if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) { + seg_start_pos = header->get_segments_offset(); + segment_memory = segment_filesize = + header->get_segment_entry_size() * header->get_segments_num(); + } + // Special case: + // Segments which start with the NULL section and have further sections + else if ( seg->get_sections_num() > 1 + && sections[seg->get_section_index_at( 0 )]->get_type() == SHT_NULL ) { + seg_start_pos = 0; + if ( seg->get_sections_num() ) { + segment_memory = segment_filesize = current_file_pos; + } + } + // New segments with not generated sections + // have to be aligned + else if ( seg->get_sections_num() + && !section_generated[seg->get_section_index_at( 0 )] ) { + Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1; + Elf64_Off cur_page_alignment = current_file_pos % align; + Elf64_Off req_page_alignment = seg->get_virtual_address() % align; + Elf64_Off error = req_page_alignment - cur_page_alignment; + + current_file_pos += ( seg->get_align() + error ) % align; + seg_start_pos = current_file_pos; + } + else if ( seg->get_sections_num() ) { + seg_start_pos = sections[seg->get_section_index_at( 0 )]->get_offset(); + } + + // Write segment's data + for ( unsigned int j = 0; j < seg->get_sections_num(); ++j ) { + Elf_Half index = seg->get_section_index_at( j ); + + section* sec = sections[ index ]; + + // The NULL section is always generated + if ( SHT_NULL == sec->get_type()) { + section_generated[index] = true; + continue; + } + + Elf_Xword secAlign = 0; + // Fix up the alignment + if ( !section_generated[index] && sec->is_address_initialized() + && SHT_NOBITS != sec->get_type() + && SHT_NULL != sec->get_type() + && 0 != sec->get_size() ) { + // Align the sections based on the virtual addresses + // when possible (this is what matters for execution) + Elf64_Off req_offset = sec->get_address() - seg->get_virtual_address(); + Elf64_Off cur_offset = current_file_pos - seg_start_pos; + if ( req_offset < cur_offset) { + // something has gone awfully wrong, abort! + // secAlign would turn out negative, seeking backwards and overwriting previous data + return false; + } + secAlign = req_offset - cur_offset; + } + else if (!section_generated[index] && !sec->is_address_initialized() ) { + // If no address has been specified then only the section + // alignment constraint has to be matched + Elf_Xword align = sec->get_addr_align(); + if (align == 0) { + align = 1; + } + Elf64_Off error = current_file_pos % align; + secAlign = ( align - error ) % align; + } + else if (section_generated[index] ) { + // Alignment for already generated sections + secAlign = sec->get_offset() - seg_start_pos - segment_filesize; + } + + // Determine the segment file and memory sizes + // Special case .tbss section (NOBITS) in non TLS segment + if ( (sec->get_flags() & SHF_ALLOC) + && !( (sec->get_flags() & SHF_TLS) && (seg->get_type() != PT_TLS) + && ( SHT_NOBITS == sec->get_type())) ) + segment_memory += sec->get_size() + secAlign; + if ( SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() ) + segment_filesize += sec->get_size() + secAlign; + + // Nothing to be done when generating nested segments + if(section_generated[index]) { + continue; + } + + current_file_pos += secAlign; + + // Set the section addresses when missing + if ( !sec->is_address_initialized() ) + sec->set_address( seg->get_virtual_address() + + current_file_pos - seg_start_pos); + + if ( 0 != sec->get_index() ) + sec->set_offset(current_file_pos); + + if ( SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() ) + current_file_pos += sec->get_size(); + section_generated[index] = true; + } + + seg->set_file_size( segment_filesize ); + + // If we already have a memory size from loading an elf file (value > 0), + // it must not shrink! + // Memory size may be bigger than file size and it is the loader's job to do something + // with the surplus bytes in memory, like initializing them with a defined value. + if ( seg->get_memory_size() < segment_memory ) { + seg->set_memory_size( segment_memory ); + } + + seg->set_offset(seg_start_pos); + } + + return true; + } + +//------------------------------------------------------------------------------ + bool layout_section_table() + { + // Simply place the section table at the end for now + Elf64_Off alignmentError = current_file_pos % 4; + current_file_pos += ( 4 - alignmentError ) % 4; + header->set_sections_offset(current_file_pos); + return true; + } + + +//------------------------------------------------------------------------------ + public: + friend class Sections; + class Sections { + public: +//------------------------------------------------------------------------------ + Sections( elfio* parent_ ) : + parent( parent_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Half size() const + { + return (Elf_Half)parent->sections_.size(); + } + +//------------------------------------------------------------------------------ + section* operator[]( unsigned int index ) const + { + section* sec = 0; + + if ( index < parent->sections_.size() ) { + sec = parent->sections_[index]; + } + + return sec; + } + +//------------------------------------------------------------------------------ + section* operator[]( const std::string& name ) const + { + section* sec = 0; + + std::vector::const_iterator it; + for ( it = parent->sections_.begin(); + it != parent->sections_.end(); + ++it ) { + if ( (*it)->get_name() == name ) { + sec = *it; + break; + } + } + + return sec; + } + +//------------------------------------------------------------------------------ + section* add( const std::string& name ) + { + section* new_section = parent->create_section(); + new_section->set_name( name ); + + Elf_Half str_index = parent->get_section_name_str_index(); + section* string_table( parent->sections_[str_index] ); + string_section_accessor str_writer( string_table ); + Elf_Word pos = str_writer.add_string( name ); + new_section->set_name_string_offset( pos ); + + return new_section; + } + +//------------------------------------------------------------------------------ + std::vector::iterator begin() { + return parent->sections_.begin(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator end() { + return parent->sections_.end(); + } + +//------------------------------------------------------------------------------ + std::vector::const_iterator begin() const { + return parent->sections_.cbegin(); + } + +//------------------------------------------------------------------------------ + std::vector::const_iterator end() const { + return parent->sections_.cend(); + } + +//------------------------------------------------------------------------------ + private: + elfio* parent; + } sections; + +//------------------------------------------------------------------------------ + public: + friend class Segments; + class Segments { + public: +//------------------------------------------------------------------------------ + Segments( elfio* parent_ ) : + parent( parent_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Half size() const + { + return (Elf_Half)parent->segments_.size(); + } + +//------------------------------------------------------------------------------ + segment* operator[]( unsigned int index ) const + { + return parent->segments_[index]; + } + + +//------------------------------------------------------------------------------ + segment* add() + { + return parent->create_segment(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator begin() { + return parent->segments_.begin(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator end() { + return parent->segments_.end(); + } + +//------------------------------------------------------------------------------ + std::vector::const_iterator begin() const { + return parent->segments_.cbegin(); + } + +//------------------------------------------------------------------------------ + std::vector::const_iterator end() const { + return parent->segments_.cend(); + } + +//------------------------------------------------------------------------------ + private: + elfio* parent; + } segments; + +//------------------------------------------------------------------------------ + private: + elf_header* header; + std::vector sections_; + std::vector segments_; + endianess_convertor convertor; + + Elf_Xword current_file_pos; +}; + +} // namespace ELFIO + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +#endif // ELFIO_HPP diff --git a/src/elfio/elfio_dump.hpp b/src/elfio/elfio_dump.hpp new file mode 100644 index 0000000..4ace665 --- /dev/null +++ b/src/elfio/elfio_dump.hpp @@ -0,0 +1,976 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DUMP_HPP +#define ELFIO_DUMP_HPP + +#include +#include +#include +#include +#include +#include + +namespace ELFIO { + + +static struct class_table_t { + const char key; + const char* str; +} class_table [] = +{ + { ELFCLASS32, "ELF32" }, + { ELFCLASS64, "ELF64" }, +}; + + +static struct endian_table_t { + const char key; + const char* str; +} endian_table [] = +{ + { ELFDATANONE, "None" }, + { ELFDATA2LSB, "Little endian" }, + { ELFDATA2MSB, "Big endian" }, +}; + + +static struct version_table_t { + const Elf64_Word key; + const char* str; +} version_table [] = +{ + { EV_NONE , "None" }, + { EV_CURRENT, "Current" }, +}; + + +static struct type_table_t { + const Elf32_Half key; + const char* str; +} type_table [] = +{ + { ET_NONE, "No file type" }, + { ET_REL , "Relocatable file" }, + { ET_EXEC, "Executable file" }, + { ET_DYN , "Shared object file" }, + { ET_CORE, "Core file" }, +}; + + +static struct machine_table_t { + const Elf64_Half key; + const char* str; +} machine_table [] = +{ + { EM_NONE , "No machine" }, + { EM_M32 , "AT&T WE 32100" }, + { EM_SPARC , "SUN SPARC" }, + { EM_386 , "Intel 80386" }, + { EM_68K , "Motorola m68k family" }, + { EM_88K , "Motorola m88k family" }, + { EM_486 , "Intel 80486// Reserved for future use" }, + { EM_860 , "Intel 80860" }, + { EM_MIPS , "MIPS R3000 (officially, big-endian only)" }, + { EM_S370 , "IBM System/370" }, + { EM_MIPS_RS3_LE , "MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated" }, + { EM_res011 , "Reserved" }, + { EM_res012 , "Reserved" }, + { EM_res013 , "Reserved" }, + { EM_res014 , "Reserved" }, + { EM_PARISC , "HPPA" }, + { EM_res016 , "Reserved" }, + { EM_VPP550 , "Fujitsu VPP500" }, + { EM_SPARC32PLUS , "Sun's v8plus" }, + { EM_960 , "Intel 80960" }, + { EM_PPC , "PowerPC" }, + { EM_PPC64 , "64-bit PowerPC" }, + { EM_S390 , "IBM S/390" }, + { EM_SPU , "Sony/Toshiba/IBM SPU" }, + { EM_res024 , "Reserved" }, + { EM_res025 , "Reserved" }, + { EM_res026 , "Reserved" }, + { EM_res027 , "Reserved" }, + { EM_res028 , "Reserved" }, + { EM_res029 , "Reserved" }, + { EM_res030 , "Reserved" }, + { EM_res031 , "Reserved" }, + { EM_res032 , "Reserved" }, + { EM_res033 , "Reserved" }, + { EM_res034 , "Reserved" }, + { EM_res035 , "Reserved" }, + { EM_V800 , "NEC V800 series" }, + { EM_FR20 , "Fujitsu FR20" }, + { EM_RH32 , "TRW RH32" }, + { EM_MCORE , "Motorola M*Core // May also be taken by Fujitsu MMA" }, + { EM_RCE , "Old name for MCore" }, + { EM_ARM , "ARM" }, + { EM_OLD_ALPHA , "Digital Alpha" }, + { EM_SH , "Renesas (formerly Hitachi) / SuperH SH" }, + { EM_SPARCV9 , "SPARC v9 64-bit" }, + { EM_TRICORE , "Siemens Tricore embedded processor" }, + { EM_ARC , "ARC Cores" }, + { EM_H8_300 , "Renesas (formerly Hitachi) H8/300" }, + { EM_H8_300H , "Renesas (formerly Hitachi) H8/300H" }, + { EM_H8S , "Renesas (formerly Hitachi) H8S" }, + { EM_H8_500 , "Renesas (formerly Hitachi) H8/500" }, + { EM_IA_64 , "Intel IA-64 Processor" }, + { EM_MIPS_X , "Stanford MIPS-X" }, + { EM_COLDFIRE , "Motorola Coldfire" }, + { EM_68HC12 , "Motorola M68HC12" }, + { EM_MMA , "Fujitsu Multimedia Accelerator" }, + { EM_PCP , "Siemens PCP" }, + { EM_NCPU , "Sony nCPU embedded RISC processor" }, + { EM_NDR1 , "Denso NDR1 microprocesspr" }, + { EM_STARCORE , "Motorola Star*Core processor" }, + { EM_ME16 , "Toyota ME16 processor" }, + { EM_ST100 , "STMicroelectronics ST100 processor" }, + { EM_TINYJ , "Advanced Logic Corp. TinyJ embedded processor" }, + { EM_X86_64 , "Advanced Micro Devices X86-64 processor" }, + { EM_PDSP , "Sony DSP Processor" }, + { EM_PDP10 , "Digital Equipment Corp. PDP-10" }, + { EM_PDP11 , "Digital Equipment Corp. PDP-11" }, + { EM_FX66 , "Siemens FX66 microcontroller" }, + { EM_ST9PLUS , "STMicroelectronics ST9+ 8/16 bit microcontroller" }, + { EM_ST7 , "STMicroelectronics ST7 8-bit microcontroller" }, + { EM_68HC16 , "Motorola MC68HC16 Microcontroller" }, + { EM_68HC11 , "Motorola MC68HC11 Microcontroller" }, + { EM_68HC08 , "Motorola MC68HC08 Microcontroller" }, + { EM_68HC05 , "Motorola MC68HC05 Microcontroller" }, + { EM_SVX , "Silicon Graphics SVx" }, + { EM_ST19 , "STMicroelectronics ST19 8-bit cpu" }, + { EM_VAX , "Digital VAX" }, + { EM_CRIS , "Axis Communications 32-bit embedded processor" }, + { EM_JAVELIN , "Infineon Technologies 32-bit embedded cpu" }, + { EM_FIREPATH , "Element 14 64-bit DSP processor" }, + { EM_ZSP , "LSI Logic's 16-bit DSP processor" }, + { EM_MMIX , "Donald Knuth's educational 64-bit processor" }, + { EM_HUANY , "Harvard's machine-independent format" }, + { EM_PRISM , "SiTera Prism" }, + { EM_AVR , "Atmel AVR 8-bit microcontroller" }, + { EM_FR30 , "Fujitsu FR30" }, + { EM_D10V , "Mitsubishi D10V" }, + { EM_D30V , "Mitsubishi D30V" }, + { EM_V850 , "NEC v850" }, + { EM_M32R , "Renesas M32R (formerly Mitsubishi M32R)" }, + { EM_MN10300 , "Matsushita MN10300" }, + { EM_MN10200 , "Matsushita MN10200" }, + { EM_PJ , "picoJava" }, + { EM_OPENRISC , "OpenRISC 32-bit embedded processor" }, + { EM_ARC_A5 , "ARC Cores Tangent-A5" }, + { EM_XTENSA , "Tensilica Xtensa Architecture" }, + { EM_VIDEOCORE , "Alphamosaic VideoCore processor" }, + { EM_TMM_GPP , "Thompson Multimedia General Purpose Processor" }, + { EM_NS32K , "National Semiconductor 32000 series" }, + { EM_TPC , "Tenor Network TPC processor" }, + { EM_SNP1K , "Trebia SNP 1000 processor" }, + { EM_ST200 , "STMicroelectronics ST200 microcontroller" }, + { EM_IP2K , "Ubicom IP2022 micro controller" }, + { EM_MAX , "MAX Processor" }, + { EM_CR , "National Semiconductor CompactRISC" }, + { EM_F2MC16 , "Fujitsu F2MC16" }, + { EM_MSP430 , "TI msp430 micro controller" }, + { EM_BLACKFIN , "ADI Blackfin" }, + { EM_SE_C33 , "S1C33 Family of Seiko Epson processors" }, + { EM_SEP , "Sharp embedded microprocessor" }, + { EM_ARCA , "Arca RISC Microprocessor" }, + { EM_UNICORE , "Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University" }, + { EM_EXCESS , "eXcess: 16/32/64-bit configurable embedded CPU" }, + { EM_DXP , "Icera Semiconductor Inc. Deep Execution Processor" }, + { EM_ALTERA_NIOS2 , "Altera Nios II soft-core processor" }, + { EM_CRX , "National Semiconductor CRX" }, + { EM_XGATE , "Motorola XGATE embedded processor" }, + { EM_C166 , "Infineon C16x/XC16x processor" }, + { EM_M16C , "Renesas M16C series microprocessors" }, + { EM_DSPIC30F , "Microchip Technology dsPIC30F Digital Signal Controller" }, + { EM_CE , "Freescale Communication Engine RISC core" }, + { EM_M32C , "Renesas M32C series microprocessors" }, + { EM_res121 , "Reserved" }, + { EM_res122 , "Reserved" }, + { EM_res123 , "Reserved" }, + { EM_res124 , "Reserved" }, + { EM_res125 , "Reserved" }, + { EM_res126 , "Reserved" }, + { EM_res127 , "Reserved" }, + { EM_res128 , "Reserved" }, + { EM_res129 , "Reserved" }, + { EM_res130 , "Reserved" }, + { EM_TSK3000 , "Altium TSK3000 core" }, + { EM_RS08 , "Freescale RS08 embedded processor" }, + { EM_res133 , "Reserved" }, + { EM_ECOG2 , "Cyan Technology eCOG2 microprocessor" }, + { EM_SCORE , "Sunplus Score" }, + { EM_SCORE7 , "Sunplus S+core7 RISC processor" }, + { EM_DSP24 , "New Japan Radio (NJR) 24-bit DSP Processor" }, + { EM_VIDEOCORE3 , "Broadcom VideoCore III processor" }, + { EM_LATTICEMICO32, "RISC processor for Lattice FPGA architecture" }, + { EM_SE_C17 , "Seiko Epson C17 family" }, + { EM_TI_C6000 , "Texas Instruments TMS320C6000 DSP family" }, + { EM_TI_C2000 , "Texas Instruments TMS320C2000 DSP family" }, + { EM_TI_C5500 , "Texas Instruments TMS320C55x DSP family" }, + { EM_res143 , "Reserved" }, + { EM_res144 , "Reserved" }, + { EM_res145 , "Reserved" }, + { EM_res146 , "Reserved" }, + { EM_res147 , "Reserved" }, + { EM_res148 , "Reserved" }, + { EM_res149 , "Reserved" }, + { EM_res150 , "Reserved" }, + { EM_res151 , "Reserved" }, + { EM_res152 , "Reserved" }, + { EM_res153 , "Reserved" }, + { EM_res154 , "Reserved" }, + { EM_res155 , "Reserved" }, + { EM_res156 , "Reserved" }, + { EM_res157 , "Reserved" }, + { EM_res158 , "Reserved" }, + { EM_res159 , "Reserved" }, + { EM_MMDSP_PLUS , "STMicroelectronics 64bit VLIW Data Signal Processor" }, + { EM_CYPRESS_M8C , "Cypress M8C microprocessor" }, + { EM_R32C , "Renesas R32C series microprocessors" }, + { EM_TRIMEDIA , "NXP Semiconductors TriMedia architecture family" }, + { EM_QDSP6 , "QUALCOMM DSP6 Processor" }, + { EM_8051 , "Intel 8051 and variants" }, + { EM_STXP7X , "STMicroelectronics STxP7x family" }, + { EM_NDS32 , "Andes Technology compact code size embedded RISC processor family" }, + { EM_ECOG1 , "Cyan Technology eCOG1X family" }, + { EM_ECOG1X , "Cyan Technology eCOG1X family" }, + { EM_MAXQ30 , "Dallas Semiconductor MAXQ30 Core Micro-controllers" }, + { EM_XIMO16 , "New Japan Radio (NJR) 16-bit DSP Processor" }, + { EM_MANIK , "M2000 Reconfigurable RISC Microprocessor" }, + { EM_CRAYNV2 , "Cray Inc. NV2 vector architecture" }, + { EM_RX , "Renesas RX family" }, + { EM_METAG , "Imagination Technologies META processor architecture" }, + { EM_MCST_ELBRUS , "MCST Elbrus general purpose hardware architecture" }, + { EM_ECOG16 , "Cyan Technology eCOG16 family" }, + { EM_CR16 , "National Semiconductor CompactRISC 16-bit processor" }, + { EM_ETPU , "Freescale Extended Time Processing Unit" }, + { EM_SLE9X , "Infineon Technologies SLE9X core" }, + { EM_L1OM , "Intel L1OM" }, + { EM_INTEL181 , "Reserved by Intel" }, + { EM_INTEL182 , "Reserved by Intel" }, + { EM_res183 , "Reserved by ARM" }, + { EM_res184 , "Reserved by ARM" }, + { EM_AVR32 , "Atmel Corporation 32-bit microprocessor family" }, + { EM_STM8 , "STMicroeletronics STM8 8-bit microcontroller" }, + { EM_TILE64 , "Tilera TILE64 multicore architecture family" }, + { EM_TILEPRO , "Tilera TILEPro multicore architecture family" }, + { EM_MICROBLAZE , "Xilinx MicroBlaze 32-bit RISC soft processor core" }, + { EM_CUDA , "NVIDIA CUDA architecture " }, +}; + + +static struct section_type_table_t { + const Elf64_Half key; + const char* str; +} section_type_table [] = +{ + { SHT_NULL , "NULL" }, + { SHT_PROGBITS , "PROGBITS" }, + { SHT_SYMTAB , "SYMTAB" }, + { SHT_STRTAB , "STRTAB" }, + { SHT_RELA , "RELA" }, + { SHT_HASH , "HASH" }, + { SHT_DYNAMIC , "DYNAMIC" }, + { SHT_NOTE , "NOTE" }, + { SHT_NOBITS , "NOBITS" }, + { SHT_REL , "REL" }, + { SHT_SHLIB , "SHLIB" }, + { SHT_DYNSYM , "DYNSYM" }, + { SHT_INIT_ARRAY , "INIT_ARRAY" }, + { SHT_FINI_ARRAY , "FINI_ARRAY" }, + { SHT_PREINIT_ARRAY, "PREINIT_ARRAY" }, + { SHT_GROUP , "GROUP" }, + { SHT_SYMTAB_SHNDX , "SYMTAB_SHNDX " }, +}; + + +static struct segment_type_table_t { + const Elf_Word key; + const char* str; +} segment_type_table [] = +{ + { PT_NULL , "NULL" }, + { PT_LOAD , "LOAD" }, + { PT_DYNAMIC, "DYNAMIC" }, + { PT_INTERP , "INTERP" }, + { PT_NOTE , "NOTE" }, + { PT_SHLIB , "SHLIB" }, + { PT_PHDR , "PHDR" }, + { PT_TLS , "TLS" }, +}; + + +static struct segment_flag_table_t { + const Elf_Word key; + const char* str; +} segment_flag_table [] = +{ + { 0, "" }, + { 1, "X" }, + { 2, "W" }, + { 3, "WX" }, + { 4, "R" }, + { 5, "RX" }, + { 6, "RW" }, + { 7, "RWX" }, +}; + + +static struct symbol_bind_t { + const Elf_Word key; + const char* str; +} symbol_bind_table [] = +{ + { STB_LOCAL , "LOCAL" }, + { STB_GLOBAL , "GLOBAL" }, + { STB_WEAK , "WEAK" }, + { STB_LOOS , "LOOS" }, + { STB_HIOS , "HIOS" }, + { STB_MULTIDEF, "MULTIDEF" }, + { STB_LOPROC , "LOPROC" }, + { STB_HIPROC , "HIPROC" }, +}; + + +static struct symbol_type_t { + const Elf_Word key; + const char* str; +} symbol_type_table [] = +{ + { STT_NOTYPE , "NOTYPE" }, + { STT_OBJECT , "OBJECT" }, + { STT_FUNC , "FUNC" }, + { STT_SECTION, "SECTION" }, + { STT_FILE , "FILE" }, + { STT_COMMON , "COMMON" }, + { STT_TLS , "TLS" }, + { STT_LOOS , "LOOS" }, + { STT_HIOS , "HIOS" }, + { STT_LOPROC , "LOPROC" }, + { STT_HIPROC , "HIPROC" }, +}; + + +static struct dynamic_tag_t { + const Elf_Word key; + const char* str; +} dynamic_tag_table [] = +{ + { DT_NULL , "NULL" }, + { DT_NEEDED , "NEEDED" }, + { DT_PLTRELSZ , "PLTRELSZ" }, + { DT_PLTGOT , "PLTGOT" }, + { DT_HASH , "HASH" }, + { DT_STRTAB , "STRTAB" }, + { DT_SYMTAB , "SYMTAB" }, + { DT_RELA , "RELA" }, + { DT_RELASZ , "RELASZ" }, + { DT_RELAENT , "RELAENT" }, + { DT_STRSZ , "STRSZ" }, + { DT_SYMENT , "SYMENT" }, + { DT_INIT , "INIT" }, + { DT_FINI , "FINI" }, + { DT_SONAME , "SONAME" }, + { DT_RPATH , "RPATH" }, + { DT_SYMBOLIC , "SYMBOLIC" }, + { DT_REL , "REL" }, + { DT_RELSZ , "RELSZ" }, + { DT_RELENT , "RELENT" }, + { DT_PLTREL , "PLTREL" }, + { DT_DEBUG , "DEBUG" }, + { DT_TEXTREL , "TEXTREL" }, + { DT_JMPREL , "JMPREL" }, + { DT_BIND_NOW , "BIND_NOW" }, + { DT_INIT_ARRAY , "INIT_ARRAY" }, + { DT_FINI_ARRAY , "FINI_ARRAY" }, + { DT_INIT_ARRAYSZ , "INIT_ARRAYSZ" }, + { DT_FINI_ARRAYSZ , "FINI_ARRAYSZ" }, + { DT_RUNPATH , "RUNPATH" }, + { DT_FLAGS , "FLAGS" }, + { DT_ENCODING , "ENCODING" }, + { DT_PREINIT_ARRAY , "PREINIT_ARRAY" }, + { DT_PREINIT_ARRAYSZ, "PREINIT_ARRAYSZ" }, + { DT_MAXPOSTAGS , "MAXPOSTAGS" }, +}; + +static const ELFIO::Elf_Xword MAX_DATA_ENTRIES = 64; + +//------------------------------------------------------------------------------ +class dump +{ +#define DUMP_DEC_FORMAT( width ) std::setw(width) << std::setfill( ' ' ) << \ + std::dec << std::right +#define DUMP_HEX_FORMAT( width ) std::setw(width) << std::setfill( '0' ) << \ + std::hex << std::right +#define DUMP_STR_FORMAT( width ) std::setw(width) << std::setfill( ' ' ) << \ + std::hex << std::left + + public: +//------------------------------------------------------------------------------ + static void + header( std::ostream& out, const elfio& reader ) + { + if (!reader.get_header_size()) + { + return; + } + out << "ELF Header" << std::endl << std::endl + << " Class: " << str_class( reader.get_class() ) << std::endl + << " Encoding: " << str_endian( reader.get_encoding() ) << std::endl + << " ELFVersion: " << str_version( reader.get_elf_version() ) << std::endl + << " Type: " << str_type( reader.get_type() ) << std::endl + << " Machine: " << str_machine( reader.get_machine() ) << std::endl + << " Version: " << str_version( reader.get_version() ) << std::endl + << " Entry: " << "0x" << std::hex << reader.get_entry() << std::endl + << " Flags: " << "0x" << std::hex << reader.get_flags() << std::endl + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type Addr Size ES Flg Lk Inf Al Name" << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type Addr Size ES Flg" << std::endl + << " Lk Inf Al Name" << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + section_header( out, i, sec, reader.get_class() ); + } + + out << "Key to Flags: W (write), A (alloc), X (execute)\n\n" + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_header( std::ostream& out, Elf_Half no, const section* sec, + unsigned char elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " + << DUMP_HEX_FORMAT( 8 ) << sec->get_address() << " " + << DUMP_HEX_FORMAT( 8 ) << sec->get_size() << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_link() << " " + << DUMP_HEX_FORMAT( 3 ) << sec->get_info() << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " + << DUMP_HEX_FORMAT( 16 ) << sec->get_address() << " " + << DUMP_HEX_FORMAT( 16 ) << sec->get_size() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " + << std::endl + << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_link() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_info() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " + << std::endl; + } + + out.flags(original_flags); + + return; + } + +//------------------------------------------------------------------------------ + static void + segment_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + if ( n == 0 ) { + return; + } + + out << "Segment headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type VirtAddr PhysAddr FileSize Mem.Size Flags Align" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type VirtAddr PhysAddr Flags" << std::endl + << " FileSize Mem.Size Align" + << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { + segment* seg = reader.segments[i]; + segment_header( out, i, seg, reader.get_class() ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + segment_header( std::ostream& out, Elf_Half no, const segment* seg, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_virtual_address() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_physical_address() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_file_size() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() ) << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_align() << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_virtual_address() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_physical_address() << " " + << DUMP_STR_FORMAT( 16 ) << str_segment_flag( seg->get_flags() ) << " " + << std::endl + << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_file_size() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_memory_size() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_align() << " " + << std::endl; + } + + out.flags(original_flags); + } + +//------------------------------------------------------------------------------ + static void + symbol_tables( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type() ) { + symbol_section_accessor symbols( reader, sec ); + + Elf_Xword sym_no = symbols.get_symbols_num(); + if ( sym_no > 0 ) { + out << "Symbol table (" << sec->get_name() << ")" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Value Size Type Bind Sect Name" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Value Size Type Bind Sect" << std::endl + << " Name" + << std::endl; + } + for ( Elf_Half i = 0; i < sym_no; ++i ) { + std::string name; + Elf64_Addr value = 0; + Elf_Xword size = 0; + unsigned char bind = 0; + unsigned char type = 0; + Elf_Half section = 0; + unsigned char other = 0; + symbols.get_symbol( i, name, value, size, bind, type, section, other ); + symbol_table( out, i, name, value, size, bind, type, section, reader.get_class() ); + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + symbol_table( std::ostream& out, + Elf_Half no, + std::string& name, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + Elf_Half section, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_HEX_FORMAT( 8 ) << value << " " + << DUMP_HEX_FORMAT( 8 ) << size << " " + << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " + << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " + << DUMP_DEC_FORMAT( 5 ) << section << " " + << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_HEX_FORMAT( 16 ) << value << " " + << DUMP_HEX_FORMAT( 16 ) << size << " " + << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " + << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " + << DUMP_DEC_FORMAT( 5 ) << section << " " + << std::endl + << " " + << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + + out.flags(original_flags); + } + +//------------------------------------------------------------------------------ + static void + notes( std::ostream& out, const elfio& reader ) + { + Elf_Half no = reader.sections.size(); + for ( Elf_Half i = 0; i < no; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_NOTE == sec->get_type() ) { // Look at notes + note_section_accessor notes( reader, sec ); + int no_notes = notes.get_notes_num(); + if ( no > 0 ) { + out << "Note section (" << sec->get_name() << ")" << std::endl + << " No Type Name" + << std::endl; + for ( int j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + void* desc; + Elf_Word descsz; + + if ( notes.get_note(j, type, name, desc, descsz) ) { + // 'name' usually contains \0 at the end. Try to fix it + name = name.c_str(); + note( out, j, type, name ); + } + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + note( std::ostream& out, + int no, + Elf_Word type, + const std::string& name ) + { + out << " [" + << DUMP_DEC_FORMAT( 2 ) << no + << "] " + << DUMP_HEX_FORMAT( 8 ) << type << " " + << DUMP_STR_FORMAT( 1 ) << name + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + dynamic_tags( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_DYNAMIC == sec->get_type() ) { + dynamic_section_accessor dynamic( reader, sec ); + + Elf_Xword dyn_no = dynamic.get_entries_num(); + if ( dyn_no > 0 ) { + out << "Dynamic section (" << sec->get_name() << ")" << std::endl; + out << "[ Nr ] Tag Name/Value" << std::endl; + for ( Elf_Xword i = 0; i < dyn_no; ++i ) { + Elf_Xword tag = 0; + Elf_Xword value = 0; + std::string str; + dynamic.get_entry( i, tag, value, str ); + dynamic_tag( out, i, tag, value, str, reader.get_class() ); + if ( DT_NULL == tag ) { + break; + } + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + dynamic_tag( std::ostream& out, + Elf_Xword no, + Elf_Xword tag, + Elf_Xword value, + std::string str, + unsigned int /*elf_class*/ ) + { + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 16 ) << str_dynamic_tag( tag ) << " "; + if ( str.empty() ) { + out << DUMP_HEX_FORMAT( 16 ) << value << " "; + } + else { + out << DUMP_STR_FORMAT( 32 ) << str << " "; + } + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_data( std::ostream& out, const section* sec ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << sec->get_name() << std::endl; + const char* pdata = sec->get_data(); + if ( pdata ){ + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( sec->get_size(), MAX_DATA_ENTRIES ); ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags(original_flags); + } + + return; + } + +//------------------------------------------------------------------------------ + static void + section_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Data:" << std::endl; + + for ( Elf_Half i = 1; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( sec->get_type() == SHT_NOBITS ) { + continue; + } + section_data( out, sec ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + segment_data( std::ostream& out, Elf_Half no, const segment* seg ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << "Segment # " << no << std::endl; + const char* pdata = seg->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( seg->get_file_size(), MAX_DATA_ENTRIES ); ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags(original_flags); + } + + return; + } + +//------------------------------------------------------------------------------ + static void + segment_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + + if ( n == 0 ) { + return; + } + + out << "Segment Data:" << std::endl; + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + segment* seg = reader.segments[i]; + segment_data( out, i, seg ); + } + + out << std::endl; + } + + private: +//------------------------------------------------------------------------------ + template< typename T, typename K > + std::string + static + find_value_in_table( const T& table, const K& key ) + { + std::string res = "?"; + for ( unsigned int i = 0; i < sizeof( table )/sizeof( table[0] ); ++i ) { + if ( table[i].key == key ) { + res = table[i].str; + break; + } + } + + return res; + } + + +//------------------------------------------------------------------------------ + template< typename T, typename K > + static + std::string + format_assoc( const T& table, const K& key ) + { + std::string str = find_value_in_table( table, key ); + if ( str == "?" ) { + std::ostringstream oss; + oss << str << " (0x" << std::hex << key << ")"; + str = oss.str(); + } + + return str; + } + + +//------------------------------------------------------------------------------ + template< typename T > + static + std::string + format_assoc( const T& table, const char key ) + { + return format_assoc( table, (const int)key ); + } + + +//------------------------------------------------------------------------------ + static + std::string + section_flags( Elf_Xword flags ) + { + std::string ret = ""; + if ( flags & SHF_WRITE ) { + ret += "W"; + } + if ( flags & SHF_ALLOC ) { + ret += "A"; + } + if ( flags & SHF_EXECINSTR ) { + ret += "X"; + } + + return ret; + } + + +//------------------------------------------------------------------------------ +#define STR_FUNC_TABLE( name ) \ + template< typename T > \ + static \ + std::string \ + str_##name( const T key ) \ + { \ + return format_assoc( name##_table, key ); \ + } + + STR_FUNC_TABLE( class ) + STR_FUNC_TABLE( endian ) + STR_FUNC_TABLE( version ) + STR_FUNC_TABLE( type ) + STR_FUNC_TABLE( machine ) + STR_FUNC_TABLE( section_type ) + STR_FUNC_TABLE( segment_type ) + STR_FUNC_TABLE( segment_flag ) + STR_FUNC_TABLE( symbol_bind ) + STR_FUNC_TABLE( symbol_type ) + STR_FUNC_TABLE( dynamic_tag ) + +#undef STR_FUNC_TABLE +#undef DUMP_DEC_FORMAT +#undef DUMP_HEX_FORMAT +#undef DUMP_STR_FORMAT +}; // class dump + + +}; // namespace ELFIO + +#endif // ELFIO_DUMP_HPP diff --git a/src/elfio/elfio_dynamic.hpp b/src/elfio/elfio_dynamic.hpp new file mode 100644 index 0000000..42f2680 --- /dev/null +++ b/src/elfio/elfio_dynamic.hpp @@ -0,0 +1,257 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DYNAMIC_HPP +#define ELFIO_DYNAMIC_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template< class S > +class dynamic_section_accessor_template +{ + public: +//------------------------------------------------------------------------------ + dynamic_section_accessor_template( const elfio& elf_file_, S* section_ ) : + elf_file( elf_file_ ), + dynamic_section( section_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_entries_num() const + { + Elf_Xword nRet = 0; + + if ( 0 != dynamic_section->get_entry_size() ) { + nRet = dynamic_section->get_size() / dynamic_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value, + std::string& str ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_get_entry_dyn< Elf32_Dyn >( index, tag, value ); + } + else { + generic_get_entry_dyn< Elf64_Dyn >( index, tag, value ); + } + + // If the tag may have a string table reference, prepare the string + if ( tag == DT_NEEDED || + tag == DT_SONAME || + tag == DT_RPATH || + tag == DT_RUNPATH ) { + string_section_accessor strsec = + elf_file.sections[ get_string_table_index() ]; + const char* result = strsec.get_string( value ); + if ( 0 == result ) { + str.clear(); + return false; + } + str = result; + } + else { + str.clear(); + } + + return true; + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf_Xword tag, + Elf_Xword value ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Dyn >( tag, value ); + } + else { + generic_add_entry< Elf64_Dyn >( tag, value ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf_Xword tag, + const std::string& str ) + { + string_section_accessor strsec = + elf_file.sections[ get_string_table_index() ]; + Elf_Xword value = strsec.add_string( str ); + add_entry( tag, value ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + Elf_Half + get_string_table_index() const + { + return (Elf_Half)dynamic_section->get_link(); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_dyn( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + // Check unusual case when dynamic section has no data + if( dynamic_section->get_data() == 0 || + ( index + 1 ) * dynamic_section->get_entry_size() > dynamic_section->get_size() ) { + tag = DT_NULL; + value = 0; + return; + } + + const T* pEntry = reinterpret_cast( + dynamic_section->get_data() + + index * dynamic_section->get_entry_size() ); + tag = convertor( pEntry->d_tag ); + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + value = 0; + break; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + value = convertor( pEntry->d_un.d_val ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + value = convertor( pEntry->d_un.d_ptr ); + break; + } + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf_Xword tag, Elf_Xword value ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + value = 0; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + entry.d_un.d_val = convertor( value ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + entry.d_un.d_ptr = convertor( value ); + break; + } + + entry.d_tag = convertor( tag ); + + dynamic_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* dynamic_section; +}; + +using dynamic_section_accessor = dynamic_section_accessor_template
; +using const_dynamic_section_accessor = dynamic_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_DYNAMIC_HPP diff --git a/src/elfio/elfio_header.hpp b/src/elfio/elfio_header.hpp new file mode 100644 index 0000000..6f8da02 --- /dev/null +++ b/src/elfio/elfio_header.hpp @@ -0,0 +1,145 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELF_HEADER_HPP +#define ELF_HEADER_HPP + +#include + +namespace ELFIO { + +class elf_header +{ + public: + virtual ~elf_header() {}; + virtual bool load( std::istream& stream ) = 0; + virtual bool save( std::ostream& stream ) const = 0; + + // ELF header functions + ELFIO_GET_ACCESS_DECL( unsigned char, class ); + ELFIO_GET_ACCESS_DECL( unsigned char, elf_version ); + ELFIO_GET_ACCESS_DECL( unsigned char, encoding ); + ELFIO_GET_ACCESS_DECL( Elf_Half, header_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size ); + + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index ); +}; + + +template< class T > struct elf_header_impl_types; +template<> struct elf_header_impl_types { + typedef Elf32_Phdr Phdr_type; + typedef Elf32_Shdr Shdr_type; + static const unsigned char file_class = ELFCLASS32; +}; +template<> struct elf_header_impl_types { + typedef Elf64_Phdr Phdr_type; + typedef Elf64_Shdr Shdr_type; + static const unsigned char file_class = ELFCLASS64; +}; + +template< class T > class elf_header_impl : public elf_header +{ + public: + elf_header_impl( endianess_convertor* convertor_, + unsigned char encoding ) + { + convertor = convertor_; + + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + + header.e_ident[EI_MAG0] = ELFMAG0; + header.e_ident[EI_MAG1] = ELFMAG1; + header.e_ident[EI_MAG2] = ELFMAG2; + header.e_ident[EI_MAG3] = ELFMAG3; + header.e_ident[EI_CLASS] = elf_header_impl_types::file_class; + header.e_ident[EI_DATA] = encoding; + header.e_ident[EI_VERSION] = EV_CURRENT; + header.e_version = (*convertor)( (Elf_Word)EV_CURRENT ); + header.e_ehsize = ( sizeof( header ) ); + header.e_ehsize = (*convertor)( header.e_ehsize ); + header.e_shstrndx = (*convertor)( (Elf_Half)1 ); + header.e_phentsize = sizeof( typename elf_header_impl_types::Phdr_type ); + header.e_shentsize = sizeof( typename elf_header_impl_types::Shdr_type ); + header.e_phentsize = (*convertor)( header.e_phentsize ); + header.e_shentsize = (*convertor)( header.e_shentsize ); + } + + bool + load( std::istream& stream ) + { + stream.seekg( 0 ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + return (stream.gcount() == sizeof( header ) ); + } + + bool + save( std::ostream& stream ) const + { + stream.seekp( 0 ); + stream.write( reinterpret_cast( &header ), sizeof( header ) ); + + return stream.good(); + } + + // ELF header functions + ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); + ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] ); + ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] ); + ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize ); + ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize ); + ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize ); + + ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version); + ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] ); + ELFIO_GET_SET_ACCESS( unsigned char, abi_version, header.e_ident[EI_ABIVERSION] ); + ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type ); + ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags ); + ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry ); + ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff ); + ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); + + private: + T header; + endianess_convertor* convertor; +}; + +} // namespace ELFIO + +#endif // ELF_HEADER_HPP diff --git a/src/elfio/elfio_note.hpp b/src/elfio/elfio_note.hpp new file mode 100644 index 0000000..8619c73 --- /dev/null +++ b/src/elfio/elfio_note.hpp @@ -0,0 +1,170 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_NOTE_HPP +#define ELFIO_NOTE_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// There are discrepancies in documentations. SCO documentation +// (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section) +// requires 8 byte entries alignment for 64-bit ELF file, +// but Oracle's definition uses the same structure +// for 32-bit and 64-bit formats. +// (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html) +// +// It looks like EM_X86_64 Linux implementation is similar to Oracle's +// definition. Therefore, the same alignment works for both formats +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +template< class S > +class note_section_accessor_template +{ + public: +//------------------------------------------------------------------------------ + note_section_accessor_template( const elfio& elf_file_, S* section_ ) : + elf_file( elf_file_ ), note_section( section_ ) + { + process_section(); + } + +//------------------------------------------------------------------------------ + Elf_Word + get_notes_num() const + { + return (Elf_Word)note_start_positions.size(); + } + +//------------------------------------------------------------------------------ + bool + get_note( Elf_Word index, + Elf_Word& type, + std::string& name, + void*& desc, + Elf_Word& descSize ) const + { + if ( index >= note_section->get_size() ) { + return false; + } + + const char* pData = note_section->get_data() + note_start_positions[index]; + int align = sizeof( Elf_Word ); + + const endianess_convertor& convertor = elf_file.get_convertor(); + type = convertor( *(const Elf_Word*)( pData + 2*align ) ); + Elf_Word namesz = convertor( *(const Elf_Word*)( pData ) ); + descSize = convertor( *(const Elf_Word*)( pData + sizeof( namesz ) ) ); + Elf_Xword max_name_size = note_section->get_size() - note_start_positions[index]; + if ( namesz > max_name_size || + namesz + descSize > max_name_size ) { + return false; + } + name.assign( pData + 3*align, namesz - 1); + if ( 0 == descSize ) { + desc = 0; + } + else { + desc = const_cast ( pData + 3*align + + ( ( namesz + align - 1 )/align )*align ); + } + + return true; + } + +//------------------------------------------------------------------------------ + void add_note( Elf_Word type, + const std::string& name, + const void* desc, + Elf_Word descSize ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + int align = sizeof( Elf_Word ); + Elf_Word nameLen = (Elf_Word)name.size() + 1; + Elf_Word nameLenConv = convertor( nameLen ); + std::string buffer( reinterpret_cast( &nameLenConv ), align ); + Elf_Word descSizeConv = convertor( descSize ); + buffer.append( reinterpret_cast( &descSizeConv ), align ); + type = convertor( type ); + buffer.append( reinterpret_cast( &type ), align ); + buffer.append( name ); + buffer.append( 1, '\x00' ); + const char pad[] = { '\0', '\0', '\0', '\0' }; + if ( nameLen % align != 0 ) { + buffer.append( pad, align - nameLen % align ); + } + if ( desc != 0 && descSize != 0 ) { + buffer.append( reinterpret_cast( desc ), descSize ); + if ( descSize % align != 0 ) { + buffer.append( pad, align - descSize % align ); + } + } + + note_start_positions.push_back( note_section->get_size() ); + note_section->append_data( buffer ); + } + + private: +//------------------------------------------------------------------------------ + void process_section() + { + const endianess_convertor& convertor = elf_file.get_convertor(); + const char* data = note_section->get_data(); + Elf_Xword size = note_section->get_size(); + Elf_Xword current = 0; + + note_start_positions.clear(); + + // Is it empty? + if ( 0 == data || 0 == size ) { + return; + } + + int align = sizeof( Elf_Word ); + while ( current + 3*align <= size ) { + note_start_positions.push_back( current ); + Elf_Word namesz = convertor( + *(const Elf_Word*)( data + current ) ); + Elf_Word descsz = convertor( + *(const Elf_Word*)( data + current + sizeof( namesz ) ) ); + + current += 3*sizeof( Elf_Word ) + + ( ( namesz + align - 1 ) / align ) * align + + ( ( descsz + align - 1 ) / align ) * align; + } + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* note_section; + std::vector note_start_positions; +}; + +using note_section_accessor = note_section_accessor_template
; +using const_note_section_accessor = note_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_NOTE_HPP diff --git a/src/elfio/elfio_relocation.hpp b/src/elfio/elfio_relocation.hpp new file mode 100644 index 0000000..4a3fab0 --- /dev/null +++ b/src/elfio/elfio_relocation.hpp @@ -0,0 +1,333 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_RELOCATION_HPP +#define ELFIO_RELOCATION_HPP + +namespace ELFIO { + +template struct get_sym_and_type; +template<> struct get_sym_and_type< Elf32_Rel > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template<> struct get_sym_and_type< Elf32_Rela > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template<> struct get_sym_and_type< Elf64_Rel > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF64_R_SYM( info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF64_R_TYPE( info ); + } +}; +template<> struct get_sym_and_type< Elf64_Rela > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF64_R_SYM( info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF64_R_TYPE( info ); + } +}; + + +//------------------------------------------------------------------------------ +template< class S > +class relocation_section_accessor_template +{ + public: +//------------------------------------------------------------------------------ + relocation_section_accessor_template( const elfio& elf_file_, S* section_ ) : + elf_file( elf_file_ ), + relocation_section( section_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_entries_num() const + { + Elf_Xword nRet = 0; + + if ( 0 != relocation_section->get_entry_size() ) { + nRet = relocation_section->get_size() / relocation_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + if ( SHT_REL == relocation_section->get_type() ) { + generic_get_entry_rel< Elf32_Rel >( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela< Elf32_Rela >( index, offset, symbol, + type, addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + generic_get_entry_rel< Elf64_Rel >( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela< Elf64_Rela >( index, offset, symbol, + type, addend ); + } + } + + return true; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf64_Addr& symbolValue, + std::string& symbolName, + Elf_Word& type, + Elf_Sxword& addend, + Elf_Half& section) const + { + // Do regular job + Elf_Word symbol; + bool ret = get_entry( index, offset, symbol, type, addend ); + + // Find the symbol + Elf_Xword size; + unsigned char bind; + unsigned char symbolType; + unsigned char other; + + symbol_section_accessor symbols( elf_file, elf_file.sections[get_symbol_table_index()] ); + ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, + size, bind, symbolType, section, other ); + + return ret; + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Xword info ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Rel >( offset, info ); + } + else { + generic_add_entry< Elf64_Rel >( offset, info ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO((Elf_Xword)symbol, type ); + } + + add_entry( offset, info ); + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Rela >( offset, info, addend ); + } + else { + generic_add_entry< Elf64_Rela >( offset, info, addend ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type, + Elf_Sxword addend ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + + add_entry( offset, info, addend ); + } + +//------------------------------------------------------------------------------ + void + add_entry( string_section_accessor str_writer, + const char* str, + symbol_section_accessor sym_writer, + Elf64_Addr value, + Elf_Word size, + unsigned char sym_info, + unsigned char other, + Elf_Half shndx, + Elf64_Addr offset, + unsigned char type ) + { + Elf_Word str_index = str_writer.add_string( str ); + Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size, + sym_info, other, shndx ); + add_entry( offset, sym_index, type ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + Elf_Half + get_symbol_table_index() const + { + return (Elf_Half)relocation_section->get_link(); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_rel( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = convertor( pEntry->r_offset ); + Elf_Xword tmp = convertor( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = 0; + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_rela( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = convertor( pEntry->r_offset ); + Elf_Xword tmp = convertor( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = convertor( pEntry->r_addend ); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf64_Addr offset, Elf_Xword info ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_offset = convertor( entry.r_offset ); + entry.r_info = convertor( entry.r_info ); + + relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_addend = addend; + entry.r_offset = convertor( entry.r_offset ); + entry.r_info = convertor( entry.r_info ); + entry.r_addend = convertor( entry.r_addend ); + + relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* relocation_section; +}; + +using relocation_section_accessor = relocation_section_accessor_template
; +using const_relocation_section_accessor = relocation_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_RELOCATION_HPP diff --git a/src/elfio/elfio_section.hpp b/src/elfio/elfio_section.hpp new file mode 100644 index 0000000..60e19df --- /dev/null +++ b/src/elfio/elfio_section.hpp @@ -0,0 +1,360 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SECTION_HPP +#define ELFIO_SECTION_HPP + +#include +#include +#include "utils/logger.h" +#include + +namespace ELFIO { + +class section +{ + friend class elfio; + public: + virtual ~section() {}; + + ELFIO_GET_ACCESS_DECL ( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( std::string, name ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset ); + ELFIO_GET_ACCESS_DECL ( Elf64_Off, offset ); + size_t stream_size; + size_t get_stream_size() const + { + return stream_size; + } + + void set_stream_size(size_t value) + { + stream_size = value; + } + + virtual const char* get_data() const = 0; + virtual void set_data( const char* pData, Elf_Word size ) = 0; + virtual void set_data( const std::string& data ) = 0; + virtual void append_data( const char* pData, Elf_Word size ) = 0; + virtual void append_data( const std::string& data ) = 0; + + protected: + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + virtual void load( std::istream& stream, + std::streampos header_offset ) = 0; + virtual void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) = 0; + virtual bool is_address_initialized() const = 0; +}; + + +template< class T > +class section_impl : public section +{ + public: +//------------------------------------------------------------------------------ + section_impl( const endianess_convertor* convertor_ ) : convertor( convertor_ ) + { + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + is_address_set = false; + data = 0; + data_size = 0; + } + +//------------------------------------------------------------------------------ + ~section_impl() + { + delete [] data; + } + +//------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type ); + ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size ); + ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link ); + ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info ); + ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign ); + ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize ); + ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name ); + ELFIO_GET_ACCESS ( Elf64_Addr, address, header.sh_addr ); + + +//------------------------------------------------------------------------------ + Elf_Half + get_index() const + { + return index; + } + + +//------------------------------------------------------------------------------ + std::string + get_name() const + { + return name; + } + +//------------------------------------------------------------------------------ + void + set_name( std::string name_ ) + { + name = name_; + } + +//------------------------------------------------------------------------------ + void + set_address( Elf64_Addr value ) + { + header.sh_addr = value; + header.sh_addr = (*convertor)( header.sh_addr ); + is_address_set = true; + } + +//------------------------------------------------------------------------------ + bool + is_address_initialized() const + { + return is_address_set; + } + +//------------------------------------------------------------------------------ + const char* + get_data() const + { + return data; + } + +//------------------------------------------------------------------------------ + void + set_data( const char* raw_data, Elf_Word size ) + { + if ( get_type() != SHT_NOBITS ) { + delete [] data; + try { + data = new char[size]; + } catch (const std::bad_alloc&) { + data = 0; + data_size = 0; + size = 0; + } + if ( 0 != data && 0 != raw_data ) { + data_size = size; + std::copy( raw_data, raw_data + size, data ); + } + } + + set_size( size ); + } + +//------------------------------------------------------------------------------ + void + set_data( const std::string& str_data ) + { + return set_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + +//------------------------------------------------------------------------------ + void + append_data( const char* raw_data, Elf_Word size ) + { + if ( get_type() != SHT_NOBITS ) { + if ( get_size() + size < data_size ) { + std::copy( raw_data, raw_data + size, data + get_size() ); + } + else { + data_size = 2*( data_size + size); + char* new_data; + try { + new_data = new char[data_size]; + } catch (const std::bad_alloc&) { + new_data = 0; + size = 0; + } + if ( 0 != new_data ) { + std::copy( data, data + get_size(), new_data ); + std::copy( raw_data, raw_data + size, new_data + get_size() ); + delete [] data; + data = new_data; + } + } + set_size( get_size() + size ); + } + } + +//------------------------------------------------------------------------------ + void + append_data( const std::string& str_data ) + { + return append_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + +//------------------------------------------------------------------------------ + protected: +//------------------------------------------------------------------------------ + ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset ); + +//------------------------------------------------------------------------------ + void + set_index( Elf_Half value ) + { + index = value; + } + +//------------------------------------------------------------------------------ + void + load( std::istream& stream, + std::streampos header_offset ) + { + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + + stream.seekg ( 0, stream.end ); + set_stream_size ( stream.tellg() ); + + stream.seekg( header_offset ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + + Elf_Xword size = get_size(); + if ( 0 == data && SHT_NULL != get_type() && SHT_NOBITS != get_type() && size < get_stream_size()) { + try { + data = new char[size + 1]; + } catch (const std::bad_alloc&) { + data = 0; + data_size = 0; + } + + if ( ( 0 != size ) && ( 0 != data ) ) { + stream.seekg( (*convertor)( header.sh_offset ) ); + if (get_flags() & 0x08000000){ + uint32_t uncompressed_size = size; + stream.read( (char *) &uncompressed_size, 4); + stream.read( data, size - 4); + + char* uncompressedData = new char[uncompressed_size + 1]; + + int ret = 0; + z_stream s; + memset(&s, 0, sizeof(s)); + + s.zalloc = Z_NULL; + s.zfree = Z_NULL; + s.opaque = Z_NULL; + + ret = inflateInit_(&s, ZLIB_VERSION, sizeof(s)); + if (ret != Z_OK) + return; + + s.avail_in = size - 4; + s.next_in = (Bytef *)data; + + s.avail_out = uncompressed_size; + s.next_out = (Bytef *)&uncompressedData[0]; + + ret = inflate(&s, Z_FINISH); + if (ret != Z_OK && ret != Z_STREAM_END){ + DEBUG_FUNCTION_LINE("NOOOO\n"); + } + + inflateEnd(&s); + + free(data); + data = uncompressedData; + data_size = uncompressed_size; + set_size(uncompressed_size); + data[data_size] = 0; // Ensure data is ended with 0 to avoid oob read + + }else{ + stream.read( data, size ); + data[size] = 0; // Ensure data is ended with 0 to avoid oob read + data_size = size; + } + }else{ + set_size(0); + DEBUG_FUNCTION_LINE("Failed to allocate memory.\n"); + } + } + } + +//------------------------------------------------------------------------------ + void + save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) + { + if ( 0 != get_index() ) { + header.sh_offset = data_offset; + header.sh_offset = (*convertor)( header.sh_offset ); + } + + save_header( stream, header_offset ); + if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && + get_size() != 0 && data != 0 ) { + save_data( stream, data_offset ); + } + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void + save_header( std::ostream& stream, + std::streampos header_offset ) const + { + stream.seekp( header_offset ); + stream.write( reinterpret_cast( &header ), sizeof( header ) ); + } + +//------------------------------------------------------------------------------ + void + save_data( std::ostream& stream, + std::streampos data_offset ) const + { + stream.seekp( data_offset ); + stream.write( get_data(), get_size() ); + } + +//------------------------------------------------------------------------------ + private: + T header; + Elf_Half index; + std::string name; + char* data; + Elf_Word data_size; + const endianess_convertor* convertor; + bool is_address_set; +}; + +} // namespace ELFIO + +#endif // ELFIO_SECTION_HPP diff --git a/src/elfio/elfio_segment.hpp b/src/elfio/elfio_segment.hpp new file mode 100644 index 0000000..642fd29 --- /dev/null +++ b/src/elfio/elfio_segment.hpp @@ -0,0 +1,246 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SEGMENT_HPP +#define ELFIO_SEGMENT_HPP + +#include +#include + +namespace ELFIO { + +class segment +{ + friend class elfio; + public: + virtual ~segment() {}; + + ELFIO_GET_ACCESS_DECL ( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size ); + ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); + + virtual const char* get_data() const = 0; + + virtual Elf_Half add_section_index( Elf_Half index, Elf_Xword addr_align ) = 0; + virtual Elf_Half get_sections_num() const = 0; + virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0; + virtual bool is_offset_initialized() const = 0; + + protected: + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + virtual const std::vector& get_sections() const = 0; + virtual void load( std::istream& stream, std::streampos header_offset ) = 0; + virtual void save( std::ostream& stream, std::streampos header_offset, + std::streampos data_offset ) = 0; +}; + + +//------------------------------------------------------------------------------ +template< class T > +class segment_impl : public segment +{ + public: +//------------------------------------------------------------------------------ + segment_impl( endianess_convertor* convertor_ ) : + stream_size( 0 ), index( 0 ), data( 0 ), convertor( convertor_ ) + { + is_offset_set = false; + std::fill_n( reinterpret_cast( &ph ), sizeof( ph ), '\0' ); + } + +//------------------------------------------------------------------------------ + virtual ~segment_impl() + { + delete [] data; + } + +//------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr ); + ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz ); + ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz ); + ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset ); + size_t stream_size; + +//------------------------------------------------------------------------------ + size_t + get_stream_size() const + { + return stream_size; + } + +//------------------------------------------------------------------------------ + void + set_stream_size(size_t value) + { + stream_size = value; + } + +//------------------------------------------------------------------------------ + Elf_Half + get_index() const + { + return index; + } + +//------------------------------------------------------------------------------ + const char* + get_data() const + { + return data; + } + +//------------------------------------------------------------------------------ + Elf_Half + add_section_index( Elf_Half sec_index, Elf_Xword addr_align ) + { + sections.push_back( sec_index ); + if ( addr_align > get_align() ) { + set_align( addr_align ); + } + + return (Elf_Half)sections.size(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_sections_num() const + { + return (Elf_Half)sections.size(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_section_index_at( Elf_Half num ) const + { + if ( num < sections.size() ) { + return sections[num]; + } + + return Elf_Half(-1); + } + +//------------------------------------------------------------------------------ + protected: +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ + void + set_offset( Elf64_Off value ) + { + ph.p_offset = value; + ph.p_offset = (*convertor)( ph.p_offset ); + is_offset_set = true; + } + +//------------------------------------------------------------------------------ + bool + is_offset_initialized() const + { + return is_offset_set; + } + +//------------------------------------------------------------------------------ + const std::vector& + get_sections() const + { + return sections; + } + +//------------------------------------------------------------------------------ + void + set_index( Elf_Half value ) + { + index = value; + } + +//------------------------------------------------------------------------------ + void + load( std::istream& stream, + std::streampos header_offset ) + { + + stream.seekg ( 0, stream.end ); + set_stream_size ( stream.tellg() ); + + stream.seekg( header_offset ); + stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); + is_offset_set = true; + + if ( PT_NULL != get_type() && 0 != get_file_size() ) { + stream.seekg( (*convertor)( ph.p_offset ) ); + Elf_Xword size = get_file_size(); + + if ( size > get_stream_size() ) { + data = 0; + } + else { + try { + data = new char[size + 1]; + } catch (const std::bad_alloc&) { + data = 0; + } + + if ( 0 != data ) { + stream.read( data, size ); + data[size] = 0; + } + } + } + } + +//------------------------------------------------------------------------------ + void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) + { + ph.p_offset = data_offset; + ph.p_offset = (*convertor)(ph.p_offset); + stream.seekp( header_offset ); + stream.write( reinterpret_cast( &ph ), sizeof( ph ) ); + } + +//------------------------------------------------------------------------------ + private: + T ph; + Elf_Half index; + char* data; + std::vector sections; + endianess_convertor* convertor; + bool is_offset_set; +}; + +} // namespace ELFIO + +#endif // ELFIO_SEGMENT_HPP diff --git a/src/elfio/elfio_strings.hpp b/src/elfio/elfio_strings.hpp new file mode 100644 index 0000000..552f000 --- /dev/null +++ b/src/elfio/elfio_strings.hpp @@ -0,0 +1,100 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_STRINGS_HPP +#define ELFIO_STRINGS_HPP + +#include +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template< class S > +class string_section_accessor_template +{ + public: +//------------------------------------------------------------------------------ + string_section_accessor_template( S* section_ ) : + string_section( section_ ) + { + } + + +//------------------------------------------------------------------------------ + const char* + get_string( Elf_Word index ) const + { + if ( string_section ) { + if ( index < string_section->get_size() ) { + const char* data = string_section->get_data(); + if ( 0 != data ) { + return data + index; + } + } + } + + return 0; + } + + +//------------------------------------------------------------------------------ + Elf_Word + add_string( const char* str ) + { + Elf_Word current_position = 0; + + if (string_section) { + // Strings are addeded to the end of the current section data + current_position = (Elf_Word)string_section->get_size(); + + if ( current_position == 0 ) { + char empty_string = '\0'; + string_section->append_data( &empty_string, 1 ); + current_position++; + } + string_section->append_data( str, (Elf_Word)std::strlen( str ) + 1 ); + } + + return current_position; + } + + +//------------------------------------------------------------------------------ + Elf_Word + add_string( const std::string& str ) + { + return add_string( str.c_str() ); + } + +//------------------------------------------------------------------------------ + private: + S* string_section; +}; + +using string_section_accessor = string_section_accessor_template
; +using const_string_section_accessor = string_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_STRINGS_HPP diff --git a/src/elfio/elfio_symbols.hpp b/src/elfio/elfio_symbols.hpp new file mode 100644 index 0000000..d18756a --- /dev/null +++ b/src/elfio/elfio_symbols.hpp @@ -0,0 +1,282 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SYMBOLS_HPP +#define ELFIO_SYMBOLS_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template< class S > +class symbol_section_accessor_template +{ + public: +//------------------------------------------------------------------------------ + symbol_section_accessor_template( const elfio& elf_file_, S* symbol_section_ ) : + elf_file( elf_file_ ), + symbol_section( symbol_section_ ) + { + find_hash_section(); + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_symbols_num() const + { + Elf_Xword nRet = 0; + if ( 0 != symbol_section->get_entry_size() ) { + nRet = symbol_section->get_size() / symbol_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_symbol( Elf_Xword index, + std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( elf_file.get_class() == ELFCLASS32 ) { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + else { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + + return ret; + } + +//------------------------------------------------------------------------------ + bool + get_symbol( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( 0 != get_hash_table_index() ) { + Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data(); + Elf_Word nchain = *(const Elf_Word*)( hash_section->get_data() + + sizeof( Elf_Word ) ); + Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); + + Elf_Word y = *(const Elf_Word*)( hash_section->get_data() + + ( 2 + val % nbucket ) * sizeof( Elf_Word ) ); + std::string str; + get_symbol( y, str, value, size, bind, type, section_index, other ); + while ( str != name && STN_UNDEF != y && y < nchain ) { + y = *(const Elf_Word*)( hash_section->get_data() + + ( 2 + nbucket + y ) * sizeof( Elf_Word ) ); + get_symbol( y, str, value, size, bind, type, section_index, other ); + } + if ( str == name ) { + ret = true; + } + } + + return ret; + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + Elf_Word nRet; + + if ( symbol_section->get_size() == 0 ) { + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + else { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( name, value, size, info, other, + shndx ); + } + else { + nRet = generic_add_symbol( name, value, size, info, other, + shndx ); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char bind, unsigned char type, unsigned char other, + Elf_Half shndx ) + { + return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, shndx ); + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( string_section_accessor& pStrWriter, const char* str, + Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + Elf_Word index = pStrWriter.add_string( str ); + return add_symbol( index, value, size, info, other, shndx ); + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( string_section_accessor& pStrWriter, const char* str, + Elf64_Addr value, Elf_Xword size, + unsigned char bind, unsigned char type, unsigned char other, + Elf_Half shndx ) + { + return add_symbol( pStrWriter, str, value, size, ELF_ST_INFO( bind, type ), other, shndx ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void + find_hash_section() + { + hash_section = 0; + hash_section_index = 0; + Elf_Half nSecNo = elf_file.sections.size(); + for ( Elf_Half i = 0; i < nSecNo && 0 == hash_section_index; ++i ) { + const section* sec = elf_file.sections[i]; + if ( sec->get_link() == symbol_section->get_index() ) { + hash_section = sec; + hash_section_index = i; + } + } + } + +//------------------------------------------------------------------------------ + Elf_Half + get_string_table_index() const + { + return (Elf_Half)symbol_section->get_link(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_hash_table_index() const + { + return hash_section_index; + } + +//------------------------------------------------------------------------------ + template< class T > + bool + generic_get_symbol( Elf_Xword index, + std::string& name, Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( index < get_symbols_num() ) { + const T* pSym = reinterpret_cast( + symbol_section->get_data() + + index * symbol_section->get_entry_size() ); + + const endianess_convertor& convertor = elf_file.get_convertor(); + + section* string_section = elf_file.sections[get_string_table_index()]; + string_section_accessor str_reader( string_section ); + const char* pStr = str_reader.get_string( convertor( pSym->st_name ) ); + if ( 0 != pStr ) { + name = pStr; + } + value = convertor( pSym->st_value ); + size = convertor( pSym->st_size ); + bind = ELF_ST_BIND( pSym->st_info ); + type = ELF_ST_TYPE( pSym->st_info ); + section_index = convertor( pSym->st_shndx ); + other = pSym->st_other; + + ret = true; + } + + return ret; + } + +//------------------------------------------------------------------------------ + template< class T > + Elf_Word + generic_add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.st_name = convertor( name ); + entry.st_value = value; + entry.st_value = convertor( entry.st_value ); + entry.st_size = size; + entry.st_size = convertor( entry.st_size ); + entry.st_info = convertor( info ); + entry.st_other = convertor( other ); + entry.st_shndx = convertor( shndx ); + + symbol_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + + Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1; + + return nRet; + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* symbol_section; + Elf_Half hash_section_index; + const section* hash_section; +}; + +using symbol_section_accessor = symbol_section_accessor_template
; +using const_symbol_section_accessor = symbol_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_SYMBOLS_HPP diff --git a/src/elfio/elfio_utils.hpp b/src/elfio/elfio_utils.hpp new file mode 100644 index 0000000..2baf5a7 --- /dev/null +++ b/src/elfio/elfio_utils.hpp @@ -0,0 +1,209 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_UTILS_HPP +#define ELFIO_UTILS_HPP + +#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const \ + { \ + return (*convertor)( FIELD ); \ + } +#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \ + void set_##NAME( TYPE value ) \ + { \ + FIELD = value; \ + FIELD = (*convertor)( FIELD ); \ + } +#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const \ + { \ + return (*convertor)( FIELD ); \ + } \ + void set_##NAME( TYPE value ) \ + { \ + FIELD = value; \ + FIELD = (*convertor)( FIELD ); \ + } + +#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0 + +#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual void set_##NAME( TYPE value ) = 0 + +#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0; \ + virtual void set_##NAME( TYPE value ) = 0 + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class endianess_convertor { + public: +//------------------------------------------------------------------------------ + endianess_convertor() + { + need_conversion = false; + } + +//------------------------------------------------------------------------------ + void + setup( unsigned char elf_file_encoding ) + { + need_conversion = ( elf_file_encoding != get_host_encoding() ); + } + +//------------------------------------------------------------------------------ + uint64_t + operator()( uint64_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x00000000000000FFull ) << 56 ) | + ( ( value & 0x000000000000FF00ull ) << 40 ) | + ( ( value & 0x0000000000FF0000ull ) << 24 ) | + ( ( value & 0x00000000FF000000ull ) << 8 ) | + ( ( value & 0x000000FF00000000ull ) >> 8 ) | + ( ( value & 0x0000FF0000000000ull ) >> 24 ) | + ( ( value & 0x00FF000000000000ull ) >> 40 ) | + ( ( value & 0xFF00000000000000ull ) >> 56 ); + + return value; + } + +//------------------------------------------------------------------------------ + int64_t + operator()( int64_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int64_t)(*this)( (uint64_t)value ); + } + +//------------------------------------------------------------------------------ + uint32_t + operator()( uint32_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x000000FF ) << 24 ) | + ( ( value & 0x0000FF00 ) << 8 ) | + ( ( value & 0x00FF0000 ) >> 8 ) | + ( ( value & 0xFF000000 ) >> 24 ); + + return value; + } + +//------------------------------------------------------------------------------ + int32_t + operator()( int32_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int32_t)(*this)( (uint32_t)value ); + } + +//------------------------------------------------------------------------------ + uint16_t + operator()( uint16_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x00FF ) << 8 ) | + ( ( value & 0xFF00 ) >> 8 ); + + return value; + } + +//------------------------------------------------------------------------------ + int16_t + operator()( int16_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int16_t)(*this)( (uint16_t)value ); + } + +//------------------------------------------------------------------------------ + int8_t + operator()( int8_t value ) const + { + return value; + } + +//------------------------------------------------------------------------------ + uint8_t + operator()( uint8_t value ) const + { + return value; + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + unsigned char + get_host_encoding() const + { + static const int tmp = 1; + if ( 1 == *(const char*)&tmp ) { + return ELFDATA2LSB; + } + else { + return ELFDATA2MSB; + } + } + +//------------------------------------------------------------------------------ + private: + bool need_conversion; +}; + + +//------------------------------------------------------------------------------ +inline +uint32_t +elf_hash( const unsigned char *name ) +{ + uint32_t h = 0, g; + while ( *name ) { + h = (h << 4) + *name++; + g = h & 0xf0000000; + if ( g != 0 ) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +} // namespace ELFIO + +#endif // ELFIO_UTILS_HPP diff --git a/src/import_stub.S b/src/import_stub.S new file mode 100644 index 0000000..7bf8dc7 --- /dev/null +++ b/src/import_stub.S @@ -0,0 +1,24 @@ +/*#define IMPORT(name) \ + .global name; \ + name: \ + lis %r11, addr_##name@h; \ + lwz %r11, addr_##name@l(%r11); \ + mtctr %r11; \ + bctr*/ + +#define IMPORT(name) \ + .global name; \ + name: \ + lis %r11, addr_##name@h; \ + ori %r11, %r11, addr_##name@l; \ + lwz %r11, 0(%r11); \ + mtctr %r11; \ + bctr + +#define IMPORT_BEGIN(lib) +#define IMPORT_END() + +.align 2; +.section ".text"; + +#include "imports.h" \ No newline at end of file diff --git a/src/imports.h b/src/imports.h new file mode 100644 index 0000000..6c113a0 --- /dev/null +++ b/src/imports.h @@ -0,0 +1,281 @@ +/* coreinit */ +IMPORT_BEGIN(coreinit); + +IMPORT(OSScreenInit); +IMPORT(OSScreenGetBufferSizeEx); +IMPORT(OSScreenSetBufferEx); +IMPORT(OSScreenEnableEx); +IMPORT(OSScreenFlipBuffersEx); +IMPORT(OSScreenClearBufferEx); +IMPORT(OSScreenPutFontEx); +IMPORT(OSFatal); +IMPORT(OSDynLoad_Acquire); +IMPORT(OSDynLoad_FindExport); +IMPORT(OSDynLoad_Release); +IMPORT(OSSetExceptionCallback); +IMPORT(OSSavesDone_ReadyToRelease); +IMPORT(OSInitMutex); +IMPORT(OSLockMutex); +IMPORT(OSUnlockMutex); +IMPORT(OSInitCond); +IMPORT(OSWaitCond); +IMPORT(OSSignalCond); +IMPORT(OSInitSpinLock); +IMPORT(OSUninterruptibleSpinLock_Acquire); +IMPORT(OSUninterruptibleSpinLock_Release); +IMPORT(OSFastMutex_Init); +IMPORT(OSFastMutex_Lock); +IMPORT(OSFastMutex_Unlock); +IMPORT(OSSleepTicks); +IMPORT(OSGetTitleID); +IMPORT(OSIsThreadTerminated); +IMPORT(OSSetThreadPriority); +IMPORT(OSCreateThread); +IMPORT(OSSetThreadCleanupCallback); +IMPORT(OSResumeThread); +IMPORT(OSIsThreadSuspended); +IMPORT(OSSuspendThread); +IMPORT(OSGetCurrentThread); +IMPORT(OSExitThread); +IMPORT(OSJoinThread); +IMPORT(OSYieldThread); +IMPORT(OSGetCoreId); +IMPORT(OSIsMainCore); +IMPORT(OSGetSystemTime); +IMPORT(OSGetSystemTick); +IMPORT(OSGetTime); +IMPORT(OSGetSymbolName); +IMPORT(OSGetSharedData); +IMPORT(OSEffectiveToPhysical); +IMPORT(OSInitSemaphore); +IMPORT(OSInitSemaphoreEx); +IMPORT(OSGetSemaphoreCount); +IMPORT(OSSignalSemaphore); +IMPORT(OSWaitSemaphore); +IMPORT(OSTryWaitSemaphore); + +IMPORT(exit); +IMPORT(_Exit); +IMPORT(__os_snprintf); +IMPORT(DisassemblePPCRange); + +IMPORT(ICInvalidateRange); +IMPORT(DCInvalidateRange); +IMPORT(DCFlushRange); +IMPORT(DCStoreRange); +IMPORT(DCStoreRangeNoSync); + +IMPORT(__gh_errno_ptr); + +IMPORT(MEMGetBaseHeapHandle); +IMPORT(MEMCreateExpHeapEx); +IMPORT(MEMDestroyExpHeap); +IMPORT(MEMAllocFromExpHeapEx); +IMPORT(MEMFreeToExpHeap); +IMPORT(MEMGetSizeForMBlockExpHeap); +IMPORT(MEMAllocFromFrmHeapEx); +IMPORT(MEMFreeToFrmHeap); +IMPORT(MEMGetAllocatableSizeForFrmHeapEx); + +IMPORT(FSInit); +IMPORT(FSShutdown); +IMPORT(FSAddClient); +IMPORT(FSAddClientEx); +IMPORT(FSDelClient); +IMPORT(FSInitCmdBlock); +IMPORT(FSChangeDir); +IMPORT(FSGetFreeSpaceSize); +IMPORT(FSGetStat); +IMPORT(FSRemove); +IMPORT(FSOpenFile); +IMPORT(FSCloseFile); +IMPORT(FSOpenDir); +IMPORT(FSMakeDir); +IMPORT(FSReadDir); +IMPORT(FSRewindDir); +IMPORT(FSCloseDir); +IMPORT(FSGetStatFile); +IMPORT(FSReadFile); +IMPORT(FSWriteFile); +IMPORT(FSSetPosFile); +IMPORT(FSFlushFile); +IMPORT(FSTruncateFile); +IMPORT(FSRename); +IMPORT(FSGetMountSource); +IMPORT(FSMount); +IMPORT(FSUnmount); + +IMPORT(IOS_Open); +IMPORT(IOS_Close); +IMPORT(IOS_Ioctl); +IMPORT(IOS_IoctlAsync); + +IMPORT(IMIsAPDEnabled); +IMPORT(IMIsDimEnabled); +IMPORT(IMEnableAPD); +IMPORT(IMEnableDim); +IMPORT(IMDisableAPD); +IMPORT(IMDisableDim); + +IMPORT(OSGetSystemInfo); + +IMPORT_END(); + +/* nsysnet */ +IMPORT_BEGIN(nsysnet); + +IMPORT(socket_lib_init); +IMPORT(getaddrinfo); +IMPORT(freeaddrinfo); +IMPORT(getnameinfo); +IMPORT(inet_ntoa); +IMPORT(inet_ntop); +IMPORT(inet_aton); +IMPORT(inet_pton); +IMPORT(ntohl); +IMPORT(ntohs); +IMPORT(htonl); +IMPORT(htons); +IMPORT(accept); +IMPORT(bind); +IMPORT(socketclose); +IMPORT(connect); +IMPORT(getpeername); +IMPORT(getsockname); +IMPORT(getsockopt); +IMPORT(listen); +IMPORT(recv); +IMPORT(recvfrom); +IMPORT(send); +IMPORT(sendto); +IMPORT(setsockopt); +IMPORT(shutdown); +IMPORT(socket); +IMPORT(select); +IMPORT(socketlasterr); + +IMPORT_END(); + +/* gx2 */ +IMPORT_BEGIN(gx2); + +IMPORT(GX2Invalidate); +IMPORT(GX2Init); +IMPORT(GX2GetSystemTVScanMode); +IMPORT(GX2CalcTVSize); +IMPORT(GX2SetTVBuffer); +IMPORT(GX2CalcDRCSize); +IMPORT(GX2SetDRCBuffer); +IMPORT(GX2CalcSurfaceSizeAndAlignment); +IMPORT(GX2InitColorBufferRegs); +IMPORT(GX2SetupContextStateEx); +IMPORT(GX2SetContextState); +IMPORT(GX2SetColorBuffer); +IMPORT(GX2SetViewport); +IMPORT(GX2SetScissor); +IMPORT(GX2SetDepthOnlyControl); +IMPORT(GX2SetColorControl); +IMPORT(GX2SetBlendControl); +IMPORT(GX2SetBlendConstantColor); +IMPORT(GX2SetCullOnlyControl); +IMPORT(GX2CalcFetchShaderSizeEx); +IMPORT(GX2InitFetchShaderEx); +IMPORT(GX2SetFetchShader); +IMPORT(GX2SetVertexShader); +IMPORT(GX2SetPixelShader); +IMPORT(GX2SetGeometryShader); +IMPORT(GX2SetGeometryUniformBlock); +IMPORT(GX2SetVertexUniformBlock); +IMPORT(GX2SetPixelUniformBlock); +IMPORT(GX2CalcGeometryShaderInputRingBufferSize); +IMPORT(GX2CalcGeometryShaderOutputRingBufferSize); +IMPORT(GX2SetGeometryShaderInputRingBuffer); +IMPORT(GX2SetGeometryShaderOutputRingBuffer); +IMPORT(GX2SetShaderModeEx); +IMPORT(GX2SetAttribBuffer); +IMPORT(GX2InitTextureRegs); +IMPORT(GX2InitSampler); +IMPORT(GX2SetPixelTexture); +IMPORT(GX2SetPixelSampler); +IMPORT(GX2ClearColor); +IMPORT(GX2CopyColorBufferToScanBuffer); +IMPORT(GX2SwapScanBuffers); +IMPORT(GX2Flush); +IMPORT(GX2WaitForVsync); +IMPORT(GX2SetTVEnable); +IMPORT(GX2SetDRCEnable); +IMPORT(GX2SetSwapInterval); +IMPORT(GX2DrawDone); +IMPORT(GX2Shutdown); +IMPORT(GX2DrawEx); +IMPORT(GX2WaitForFlip); +IMPORT(GX2GetSwapStatus); + +IMPORT_END(); + +/* nn_ac */ +IMPORT_BEGIN(nn_ac); +IMPORT(ACInitialize); +IMPORT(ACFinalize); +IMPORT(ACConnect); +IMPORT(ACClose); +IMPORT(ACGetAssignedAddress); +IMPORT(ACGetAssignedSubnet); +IMPORT_END(); + +/* proc_ui */ +IMPORT_BEGIN(proc_ui); + +IMPORT(ProcUIInit); +IMPORT(ProcUIShutdown); +IMPORT(ProcUIDrawDoneRelease); +IMPORT(ProcUIProcessMessages); + +IMPORT_END(); + +/* sndcore2 */ +IMPORT_BEGIN(sndcore2); + +IMPORT(AXInitWithParams); +IMPORT(AXQuit); +IMPORT(AXRegisterFrameCallback); +IMPORT(AXAcquireMultiVoice); +IMPORT(AXSetMultiVoiceDeviceMix); +IMPORT(AXSetMultiVoiceOffsets); +IMPORT(AXSetMultiVoiceCurrentOffset); +IMPORT(AXSetMultiVoiceState); +IMPORT(AXSetMultiVoiceVe); +IMPORT(AXSetMultiVoiceSrcType); +IMPORT(AXSetMultiVoiceSrcRatio); +IMPORT(AXIsMultiVoiceRunning); +IMPORT(AXFreeMultiVoice); + +IMPORT_END(); + +/* sysapp */ +IMPORT_BEGIN(sysapp); + +IMPORT(SYSRelaunchTitle); +IMPORT(_SYSGetSystemApplicationTitleId); +IMPORT(SYSLaunchMenu); + +IMPORT_END(); + +/* vpad */ +IMPORT_BEGIN(vpad); + +IMPORT(VPADRead); +IMPORT(VPADInit); +IMPORT(VPADGetTPCalibratedPoint); + +IMPORT_END(); + + +/* nsyskbd */ +IMPORT_BEGIN(zlib125); + +IMPORT(inflateInit_); +IMPORT(inflate); +IMPORT(inflateEnd); + +IMPORT_END(); diff --git a/src/kernel.cpp b/src/kernel.cpp new file mode 100644 index 0000000..f9d703e --- /dev/null +++ b/src/kernel.cpp @@ -0,0 +1,40 @@ +#include +#include "kernel.h" + +/* assembly functions */ +extern "C" void Syscall_0x36(void); +extern "C" void KernelPatches(void); + +void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value); + +void doKernelSetup(){ + kern_write((void*)(KERN_SYSCALL_TBL_1 + (0x36 * 4)), (unsigned int)KernelPatches); + kern_write((void*)(KERN_SYSCALL_TBL_2 + (0x36 * 4)), (unsigned int)KernelPatches); + kern_write((void*)(KERN_SYSCALL_TBL_3 + (0x36 * 4)), (unsigned int)KernelPatches); + kern_write((void*)(KERN_SYSCALL_TBL_4 + (0x36 * 4)), (unsigned int)KernelPatches); + kern_write((void*)(KERN_SYSCALL_TBL_5 + (0x36 * 4)), (unsigned int)KernelPatches); + + Syscall_0x36(); +} + +/* Write a 32-bit word with kernel permissions */ +void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value) { + asm volatile ( + "li 3,1\n" + "li 4,0\n" + "mr 5,%1\n" + "li 6,0\n" + "li 7,0\n" + "lis 8,1\n" + "mr 9,%0\n" + "mr %1,1\n" + "li 0,0x3500\n" + "sc\n" + "nop\n" + "mr 1,%1\n" + : + : "r"(addr), "r"(value) + : "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12" + ); +} \ No newline at end of file diff --git a/src/kernel.h b/src/kernel.h new file mode 100644 index 0000000..0c62312 --- /dev/null +++ b/src/kernel.h @@ -0,0 +1,10 @@ +#pragma once + +#define KERN_SYSCALL_TBL_1 0xFFE84C70 // unknown +#define KERN_SYSCALL_TBL_2 0xFFE85070 // works with games +#define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader +#define KERN_SYSCALL_TBL_4 0xFFEAAA60 // works with home menu +#define KERN_SYSCALL_TBL_5 0xFFEAAE60 // works with browser (previously KERN_SYSCALL_TBL) + + +void doKernelSetup(); \ No newline at end of file diff --git a/src/kernel_asm.S b/src/kernel_asm.S new file mode 100644 index 0000000..ab2c207 --- /dev/null +++ b/src/kernel_asm.S @@ -0,0 +1,210 @@ +.section ".kernel_code" + .globl SaveAndResetDataBATs_And_SRs_hook +SaveAndResetDataBATs_And_SRs_hook: + # setup CTR to the position we need to return to + mflr r5 + mtctr r5 + # set link register to its original value + mtlr r7 + # setup us a nice DBAT for our code data with same region as our code + mfspr r5, 560 + mtspr 570, r5 + mfspr r5, 561 + mtspr 571, r5 + # restore the original kernel instructions that we replaced + lwz r5, 0x34(r3) + lwz r6, 0x38(r3) + lwz r7, 0x3C(r3) + lwz r8, 0x40(r3) + lwz r9, 0x44(r3) + lwz r10, 0x48(r3) + lwz r11, 0x4C(r3) + lwz r3, 0x50(r3) + isync + mtsr 7, r5 + # jump back to the position in kernel after our patch (from LR) + bctr + + +#define BAT_SETUP_HOOK_ADDR 0xFFF1D624 +# not all of those NOP address are required for every firmware +# mainly these should stop the kernel from removing our IBAT4 and DBAT5 +#define BAT_SET_NOP_ADDR_1 0xFFF06B6C +#define BAT_SET_NOP_ADDR_2 0xFFF06BF8 +#define BAT_SET_NOP_ADDR_3 0xFFF003C8 +#define BAT_SET_NOP_ADDR_4 0xFFF003CC +#define BAT_SET_NOP_ADDR_5 0xFFF1D70C +#define BAT_SET_NOP_ADDR_6 0xFFF1D728 +#define BAT_SET_NOP_ADDR_7 0xFFF1D82C + +#define BAT_SET_NOP_ADDR_8 0xFFEE11C4 +#define BAT_SET_NOP_ADDR_9 0xFFEE11C8 + +#define BAT_SETUP_HOOK_ENTRY 0x00800000 + + +#define BAT4U_VAL 0x008000FF +#define BAT4L_VAL 0x30800012 + + +#define SET_R4_TO_ADDR(addr) \ + lis r3, addr@h ; \ + ori r3, r3, addr@l ; \ + stw r4, 0(r3) ; \ + dcbf 0, r3 ; \ + icbi 0, r3 ; + + .globl Syscall_0x36 +Syscall_0x36: + li r0, 0x3600 + sc + blr + + .globl KernelPatches +KernelPatches: + # store the old DBAT0 + mfdbatu r5, 0 + mfdbatl r6, 0 + + # memory barrier + eieio + isync + + # setup DBAT0 for access to kernel code memory + lis r3, 0xFFF0 + ori r3, r3, 0x0002 + mtdbatu 0, r3 + lis r3, 0xFFF0 + ori r3, r3, 0x0032 + mtdbatl 0, r3 + + # memory barrier + eieio + isync + + # SaveAndResetDataBATs_And_SRs hook setup, but could be any BAT function though + # just chosen because its simple + lis r3, BAT_SETUP_HOOK_ADDR@h + ori r3, r3, BAT_SETUP_HOOK_ADDR@l + + # make the kernel setup our section in IBAT4 and + # jump to our function to restore the replaced instructions + lis r4, 0x3ce0 # lis r7, BAT4L_VAL@h + ori r4, r4, BAT4L_VAL@h + stw r4, 0x00(r3) + lis r4, 0x60e7 # ori r7, r7, BAT4L_VAL@l + ori r4, r4, BAT4L_VAL@l + stw r4, 0x04(r3) + lis r4, 0x7cf1 # mtspr 561, r7 + ori r4, r4, 0x8ba6 + stw r4, 0x08(r3) + lis r4, 0x3ce0 # lis r7, BAT4U_VAL@h + ori r4, r4, BAT4U_VAL@h + stw r4, 0x0C(r3) + lis r4, 0x60e7 # ori r7, r7, BAT4U_VAL@l + ori r4, r4, BAT4U_VAL@l + stw r4, 0x10(r3) + lis r4, 0x7cf0 # mtspr 560, r7 + ori r4, r4, 0x8ba6 + stw r4, 0x14(r3) + lis r4, 0x7c00 # eieio + ori r4, r4, 0x06ac + stw r4, 0x18(r3) + lis r4, 0x4c00 # isync + ori r4, r4, 0x012c + stw r4, 0x1C(r3) + lis r4, 0x7ce8 # mflr r7 + ori r4, r4, 0x02a6 + stw r4, 0x20(r3) + lis r4, (BAT_SETUP_HOOK_ENTRY | 0x48000003)@h # bla BAT_SETUP_HOOK_ENTRY + ori r4, r4, (BAT_SETUP_HOOK_ENTRY | 0x48000003)@l + stw r4, 0x24(r3) + + # flush and invalidate the replaced instructions + lis r3, (BAT_SETUP_HOOK_ADDR & ~31)@h + ori r3, r3, (BAT_SETUP_HOOK_ADDR & ~31)@l + dcbf 0, r3 + icbi 0, r3 + lis r3, ((BAT_SETUP_HOOK_ADDR + 0x20) & ~31)@h + ori r3, r3, ((BAT_SETUP_HOOK_ADDR + 0x20) & ~31)@l + dcbf 0, r3 + icbi 0, r3 + sync + + # setup IBAT4 for core 1 at this position (not really required but wont hurt) + # IBATL 4 + lis r3, BAT4L_VAL@h + ori r3, r3, BAT4L_VAL@l + mtspr 561, r3 + + # IBATU 4 + lis r3, BAT4U_VAL@h + ori r3, r3, BAT4U_VAL@l + mtspr 560, r3 + + # memory barrier + eieio + isync + + # write "nop" to some positions + lis r4, 0x6000 + # nop on IBATU 4 and DBAT 5 set/reset +#ifdef BAT_SET_NOP_ADDR_1 + SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_1) +#endif +#ifdef BAT_SET_NOP_ADDR_2 + SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_2) +#endif +#ifdef BAT_SET_NOP_ADDR_3 + SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_3) +#endif +#ifdef BAT_SET_NOP_ADDR_4 + SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_4) +#endif +#ifdef BAT_SET_NOP_ADDR_5 + SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_5) +#endif +#ifdef BAT_SET_NOP_ADDR_6 + SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_6) +#endif +#ifdef BAT_SET_NOP_ADDR_7 + SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_7) +#endif + +#if (defined(BAT_SET_NOP_ADDR_8) && defined(BAT_SET_NOP_ADDR_9)) + # memory barrier + eieio + isync + + # setup DBAT0 for access to kernel code memory + lis r3, 0xFFEE + ori r3, r3, 0x0002 + mtdbatu 0, r3 + lis r3, 0xFFEE + ori r3, r3, 0x0032 + mtdbatl 0, r3 + + # memory barrier + eieio + isync + + # write "nop" to some positions + lis r4, 0x6000 + SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_8) + SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_9) +#endif + + # memory barrier + eieio + isync + + # restore DBAT 0 and return from interrupt + mtdbatu 0, r5 + mtdbatl 0, r6 + + # memory barrier + eieio + isync + + blr + diff --git a/src/link.ld b/src/link.ld new file mode 100644 index 0000000..bb4079d --- /dev/null +++ b/src/link.ld @@ -0,0 +1,26 @@ +OUTPUT(payload.elf); + +ENTRY(_start); + +SECTIONS { + . = 0x00800000; + .text : { + *(.kernel_code*); + *(.text*); + /* Tell linker to not garbage collect this section as it is not referenced anywhere */ + KEEP(*(.kernel_code*)); + } + .data : { + *(.rodata*); + *(.data*); + *(.sdata*); + *(.bss*); + *(.sbss*); + } + __CODE_END = .; + /DISCARD/ : { + *(*); + } +} + +ASSERT((SIZEOF(.text) + SIZEOF(.data)) < 0x100000, "elf is too big"); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..27b222d --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "ElfUtils.h" +#include "module/ModuleData.h" +#include "module/ModuleDataFactory.h" +#include "common/module_defines.h" + +#include "main.h" +#include "kernel.h" +#include "dynamic.h" +#include "utils/logger.h" +#include "utils/utils.h" +#include "utils/sd_fat_devoptab.h" + +#define gModuleData ((module_information_t *) (0x00880000)) +static_assert(sizeof(module_information_t) <= 0x80000); + +bool doRelocation(std::vector &relocData, relocation_trampolin_entry_t * tramp_data, uint32_t tramp_length); + + +bool CheckRunning() { + + switch(ProcUIProcessMessages(true)) { + case PROCUI_STATUS_EXITING: { + return false; + } + case PROCUI_STATUS_RELEASE_FOREGROUND: { + ProcUIDrawDoneRelease(); + break; + } + case PROCUI_STATUS_IN_FOREGROUND: { + break; + } + case PROCUI_STATUS_IN_BACKGROUND: + default: + break; + } + return true; +} + +extern "C" int _start(int argc, char **argv) { + doKernelSetup(); + InitFunctionPointers(); + + socket_lib_init(); + log_init(); + + int res = 0; + if((res = mount_sd_fat("sd")) >= 0) { + DEBUG_FUNCTION_LINE("Mounted sd card\n"); + + uint32_t ApplicationMemoryEnd; + + asm volatile("lis %0, __CODE_END@h; ori %0, %0, __CODE_END@l" : "=r" (ApplicationMemoryEnd)); + ApplicationMemoryEnd = (ApplicationMemoryEnd + 0x10000) & 0xFFFF0000; + ModuleData * moduleData = ModuleDataFactory::load("sd:/wiiu/payload.rpx", ApplicationMemoryEnd, 0x01000000 - ApplicationMemoryEnd, gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH); + if(moduleData != NULL) { + DEBUG_FUNCTION_LINE("Loaded module data\n"); + std::vector relocData = moduleData->getRelocationDataList(); + if(!doRelocation(relocData, gModuleData->trampolines,DYN_LINK_TRAMPOLIN_LIST_LENGTH)) { + DEBUG_FUNCTION_LINE("relocations failed\n"); + } + if(moduleData->getBSSAddr() != 0) { + DEBUG_FUNCTION_LINE("memset .bss %08X (%d)\n", moduleData->getBSSAddr(), moduleData->getBSSSize()); + memset((void*)moduleData->getBSSAddr(), 0, moduleData->getBSSSize()); + } + if(moduleData->getSBSSAddr() != 0) { + DEBUG_FUNCTION_LINE("memset .sbss %08X (%d)\n", moduleData->getSBSSAddr(), moduleData->getSBSSSize()); + memset((void*)moduleData->getSBSSAddr(), 0, moduleData->getSBSSSize()); + } + DCFlushRange((void*)0x00800000, 0x00800000); + ICInvalidateRange((void*)0x00800000, 0x00800000); + DEBUG_FUNCTION_LINE("New entrypoint: %08X\n", moduleData->getEntrypoint()); + ((int (*)(int, char **))moduleData->getEntrypoint())(argc, argv); + delete moduleData; + } else { + DEBUG_FUNCTION_LINE("Failed to load module\n"); + } + } else { + DEBUG_FUNCTION_LINE("Mounted sd card failed %d.\n", res); + } + + SYSLaunchMenu(); + + ProcUIInit(OSSavesDone_ReadyToRelease); + DEBUG_FUNCTION_LINE("In ProcUI loop\n"); + while(CheckRunning()) { + // wait. + OSSleepTicks(OSMillisecondsToTicks(100)); + } + ProcUIShutdown(); + + return 0; +} + + +bool doRelocation(std::vector &relocData, relocation_trampolin_entry_t * tramp_data, uint32_t tramp_length) { + for (auto const& curReloc : relocData) { + RelocationData * cur = curReloc; + std::string functionName = cur->getName(); + std::string rplName = cur->getImportRPLInformation()->getName(); + int32_t isData = cur->getImportRPLInformation()->isData(); + OSDynLoad_Module rplHandle = 0; + OSDynLoad_Acquire(rplName.c_str(), &rplHandle); + + uint32_t functionAddress = 0; + OSDynLoad_FindExport(rplHandle, isData, functionName.c_str(), (void**) &functionAddress); + if(functionAddress == 0) { + return false; + } + if(!ElfUtils::elfLinkOne(cur->getType(), cur->getOffset(), cur->getAddend(), (uint32_t) cur->getDestination(), functionAddress, tramp_data, tramp_length, RELOC_TYPE_IMPORT)) { + DEBUG_FUNCTION_LINE("Relocation failed\n"); + return false; + } + } + + DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampolin_entry_t)); + ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampolin_entry_t)); + return true; +} diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..6449b0d --- /dev/null +++ b/src/main.h @@ -0,0 +1,16 @@ +//Main.h +#ifndef _MAIN_H_ +#define _MAIN_H_ + + +/* Main */ +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/module/DynamicLinkingHelper.cpp b/src/module/DynamicLinkingHelper.cpp new file mode 100644 index 0000000..eef4960 --- /dev/null +++ b/src/module/DynamicLinkingHelper.cpp @@ -0,0 +1,104 @@ +#include "DynamicLinkingHelper.h" +#include +#include +#include +#include +#include "utils/logger.h" +#include "common/module_defines.h" + +dyn_linking_function_t * DynamicLinkingHelper::getOrAddFunctionEntryByName(dyn_linking_relocation_data_t * data, const char* functionName) { + if(data == NULL) { + return NULL; + } + if(functionName == NULL) { + return NULL; + } + dyn_linking_function_t * result = NULL; + for(int32_t i = 0; i < DYN_LINK_FUNCTION_LIST_LENGTH; i++) { + dyn_linking_function_t * curEntry = &(data->functions[i]); + if(strlen(curEntry->functionName) == 0) { + if(strlen(functionName) > DYN_LINK_FUNCTION_NAME_LENGTH) { + DEBUG_FUNCTION_LINE("Failed to add function name, it's too long.\n"); + return NULL; + } + strncpy(curEntry->functionName,functionName,DYN_LINK_FUNCTION_NAME_LENGTH); + result = curEntry; + break; + } + if(strncmp(curEntry->functionName,functionName,DYN_LINK_FUNCTION_NAME_LENGTH) == 0) { + result = curEntry; + break; + } + } + return result; +} + +dyn_linking_import_t * DynamicLinkingHelper::getOrAddFunctionImportByName(dyn_linking_relocation_data_t * data, const char* importName) { + return getOrAddImport(data, importName, false); +} + +dyn_linking_import_t * DynamicLinkingHelper::getOrAddDataImportByName(dyn_linking_relocation_data_t * data, const char* importName) { + return getOrAddImport(data, importName, true); +} + +dyn_linking_import_t * DynamicLinkingHelper::getOrAddImport(dyn_linking_relocation_data_t * data, const char* importName, bool isData) { + if(importName == NULL || data == NULL) { + return NULL; + } + dyn_linking_import_t * result = NULL; + for(int32_t i = 0; i < DYN_LINK_IMPORT_LIST_LENGTH; i++) { + dyn_linking_import_t * curEntry = &(data->imports[i]); + if(strlen(curEntry->importName) == 0) { + if(strlen(importName) > DYN_LINK_IMPORT_NAME_LENGTH) { + DEBUG_FUNCTION_LINE("Failed to add Import, it's too long.\n"); + return NULL; + } + strncpy(curEntry->importName,importName,DYN_LINK_IMPORT_NAME_LENGTH); + curEntry->isData = isData; + result = curEntry; + break; + } + if(strncmp(curEntry->importName,importName,DYN_LINK_IMPORT_NAME_LENGTH) == 0 && (curEntry->isData == isData)) { + return curEntry; + } + } + return result; +} + +bool DynamicLinkingHelper::addReloationEntry(dyn_linking_relocation_data_t * linking_data, dyn_linking_relocation_entry_t * linking_entries, uint32_t linking_entry_length, RelocationData * relocationData) { + return addReloationEntry(linking_data, linking_entries, linking_entry_length, relocationData->getType(), relocationData->getOffset(), relocationData->getAddend(), relocationData->getDestination(), relocationData->getName(), relocationData->getImportRPLInformation()); +} + +bool DynamicLinkingHelper::addReloationEntry(dyn_linking_relocation_data_t * linking_data, dyn_linking_relocation_entry_t * linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination, std::string name, ImportRPLInformation * rplInfo) { + dyn_linking_import_t * importInfoGbl = DynamicLinkingHelper::getOrAddImport(linking_data, rplInfo->getName().c_str(),rplInfo->isData()); + if(importInfoGbl == NULL) { + DEBUG_FUNCTION_LINE("Getting import info failed. Probably maximum of %d rpl files to import reached.\n",DYN_LINK_IMPORT_LIST_LENGTH); + return false; + } + + dyn_linking_function_t * functionInfo = DynamicLinkingHelper::getOrAddFunctionEntryByName(linking_data, name.c_str()); + if(functionInfo == NULL) { + DEBUG_FUNCTION_LINE("Getting import info failed. Probably maximum of %d function to be relocated reached.\n",DYN_LINK_FUNCTION_LIST_LENGTH); + return false; + } + + return addReloationEntry(linking_entries, linking_entry_length, type, offset, addend, destination, functionInfo, importInfoGbl); +} + +bool DynamicLinkingHelper::addReloationEntry(dyn_linking_relocation_entry_t * linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination, dyn_linking_function_t * functionName, dyn_linking_import_t * importInfo) { + for(uint32_t i = 0; i < linking_entry_length; i++) { + dyn_linking_relocation_entry_t * curEntry = &(linking_entries[i]); + if(curEntry->functionEntry != NULL) { + continue; + } + curEntry->type = type; + curEntry->offset = offset; + curEntry->addend = addend; + curEntry->destination = destination; + curEntry->functionEntry = functionName; + curEntry->importEntry = importInfo; + + return true; + } + return false; +} diff --git a/src/module/DynamicLinkingHelper.h b/src/module/DynamicLinkingHelper.h new file mode 100644 index 0000000..0e30dc5 --- /dev/null +++ b/src/module/DynamicLinkingHelper.h @@ -0,0 +1,60 @@ +#pragma once +#include "common/dynamic_linking_defines.h" +#include "utils/logger.h" +#include +#include +#include "RelocationData.h" + +class DynamicLinkingHelper { +public: + /** + Gets the function entry for a given function name. If the function name is not present in the list, it will be added. + + \param functionName Name of the function + \return Returns a pointer to the entry which contains the functionName. Null on error or if the list full. + **/ + static dyn_linking_function_t * getOrAddFunctionEntryByName(dyn_linking_relocation_data_t * data, const char * functionName); + + /** + Gets the function import entry for a given function name. If the import is not present in the list, it will be added. + This will return entries for _function_ imports. + + \param importName Name of the function + \return Returns a pointer to the function import entry which contains the importName. Null on error or if the list full. + **/ + static dyn_linking_import_t * getOrAddFunctionImportByName(dyn_linking_relocation_data_t * data, const char * importName); + + + /** + Gets the data import entry for a given data name. If the import is not present in the list, it will be added. + This will return entries for _data_ imports. + + \param importName Name of the data + \return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full. + **/ + static dyn_linking_import_t * getOrAddDataImportByName(dyn_linking_relocation_data_t * data, const char * importName); + + + /** + Gets the import entry for a given data name and type. If the import is not present in the list, it will be added. + This will return entries for _data_ and _function_ imports, depending on the isData parameter. + + \param importName Name of the data + \param isData Set this to true to return a data import + + \return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full. + **/ + static dyn_linking_import_t * getOrAddImport(dyn_linking_relocation_data_t * data, const char * importName, bool isData); + + static bool addReloationEntry(dyn_linking_relocation_data_t * linking_data, dyn_linking_relocation_entry_t * linking_entries, uint32_t linking_entry_length, RelocationData * relocationData); + + static bool addReloationEntry(dyn_linking_relocation_data_t * linking_data, dyn_linking_relocation_entry_t * linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination, std::string name, ImportRPLInformation * rplInfo); + + static bool addReloationEntry(dyn_linking_relocation_entry_t * linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination, dyn_linking_function_t * functionName, dyn_linking_import_t * importInfo); +private: + DynamicLinkingHelper() { + } + + ~DynamicLinkingHelper() { + } +}; diff --git a/src/module/ImportRPLInformation.h b/src/module/ImportRPLInformation.h new file mode 100644 index 0000000..ded0760 --- /dev/null +++ b/src/module/ImportRPLInformation.h @@ -0,0 +1,67 @@ +/**************************************************************************** + * Copyright (C) 2018 Maschell + * + * 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 3 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 . + ****************************************************************************/ + +#pragma once + +#include +#include "utils/logger.h" + +class ImportRPLInformation { + +public: + ImportRPLInformation(std::string name, bool isData = false) { + this->name = name; + this->_isData = isData; + } + + ~ImportRPLInformation() { + } + + static ImportRPLInformation * createImportRPLInformation(std::string rawSectionName) { + std::string fimport = ".fimport_"; + std::string dimport = ".dimport_"; + + bool data = false; + + std::string rplName = ""; + + if(rawSectionName.size() < fimport.size()) { + return NULL; + } else if (std::equal(fimport.begin(), fimport.end(), rawSectionName.begin())) { + rplName = rawSectionName.substr(fimport.size()); + } else if (std::equal(dimport.begin(), dimport.end(), rawSectionName.begin())) { + rplName = rawSectionName.substr(dimport.size()); + data = true; + } else { + DEBUG_FUNCTION_LINE("invalid section name\n"); + return NULL; + } + return new ImportRPLInformation(rplName, data); + } + + std::string getName() { + return name; + } + + bool isData() { + return _isData; + } + +private: + std::string name; + bool _isData = false; +}; diff --git a/src/module/ModuleData.cpp b/src/module/ModuleData.cpp new file mode 100644 index 0000000..5c41dba --- /dev/null +++ b/src/module/ModuleData.cpp @@ -0,0 +1,12 @@ +#include "ModuleData.h" +#include "utils/StringTools.h" + +std::string ModuleData::toString() { + std::string res = StringTools::strfmt("Entrypoint %08X, bss: %08X (%d), bss: %08X (%d)\n", getEntrypoint(), getBSSAddr(), getBSSSize(), getSBSSAddr(), getSBSSSize()); + for (auto const& reloc : relocation_data_list) { + if(reloc != NULL) { + res += reloc->toString(); + } + } + return res; +} diff --git a/src/module/ModuleData.h b/src/module/ModuleData.h new file mode 100644 index 0000000..41b9a77 --- /dev/null +++ b/src/module/ModuleData.h @@ -0,0 +1,88 @@ +/**************************************************************************** + * Copyright (C) 2018 Maschell + * + * 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 3 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 . + ****************************************************************************/ + +#pragma once + +#include +#include +#include "RelocationData.h" + +class ModuleData { +public: + ModuleData() { + } + + ~ModuleData() { + for (auto const& reloc : relocation_data_list) { + if(reloc != NULL) { + delete reloc; + } + } + } + + void setBSSLocation(uint32_t addr, uint32_t size) { + this->bssAddr = addr; + this->bssSize = size; + } + + void setSBSSLocation(uint32_t addr, uint32_t size) { + this->sbssAddr = addr; + this->sbssSize = size; + } + + void setEntrypoint(uint32_t addr) { + this->entrypoint = addr; + } + + void addRelocationData(RelocationData * relocation_data) { + relocation_data_list.push_back(relocation_data); + } + + std::vector getRelocationDataList() { + return relocation_data_list; + } + + uint32_t getBSSAddr() { + return bssAddr; + } + + uint32_t getBSSSize() { + return bssSize; + } + + uint32_t getSBSSAddr() { + return sbssAddr; + } + + uint32_t getSBSSSize() { + return sbssSize; + } + + uint32_t getEntrypoint() { + return entrypoint; + } + + std::string toString(); +private: + std::vector relocation_data_list; + + uint32_t bssAddr = 0; + uint32_t bssSize = 0; + uint32_t sbssAddr = 0; + uint32_t sbssSize = 0; + uint32_t entrypoint = 0; +}; diff --git a/src/module/ModuleDataFactory.cpp b/src/module/ModuleDataFactory.cpp new file mode 100644 index 0000000..22cd562 --- /dev/null +++ b/src/module/ModuleDataFactory.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** + * Copyright (C) 2018 Maschell + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ + +#include +#include +#include +#include +#include "ModuleDataFactory.h" +#include "elfio/elfio.hpp" +#include "utils/utils.h" +#include "../ElfUtils.h" + +using namespace ELFIO; + +ModuleData * ModuleDataFactory::load(std::string path, uint32_t destination_address, uint32_t maximum_size, relocation_trampolin_entry_t * trampolin_data, uint32_t trampolin_data_length) { + elfio reader; + ModuleData * moduleData = new ModuleData(); + if(moduleData == NULL) { + return NULL; + } + + // Load ELF data + if (!reader.load(path)) { + DEBUG_FUNCTION_LINE("Can't find or process ELF file\n"); + delete moduleData; + return NULL; + } + + uint32_t sec_num = reader.sections.size(); + + uint8_t **destinations = (uint8_t **) malloc(sizeof(uint8_t *) * sec_num); + + uint32_t baseOffset = destination_address; + + uint32_t offset_text = baseOffset; + uint32_t offset_data = offset_text; + + uint32_t entrypoint = offset_text + (uint32_t) reader.get_entry() - 0x02000000; + + uint32_t totalSize = 0; + + for(uint32_t i = 0; i < sec_num; ++i ) { + section* psec = reader.sections[i]; + if (psec->get_type() == 0x80000002) { + continue; + } + + if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) { + uint32_t sectionSize = psec->get_size(); + uint32_t address = (uint32_t) psec->get_address(); + + destinations[psec->get_index()] = (uint8_t *) baseOffset; + + uint32_t destination = baseOffset + address; + if((address >= 0x02000000) && address < 0x10000000) { + destination -= 0x02000000; + destinations[psec->get_index()] -= 0x02000000; + baseOffset += sectionSize; + offset_data += sectionSize; + } else if((address >= 0x10000000) && address < 0xC0000000) { + destination -= 0x10000000; + destinations[psec->get_index()] -= 0x10000000; + } else if(address >= 0xC0000000) { + destination -= 0xC0000000; + destinations[psec->get_index()] -= 0xC0000000; + } else { + DEBUG_FUNCTION_LINE("Unhandled case\n"); + free(destinations); + delete moduleData; + return NULL; + } + + const char* p = reader.sections[i]->get_data(); + + if(psec->get_type() == SHT_NOBITS) { + DEBUG_FUNCTION_LINE("memset section %s %08X to 0 (%d bytes)\n", psec->get_name().c_str(), destination, sectionSize); + memset((void*) destination, 0, sectionSize); + } else if(psec->get_type() == SHT_PROGBITS) { + DEBUG_FUNCTION_LINE("Copy section %s %08X -> %08X (%d bytes)\n", psec->get_name().c_str(), p, destination, sectionSize); + memcpy((void*) destination, p, sectionSize); + } + + //nextAddress = ROUNDUP(destination + sectionSize,0x100); + if(psec->get_name().compare(".bss") == 0) { + moduleData->setBSSLocation(destination, sectionSize); + DEBUG_FUNCTION_LINE("Saved %s section info. Location: %08X size: %08X\n", psec->get_name().c_str(), destination, sectionSize); + } else if(psec->get_name().compare(".sbss") == 0) { + moduleData->setSBSSLocation(destination, sectionSize); + DEBUG_FUNCTION_LINE("Saved %s section info. Location: %08X size: %08X\n", psec->get_name().c_str(), destination, sectionSize); + } + totalSize += sectionSize; + + DCFlushRange((void*)destination, sectionSize); + ICInvalidateRange((void*)destination, sectionSize); + } + } + + for(uint32_t i = 0; i < sec_num; ++i ) { + section* psec = reader.sections[i]; + if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) { + DEBUG_FUNCTION_LINE("Linking (%d)... %s\n",i,psec->get_name().c_str()); + if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], offset_text, offset_data, trampolin_data, trampolin_data_length)) { + DEBUG_FUNCTION_LINE("elfLink failed\n"); + free(destinations); + delete moduleData; + return NULL; + } + } + } + std::vector relocationData = getImportRelocationData(reader, destinations); + + for (auto const& reloc : relocationData) { + moduleData->addRelocationData(reloc); + } + + DCFlushRange((void*)destination_address, totalSize); + ICInvalidateRange((void*)destination_address, totalSize); + + free(destinations); + + moduleData->setEntrypoint(entrypoint); + DEBUG_FUNCTION_LINE("Saved entrypoint as %08X\n", entrypoint); + + return moduleData; +} + + +std::vector ModuleDataFactory::getImportRelocationData(elfio& reader, uint8_t ** destinations) { + std::vector result; + std::map infoMap; + + uint32_t sec_num = reader.sections.size(); + + for ( uint32_t i = 0; i < sec_num; ++i ) { + section* psec = reader.sections[i]; + if (psec->get_type() == 0x80000002) { + infoMap[i] = psec->get_name(); + } + } + + for (uint32_t i = 0; i < sec_num; ++i ) { + section* psec = reader.sections[i]; + if(psec->get_type() == SHT_RELA || psec->get_type() == SHT_REL) { + DEBUG_FUNCTION_LINE("Found relocation section %s\n",psec->get_name().c_str()); + relocation_section_accessor rel(reader, psec); + for ( uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j ) { + Elf64_Addr offset; + Elf_Word type; + Elf_Sxword addend; + std::string sym_name; + Elf64_Addr sym_value; + Elf_Half sym_section_index; + + if(!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) { + DEBUG_FUNCTION_LINE("Failed to get relocation\n"); + break; + } + + uint32_t adjusted_sym_value = (uint32_t) sym_value; + if(adjusted_sym_value < 0xC0000000) { + continue; + } + ImportRPLInformation * rplInfo = ImportRPLInformation::createImportRPLInformation(infoMap[sym_section_index]); + if(rplInfo == NULL) { + DEBUG_FUNCTION_LINE("Failed to create import information\n"); + break; + } + + uint32_t section_index = psec->get_info(); + + // When these relocations are performed, we don't need the 0xC0000000 offset anymore. + RelocationData * relocationData = new RelocationData(type, offset - 0x02000000, addend, (void*)(destinations[section_index] + 0x02000000), sym_name, rplInfo); + //relocationData->printInformation(); + result.push_back(relocationData); + } + } + } + return result; +} +bool ModuleDataFactory::linkSection(elfio& reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampolin_entry_t * trampolin_data, uint32_t trampolin_data_length) { + uint32_t sec_num = reader.sections.size(); + + for (uint32_t i = 0; i < sec_num; ++i ) { + section* psec = reader.sections[i]; + if(psec->get_info() == section_index) { + DEBUG_FUNCTION_LINE("Found relocation section %s\n",psec->get_name().c_str()); + relocation_section_accessor rel(reader, psec); + for ( uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j ) { + Elf64_Addr offset; + Elf_Word type; + Elf_Sxword addend; + std::string sym_name; + Elf64_Addr sym_value; + Elf_Half sym_section_index; + + if(!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) { + DEBUG_FUNCTION_LINE("Failed to get relocation\n"); + break; + } + + uint32_t adjusted_sym_value = (uint32_t) sym_value; + if((adjusted_sym_value >= 0x02000000) && adjusted_sym_value < 0x10000000) { + adjusted_sym_value -= 0x02000000; + adjusted_sym_value += base_text; + } else if((adjusted_sym_value >= 0x10000000) && adjusted_sym_value < 0xC0000000) { + adjusted_sym_value -= 0x10000000; + adjusted_sym_value += base_data; + } else if(adjusted_sym_value >= 0xC0000000) { + // Skip imports + continue; + } else if(adjusted_sym_value == 0x0) { + // + } else { + DEBUG_FUNCTION_LINE("Unhandled case %08X\n",adjusted_sym_value); + return false; + } + + if(sym_section_index == SHN_ABS) { + // + } else if(sym_section_index > SHN_LORESERVE) { + DEBUG_FUNCTION_LINE("NOT IMPLEMENTED: %04X\n", sym_section_index); + return false; + } + + if(!ElfUtils::elfLinkOne(type, offset, addend, destination, adjusted_sym_value, trampolin_data, trampolin_data_length, RELOC_TYPE_FIXED)) { + DEBUG_FUNCTION_LINE("Link failed\n"); + return false; + } + } + } + } + return true; +} diff --git a/src/module/ModuleDataFactory.h b/src/module/ModuleDataFactory.h new file mode 100644 index 0000000..b0a2525 --- /dev/null +++ b/src/module/ModuleDataFactory.h @@ -0,0 +1,32 @@ +/**************************************************************************** + * Copyright (C) 2019 Maschell + * + * 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 3 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 . + ****************************************************************************/ + +#pragma once + +#include +#include +#include +#include "common/relocation_defines.h" +#include "ModuleData.h" +#include "elfio/elfio.hpp" + +class ModuleDataFactory { +public: + static ModuleData * load(std::string path, uint32_t destination_address, uint32_t maximum_size, relocation_trampolin_entry_t * trampolin_data, uint32_t trampolin_data_length); + static bool linkSection(ELFIO::elfio& reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampolin_entry_t * trampolin_data, uint32_t trampolin_data_length); + static std::vector getImportRelocationData(ELFIO::elfio& reader, uint8_t ** destinations); +}; diff --git a/src/module/ModuleDataPersistence.cpp b/src/module/ModuleDataPersistence.cpp new file mode 100644 index 0000000..4048a49 --- /dev/null +++ b/src/module/ModuleDataPersistence.cpp @@ -0,0 +1,106 @@ +#include + +#include "ModuleDataPersistence.h" +#include "DynamicLinkingHelper.h" +#include "common/module_defines.h" +#include "ModuleData.h" +#include "RelocationData.h" + +bool ModuleDataPersistence::saveModuleData(module_information_t * moduleInformation, ModuleData * module) { + int32_t module_count = moduleInformation->number_used_modules; + + if(module_count >= MAXIMUM_MODULES) { + return false; + } + // Copy data to global struct. + module_information_single_t * module_data = &(moduleInformation->module_data[module_count]); + + // Relocation + std::vector relocationData = module->getRelocationDataList(); + for (auto const& reloc : relocationData) { + if(!DynamicLinkingHelper::addReloationEntry(&(moduleInformation->linking_data), module_data->linking_entries, DYN_LINK_RELOCATION_LIST_LENGTH, reloc)) { + return false; + } + } + + module_data->bssAddr = module->getBSSAddr(); + module_data->bssSize = module->getBSSSize(); + module_data->sbssAddr = module->getSBSSAddr(); + module_data->sbssSize = module->getSBSSSize(); + + module_data->entrypoint = module->getEntrypoint(); + + moduleInformation->number_used_modules++; + + DCFlushRange((void*)moduleInformation,sizeof(module_information_t)); + ICInvalidateRange((void*)moduleInformation,sizeof(module_information_t)); + + return true; +} + +std::vector ModuleDataPersistence::loadModuleData(module_information_t * moduleInformation) { + std::vector result; + if(moduleInformation == NULL) { + DEBUG_FUNCTION_LINE("moduleInformation == NULL\n"); + return result; + } + DCFlushRange((void*)moduleInformation,sizeof(module_information_t)); + ICInvalidateRange((void*)moduleInformation,sizeof(module_information_t)); + + int32_t module_count = moduleInformation->number_used_modules; + if(module_count > MAXIMUM_MODULES) { + DEBUG_FUNCTION_LINE("moduleInformation->module_count was bigger then allowed. %d > %d. Limiting to %d\n",module_count, MAXIMUM_MODULES, MAXIMUM_MODULES); + module_count = MAXIMUM_MODULES; + } + for(int32_t i = 0; i < module_count; i++) { + // Copy data from struct. + module_information_single_t * module_data = &(moduleInformation->module_data[i]); + ModuleData * moduleData = new ModuleData(); + if(moduleData == NULL){ + DEBUG_FUNCTION_LINE("Failed to allocate data for ModuleData object\n"); + continue; + } + moduleData->setBSSLocation(module_data->bssAddr, module_data->bssSize); + moduleData->setSBSSLocation(module_data->sbssAddr, module_data->sbssSize); + moduleData->setEntrypoint(module_data->entrypoint); + + for(uint32_t j = 0; j < DYN_LINK_RELOCATION_LIST_LENGTH; j++) { + dyn_linking_relocation_entry_t * linking_entry = &(module_data->linking_entries[j]); + if(linking_entry->destination == NULL){ + break; + } + dyn_linking_import_t* importEntry = linking_entry->importEntry; + if(importEntry == NULL){ + DEBUG_FUNCTION_LINE("importEntry was NULL, skipping relocation entry\n"); + continue; + } + if(importEntry->importName == NULL){ + DEBUG_FUNCTION_LINE("importEntry->importName was NULL, skipping relocation entry\n"); + continue; + } + dyn_linking_function_t* functionEntry = linking_entry->functionEntry; + + if(functionEntry == NULL){ + DEBUG_FUNCTION_LINE("functionEntry was NULL, skipping relocation entry\n"); + continue; + } + if(functionEntry->functionName == NULL){ + DEBUG_FUNCTION_LINE("functionEntry->functionName was NULL, skipping relocation entry\n"); + continue; + } + ImportRPLInformation * rplInfo = new ImportRPLInformation(importEntry->importName, importEntry->isData); + if(rplInfo == NULL){ + DEBUG_FUNCTION_LINE("Failed to allocate ImportRPLInformation object. Skipping relocation entry.\n"); + continue; + } + RelocationData * reloc = new RelocationData(linking_entry->type, linking_entry->offset, linking_entry->addend, linking_entry->destination, functionEntry->functionName, rplInfo); + if(reloc == NULL){ + DEBUG_FUNCTION_LINE("Failed to allocate RelocationData object. Skipping relocation entry.\n"); + continue; + } + moduleData->addRelocationData(reloc); + } + result.push_back(moduleData); + } + return result; +} diff --git a/src/module/ModuleDataPersistence.h b/src/module/ModuleDataPersistence.h new file mode 100644 index 0000000..2c35ff6 --- /dev/null +++ b/src/module/ModuleDataPersistence.h @@ -0,0 +1,10 @@ +#pragma once + +#include "common/module_defines.h" +#include "ModuleData.h" + +class ModuleDataPersistence { +public: + static bool saveModuleData(module_information_t * moduleInformation, ModuleData * module); + static std::vector loadModuleData(module_information_t * moduleInformation); +}; diff --git a/src/module/RelocationData.cpp b/src/module/RelocationData.cpp new file mode 100644 index 0000000..8fdcc3a --- /dev/null +++ b/src/module/RelocationData.cpp @@ -0,0 +1,6 @@ +#include "RelocationData.h" +#include "utils/StringTools.h" + +std::string RelocationData::toString(){ + return StringTools::strfmt("%s destination: %08X offset: %08X type: %02X addend: %d rplName: %s isData: %d \n",name.c_str(), destination, offset, type, addend, rplInfo->getName().c_str(), rplInfo->isData() ); +} diff --git a/src/module/RelocationData.h b/src/module/RelocationData.h new file mode 100644 index 0000000..5e463b3 --- /dev/null +++ b/src/module/RelocationData.h @@ -0,0 +1,73 @@ +/**************************************************************************** + * Copyright (C) 2018 Maschell + * + * 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 3 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 . + ****************************************************************************/ + +#pragma once + +#include +#include "ImportRPLInformation.h" + +class RelocationData { + +public: + RelocationData(char type, size_t offset, int32_t addend, void *destination, std::string name, ImportRPLInformation * rplInfo) { + this->type = type; + this->offset = offset; + this->addend = addend; + this->destination = destination; + this->name = name; + this->rplInfo = rplInfo; + } + + ~RelocationData() { + if(rplInfo != NULL) { + delete rplInfo; + } + } + + char getType() { + return type; + } + + size_t getOffset() { + return offset; + } + + int32_t getAddend() { + return addend; + } + + void * getDestination() { + return destination; + } + + std::string getName() { + return name; + } + + ImportRPLInformation * getImportRPLInformation() { + return rplInfo; + } + + std::string toString(); +private: + char type; + size_t offset; + int32_t addend; + void *destination; + std::string name; + ImportRPLInformation * rplInfo; +}; diff --git a/src/utils/FSOSUtils.cpp b/src/utils/FSOSUtils.cpp new file mode 100644 index 0000000..c5fe3bf --- /dev/null +++ b/src/utils/FSOSUtils.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include "utils/logger.h" +#include "FSOSUtils.h" + +#define FS_MOUNT_SOURCE_SIZE 0x300 +#define FS_MAX_MOUNTPATH_SIZE 128 +#define FS_SOURCETYPE_EXTERNAL 0 + +int32_t FSOSUtils::MountFS(FSClient *pClient, FSCmdBlock *pCmd, char **mount_path) { + int32_t result = -1; + DEBUG_FUNCTION_LINE("\n"); + FSMountSource *mountSrc = (FSMountSource*) malloc(sizeof(FSMountSource)); + if(!mountSrc) { + return -3; + } + + DEBUG_FUNCTION_LINE("\n"); + char* mountPath = (char*) malloc(FS_MAX_MOUNTPATH_SIZE); + if(!mountPath) { + free(mountSrc); + mountSrc = NULL; + return -4; + } + DEBUG_FUNCTION_LINE("\n"); + memset(mountSrc, 0, FS_MOUNT_SOURCE_SIZE); + memset(mountPath, 0, FS_MAX_MOUNTPATH_SIZE); + + + // Mount sdcard + if (FSGetMountSource(pClient, pCmd, FS_MOUNT_SOURCE_SD, mountSrc, -1) == 0) { + DEBUG_FUNCTION_LINE("\n"); + result = FSMount(pClient, pCmd, mountSrc, mountPath, FS_MAX_MOUNTPATH_SIZE, -1); + if((result == 0) && mount_path) { + *mount_path = (char*)malloc(strlen(mountPath) + 1); + if(*mount_path) + strcpy(*mount_path, mountPath); + } + } + + DEBUG_FUNCTION_LINE("\n"); + free(mountPath); + free(mountSrc); + + mountPath = NULL; + mountSrc = NULL; + + return result; +} + +int32_t FSOSUtils::UmountFS(FSClient *pClient, FSCmdBlock *pCmd, const char *mountPath) { + int32_t result = -1; + result = FSUnmount(pClient, pCmd, mountPath, -1); + + return result; +} diff --git a/src/utils/FSOSUtils.h b/src/utils/FSOSUtils.h new file mode 100644 index 0000000..648af2e --- /dev/null +++ b/src/utils/FSOSUtils.h @@ -0,0 +1,13 @@ +#ifndef __FS_OS_UTILS_H_ +#define __FS_OS_UTILS_H_ + +#include +#include + +class FSOSUtils { +public: + static int32_t MountFS(FSClient *pClient, FSCmdBlock *pCmd, char **mount_path); + static int32_t UmountFS(FSClient *pClient, FSCmdBlock *pCmd, const char *mountPath); +}; + +#endif // __FS_OS_UTILS_H_ diff --git a/src/utils/StringTools.cpp b/src/utils/StringTools.cpp new file mode 100644 index 0000000..ec7cf68 --- /dev/null +++ b/src/utils/StringTools.cpp @@ -0,0 +1,290 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +BOOL StringTools::EndsWith(const std::string& a, const std::string& b) { + if (b.size() > a.size()) + return false; + return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin()); +} + +const char * StringTools::byte_to_binary(int32_t x) { + static char b[9]; + b[0] = '\0'; + + int32_t z; + for (z = 128; z > 0; z >>= 1) { + strcat(b, ((x & z) == z) ? "1" : "0"); + } + + return b; +} + +std::string StringTools::removeCharFromString(std::string& input,char toBeRemoved) { + std::string output = input; + size_t position; + while(1) { + position = output.find(toBeRemoved); + if(position == std::string::npos) + break; + output.erase(position, 1); + } + return output; +} + +const char * StringTools::fmt(const char * format, ...) { + static char strChar[512]; + strChar[0] = 0; + + va_list va; + va_start(va, format); + if((vsprintf(strChar, format, va) >= 0)) { + va_end(va); + return (const char *) strChar; + } + va_end(va); + + return NULL; +} + +const wchar_t * StringTools::wfmt(const char * format, ...) { + static char tmp[512]; + static wchar_t strWChar[512]; + strWChar[0] = 0; + tmp[0] = 0; + + if(!format) + return (const wchar_t *) strWChar; + + if(strcmp(format, "") == 0) + return (const wchar_t *) strWChar; + + va_list va; + va_start(va, format); + if((vsprintf(tmp, format, va) >= 0)) { + int bt; + int32_t strlength = strlen(tmp); + bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512 ); + + if(bt > 0) { + strWChar[bt] = 0; + return (const wchar_t *) strWChar; + } + } + va_end(va); + + return NULL; +} + +int32_t StringTools::strprintf(std::string &str, const char * format, ...) { + static char tmp[512]; + tmp[0] = 0; + int32_t result = 0; + + va_list va; + va_start(va, format); + if((vsprintf(tmp, format, va) >= 0)) { + str = tmp; + result = str.size(); + } + va_end(va); + + return result; +} + +std::string StringTools::strfmt(const char * format, ...) { + std::string str; + static char tmp[512]; + tmp[0] = 0; + + va_list va; + va_start(va, format); + if((vsprintf(tmp, format, va) >= 0)) { + str = tmp; + } + va_end(va); + + return str; +} + +BOOL StringTools::char2wchar_t(const char * strChar, wchar_t * dest) { + if(!strChar || !dest) + return false; + + int bt; + bt = mbstowcs(dest, strChar, strlen(strChar)); + if (bt > 0) { + dest[bt] = 0; + return true; + } + + return false; +} + +int32_t StringTools::strtokcmp(const char * string, const char * compare, const char * separator) { + if(!string || !compare) + return -1; + + char TokCopy[512]; + strncpy(TokCopy, compare, sizeof(TokCopy)); + TokCopy[511] = '\0'; + + char * strTok = strtok(TokCopy, separator); + + while (strTok != NULL) { + if (strcasecmp(string, strTok) == 0) { + return 0; + } + strTok = strtok(NULL,separator); + } + + return -1; +} + +int32_t StringTools::strextcmp(const char * string, const char * extension, char seperator) { + if(!string || !extension) + return -1; + + char *ptr = strrchr(string, seperator); + if(!ptr) + return -1; + + return strcasecmp(ptr + 1, extension); +} + + +std::vector StringTools::stringSplit(const std::string & inValue, const std::string & splitter) { + std::string value = inValue; + std::vector result; + while (true) { + uint32_t index = value.find(splitter); + if (index == std::string::npos) { + result.push_back(value); + break; + } + std::string first = value.substr(0, index); + result.push_back(first); + if (index + splitter.size() == value.length()) { + result.push_back(""); + break; + } + if(index + splitter.size() > value.length()) { + break; + } + value = value.substr(index + splitter.size(), value.length()); + } + return result; +} + + +const char * StringTools::FullpathToFilename(const char *path) { + if(!path) + return path; + + const char * ptr = path; + const char * Filename = ptr; + + while(*ptr != '\0') { + if(ptr[0] == '/' && ptr[1] != '\0') + Filename = ptr+1; + + ++ptr; + } + + return Filename; + } + +void StringTools::RemoveDoubleSlashs(std::string &str) { + uint32_t length = str.size(); + + //! clear path of double slashes + for(uint32_t i = 1; i < length; ++i) { + if(str[i-1] == '/' && str[i] == '/') { + str.erase(i, 1); + i--; + length--; + } + } + } + + +// You must free the result if result is non-NULL. +char * StringTools::str_replace(char *orig, char *rep, char *with) { + char *result; // the return string + char *ins; // the next insert point + char *tmp; // varies + int len_rep; // length of rep (the string to remove) + int len_with; // length of with (the string to replace rep with) + int len_front; // distance between rep and end of last rep + int count; // number of replacements + + // sanity checks and initialization + if (!orig || !rep) + return NULL; + len_rep = strlen(rep); + if (len_rep == 0) + return NULL; // empty rep causes infinite loop during count + if (!with) + with = ""; + len_with = strlen(with); + + // count the number of replacements needed + ins = orig; + for (count = 0; tmp = strstr(ins, rep); ++count) { + ins = tmp + len_rep; + } + + tmp = result = (char*)malloc(strlen(orig) + (len_with - len_rep) * count + 1); + + if (!result) + return NULL; + + // first time through the loop, all the variable are set correctly + // from here on, + // tmp points to the end of the result string + // ins points to the next occurrence of rep in orig + // orig points to the remainder of orig after "end of rep" + while (count--) { + ins = strstr(orig, rep); + len_front = ins - orig; + tmp = strncpy(tmp, orig, len_front) + len_front; + tmp = strcpy(tmp, with) + len_with; + orig += len_front + len_rep; // move to next "end of rep" + } + strcpy(tmp, orig); + return result; +} diff --git a/src/utils/StringTools.h b/src/utils/StringTools.h new file mode 100644 index 0000000..8087a70 --- /dev/null +++ b/src/utils/StringTools.h @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef __STRING_TOOLS_H +#define __STRING_TOOLS_H + +#include +#include +#include + +class StringTools { +public: + static BOOL EndsWith(const std::string& a, const std::string& b); + static const char * byte_to_binary(int32_t x); + static std::string removeCharFromString(std::string& input,char toBeRemoved); + static const char * fmt(const char * format, ...); + static const wchar_t * wfmt(const char * format, ...); + static int32_t strprintf(std::string &str, const char * format, ...); + static std::string strfmt(const char * format, ...); + static BOOL char2wchar_t(const char * src, wchar_t * dest); + static int32_t strtokcmp(const char * string, const char * compare, const char * separator); + static int32_t strextcmp(const char * string, const char * extension, char seperator); + static char *str_replace(char *orig, char *rep, char *with); + static const char * FullpathToFilename(const char *path); + static void RemoveDoubleSlashs(std::string &str); + static std::vector stringSplit(const std::string & value, const std::string & splitter); +}; + +#endif /* __STRING_TOOLS_H */ + diff --git a/src/utils/logger.c b/src/utils/logger.c new file mode 100644 index 0000000..0922230 --- /dev/null +++ b/src/utils/logger.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int log_socket __attribute__((section(".data")))= -1; +static struct sockaddr_in connect_addr __attribute__((section(".data"))); +static volatile int log_lock __attribute__((section(".data"))) = 0; + +void log_init_() { + int broadcastEnable = 1; + log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (log_socket < 0) + return; + + setsockopt(log_socket, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)); + + memset(&connect_addr, 0, sizeof(struct sockaddr_in)); + connect_addr.sin_family = AF_INET; + connect_addr.sin_port = 4405; + connect_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); +} + +void log_print_(const char *str) { + // socket is always 0 initially as it is in the BSS + if(log_socket < 0) { + return; + } + + while(log_lock) + OSSleepTicks(OSMicrosecondsToTicks(1000)); + log_lock = 1; + + int len = strlen(str); + int ret; + while (len > 0) { + int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet + ret = sendto(log_socket, str, block, 0, (struct sockaddr *)&connect_addr, sizeof(struct sockaddr_in)); + if(ret < 0) + break; + + len -= ret; + str += ret; + } + + log_lock = 0; +} + +void OSFatal_printf(const char *format, ...) { + char tmp[512]; + tmp[0] = 0; + va_list va; + va_start(va, format); + if((vsprintf(tmp, format, va) >= 0)) { + OSFatal(tmp); + } + va_end(va); +} + +void log_printf_(const char *format, ...) { + if(log_socket < 0) { + return; + } + + char tmp[512]; + tmp[0] = 0; + + va_list va; + va_start(va, format); + if((vsprintf(tmp, format, va) >= 0)) { + log_print_(tmp); + } + va_end(va); +} + diff --git a/src/utils/logger.h b/src/utils/logger.h new file mode 100644 index 0000000..d026b05 --- /dev/null +++ b/src/utils/logger.h @@ -0,0 +1,38 @@ +#ifndef __LOGGER_H_ +#define __LOGGER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void log_init_(); +//void log_deinit_(void); +void log_print_(const char *str); +void log_printf_(const char *format, ...); +void OSFatal_printf(const char *format, ...); + +#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) + +#define OSFATAL_FUNCTION_LINE(FMT, ARGS...)do { \ + OSFatal_printf("[%s]%s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ + } while (0) + + + +#define log_init() log_init_() +//#define log_deinit() log_deinit_() +#define log_print(str) log_print_(str) +#define log_printf(FMT, ARGS...) log_printf_(FMT, ## ARGS); + +#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \ + log_printf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ + } while (0) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/utils/memory.c b/src/utils/memory.c new file mode 100644 index 0000000..214726d --- /dev/null +++ b/src/utils/memory.c @@ -0,0 +1,107 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include +#include +#include +#include +#include +#include + +extern uint32_t * pMEMAllocFromDefaultHeapEx; +extern uint32_t * pMEMAllocFromDefaultHeap; +extern uint32_t * pMEMFreeToDefaultHeap; + +//!------------------------------------------------------------------------------------------- +//! reent versions +//!------------------------------------------------------------------------------------------- +void *_malloc_r(struct _reent *r, size_t size) { + void *ptr = ((void * (*)(size_t))(*pMEMAllocFromDefaultHeap))(size); + if (!ptr) { + r->_errno = ENOMEM; + } + return ptr; +} + +void *_calloc_r(struct _reent *r, size_t num, size_t size) { + void *ptr = ((void * (*)(size_t))(*pMEMAllocFromDefaultHeap))(size); + if (ptr) { + memset(ptr, 0, num * size); + } else { + r->_errno = ENOMEM; + } + + return ptr; +} + +void *_memalign_r(struct _reent *r, size_t align, size_t size) { + return ((void * (*)(size_t, size_t))(*pMEMAllocFromDefaultHeapEx))(size, align); +} + +void _free_r(struct _reent *r, void *ptr) { + if (ptr) { + ((void (*)(void *))(*pMEMFreeToDefaultHeap))(ptr); + } +} + +void *_realloc_r(struct _reent *r, void *p, size_t size) { + void *new_ptr = ((void * (*)(size_t))(*pMEMAllocFromDefaultHeap))(size); + if (!new_ptr) { + r->_errno = ENOMEM; + return new_ptr; + } + + if (p) { + size_t old_size = MEMGetSizeForMBlockExpHeap(p); + memcpy(new_ptr, p, old_size <= size ? old_size : size); + ((void (*)(void *))(*pMEMFreeToDefaultHeap))(p); + } + return new_ptr; +} + +struct mallinfo _mallinfo_r(struct _reent *r) { + struct mallinfo info = { 0 }; + return info; +} + +void +_malloc_stats_r(struct _reent *r) { +} + +int +_mallopt_r(struct _reent *r, int param, int value) { + return 0; +} + +size_t +_malloc_usable_size_r(struct _reent *r, void *ptr) { + return MEMGetSizeForMBlockExpHeap(ptr); +} + +void * +_valloc_r(struct _reent *r, size_t size) { + return ((void * (*)(size_t, size_t))(*pMEMAllocFromDefaultHeapEx))(size, OS_PAGE_SIZE); +} + +void * +_pvalloc_r(struct _reent *r, size_t size) { + return ((void * (*)(size_t, size_t))(*pMEMAllocFromDefaultHeapEx))((size + (OS_PAGE_SIZE - 1)) & ~(OS_PAGE_SIZE - 1), OS_PAGE_SIZE); +} + +int +_malloc_trim_r(struct _reent *r, size_t pad) { + return 0; +} diff --git a/src/utils/memory.h b/src/utils/memory.h new file mode 100644 index 0000000..db67a05 --- /dev/null +++ b/src/utils/memory.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 3 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 __MEMORY_H_ +#define __MEMORY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void memoryInitialize(void); +void memoryRelease(void); + +void * MEM2_alloc(u32 size, u32 align); +void MEM2_free(void *ptr); + +void * MEM1_alloc(u32 size, u32 align); +void MEM1_free(void *ptr); + +void * MEMBucket_alloc(u32 size, u32 align); +void MEMBucket_free(void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif // __MEMORY_H_ diff --git a/src/utils/sd_fat_devoptab.cpp b/src/utils/sd_fat_devoptab.cpp new file mode 100644 index 0000000..527b7fa --- /dev/null +++ b/src/utils/sd_fat_devoptab.cpp @@ -0,0 +1,1016 @@ +/*************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd_fat_devoptab.h" +#include "FSOSUtils.h" +#include "utils/StringTools.h" +#include "utils/logger.h" + +#define FS_ALIGNMENT 0x40 +#define FS_ALIGN(x) (((x) + FS_ALIGNMENT - 1) & ~(FS_ALIGNMENT - 1)) + +typedef struct _sd_fat_private_t { + char *mount_path; + FSClient *pClient; + FSCmdBlock *pCmd; + OSMutex *pMutex; +} sd_fat_private_t; + +typedef struct _sd_fat_file_state_t { + sd_fat_private_t *dev; + int fd; /* File descriptor */ + int flags; /* Opening flags */ + bool read; /* True if allowed to read from file */ + bool write; /* True if allowed to write to file */ + bool append; /* True if allowed to append to file */ + uint64_t pos; /* Current position within the file (in bytes) */ + uint64_t len; /* Total length of the file (in bytes) */ + struct _sd_fat_file_state_t *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */ + struct _sd_fat_file_state_t *nextOpenFile; /* The next entry in a double-linked FILO list of open files */ +} sd_fat_file_state_t; + +typedef struct _sd_fat_dir_entry_t { + sd_fat_private_t *dev; + int dirHandle; +} sd_fat_dir_entry_t; + +static sd_fat_private_t *sd_fat_get_device_data(const char *path) { + const devoptab_t *devoptab = NULL; + char name[128] = {0}; + int i; + + // Get the device name from the path + strncpy(name, path, 127); + strtok(name, ":/"); + + // Search the devoptab table for the specified device name + // NOTE: We do this manually due to a 'bug' in GetDeviceOpTab + // which ignores names with suffixes and causes names + // like "ntfs" and "ntfs1" to be seen as equals + for (i = 3; i < STD_MAX; i++) { + devoptab = devoptab_list[i]; + if (devoptab && devoptab->name) { + if (strcmp(name, devoptab->name) == 0) { + return (sd_fat_private_t *)devoptab->deviceData; + } + } + } + + return NULL; +} + +static char *sd_fat_real_path (const char *path, sd_fat_private_t *dev) { + // Sanity check + if (!path) + return NULL; + + // Move the path pointer to the start of the actual path + if (strchr(path, ':') != NULL) { + path = strchr(path, ':') + 1; + } + + int mount_len = strlen(dev->mount_path); + + char *new_name = (char*)malloc(mount_len + strlen(path) + 1); + if(new_name) { + strcpy(new_name, dev->mount_path); + strcpy(new_name + mount_len, path); + return new_name; + } + return new_name; +} + +static int sd_fat_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) { + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fileStruct; + + file->dev = dev; + // Determine which mode the file is opened for + file->flags = flags; + + const char *mode_str; + + if ((flags & 0x03) == O_RDONLY) { + file->read = true; + file->write = false; + file->append = false; + mode_str = "r"; + } else if ((flags & 0x03) == O_WRONLY) { + file->read = false; + file->write = true; + file->append = (flags & O_APPEND); + mode_str = file->append ? "a" : "w"; + } else if ((flags & 0x03) == O_RDWR) { + file->read = true; + file->write = true; + file->append = (flags & O_APPEND); + mode_str = file->append ? "a+" : "r+"; + } else { + r->_errno = EACCES; + return -1; + } + + int32_t fd = -1; + + OSLockMutex((OSMutex *)dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!path) { + r->_errno = ENOMEM; + OSUnlockMutex((OSMutex *)dev->pMutex); + return -1; + } + + int result = FSOpenFile(dev->pClient, dev->pCmd, real_path, mode_str, (FSFileHandle*) &fd, -1); + + free(real_path); + + if(result == 0) { + FSStat stats; + result = FSGetStatFile(dev->pClient, dev->pCmd, fd, &stats, -1); + if(result != 0) { + FSCloseFile(dev->pClient, dev->pCmd, fd, -1); + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + file->fd = fd; + file->pos = 0; + file->len = stats.size; + OSUnlockMutex(dev->pMutex); + return (int)file; + } + + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; +} + + +static int sd_fat_close_r (struct _reent *r, void *fd) { + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSCloseFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + return 0; +} + +static off_t sd_fat_seek_r (struct _reent *r, void* fd, off_t pos, int dir) { + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + switch(dir) { + case SEEK_SET: + file->pos = pos; + break; + case SEEK_CUR: + file->pos += pos; + break; + case SEEK_END: + file->pos = file->len + pos; + break; + default: + r->_errno = EINVAL; + return -1; + } + + int result = FSSetPosFile(file->dev->pClient, file->dev->pCmd, file->fd, file->pos, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result == 0) { + return file->pos; + } + + return result; +} + +static ssize_t sd_fat_write_r (struct _reent *r, void *fd, const char *ptr, size_t len) { + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + if(!file->write) { + r->_errno = EACCES; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + size_t len_aligned = FS_ALIGN(len); + if(len_aligned > 0x4000) + len_aligned = 0x4000; + + unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); + if(!tmpBuf) { + r->_errno = ENOMEM; + OSUnlockMutex(file->dev->pMutex); + return 0; + } + + size_t done = 0; + + while(done < len) { + size_t write_size = (len_aligned < (len - done)) ? len_aligned : (len - done); + memcpy(tmpBuf, ptr + done, write_size); + + int result = FSWriteFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, write_size, file->fd, 0, -1); + if(result < 0) { + r->_errno = result; + break; + } else if(result == 0) { + if(write_size > 0) + done = 0; + break; + } else { + done += result; + file->pos += result; + } + } + + free(tmpBuf); + OSUnlockMutex(file->dev->pMutex); + return done; +} + +static ssize_t sd_fat_read_r (struct _reent *r, void* fd, char *ptr, size_t len) { + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + if(!file->read) { + r->_errno = EACCES; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + size_t len_aligned = FS_ALIGN(len); + if(len_aligned > 0x4000) + len_aligned = 0x4000; + + unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); + if(!tmpBuf) { + r->_errno = ENOMEM; + OSUnlockMutex(file->dev->pMutex); + return 0; + } + + size_t done = 0; + + while(done < len) { + size_t read_size = (len_aligned < (len - done)) ? len_aligned : (len - done); + + int result = FSReadFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, read_size, file->fd, 0, -1); + if(result < 0) { + r->_errno = result; + done = 0; + break; + } else if(result == 0) { + //! TODO: error on read_size > 0 + break; + } else { + memcpy(ptr + done, tmpBuf, read_size); + done += result; + file->pos += result; + } + } + + free(tmpBuf); + OSUnlockMutex(file->dev->pMutex); + return done; +} + + +static int sd_fat_fstat_r (struct _reent *r, void* fd, struct stat *st) { + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + // Zero out the stat buffer + memset(st, 0, sizeof(struct stat)); + + FSStat stats; + int result = FSGetStatFile(file->dev->pClient, file->dev->pCmd, file->fd, &stats, -1); + if(result != 0) { + r->_errno = result; + OSUnlockMutex(file->dev->pMutex); + return -1; + } + + st->st_mode = S_IFREG; + st->st_size = stats.size; + st->st_blocks = (stats.size + 511) >> 9; + st->st_nlink = 1; + + // Fill in the generic entry stats + st->st_dev = stats.entryId; + st->st_uid = stats.owner; + st->st_gid = stats.group; + st->st_ino = stats.entryId; + st->st_atime = stats.modified; + st->st_ctime = stats.created; + st->st_mtime = stats.modified; + OSUnlockMutex(file->dev->pMutex); + return 0; +} + +static int sd_fat_ftruncate_r (struct _reent *r, void* fd, off_t len) { + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSTruncateFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_fsync_r (struct _reent *r, void* fd) { + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSFlushFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_stat_r (struct _reent *r, const char *path, struct stat *st) { + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + // Zero out the stat buffer + memset(st, 0, sizeof(struct stat)); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + FSStat stats; + + int result = FSGetStat(dev->pClient, dev->pCmd, real_path, &stats, -1); + + free(real_path); + + if(result < 0) { + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + + // mark root also as directory + st->st_mode = ((stats.flags & 0x80000000) || (strlen(dev->mount_path) + 1 == strlen(real_path)))? S_IFDIR : S_IFREG; + st->st_nlink = 1; + st->st_size = stats.size; + st->st_blocks = (stats.size + 511) >> 9; + // Fill in the generic entry stats + st->st_dev = stats.entryId; + st->st_uid = stats.owner; + st->st_gid = stats.group; + st->st_ino = stats.entryId; + st->st_atime = stats.modified; + st->st_ctime = stats.created; + st->st_mtime = stats.modified; + + OSUnlockMutex(dev->pMutex); + + return 0; +} + +static int sd_fat_link_r (struct _reent *r, const char *existing, const char *newLink) { + r->_errno = ENOTSUP; + return -1; +} + +static int sd_fat_unlink_r (struct _reent *r, const char *name) { + sd_fat_private_t *dev = sd_fat_get_device_data(name); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(name, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + + int result = FSRemove(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_chdir_r (struct _reent *r, const char *name) { + sd_fat_private_t *dev = sd_fat_get_device_data(name); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(name, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSChangeDir(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_rename_r (struct _reent *r, const char *oldName, const char *newName) { + sd_fat_private_t *dev = sd_fat_get_device_data(oldName); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_oldpath = sd_fat_real_path(oldName, dev); + if(!real_oldpath) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + char *real_newpath = sd_fat_real_path(newName, dev); + if(!real_newpath) { + r->_errno = ENOMEM; + free(real_oldpath); + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSRename(dev->pClient, dev->pCmd, real_oldpath, real_newpath, -1); + + free(real_oldpath); + free(real_newpath); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; + +} + +static int sd_fat_mkdir_r (struct _reent *r, const char *path, int mode) { + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSMakeDir(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) { + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + // Zero out the stat buffer + memset(buf, 0, sizeof(struct statvfs)); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + uint64_t size; + + int result = FSGetFreeSpaceSize(dev->pClient, dev->pCmd, real_path, &size, -1); + + free(real_path); + + if(result < 0) { + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + + // File system block size + buf->f_bsize = 512; + + // Fundamental file system block size + buf->f_frsize = 512; + + // Total number of blocks on file system in units of f_frsize + buf->f_blocks = size >> 9; // this is unknown + + // Free blocks available for all and for non-privileged processes + buf->f_bfree = buf->f_bavail = size >> 9; + + // Number of inodes at this point in time + buf->f_files = 0xffffffff; + + // Free inodes available for all and for non-privileged processes + buf->f_ffree = 0xffffffff; + + // File system id + buf->f_fsid = (int)dev; + + // Bit mask of f_flag values. + buf->f_flag = 0; + + // Maximum length of filenames + buf->f_namemax = 255; + + OSUnlockMutex(dev->pMutex); + + return 0; +} + +static DIR_ITER *sd_fat_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path) { + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return NULL; + } + + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return NULL; + } + + int32_t dirHandle; + + int result = FSOpenDir(dev->pClient, dev->pCmd, real_path, (FSDirectoryHandle*) &dirHandle, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return NULL; + } + + dirIter->dev = dev; + dirIter->dirHandle = dirHandle; + + return dirState; +} + +static int sd_fat_dirclose_r (struct _reent *r, DIR_ITER *dirState) { + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + int result = FSCloseDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, -1); + + OSUnlockMutex(dirIter->dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + return 0; +} + +static int sd_fat_dirreset_r (struct _reent *r, DIR_ITER *dirState) { + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + int result = FSRewindDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, -1); + + OSUnlockMutex(dirIter->dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + return 0; +} + +static int sd_fat_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st) { + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + FSDirectoryEntry * dir_entry = (FSDirectoryEntry *)malloc(sizeof(FSDirectoryEntry)); + + int result = FSReadDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, dir_entry, -1); + if(result < 0) { + free(dir_entry); + r->_errno = result; + OSUnlockMutex(dirIter->dev->pMutex); + return -1; + } + + // Fetch the current entry + strcpy(filename, dir_entry->name); + + if(st) { + memset(st, 0, sizeof(struct stat)); + st->st_mode = (dir_entry->info.flags & 0x80000000) ? S_IFDIR : S_IFREG; + st->st_nlink = 1; + st->st_size = dir_entry->info.size; + st->st_blocks = (dir_entry->info.size + 511) >> 9; + st->st_dev = dir_entry->info.entryId; + st->st_uid = dir_entry->info.owner; + st->st_gid = dir_entry->info.group; + st->st_ino = dir_entry->info.entryId; + st->st_atime = dir_entry->info.modified; + st->st_ctime = dir_entry->info.created; + st->st_mtime = dir_entry->info.modified; + } + + free(dir_entry); + OSUnlockMutex(dirIter->dev->pMutex); + return 0; +} + +// SD device driver devoptab +static const devoptab_t devops_sd_fat = { + NULL, /* Device name */ + sizeof (sd_fat_file_state_t), + sd_fat_open_r, + sd_fat_close_r, + sd_fat_write_r, + sd_fat_read_r, + sd_fat_seek_r, + sd_fat_fstat_r, + sd_fat_stat_r, + sd_fat_link_r, + sd_fat_unlink_r, + sd_fat_chdir_r, + sd_fat_rename_r, + sd_fat_mkdir_r, + sizeof (sd_fat_dir_entry_t), + sd_fat_diropen_r, + sd_fat_dirreset_r, + sd_fat_dirnext_r, + sd_fat_dirclose_r, + sd_fat_statvfs_r, + sd_fat_ftruncate_r, + sd_fat_fsync_r, + NULL, /* Device data */ + NULL, /* sd_fat_chmod_r */ + NULL, /* sd_fat_fchmod_r */ + NULL, /* sd_fat_rmdir_r */ + NULL, + NULL +}; + + +static int sd_fat_add_device (const char *name, const char *mount_path, FSClient *pClient, FSCmdBlock *pCmd) { + devoptab_t *dev = NULL; + char *devname = NULL; + char *devpath = NULL; + int i; + + // Sanity check + if (!name) { + errno = EINVAL; + return -1; + } + + // Allocate a devoptab for this device + dev = (devoptab_t *) malloc(sizeof(devoptab_t) + strlen(name) + 1); + if (!dev) { + errno = ENOMEM; + return -1; + } + + // Use the space allocated at the end of the devoptab for storing the device name + devname = (char*)(dev + 1); + strcpy(devname, name); + + // create private data + int mount_path_len = 0; + if(mount_path != NULL) { + mount_path_len = strlen(mount_path); + } + sd_fat_private_t *priv = (sd_fat_private_t *)malloc(sizeof(sd_fat_private_t) + mount_path_len + 1); + if(!priv) { + free(dev); + errno = ENOMEM; + return -1; + } + + devpath = (char*)(priv+1); + if(mount_path != NULL) { + strcpy(devpath, mount_path); + } + + // setup private data + priv->mount_path = devpath; + priv->pClient = pClient; + priv->pCmd = pCmd; + priv->pMutex = (OSMutex*) malloc(sizeof(OSMutex)); + + if(!priv->pMutex) { + free(dev); + free(priv); + errno = ENOMEM; + return -1; + } + + OSInitMutex(priv->pMutex); + + // Setup the devoptab + memcpy(dev, &devops_sd_fat, sizeof(devoptab_t)); + dev->name = devname; + dev->deviceData = priv; + + // Add the device to the devoptab table (if there is a free slot) + for (i = 3; i < STD_MAX; i++) { + if (devoptab_list[i] == devoptab_list[0]) { + devoptab_list[i] = dev; + return 0; + } + } + + // failure, free all memory + free(priv); + free(dev); + + // If we reach here then there are no free slots in the devoptab table for this device + errno = EADDRNOTAVAIL; + return -1; +} + +/* +Because of some weird reason unmounting doesn't work properly. +This fix if mainly when a usb drive is connected. +It resets the devoptab_list, otherwise mounting again would throw an exception (in strlen). +No memory is free'd here. Maybe a problem?!?!? +*/ + +void deleteDevTabsNames() { + const devoptab_t * devoptab = NULL; + uint32_t last_entry = (uint32_t) devoptab_list[STD_MAX-1]; + for (int i = 3; i < STD_MAX; i++) { + devoptab = devoptab_list[i]; + + if (devoptab) { + //log_printf("check devotab %d %08X\n",i,devoptab); + if((uint32_t) devoptab != last_entry) { + devoptab_list[i] = (const devoptab_t *)last_entry; + //log_printf("Removed devotab %d %08X %08X %08X\n",i,devoptab,devoptab->name,devoptab->deviceData); + } + } + } +} + +static int sd_fat_remove_device (const char *path, FSClient **pClient, FSCmdBlock **pCmd, char **mountPath) { + const devoptab_t *devoptab = NULL; + char name[128] = {0}; + int i; + + // Get the device name from the path + strncpy(name, path, 127); + strtok(name, ":/"); + + // Find and remove the specified device from the devoptab table + // NOTE: We do this manually due to a 'bug' in RemoveDevice + // which ignores names with suffixes and causes names + // like "ntfs" and "ntfs1" to be seen as equals + for (i = 3; i < STD_MAX; i++) { + devoptab = devoptab_list[i]; + if (devoptab && devoptab->name) { + if (strcmp(name, devoptab->name) == 0) { + devoptab_list[i] = devoptab_list[0]; + + if(devoptab->deviceData) { + sd_fat_private_t *priv = (sd_fat_private_t *)devoptab->deviceData; + if(pClient != NULL) *pClient = priv->pClient; + if(pCmd != NULL) *pCmd = priv->pCmd; + if(mountPath != NULL) { + *mountPath = (char*) malloc(strlen(priv->mount_path)+1); + if(*mountPath) + strcpy(*mountPath, priv->mount_path); + } + if(priv->pMutex) + free(priv->pMutex); + free(devoptab->deviceData); + } + + free((devoptab_t*)devoptab); + return 0; + } + } + } + + return -1; +} + +int32_t mount_sd_fat(const char *path) { + int result = -1; + + // get command and client + FSClient* pClient = (FSClient *) malloc(sizeof(FSClient)); + FSCmdBlock* pCmd = (FSCmdBlock*) malloc(sizeof(FSCmdBlock)); + + if(!pClient || !pCmd) { + // just in case free if not 0 + if(pClient) + free(pClient); + if(pCmd) + free(pCmd); + return -2; + } + + FSInit(); + FSInitCmdBlock(pCmd); + FSAddClient(pClient, 0); + + char *mountPath = NULL; + + DEBUG_FUNCTION_LINE("Calling MountFS\n"); + if(FSOSUtils::MountFS(pClient, pCmd, &mountPath) == 0) { + result = sd_fat_add_device(path, mountPath, pClient, pCmd); + free(mountPath); + } + + return result; +} + +int32_t unmount_sd_fat(const char *path) { + FSClient *pClient = 0; + FSCmdBlock *pCmd = 0; + char *mountPath = 0; + + int result = sd_fat_remove_device(path, &pClient, &pCmd, &mountPath); + if(result == 0) { + FSOSUtils::UmountFS(pClient, pCmd, mountPath); + FSDelClient(pClient,0); + free(pClient); + free(pCmd); + free(mountPath); + //FSShutdown(); + } + return result; +} + +int32_t mount_fake() { + return sd_fat_add_device("fake", NULL, NULL, NULL); +} + +int32_t unmount_fake() { + return sd_fat_remove_device ("fake", NULL,NULL,NULL); +} diff --git a/src/utils/sd_fat_devoptab.h b/src/utils/sd_fat_devoptab.h new file mode 100644 index 0000000..88a1c04 --- /dev/null +++ b/src/utils/sd_fat_devoptab.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __SD_FAT_DEVOPTAB_H_ +#define __SD_FAT_DEVOPTAB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t mount_sd_fat(const char *path); +int32_t unmount_sd_fat(const char *path); +int32_t mount_fake(); +int32_t unmount_fake(); +void deleteDevTabsNames(); +#ifdef __cplusplus +} +#endif + +#endif // __SD_FAT_DEVOPTAB_H_ diff --git a/src/utils/utils.c b/src/utils/utils.c new file mode 100644 index 0000000..a8b56ee --- /dev/null +++ b/src/utils/utils.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include +#include "utils/logger.h" + +// https://gist.github.com/ccbrown/9722406 +void dumpHex(const void* data, size_t size) { + char ascii[17]; + size_t i, j; + ascii[16] = '\0'; + DEBUG_FUNCTION_LINE("0x%08X (0x0000): ", data); + for (i = 0; i < size; ++i) { + log_printf("%02X ", ((unsigned char*)data)[i]); + if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { + ascii[i % 16] = ((unsigned char*)data)[i]; + } else { + ascii[i % 16] = '.'; + } + if ((i+1) % 8 == 0 || i+1 == size) { + log_print(" "); + if ((i+1) % 16 == 0) { + log_printf("| %s \n", ascii); + if(i + 1 < size) { + DEBUG_FUNCTION_LINE("0x%08X (0x%04X); ", data + i + 1,i+1); + } + } else if (i+1 == size) { + ascii[(i+1) % 16] = '\0'; + if ((i+1) % 16 <= 8) { + log_print(" "); + } + for (j = (i+1) % 16; j < 16; ++j) { + log_print(" "); + } + log_printf("| %s \n", ascii); + } + } + } +} diff --git a/src/utils/utils.h b/src/utils/utils.h new file mode 100644 index 0000000..26caaaf --- /dev/null +++ b/src/utils/utils.h @@ -0,0 +1,35 @@ +#ifndef __UTILS_H_ +#define __UTILS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define LIMIT(x, min, max) \ + ({ \ + typeof( x ) _x = x; \ + typeof( min ) _min = min; \ + typeof( max ) _max = max; \ + ( ( ( _x ) < ( _min ) ) ? ( _min ) : ( ( _x ) > ( _max ) ) ? ( _max) : ( _x ) ); \ +}) + +#define DegToRad(a) ( (a) * 0.01745329252f ) +#define RadToDeg(a) ( (a) * 57.29577951f ) + +#define ALIGN4(x) (((x) + 3) & ~3) +#define ALIGN32(x) (((x) + 31) & ~31) + +#define le16(i) ((((uint16_t) ((i) & 0xFF)) << 8) | ((uint16_t) (((i) & 0xFF00) >> 8))) +#define le32(i) ((((uint32_t)le16((i) & 0xFFFF)) << 16) | ((uint32_t)le16(((i) & 0xFFFF0000) >> 16))) +#define le64(i) ((((uint64_t)le32((i) & 0xFFFFFFFFLL)) << 32) | ((uint64_t)le32(((i) & 0xFFFFFFFF00000000LL) >> 32))) + +//Needs to have log_init() called beforehand. +void dumpHex(const void* data, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif // __UTILS_H_