dt_link.c revision 2
2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. 2N/A".shstrtab\0" /* 1 */ 2N/A".SUNW_dof\0" /* 11 */ 2N/A".rela.SUNW_dof";
/* 37 */ 2N/A".rel.SUNW_dof";
/* 37 */ 2N/A".shstrtab\0" /* 1 */ 2N/A".SUNW_dof\0" /* 11 */ 2N/A".rela.SUNW_dof";
/* 37 */ 2N/A * First compute the size of the string table and the number of 2N/A * relocations present in the DOF. 2N/A * The first symbol table entry must be zeroed and is always ignored. 2N/A * Take a second pass through the DOF sections filling in the 2N/A * memory we allocated. 2N/A * Add 4 bytes to hit the low half of this 64-bit 2N/A * big-endian address. 2N/A * Add a symbol for the DOF itself. We use a different symbol for 2N/A * lazily and actively loaded DOF to make them easy to distinguish. 2N/A * First compute the size of the string table and the number of 2N/A * relocations present in the DOF. 2N/A * The first symbol table entry must be zeroed and is always ignored. 2N/A * Take a second pass through the DOF sections filling in the 2N/A * memory we allocated. 2N/A * Add a symbol for the DOF itself. We use a different symbol for 2N/A * lazily and actively loaded DOF to make them easy to distinguish. 2N/A * Write out an ELF32 file prologue consisting of a header, section headers, 2N/A * and a section header string table. The DOF data will follow this prologue 2N/A * and complete the contents of the given ELF file. 2N/A return (-
1);
/* errno is set for us */ 2N/A * If there are no relocations, we only need enough sections for 2N/A * the shstrtab and the DOF. 2N/A * Write out an ELF64 file prologue consisting of a header, section headers, 2N/A * and a section header string table. The DOF data will follow this prologue 2N/A * and complete the contents of the given ELF file. 2N/A return (-
1);
/* errno is set for us */ 2N/A * If there are no relocations, we only need enough sections for 2N/A * the shstrtab and the DOF. 2N/A * We only know about some specific relocation types. 2N/A * We may have already processed this object file in an earlier linker 2N/A * invocation. Check to see if the present instruction sequence matches 2N/A * the one we would install below. 2N/A * We only expect call instructions with a displacement of 0. 2N/A * It would necessarily indicate incorrect usage if an is- 2N/A * enabled probe were tail-called so flag that as an error. 2N/A * It's also potentially (very) tricky to handle gracefully, 2N/A * but could be done if this were a desired use scenario. 2N/A * On SPARC, we take advantage of the fact that the first 2N/A * argument shares the same register as for the return value. 2N/A * The macro handles the work of zeroing that register so we 2N/A * don't need to do anything special here. We instrument the 2N/A * instruction in the delay slot as we'll need to modify the 2N/A * return register after that instruction has been emulated. 2N/A * If the call is followed by a restore, it's a tail call so 2N/A * change the call to a ret. If the call if followed by a mov 2N/A * of a register into %o7, it's a tail call in leaf context 2N/A * so change the call to a retl-like instruction that returns 2N/A * to that register value + 8 (rather than the typical %o7 + 2N/A * 8); the delay slot instruction is left, but should have no 2N/A * effect. Otherwise we change the call to be a nop. We 2N/A * identify the subsequent instruction as the probe point in 2N/A * all but the leaf tail-call case to ensure that arguments to 2N/A * the probe are complete and consistent. An astute, though 2N/A * largely hypothetical, observer would note that there is the 2N/A * possibility of a false-positive probe firing if the function 2N/A * contained a branch to the instruction in the delay slot of 2N/A * the call. Fixing this would require significant in-kernel 2N/A * modifications, and isn't worth doing until we see it in the 2N/A * On x86, the first byte of the instruction is the call opcode and 2N/A * the next four bytes are the 32-bit address; the relocation is for 2N/A * the address operand. We back up the offset to the first byte of 2N/A * the instruction. For is-enabled probes, we later advance the offset 2N/A * so that it hits the first nop in the instruction sequence. 2N/A * We only know about some specific relocation types. Luckily 2N/A * these types have the same values on both 32-bit and 64-bit 2N/A * x86 architectures. 2N/A * We may have already processed this object file in an earlier linker 2N/A * invocation. Check to see if the present instruction sequence matches 2N/A * the one we would install. For is-enabled probes, we advance the 2N/A * offset to the first nop instruction in the sequence to match the 2N/A * text modification code below. 2N/A * We expect either a call instrution with a 32-bit displacement or a 2N/A * jmp instruction with a 32-bit displacement acting as a tail-call. 2N/A * Establish the instruction sequence -- all nops for probes, and an 2N/A * instruction to clear the return value register (%eax/%rax) followed 2N/A * by nops for is-enabled probes. For is-enabled probes, we advance 2N/A * the offset to the first nop. This isn't stricly necessary but makes 2N/A * for more readable disassembly when the probe is enabled. 2N/A "permitted; use the contents of the archive instead: %s",
2N/A "invalid file type: %s",
obj));
2N/A "incorrect ELF class for object file: %s",
obj));
2N/A "incorrect ELF machine type for object file: %s",
obj));
2N/A * We use this token as a relatively unique handle for this file on the 2N/A * system in order to disambiguate potential conflicts between files of 2N/A * the same name which contain identially named local symbols. 2N/A "failed to generate unique key for object file: %s",
obj));
2N/A * Skip any non-relocation sections. 2N/A /* Only consider a section if data is present */ 2N/A * Grab the section, section header and section data for the 2N/A * symbol table that this relocation section references. 2N/A * Ditto for that symbol table's string table. 2N/A * Grab the section, section header and section data for the 2N/A * target section for the relocations. For the relocations 2N/A * we're looking for -- this will typically be the text of the 2N/A * We're looking for relocations to symbols matching this form: 2N/A * __dtrace[enabled]_<prov>___<probe> 2N/A * For the generated object, we need to record the location 2N/A * identified by the relocation, and create a new relocation 2N/A * in the generated object that will be resolved at link time 2N/A * to the location of the function in which the probe is 2N/A * embedded. In the target object, we change the matched symbol 2N/A * so that it will be ignored at link time, and we modify the 2N/A * target (text) section to replace the call instruction with 2N/A * If the function containing the probe is locally scoped 2N/A * (static), we create an alias used by the relocation in the 2N/A * generated object. The alias, a new symbol, will be global 2N/A * (so that the relocation from the generated object can be 2N/A * resolved), and hidden (so that it is converted to a local 2N/A * symbol at link time). Such aliases have this form: 2N/A * $dtrace<key>.<function> 2N/A * We take a first pass through all the relocations to 2N/A * populate our string table and count the number of extra 2N/A * symbols we'll require. 2N/A * If this symbol isn't of type function, we've really 2N/A * driven off the rails or the object file is corrupt. 2N/A "expected %s to be of type function", s));
2N/A * If needed, allocate the additional space for the symbol 2N/A * table and string table copying the old data into the new 2N/A * buffers, and marking the buffers as dirty. We inject those 2N/A * newly allocated buffers into the libelf data structures, but 2N/A * are still responsible for freeing them once we're done with 2N/A * The first byte of the string table is reserved for 2N/A * Now that the tables have been allocated, perform the 2N/A * modifications described above. 2N/A * Check to see if this is an 'is-enabled' check as 2N/A * opposed to a normal probe. 2N/A * If a NULL relocation name is passed to 2N/A * dt_probe_define(), the function name is used for the 2N/A * relocation. The relocation needs to use a mangled 2N/A * name if the symbol is locally scoped; the function 2N/A * name may need to change if we've found the global 2N/A * alias for the locally scoped symbol (we prefer 2N/A * global symbols to locals in dt_symtab_lookup()). 2N/A "no such probe %s", p));
2N/A "failed to allocate space for probe"));
2N/A * This symbol may already have been marked to 2N/A * be ignored by another relocation referencing 2N/A * the same symbol or if this object file has 2N/A * already been processed by an earlier link 2N/A "an error was encountered while processing %s",
obj));
2N/A * A NULL program indicates a special use in which we just link 2N/A * together a bunch of object files specified in objv and then 2N/A * unlink(2) those object files. 2N/A const char *
fmt =
"%s -o %s -r";
2N/A "failed to link %s: %s failed due to signal %d",
2N/A "failed to link %s: %s exited with status %d\n",
2N/A return (-
1);
/* errno is set for us */ 2N/A * If there are is-enabled probes then we need to force use of DOF 2N/A return (-
1);
/* errno is set for us */ 2N/A * Create a temporary file and then unlink it if we're going to 2N/A * combine it with drti.o later. We can still refer to it in child 2N/A * If -xlinktype=DOF has been selected, just write out the DOF. 2N/A * Otherwise proceed to the default of generating and linking ELF. 2N/A break;
/* fall through to the rest of dtrace_program_link() */ 2N/A const char *
fmt =
"%s -o %s -r -Blocal -Breduce /dev/fd/%d %s";
2N/A "failed to link %s: %s failed due to signal %d",
2N/A "failed to link %s: %s exited with status %d\n",