1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include <string.h>
8 :
9 : #include "native_client/src/include/nacl_macros.h"
10 : #include "native_client/src/shared/gio/gio.h"
11 : #include "native_client/src/trusted/service_runtime/nacl_error_gio.h"
12 :
13 : /*
14 : * This is a service-runtime provided subclass of Gio that is used for
15 : * NaClLog's output Gio stream. In addition to the normal logging and
16 : * error reporting function, it retains a copy of the last (N>=2) line
17 : * of logging output for use with fatal error reporting -- the abort
18 : * behavior in NaClLog is modified to use a functor that takes the
19 : * retained last output lines and sends them to the plugin prior to
20 : * copying it to an on-stack buffer and crashing. The latter is for
21 : * inclusion in breakpad's minidump, which should capture the thread
22 : * stack. The former is to allow the plugin to forward the log
23 : * message to the JavaScript console, so developers can get a better
24 : * idea of what happened -- they won't have direct access to the
25 : * minidumps (potential user privacy issue), so without this they'd
26 : * have to ask Google, which isn't exactly scalable.
27 : *
28 : * Since trying to use the reverse channel or SRPC when there's a
29 : * fatal error might not be kosher, we shouldn't rely on too much
30 : * infrastructure to be operational. The system may be so messed up
31 : * that doing so will just lead to another LOG_FATAL error. We could
32 : * prevent infinite regress by setting a global variable to prevent
33 : * recursive plugin logging, but rather than hacks like that, we
34 : * commandeer the bootstrap channel -- which is currently only used to
35 : * pass the socket address used to connect to the secure command
36 : * channel to the service runtime and then to connect to the PPAPI
37 : * proxy. We use low-level, platform-specific I/O routines to send
38 : * the logging string via this channel.
39 : *
40 : * (The reason N>=2 above is because the log module will, after
41 : * printing the LOG_FATAL message, always append a LOG_ERROR message
42 : * "LOG_FATAL abort exit\n" as an easy-to-recognize output for drivers
43 : * of the software, and that will be the last entry in the output
44 : * stream. So if N==1, that's all that we'd see.)
45 : */
46 :
47 : struct GioVtbl const kNaClErrorGioVtbl; /* fwd */
48 :
49 : int NaClErrorGioCtor(struct NaClErrorGio *self,
50 1 : struct Gio *pass_through) {
51 1 : memset(self->circular_buffer, 0, NACL_ARRAY_SIZE(self->circular_buffer));
52 1 : self->insert_ix = 0;
53 1 : self->num_bytes = 0;
54 1 : self->pass_through = pass_through;
55 1 : self->vtbl = &kNaClErrorGioVtbl;
56 1 : return 1;
57 1 : }
58 :
59 1 : void NaClErrorGioDtor(struct Gio *vself) {
60 1 : struct NaClErrorGio *self = (struct NaClErrorGio *) vself;
61 :
62 : /* excessive paranoia? */
63 1 : memset(self->circular_buffer, 0, NACL_ARRAY_SIZE(self->circular_buffer));
64 1 : self->insert_ix = 0;
65 1 : self->num_bytes = 0;
66 1 : self->pass_through = NULL;
67 1 : self->vtbl = NULL;
68 1 : }
69 :
70 : ssize_t NaClErrorGioRead(struct Gio *vself,
71 : void *buf,
72 0 : size_t count) {
73 0 : struct NaClErrorGio *self = (struct NaClErrorGio *) vself;
74 0 : return (*self->pass_through->vtbl->Read)(self->pass_through, buf, count);
75 0 : }
76 :
77 : ssize_t NaClErrorGioWrite(struct Gio *vself,
78 : void const *buf,
79 1 : size_t count) {
80 1 : struct NaClErrorGio *self = (struct NaClErrorGio *) vself;
81 1 : uint8_t *byte_buf = (uint8_t *) buf;
82 : ssize_t actual;
83 : size_t ix;
84 :
85 1 : actual = (*self->pass_through->vtbl->Write)(self->pass_through, buf, count);
86 1 : if (actual > 0) {
87 1 : for (ix = 0; ix < (size_t) actual; ++ix) {
88 1 : self->circular_buffer[self->insert_ix] = byte_buf[ix];
89 : self->insert_ix = (self->insert_ix + 1) %
90 1 : NACL_ARRAY_SIZE(self->circular_buffer);
91 1 : }
92 : if ((size_t) actual >
93 1 : NACL_ARRAY_SIZE(self->circular_buffer) - self->num_bytes) {
94 1 : self->num_bytes = NACL_ARRAY_SIZE(self->circular_buffer);
95 1 : } else {
96 1 : self->num_bytes += actual;
97 : }
98 : }
99 1 : return actual;
100 1 : }
101 :
102 : off_t NaClErrorGioSeek(struct Gio *vself,
103 : off_t offset,
104 0 : int whence) {
105 0 : struct NaClErrorGio *self = (struct NaClErrorGio *) vself;
106 0 : return (*self->pass_through->vtbl->Seek)(self->pass_through, offset, whence);
107 0 : }
108 :
109 0 : int NaClErrorGioFlush(struct Gio *vself) {
110 0 : struct NaClErrorGio *self = (struct NaClErrorGio *) vself;
111 0 : return (*self->pass_through->vtbl->Flush)(self->pass_through);
112 0 : }
113 :
114 0 : int NaClErrorGioClose(struct Gio *vself) {
115 0 : return (*vself->vtbl->Flush)(vself);
116 0 : }
117 :
118 : struct GioVtbl const kNaClErrorGioVtbl = {
119 : NaClErrorGioDtor,
120 : NaClErrorGioRead,
121 : NaClErrorGioWrite,
122 : NaClErrorGioSeek,
123 : NaClErrorGioFlush,
124 : NaClErrorGioClose,
125 : };
126 :
127 : size_t NaClErrorGioGetOutput(struct NaClErrorGio *self,
128 : char *buffer,
129 1 : size_t buffer_size) {
130 : size_t num_copy;
131 : size_t ix;
132 : size_t count;
133 :
134 1 : num_copy = self->num_bytes;
135 : /* 0 <= num_copy <= NACL_ARRAY_SIZE(self->circular_buffer) */
136 1 : if (0 == buffer_size) {
137 1 : return self->num_bytes;
138 : }
139 : /* buffer_size > 0 */
140 1 : if (num_copy > buffer_size) {
141 1 : num_copy = buffer_size;
142 : }
143 : /*
144 : * 0 <= num_copy <= min(NACL_ARRAY_SIZE(self->circular_buffer),
145 : * buffer_size)
146 : */
147 : ix = (self->insert_ix +
148 : NACL_ARRAY_SIZE(self->circular_buffer) - self->num_bytes) %
149 1 : NACL_ARRAY_SIZE(self->circular_buffer);
150 1 : for (count = 0; count < num_copy; ++count) {
151 1 : buffer[count] = self->circular_buffer[ix];
152 1 : ix = (ix + 1) % NACL_ARRAY_SIZE(self->circular_buffer);
153 1 : }
154 : /*
155 : * count = num_copy
156 : * <= min(NACL_ARRAY_SIZE(self->circular_buffer), buffer_size)
157 : */
158 1 : return self->num_bytes;
159 1 : }
160 :
|