dlfcn_test.cpp revision 156da966214957c5616a0b83cc84686eedfc4e31
1acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao/* 2acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Copyright (C) 2012 The Android Open Source Project 3acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * 4acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Licensed under the Apache License, Version 2.0 (the "License"); 5acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * you may not use this file except in compliance with the License. 6acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * You may obtain a copy of the License at 7acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * 8acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * http://www.apache.org/licenses/LICENSE-2.0 9acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * 10acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Unless required by applicable law or agreed to in writing, software 11acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * distributed under the License is distributed on an "AS IS" BASIS, 12acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * See the License for the specific language governing permissions and 14acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * limitations under the License. 15acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao */ 16acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao 17acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao#include <gtest/gtest.h> 18acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao 19acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao#include <dlfcn.h> 208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <libgen.h> 218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <limits.h> 228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdio.h> 238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdint.h> 248e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 258e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <string> 26acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao 27acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaostatic bool gCalled = false; 28acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoextern "C" void DlSymTestFunction() { 29acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao gCalled = true; 30acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao} 31acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao 32acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoTEST(dlopen, dlsym_in_self) { 33acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao void* self = dlopen(NULL, RTLD_NOW); 34acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao ASSERT_TRUE(self != NULL); 35acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao 36acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao void* sym = dlsym(self, "DlSymTestFunction"); 37acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao ASSERT_TRUE(sym != NULL); 38acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao 39acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao void (*function)() = reinterpret_cast<void(*)()>(sym); 40acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao 41acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao gCalled = false; 42acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao function(); 43acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao ASSERT_TRUE(gCalled); 44acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao} 458e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 468e15b08ae22a5230c1fea4779410de0420fa939cElliott HughesTEST(dlopen, dladdr) { 478e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes void* self = dlopen(NULL, RTLD_NOW); 488e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_TRUE(self != NULL); 498e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 508e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes void* sym = dlsym(self, "DlSymTestFunction"); 518e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_TRUE(sym != NULL); 528e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 538e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address. 548e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2); 558e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 568e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes Dl_info info; 578e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes int rc = dladdr(addr, &info); 588e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_NE(rc, 0); // Zero on error, non-zero on success. 598e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 608e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // Get the name of this executable. 618e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes char executable_path[PATH_MAX]; 628e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path)); 638e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_NE(rc, -1); 648e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes executable_path[rc] = '\0'; 658e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes std::string executable_name(basename(executable_path)); 668e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 678e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // The filename should be that of this executable. 688e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // Note that we don't know whether or not we have the full path, so we want an "ends_with" test. 698e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes std::string dli_fname(info.dli_fname); 708e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes dli_fname = basename(&dli_fname[0]); 718e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_EQ(dli_fname, executable_name); 728e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 738e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // The symbol name should be the symbol we looked up. 748e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_STREQ(info.dli_sname, "DlSymTestFunction"); 758e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 768e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // The address should be the exact address of the symbol. 778e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_EQ(info.dli_saddr, sym); 788e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 798e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // Look in /proc/pid/maps to find out what address we were loaded at. 808e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic. 818e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes void* base_address = NULL; 828e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes char path[PATH_MAX]; 838e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes snprintf(path, sizeof(path), "/proc/%d/maps", getpid()); 848e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes char line[BUFSIZ]; 858e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes FILE* fp = fopen(path, "r"); 868e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_TRUE(fp != NULL); 878e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes while (fgets(line, sizeof(line), fp) != NULL) { 888e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes uintptr_t start = strtoul(line, 0, 16); 898e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes line[strlen(line) - 1] = '\0'; // Chomp the '\n'. 908e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes char* path = strchr(line, '/'); 91156da966214957c5616a0b83cc84686eedfc4e31Elliott Hughes if (path != NULL && strcmp(executable_path, path) == 0) { 928e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes base_address = reinterpret_cast<void*>(start); 938e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes break; 948e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes } 958e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes } 968e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes fclose(fp); 978e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 988e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // The base address should be the address we were loaded at. 998e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_EQ(info.dli_fbase, base_address); 1008e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes} 1018e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1028e15b08ae22a5230c1fea4779410de0420fa939cElliott HughesTEST(dlopen, dladdr_invalid) { 1038e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes Dl_info info; 1048e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1058e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // No symbol corresponding to NULL. 1068e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success. 1078e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1088e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // No symbol corresponding to a stack address. 1098e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success. 1108e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes} 111