Java 2 Ada - Tag ELF2023-08-20T14:14:31+00:00Stephane Carrezurn:md5:d12e23c53b2436d6becce3d51ddbdf38AWAAda BFD 1.3.0urn:md5:0f5fbfe07c452321316d3dea42e681502023-08-20T14:14:31+00:002023-08-20T14:14:31+00:00Stephane CarrezreleaseELFCOFFbinutilsAda
<div class="post-text"><h5>[Ada/ada-bfd-1.3.jpg](Ada/ada-bfd-1.3.jpg)</h5><ol><li><ol><li>Integration with Alire</li></ol></li></ol><p>For Linux users only, the <a href="Ada BFD">Ada BFD</a>(https://github.com/stcarrez/ada-bfd) has an associated Alire crate which allows you to use it easily. To get access to the Alire crate, you should add the <a href="AWA Alire index">AWA Alire index</a>(https://github.com/stcarrez/awa-alire-index) in your Alire configuration as follows:</p><p>``` alr index <del>add=https://github.com/stcarrez/awa-alire-index.git </del>name awa ```</p><p>Then, you can get access to the crate by using</p><p>``` alr with bfdada ```</p><p>Let's see how to use this library...</p><ol><li><ol><li>Declarations</li></ol></li></ol><p>The <a href="Ada BFD">Ada BFD</a>(https://github.com/stcarrez/ada-bfd) library provides a set of Ada bindings that give access to the BFD library. A binary file such as an object file, an executable or an archive is represented by the `Bfd.Files.File_Type` limited type. The symbol table is represented by the `Bfd.Symbols.Symbol_Table` limited type. These two types hold internal data used and managed by the BFD library.</p><p>```<a href="ada">ada</a> with Bfd.Files; with Bfd.Sections; with Bfd.Symbols; ...</p><pre><code> File : Bfd.Files.File_Type;
Symbols : Bfd.Symbols.Symbol_Table;
</code></pre><p>```</p><ol><li><ol><li>Opening the BFD file</li></ol></li></ol><p>The first step is to use the `Open` procedure to read the object or executable file whose path is given as argument. The `File_Type` parameter will be initialized to get access to the binary file information. The `Check_Format` function must then be called to let the BFD library gather the file format information and verify that it is an object file or an executable.</p><p>```<a href="ada">ada</a> Bfd.Files.Open (File, Path, ""); if Bfd.Files.Check_Format (File, Bfd.Files.OBJECT) then</p><pre><code> ...
</code></pre><p>end if; ```</p><p>The `File_Type` uses finalization so that it will close and reclaim resources automatically.</p><ol><li><ol><li>Loading the symbol table</li></ol></li></ol><p>The symbol table is loaded by using the `Read_Symbols` procedure.</p><p>```<a href="ada">ada</a></p><pre><code> Bfd.Symbols.Read_Symbols (File, Symbols);
</code></pre><p>```</p><p>The resources used by the symbol table will be freed when the symbol table instance is finalized.</p><ol><li><ol><li>Find nearest line</li></ol></li></ol><p>Once the symbol table is loaded, we can use the `Find_Nearest_Line` function to find the nearest line of a function knowing some address. This is almost a part of that function that the <a href="addr2line (1)">addr2line (1)</a>(https://www.man7.org/linux/man-pages/man1/addr2line.1.html) command is using.</p><p>```<a href="ada">ada</a> File_Name, Func_Name : Ada.Strings.Unbounded.Unbounded_String; Text_Section : Bfd.Sections.Section; Line : Natural; Pc : constant Bfd.Vma_Type := ...; ...</p><pre><code> Text_Section := Bfd.Sections.Find_Section (File, ".text");
Bfd.Symbols.Find_Nearest_Line (File => File,
Sec => Text_Section,
Symbols => Symbols,
Addr => Pc,
Name => File_Name,
Func => Func_Name,
Line => Line);
</code></pre><p>```</p><p>One tricky aspect of using `Find_Nearest_Line` is the fact that the address we are giving must **sometimes** be converted to an offset within the text region. With <a href="Address space layout randomization (ASLR)">Address space layout randomization (ASLR)</a>(https://en.wikipedia.org/wiki/Address_space_layout_randomization) a program is mapped at a random address when it executes. Before calling `Find_Nearest_Line`, we must subtract the base address of the memory region. We must now find the virtual address of the start of the text region that is mapped in memory. While the program is running, you can find the base address of the program by looking at the `/proc/self/maps` file. This special file indicates the list of memory regions used by the process with the addresses, flags and other information. Without ASLR, the program is almost always loaded at the `0x00400000` address.</p><p>``` 00400000-007f9000 r-xp 00000000 fd:01 12067645 /home/... 009f8000-009fa000 r--p 003f8000 fd:01 12067645 /home/... 009fa000-00a01000 rw-p 003fa000 fd:01 12067645 /home/... ```</p><p>But when it is mapped at a random address, we get a different address each time the program is launched:</p><p>``` 55d5983d9000-55d598592000 r--p 00000000 fc:02 1573554 /... 55d598592000-55d599376000 r-xp 001b9000 fc:02 1573554 /... 55d599376000-55d5997ed000 r--p 00f9d000 fc:02 1573554 /... 55d5997ee000-55d5998bb000 r--p 01414000 fc:02 1573554 /... 55d5998bb000-55d5998c6000 rw-p 014e1000 fc:02 1573554 /... ```</p><p>In that case, the value to use it the first address of first `r--p` region associated with the program (here `0x55d5983d9000`).</p><p>Another method to know the virtual base address is to use the <a href="dl_iterate_phdr (3)">dl_iterate_phdr (3)</a>(https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html) function and look at the shared objects which are loaded. This function must be executed by the program itself: it gets as parameter a callback function which is called for each loaded shared object and a data parameter that will be passed to the callback.</p><p>```</p><ol><li>include <dlfcn.h></li></ol><p>static int dl_callback (struct dl_phdr_info* info, size_t size, void* data) {</p><pre><code> /* VM base address is: info->dlpi_addr */
return 0;
</code></pre><p>} ...</p><pre><code> dl_iterate_phdr (dl_callback, 0);
</code></pre><p>```</p><p>When the callback is called, you can get the name of the shared object by looking at `info->dlpi_name` and the virtual base address by looking at `info->dlpi_addr`.</p><p><a href="Ada BFD">Ada BFD</a>(https://github.com/stcarrez/ada-bfd) is a very specific library that is not always easy to use due to the complexity of binary program representation (ELF, DWARF, ...) and program execution. It is however used in very specific contexts such as the <a href="Muen Separation Kernel">Muen Separation Kernel</a>(https://muen.codelabs.ch/) and the <a href="Memory Analysis Tool">Memory Analysis Tool</a>(https://github.com/stcarrez/mat).</p></div> New release Ada BFD 1.2.0urn:md5:49b106f1dd4b211d749df14de73863ab2021-04-11T18:37:21+00:002021-04-11T18:37:21+00:00Stephane CarrezbinutilsreleaseAdaELF
<div class="post-text"><p>The new release is a cleanup and update of the library to support newer version of GNU binutils. The main changes are below:</p><ul><li>Cleanup build process and use gprinstall for installation</li><li>Fix build with binutils > 2.34</li><li>Remove invalid API: `Bfd.Set_Error_Handler`</li><li>Remove fake API: `Bfd.Symbols.Is_Local_Label_Name`</li></ul><ol><li><ol><li>Installation</li></ol></li></ol><p>To use the Ada BFD library, you may either build it from the sources <a href="ada-bfd-1.2.0.tar.gz">ada-bfd-1.2.0.tar.gz</a>(https://download.vacs.fr/ada-bfd/ada-bfd-1.2.0.tar.gz) or install the Debian packages.</p><p>To build from the sources, you need to have a working GNAT Ada compiler as well as the `binutils-dev` Debian package installed. Then, run the following commands:</p><p>```sh git clone <a href="https://github.com/stcarrez/ada-bfd.git">https://github.com/stcarrez/ada-bfd.git</a> cd ada-bfd ./configure make build check install ```</p><p>For the Debian package installation, use the configuration that corresponds to your setup:</p><p>``` deb <a href="https://apt.vacs.fr/ubuntu-bionic">https://apt.vacs.fr/ubuntu-bionic</a> bionic main deb <a href="https://apt.vacs.fr/ubuntu-focal">https://apt.vacs.fr/ubuntu-focal</a> focal main deb <a href="https://apt.vacs.fr/debian-buster">https://apt.vacs.fr/debian-buster</a> buster main ```</p><p>and then run:</p><p>``` sudo apt-get update</p><ol><li>Bionic: sudo apt-get install libbfdada1-dev</li><li>Focal: sudo apt-get install libbfdada2-dev</li><li>Buster: sudo apt-get install libbfdada3-dev</li></ol><p>```</p><ol><li><ol><li>Reading the ELF sections</li></ol></li></ol><p>Using the Ada BFD library in a projet is quite easy, the first step is to add the following line in your GNAT project file:</p><p>``` <a href="Ada">Ada</a> with "bfdada"; ```</p><p>To access the information of a binary, you must first define an instance of the `File_Type` and open the file. You will do this as follows:</p><p>``` <a href="Ada">Ada</a> with Bfd.Files;</p><pre><code> ...
Path : constant String := "..."; -- the binary to load
File : Bfd.Files.File_Type;
...
Bfd.Files.Open (File, Path, "");
</code></pre><p>```</p><p>Looking at the ELF section is easily made by using the `Section_Iterator` provided by the `Bfd.Sections` package.</p><p>```ada with Bfd.Sections;</p><pre><code> ...
Iter : Bfd.Sections.Section_Iterator := Bfd.Sections.Get_Sections (File);
...
while Bfd.Sections.Has_Element (Iter) loop
declare
S : constant Bfd.Sections.Section := Bfd.Sections.Element (Iter);
begin
Ada.Text_IO.Put_Line (Bfd.Sections.Get_Name (S));
end;
Bfd.Sections.Next (Iter);
end loop;
</code></pre><p>```</p><p>The library contains several examples that show different features of the Ada BFD library:</p><p>| <a href="bfdinfo.adb">bfdinfo.adb</a>(https://github.com/stcarrez/ada-bfd/blob/master/samples/bfdinfo.adb) | ./bin/bfdinfo ./bin/bfdgen | Open BFD file, get flags, list sections and symbols | | <a href="sections.adb">sections.adb</a>(https://github.com/stcarrez/ada-bfd/blob/master/samples/sections.adb) | ./bin/sections ./bin/bfdgen | Display the ELF sections with the `Bfd.Sections` | | <a href="symbol.adb">symbol.adb</a>(https://github.com/stcarrez/ada-bfd/blob/master/samples/symbol.adb) | ./bin/symbol ./bin/bfdgen main | Read the symbol table with `Bfd.Symbols` | | <a href="disassemble.adb">disassemble.adb</a>(https://github.com/stcarrez/ada-bfd/blob/master/samples/disassemble.adb) | ./bin/disassemble ./bin/bfdgen | Disassemble the text section with `Bfd.Disassemble` |</p></div> Ada BFD 1.1.0 is availableurn:md5:db12f172ade35c17c3e28dc974c1fac62015-05-16T13:31:00+00:002015-05-16T13:31:00+00:00Stephane CarrezreleaseCOFFELFbinutils
<div class="post-text"><p>I've added the support to the GNU demangler so that it is now possible to demangle symbols. You can demangle C++, Java and Ada symbols. To use the demangler you need a BFD file which is a limited type.</p><pre><code class="lang-ada">with Bfd.Files;
with Bfd.Symbols;
...
File : Bfd.Files.File_Type;
</code></pre><p>The BFD file is opened as follows:</p><pre><code class="lang-ada"> Bfd.Files.Open (File, Path, "");
</code></pre><p>Then, you may convert any symbol name using the <code>Demangle</code> function:</p><pre><code class="lang-ada"> Name : String := Bfd.Symbols.Demangle (File, "bfd__symbols__get_name",
Constants.DMGL_GNAT);
</code></pre><p>Sources are now moved to GitHub: <a href="https://github.com/stcarrez/ada-bfd">https://github.com/stcarrez/ada-bfd</a></p><p>You can download the release at: <a href="http://download.vacs.fr/ada-bfd/ada-bfd-1.1.0.tar.gz">http://download.vacs.fr/ada-bfd/ada-bfd-1.1.0.tar.gz</a></p></div> Ada BFD 1.0.1 is availableurn:md5:f6fe870b3f286a5697e740034e27b4a72014-12-24T15:51:43+00:002014-12-24T15:51:43+00:00Stephane CarrezreleaseCOFFELFbinutils
<div class="post-text"><p>Ada BFD is an Ada binding for the <a href="http://www.gnu.org/software/binutils/">GNU Binutils BFD</a> library.</p><p>It allows to read binary ELF, COFF files by using the GNU BFD and allows your program to read ELF sections, get access to the symbol table and use the disassembler.</p><p>The new version fixes build and compilation issues with recent releases of GNU Binutils and it also provides support to build Debian packages.</p><p><a href="http://download.vacs.fr/ada-bfd/ada-bfd-1.0.1.tar.gz">http://download.vacs.fr/ada-bfd/ada-bfd-1.0.1.tar.gz</a></p></div> Ada BFD 1.0 is availableurn:md5:716e99fef391298a49b1b5e99431044d2012-11-11T09:33:35+00:002012-11-11T09:33:35+00:00Stephane CarrezCOFFELFbinutilsrelease
<div class="post-text"><p>Ada BFD is an Ada binding for the GNU Binutils BFD library.</p><p>It allows to read binary ELF, COFF files by using the GNU BFD. The Ada BFD library allows to:</p><ul><li> list and scan the ELF sections of an executable or object file,</li><li> get the content of the ELF sections,</li><li> get access to the symbol table,</li><li> use the BFD disassembler</li></ul><p>Version 1.0 of this Ada binding library is now available on <a href="http://code.google.com/p/ada-bfd/">Ada BFD</a>. This new release bring the following changes:</p><ul><li>Fixed installation of library</li><li>Added examples for BfdAda</li><li>Add support to use the disassembler</li></ul></div> Reading a program symbol table with Ada BFDurn:md5:b3252b8f4bdaffabc698a9fdf276fa152012-11-11T09:26:00+00:002012-11-11T09:26:00+00:00Stephane CarrezCOFFELFTutorialbinutils
<div class="post-text"><p>The <a href="http://www.gnu.org/software/binutils/">GNU Binutils</a> provides support for reading and writing program files in various formats such as <a href="http://en.wikipedia.org/wiki/Executable_and_Linkable_Format">ELF</a>, <a href="http://en.wikipedia.org/wiki/COFF">COFF</a>. This support is known as the <b>BFD</b>, the Binary File Descriptor library (or the Big F*cking Deal). This article illustrates how an Ada application can use the BFD library to have access to a program symbol table.</p><h2>Declarations</h2><p>The <a href="https://github.com/stcarrez/ada-bfd">Ada BFD</a> library provides a set of Ada bindings that give access to the BFD library. A binary file such as an object file, an executable or an archive is represented by the <code>Bfd.Files.File_Type</code> limited type. The symbol table is represented by the <code>Bfd.Symbols.Symbol_Table</code> limited type. These two types hold internal data used and managed by the BFD library.</p><pre><code class="lang-ada">with Bfd.Files;
with Bfd.Sections;
with Bfd.Symbols;
...
File : Bfd.Files.File_Type;
Symbols : Bfd.Symbols.Symbol_Table;
</code></pre><h2>Opening the BFD file</h2><p>The <code>Open</code> procedure must be called to read the object or executable file whose path is given as argument. The <code>File_Type</code> parameter will be initialized to get access to the binary file information. The <code>Check_Format</code> function must then be called to let the BFD library gather the file format information and verify that it is an object file or an executable.</p><pre><code class="lang-ada">Bfd.Files.Open (File, Path, "");
if Bfd.Files.Check_Format (File, Bfd.Files.OBJECT) then
...
end if;
</code></pre><h2>Loading the symbol table</h2><p>The symbol table is loaded by using the <code>Read_Symbols</code> procedure.</p><pre><code class="lang-ada"> Bfd.Symbols.Read_Symbols (File, Symbols);
</code></pre><p>The resources used by the symbol table will be freed when the symbol table instance is finalized.</p><h2>Looking for a symbol</h2><p>Once the symbol table is loaded, we can use the <code>Get_Symbol</code> function to find a symbol knowing its name. If the symbol is not found, a <code>Null_Symbol</code> is returned.</p><pre><code class="lang-ada">Sym : Bfd.Symbols.Symbol := Bfd.Symbols.Get_Symbol (Symbols, "_main");
...
if Sym /= Bfd.Symbols.Null_Symbol then
-- Symbol found
end if;
</code></pre><p>Each symbol has the following set of information:</p><ul><li>A name (it may not be unique),</li><li>A set of flags that describe the symbol (global, local, weak, constructor, TLS, ...),</li><li>A symbol value,</li><li>A section to which the symbol belongs.</li></ul><pre><code class="lang-ada">Sec : constant Bfd.Sections.Section := Bfd.Symbols.Get_Section (Sym);
Flags : constant Bfd.Symbol_Flags := Bfd.Symbols.Get_Flags (Sym);
Value : constant Bfd.Symbol_Value := Bfd.Symbols.Get_Value (Sym);
</code></pre><p>Before interpreting and using the symbol value returned by <code>Get_Value</code>, you must look at the section to check for an undefined symbol. Indeed, undefined symbols being not yet resolved by the linker they have no value and no section. You can check that by using the <code>Is_Undefined_Section</code> function:</p><pre><code class="lang-ada">if Bfd.Sections.Is_Undefined_Section (Sec) then
Ada.Text_IO.Put_Line ("undefined symbol");
end if;
</code></pre><p>When the symbol is defined, you must look at the flags and also the section information to know more about it.</p><pre><code class="lang-ada">if (Flags and Bfd.Symbols.BSF_GLOBAL) /= 0 then
Ada.Text_IO.Put_Line ("global symbol in section "
& Bfd.Sections.Get_Name (Sec)
& " := " & Bfd.Symbol_Value'Image (Value));
elsif (Flags and Bfd.Symbols.BSF_LOCAL) /= 0 then
Ada.Text_IO.Put_Line ("local symbol in section "
& Bfd.Sections.Get_Name (Sec)
& " := " & Bfd.Symbol_Value'Image (Value));
else
Ada.Text_IO.Put_Line ("other symbol in section "
& Bfd.Sections.Get_Name (Sec)
& " := " & Bfd.Symbol_Value'Image (Value));
end if;
</code></pre><h2>Conclusion and references</h2><p>Reading an executable symbol table has been made fairly simple with the use of the <a href="https://github.com/stcarrez/ada-bfd">Ada BFD</a> library. Furthermore, the library allows to scan the sections, read their content and even use the BFD disassembler.</p><p><a href="https://github.com/stcarrez/ada-bfd/blob/master/samples/symbol.adb">symbol.adb</a><br><a href="http://sourceware.org/binutils/docs/bfd/index.html">BFD Documentation</a></p></div>