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