BDE 4.39.x Production Release
Loading...
Searching...
No Matches
balst_resolver_filehelper.h
Go to the documentation of this file.
1/// @file balst_resolver_filehelper.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balst_resolver_filehelper.h -*-C++-*-
8#ifndef INCLUDED_BALST_RESOLVER_FILEHELPER
9#define INCLUDED_BALST_RESOLVER_FILEHELPER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balst_resolver_filehelper balst_resolver_filehelper
15/// @brief Provide platform-independent file input for stack trace resolvers.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balst
19/// @{
20/// @addtogroup balst_resolver_filehelper
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balst_resolver_filehelper-purpose"> Purpose</a>
25/// * <a href="#balst_resolver_filehelper-classes"> Classes </a>
26/// * <a href="#balst_resolver_filehelper-description"> Description </a>
27/// * <a href="#balst_resolver_filehelper-usage"> Usage </a>
28/// * <a href="#balst_resolver_filehelper-example-1-basic-usage"> Example 1: Basic Usage </a>
29///
30/// # Purpose {#balst_resolver_filehelper-purpose}
31/// Provide platform-independent file input for stack trace resolvers.
32///
33/// # Classes {#balst_resolver_filehelper-classes}
34///
35/// - balst::Resolver_FileHelper: file input for stack trace resolvers
36///
37/// @see balst_resolverimpl_elf
38///
39/// # Description {#balst_resolver_filehelper-description}
40/// The one class in this component opens a file in readonly mode
41/// and then owns the file descriptor, and provides 3 utility functions for
42/// reading from the file: `readBytes`, which attempts to read a number of bytes
43/// into a buffer, and does a partial read if it can't read that many;
44/// `readExact`, which either reads an exact number of bytes or fails, and
45/// `loadString`, which reads a 0 terminated string from the file, copies it to
46/// a buffer it allocates, and returns a pointer to the copy.
47///
48/// ## Usage {#balst_resolver_filehelper-usage}
49///
50///
51/// This section illustrates intended use of this component.
52///
53/// ### Example 1: Basic Usage {#balst_resolver_filehelper-example-1-basic-usage}
54///
55///
56/// First, we prepare the file to be used by this usage example:
57/// @code
58/// bslma::TestAllocator ta;
59///
60/// char fileNameBuffer[100];
61/// sprintf(fileNameBuffer,
62/// "/tmp/balst_Resolver_FileHelper.usage.%d.txt",
63/// getProcessId());
64/// @endcode
65/// Make sure file does not already exist.
66/// @code
67/// bdls::FilesystemUtil::remove(fileNameBuffer);
68/// @endcode
69/// Next, Create the file and open a file descriptor to it. The boolean
70/// flags indicate that the file is writable, and not previously existing
71/// (and therefore must be created).
72/// @code
73/// FdType fd = FilesystemUtil::open(
74/// fileNameBuffer,
75/// FilesystemUtil::e_OPEN_OR_CREATE, // doesn't already exist
76/// FilesystemUtil::e_READ_WRITE); // writable
77/// assert(FilesystemUtil::k_INVALID_FD != fd);
78/// @endcode
79/// 64 char long string
80/// @code
81/// const char *testString64 =
82/// "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
83/// "0123456789+-";
84/// @endcode
85/// Populate the file with known data, with a zero byte at a known offset.
86/// @code
87/// int rc;
88/// for (int i = 0; i < 20; ++i) {
89/// rc = FilesystemUtil::write(fd, testString64, 64);
90/// assert(64 == rc);
91/// }
92///
93/// enum { OFFSET_OF_ZERO_BYTE = 7 * 64 };
94///
95/// rc = (int) FilesystemUtil::seek(fd,
96/// OFFSET_OF_ZERO_BYTE,
97/// FilesystemUtil::e_SEEK_FROM_BEGINNING);
98/// assert(OFFSET_OF_ZERO_BYTE == rc);
99///
100/// rc = FilesystemUtil::write(fd, "", 1); // write the zero byte
101/// assert(1 == rc);
102///
103/// rc = FilesystemUtil::close(fd);
104/// assert(0 == rc);
105///
106/// {
107/// balst::Resolver_FileHelper helper;
108/// rc = helper.openFile(fileNameBuffer);
109/// assert(0 == rc);
110///
111/// char buf[100]; Span bufSpan(buf);
112/// memset(buf, 0, sizeof(buf));
113/// rc = helper.readExact(Span(buf, 6),
114/// 128); // offset
115/// assert(0 == rc);
116/// assert(!strcmp(buf, "abcdef"));
117/// @endcode
118/// `readExact` past EOF fails
119/// @code
120/// rc = helper.readExact(Span(buf, 6),
121/// 64 * 40); // offset
122/// assert(0 != rc);
123/// @endcode
124/// `loadString` will read a zero terminated string at a given offset,
125/// using a buffer passed in, and allocating memory for a new copy of
126/// the string.
127/// @code
128/// memset(buf, 'a', sizeof(buf));
129/// bsl::string_view result = helper.loadString(buf,
130/// OFFSET_OF_ZERO_BYTE - 12);
131/// assert(12 == result.length());
132/// assert("0123456789+-" == result);
133/// }
134/// bdls::FilesystemUtil::remove(fileNameBuffer);
135/// @endcode
136/// @}
137/** @} */
138/** @} */
139
140/** @addtogroup bal
141 * @{
142 */
143/** @addtogroup balst
144 * @{
145 */
146/** @addtogroup balst_resolver_filehelper
147 * @{
148 */
149
150#include <balscm_version.h>
151
153
154#if defined(BALST_OBJECTFILEFORMAT_RESOLVER_ELF)
155#include <bdls_filesystemutil.h>
156
157#include <bslma_allocator.h>
158
159#include <bsls_assert.h>
160#include <bsls_review.h>
161#include <bsls_types.h>
162
163#include <bsl_span.h>
164#include <bsl_variant.h>
165
166
167
168namespace balst {
169 // =========================
170 // class Resolver_FileHelper
171 // =========================
172
173/// This class provides a low-level file utility functions for `Resolver<Elf>`.
174/// This class contains the file descriptor of current object file.
175///
176/// \note Note that the file is opened readonly, and all reads specify the offset, so the
177/// offset of the file descriptor is not considered part of the state of this
178/// object.
179///
180/// See @ref balst_resolver_filehelper
181class Resolver_FileHelper {
182
183 // PRIVATE TYPES
184 typedef bdls::FilesystemUtil FilesystemUtil;
185 typedef FilesystemUtil::FileDescriptor FileDescriptor;
186 typedef bsls::Types::UintPtr UintPtr;
187 typedef bsls::Types::IntPtr IntPtr;
188 typedef bsl::span<char> Span;
189 typedef bsl::span<const char> CSpan;
190 typedef bsl::ptrdiff_t ptrdiff_t;
191
192 public:
193 // PUBLIC CONSTANTS
194
195 /// length in bytes of d_buffer_p; 32K minus a little so we don't waste a
196 /// page
197 enum { k_DEFAULT_SCRATCH_BUF_LEN = (1 << 15) - 64 };
198
199 // PUBLIC TYPES
200 typedef FilesystemUtil::Offset Offset;
201
202 private:
203 // PRIVATE TYPES
204 class FileReader {
205 // DATA
206 FileDescriptor d_fd;
207
208 public:
209 // CREATORS
210
211 /// Bind this file reader to the specified `fd`.
212 ///
213 /// \pre The behavior is undefined if `fd` is invalid.
214 FileReader(FileDescriptor fd);
215
216 /// Close the file to which this `FileReader` is bound.
217 ~FileReader();
218
219 // ACCESSORS
220
221 /// The size of the open file.
222 Offset fileSize() const;
223
224 /// Load a string, terminated by either a null, by EOF, or by the end
225 /// of the file, into the specified `writeSpan` and return a
226 /// @ref string_view referring to it. The resulting @ref string_view will
227 /// refer to memory copied to `writeSpan`.
228 ///
229 /// \pre The behavior is undefined unless `offset >= 0`.
230 bsl::string_view loadString(const Span& writeSpan,
231 Offset offset) const;
232
233 /// Read into the specified `writeSpan` data starting at the specified
234 /// `offset` in the current ELF file. Terminate reading either when
235 /// the end of `writeSpan` is reached, or EOF. Return a span of the bytes read into `writeSpan`.
236 ///
237 /// \pre The behavior is undefined unless
238 /// `offset >= 0`.
239 CSpan readBytes(const Span& writeSpan, Offset offset) const;
240 };
241
242 class MappedFileReader {
243 // DATA
244 const CSpan d_mappedFile;
245
246 public:
247 // CREATORS
248
249 /// Map this reader to the specified `mappedFile`. The behavior is
250 // undefined if `mappedFile` is empty.
251 MappedFileReader(const CSpan& mappedFile);
252
253 // ACCESSORS
254
255 /// The size of the mapped segment.
256 Offset fileSize() const;
257
258 /// Return a @ref string_view referring to a null-terminated string from
259 /// `d_mappedFile` beginning at the specified `offset`. If no `\0` is
260 /// found, return a @ref string_view ranging from `offset` to the end of `d_mappedFile`.
261 ///
262 /// \pre The behavior is undefined unless `offset >= 0`.
263 ///
264 /// \note Note that the string will never be longer than `writeSpan` and the
265 /// result will be copied into `writeSpan`.
266 bsl::string_view loadString(const Span& writeSpan,
267 Offset offset) const;
268
269 /// Read into the specified `writeSpan` data starting at the specified
270 /// `offset` in the current ELF file. Terminate reading either when
271 /// the end of `writeSpan` is reached, or EOF. Return a span of the bytes read into `writeSpan`.
272 ///
273 /// \pre The behavior is undefined unless
274 /// `offset >= 0`.
275 CSpan readBytes(const Span& writeSpan, Offset offset) const;
276 };
277
279 FileReader,
280 MappedFileReader> ReaderType;
281
282 enum ReaderIndex { e_MONO_STATE,
283 e_OPEN_FILE,
284 e_MAPPED_FILE };
285
286 private:
287 // DATA
288 ReaderType d_reader; // Either null, or a file descriptor of an open
289 // file, or a string_view of a file image in
290 // memory
291
292 private:
293 // NOT IMPLEMENTED
294 Resolver_FileHelper(const Resolver_FileHelper&);
295 Resolver_FileHelper& operator=(const Resolver_FileHelper&);
296
297 public:
298 // CREATORS
299
300 /// Create a file helper object in an invalid state.
301 Resolver_FileHelper();
302
303 // MANIPULATOR
304
305 /// Open the file referred to by the specified `fileName` for read-only
306 /// access, and if it opens successfully, set `d_reader` to a `FileReader`
307 /// type and bind it to the opened file. Return 0 on success and a
308 /// non-zero value otherwise.
309 int openFile(const char *fileName);
310
311 /// Open this object to access the memory referred to by the specified
312 /// `mappedFile` as if it were a disk file. Return 0 on success and a
313 /// non-zero value otherwise.
314 int openMappedFile(const CSpan& mappedFile);
315
316 // ACCESSORS
317
318 /// The size of the open file or mapped segment.
319 Offset fileSize() const;
320
321 /// Read a null-terminated string from `offset` in the file or mapped file
322 /// into `writeSpan` and return a @ref string_view to the string. If we run
323 /// out of room in `writeSpan`, reach end of file, or reach end of mapped
324 /// area, return a non-null-terminated @ref string_view .
325 ///
326 /// \pre The behavior is undefined unless `!outSpan.empty()` and `offset >= 0`.
327 /// \note Note that the
328 /// returned @ref string_view never contains the terminating `\0`.
329 bsl::string_view loadString(const Span& writeSpan,
330 Offset offset) const;
331
332 /// Read into the specified `outSpan` up to the specified `outSpan.size()`
333 /// of data starting at the specified `offset` in the current ELF file.
334 /// Return a span referring to the section of `outSpan` containing, which can be empty.
335 ///
336 /// \pre The behavior is undefined unless `!outSpan.empty()` and
337 /// `offset >= 0`.
338 CSpan readBytes(const Span& outSpan, Offset offset) const;
339
340 /// Read into the specified `outSpan` exactly the specified
341 /// `outSpan.size()` bytes of data starting at the specified `offset` in
342 /// the current ELF file. Return 0 on success, or a negative value otherwise.
343 ///
344 /// \pre The behavior is undefined unless `!outSpan.empty()` and
345 /// `offset >= 0`.
346 int readExact(const Span& outSpan, Offset offset) const;
347};
348
349// ============================================================================
350// INLINE FUNCTION DEFINITIONS
351// ============================================================================
352
353 // -------------------
354 // Resolver_FileHelper
355 // -------------------
356
357// ACCESSORS
358inline
359int Resolver_FileHelper::readExact(const Span& outSpan, Offset offset) const
360{
361 BSLS_ASSERT(offset >= 0);
362
363 CSpan res = readBytes(outSpan, offset);
364 if (res.size() != outSpan.size() || res.data() != outSpan.data()) {
365 return -1; // RETURN
366 }
367
368 return 0;
369}
370
371} // close package namespace
372
373
374#endif
375
376#endif
377
378// ----------------------------------------------------------------------------
379// Copyright 2018 Bloomberg Finance L.P.
380//
381// Licensed under the Apache License, Version 2.0 (the "License");
382// you may not use this file except in compliance with the License.
383// You may obtain a copy of the License at
384//
385// http://www.apache.org/licenses/LICENSE-2.0
386//
387// Unless required by applicable law or agreed to in writing, software
388// distributed under the License is distributed on an "AS IS" BASIS,
389// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
390// See the License for the specific language governing permissions and
391// limitations under the License.
392// ----------------------------- END-OF-FILE ----------------------------------
393
394/** @} */
395/** @} */
396/** @} */
Definition bslstl_stringview.h:471
Definition bslstl_variant.h:3806
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition balst_objectfileformat.h:152
Definition bdls_filesystemutil.h:364
Definition bslstl_monostate.h:77
std::size_t UintPtr
Definition bsls_types.h:128
std::ptrdiff_t IntPtr
Definition bsls_types.h:132