1 /*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <portability.h>
18 #include <unistd.h>
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <signal.h>
22 #include <signal_portable.h>
23 #include <portability.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <errno_portable.h>
27 #include <asm/unistd-portable.h>
28 #include <asm/unistd.h>
29 #include <signalfd_portable.h>
30 #include <filefd_portable.h>
31
32 #define PORTABLE_TAG "signal_portable"
33 #include <log_portable.h>
34
35
36 #if SIGBUS_PORTABLE == SIGBUS
37 #error Bad build environment
38 #endif
39
40 typedef void (*sig3handler_t)(int, siginfo_t *, void *);
41
42 static volatile int signal_handler_mapping_enabled = 1;
43
44 extern int syscall(int, ...);
45
46
signal_disable_mapping()47 __hidden void signal_disable_mapping()
48 {
49 ALOGV("%s(): signal_handler_mapping_enabled:%d = 0;", __func__,
50 signal_handler_mapping_enabled);
51
52 signal_handler_mapping_enabled = 0;
53 }
54
55
56 /*
57 * The next five hidden functions are not exposed in the
58 * libportable shared object. They are used here and other
59 * functions, like waitpid(), which need to map signal numbers.
60 */
map_portable_signum_to_name(int portable_signum)61 __hidden char *map_portable_signum_to_name(int portable_signum)
62 {
63 char *name;
64
65 switch(portable_signum) {
66 case SIGHUP_PORTABLE: name = "SIGHUP_PORTABLE:1"; break;
67 case SIGINT_PORTABLE: name = "SIGINT_PORTABLE:2"; break;
68 case SIGQUIT_PORTABLE: name = "SIGQUIT_PORTABLE:3"; break;
69 case SIGILL_PORTABLE: name = "SIGILL_PORTABLE:4"; break;
70 case SIGTRAP_PORTABLE: name = "SIGTRAP_PORTABLE:5"; break;
71 case SIGABRT_PORTABLE: name = "SIGABRT_PORTABLE:6"; break;
72 case SIGBUS_PORTABLE: name = "SIGBUS_PORTABLE:7"; break;
73 case SIGFPE_PORTABLE: name = "SIGFPE_PORTABLE:8"; break;
74 case SIGKILL_PORTABLE: name = "SIGKILL_PORTABLE:9"; break;
75 case SIGUSR1_PORTABLE: name = "SIGUSR1_PORTABLE:10"; break;
76 case SIGSEGV_PORTABLE: name = "SIGSEGV_PORTABLE:11"; break;
77 case SIGUSR2_PORTABLE: name = "SIGUSR2_PORTABLE:12"; break;
78 case SIGPIPE_PORTABLE: name = "SIGPIPE_PORTABLE:13"; break;
79 case SIGALRM_PORTABLE: name = "SIGALRM_PORTABLE:14"; break;
80 case SIGTERM_PORTABLE: name = "SIGTERM_PORTABLE:15"; break;
81 case SIGSTKFLT_PORTABLE: name = "SIGSTKFLT_PORTABLE:16"; break;
82 case SIGCHLD_PORTABLE: name = "SIGCHLD_PORTABLE:17"; break;
83 case SIGCONT_PORTABLE: name = "SIGCONT_PORTABLE:18"; break;
84 case SIGSTOP_PORTABLE: name = "SIGSTOP_PORTABLE:19"; break;
85 case SIGTSTP_PORTABLE: name = "SIGTSTP_PORTABLE:20"; break;
86 case SIGTTIN_PORTABLE: name = "SIGTTIN_PORTABLE:21"; break;
87 case SIGTTOU_PORTABLE: name = "SIGTTOU_PORTABLE:22"; break;
88 case SIGURG_PORTABLE: name = "SIGURG_PORTABLE:23"; break;
89 case SIGXCPU_PORTABLE: name = "SIGXCPU_PORTABLE:24"; break;
90 case SIGXFSZ_PORTABLE: name = "SIGXFSZ_PORTABLE:25"; break;
91 case SIGVTALRM_PORTABLE: name = "SIGVTALRM_PORTABLE:26"; break;
92 case SIGPROF_PORTABLE: name = "SIGPROF_PORTABLE:27"; break;
93 case SIGWINCH_PORTABLE: name = "SIGWINCH_PORTABLE:28"; break;
94 case SIGIO_PORTABLE: name = "SIGIO_PORTABLE:29"; break;
95 case SIGPWR_PORTABLE: name = "SIGPWR_PORTABLE:30"; break;
96 case SIGSYS_PORTABLE: name = "SIGSYS_PORTABLE:31"; break;
97 case SIGRTMIN_PORTABLE: name = "SIGRTMIN_PORTABLE:32"; break;
98
99 case SIGRT_1_PORTABLE: name = "SIGRT_1_PORTABLE:33"; break;
100 case SIGRT_2_PORTABLE: name = "SIGRT_2_PORTABLE:34"; break;
101 case SIGRT_3_PORTABLE: name = "SIGRT_3_PORTABLE:35"; break;
102 case SIGRT_4_PORTABLE: name = "SIGRT_4_PORTABLE:36"; break;
103 case SIGRT_5_PORTABLE: name = "SIGRT_5_PORTABLE:37"; break;
104 case SIGRT_6_PORTABLE: name = "SIGRT_6_PORTABLE:38"; break;
105 case SIGRT_7_PORTABLE: name = "SIGRT_7_PORTABLE:39"; break;
106 case SIGRT_8_PORTABLE: name = "SIGRT_8_PORTABLE:40"; break;
107 case SIGRT_9_PORTABLE: name = "SIGRT_9_PORTABLE:41"; break;
108 case SIGRT_10_PORTABLE: name = "SIGRT_10_PORTABLE:42"; break;
109 case SIGRT_11_PORTABLE: name = "SIGRT_11_PORTABLE:43"; break;
110 case SIGRT_12_PORTABLE: name = "SIGRT_12_PORTABLE:44"; break;
111 case SIGRT_13_PORTABLE: name = "SIGRT_13_PORTABLE:45"; break;
112 case SIGRT_14_PORTABLE: name = "SIGRT_14_PORTABLE:46"; break;
113 case SIGRT_15_PORTABLE: name = "SIGRT_15_PORTABLE:47"; break;
114 case SIGRT_16_PORTABLE: name = "SIGRT_16_PORTABLE:48"; break;
115 case SIGRT_17_PORTABLE: name = "SIGRT_17_PORTABLE:49"; break;
116 case SIGRT_18_PORTABLE: name = "SIGRT_18_PORTABLE:50"; break;
117 case SIGRT_19_PORTABLE: name = "SIGRT_19_PORTABLE:51"; break;
118 case SIGRT_20_PORTABLE: name = "SIGRT_20_PORTABLE:52"; break;
119 case SIGRT_21_PORTABLE: name = "SIGRT_21_PORTABLE:53"; break;
120 case SIGRT_22_PORTABLE: name = "SIGRT_22_PORTABLE:54"; break;
121 case SIGRT_23_PORTABLE: name = "SIGRT_23_PORTABLE:55"; break;
122 case SIGRT_24_PORTABLE: name = "SIGRT_24_PORTABLE:56"; break;
123 case SIGRT_25_PORTABLE: name = "SIGRT_25_PORTABLE:57"; break;
124 case SIGRT_26_PORTABLE: name = "SIGRT_26_PORTABLE:58"; break;
125 case SIGRT_27_PORTABLE: name = "SIGRT_27_PORTABLE:59"; break;
126 case SIGRT_28_PORTABLE: name = "SIGRT_28_PORTABLE:60"; break;
127 case SIGRT_29_PORTABLE: name = "SIGRT_29_PORTABLE:61"; break;
128 case SIGRT_30_PORTABLE: name = "SIGRT_30_PORTABLE:62"; break;
129 case SIGRT_31_PORTABLE: name = "SIGRT_31_PORTABLE:63"; break;
130 case SIGRTMAX_PORTABLE: name = "SIGRTMAX_PORTABLE:64"; break;
131
132 default: name = "<<UNKNOWN>>"; break;
133 }
134 return name;
135 }
136
137
map_mips_signum_to_name(int mips_signum)138 __hidden char *map_mips_signum_to_name(int mips_signum)
139 {
140 char *name;
141
142 switch(mips_signum) {
143 case SIGHUP: name = "SIGHUP:1"; break;
144 case SIGINT: name = "SIGINT:2"; break;
145 case SIGQUIT: name = "SIGQUIT:3"; break;
146 case SIGILL: name = "SIGILL:4"; break;
147 case SIGTRAP: name = "SIGTRAP:5"; break;
148 case SIGIOT: name = "SIGIOT:6"; break;
149 case SIGEMT: name = "SIGEMT:7"; break;
150 case SIGFPE: name = "SIGFPE:8"; break;
151 case SIGKILL: name = "SIGKILL:9"; break;
152 case SIGBUS: name = "SIGBUS:10"; break;
153 case SIGSEGV: name = "SIGSEGV:11"; break;
154 case SIGSYS: name = "SIGSYS:12"; break;
155 case SIGPIPE: name = "SIGPIPE:13"; break;
156 case SIGALRM: name = "SIGALRM:14"; break;
157 case SIGTERM: name = "SIGTERM:15"; break;
158 case SIGUSR1: name = "SIGUSR1:16"; break;
159 case SIGUSR2: name = "SIGUSR2:17"; break;
160 case SIGCHLD: name = "SIGCHLD:18"; break;
161 case SIGPWR: name = "SIGPWR:19"; break;
162 case SIGWINCH: name = "SIGWINCH:20"; break;
163 case SIGURG: name = "SIGURG:21"; break;
164 case SIGIO: name = "SIGIO:22"; break;
165 case SIGSTOP: name = "SIGSTOP:23"; break;
166 case SIGTSTP: name = "SIGTSTP:24"; break;
167 case SIGCONT: name = "SIGCONT:25"; break;
168 case SIGTTIN: name = "SIGTTIN:26"; break;
169 case SIGTTOU: name = "SIGTTOU:27"; break;
170 case SIGVTALRM: name = "SIGVTALRM:28"; break;
171 case SIGPROF: name = "SIGPROF:29"; break;
172 case SIGXCPU: name = "SIGXCPU:30"; break;
173 case SIGXFSZ: name = "SIGXFSZ:31"; break;
174
175 case SIGRTMIN: name = "SIGRTMIN:32"; break;
176 case SIGRT_1: name = "SIGRT_1:33"; break;
177 case SIGRT_2: name = "SIGRT_2:34"; break;
178 case SIGRT_3: name = "SIGRT_3:35"; break;
179 case SIGRT_4: name = "SIGRT_4:36"; break;
180 case SIGRT_5: name = "SIGRT_5:37"; break;
181 case SIGRT_6: name = "SIGRT_6:38"; break;
182 case SIGRT_7: name = "SIGRT_7:39"; break;
183 case SIGRT_8: name = "SIGRT_8:40"; break;
184 case SIGRT_9: name = "SIGRT_9:41"; break;
185 case SIGRT_10: name = "SIGRT_10:42"; break;
186 case SIGRT_11: name = "SIGRT_11:43"; break;
187 case SIGRT_12: name = "SIGRT_12:44"; break;
188 case SIGRT_13: name = "SIGRT_13:45"; break;
189 case SIGRT_14: name = "SIGRT_14:46"; break;
190 case SIGRT_15: name = "SIGRT_15:47"; break;
191 case SIGRT_16: name = "SIGRT_16:48"; break;
192 case SIGRT_17: name = "SIGRT_17:49"; break;
193 case SIGRT_18: name = "SIGRT_18:50"; break;
194 case SIGRT_19: name = "SIGRT_19:51"; break;
195 case SIGRT_20: name = "SIGRT_20:52"; break;
196 case SIGRT_21: name = "SIGRT_21:53"; break;
197 case SIGRT_22: name = "SIGRT_22:54"; break;
198 case SIGRT_23: name = "SIGRT_23:55"; break;
199 case SIGRT_24: name = "SIGRT_24:56"; break;
200 case SIGRT_25: name = "SIGRT_25:57"; break;
201 case SIGRT_26: name = "SIGRT_26:58"; break;
202 case SIGRT_27: name = "SIGRT_27:59"; break;
203 case SIGRT_28: name = "SIGRT_28:60"; break;
204 case SIGRT_29: name = "SIGRT_29:61"; break;
205 case SIGRT_30: name = "SIGRT_30:62"; break;
206 case SIGRT_31: name = "SIGRT_31:63"; break;
207 case SIGRT_32: name = "SIGRT_32:64"; break;
208
209 /* NOTE: SIGRT_33...SIGRTMAX-1 Not printed */
210
211 case SIGRTMAX: name = "SIGRTMAX:128"; break;
212 default: name = "<<UNKNOWN>>"; break;
213 }
214 return name;
215 }
216
217
218 /*
219 * Maps a signal number from portable to native.
220 */
signum_pton(int portable_signum)221 __hidden int signum_pton(int portable_signum)
222 {
223 int mips_signum = -1;
224
225 switch(portable_signum) {
226 case SIGHUP_PORTABLE: /* 1 */
227 return SIGHUP;
228
229 case SIGINT_PORTABLE: /* 2 */
230 return SIGINT;
231
232 case SIGQUIT_PORTABLE: /* 3 */
233 return SIGQUIT;
234
235 case SIGILL_PORTABLE: /* 4 */
236 return SIGILL;
237
238 case SIGTRAP_PORTABLE: /* 5 */
239 return SIGTRAP;
240
241 case SIGABRT_PORTABLE: /* 6 */
242 return SIGABRT;
243
244 case SIGBUS_PORTABLE: /* 7 --> 10 */
245 return SIGBUS;
246
247 case SIGFPE_PORTABLE: /* 8 */
248 return SIGFPE;
249
250 case SIGKILL_PORTABLE: /* 9 */
251 return SIGKILL;
252
253 case SIGUSR1_PORTABLE: /* 10 --> 16 */
254 return SIGUSR1;
255
256 case SIGSEGV_PORTABLE: /* 11 */
257 return SIGSEGV;
258
259 case SIGUSR2_PORTABLE: /* 12 --> 17 */
260 return SIGUSR2;
261
262 case SIGPIPE_PORTABLE: /* 13 */
263 return SIGPIPE;
264
265 case SIGALRM_PORTABLE: /* 14 */
266 return SIGALRM;
267
268 case SIGTERM_PORTABLE: /* 15 */
269 return SIGTERM;
270
271 case SIGSTKFLT_PORTABLE: /* 16 --> 7 */
272 return SIGEMT; /* No native SIGSTKFLT exist ...
273 ... mapping it to SIGEMT. */
274
275 case SIGCHLD_PORTABLE: /* 17 --> 18 */
276 return SIGCHLD;
277
278 case SIGCONT_PORTABLE: /* 18 --> 25 */
279 return SIGCONT;
280
281 case SIGSTOP_PORTABLE: /* 19 --> 23 */
282 return SIGSTOP;
283
284 case SIGTSTP_PORTABLE: /* 20 --> 24 */
285 return SIGTSTP;
286
287 case SIGTTIN_PORTABLE: /* 21 --> 26 */
288 return SIGTTIN;
289
290 case SIGTTOU_PORTABLE: /* 22 --> 27 */
291 return SIGTTOU;
292
293 case SIGURG_PORTABLE: /* 23 --> 21 */
294 return SIGURG;
295
296 case SIGXCPU_PORTABLE: /* 24 --> 30 */
297 return SIGXCPU;
298
299 case SIGXFSZ_PORTABLE: /* 25 --> 31 */
300 return SIGXFSZ;
301
302 case SIGVTALRM_PORTABLE: /* 26 --> 28 */
303 return SIGVTALRM;
304
305 case SIGPROF_PORTABLE: /* 27 --> 29 */
306 return SIGPROF;
307
308 case SIGWINCH_PORTABLE: /* 28 --> 20 */
309 return SIGWINCH;
310
311 case SIGIO_PORTABLE: /* 29 --> 22 */
312 return SIGIO;
313
314 case SIGPWR_PORTABLE: /* 30 --> 19 */
315 return SIGPWR;
316
317 case SIGSYS_PORTABLE: /* 31 --> 12 */
318 return SIGSYS;
319 /*
320 * Mapping lower 32 Real Time signals to identical Native signal numbers.
321 * NOTE: SIGRTMAX_PORTABLE == 64 but SIGRTMAX == 128.
322 */
323 case SIGRTMIN_PORTABLE...SIGRTMAX_PORTABLE: /* 32 ... 64 */
324 ASSERT(SIGRTMIN_PORTABLE == SIGRTMIN);
325 ASSERT(SIGRTMAX_PORTABLE <= SIGRTMAX);
326 return portable_signum;
327
328 default:
329 ALOGE("%s: switch default: NOTE portable_signum:%d Not supported. Just a Test?",
330 __func__, portable_signum);
331 /*
332 * User could be LTP testing with bogus signal numbers,
333 * if so we mimic the test.
334 *
335 * If the signal is just outside the PORTABLE range
336 * we use a signal just outside the Native/MIPS range.
337 */
338 if (portable_signum < 0) {
339 mips_signum = portable_signum;
340 } else if (portable_signum > NSIG_PORTABLE) {
341 mips_signum = (portable_signum - NSIG_PORTABLE) + NSIG;
342 } else {
343 ALOGE("%s: 0 <= portable_signum:%d <= NSIG_PORTABLE:%d; Not supported, return(0);",
344 __func__, portable_signum, NSIG_PORTABLE);
345
346 mips_signum = 0;
347 }
348 break;
349 }
350 ALOGV("%s(portable_signum:%d): return(mips_signum:%d);", __func__,
351 portable_signum, mips_signum);
352
353 return mips_signum;
354 }
355
356
357 /*
358 * Maps a signal number from native to portable.
359 */
signum_ntop(int mips_signum)360 __hidden int signum_ntop(int mips_signum)
361 {
362 int portable_ssignum = -1;
363
364 switch(mips_signum) {
365 case SIGHUP: /* 1 */
366 return SIGHUP_PORTABLE;
367
368 case SIGINT: /* 2 */
369 return SIGINT_PORTABLE;
370
371 case SIGQUIT: /* 3 */
372 return SIGQUIT_PORTABLE;
373
374 case SIGILL: /* 4 */
375 return SIGILL_PORTABLE;
376
377 case SIGTRAP: /* 5 */
378 return SIGTRAP_PORTABLE;
379
380 case SIGABRT: /* 6 */
381 return SIGABRT_PORTABLE;
382
383 case SIGBUS: /* 7 <-- 10 */
384 return SIGBUS_PORTABLE;
385
386 case SIGFPE: /* 8 */
387 return SIGFPE_PORTABLE;
388
389 case SIGKILL: /* 9 */
390 return SIGKILL_PORTABLE;
391
392 case SIGUSR1: /* 10 <-- 16 */
393 return SIGUSR1_PORTABLE;
394
395 case SIGSEGV: /* 11 */
396 return SIGSEGV_PORTABLE;
397
398 case SIGUSR2: /* 12 <-- 17 */
399 return SIGUSR2_PORTABLE;
400
401 case SIGPIPE: /* 13 */
402 return SIGPIPE_PORTABLE;
403
404 case SIGALRM: /* 14 */
405 return SIGALRM_PORTABLE;
406
407 case SIGTERM: /* 15 */
408 return SIGTERM_PORTABLE;
409
410 case SIGEMT: /* 16 <--- 7 */
411 return SIGSTKFLT_PORTABLE; /* No native SIGSTKFLT exist ...
412 ... reverse mapping SIGEMT ...
413 ... back to SIGSTKFLT. */
414
415 case SIGCHLD: /* 17 <-- 18 */
416 return SIGCHLD_PORTABLE;
417
418 case SIGCONT: /* 18 <-- 15 */
419 return SIGCONT_PORTABLE;
420
421 case SIGSTOP: /* 19 <-- 23 */
422 return SIGSTOP_PORTABLE;
423
424 case SIGTSTP: /* 20 <-- 24 */
425 return SIGTSTP_PORTABLE;
426
427 case SIGTTIN: /* 21 <-- 26 */
428 return SIGTTIN_PORTABLE;
429
430 case SIGTTOU: /* 22 <-- 27 */
431 return SIGTTOU_PORTABLE;
432
433 case SIGURG: /* 23 <-- 21 */
434 return SIGURG_PORTABLE;
435
436 case SIGXCPU: /* 24 <-- 30 */
437 return SIGXCPU_PORTABLE;
438
439 case SIGXFSZ: /* 25 <-- 31 */
440 return SIGXFSZ_PORTABLE;
441
442 case SIGVTALRM: /* 26 <-- 28 */
443 return SIGVTALRM_PORTABLE;
444
445 case SIGPROF: /* 27 <-- 29 */
446 return SIGPROF_PORTABLE;
447
448 case SIGWINCH: /* 28 <-- 20 */
449 return SIGWINCH_PORTABLE;
450
451 case SIGIO: /* 29 <-- 22 */
452 return SIGIO_PORTABLE;
453
454 case SIGPWR: /* 30 <-- 19 */
455 return SIGPWR_PORTABLE;
456
457 case SIGSYS: /* 31 <-- 12 */
458 return SIGSYS_PORTABLE;
459
460 /*
461 * Mapping lower 32 Real Time signals to identical Portable signal numbers.
462 * NOTE: SIGRTMAX_PORTABLE == 64 but SIGRTMAX == 128.
463 */
464 case SIGRTMIN...SIGRTMAX_PORTABLE: /* 32 ... 64 */
465 ASSERT(SIGRTMIN == SIGRTMIN_PORTABLE);
466 ASSERT(SIGRTMAX >= SIGRTMAX_PORTABLE);
467 return mips_signum;
468
469 /*
470 * Mapping upper 63 Native Real Time signals to the last Portable signal number.
471 * Shouldn't even be possible to be using these signals.
472 */
473 case (SIGRTMAX_PORTABLE+1)...SIGRTMAX: /* 65 ... 128 */
474 ASSERT(SIGRTMIN == SIGRTMIN_PORTABLE);
475 ASSERT(SIGRTMAX >= SIGRTMAX_PORTABLE);
476
477 ALOGE("%s: mips_signum:%d Can't be mapped to a unique portable signal;", __func__,
478 mips_signum);
479
480 ALOGE("%s: Mapping highest 63 Real Time Signals to the largest RT Portable SigNo.",
481 __func__);
482
483 return SIGRTMAX_PORTABLE;
484
485
486 default:
487 ALOGE("%s: switch default: mips_signum:%d Not supported! return(0);", __func__,
488 mips_signum);
489 #if 0
490 LOG_FATAL("%s: mips_signum:%d is not portable;", __func__, mips_signum);
491 #endif
492 return 0;
493 }
494 return portable_ssignum;
495 }
496
497
498 /*
499 * Deal with siginfo structure being a bit different.
500 * Need to swap errno and code fields.
501 */
siginfo_pton(siginfo_portable_t * portable_sip,siginfo_t * native_sip)502 static void siginfo_pton(siginfo_portable_t *portable_sip, siginfo_t *native_sip)
503 {
504
505 ALOGV("%s(portable_sip:%p, native_sip:%p) {", __func__,
506 portable_sip, native_sip);
507
508 ASSERT(sizeof(siginfo_portable_t) == sizeof(siginfo_t));
509
510 /*
511 * Default to the same structure members,
512 * code and errno are swapped between ARM and MIPS,
513 * and errno needs to be translated.
514 *
515 * The signal number isn't translated, as the kernel
516 * will fill it it when it delivers the signal.
517 */
518
519 *native_sip = *((siginfo_t *)portable_sip);
520 native_sip->si_signo = 0;
521 native_sip->si_code = portable_sip->si_code;
522 native_sip->si_errno = errno_pton(portable_sip->si_errno);
523
524 ALOGV("%s: return; }", __func__);
525 }
526
527
siginfo_ntop(siginfo_t * native_sip,siginfo_portable_t * portable_sip)528 static void siginfo_ntop(siginfo_t *native_sip, siginfo_portable_t *portable_sip)
529 {
530
531 ALOGV("%s(native_sip,:%p, portable_sip:%p) {", __func__,
532 native_sip, portable_sip);
533
534 ASSERT(sizeof(siginfo_portable_t) == sizeof(siginfo_t));
535
536 /*
537 * Structure assignment to default to the same structure members,
538 * as only the code and errno are swapped in position between
539 * ARM and MIPS; errno and signal number also need to be translated.
540 */
541 *portable_sip = *((siginfo_portable_t *)native_sip);
542
543 portable_sip->si_signo = signum_ntop(native_sip->si_signo);
544 portable_sip->si_code = native_sip->si_code;
545 portable_sip->si_errno = errno_ntop(native_sip->si_errno);
546
547 ALOGV("%s: return; }", __func__);
548 }
549
550
551 /*
552 * Array of signal handlers as the portable users expects they
553 * they have been registered in the kernel. Problem is we need
554 * to have our own handler to map the MIPS signal number to a
555 * portable signal number.
556 */
557 static sig3handler_portable_t mips_portable_sighandler[NSIG_PORTABLE + 1] = { NULL };
558
mips_sigaction_handler(int mips_signum,siginfo_t * sip,void * ucp)559 static void mips_sigaction_handler(int mips_signum, siginfo_t *sip, void *ucp)
560 {
561 int portable_signum;
562 char *portable_signame;
563 char *mips_signame = map_mips_signum_to_name(mips_signum);
564 sig3handler_portable_t portable_sighandler;
565 siginfo_portable_t portable_si;
566 siginfo_portable_t *portable_sip;
567
568 ALOGV(" ");
569 ALOGV("%s(mips_signum:%d:'%s', sip:%p, ucp:%p) {", __func__,
570 mips_signum,
571 mips_signame, sip, ucp);
572
573 portable_signum = signum_ntop(mips_signum);
574 portable_signame = map_portable_signum_to_name(portable_signum);
575 portable_sighandler = mips_portable_sighandler[portable_signum];
576
577 if (invalid_pointer(portable_sighandler)) {
578 /*
579 * If a portable/ARM application tries to set signals in the signal mask > 32
580 * it results in a signal_handler being set to -1:SIG_ERR. Calling a function
581 * at location -1 doesn't produce very informative Android backtraces on MIPS.
582 */
583 ALOGE("%s: invalid_pointer(portable_sighandler:%p); Likely about to Trap or Bus Error!",
584 __func__, portable_sighandler);
585
586 ALOGE("%s: HINT: Likely best to use gdbserver and look at sigaction arguments.", __func__);
587 }
588 ASSERT(portable_sighandler != NULL);
589 ASSERT(portable_sighandler != (sig3handler_portable_t) SIG_DFL);
590 ASSERT(portable_sighandler != (sig3handler_portable_t) SIG_IGN);
591
592 if (sip == NULL) {
593 portable_sip = NULL;
594 } else {
595 /* Map signinfo from native to portable format */
596 portable_sip = &portable_si;
597 siginfo_ntop(sip, portable_sip);
598 }
599
600
601 ALOGV("%s: Calling portable_sighandler:%p(portable_signum:%d, portable_sip:%p, ucp:%p);",
602 __func__, portable_sighandler, portable_signum, portable_sip, ucp);
603
604 portable_sighandler(portable_signum, portable_sip, ucp);
605
606 ALOGV("%s: return; }", __func__);
607 }
608
609
mips_sighandler(int mips_signum)610 static void mips_sighandler(int mips_signum)
611 {
612 int portable_signum;
613 char *portable_signame;
614 char *mips_signame = map_mips_signum_to_name(mips_signum);
615 sig3handler_portable_t portable_sighandler;
616
617 ALOGV(" ");
618 ALOGV("%s(mips_signum:%d:'%s') {", __func__, mips_signum, mips_signame);
619
620 mips_sigaction_handler(mips_signum, NULL, NULL);
621
622 ALOGV("%s: return; }", __func__);
623 }
624
625
sighandler_pton(sighandler_portable_t portable_handler,int sigaction)626 static sighandler_t sighandler_pton(sighandler_portable_t portable_handler, int sigaction)
627 {
628 sighandler_t mips_handler;
629
630 ALOGV("%s(portable_handler:%p, sigaction:%d) {", __func__,
631 portable_handler, sigaction);
632
633 switch((int) portable_handler) {
634 case (int) SIG_DFL:
635 case (int) SIG_IGN:
636 mips_handler = portable_handler;
637 break;
638
639 default: /* NOTE: Includes SIG_ERR:-1 */
640 if (invalid_pointer(portable_handler)) {
641 /*
642 * Calling sigaction() with a bogus signal handler doesn't fail,
643 * so we let the portable cases fail later as the native case would.
644 */
645 ALOGE("%s: invalid_pointer(portable_handler:%p)!", __func__, portable_handler);
646 ALOGE("%s: HINT: Likely to cause a BUS Error ....", __func__);
647 ALOGE("%s: HINT: ... when the signal handler is called!", __func__);
648 }
649
650 /*
651 * Signal Mapping can be disabled in the rare case of the clone
652 * flags not being compatble for VM and file descriptors.
653 */
654 if (signal_handler_mapping_enabled) {
655 if (sigaction)
656 mips_handler = (sighandler_t) mips_sigaction_handler;
657 else
658 mips_handler = (sighandler_t) mips_sighandler;
659 } else {
660 mips_handler = portable_handler; /* Don't MAP */
661 }
662 break;
663 }
664
665 ALOGV("%s: return(mips_handler:%p); }", __func__, mips_handler);
666 return mips_handler;
667 }
668
669
670 /*
671 * This function maps the signal number and calls one of the low level mips signal()
672 * functions implemented in libc/unistd/signal.c:
673 * sysv_signal()
674 * bsd_signal()
675 *
676 * The last 2 parameters to this static function, mips_signal_fn*, specify which of
677 * these functions to call. We intercept the above to functions, as well as signal(),
678 * and call the associated *_portable() functions below.
679 *
680 * In addition, we intercept the signal_handler with our own handlers that map the
681 * signal number from the MIPS convention to the PORTABLE/ARM convention.
682 */
683 static sighandler_portable_t
do_signal_portable(int portable_signum,sighandler_portable_t portable_handler,__sighandler_t (mips_signal_fn)(int,__sighandler_t))684 do_signal_portable(int portable_signum, sighandler_portable_t portable_handler,
685 __sighandler_t (mips_signal_fn)(int, __sighandler_t))
686 {
687 char *portable_signame = map_portable_signum_to_name(portable_signum);
688 int mips_signum;
689 sighandler_t mips_handler;
690 sighandler_portable_t rv;
691 sighandler_portable_t prev_portable_handler;
692
693 ALOGV("%s(portable_signum:%d:%s, portable_handler:%p, mips_signal_fn:%p) {", __func__,
694 portable_signum,
695 portable_signame, portable_handler, mips_signal_fn);
696
697 mips_signum = signum_pton(portable_signum);
698
699 if ((portable_signum != 0) && ((mips_signum <= 0) || (mips_signum > NSIG))) {
700 /*
701 * Invalid request; Let the kernel generate the proper return value and set errno.
702 */
703 mips_handler = sighandler_pton(portable_handler, 0);
704 rv = mips_signal_fn(mips_signum, mips_handler);
705 } else {
706 /*
707 * We have a usable signal number, redirect it to our signal handler
708 * if a portable handler was provided so we can convert the signal number.
709 * Save our current mapped signal handler for likely return.
710 */
711 prev_portable_handler = (sighandler_portable_t) mips_portable_sighandler[portable_signum];
712
713 mips_handler = sighandler_pton(portable_handler, 0);
714 if (mips_handler != portable_handler) {
715 mips_portable_sighandler[portable_signum] = (sig3handler_portable_t) portable_handler;
716 }
717 rv = mips_signal_fn(mips_signum, mips_handler);
718
719 if ((rv == (sighandler_portable_t) mips_sighandler) ||
720 (rv == (sighandler_portable_t) mips_sigaction_handler)) {
721
722 rv = (sighandler_t) prev_portable_handler;
723 }
724 }
725
726 ALOGV("%s: return(rv:%p); }", __func__, rv);
727 return rv;
728 }
729
730
731 /*
732 * signal() can't be called directly, due to an in-line function in signal.h which
733 * redirects the call to bsd_signal(). _signal() is a static function; not to be called
734 * directly. This function isn't actually needed.
735 */
WRAP(signal)736 sighandler_portable_t WRAP(signal)(int portable_signum, sighandler_portable_t handler)
737 {
738 sighandler_portable_t rv;
739
740 ALOGV(" ");
741 ALOGV("%s(portable_signum:%d, handler:%p) {", __func__,
742 portable_signum, handler);
743
744 /* bsd does a SA_RESTART */
745 rv = do_signal_portable(portable_signum, handler, bsd_signal);
746
747 ALOGV("%s: return(ret:%p); }", __func__, rv);
748 return rv;
749 }
750
751
WRAP(sysv_signal)752 sighandler_portable_t WRAP(sysv_signal)(int portable_signum, sighandler_portable_t handler)
753 {
754 sighandler_portable_t rv;
755
756 ALOGV(" ");
757 ALOGV("%s(portable_signum:%d, handler:%p) {", __func__,
758 portable_signum, handler);
759
760 /* sysv does a SA_RESETHAND */
761 rv = do_signal_portable(portable_signum, handler, sysv_signal);
762
763 ALOGV("%s: return(ret:%p); }", __func__, rv);
764 return rv;
765 }
766
767
768 /*
769 * NOTE:
770 * handler is either the Bionic
771 * bsd_signal() signal handler
772 * or
773 * the sysv_signal() signal handler.
774 */
775
WRAP(bsd_signal)776 sighandler_portable_t WRAP(bsd_signal)(int portable_signum, sighandler_portable_t handler)
777 {
778 sighandler_portable_t rv;
779
780 ALOGV(" ");
781 ALOGV("%s(portable_signum:%d, handler:%p) {", __func__,
782 portable_signum, handler);
783
784 /* bsd does a SA_RESTART */
785 rv = do_signal_portable(portable_signum, handler, bsd_signal);
786
787 ALOGV("%s: return(ret:%p); }", __func__, rv);
788 return rv;
789 }
790
791
do_kill(int id,int portable_signum,int (* fn)(int,int))792 static int do_kill(int id, int portable_signum, int (*fn)(int, int))
793 {
794 char *portable_signame = map_portable_signum_to_name(portable_signum);
795 int mips_signum;
796 int rv;
797
798 ALOGV("%s(id:%d, portable_signum:%d:'%s', fn:%p) {", __func__,
799 id, portable_signum,
800 portable_signame, fn);
801
802 mips_signum = signum_pton(portable_signum);
803
804 if ((portable_signum != 0) && (mips_signum == 0)) {
805 rv = 0;
806 } else {
807 ALOGV("%s: Calling fn:%p(id:%d, mips_signum:%d);", __func__,
808 fn, id, mips_signum);
809
810 rv = fn(id, mips_signum);
811 }
812 ALOGV("%s: return(rv:%d); }", __func__, rv);
813 return rv;
814 }
815
816
WRAP(killpg)817 int WRAP(killpg)(int pgrp, int portable_signum)
818 {
819 extern int REAL(killpg)(int pgrp, int sig);
820 int rv;
821
822 ALOGV(" ");
823 ALOGV("%s(pgrp:%d, portable_signum:%d) {", __func__,
824 pgrp, portable_signum);
825
826 rv = do_kill(pgrp, portable_signum, REAL(killpg));
827
828 ALOGV("%s: return(rv:%d); }", __func__, rv);
829 return rv;
830 }
831
832
WRAP(kill)833 int WRAP(kill)(pid_t pid, int portable_signum)
834 {
835 extern int REAL(kill)(pid_t, int);
836 int rv;
837
838 ALOGV(" ");
839 ALOGV("%s(pid:%d, portable_signum:%d) {", __func__,
840 pid, portable_signum);
841
842 rv = do_kill(pid, portable_signum, REAL(kill));
843
844 ALOGV("%s: return(rv:%d); }", __func__, rv);
845 return rv;
846 }
847
848
WRAP(tkill)849 int WRAP(tkill)(int tid, int portable_signum)
850 {
851 extern int REAL(tkill)(int, int);
852 int rv;
853
854 ALOGV(" ");
855 ALOGV("%s(tid:%d, portable_signum:%d) {", __func__,
856 tid, portable_signum);
857
858 rv = do_kill(tid, portable_signum, REAL(tkill));
859
860 ALOGV("%s: return(rv:%d); }", __func__, rv);
861 return rv;
862 }
863
864
865 /* tgkill is not exported from android-14 libc.so */
866 #if 0
867 int WRAP(tgkill)(int tgid, int tid, int portable_signum)
868 {
869 extern int tgkill(int, int, int);
870 char *portable_signame = map_portable_signum_to_name(portable_signum);
871 int mips_signum;
872 int rv;
873
874 ALOGV("%s(tgid:%d, tid:%d, portable_signum:%d:'%s') {", __func__,
875 tgid, tid, portable_signum, portable_signame);
876
877 mips_signum = signum_pton(portable_signum);
878
879 if ((portable_signum != 0) && (mips_signum == 0))
880 rv = 0;
881 else
882 rv = REAL(tgkill)(tgid, tid, mips_signum);
883
884 ALOGV("%s: return rv:%d; }", __func__, rv);
885 return rv;
886 }
887 #endif
888
889
WRAP(raise)890 int WRAP(raise)(int portable_signum)
891 {
892 char *portable_signame = map_portable_signum_to_name(portable_signum);
893 int mips_signum = signum_pton(portable_signum);
894 int rv;
895
896 ALOGV("%s(portable_signum:%d:'%s') {", __func__, portable_signum, portable_signame);
897
898 if ((portable_signum != 0) && (mips_signum == 0))
899 rv = 0;
900 else
901 rv = REAL(raise)(mips_signum);
902
903 ALOGV("%s: return(rv:%d); }", __func__, rv);
904 return rv;
905 }
906
907
sigset_pton(sigset_portable_t * portable_sigset,sigset_t * mips_sigset)908 void sigset_pton(sigset_portable_t *portable_sigset, sigset_t *mips_sigset)
909 {
910 int portable_signum;
911
912 ASSERT(mips_sigset != NULL);
913
914 ALOGV("%s(portable_sigset:%p, mips_sigset:%p) {", __func__,
915 portable_sigset, mips_sigset);
916
917 sigemptyset(mips_sigset);
918 if (invalid_pointer((void *)portable_sigset)) {
919 ALOGE("%s: portable_sigset:%p is not valid; returning empty set.", __func__,
920 portable_sigset);
921 goto done;
922 }
923
924 for(portable_signum = 1; portable_signum <= NSIG_PORTABLE; portable_signum++) {
925
926 if (WRAP(sigismember)(portable_sigset, portable_signum)) {
927 char *portable_signame = map_portable_signum_to_name(portable_signum);
928 int mips_signum = signum_pton(portable_signum);
929 char *mips_signame;
930
931 if (mips_signum != 0) {
932 int err;
933
934 mips_signame = map_mips_signum_to_name(mips_signum);
935 ALOGV("%s: sigaddset(mips_sigset:%p, mips_signum:%d:'%s');", __func__,
936 mips_sigset, mips_signum,
937 mips_signame);
938
939 err = sigaddset(mips_sigset, mips_signum);
940 if (err == -1) {
941 PERROR("sigaddset");
942 }
943 }
944 }
945 }
946
947 done:
948 ALOGV("%s: return; }", __func__);
949 return;
950 }
951
952
953 void
sigset_ntop(const sigset_t * const_mips_sigset,sigset_portable_t * portable_sigset)954 sigset_ntop(const sigset_t *const_mips_sigset, sigset_portable_t *portable_sigset)
955 {
956 int mips_signum;
957 sigset_t *mips_sigset = (sigset_t *) const_mips_sigset;
958
959 ALOGV("%s(const_mips_sigset:%p, portable_sigset:%p) {", __func__,
960 const_mips_sigset, portable_sigset);
961
962 ASSERT(mips_sigset != NULL);
963
964 if (invalid_pointer((void *)portable_sigset)) {
965 ALOGE("%s: portable_sigset:%p is not Valid; can't return sigset", __func__,
966 portable_sigset);
967 goto done;
968 }
969 WRAP(sigemptyset)(portable_sigset);
970
971 for(mips_signum = 1; mips_signum <= NSIG; mips_signum++) {
972 if (sigismember(mips_sigset, mips_signum)) {
973 int portable_signum = signum_ntop(mips_signum);
974
975 if (portable_signum != 0)
976 WRAP(sigaddset)(portable_sigset, portable_signum);
977 }
978 }
979
980 done:
981 ALOGV("%s: return; }", __func__);
982 return;
983 }
984
985
sigaction_flags_pton(int portable_flags)986 static int sigaction_flags_pton(int portable_flags)
987 {
988 int mips_flags = 0;
989
990 if (portable_flags & SA_NOCLDSTOP_PORTABLE) {
991 mips_flags |= SA_NOCLDSTOP;
992 }
993 if (portable_flags & SA_NOCLDWAIT_PORTABLE) {
994 mips_flags |= SA_NOCLDWAIT;
995 }
996 if (portable_flags & SA_SIGINFO_PORTABLE) {
997 mips_flags |= SA_SIGINFO;
998 }
999 if (portable_flags & SA_THIRTYTWO_PORTABLE) {
1000 ALOGV("%s: SA_THIRTYTWO_PORTABLE isn't SUPPORTED.", __func__);
1001 }
1002 if (portable_flags & SA_RESTORER_PORTABLE) {
1003 mips_flags |= SA_RESTORER;
1004 }
1005 if (portable_flags & SA_ONSTACK_PORTABLE) {
1006 mips_flags |= SA_ONSTACK;
1007 }
1008 if (portable_flags & SA_RESTART_PORTABLE) {
1009 mips_flags |= SA_RESTART;
1010 }
1011 if (portable_flags & SA_NODEFER_PORTABLE) {
1012 mips_flags |= SA_NODEFER;
1013 }
1014 if (portable_flags & SA_RESETHAND_PORTABLE) {
1015 mips_flags |= SA_RESETHAND;
1016 }
1017
1018 ALOGV("%s(portable_flags:0x%x) return(mips_flags:0x%x);", __func__,
1019 portable_flags, mips_flags);
1020
1021 return mips_flags;
1022 }
1023
1024
sigaction_flags_ntop(int mips_flags)1025 int sigaction_flags_ntop(int mips_flags)
1026 {
1027 int portable_flags = 0;
1028
1029 if (mips_flags & SA_NOCLDSTOP) portable_flags |= SA_NOCLDSTOP_PORTABLE;
1030 if (mips_flags & SA_NOCLDWAIT) portable_flags |= SA_NOCLDWAIT_PORTABLE;
1031 if (mips_flags & SA_SIGINFO) portable_flags |= SA_SIGINFO_PORTABLE;
1032 #ifdef SA_THIRTYTWO
1033 if (mips_flags & SA_THIRTYTWO) portable_flags |= SA_THIRTYTWO_PORTABLE;
1034 #endif
1035 if (mips_flags & SA_RESTORER) portable_flags |= SA_RESTORER_PORTABLE;
1036 if (mips_flags & SA_ONSTACK) portable_flags |= SA_ONSTACK_PORTABLE;
1037 if (mips_flags & SA_RESTART) portable_flags |= SA_RESTART_PORTABLE;
1038 if (mips_flags & SA_NODEFER) portable_flags |= SA_NODEFER_PORTABLE;
1039 if (mips_flags & SA_RESETHAND) portable_flags |= SA_RESETHAND_PORTABLE;
1040
1041 ALOGV("%s(mips_flags:0x%x) return(portable_flags:0x%x);", __func__,
1042 mips_flags, portable_flags);
1043
1044 return portable_flags;
1045 }
1046
1047
1048 /*
1049 * Called by portable/ARM code, which we map and do MIPS system calls.
1050 *
1051 * The incoming system call used a Portable/ARM sigaction structure:
1052 * ------------------------------------------------------------------
1053 * struct sigaction_portable {
1054 * union {
1055 * __sighandler_portable_t _sa_handler;
1056 * __sigaction_handler_portable_t _sa_sigaction;
1057 * } _u;
1058 * sigset_portable_t sa_mask;
1059 * unsigned long sa_flags;
1060 * void (*sa_restorer)(void);
1061 * };
1062 *
1063 * A similar, but different, structure is used in the MIPS/Native system call:
1064 * ---------------------------------------------------------------------------
1065 * struct sigaction {
1066 * unsigned int sa_flags;
1067 * union {
1068 * __sighandler_t sa_handler;
1069 * __sigaction_handler_portable_t _sa_sigaction;
1070 * } __u;
1071 * sigset_t sa_mask;
1072 * };
1073 *
1074 * This sigaction structure needs to be mapped before the MIPS systems call as well as after for
1075 * returning the old/previous sigaction. Also, like signal_portable() above, we need to maintain
1076 * a table of signal handlers that our intercepting handler can call after it converts the signal
1077 * numbers.
1078 */
do_sigaction_portable(int portable_signum,const struct sigaction_portable * act,struct sigaction_portable * oldact,sigaction_fn fn,rt_sigaction_fn rt_fn)1079 static int do_sigaction_portable(int portable_signum, const struct sigaction_portable *act,
1080 struct sigaction_portable *oldact, sigaction_fn fn,
1081 rt_sigaction_fn rt_fn)
1082 {
1083 int mips_signum;
1084 char *mips_signame;
1085 struct sigaction mips_act;
1086 struct sigaction *mips_act_ptr;
1087 struct sigaction mips_oldact;
1088 sighandler_t mips_handler;
1089 sighandler_portable_t portable_handler;
1090 sig3handler_portable_t prev_portable_handler;
1091 char *portable_signame = map_portable_signum_to_name(portable_signum);
1092 int rv;
1093
1094 ALOGV("%s(portable_signum:%d:'%s', act:%p, oldact:%p, fn:%p, rt_fn:%p) {", __func__,
1095 portable_signum,
1096 portable_signame, act, oldact, fn, rt_fn);
1097
1098 mips_signum = signum_pton(portable_signum);
1099 mips_signame = map_mips_signum_to_name(mips_signum);
1100
1101 if ((portable_signum != 0) && (mips_signum == 0)) {
1102 /* We got a portable signum that we can't map; Ignore the request */
1103 rv = 0;
1104 goto done;
1105 }
1106 if (portable_signum > 0 && portable_signum <= NSIG_PORTABLE)
1107 prev_portable_handler = mips_portable_sighandler[portable_signum];
1108 else
1109 prev_portable_handler = NULL;
1110
1111 memset(&mips_act, 0, sizeof(mips_act));
1112
1113 if (invalid_pointer((void *)act)) {
1114 mips_act_ptr = (struct sigaction *)act;
1115 } else {
1116 /*
1117 * Make the MIPS version of sigaction, which has no sa_restorer function pointer.
1118 * Also the handler will be called with a pointer to a to a sigcontext structure
1119 * which is totally non-portable.
1120 */
1121 sigset_pton(((sigset_portable_t *)&act->sa_mask),
1122 ((sigset_t *) &mips_act.sa_mask));
1123
1124 mips_act.sa_flags = sigaction_flags_pton(act->sa_flags);
1125
1126 if (mips_act.sa_flags & SA_SIGINFO) {
1127 /*
1128 * Providing the three argument version of a signal handler.
1129 */
1130 portable_handler = (sighandler_portable_t) act->sa_sigaction_portable;
1131 if ((portable_signum <= 0) || (portable_signum > NSIG_PORTABLE)) {
1132 /*
1133 * Let the kernel generate the proper return value and set errno.
1134 */
1135 mips_act.sa_sigaction = (sig3handler_t) portable_handler;
1136 } else {
1137 mips_handler = sighandler_pton(portable_handler, 1);
1138 if (mips_handler != portable_handler) {
1139 mips_portable_sighandler[portable_signum] =
1140 (sig3handler_portable_t) portable_handler;
1141 }
1142 mips_act.sa_sigaction = (sig3handler_t) mips_handler;
1143 }
1144 } else {
1145 /*
1146 * Providing the classic single argument version of a signal handler.
1147 */
1148 portable_handler = act->sa_handler_portable;
1149 if ((portable_signum <= 0) || (portable_signum > NSIG_PORTABLE)) {
1150 /*
1151 * Let the kernel generate the proper return value and set errno.
1152 */
1153 mips_act.sa_handler = (sighandler_t) portable_handler;
1154 } else {
1155 mips_handler = sighandler_pton(portable_handler, 1);
1156 if (mips_handler != portable_handler) {
1157 mips_portable_sighandler[portable_signum] =
1158 (sig3handler_portable_t) portable_handler;
1159 }
1160 mips_act.sa_handler = mips_handler;
1161 }
1162 }
1163 mips_act_ptr = &mips_act;
1164 }
1165
1166 if (fn != NULL) {
1167 ASSERT(rt_fn == NULL);
1168 rv = fn(mips_signum, mips_act_ptr, &mips_oldact);
1169 } else {
1170 ASSERT(rt_fn != NULL);
1171 rv = rt_fn(mips_signum, mips_act_ptr, &mips_oldact, sizeof(sigset_t));
1172 }
1173
1174 if (rv == 0 && oldact) {
1175 if (mips_oldact.sa_sigaction == (__sigaction_handler_portable_t) mips_sigaction_handler ||
1176 mips_oldact.sa_sigaction == (__sigaction_handler_portable_t) mips_sighandler) {
1177
1178 oldact->sa_sigaction_portable =
1179 (__sigaction_handler_portable_t) prev_portable_handler;
1180 } else {
1181 oldact->sa_sigaction_portable =
1182 (__sigaction_handler_portable_t) mips_oldact.sa_sigaction;
1183 }
1184 sigset_ntop((sigset_t *) &(mips_oldact.sa_mask),
1185 (sigset_portable_t *) &(oldact->sa_mask));
1186
1187 oldact->sa_flags = sigaction_flags_ntop(mips_oldact.sa_flags);
1188 oldact->sa_restorer = NULL;
1189 }
1190
1191 done:
1192 ALOGV("%s: return(rv:%d); }", __func__, rv);
1193 return rv;
1194 }
1195
1196
WRAP(sigaction)1197 int WRAP(sigaction)(int portable_signum, const struct sigaction_portable *act,
1198 struct sigaction_portable *oldact)
1199 {
1200 extern int REAL(sigaction)(int, const struct sigaction *, struct sigaction *);
1201 int rv;
1202
1203 ALOGV(" ");
1204 ALOGV("%s(portable_signum:%d, act:%p, oldact:%p) {", __func__,
1205 portable_signum, act, oldact);
1206
1207 rv = do_sigaction_portable(portable_signum, act, oldact, REAL(sigaction), NULL);
1208
1209 ALOGV("%s: return(rv:%d); }", __func__, rv);
1210 return rv;
1211 }
1212
1213
1214 /*
1215 * Currently signalfd() isn't supported by bionic with
1216 * only the portable syscall.c code using this code by
1217 * intercepting the syscall(__NR_signalfd4, ...) in bionic.
1218 */
do_signalfd4_portable(int fd,const sigset_portable_t * portable_sigmask,int portable_sigsetsize,int portable_flags)1219 __hidden int do_signalfd4_portable(int fd, const sigset_portable_t *portable_sigmask,
1220 int portable_sigsetsize, int portable_flags)
1221 {
1222 sigset_t native_sigmask;
1223 int native_sigsetsize = sizeof(native_sigmask);
1224 int native_flags = 0;
1225 int rv;
1226
1227 ALOGV("%s(fd:%d, portable_sigmask:%p, portable_sigsetsize:%d, portable_flags:0x%x) {",
1228 __func__, fd, portable_sigmask, portable_sigsetsize, portable_flags);
1229
1230 sigset_pton((sigset_portable_t *)portable_sigmask, &native_sigmask);
1231
1232 if (portable_flags & SFD_NONBLOCK_PORTABLE) {
1233 native_flags |= SFD_NONBLOCK;
1234 }
1235 if (portable_flags & SFD_CLOEXEC_PORTABLE) {
1236 native_flags |= SFD_CLOEXEC;
1237 }
1238 rv = syscall(__NR_signalfd4, fd, &native_sigmask, native_sigsetsize, native_flags);
1239
1240 if (rv >= 0) {
1241 if (native_flags & SFD_CLOEXEC) {
1242 filefd_CLOEXEC_enabled(rv);
1243 }
1244
1245 /*
1246 * Reads on this file descriptor must be mapped to be portable.
1247 * The mapping should survive a fork and most clones naturally.
1248 * For the system call to be completely portable it has to propagate
1249 * these mapped files after an execve(). Environment variables have
1250 * been added to do that. See filefd.c for details.
1251 */
1252 filefd_opened(rv, SIGNAL_FD_TYPE);
1253 }
1254
1255 ALOGV("%s: return(rv:%d); }", __func__, rv);
1256 return rv;
1257 }
1258
1259
1260 #if 0
1261 /*
1262 * signalfd() isn't available in Bionic yet. When it is, it will be implemented like
1263 * the glibc version where the sigsetsize is computed in the bionic code and passed
1264 * down to the kernel with __NR_signalfd4.
1265 *
1266 * This function can't be called from bionic, so there isn't an entry in the experimental
1267 * linker.cpp table for testing and this function.
1268 */
1269 int WRAP(signalfd)(int fd, const sigset_portable_t *portable_sigmask, int portable_flags)
1270 {
1271 int portable_sigsetsize = sizeof(sigset_portable_t);
1272 int rv;
1273
1274 ALOGV("%s(fd:%d, portable_sigmask:%p, portable_flags:0x%x) {", __func__,
1275 fd, portable_sigmask, portable_flags);
1276
1277 rv = do_signalfd4_portable(fd, portable_sigsetsize, portable_sigmask, portable_flags);
1278
1279 ALOGV("%s: return(rv:%d); }", __func__, rv);
1280 return rv;
1281 }
1282 #endif
1283
1284
1285 /*
1286 * Called by read_portable() to do signalfd read() mapping.
1287 */
read_signalfd_mapper(int fd,void * buf,size_t count)1288 __hidden int read_signalfd_mapper(int fd, void *buf, size_t count)
1289 {
1290 int rv;
1291
1292 ALOGV("%s(fd:%d, buf:0x%p, count:%d) {", __func__,
1293 fd, buf, count);
1294
1295 rv = read(fd, buf, count);
1296 if (rv > 0) {
1297 int siginfos = rv/sizeof(struct signalfd_siginfo);
1298 struct signalfd_siginfo *si = (struct signalfd_siginfo *) buf;
1299 int i;
1300
1301 /* Read signalfd_siginfo structure(s) if read is large enough */
1302 for (i = 0; i < siginfos; i++, si++) {
1303 int ssi_signo;
1304
1305 ssi_signo = si->ssi_signo;
1306 si->ssi_signo = signum_ntop(si->ssi_signo);
1307 ALOGV("%s: si->ssi_signo:%d = signum_ntop(si->ssi_signo:%d); i:%d", __func__,
1308 si->ssi_signo, ssi_signo, i);
1309
1310 si->ssi_errno = errno_ntop(si->ssi_errno);
1311
1312 /*
1313 * The ssi_codes appear to be generic; defined in
1314 * the kernel in include/asm-generic/siginfo.h
1315 */
1316 if (si->ssi_status > 0 && si->ssi_status <= NSIG) {
1317 si->ssi_status = signum_ntop(si->ssi_status);
1318 }
1319
1320 /*
1321 * The rest of the struct members, like
1322 * ssi_trapno, ssi_int, ssi_ptr
1323 * are not likely worth dealing with.
1324 */
1325 }
1326 }
1327
1328 ALOGV("%s: return(rv:%d); }", __func__, rv);
1329 return rv;
1330 }
1331
WRAP(sigsuspend)1332 int WRAP(sigsuspend)(const sigset_portable_t *portable_sigmask)
1333 {
1334 int rv;
1335 sigset_t mips_sigmask;
1336
1337 ALOGV("%s(portable_sigmask:%p) {", __func__, portable_sigmask);
1338
1339 if (invalid_pointer((void *)portable_sigmask)) {
1340 *REAL(__errno)() = EFAULT;
1341 rv = -1;
1342 } else {
1343 sigset_pton((sigset_portable_t *)portable_sigmask, &mips_sigmask);
1344 rv = REAL(sigsuspend)(&mips_sigmask);
1345 }
1346
1347 ALOGV("%s: return(rv:%d); }", __func__, rv);
1348 return rv;
1349 }
1350
1351
WRAP(sigpending)1352 int WRAP(sigpending)(sigset_portable_t *portable_sigset)
1353 {
1354 int rv;
1355 sigset_t mips_sigset;
1356
1357 ALOGV("%s(portable_sigset:%p) {", __func__,
1358 portable_sigset);
1359
1360 if (invalid_pointer((void *)portable_sigset)) {
1361 *REAL(__errno)() = EFAULT;
1362 rv = -1;
1363 } else {
1364 rv = REAL(sigpending)(&mips_sigset);
1365 sigset_ntop(&mips_sigset, portable_sigset);
1366 }
1367
1368 ALOGV("%s: return(rv:%d); }", __func__, rv);
1369 return rv;
1370 }
1371
1372
WRAP(sigwait)1373 int WRAP(sigwait)(const sigset_portable_t *portable_sigset, int *ptr_to_portable_sig)
1374 {
1375 int rv;
1376 sigset_t mips_sigset;
1377 int mips_sig;
1378 int portable_sig;
1379
1380 ALOGV("%s(portable_sigset:%p, ptr_to_portable_sig:%p) {", __func__,
1381 portable_sigset, ptr_to_portable_sig);
1382
1383 if (invalid_pointer((void *)portable_sigset)) {
1384 *REAL(__errno)() = EFAULT;
1385 rv = -1;
1386 } else {
1387 sigset_pton((sigset_portable_t *)portable_sigset, &mips_sigset);
1388
1389 rv = REAL(sigwait)(&mips_sigset, &mips_sig);
1390
1391 portable_sig = signum_ntop(mips_sig);
1392 *ptr_to_portable_sig = portable_sig;
1393 }
1394 ALOGV("%s: return(rv:%d); }", __func__, rv);
1395 return rv;
1396 }
1397
1398
WRAP(siginterrupt)1399 int WRAP(siginterrupt)(int portable_signum, int flag)
1400
1401 {
1402 int rv;
1403 int mips_signum;
1404
1405 ALOGV("%s(portable_signum:%d, flag:0x%x) {", __func__,
1406 portable_signum, flag);
1407
1408 mips_signum = signum_pton(portable_signum);
1409
1410 if ((portable_signum != 0) && (mips_signum == 0)) {
1411 ALOGE("%s: Unsupported portable_signum:%d; Ignoring.", __func__,
1412 portable_signum);
1413 rv = 0;
1414 } else {
1415 rv = REAL(siginterrupt)(mips_signum, flag);
1416 }
1417 ALOGV("%s: return(rv:%d); }", __func__, rv);
1418 return rv;
1419 }
1420
1421
do_sigmask(int portable_how,const sigset_portable_t * portable_sigset,sigset_portable_t * portable_oldset,sigmask_fn fn,rt_sigmask_fn rt_fn)1422 __hidden int do_sigmask(int portable_how, const sigset_portable_t *portable_sigset,
1423 sigset_portable_t *portable_oldset, sigmask_fn fn,
1424 rt_sigmask_fn rt_fn)
1425 {
1426 int rv;
1427 int how;
1428 char *how_name;
1429 sigset_t mips_sigset, *mips_sigset_p;
1430 sigset_t mips_oldset, *mips_oldset_p;
1431
1432 ALOGV("%s(portable_how:%d, portable_sigset:%p, portable_oldset:%p, fn:%p, rt_fn:%p) {",
1433 __func__, portable_how, portable_sigset, portable_oldset, fn, rt_fn);
1434
1435 switch(portable_how) {
1436 case SIG_BLOCK_PORTABLE: how = SIG_BLOCK; how_name = "SIG_BLOCK"; break;
1437 case SIG_UNBLOCK_PORTABLE: how = SIG_UNBLOCK; how_name = "SIG_UNBLOCK"; break;
1438 case SIG_SETMASK_PORTABLE: how = SIG_SETMASK; how_name = "SIG_SETMASK"; break;
1439
1440 default:
1441 ALOGE("%s: portable_how:%d NOT SUPPORTED!", __func__, portable_how);
1442 how = -1;
1443 break;
1444 }
1445
1446 if (invalid_pointer((void *)portable_sigset)) {
1447 mips_sigset_p = (sigset_t *) portable_sigset;
1448 } else {
1449 mips_sigset_p = &mips_sigset;
1450 memset(mips_sigset_p, 0, sizeof(mips_sigset));
1451 sigemptyset(mips_sigset_p);
1452 sigset_pton((sigset_portable_t *)portable_sigset, &mips_sigset);
1453 }
1454
1455 if (invalid_pointer((void *)portable_oldset)) {
1456 mips_oldset_p = (sigset_t *) portable_oldset;
1457 } else {
1458 mips_oldset_p = &mips_oldset;
1459 memset(mips_oldset_p, 0, sizeof(mips_oldset));
1460 sigemptyset(mips_oldset_p);
1461 }
1462
1463 if (fn != NULL) {
1464 ASSERT(rt_fn == NULL);
1465 rv = fn(how, mips_sigset_p, mips_oldset_p);
1466 } else {
1467 ASSERT(rt_fn != NULL);
1468 rv = rt_fn(how, mips_sigset_p, mips_oldset_p, sizeof(sigset_t));
1469 }
1470
1471 if (rv == 0 && !invalid_pointer(portable_oldset)) {
1472 /* Map returned mips_oldset to portable_oldset for return to caller */
1473 sigset_ntop(mips_oldset_p, portable_oldset);
1474 }
1475
1476 ALOGV("%s: return(rv:%d); }", __func__, rv);
1477 return rv;
1478 }
1479
1480
WRAP(sigprocmask)1481 int WRAP(sigprocmask)(int portable_how, const sigset_portable_t *portable_sigset,
1482 sigset_portable_t *portable_oldset)
1483 {
1484 extern int REAL(sigprocmask)(int, const sigset_t *, sigset_t *);
1485 int rv;
1486
1487 ALOGV(" ");
1488 ALOGV("%s(portable_how:%d, portable_sigset:%p, portable_oldset:%p) {", __func__,
1489 portable_how, portable_sigset, portable_oldset);
1490
1491 rv = do_sigmask(portable_how, portable_sigset, portable_oldset, REAL(sigprocmask), NULL);
1492
1493 ALOGV("%s: return(rv:%d); }", __func__, rv);
1494 return rv;
1495 }
1496
1497
WRAP(__rt_sigaction)1498 int WRAP(__rt_sigaction)(int portable_signum, const struct sigaction_portable *act,
1499 struct sigaction_portable *oldact, size_t sigsetsize)
1500 {
1501 extern int REAL(__rt_sigaction)(int , const struct sigaction *, struct sigaction *, size_t);
1502 int rv;
1503
1504 ALOGV(" ");
1505 ALOGV("%s(portable_signum:%d, act:%p, oldset:%p, sigsetsize:%d) {", __func__,
1506 portable_signum, act, oldact, sigsetsize);
1507
1508 /* NOTE: ARM kernel is expecting sizeof(sigset_t) to be 8 bytes */
1509 if (sigsetsize != (2* sizeof(long))) {
1510 *REAL(__errno)() = EINVAL;
1511 rv = -1;
1512 goto done;
1513 }
1514 rv = do_sigaction_portable(portable_signum, act, oldact, NULL, REAL(__rt_sigaction));
1515
1516 done:
1517 ALOGV("%s: return(rv:%d); }", __func__, rv);
1518 return rv;
1519 }
1520
WRAP(__rt_sigprocmask)1521 int WRAP(__rt_sigprocmask)(int portable_how,
1522 const sigset_portable_t *portable_sigset,
1523 sigset_portable_t *portable_oldset,
1524 size_t sigsetsize)
1525 {
1526 extern int REAL(__rt_sigprocmask)(int, const sigset_t *, sigset_t *, size_t);
1527 int rv;
1528
1529 ALOGV(" ");
1530 ALOGV("%s(portable_how:%d, portable_sigset:%p, portable_oldset:%p, sigsetsize:%d) {",
1531 __func__, portable_how, portable_sigset, portable_oldset, sigsetsize);
1532
1533 /* NOTE: ARM kernel is expecting sizeof(sigset_t) to be 8 bytes */
1534 if (sigsetsize != (2* sizeof(long))) {
1535 *REAL(__errno)() = EINVAL;
1536 rv = -1;
1537 goto done;
1538 }
1539 rv = do_sigmask(portable_how, portable_sigset, portable_oldset, NULL, REAL(__rt_sigprocmask));
1540
1541 done:
1542 ALOGV("%s: return(rv:%d); }", __func__, rv);
1543
1544 return rv;
1545 }
1546
1547
WRAP(__rt_sigtimedwait)1548 int WRAP(__rt_sigtimedwait)(const sigset_portable_t *portable_sigset,
1549 siginfo_portable_t *portable_siginfo,
1550 const struct timespec *timeout,
1551 size_t portable_sigsetsize)
1552 {
1553 extern int REAL(__rt_sigtimedwait)(const sigset_t *, siginfo_t *, const struct timespec *, size_t);
1554
1555 sigset_t native_sigset_struct;
1556 sigset_t *native_sigset = &native_sigset_struct;
1557 siginfo_t native_siginfo_struct;
1558 siginfo_t *native_siginfo;
1559 int rv;
1560
1561 ALOGV(" ");
1562 ALOGV("%s(portable_sigset:%p, portable_siginfo:%p, timeout:%p, portable_sigsetsize:%d) {",
1563 __func__, portable_sigset, portable_siginfo, timeout, portable_sigsetsize);
1564
1565 /* NOTE: ARM kernel is expecting sizeof(sigset_t) to be 8 bytes */
1566 if (portable_sigsetsize != (2* sizeof(long))) {
1567 *REAL(__errno)() = EINVAL;
1568 rv = -1;
1569 goto done;
1570 }
1571 if (portable_sigset == NULL) {
1572 native_sigset = NULL;
1573 } else {
1574 sigset_pton((sigset_portable_t *)portable_sigset, native_sigset);
1575 }
1576 if (portable_siginfo == NULL) {
1577 native_siginfo = NULL;
1578 } else {
1579 native_siginfo = &native_siginfo_struct;
1580 }
1581 rv = REAL(__rt_sigtimedwait)(native_sigset, native_siginfo, timeout, sizeof(sigset_t));
1582 if (rv == 0 && native_siginfo != NULL) {
1583 /* Map siginfo struct from native to portable format. */
1584 siginfo_ntop(native_siginfo, portable_siginfo);
1585 }
1586
1587 done:
1588 ALOGV("%s: return(rv:%d); }", __func__, rv);
1589 return rv;
1590 }
1591
1592
1593 #ifdef __NR_rt_sigqueueinfo
1594
1595 #if 0
1596 /*
1597 * sigqueue():
1598 * This function became available in UNIX GLIBC after 1993.
1599 * It's not available in any versions of Android yet, and
1600 * it can't be called via syscall(). It's been useful for
1601 * testing with the LTP by the posix testsuite, and tests
1602 * show that it works fine.
1603 *
1604 * NOTE:
1605 * Android has in incorrect limit on the number of queueable signals
1606 * defined in libc/unistd/sysconf.c:
1607 *
1608 * #define SYSTEM_SIGQUEUE_MAX 32
1609 *
1610 * sigqueue() must return EAGAIN if exceeded and we don't on Android.
1611 */
1612 int WRAP(sigqueue)(pid_t pid, int portable_sig, const union sigval value)
1613 {
1614 siginfo_t native_siginfo;
1615 siginfo_t *native_sip;
1616 siginfo_portable_t portable_siginfo;
1617 siginfo_portable_t *portable_sip;
1618 int native_sig;
1619 int rv;
1620
1621 ALOGV(" ");
1622 ALOGV("%s(pid:%d, portable_sig:%d, value:%p) {", __func__,
1623 pid, portable_sig, value.sival_ptr);
1624
1625 native_sig = signum_pton(portable_sig);
1626 native_sip = &native_siginfo;
1627
1628 portable_sip = &portable_siginfo;
1629 portable_sip->si_signo = 0; /* Filled in by the kernel */
1630 portable_sip->si_code = SI_QUEUE;
1631 portable_sip->si_pid = getpid(); /* Process ID of sender */
1632 portable_sip->si_uid = getuid(); /* Real UID of sender */
1633 portable_sip->si_value = value; /* Last arg supplied */
1634
1635 siginfo_pton(portable_sip, native_sip);
1636
1637 /*
1638 * man page says sigqueue() is implemented via rt_sigqueueinfo().
1639 */
1640 ALOGV("%s: calling syscall(__NR_rt_sigqueueinfo:%d, pid:%d, native_sig:%d, native_sip:%p);",
1641 __func__, __NR_rt_sigqueueinfo, pid, native_sig, native_sip);
1642
1643 rv = syscall(__NR_rt_sigqueueinfo, pid, native_sig, native_sip);
1644
1645 ALOGV("%s: return(rv:%d); }", __func__, rv);
1646 return rv;
1647 }
1648 #endif
1649
1650
1651 /*
1652 * Real Time version of sigqueueinfo().
1653 */
WRAP(rt_sigqueueinfo)1654 int WRAP(rt_sigqueueinfo)(pid_t pid, int portable_sig, siginfo_portable_t *portable_sip)
1655 {
1656 int native_sig;
1657 siginfo_t native_siginfo, *native_sip;
1658 int rv;
1659
1660 ALOGV(" ");
1661 ALOGV("%s(pid:%d, portable_sig:%d, portable_sip:%p) {", __func__,
1662 pid, portable_sig, portable_sip);
1663
1664 native_sig = signum_pton(portable_sig);
1665
1666 if (portable_sip != NULL) {
1667 native_sip = &native_siginfo;
1668 siginfo_pton(portable_sip, native_sip);
1669 } else {
1670 native_sip = NULL;
1671 }
1672 rv = syscall(__NR_rt_sigqueueinfo, pid, native_sig, native_sip);
1673
1674 ALOGV("%s: return(rv:%d); }", __func__, rv);
1675 return rv;
1676 }
1677 #endif /* __NR_rt_sigqueueinfo */
1678
1679
1680 #ifdef __NR_rt_tgsigqueueinfo
1681 /*
1682 * Thread Group flavor of the real time version of sigqueueinfo().
1683 */
WRAP(rt_tgsigqueueinfo)1684 int WRAP(rt_tgsigqueueinfo)(pid_t tgid, pid_t pid, int portable_sig,
1685 siginfo_portable_t *portable_sip)
1686 {
1687 siginfo_t native_siginfo, *native_sip;
1688 int native_sig;
1689 int rv;
1690
1691 ALOGV(" ");
1692 ALOGV("%s(tgid:%d, pid:%d, portable_sig:%d, portable_sip:%p) {", __func__,
1693 tgid, pid, portable_sig, portable_sip);
1694
1695 native_sig = signum_pton(portable_sig);
1696
1697 if (portable_sip != NULL) {
1698 native_sip = &native_siginfo;
1699 siginfo_pton(portable_sip, native_sip);
1700 } else {
1701 native_sip = NULL;
1702 }
1703 rv = syscall(__NR_rt_tgsigqueueinfo, pid, native_sig, native_sip);
1704
1705 ALOGV("%s: return(rv:%d); }", __func__, rv);
1706 return rv;
1707 }
1708 #endif /* __NR_rt_tgsigqueueinfo */
1709
1710
1711 /*
1712 * ss_flags and ss_size are located in different locations in stack_t structure:
1713 *
1714 * Incomming ARM/Portable stack_t: Outgoing MIPS stack_t:
1715 * ------------------------------- ----------------------------
1716 * typedef struct sigaltstack { typedef struct sigaltstack {
1717 * void __user *ss_sp; void *ss_sp;
1718 * int ss_flags; size_t ss_size;
1719 * size_t ss_size; int ss_flags;
1720 * } stack_t;
1721 *
1722 */
WRAP(sigaltstack)1723 int WRAP(sigaltstack)(const portable_stack_t *ss, portable_stack_t *oss)
1724 {
1725 int rv;
1726 stack_t new_stack, *mips_ss;
1727 stack_t old_stack, *mips_oss;
1728
1729 ALOGV(" ");
1730 ALOGV("%s(ss:%p, oss:%p) {", __func__, ss, oss);
1731
1732 if (ss == NULL) {
1733 mips_ss = NULL;
1734 } else {
1735 if (invalid_pointer((void *)ss)) {
1736 ALOGE("%s: invalid_pointer(ss:%p): Let kernel set proper errno and set return value.",
1737 __func__, ss);
1738
1739 mips_ss = (stack_t *) ss;
1740 } else {
1741 memset(&new_stack, 0, sizeof(stack_t));
1742 new_stack.ss_sp = ss->ss_sp;
1743 new_stack.ss_flags = ss->ss_flags;
1744 new_stack.ss_size = ss->ss_size;
1745 mips_ss = &new_stack;
1746 }
1747 }
1748 if (oss == NULL) {
1749 mips_oss = NULL;
1750 } else {
1751 if (invalid_pointer((void *)oss)) {
1752 ALOGE("%s: invalid_pointer(oss:%p): Let kernel set proper errno and return value.",
1753 __func__, oss);
1754
1755 mips_oss = (stack_t *)oss;
1756 } else {
1757 memset(&old_stack, 0, sizeof(stack_t));
1758 mips_oss = &old_stack;
1759 }
1760 }
1761
1762 rv = REAL(sigaltstack)(mips_ss, mips_oss);
1763
1764 if (!invalid_pointer(oss)) {
1765 oss->ss_sp = old_stack.ss_sp;
1766 oss->ss_flags = old_stack.ss_flags;
1767 oss->ss_size = old_stack.ss_size;
1768 }
1769 ALOGV("%s: return(rv:%d); }", __func__, rv);
1770
1771 return rv;
1772 }
1773