plt.c revision fbd9742d03154ca842eeae8f6a32e35c1e3c8326
1#include <gelf.h> 2#include <sys/ptrace.h> 3#include <errno.h> 4#include <error.h> 5#include <inttypes.h> 6#include <assert.h> 7#include <string.h> 8 9#include "proc.h" 10#include "common.h" 11#include "library.h" 12#include "breakpoint.h" 13#include "linux-gnu/trace.h" 14 15/* There are two PLT types on 32-bit PPC: old-style, BSS PLT, and 16 * new-style "secure" PLT. We can tell one from the other by the 17 * flags on the .plt section. If it's +X (executable), it's BSS PLT, 18 * otherwise it's secure. 19 * 20 * BSS PLT works the same way as most architectures: the .plt section 21 * contains trampolines and we put breakpoints to those. With secure 22 * PLT, the .plt section doesn't contain instructions but addresses. 23 * The real PLT table is stored in .text. Addresses of those PLT 24 * entries can be computed, and it fact that's what the glink deal 25 * below does. 26 * 27 * If not prelinked, BSS PLT entries in the .plt section contain 28 * zeroes that are overwritten by the dynamic linker during start-up. 29 * For that reason, ltrace realizes those breakpoints only after 30 * .start is hit. 31 * 32 * 64-bit PPC is more involved. Program linker creates for each 33 * library call a _stub_ symbol named xxxxxxxx.plt_call.<callee> 34 * (where xxxxxxxx is a hexadecimal number). That stub does the call 35 * dispatch: it loads an address of a function to call from the 36 * section .plt, and branches. PLT entries themselves are essentially 37 * a curried call to the resolver. When the symbol is resolved, the 38 * resolver updates the value stored in .plt, and the next time 39 * around, the stub calls the library function directly. So we make 40 * at most one trip (none if the binary is prelinked) through each PLT 41 * entry, and correspondingly that is useless as a breakpoint site. 42 * 43 * Note the three confusing terms: stubs (that play the role of PLT 44 * entries), PLT entries, .plt section. 45 * 46 * We first check symbol tables and see if we happen to have stub 47 * symbols available. If yes we just put breakpoints to those, and 48 * treat them as usual breakpoints. The only tricky part is realizing 49 * that there can be more than one breakpoint per symbol. 50 * 51 * The case that we don't have the stub symbols available is harder. 52 * The following scheme uses two kinds of PLT breakpoints: unresolved 53 * and resolved (to some address). When the process starts (or when 54 * we attach), we distribute unresolved PLT breakpoints to the PLT 55 * entries (not stubs). Then we look in .plt, and for each entry 56 * whose value is different than the corresponding PLT entry address, 57 * we assume it was already resolved, and convert the breakpoint to 58 * resolved. We also rewrite the resolved value in .plt back to the 59 * PLT address. 60 * 61 * When a PLT entry hits a resolved breakpoint (which happens because 62 * we rewrite .plt with the original unresolved addresses), we move 63 * the instruction pointer to the corresponding address and continue 64 * the process as if nothing happened. 65 * 66 * When unresolved PLT entry is called for the first time, we need to 67 * catch the new value that the resolver will write to a .plt slot. 68 * We also need to prevent another thread from racing through and 69 * taking the branch without ltrace noticing. So when unresolved PLT 70 * entry hits, we have to stop all threads. We then single-step 71 * through the resolver, until the .plt slot changes. When it does, 72 * we treat it the same way as above: convert the PLT breakpoint to 73 * resolved, and rewrite the .plt value back to PLT address. We then 74 * start all threads again. 75 * 76 * As an optimization, we remember the address where the address was 77 * resolved, and put a breakpoint there. The next time around (when 78 * the next PLT entry is to be resolved), instead of single-stepping 79 * through half the dynamic linker, we just let the thread run and hit 80 * this breakpoint. When it hits, we know the PLT entry was resolved. 81 * 82 * XXX TODO As an additional optimization, after the above is done, we 83 * might emulate the instruction that updates .plt. We would compute 84 * the resolved address, and instead of letting the dynamic linker put 85 * it in .plt, we would resolve the breakpoint to that address. This 86 * way we wouldn't need to stop other threads. Otherwise there's no 87 * way around that. Unless we know where the stubs are, we don't have 88 * a way to catch a thread that would use the window of opportunity 89 * between updating .plt and notifying ltrace that it happened. 90 * 91 * XXX TODO If we have hardware watch point, we might put a read watch 92 * on .plt slot, and discover the offenders this way. I don't know 93 * the details, but I assume at most a handful (like, one or two, if 94 * available at all) addresses may be watched at a time, and thus this 95 * would be used as an amendment of the above rather than full-on 96 * solution to PLT tracing on PPC. 97 */ 98 99#define PPC_PLT_STUB_SIZE 16 100#define PPC64_PLT_STUB_SIZE 8 //xxx 101 102static inline int 103host_powerpc64() 104{ 105#ifdef __powerpc64__ 106 return 1; 107#else 108 return 0; 109#endif 110} 111 112GElf_Addr 113arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela) 114{ 115 if (lte->ehdr.e_machine == EM_PPC && lte->arch.secure_plt) { 116 assert(lte->arch.plt_stub_vma != 0); 117 return lte->arch.plt_stub_vma + PPC_PLT_STUB_SIZE * ndx; 118 119 } else if (lte->ehdr.e_machine == EM_PPC) { 120 return rela->r_offset; 121 122 } else { 123 /* If we get here, we don't have stub symbols. In 124 * that case we put brakpoints to PLT entries the same 125 * as the PPC32 secure PLT case does. */ 126 assert(lte->arch.plt_stub_vma != 0); 127 return lte->arch.plt_stub_vma + PPC64_PLT_STUB_SIZE * ndx; 128 } 129} 130 131int 132arch_translate_address(struct Process *proc, 133 target_address_t addr, target_address_t *ret) 134{ 135 if (proc->e_machine == EM_PPC64) { 136 assert(host_powerpc64()); 137 long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); 138 if (l == -1 && errno) { 139 error(0, errno, ".opd translation of %p", addr); 140 return -1; 141 } 142 *ret = (target_address_t)l; 143 return 0; 144 } 145 146 *ret = addr; 147 return 0; 148} 149 150void * 151sym2addr(struct Process *proc, struct library_symbol *sym) 152{ 153 return sym->enter_addr; 154} 155 156static GElf_Addr 157get_glink_vma(struct ltelf *lte, GElf_Addr ppcgot, Elf_Data *plt_data) 158{ 159 Elf_Scn *ppcgot_sec = NULL; 160 GElf_Shdr ppcgot_shdr; 161 if (ppcgot != 0 162 && elf_get_section_covering(lte, ppcgot, 163 &ppcgot_sec, &ppcgot_shdr) < 0) 164 error(0, 0, "DT_PPC_GOT=%#"PRIx64", but no such section found", 165 ppcgot); 166 167 if (ppcgot_sec != NULL) { 168 Elf_Data *data = elf_loaddata(ppcgot_sec, &ppcgot_shdr); 169 if (data == NULL || data->d_size < 8 ) { 170 error(0, 0, "couldn't read GOT data"); 171 } else { 172 // where PPCGOT begins in .got 173 size_t offset = ppcgot - ppcgot_shdr.sh_addr; 174 assert(offset % 4 == 0); 175 uint32_t glink_vma; 176 if (elf_read_u32(data, offset + 4, &glink_vma) < 0) { 177 error(0, 0, "couldn't read glink VMA address" 178 " at %zd@GOT", offset); 179 return 0; 180 } 181 if (glink_vma != 0) { 182 debug(1, "PPC GOT glink_vma address: %#" PRIx32, 183 glink_vma); 184 return (GElf_Addr)glink_vma; 185 } 186 } 187 } 188 189 if (plt_data != NULL) { 190 uint32_t glink_vma; 191 if (elf_read_u32(plt_data, 0, &glink_vma) < 0) { 192 error(0, 0, "couldn't read glink VMA address"); 193 return 0; 194 } 195 debug(1, ".plt glink_vma address: %#" PRIx32, glink_vma); 196 return (GElf_Addr)glink_vma; 197 } 198 199 return 0; 200} 201 202static int 203load_dynamic_entry(struct ltelf *lte, int tag, GElf_Addr *valuep) 204{ 205 Elf_Scn *scn; 206 GElf_Shdr shdr; 207 if (elf_get_section_type(lte, SHT_DYNAMIC, &scn, &shdr) < 0 208 || scn == NULL) { 209 fail: 210 error(0, 0, "Couldn't get SHT_DYNAMIC: %s", 211 elf_errmsg(-1)); 212 return -1; 213 } 214 215 Elf_Data *data = elf_loaddata(scn, &shdr); 216 if (data == NULL) 217 goto fail; 218 219 size_t j; 220 for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) { 221 GElf_Dyn dyn; 222 if (gelf_getdyn(data, j, &dyn) == NULL) 223 goto fail; 224 225 if(dyn.d_tag == tag) { 226 *valuep = dyn.d_un.d_ptr; 227 return 0; 228 } 229 } 230 231 return -1; 232} 233 234static int 235load_ppcgot(struct ltelf *lte, GElf_Addr *ppcgotp) 236{ 237 return load_dynamic_entry(lte, DT_PPC_GOT, ppcgotp); 238} 239 240static int 241load_ppc64_glink(struct ltelf *lte, GElf_Addr *glinkp) 242{ 243 return load_dynamic_entry(lte, DT_PPC64_GLINK, glinkp); 244} 245 246int 247arch_elf_init(struct ltelf *lte) 248{ 249 lte->arch.secure_plt = !(lte->plt_flags & SHF_EXECINSTR); 250 if (lte->ehdr.e_machine == EM_PPC && lte->arch.secure_plt) { 251 GElf_Addr ppcgot; 252 if (load_ppcgot(lte, &ppcgot) < 0) { 253 error(0, 0, "couldn't find DT_PPC_GOT"); 254 return -1; 255 } 256 GElf_Addr glink_vma = get_glink_vma(lte, ppcgot, lte->plt_data); 257 258 assert (lte->relplt_size % 12 == 0); 259 size_t count = lte->relplt_size / 12; // size of RELA entry 260 lte->arch.plt_stub_vma = glink_vma 261 - (GElf_Addr)count * PPC_PLT_STUB_SIZE; 262 debug(1, "stub_vma is %#" PRIx64, lte->arch.plt_stub_vma); 263 264 } else if (lte->ehdr.e_machine == EM_PPC64) { 265 GElf_Addr glink_vma; 266 if (load_ppc64_glink(lte, &glink_vma) < 0) { 267 error(0, 0, "couldn't find DT_PPC64_GLINK"); 268 return -1; 269 } 270 271 /* The first glink stub starts at offset 32. */ 272 lte->arch.plt_stub_vma = glink_vma + 32; 273 } 274 275 /* On PPC64, look for stub symbols in symbol table. These are 276 * called: xxxxxxxx.plt_call.callee_name@version+addend. */ 277 if (lte->ehdr.e_machine == EM_PPC64 278 && lte->symtab != NULL && lte->strtab != NULL) { 279 280 /* N.B. We can't simply skip the symbols that we fail 281 * to read or malloc. There may be more than one stub 282 * per symbol name, and if we failed in one but 283 * succeeded in another, the PLT enabling code would 284 * have no way to tell that something is missing. We 285 * could work around that, of course, but it doesn't 286 * seem worth the trouble. So if anything fails, we 287 * just pretend that we don't have stub symbols at 288 * all, as if the binary is stripped. */ 289 290 size_t i; 291 for (i = 0; i < lte->symtab_count; ++i) { 292 GElf_Sym sym; 293 if (gelf_getsym(lte->symtab, i, &sym) == NULL) { 294 struct library_symbol *sym, *next; 295 fail: 296 for (sym = lte->arch.stubs; sym != NULL; ) { 297 next = sym->next; 298 library_symbol_destroy(sym); 299 free(sym); 300 sym = next; 301 } 302 lte->arch.stubs = NULL; 303 break; 304 } 305 306 const char *name = lte->strtab + sym.st_name; 307 308#define STUBN ".plt_call." 309 if ((name = strstr(name, STUBN)) == NULL) 310 continue; 311 name += sizeof(STUBN) - 1; 312#undef STUBN 313 314 size_t len; 315 const char *ver = strchr(name, '@'); 316 if (ver != NULL) { 317 len = ver - name; 318 319 } else { 320 /* If there is "+" at all, check that 321 * the symbol name ends in "+0". */ 322 const char *add = strrchr(name, '+'); 323 if (add != NULL) { 324 assert(strcmp(add, "+0") == 0); 325 len = add - name; 326 } else { 327 len = strlen(name); 328 } 329 } 330 331 char *sym_name = strndup(name, len); 332 struct library_symbol *libsym = malloc(sizeof(*libsym)); 333 if (sym_name == NULL || libsym == NULL) { 334 fail2: 335 free(sym_name); 336 free(libsym); 337 goto fail; 338 } 339 340 target_address_t addr 341 = (target_address_t)sym.st_value + lte->bias; 342 if (library_symbol_init(libsym, addr, sym_name, 1, 343 LS_TOPLT_EXEC) < 0) 344 goto fail2; 345 libsym->arch.type = PPC64PLT_STUB; 346 libsym->next = lte->arch.stubs; 347 lte->arch.stubs = libsym; 348 } 349 } 350 351 return 0; 352} 353 354static int 355read_plt_slot_value(struct Process *proc, GElf_Addr addr, GElf_Addr *valp) 356{ 357 /* on PPC32 we need to do things differently, but PPC64/PPC32 358 * is currently not supported anyway. */ 359 assert(host_powerpc64()); 360 361 long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); 362 if (l == -1 && errno != 0) { 363 error(0, errno, "ptrace .plt slot value @%#" PRIx64, addr); 364 return -1; 365 } 366 367 *valp = (GElf_Addr)l; 368 return 0; 369} 370 371static int 372unresolve_plt_slot(struct Process *proc, GElf_Addr addr, GElf_Addr value) 373{ 374 /* We only modify plt_entry[0], which holds the resolved 375 * address of the routine. We keep the TOC and environment 376 * pointers intact. Hence the only adjustment that we need to 377 * do is to IP. */ 378 if (ptrace(PTRACE_POKETEXT, proc->pid, addr, value) < 0) { 379 error(0, errno, "unresolve .plt slot"); 380 return -1; 381 } 382 return 0; 383} 384 385enum plt_status 386arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte, 387 const char *a_name, GElf_Rela *rela, size_t ndx, 388 struct library_symbol **ret) 389{ 390 if (lte->ehdr.e_machine == EM_PPC) 391 return plt_default; 392 393 /* PPC64. If we have stubs, we return a chain of breakpoint 394 * sites, one for each stub that corresponds to this PLT 395 * entry. */ 396 struct library_symbol *chain = NULL; 397 struct library_symbol **symp; 398 for (symp = <e->arch.stubs; *symp != NULL; ) { 399 struct library_symbol *sym = *symp; 400 if (strcmp(sym->name, a_name) != 0) { 401 symp = &(*symp)->next; 402 continue; 403 } 404 405 /* Re-chain the symbol from stubs to CHAIN. */ 406 *symp = sym->next; 407 sym->next = chain; 408 chain = sym; 409 } 410 411 if (chain != NULL) { 412 *ret = chain; 413 return plt_ok; 414 } 415 416 /* We don't have stub symbols. Find corresponding .plt slot, 417 * and check whether it contains the corresponding PLT address 418 * (or 0 if the dynamic linker hasn't run yet). N.B. we don't 419 * want read this from ELF file, but from process image. That 420 * makes a difference if we are attaching to a running 421 * process. */ 422 423 GElf_Addr plt_entry_addr = arch_plt_sym_val(lte, ndx, rela); 424 GElf_Addr plt_slot_addr = rela->r_offset; 425 assert(plt_slot_addr >= lte->plt_addr 426 || plt_slot_addr < lte->plt_addr + lte->plt_size); 427 428 GElf_Addr plt_slot_value; 429 if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0) 430 return plt_fail; 431 432 char *name = strdup(a_name); 433 struct library_symbol *libsym = malloc(sizeof(*libsym)); 434 if (name == NULL || libsym == NULL) { 435 error(0, errno, "allocation for .plt slot"); 436 fail: 437 free(name); 438 free(libsym); 439 return plt_fail; 440 } 441 442 if (library_symbol_init(libsym, (target_address_t)plt_entry_addr, 443 name, 1, LS_TOPLT_EXEC) < 0) 444 goto fail; 445 libsym->arch.plt_slot_addr = plt_slot_addr; 446 447 if (plt_slot_value == plt_entry_addr || plt_slot_value == 0) { 448 libsym->arch.type = PPC64PLT_UNRESOLVED; 449 libsym->arch.resolved_value = plt_entry_addr; 450 451 } else { 452 /* Unresolve the .plt slot. If the binary was 453 * prelinked, this makes the code invalid, because in 454 * case of prelinked binary, the dynamic linker 455 * doesn't update .plt[0] and .plt[1] with addresses 456 * of the resover. But we don't care, we will never 457 * need to enter the resolver. That just means that 458 * we have to un-un-resolve this back before we 459 * detach. */ 460 461 if (unresolve_plt_slot(proc, plt_slot_addr, plt_entry_addr) < 0) { 462 library_symbol_destroy(libsym); 463 goto fail; 464 } 465 libsym->arch.type = PPC64PLT_RESOLVED; 466 libsym->arch.resolved_value = plt_slot_value; 467 } 468 469 *ret = libsym; 470 return plt_ok; 471} 472 473void 474arch_elf_destroy(struct ltelf *lte) 475{ 476 struct library_symbol *sym; 477 for (sym = lte->arch.stubs; sym != NULL; ) { 478 struct library_symbol *next = sym->next; 479 library_symbol_destroy(sym); 480 free(sym); 481 sym = next; 482 } 483} 484 485static void 486dl_plt_update_bp_on_hit(struct breakpoint *bp, struct Process *proc) 487{ 488 struct process_stopping_handler *self = proc->arch.handler; 489 assert(self != NULL); 490 491 struct library_symbol *libsym = self->breakpoint_being_enabled->libsym; 492 GElf_Addr value; 493 if (read_plt_slot_value(proc, libsym->arch.plt_slot_addr, &value) < 0) 494 return; 495 496 /* cb_on_all_stopped looks if HANDLER is set to NULL as a way 497 * to check that this was run. It's an error if it 498 * wasn't. */ 499 breakpoint_turn_off(bp, proc); 500 proc->arch.handler = NULL; 501} 502 503static void 504cb_on_all_stopped(struct process_stopping_handler *self) 505{ 506 /* Put that in for dl_plt_update_bp_on_hit to see. */ 507 assert(self->task_enabling_breakpoint->arch.handler == NULL); 508 self->task_enabling_breakpoint->arch.handler = self; 509 510 linux_ptrace_disable_and_continue(self); 511} 512 513static enum callback_status 514cb_keep_stepping_p(struct process_stopping_handler *self) 515{ 516 struct Process *proc = self->task_enabling_breakpoint; 517 struct library_symbol *libsym = self->breakpoint_being_enabled->libsym; 518 GElf_Addr value; 519 if (read_plt_slot_value(proc, libsym->arch.plt_slot_addr, &value) < 0) 520 return CBS_FAIL; 521 522 /* In UNRESOLVED state, the RESOLVED_VALUE in fact contains 523 * the PLT entry value. */ 524 if (value == libsym->arch.resolved_value) 525 return CBS_CONT; 526 527 /* The .plt slot got resolved! We can migrate the breakpoint 528 * to RESOLVED and stop single-stepping. */ 529 if (unresolve_plt_slot(proc, libsym->arch.plt_slot_addr, 530 libsym->arch.resolved_value) < 0) 531 return CBS_FAIL; 532 533 /* Install breakpoint to the address where the change takes 534 * place. If we fail, then that just means that we'll have to 535 * singlestep the next time around as well. */ 536 struct Process *leader = proc->leader; 537 if (leader == NULL || leader->arch.dl_plt_update_bp != NULL) 538 goto resolve; 539 540 /* We need to install to the next instruction. ADDR points to 541 * a store instruction, so moving the breakpoint one 542 * instruction forward is safe. */ 543 target_address_t addr = get_instruction_pointer(proc) + 4; 544 leader->arch.dl_plt_update_bp = insert_breakpoint(proc, addr, NULL); 545 546 /* Turn it off for now. We will turn it on again when we hit 547 * the PLT entry that needs this. */ 548 breakpoint_turn_off(leader->arch.dl_plt_update_bp, proc); 549 550 if (leader->arch.dl_plt_update_bp != NULL) { 551 static struct bp_callbacks dl_plt_update_cbs = { 552 .on_hit = dl_plt_update_bp_on_hit, 553 }; 554 leader->arch.dl_plt_update_bp->cbs = &dl_plt_update_cbs; 555 } 556 557resolve: 558 libsym->arch.type = PPC64PLT_RESOLVED; 559 libsym->arch.resolved_value = value; 560 561 return CBS_STOP; 562} 563 564static void 565ppc64_plt_bp_continue(struct breakpoint *bp, struct Process *proc) 566{ 567 switch (bp->libsym->arch.type) { 568 target_address_t rv; 569 struct Process *leader; 570 void (*on_all_stopped)(struct process_stopping_handler *); 571 enum callback_status (*keep_stepping_p) 572 (struct process_stopping_handler *); 573 574 case PPC64PLT_UNRESOLVED: 575 on_all_stopped = NULL; 576 keep_stepping_p = NULL; 577 leader = proc->leader; 578 579 if (leader != NULL && leader->arch.dl_plt_update_bp != NULL) { 580 if (breakpoint_turn_on(leader->arch.dl_plt_update_bp, 581 proc) < 0) 582 goto stepping; 583 on_all_stopped = cb_on_all_stopped; 584 } else { 585 stepping: 586 keep_stepping_p = cb_keep_stepping_p; 587 } 588 589 if (process_install_stopping_handler 590 (proc, bp, on_all_stopped, keep_stepping_p, NULL) < 0) { 591 perror("ppc64_unresolved_bp_continue: couldn't install" 592 " event handler"); 593 continue_after_breakpoint(proc, bp); 594 } 595 return; 596 597 case PPC64PLT_RESOLVED: 598 rv = (target_address_t)bp->libsym->arch.resolved_value; 599 set_instruction_pointer(proc, rv); 600 continue_process(proc->pid); 601 return; 602 603 case PPC_DEFAULT: 604 case PPC64PLT_STUB: 605 /* These should never hit here. */ 606 break; 607 } 608 609 assert(bp->libsym->arch.type != bp->libsym->arch.type); 610 abort(); 611} 612 613int 614arch_library_symbol_init(struct library_symbol *libsym) 615{ 616 /* We set type explicitly in the code above, where we have the 617 * necessary context. This is for calls from ltrace-elf.c and 618 * such. */ 619 libsym->arch.type = PPC_DEFAULT; 620 return 0; 621} 622 623void 624arch_library_symbol_destroy(struct library_symbol *libsym) 625{ 626} 627 628int 629arch_library_symbol_clone(struct library_symbol *retp, 630 struct library_symbol *libsym) 631{ 632 retp->arch = libsym->arch; 633 return 0; 634} 635 636/* For some symbol types, we need to set up custom callbacks. XXX we 637 * don't need PROC here, we can store the data in BP if it is of 638 * interest to us. */ 639int 640arch_breakpoint_init(struct Process *proc, struct breakpoint *bp) 641{ 642 if (proc->e_machine == EM_PPC 643 || bp->libsym == NULL) 644 return 0; 645 646 /* Entry point breakpoints (LS_TOPLT_NONE) and stub PLT 647 * breakpoints need no special handling. */ 648 if (bp->libsym->plt_type != LS_TOPLT_EXEC 649 || bp->libsym->arch.type == PPC64PLT_STUB) 650 return 0; 651 652 static struct bp_callbacks cbs = { 653 .on_continue = ppc64_plt_bp_continue, 654 }; 655 breakpoint_set_callbacks(bp, &cbs); 656 return 0; 657} 658 659void 660arch_breakpoint_destroy(struct breakpoint *bp) 661{ 662} 663 664int 665arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp) 666{ 667 retp->arch = sbp->arch; 668 return 0; 669} 670 671int 672arch_process_init(struct Process *proc) 673{ 674 proc->arch.dl_plt_update_bp = NULL; 675 proc->arch.handler = NULL; 676 return 0; 677} 678 679void 680arch_process_destroy(struct Process *proc) 681{ 682} 683 684int 685arch_process_clone(struct Process *retp, struct Process *proc) 686{ 687 retp->arch = proc->arch; 688 return 0; 689} 690 691int 692arch_process_exec(struct Process *proc) 693{ 694 return arch_process_init(proc); 695} 696