Add autoconf checks for platforms without IPv6
[mono.git] / mcs / tools / cil-strip / AssemblyStripper.cs
1 //
2 // AssemblyStripper.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@novell.com)
6 //
7 // (C) 2008 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System.Collections;
30 using System.IO;
31
32 using Mono.Cecil;
33 using Mono.Cecil.Binary;
34 using Mono.Cecil.Cil;
35 using Mono.Cecil.Metadata;
36
37 namespace Mono.CilStripper {
38
39         class AssemblyStripper {
40
41                 AssemblyDefinition assembly;
42                 BinaryWriter writer;
43
44                 Image original;
45                 Image stripped;
46
47                 ReflectionWriter reflection_writer;
48                 MetadataWriter metadata_writer;
49
50                 TablesHeap original_tables;
51                 TablesHeap stripped_tables;
52
53                 AssemblyStripper (AssemblyDefinition assembly, BinaryWriter writer)
54                 {
55                         this.assembly = assembly;
56                         this.writer = writer;
57                 }
58
59                 void Strip ()
60                 {
61                         FullLoad ();
62                         ClearMethodBodies ();
63                         CopyOriginalImage ();
64                         PatchMethods ();
65                         PatchFields ();
66                         PatchResources ();
67                         Write ();
68                 }
69
70                 void FullLoad ()
71                 {
72                         assembly.MainModule.FullLoad ();
73                 }
74
75                 void ClearMethodBodies ()
76                 {
77                         foreach (TypeDefinition type in assembly.MainModule.Types) {
78                                 ClearMethodBodies (type.Constructors);
79                                 ClearMethodBodies (type.Methods);
80                         }
81                 }
82
83                 static void ClearMethodBodies (ICollection methods)
84                 {
85                         foreach (MethodDefinition method in methods) {
86                                 if (!method.HasBody)
87                                         continue;
88
89                                 MethodBody body = new MethodBody (method);
90                                 body.CilWorker.Emit (OpCodes.Ret);
91
92                                 method.Body = body;
93                         }
94                 }
95
96                 void CopyOriginalImage ()
97                 {
98                         original = assembly.MainModule.Image;
99                         stripped = Image.CreateImage();
100
101                         stripped.Accept (new CopyImageVisitor (original));
102
103                         assembly.MainModule.Image = stripped;
104
105                         original_tables = original.MetadataRoot.Streams.TablesHeap;
106                         stripped_tables = stripped.MetadataRoot.Streams.TablesHeap;
107
108                         TableCollection tables = original_tables.Tables;
109                         foreach (IMetadataTable table in tables)
110                                 stripped_tables.Tables.Add(table);
111
112                         stripped_tables.Valid = original_tables.Valid;
113                         stripped_tables.Sorted = original_tables.Sorted;
114
115                         reflection_writer = new ReflectionWriter (assembly.MainModule);
116                         reflection_writer.StructureWriter = new StructureWriter (assembly, writer);
117                         reflection_writer.CodeWriter.Stripped = true;
118
119                         metadata_writer = reflection_writer.MetadataWriter;
120
121                         PatchHeap (metadata_writer.StringWriter, original.MetadataRoot.Streams.StringsHeap);
122                         PatchHeap (metadata_writer.GuidWriter, original.MetadataRoot.Streams.GuidHeap);
123                         PatchHeap (metadata_writer.UserStringWriter, original.MetadataRoot.Streams.UserStringsHeap);
124                         PatchHeap (metadata_writer.BlobWriter, original.MetadataRoot.Streams.BlobHeap);
125
126                         if (assembly.EntryPoint != null)
127                                 metadata_writer.EntryPointToken = assembly.EntryPoint.MetadataToken.ToUInt ();
128                 }
129
130                 static void PatchHeap (MemoryBinaryWriter heap_writer, MetadataHeap heap)
131                 {
132                         if (heap == null)
133                                 return;
134
135                         heap_writer.BaseStream.Position = 0;
136                         heap_writer.Write (heap.Data);
137                 }
138
139                 void PatchMethods ()
140                 {
141                         MethodTable methodTable = (MethodTable) stripped_tables [MethodTable.RId];
142                         if (methodTable == null)
143                                 return;
144
145                         RVA method_rva = RVA.Zero;
146
147                         for (int i = 0; i < methodTable.Rows.Count; i++) {
148                                 MethodRow methodRow = methodTable[i];
149
150                                 MetadataToken methodToken = MetadataToken.FromMetadataRow (TokenType.Method, i);
151
152                                 MethodDefinition method = (MethodDefinition) assembly.MainModule.LookupByToken (methodToken);
153
154                                 if (method.HasBody) {
155                                         method_rva = method_rva != RVA.Zero
156                                                 ? method_rva
157                                                 : reflection_writer.CodeWriter.WriteMethodBody (method);
158
159                                         methodRow.RVA = method_rva;
160                                 } else
161                                         methodRow.RVA = RVA.Zero;
162                         }
163                 }
164
165                 void PatchFields ()
166                 {
167                         FieldRVATable fieldRvaTable = (FieldRVATable) stripped_tables [FieldRVATable.RId];
168                         if (fieldRvaTable == null)
169                                 return;
170
171                         for (int i = 0; i < fieldRvaTable.Rows.Count; i++) {
172                                 FieldRVARow fieldRvaRow = fieldRvaTable [i];
173
174                                 MetadataToken fieldToken = new MetadataToken (TokenType.Field, fieldRvaRow.Field);
175
176                                 FieldDefinition field = (FieldDefinition) assembly.MainModule.LookupByToken (fieldToken);
177
178                                 fieldRvaRow.RVA = metadata_writer.GetDataCursor ();
179                                 metadata_writer.AddData (field.InitialValue.Length + 3 & (~3));
180                                 metadata_writer.AddFieldInitData (field.InitialValue);
181                         }
182                 }
183
184                 void PatchResources ()
185                 {
186                         ManifestResourceTable resourceTable = (ManifestResourceTable) stripped_tables [ManifestResourceTable.RId];
187                         if (resourceTable == null)
188                                 return;
189
190                         for (int i = 0; i < resourceTable.Rows.Count; i++) {
191                                 ManifestResourceRow resourceRow = resourceTable [i];
192
193                                 if (resourceRow.Implementation.RID != 0)
194                                         continue;
195
196                                 foreach (Resource resource in assembly.MainModule.Resources) {
197                                         EmbeddedResource er = resource as EmbeddedResource;
198                                         if (er == null)
199                                                 continue;
200
201                                         if (resource.Name != original.MetadataRoot.Streams.StringsHeap [resourceRow.Name])
202                                                 continue;
203
204                                         resourceRow.Offset = metadata_writer.AddResource (er.Data);
205                                 }
206                         }
207                 }
208
209                 void Write ()
210                 {
211                         stripped.MetadataRoot.Accept (metadata_writer);
212                 }
213
214                 public static void StripAssembly (AssemblyDefinition assembly, string file)
215                 {
216                         using (FileStream fs = new FileStream (file, FileMode.Create, FileAccess.Write, FileShare.None)) {
217                                 new AssemblyStripper (assembly, new BinaryWriter (fs)).Strip ();
218                         }
219                 }
220         }
221 }