Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

debugging tools for *nix platforms #4925

Merged
merged 5 commits into from
Dec 27, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 62 additions & 1 deletion base/sysinfo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ export CPU_CORES,
loadavg,
free_memory,
total_memory,
shlib_ext
shlib_ext,
shlib_list,
dlpath

import ..Base: WORD_SIZE, OS_NAME, ARCH, MACHINE
import ..Base: show, uv_error
Expand Down Expand Up @@ -90,6 +92,7 @@ function _cpu_summary(io::IO, cpu::Array{CPUinfo}, i, j)
summary.speed = div(summary.speed,count)
show(io,summary,true,"#1-$(count) ")
end
println(io)
end

function cpu_summary(io::IO=STDOUT, cpu::Array{CPUinfo}=cpu_info())
Expand Down Expand Up @@ -140,4 +143,62 @@ else
const shlib_ext = "so"
end

@linux_only begin
immutable dl_phdr_info
# Base address of object
addr::Cuint

# Null-terminated name of object
name::Ptr{Uint8}

# Pointer to array of ELF program headers for this object
phdr::Ptr{Void}

# Number of program headers for this object
phnum::Cshort
end

# This callback function called by dl_iterate_phdr() on Linux
function dl_phdr_info_callback( di_ptr::Ptr{dl_phdr_info}, size::Csize_t, dynamic_libraries_ptr::Ptr{Array{String,1}} )
di = unsafe_load(di_ptr)

# Skip over objects without a path (as they represent this own object)
name = bytestring(di.name)
if !isempty(name)
dynamic_libraries = unsafe_pointer_to_objref( dynamic_libraries_ptr )
push!(dynamic_libraries, name )
end
convert(Cint, 0)::Cint
end
end #@linux_only

function shlib_list()
dynamic_libraries = Array(String,0)

@linux_only begin
const callback = cfunction(dl_phdr_info_callback, Cint, (Ptr{dl_phdr_info}, Csize_t, Ptr{Array{String,1}} ))
ccall( cglobal("dl_iterate_phdr"), Cint, (Ptr{Void}, Ptr{Void}), callback, pointer_from_objref(dynamic_libraries) )
end

@osx_only begin
numImages = ccall( cglobal("_dyld_image_count"), Cint, (), )

# start at 1 instead of 0 to skip self
for i in 1:numImages-1
name = bytestring(ccall( cglobal("_dyld_get_image_name"), Ptr{Uint8}, (Uint32,), uint32(i)))
push!(dynamic_libraries, name)
end
end

dynamic_libraries
end

function dlpath( handle::Ptr{Void} )
return bytestring(ccall( :jl_pathname_for_handle, Ptr{Uint8}, (Ptr{Void},), handle ))
end

function dlpath( libname::String )
return dlpath( dlopen(libname) )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing a dlclose?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes. Thank you. Fixed in 47915f3

end

end
3 changes: 3 additions & 0 deletions base/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@ function versioninfo(io::IO=STDOUT, verbose::Bool=false)
end
println(io, "Platform Info:")
println(io, " System: ", Sys.OS_NAME, " (", Sys.MACHINE, ")")

cpu = Sys.cpu_info()
println(io, " CPU: ", cpu[1].model)
println(io, " WORD_SIZE: ", Sys.WORD_SIZE)
if verbose
lsb = ""
Expand Down
107 changes: 107 additions & 0 deletions src/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mman.h>
#include <dlfcn.h>
#endif
#include <errno.h>
#include <signal.h>
Expand All @@ -24,6 +25,15 @@ char *dirname(char *);
#endif
#include <fcntl.h>

#ifdef __APPLE__
#include <mach-o/dyld.h>
#include <mach-o/nlist.h>
#endif

#ifdef _OS_LINUX_
#include <link.h>
#endif

#define __STDC_CONSTANT_MACROS
#define __STDC_LIMIT_MACROS
#include <llvm-c/Target.h>
Expand Down Expand Up @@ -517,3 +527,100 @@ DLLEXPORT long jl_SC_CLK_TCK(void)
return 0;
#endif
}

// Dynamic Library interrogation

#ifdef __APPLE__
// This code gratefully lifted from: http://stackoverflow.com/questions/20481058
#ifdef __LP64__
typedef struct mach_header_64 mach_header_t;
typedef struct segment_command_64 segment_command_t;
typedef struct nlist_64 nlist_t;
#else
typedef struct mach_header mach_header_t;
typedef struct segment_command segment_command_t;
typedef struct nlist nlist_t;
#endif

static const char * first_external_symbol_for_image(const mach_header_t *header)
{
Dl_info info;
if (dladdr(header, &info) == 0)
return NULL;

segment_command_t *seg_linkedit = NULL;
segment_command_t *seg_text = NULL;
struct symtab_command *symtab = NULL;

struct load_command *cmd = (struct load_command *)((intptr_t)header + sizeof(mach_header_t));
for (uint32_t i = 0; i < header->ncmds; i++, cmd = (struct load_command *)((intptr_t)cmd + cmd->cmdsize))
{
switch(cmd->cmd)
{
case LC_SEGMENT:
case LC_SEGMENT_64:
if (!strcmp(((segment_command_t *)cmd)->segname, SEG_TEXT))
seg_text = (segment_command_t *)cmd;
else if (!strcmp(((segment_command_t *)cmd)->segname, SEG_LINKEDIT))
seg_linkedit = (segment_command_t *)cmd;
break;

case LC_SYMTAB:
symtab = (struct symtab_command *)cmd;
break;
}
}

if ((seg_text == NULL) || (seg_linkedit == NULL) || (symtab == NULL))
return NULL;

intptr_t file_slide = ((intptr_t)seg_linkedit->vmaddr - (intptr_t)seg_text->vmaddr) - seg_linkedit->fileoff;
intptr_t strings = (intptr_t)header + (symtab->stroff + file_slide);
nlist_t *sym = (nlist_t *)((intptr_t)header + (symtab->symoff + file_slide));

for (uint32_t i = 0; i < symtab->nsyms; i++, sym++)
{
if ((sym->n_type & N_EXT) != N_EXT || !sym->n_value)
continue;

return (const char *)strings + sym->n_un.n_strx;
}

return NULL;
}
#endif


// Takes a handle (as returned from dlopen()) and returns the absolute path to the image loaded
DLLEXPORT const char * jl_pathname_for_handle(uv_lib_t * uv_lib)
{
if( !uv_lib )
return NULL;

void * handle = uv_lib->handle;
#ifdef __APPLE__
for (int32_t i = _dyld_image_count(); i >= 0 ; i--) {
const char *first_symbol = first_external_symbol_for_image((const mach_header_t *)_dyld_get_image_header(i));
if (first_symbol && strlen(first_symbol) > 1) {
handle = (void *)((intptr_t)handle | 1); // in order to trigger findExportedSymbol instead of findExportedSymbolInImageOrDependentImages. See `dlsym` implementation at http://opensource.apple.com/source/dyld/dyld-239.3/src/dyldAPIs.cpp
first_symbol++; // in order to remove the leading underscore
void *address = dlsym(handle, first_symbol);
Dl_info info;
if (dladdr(address, &info))
return info.dli_fname;
}
}
#endif

#ifdef _OS_LINUX_
struct link_map * map;
dlinfo( handle, RTLD_DI_LINKMAP, &map );
if (map)
return map->l_name;
#endif

#ifdef _OS_WINDOWS_
// Not supported yet...
#endif
return NULL;
}