aboutsummaryrefslogtreecommitdiffstats
path: root/src/ortho/mcode/coffdump.adb
blob: 6384b6c276cc9d7f7770a9dca306b1e2435e2994 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
--  COFF dumper.
--  Copyright (C) 2006 Tristan Gingold
--
--  GHDL is free software; you can 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, or (at your option) any later
--  version.
--
--  GHDL is distributed in the hope that it will be useful, but WITHOUT ANY
--  WARRANTY; without even the implied warranty of MERCHANTABILITY or
--  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
--  for more details.
--
--  You should have received a copy of the GNU General Public License
--  along with GCC; see the file COPYING.  If not, write to the Free
--  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
--  02111-1307, USA.
with Coff; use Coff;
with Interfaces; use Interfaces;
with System;
with Ada.Unchecked_Conversion;
with Ada.Command_Line; use Ada.Command_Line;
with GNAT.OS_Lib; use GNAT.OS_Lib;
with Ada.Text_IO; use Ada.Text_IO;
with Hex_Images; use Hex_Images;

procedure Coffdump is
   type Cstring is array (Unsigned_32 range <>) of Character;
   type Cstring_Acc is access Cstring;
   type Section_Array is array (Unsigned_16 range <>) of Scnhdr;
   type Section_Array_Acc is access Section_Array;
   --  Array of sections.
   Sections : Section_Array_Acc;

   type External_Symbol is array (0 .. Symesz - 1) of Character;
   type External_Symbol_Array is array (Unsigned_32 range <>)
     of External_Symbol;
   type Symbol_Array_Acc is access External_Symbol_Array;
   --  Symbols table.
   External_Symbols : Symbol_Array_Acc;

   --  String table.
   Str : Cstring_Acc;
   Str_Size : Natural;

   Hdr : Filehdr;
   --Sym : Syment;
   Fd : File_Descriptor;
   Skip : Natural;
   Skip_Kind : Unsigned_8;
   Aux_File : Auxent_File;
   Aux_Scn : Auxent_Scn;
   Rel : Reloc;
   Len : Natural;

   Nul : constant Character := Character'Val (0);

   function Find_Nul (S : String) return String is
   begin
      for I in S'Range loop
         if S (I) = Nul then
            return S (S'First .. I - 1);
         end if;
      end loop;
      return S;
   end Find_Nul;

   function Get_String (N : Strent_Type; S : String) return String
   is
   begin
      if N.E_Zeroes /= 0 then
         return Find_Nul (S);
      else
         for I in N.E_Offset .. Str'Last loop
            if Str (I) = Nul then
               return String (Str (N.E_Offset .. I - 1));
            end if;
         end loop;
         raise Program_Error;
      end if;
   end Get_String;

   procedure Memcpy
     (Dst : System.Address; Src : System.Address; Size : Natural);
   pragma Import (C, Memcpy);

   function Get_Section_Name (N : Unsigned_16) return String is
   begin
      if N = N_UNDEF then
         return "UNDEF";
      elsif N = N_ABS then
         return "ABS";
      elsif N = N_DEBUG then
         return "DEBUG";
      elsif N > Hdr.F_Nscns then
         return "???";
      else
         return Find_Nul (Sections (N).S_Name);
      end if;
   end Get_Section_Name;

   function Get_Symbol (N : Unsigned_32) return Syment is
      function Unchecked_Conv is new Ada.Unchecked_Conversion
        (Source => External_Symbol, Target => Syment);
   begin
      if N > Hdr.F_Nsyms then
         raise Constraint_Error;
      end if;
      return Unchecked_Conv (External_Symbols (N));
   end Get_Symbol;

   function Get_Symbol_Name (N : Unsigned_32) return String
   is
      S : Syment := Get_Symbol (N);
   begin
      return Get_String (S.E.E, S.E.E_Name);
   end Get_Symbol_Name;
begin
   for I in 1 .. Argument_Count loop
      Fd := Open_Read (Argument (I), Binary);
      if Fd = Invalid_FD then
         Put_Line ("cannot open " & Argument (I));
         return;
      end if;
      --  Read file header.
      if Read (Fd, Hdr'Address, Filehdr_Size) /= Filehdr_Size then
         Put_Line ("cannot read header");
         return;
      end if;
      Put_Line ("File: " & Argument (I));
      Put_Line ("magic:               " & Hex_Image (Hdr.F_Magic));
      Put_Line ("number of sections:  " & Hex_Image (Hdr.F_Nscns));
      Put_Line ("time and date stamp: " & Hex_Image (Hdr.F_Timdat));
      Put_Line ("symtab file pointer: " & Hex_Image (Hdr.F_Symptr));
      Put_Line ("nbr symtab entries:  " & Hex_Image (Hdr.F_Nsyms));
      Put_Line ("opt header size:     " & Hex_Image (Hdr.F_Opthdr));
      Put_Line ("flags:               " & Hex_Image (Hdr.F_Flags));

      --  Read sections header.
      Lseek (Fd, Long_Integer (Hdr.F_Opthdr), Seek_Cur);
      Sections := new Section_Array (1 .. Hdr.F_Nscns);
      Len := Scnhdr_Size * Natural (Hdr.F_Nscns);
      if Read (Fd, Sections (1)'Address, Len) /= Len then
         Put_Line ("cannot read section header");
         return;
      end if;
      for I in 1 .. Hdr.F_Nscns loop
         declare
            S: Scnhdr renames Sections (I);
         begin
            Put_Line ("Section " & Find_Nul (S.S_Name));
            Put_Line ("Physical address :     " & Hex_Image (S.S_Paddr));
            Put_Line ("Virtual address :      " & Hex_Image (S.S_Vaddr));
            Put_Line ("section size :         " & Hex_Image (S.S_Size));
            Put_Line ("section pointer :      " & Hex_Image (S.S_Scnptr));
            Put_Line ("relocation pointer :   " & Hex_Image (S.S_Relptr));
            Put_Line ("line num pointer :     " & Hex_Image (S.S_Lnnoptr));
            Put_Line ("Nbr reloc entries :    " & Hex_Image (S.S_Nreloc));
            Put_Line ("Nbr line num entries : " & Hex_Image (S.S_Nlnno));
            Put_Line ("Flags :                " & Hex_Image (S.S_Flags));
         end;
      end loop;

      --  Read string table.
      Lseek (Fd,
             Long_Integer (Hdr.F_Symptr + Hdr.F_Nsyms * Unsigned_32 (Symesz)),
             Seek_Set);
      if Read (Fd, Str_Size'Address, 4) /= 4 then
         Put_Line ("cannot read string table size");
         return;
      end if;
      Str := new Cstring (0 .. Unsigned_32 (Str_Size));
      if Read (Fd, Str (4)'Address, Str_Size - 4) /= Str_Size - 4 then
         Put_Line ("cannot read string table");
         return;
      end if;

      --  Read symbol table.
      Lseek (Fd, Long_Integer (Hdr.F_Symptr), Seek_Set);
      External_Symbols := new External_Symbol_Array (0 .. Hdr.F_Nsyms - 1);
      Len := Natural (Hdr.F_Nsyms) * Symesz;
      if Read (Fd, External_Symbols (0)'Address, Len) /= Len then
            Put_Line ("cannot read symbol");
            return;
         end if;

      Skip := 0;
      Skip_Kind := C_NULL;
      for I in External_Symbols'range loop
         if Skip > 0 then
            case Skip_Kind is
               when C_FILE =>
                  Memcpy (Aux_File'Address, External_Symbols (I)'Address,
                          Aux_File'Size / 8);
                  Put_Line ("aux file : " & Get_String (Aux_File.X_N,
                                                        Aux_File.X_Fname));
                  Skip_Kind := C_NULL;
               when C_STAT =>
                  Memcpy (Aux_Scn'Address, External_Symbols (I)'Address,
                          Aux_Scn'Size / 8);
                  Put_Line ("section len:   " & Hex_Image (Aux_Scn.X_Scnlen));
                  Put_Line ("nbr reloc ent: " & Hex_Image (Aux_Scn.X_Nreloc));
                  Put_Line ("nbr line num:  " & Hex_Image (Aux_Scn.X_Nlinno));
               when others =>
                  Put_Line ("skip");
            end case;
            Skip := Skip - 1;
         else
            declare
               S : Syment := Get_Symbol (I);
            begin
               Put_Line ("Symbol #" & Hex_Image (I));
               Put_Line ("symbol name : " & Get_Symbol_Name (I));
               Put_Line ("symbol value: " & Hex_Image (S.E_Value));
               Put_Line ("section num : " & Hex_Image (S.E_Scnum)
                         & "  " & Get_Section_Name (S.E_Scnum));
               Put_Line ("type        : " & Hex_Image (S.E_Type));
               Put      ("sclass      : " & Hex_Image (S.E_Sclass));
               if Sclass_Desc (S.E_Sclass).Name /= null then
                  Put ("  (");
                  Put (Sclass_Desc (S.E_Sclass).Name.all);
                  Put (" - ");
                  Put (Sclass_Desc (S.E_Sclass).Meaning.all);
                  Put (")");
               end if;
               New_Line;
               Put_Line ("numaux      : " & Hex_Image (S.E_Numaux));
               if S.E_Numaux > 0 then
                  case S.E_Sclass is
                     when C_FILE =>
                        Skip_Kind := C_FILE;
                     when C_STAT =>
                        Skip_Kind := C_STAT;
                     when others =>
                        Skip_Kind := C_NULL;
                  end case;
               end if;
               Skip := Natural (S.E_Numaux);
            end;
         end if;
      end loop;

      --  Disp relocs.
      for I in 1 .. Hdr.F_Nscns loop
         if Sections (I).S_Nreloc > 0 then
            --  Read relocations.
            Put_Line ("Relocations for section " & Get_Section_Name (I));
            Lseek (Fd, Long_Integer (Sections (I).S_Relptr), Seek_Set);
            for J in 1 .. Sections (I).S_Nreloc loop
               if Read (Fd, Rel'Address, Relsz) /= Relsz then
                  Put_Line ("cannot read reloc");
                  return;
               end if;
               Put_Line ("reloc virtual addr: " & Hex_Image (Rel.R_Vaddr));
               Put_Line ("symbol index      : " & Hex_Image (Rel.R_Symndx)
                         & "  " & Get_Symbol_Name (Rel.R_Symndx));
               Put ("type of relocation: " & Hex_Image (Rel.R_Type));
               case Rel.R_Type is
                  when Reloc_Rel32 =>
                     Put (" RELOC_REL32");
                  when Reloc_Addr32 =>
                     Put (" RELOC_ADDR32");
                  when others =>
                     null;
               end case;
               New_Line;
            end loop;
         end if;
      end loop;

      Close (Fd);
   end loop;
end Coffdump;