Qt 4.8
qelfparser_p.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qelfparser_p.h"
43 
44 #ifndef QT_NO_LIBRARY
45 #if defined (Q_OF_ELF) && defined(Q_CC_GNU)
46 
47 #include "qlibrary_p.h"
48 #include <qdebug.h>
49 
51 
52 // #define QELFPARSER_DEBUG 1
53 
54 const char *QElfParser::parseSectionHeader(const char *data, ElfSectionHeader *sh)
55 {
56  sh->name = read<qelfword_t>(data);
57  data += sizeof(qelfword_t); // sh_name
58  sh->type = read<qelfword_t>(data);
59  data += sizeof(qelfword_t) // sh_type
60  + sizeof(qelfaddr_t) // sh_flags
61  + sizeof(qelfaddr_t); // sh_addr
62  sh->offset = read<qelfoff_t>(data);
63  data += sizeof(qelfoff_t); // sh_offset
64  sh->size = read<qelfoff_t>(data);
65  data += sizeof(qelfoff_t); // sh_size
66  return data;
67 }
68 
69 int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library, QLibraryPrivate *lib, long *pos, ulong *sectionlen)
70 {
71 #if defined(QELFPARSER_DEBUG)
72  qDebug() << "QElfParser::parse " << library;
73 #endif
74 
75  if (fdlen < 64){
76  if (lib)
77  lib->errorString = QLibrary::tr("'%1' is not an ELF object (%2)").arg(library).arg(QLatin1String("file too small"));
78  return NotElf;
79  }
80  const char *data = dataStart;
81  if (qstrncmp(data, "\177ELF", 4) != 0) {
82  if (lib)
83  lib->errorString = QLibrary::tr("'%1' is not an ELF object").arg(library);
84  return NotElf;
85  }
86  // 32 or 64 bit
87  if (data[4] != 1 && data[4] != 2) {
88  if (lib)
89  lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("odd cpu architecture"));
90  return Corrupt;
91  }
92  m_bits = (data[4] << 5);
93 
94  /* If you remove this check, to read ELF objects of a different arch, please make sure you modify the typedefs
95  to match the _plugin_ architecture.
96  */
97  if ((sizeof(void*) == 4 && m_bits != 32) || (sizeof(void*) == 8 && m_bits != 64)) {
98  if (lib)
99  lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("wrong cpu architecture"));
100  return Corrupt;
101  }
102  // endian
103  if (data[5] == 0) {
104  if (lib)
105  lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("odd endianess"));
106  return Corrupt;
107  }
108  m_endian = (data[5] == 1 ? ElfLittleEndian : ElfBigEndian);
109 
110  data += 16 // e_ident
111  + sizeof(qelfhalf_t) // e_type
112  + sizeof(qelfhalf_t) // e_machine
113  + sizeof(qelfword_t) // e_version
114  + sizeof(qelfaddr_t) // e_entry
115  + sizeof(qelfoff_t); // e_phoff
116 
117  qelfoff_t e_shoff = read<qelfoff_t> (data);
118  data += sizeof(qelfoff_t) // e_shoff
119  + sizeof(qelfword_t); // e_flags
120 
121  qelfhalf_t e_shsize = read<qelfhalf_t> (data);
122 
123  if (e_shsize > fdlen) {
124  if (lib)
125  lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("unexpected e_shsize"));
126  return Corrupt;
127  }
128 
129  data += sizeof(qelfhalf_t) // e_ehsize
130  + sizeof(qelfhalf_t) // e_phentsize
131  + sizeof(qelfhalf_t); // e_phnum
132 
133  qelfhalf_t e_shentsize = read<qelfhalf_t> (data);
134 
135  if (e_shentsize % 4){
136  if (lib)
137  lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("unexpected e_shentsize"));
138  return Corrupt;
139  }
140  data += sizeof(qelfhalf_t); // e_shentsize
141  qelfhalf_t e_shnum = read<qelfhalf_t> (data);
142  data += sizeof(qelfhalf_t); // e_shnum
143  qelfhalf_t e_shtrndx = read<qelfhalf_t> (data);
144  data += sizeof(qelfhalf_t); // e_shtrndx
145 
146  if ((quint32)(e_shnum * e_shentsize) > fdlen) {
147  if (lib)
148  lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
149  .arg(QLatin1String("announced %2 sections, each %3 bytes, exceed file size"))
150  .arg(e_shnum).arg(e_shentsize);
151  return Corrupt;
152  }
153 
154 #if defined(QELFPARSER_DEBUG)
155  qDebug() << e_shnum << "sections starting at " << ("0x" + QByteArray::number(e_shoff, 16)).data() << "each" << e_shentsize << "bytes";
156 #endif
157 
158  ElfSectionHeader strtab;
159  qulonglong soff = e_shoff + e_shentsize * (e_shtrndx);
160 
161  if ((soff + e_shentsize) > fdlen || soff % 4 || soff == 0) {
162  if (lib)
163  lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
164  .arg(QLatin1String("shstrtab section header seems to be at %1"))
165  .arg(QString::number(soff, 16));
166  return Corrupt;
167  }
168 
169  parseSectionHeader(dataStart + soff, &strtab);
170  m_stringTableFileOffset = strtab.offset;
171 
172  if ((quint32)(m_stringTableFileOffset + e_shentsize) >= fdlen || m_stringTableFileOffset == 0) {
173  if (lib)
174  lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
175  .arg(QLatin1String("string table seems to be at %1"))
176  .arg(QString::number(soff, 16));
177  return Corrupt;
178  }
179 
180 #if defined(QELFPARSER_DEBUG)
181  qDebug(".shstrtab at 0x%s", QByteArray::number(m_stringTableFileOffset, 16).data());
182 #endif
183 
184  const char *s = dataStart + e_shoff;
185  for (int i = 0; i < e_shnum; ++i) {
186  ElfSectionHeader sh;
187  parseSectionHeader(s, &sh);
188  if (sh.name == 0) {
189  s += e_shentsize;
190  continue;
191  }
192  const char *shnam = dataStart + m_stringTableFileOffset + sh.name;
193 
194  if (m_stringTableFileOffset + sh.name > fdlen) {
195  if (lib)
196  lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
197  .arg(QLatin1String("section name %2 of %3 behind end of file"))
198  .arg(i).arg(e_shnum);
199  return Corrupt;
200  }
201 
202 #if defined(QELFPARSER_DEBUG)
203  qDebug() << "++++" << i << shnam;
204 #endif
205 
206  if (qstrcmp(shnam, ".qtplugin") == 0 || qstrcmp(shnam, ".rodata") == 0) {
207  if (!(sh.type & 0x1)) {
208  if (shnam[1] == 'r') {
209  if (lib)
210  lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
211  .arg(QLatin1String("empty .rodata. not a library."));
212  return Corrupt;
213  }
214 #if defined(QELFPARSER_DEBUG)
215  qDebug()<<"section is not program data. skipped.";
216 #endif
217  s += e_shentsize;
218  continue;
219  }
220 
221  if (sh.offset == 0 || (sh.offset + sh.size) > fdlen) {
222  if (lib)
223  lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
224  .arg(QLatin1String("missing section data. This is not a library."));
225  return Corrupt;
226  }
227  *pos = sh.offset;
228  *sectionlen = sh.size - 1;
229  if (shnam[1] == 'q')
230  return Ok;
231  }
232  s += e_shentsize;
233  }
234  return NoQtSection;
235 }
236 
238 
239 #endif // defined(Q_OF_ELF) && defined(Q_CC_GNU)
240 #endif // QT_NO_LIBRARY
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qstring.cpp:6448
int qstrncmp(const char *str1, const char *str2, uint len)
Definition: qbytearray.h:101
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
The QString class provides a Unicode character string.
Definition: qstring.h:83
int qstrcmp(const char *str1, const char *str2)
A safe strcmp() function.
Definition: qbytearray.cpp:231
Q_CORE_EXPORT void qDebug(const char *,...)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
int size() const
Returns the number of characters in this string.
Definition: qstring.h:102
static const char * data(const QByteArray &arr)
unsigned long ulong
Definition: qglobal.h:997
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
QString errorString
Definition: qlibrary_p.h:99
Definition: qbezier.cpp:259
unsigned int quint32
Definition: qglobal.h:938
quint64 qulonglong
Definition: qglobal.h:952
static QByteArray number(int, int base=10)
Returns a byte array containing the string equivalent of the number n to base base (10 by default)...