Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-export-metadata.h"
20 : #include "rust-hir-visitor.h"
21 : #include "rust-hir-full.h"
22 : #include "rust-hir-map.h"
23 : #include "rust-ast-dump.h"
24 : #include "rust-abi.h"
25 : #include "rust-item.h"
26 : #include "rust-macro.h"
27 : #include "rust-object-export.h"
28 :
29 : #include "md5.h"
30 : #include "rust-system.h"
31 :
32 : namespace Rust {
33 : namespace Metadata {
34 :
35 : static const std::string extension_path = ".rox";
36 :
37 4420 : ExportContext::ExportContext () : mappings (Analysis::Mappings::get ()) {}
38 :
39 4420 : ExportContext::~ExportContext () {}
40 :
41 : void
42 4420 : ExportContext::emit_crate (AST::Crate &c)
43 : {
44 4420 : std::stringstream oss;
45 4420 : using AST::Dump;
46 4420 : AST::Dump dumper (
47 : oss,
48 : Dump::Configuration{Dump::Configuration::InternalComment::Hide,
49 : Dump::Configuration::NodeDescription::Hide,
50 : Dump::Configuration::Comment::Hide,
51 : Dump::Configuration::Newline::Hide,
52 : Dump::Configuration::Indentation::None},
53 4420 : {});
54 4420 : dumper.process (c);
55 :
56 8840 : public_interface_buffer += oss.str ();
57 4420 : }
58 : void
59 3 : ExportContext::emit_macro (AST::MacroRulesDefinition ¯o)
60 : {
61 3 : std::stringstream oss;
62 3 : AST::Dump dumper (oss);
63 :
64 3 : dumper.go (macro);
65 :
66 6 : public_interface_buffer += oss.str ();
67 3 : }
68 :
69 : const std::string &
70 4420 : ExportContext::get_interface_buffer () const
71 : {
72 4420 : return public_interface_buffer;
73 : }
74 :
75 4420 : PublicInterface::PublicInterface (HIR::Crate &crate)
76 4420 : : crate (crate), mappings (Analysis::Mappings::get ()), context ()
77 4420 : {}
78 :
79 : void
80 0 : PublicInterface::Export (HIR::Crate &crate)
81 : {
82 0 : PublicInterface interface (crate);
83 0 : interface.gather_export_data ();
84 0 : interface.write_to_object_file ();
85 0 : }
86 :
87 : void
88 4420 : PublicInterface::ExportTo (HIR::Crate &crate, const std::string &output_path)
89 : {
90 4420 : PublicInterface interface (crate);
91 4420 : interface.gather_export_data ();
92 4420 : interface.write_to_path (output_path);
93 4420 : }
94 :
95 : void
96 4420 : PublicInterface::gather_export_data ()
97 : {
98 4420 : auto crate_num
99 4420 : = mappings.crate.lookup_crate_num (crate.get_mappings ().get_nodeid ());
100 4420 : auto &ast_crate = mappings.crate.get_ast_crate (crate_num.value ());
101 4420 : context.emit_crate (ast_crate);
102 :
103 4423 : for (auto ¯o : mappings.get_exported_macros ())
104 4423 : context.emit_macro (macro);
105 4420 : }
106 :
107 : void
108 0 : PublicInterface::write_to_object_file () const
109 : {
110 : // done
111 0 : const auto &buf = context.get_interface_buffer ();
112 0 : std::string size_buffer = std::to_string (buf.size ());
113 :
114 : // md5 this
115 0 : struct md5_ctx chksm;
116 0 : unsigned char checksum[16];
117 :
118 0 : md5_init_ctx (&chksm);
119 0 : md5_process_bytes (buf.c_str (), buf.size (), &chksm);
120 0 : md5_finish_ctx (&chksm, checksum);
121 :
122 : // MAGIC MD5 DLIM DLIM buffer-size DELIM contents
123 0 : const std::string current_crate_name
124 0 : = mappings.crate.get_current_crate_name ();
125 :
126 : // extern void
127 0 : rust_write_export_data (kMagicHeader, sizeof (kMagicHeader));
128 0 : rust_write_export_data ((const char *) checksum, sizeof (checksum));
129 0 : rust_write_export_data (kSzDelim, sizeof (kSzDelim));
130 0 : rust_write_export_data (current_crate_name.c_str (),
131 0 : current_crate_name.size ());
132 0 : rust_write_export_data (kSzDelim, sizeof (kSzDelim));
133 0 : rust_write_export_data (size_buffer.c_str (), size_buffer.size ());
134 0 : rust_write_export_data (kSzDelim, sizeof (kSzDelim));
135 0 : rust_write_export_data (buf.c_str (), buf.size ());
136 0 : }
137 :
138 : void
139 4420 : PublicInterface::write_to_path (const std::string &path) const
140 : {
141 : // validate path contains correct extension
142 4420 : const std::string expected_file_name = expected_metadata_filename ();
143 4420 : const char *path_base_name = lbasename (path.c_str ());
144 4420 : if (strcmp (path_base_name, expected_file_name.c_str ()) != 0)
145 : {
146 0 : rust_error_at (UNDEF_LOCATION,
147 : "expected metadata-output path to have base file name of: "
148 : "%qs got %qs",
149 : expected_file_name.c_str (), path_base_name);
150 0 : return;
151 : }
152 :
153 : // done
154 4420 : const auto &buf = context.get_interface_buffer ();
155 4420 : std::string size_buffer = std::to_string (buf.size ());
156 :
157 : // md5 this
158 4420 : struct md5_ctx chksm;
159 4420 : unsigned char checksum[16];
160 :
161 4420 : md5_init_ctx (&chksm);
162 4420 : md5_process_bytes (buf.c_str (), buf.size (), &chksm);
163 4420 : md5_finish_ctx (&chksm, checksum);
164 :
165 : // MAGIC MD5 DLIM DLIM buffer-size DELIM contents
166 4420 : const std::string current_crate_name
167 4420 : = mappings.crate.get_current_crate_name ();
168 :
169 : // write to path
170 4420 : FILE *nfd = fopen (path.c_str (), "wb");
171 4420 : if (nfd == NULL)
172 : {
173 0 : rust_error_at (UNDEF_LOCATION, "failed to open file %qs for writing: %s",
174 0 : path.c_str (), xstrerror (errno));
175 0 : return;
176 : }
177 :
178 : // write data
179 4420 : if (fwrite (kMagicHeader, sizeof (kMagicHeader), 1, nfd) < 1)
180 : {
181 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
182 0 : path.c_str (), xstrerror (errno));
183 0 : fclose (nfd);
184 0 : return;
185 : }
186 :
187 4420 : if (fwrite (checksum, sizeof (checksum), 1, nfd) < 1)
188 : {
189 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
190 0 : path.c_str (), xstrerror (errno));
191 0 : fclose (nfd);
192 0 : return;
193 : }
194 :
195 4420 : if (fwrite (kSzDelim, sizeof (kSzDelim), 1, nfd) < 1)
196 : {
197 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
198 0 : path.c_str (), xstrerror (errno));
199 0 : fclose (nfd);
200 0 : return;
201 : }
202 :
203 4420 : if (fwrite (current_crate_name.c_str (), current_crate_name.size (), 1, nfd)
204 : < 1)
205 : {
206 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
207 0 : path.c_str (), xstrerror (errno));
208 0 : fclose (nfd);
209 0 : return;
210 : }
211 :
212 4420 : if (fwrite (kSzDelim, sizeof (kSzDelim), 1, nfd) < 1)
213 : {
214 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
215 0 : path.c_str (), xstrerror (errno));
216 0 : fclose (nfd);
217 0 : return;
218 : }
219 :
220 4420 : if (fwrite (size_buffer.c_str (), size_buffer.size (), 1, nfd) < 1)
221 : {
222 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
223 0 : path.c_str (), xstrerror (errno));
224 0 : fclose (nfd);
225 0 : return;
226 : }
227 :
228 4420 : if (fwrite (kSzDelim, sizeof (kSzDelim), 1, nfd) < 1)
229 : {
230 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
231 0 : path.c_str (), xstrerror (errno));
232 0 : fclose (nfd);
233 0 : return;
234 : }
235 :
236 4420 : if (!buf.empty ())
237 4420 : if (fwrite (buf.c_str (), buf.size (), 1, nfd) < 1)
238 : {
239 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
240 0 : path.c_str (), xstrerror (errno));
241 0 : fclose (nfd);
242 0 : return;
243 : }
244 :
245 : // done
246 4420 : fclose (nfd);
247 4420 : }
248 :
249 : bool
250 0 : PublicInterface::is_crate_public (const HIR::VisItem &item)
251 : {
252 0 : const HIR::Visibility &visibility = item.get_visibility ();
253 :
254 0 : bool is_public
255 0 : = visibility.get_vis_type () == HIR::Visibility::VisType::Public;
256 0 : bool has_path = !visibility.get_path ().is_error ();
257 :
258 : // FIXME this might be pub(crate)
259 : // Arthur magic required here
260 :
261 0 : return is_public && !has_path;
262 : }
263 :
264 : std::string
265 8840 : PublicInterface::expected_metadata_filename ()
266 : {
267 8840 : auto &mappings = Analysis::Mappings::get ();
268 :
269 8840 : const std::string current_crate_name
270 8840 : = mappings.crate.get_current_crate_name ();
271 8840 : return current_crate_name + extension_path;
272 8840 : }
273 :
274 : } // namespace Metadata
275 : } // namespace Rust
|