~autopilot/autopilot-qt/1.3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/*
Copyright 2012 Canonical

This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License version 3, as published
by the Free Software Foundation.
*/

#include "qttestability.h"

#include <link.h>
#include <string>
#include <iostream>

typedef enum
{
    QT_VERSION_4,
    QT_VERSION_5,
    QT_VERSION_UNKNOWN
} QtVersion;

static int
callback(struct dl_phdr_info *info, size_t size, void *data)
{
    (void) size;
    QtVersion *v = (QtVersion*) data;

    if (*v == QT_VERSION_UNKNOWN)
    {
        std::string lib_path(info->dlpi_name);
        if (lib_path.rfind("libQtCore.so.4") != std::string::npos)
        {
            *v = QT_VERSION_4;
        }
        else if (lib_path.rfind("libQtCore.so.5") != std::string::npos || lib_path.rfind("libQt5Core.so.5") != std::string::npos)
        {
            *v = QT_VERSION_5;
        }
    }

    return 0;
}

void qt_testability_init(void)
{
    QtVersion version = QT_VERSION_UNKNOWN;
    dl_iterate_phdr(callback, &version);

    std::string driver_name;
    if (version == QT_VERSION_4)
    {
        driver_name = "libautopilot_driver_qt4.so.1";
    }
    else if (version == QT_VERSION_5)
    {
        driver_name = "libautopilot_driver_qt5.so.1";
    }
    else
    {
        std::cerr << "We don't seem to link to version 4 or 5 of QtCore." << std::endl
            << "Unable to determine which autopilot driver to load." << std::endl
            << "Autopilot introspection will not be available for this process." << std::endl;
            return;
    }

    void* driver = dlopen(driver_name.c_str(), RTLD_LAZY);
    if (!driver)
    {
        std::cerr << "Cannot load library: " << dlerror() << std::endl
            << "Autopilot introspection will not be available for this process." << std::endl;
            return;
    }

    // load the entry point function for the actual driver:
    typedef void (*entry_t)();
    // clear errors:
    dlerror();
    entry_t entry_point = (entry_t) dlsym(driver, "qt_testability_init");
    const char* err = dlerror();
    if (err)
    {
        std::cerr << "Cannot load library entry point symbol: " << err << std::endl
        << "Autopilot introspection will not be available for this process." << std::endl;
            return;
    }
    entry_point();
}