Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
os_fuchsia.cc
Go to the documentation of this file.
1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/globals.h"
6#if defined(DART_HOST_OS_FUCHSIA)
7
8#include "vm/os.h"
9
10#include <dlfcn.h>
11#include <elf.h>
12#include <errno.h>
13#include <fcntl.h>
14#include <stdint.h>
15#include <string.h>
16#include <unistd.h>
17
18#include <fuchsia/intl/cpp/fidl.h>
19#include <lib/async-loop/default.h>
20#include <lib/async-loop/loop.h>
21#include <lib/async/default.h>
22#include <lib/inspect/component/cpp/component.h>
23#include <lib/inspect/cpp/inspect.h>
24#include <lib/sys/cpp/component_context.h>
25#include <lib/sys/cpp/service_directory.h>
26#include <zircon/process.h>
27#include <zircon/syscalls.h>
28#include <zircon/syscalls/object.h>
29#include <zircon/threads.h>
30#include <zircon/time.h>
31#include <zircon/types.h>
32
33#include <set>
34
35#include "unicode/errorcode.h"
36#include "unicode/timezone.h"
37#include "unicode/umachine.h"
38
39#include "platform/assert.h"
40#include "platform/syslog.h"
41#include "platform/utils.h"
42#include "vm/image_snapshot.h"
43#include "vm/lockers.h"
44#include "vm/os_thread.h"
45#include "vm/zone.h"
46
47namespace {
48
49using dart::Mutex;
51using dart::Syslog;
52using dart::Zone;
53
54// This is the default timezone returned if it could not be obtained. For
55// Fuchsia, the default device timezone is always UTC.
56static const char kDefaultTimezone[] = "UTC";
57
58static constexpr int32_t kMsPerSec = 1000;
59
60// The data directory containing ICU timezone data files.
61static constexpr char kICUTZDataDir[] = "/config/data/tzdata/icu/44/le";
62// An updated location for ICU timezone data files.
63// See:
64// https://fuchsia.dev/fuchsia-src/development/internationalization/icu_data#timezone_configuration_data
65// https://fuchsia.dev/fuchsia-src/concepts/process/namespaces
66static constexpr char kICUTZDataDir2[] = "/config/tzdata/icu/44/le";
67
68// This is the general OK status.
69static constexpr int32_t kOk = 0;
70
71// This status means that the error code is not initialized yet ("set" was not
72// yet called). Error codes are usually either 0 (kOk), or negative.
73static constexpr int32_t kUninitialized = 1;
74
75// The status codes for tzdata file open and read.
76enum class TZDataStatus {
77 // The operation completed without error.
78 OK = 0,
79 // The open call for the tzdata file did not succeed.
80 COULD_NOT_OPEN = -1,
81 // The close call (after tzdata was loaded) did not succeed.
82 COULD_NOT_CLOSE = -2,
83};
84
85// Adds a facility for introspecting timezone data errors. Allows insight into
86// the internal state of the VM even if error reporting facilities fail.
87//
88// Under normal operation, all metric values below should be zero.
89class InspectMetrics {
90 public:
91 // Takes ownership of the vm_node.
92 explicit InspectMetrics(std::unique_ptr<inspect::Node> vm_node)
93 : vm_node_(std::move(vm_node)),
94 dst_status_(vm_node_->CreateInt("dst_status", kUninitialized)),
95 tz_data_status_(vm_node_->CreateInt("tz_data_status", kUninitialized)),
96 tz_data_close_status_(
97 vm_node_->CreateInt("tz_data_close_status", kUninitialized)),
98 get_profile_status_(
99 vm_node_->CreateInt("get_profile_status", kUninitialized)),
100 profiles_timezone_content_status_(
101 vm_node_->CreateInt("timezone_content_status", kOk)),
102 num_get_profile_calls_(vm_node_->CreateInt("num_get_profile_calls", 0)),
103 num_on_change_calls_(vm_node_->CreateInt("num_on_change_calls", 0)),
104 num_intl_provider_errors_(
105 vm_node_->CreateInt("num_intl_provider_errors", 0)) {}
106
107 // Registers a single call to GetProfile callback.
108 void RegisterGetProfileCall() { num_get_profile_calls_.Add(1); }
109
110 // Registers a single call to OnChange callback.
111 void RegisterOnChangeCall() { num_on_change_calls_.Add(1); }
112
113 // Registers a provider error.
114 void RegisterIntlProviderError() { num_intl_provider_errors_.Add(1); }
115
116 // Sets the last status code for DST offset calls.
117 void SetDSTOffsetStatus(zx_status_t status) {
118 dst_status_.Set(static_cast<int32_t>(status));
119 }
120
121 // Sets the return value of call to InitializeTZData, and the status of the
122 // reported by close() on tzdata files.
123 void SetInitTzData(TZDataStatus value, int32_t status) {
124 tz_data_status_.Set(static_cast<int32_t>(value));
125 tz_data_close_status_.Set(status);
126 }
127
128 // Sets the last status code for the call to PropertyProvider::GetProfile.
129 void SetProfileStatus(zx_status_t status) {
130 get_profile_status_.Set(static_cast<int32_t>(status));
131 }
132
133 // Sets the last status seen while examining timezones returned from
134 // PropertyProvider::GetProfile.
135 void SetTimeZoneContentStatus(zx_status_t status) {
136 profiles_timezone_content_status_.Set(static_cast<int32_t>(status));
137 }
138
139 private:
140 // The OS metrics node.
141 std::unique_ptr<inspect::Node> vm_node_;
142
143 // The status of the last GetTimeZoneOffset call.
144 inspect::IntProperty dst_status_;
145
146 // The status of the initialization.
147 inspect::IntProperty tz_data_status_;
148
149 // The return code for the close() call for tzdata files.
150 inspect::IntProperty tz_data_close_status_;
151
152 // The return code of the GetProfile call in GetTimeZoneName. If this is
153 // nonzero, then os_fuchsia.cc reported a default timezone as a fallback.
154 inspect::IntProperty get_profile_status_;
155
156 // U_ILLEGAL_ARGUMENT_ERROR(=1) if timezones read from ProfileProvider were
157 // incorrect. Otherwise 0. If this metric reports U_ILLEGAL_ARGUMENT_ERROR,
158 // the os_fuchsia.cc module reported a default timezone as a fallback.
159 inspect::IntProperty profiles_timezone_content_status_;
160
161 // Keeps a number of get_profile update calls.
162 inspect::IntProperty num_get_profile_calls_;
163
164 // Number of "on change" callback calls.
165 inspect::IntProperty num_on_change_calls_;
166
167 // Keeps a number of errors encountered in intl provider.
168 inspect::IntProperty num_intl_provider_errors_;
169};
170
171// Thread-safe storage for the current timezone name.
172//
173// Keeps an up to date timezone cache, updating if needed through the
174// asynchronous update interface. Access to this class is thread-safe.
175class TimezoneName final {
176 public:
177 // Creates a new instance of TimezoneName. Does not take ownership of
178 // metrics.
179 static std::shared_ptr<TimezoneName> New(
180 fuchsia::intl::PropertyProviderPtr proxy,
181 std::weak_ptr<InspectMetrics> metrics) {
182 auto timezone_name =
183 std::make_shared<TimezoneName>(std::move(proxy), metrics);
184 timezone_name->InitHandlers(timezone_name);
185 return timezone_name;
186 }
187
188 TimezoneName(fuchsia::intl::PropertyProviderPtr proxy,
189 std::weak_ptr<InspectMetrics> metrics)
190 : m_(),
191 metrics_(std::move(metrics)),
192 proxy_(std::move(proxy)),
193 timezone_name_(kDefaultTimezone) {
194 ASSERT(metrics_.lock() != nullptr);
195 }
196
197 // Gets the current timezone name. Repeated calls may retrieve updated
198 // values.
199 std::string Get() const {
200 MutexLocker lock(&m_);
201 // Returns a copy, to avoid a data race with async updates.
202 return timezone_name_;
203 }
204
205 private:
206 // Sets the event handlers in this resolver. Intended to resolve a circular
207 // reference between the shared timezone name and this.
208 void InitHandlers(std::shared_ptr<TimezoneName> timezone_name) {
209 ASSERT(timezone_name.get() == this);
210 timezone_name->proxy_.set_error_handler(
211 [weak_this =
212 std::weak_ptr<TimezoneName>(timezone_name)](zx_status_t status) {
213 if (!weak_this.expired()) {
214 weak_this.lock()->ErrorHandler(status);
215 }
216 });
217 timezone_name->proxy_.events().OnChange =
218 [weak_this = std::weak_ptr<TimezoneName>(timezone_name)]() {
219 if (!weak_this.expired()) {
220 weak_this.lock()->OnChangeCallback();
221 }
222 };
223 timezone_name->proxy_->GetProfile(
224 [weak_this = std::weak_ptr<TimezoneName>(timezone_name)](
225 fuchsia::intl::Profile profile) {
226 if (!weak_this.expired()) {
227 weak_this.lock()->GetProfileCallback(std::move(profile));
228 }
229 });
230 }
231
232 // Called on a profile provider error in the context of the event loop
233 // thread.
234 void ErrorHandler(zx_status_t status) {
235 MutexLocker lock(&m_);
236 WithMetrics([status](std::shared_ptr<InspectMetrics> metrics) {
237 metrics->SetProfileStatus(status);
238 metrics->RegisterIntlProviderError();
239 });
240 }
241
242 // Called when an OnChange event is received in the context of the event loop
243 // thread. The only action here is to trigger an asynchronous update of the
244 // intl profile.
245 void OnChangeCallback() {
246 MutexLocker lock(&m_);
247 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
248 metrics->RegisterOnChangeCall();
249 });
250 proxy_->GetProfile([this](fuchsia::intl::Profile profile) {
251 this->GetProfileCallback(std::move(profile));
252 });
253 }
254
255 // Called when a GetProfile async request is resolved, in the context of the
256 // event loop thread.
257 void GetProfileCallback(fuchsia::intl::Profile profile) {
258 MutexLocker lock(&m_);
259 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
260 metrics->RegisterGetProfileCall();
261 });
262 const std::vector<fuchsia::intl::TimeZoneId>& timezones =
263 profile.time_zones();
264 if (timezones.empty()) {
265 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
266 metrics->SetTimeZoneContentStatus(U_ILLEGAL_ARGUMENT_ERROR);
267 });
268 // Empty timezone array is not up to fuchsia::intl spec. The serving
269 // endpoint is broken and should be fixed.
270 Syslog::PrintErr("got empty timezone value\n");
271 return;
272 }
273 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
274 metrics->SetProfileStatus(ZX_OK);
275 metrics->SetTimeZoneContentStatus(ZX_OK);
276 });
277
278 timezone_name_ = timezones[0].id;
279 }
280
281 // Runs the provided function only on valid metrics.
282 void WithMetrics(std::function<void(std::shared_ptr<InspectMetrics> m)> f) {
283 std::shared_ptr<InspectMetrics> l = metrics_.lock();
284 if (l != nullptr) {
285 f(l);
286 }
287 }
288
289 // Guards timezone_name_ because the callbacks will be called in an
290 // asynchronous thread.
291 mutable Mutex m_;
292
293 // Used to keep tally on the update events. Not owned.
294 std::weak_ptr<InspectMetrics> metrics_;
295
296 // A client-side proxy for a connection to the property provider service.
297 fuchsia::intl::PropertyProviderPtr proxy_;
298
299 // Caches the current timezone name. This is updated asynchronously through
300 // GetProfileCallback.
301 std::string timezone_name_;
302};
303
304// The timezone names encountered so far. The timezone names must live forever.
305std::set<std::string> timezone_names;
306
307// Initialized on OS:Init(), deinitialized on OS::Cleanup.
308std::shared_ptr<InspectMetrics> metrics;
309std::shared_ptr<TimezoneName> timezone_name;
310async_loop_t* message_loop = nullptr;
311
312// Initializes the source of timezone data if available. Timezone data file in
313// Fuchsia is at a fixed directory path. Returns true on success.
314bool InitializeTZData() {
315 ASSERT(metrics != nullptr);
316 // Try opening the path to check if present. No need to verify that it is a
317 // directory since ICU loading will return an error if the TZ data path is
318 // wrong.
319 //
320 // Try the new dir first, sub with the old fallback.
321 const char* tz_dirname = kICUTZDataDir2;
322 int fd = openat(AT_FDCWD, tz_dirname, O_RDONLY);
323 if (fd < 0) {
324 tz_dirname = kICUTZDataDir;
325 fd = openat(AT_FDCWD, tz_dirname, O_RDONLY);
326 }
327 if (fd < 0) {
328 metrics->SetInitTzData(TZDataStatus::COULD_NOT_OPEN, fd);
329 return false;
330 }
331 // 0 == Not overwriting the env var if already set.
332 setenv("ICU_TIMEZONE_FILES_DIR", tz_dirname, 0);
333 int32_t close_status = close(fd);
334 if (close_status != 0) {
335 metrics->SetInitTzData(TZDataStatus::COULD_NOT_CLOSE, close_status);
336 return false;
337 }
338 metrics->SetInitTzData(TZDataStatus::OK, 0);
339 return true;
340}
341
342int64_t GetCurrentTimeNanos() {
343 struct timespec ts;
344 if (timespec_get(&ts, TIME_UTC) == 0) {
345 FATAL("timespec_get failed");
346 return 0;
347 }
348 return zx_time_add_duration(ZX_SEC(ts.tv_sec), ZX_NSEC(ts.tv_nsec));
349}
350
351} // namespace
352
353namespace dart {
354
355#ifndef PRODUCT
356
357DEFINE_FLAG(bool,
358 generate_perf_events_symbols,
359 false,
360 "Generate events symbols for profiling with perf");
361
362#endif // !PRODUCT
363
364intptr_t OS::ProcessId() {
365 return static_cast<intptr_t>(getpid());
366}
367
368// TODO(FL-98): Change this to talk to fuchsia.dart to get timezone service to
369// directly get timezone.
370//
371// Putting this hack right now due to CP-120 as I need to remove
372// component:ConnectToEnvironmentServices and this is the only thing that is
373// blocking it and FL-98 will take time.
374static fuchsia::intl::PropertyProviderPtr property_provider;
375
376static zx_status_t GetLocalAndDstOffsetInSeconds(int64_t seconds_since_epoch,
377 int32_t* local_offset,
378 int32_t* dst_offset) {
379 const char* timezone_id = OS::GetTimeZoneName(seconds_since_epoch);
380 std::unique_ptr<icu::TimeZone> timezone(
381 icu::TimeZone::createTimeZone(timezone_id));
382 UErrorCode error = U_ZERO_ERROR;
383 const auto ms_since_epoch =
384 static_cast<UDate>(kMsPerSec * seconds_since_epoch);
385 // The units of time that local_offset and dst_offset are returned from this
386 // function is, usefully, not documented, but it seems that the units are
387 // milliseconds. Add these variables here for clarity.
388 int32_t local_offset_ms = 0;
389 int32_t dst_offset_ms = 0;
390 timezone->getOffset(ms_since_epoch, /*local_time=*/0, local_offset_ms,
391 dst_offset_ms, error);
392 metrics->SetDSTOffsetStatus(error);
393 if (error != U_ZERO_ERROR) {
394 icu::ErrorCode icu_error;
395 icu_error.set(error);
396 Syslog::PrintErr("could not get DST offset: %s\n", icu_error.errorName());
397 return ZX_ERR_INTERNAL;
398 }
399 // We must return offset in seconds, so convert.
400 *local_offset = local_offset_ms / kMsPerSec;
401 *dst_offset = dst_offset_ms / kMsPerSec;
402 return ZX_OK;
403}
404
405// Returns a C string with the time zone name. This module retains the
406// ownership of the pointer.
407const char* OS::GetTimeZoneName(int64_t seconds_since_epoch) {
408 ASSERT(timezone_name != nullptr);
409
410 // Sadly, since we do not know how long the timezone name will be needed, we
411 // can not ever deallocate it. So instead, we put it into a a set that will
412 // not move it around in memory and return a pointer to it. Since the number
413 // of timezones is finite, this ensures that the memory taken up by timezones
414 // does not grow indefinitely, even if we end up retaining all the timezones
415 // there are.
416 const auto i = timezone_names.insert(timezone_name->Get());
417 ASSERT(i.first != timezone_names.end());
418 return i.first->c_str();
419}
420
421int OS::GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch) {
422 int32_t local_offset = 0;
423 int32_t dst_offset = 0;
424 const zx_status_t status = GetLocalAndDstOffsetInSeconds(
425 seconds_since_epoch, &local_offset, &dst_offset);
426 return status == ZX_OK ? local_offset + dst_offset : 0;
427}
428
429int64_t OS::GetCurrentTimeMillis() {
430 return GetCurrentTimeNanos() / ZX_MSEC(1);
431}
432
433int64_t OS::GetCurrentTimeMicros() {
434 return GetCurrentTimeNanos() / ZX_USEC(1);
435}
436
438 return zx_clock_get_monotonic();
439}
440
443}
444
446 const int64_t ticks = GetCurrentMonotonicTicks();
448 return ticks / kNanosecondsPerMicrosecond;
449}
450
452 zx_info_thread_stats_t info = {};
453 zx_status_t status = zx_object_get_info(thrd_get_zx_handle(thrd_current()),
454 ZX_INFO_THREAD_STATS, &info,
455 sizeof(info), nullptr, nullptr);
456 return status == ZX_OK ? info.total_runtime / kNanosecondsPerMicrosecond : 0;
457}
458
460#if defined(SUPPORT_TIMELINE)
462#else
463 return -1;
464#endif
465}
466
467// TODO(5411554): May need to hoist these architecture dependent code
468// into a architecture specific file e.g: os_ia32_fuchsia.cc
470#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
471 defined(TARGET_ARCH_ARM64)
472 const int kMinimumAlignment = 16;
473#elif defined(TARGET_ARCH_ARM)
474 const int kMinimumAlignment = 8;
475#else
476#error Unsupported architecture.
477#endif
478 intptr_t alignment = kMinimumAlignment;
479 // TODO(5411554): Allow overriding default stack alignment for
480 // testing purposes.
481 // Flags::DebugIsInt("stackalign", &alignment);
482 ASSERT(Utils::IsPowerOfTwo(alignment));
483 ASSERT(alignment >= kMinimumAlignment);
484 return alignment;
485}
486
488 return sysconf(_SC_NPROCESSORS_CONF);
489}
490
491void OS::Sleep(int64_t millis) {
493}
494
495void OS::SleepMicros(int64_t micros) {
496 zx_nanosleep(zx_deadline_after(micros * kNanosecondsPerMicrosecond));
497}
498
499void OS::DebugBreak() {
501}
502
503DART_NOINLINE uintptr_t OS::GetProgramCounter() {
504 return reinterpret_cast<uintptr_t>(
505 __builtin_extract_return_addr(__builtin_return_address(0)));
506}
507
508void OS::Print(const char* format, ...) {
509 va_list args;
511 VFPrint(stdout, format, args);
512 va_end(args);
513}
514
515void OS::VFPrint(FILE* stream, const char* format, va_list args) {
516 vfprintf(stream, format, args);
517 fflush(stream);
518}
519
520char* OS::SCreate(Zone* zone, const char* format, ...) {
521 va_list args;
523 char* buffer = VSCreate(zone, format, args);
524 va_end(args);
525 return buffer;
526}
527
528char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
529 // Measure.
530 va_list measure_args;
531 va_copy(measure_args, args);
532 intptr_t len = Utils::VSNPrint(nullptr, 0, format, measure_args);
533 va_end(measure_args);
534
535 char* buffer;
536 if (zone != nullptr) {
537 buffer = zone->Alloc<char>(len + 1);
538 } else {
539 buffer = reinterpret_cast<char*>(malloc(len + 1));
540 }
541 ASSERT(buffer != nullptr);
542
543 // Print.
544 va_list print_args;
545 va_copy(print_args, args);
546 Utils::VSNPrint(buffer, len + 1, format, print_args);
547 va_end(print_args);
548 return buffer;
549}
550
551bool OS::StringToInt64(const char* str, int64_t* value) {
552 ASSERT(str != nullptr && strlen(str) > 0 && value != nullptr);
553 int32_t base = 10;
554 char* endptr;
555 int i = 0;
556 if (str[0] == '-') {
557 i = 1;
558 } else if (str[0] == '+') {
559 i = 1;
560 }
561 if ((str[i] == '0') && (str[i + 1] == 'x' || str[i + 1] == 'X') &&
562 (str[i + 2] != '\0')) {
563 base = 16;
564 }
565 errno = 0;
566 if (base == 16) {
567 // Unsigned 64-bit hexadecimal integer literals are allowed but
568 // immediately interpreted as signed 64-bit integers.
569 *value = static_cast<int64_t>(strtoull(str, &endptr, base));
570 } else {
571 *value = strtoll(str, &endptr, base);
572 }
573 return ((errno == 0) && (endptr != str) && (*endptr == 0));
574}
575
577#ifndef PRODUCT
578 if (FLAG_generate_perf_events_symbols) {
580 }
581#endif // !PRODUCT
582}
583
584void OS::PrintErr(const char* format, ...) {
585 va_list args;
587 VFPrint(stderr, format, args);
588 va_end(args);
589}
590
591void OS::Init() {
592 if (async_get_default_dispatcher() == nullptr) {
593 async_loop_create(&kAsyncLoopConfigAttachToCurrentThread, &message_loop);
594 async_set_default_dispatcher(async_loop_get_dispatcher(message_loop));
595 async_loop_start_thread(message_loop, "Fuchsia async loop", nullptr);
596 }
597
598 auto vm_node = dart::TakeDartVmNode();
599
600 // TODO(fxbug.dev/69558) allow vm_node to be null and not crash
601 ASSERT(vm_node != nullptr);
602 metrics = std::make_shared<InspectMetrics>(std::move(vm_node));
603
604 InitializeTZData();
605 auto services = sys::ServiceDirectory::CreateFromNamespace();
606 services->Connect(property_provider.NewRequest());
607
608 timezone_name = TimezoneName::New(std::move(property_provider), metrics);
609}
610
611void OS::Cleanup() {
612 if (message_loop != nullptr) {
613 async_loop_shutdown(message_loop);
614 }
615 timezone_name.reset();
616 metrics.reset();
617
618 if (message_loop != nullptr) {
619 // Check message_loop is still the default dispatcher before clearing it.
620 if (async_get_default_dispatcher() ==
621 async_loop_get_dispatcher(message_loop)) {
622 async_set_default_dispatcher(nullptr);
623 }
624 async_loop_destroy(message_loop);
625 message_loop = nullptr;
626 }
627}
628
629void OS::PrepareToAbort() {}
630
631void OS::Abort() {
633 abort();
634}
635
636void OS::Exit(int code) {
637 exit(code);
638}
639
640// Used to choose between Elf32/Elf64 types based on host archotecture bitsize.
641#if defined(ARCH_IS_64_BIT)
642#define ElfW(Type) Elf64_##Type
643#else
644#define ElfW(Type) Elf32_##Type
645#endif
646
647OS::BuildId OS::GetAppBuildId(const uint8_t* snapshot_instructions) {
648 // First return the build ID information from the instructions image if
649 // available.
650 const Image instructions_image(snapshot_instructions);
651 if (auto* const image_build_id = instructions_image.build_id()) {
652 return {instructions_image.build_id_length(), image_build_id};
653 }
654 const uint8_t* dso_base = GetAppDSOBase(snapshot_instructions);
655 const ElfW(Ehdr)& elf_header = *reinterpret_cast<const ElfW(Ehdr)*>(dso_base);
656 const ElfW(Phdr)* const phdr_array =
657 reinterpret_cast<const ElfW(Phdr)*>(dso_base + elf_header.e_phoff);
658 for (intptr_t i = 0; i < elf_header.e_phnum; i++) {
659 const ElfW(Phdr)& header = phdr_array[i];
660 if (header.p_type != PT_NOTE) continue;
661 if ((header.p_flags & PF_R) != PF_R) continue;
662 const uint8_t* const note_addr = dso_base + header.p_vaddr;
663 const Elf32_Nhdr& note_header =
664 *reinterpret_cast<const Elf32_Nhdr*>(note_addr);
665 if (note_header.n_type != NT_GNU_BUILD_ID) continue;
666 const char* const note_contents =
667 reinterpret_cast<const char*>(note_addr + sizeof(Elf32_Nhdr));
668 // The note name contains the null terminator as well.
669 if (note_header.n_namesz != strlen(ELF_NOTE_GNU) + 1) continue;
670 if (strncmp(ELF_NOTE_GNU, note_contents, note_header.n_namesz) == 0) {
671 return {static_cast<intptr_t>(note_header.n_descsz),
672 reinterpret_cast<const uint8_t*>(note_contents +
673 note_header.n_namesz)};
674 }
675 }
676 return {0, nullptr};
677}
678
679} // namespace dart
680
681#endif // defined(DART_HOST_OS_FUCHSIA)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
static DART_NORETURN void Exit(int code)
static int NumberOfAvailableProcessors()
static const char * GetTimeZoneName(int64_t seconds_since_epoch)
static void SleepMicros(int64_t micros)
static int64_t GetCurrentTimeMillis()
static void RegisterCodeObservers()
static int64_t GetCurrentMonotonicMicros()
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void Sleep(int64_t millis)
static void Print(const char *format,...) PRINTF_ATTRIBUTE(1
static bool StringToInt64(const char *str, int64_t *value)
static BuildId GetAppBuildId(const uint8_t *snapshot_instructions)
static const uint8_t * GetAppDSOBase(const uint8_t *snapshot_instructions)
Definition os.cc:13
static void Init()
static int64_t GetCurrentTimeMicros()
static intptr_t ActivationFrameAlignment()
static void static void static void VFPrint(FILE *stream, const char *format, va_list args)
static void Cleanup()
static void DebugBreak()
static DART_NORETURN void Abort()
static char static char * VSCreate(Zone *zone, const char *format, va_list args)
static int64_t GetCurrentThreadCPUMicros()
static uintptr_t GetProgramCounter()
static intptr_t ProcessId()
static void PrepareToAbort()
static int64_t GetCurrentMonotonicFrequency()
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
static int64_t GetCurrentMonotonicTicks()
static int64_t GetCurrentMonotonicMicrosForTimeline()
static int GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch)
static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
static constexpr bool IsPowerOfTwo(T x)
Definition utils.h:61
#define UNIMPLEMENTED
#define ASSERT(E)
#define FATAL(error)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
uint32_t uint32_t * format
#define DEFINE_FLAG(type, name, default_value, comment)
Definition flags.h:16
const GrXPFactory * Get(SkBlendMode mode)
va_start(args, format)
exit(kErrorExitCode)
va_end(args)
constexpr intptr_t kMicrosecondsPerMillisecond
Definition globals.h:561
constexpr intptr_t kNanosecondsPerMicrosecond
Definition globals.h:564
void * malloc(size_t size)
Definition allocation.cc:19
constexpr intptr_t kNanosecondsPerSecond
Definition globals.h:567
std::unique_ptr< inspect::Node > TakeDartVmNode()
CanvasImage Image
Definition dart_ui.cc:55
Definition ref_ptr.h:256
static const char header[]
Definition skpbench.cpp:88