Skip to content

Commit 2954519

Browse files
committed
Make sure we can run with no locally available objects.
Add an env var that lets us tell pstack to never open libraries locally. this makes it easier to test debuginfod, and check for correctness for some upstream apps.
1 parent 97e7292 commit 2954519

File tree

5 files changed

+38
-28
lines changed

5 files changed

+38
-28
lines changed

context.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@ Context::flush(std::shared_ptr<Elf::Object> o)
129129
dwarfCache.erase(o);
130130
}
131131

132-
133132
// pretty-printer for key types.
134133
template <typename T> struct ContainerKeyDescr{};
135134
std::ostream &operator << (std::ostream &os, const ContainerKeyDescr<std::filesystem::path> &) { return os << "path"; }
@@ -201,6 +200,8 @@ Context::getImageInPath(const std::vector<std::filesystem::path> &paths, NameMap
201200
*/
202201
std::shared_ptr<Elf::Object>
203202
Context::getImage(const std::filesystem::path &name) {
203+
if (options.noLocalFiles)
204+
return nullptr;
204205
return getImageInPath(exePrefixes, imageByName, name, false, false);
205206
}
206207

libpstack/context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct Options {
2121
bool noExtDebug = false; // don't look for exernal ELF info, i.e., using debuglink, or buildid.
2222
bool withDebuginfod = false; // use debuginfod client library.
2323
bool noBuildIds = false;
24+
bool noLocalFiles = false;
2425
int maxdepth = std::numeric_limits<int>::max();
2526
int maxframes = 30;
2627
};

libpstack/proc.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,10 @@ struct MappedObject {
241241
};
242242

243243
class Process : public ps_prochandle {
244-
Elf::Addr entry;
245-
Elf::Addr dt_debug;
246-
Elf::Addr interpBase;
244+
Elf::Addr entry{};
245+
Elf::Addr dt_debug{};
246+
Elf::Addr interpBase{};
247+
Elf::Addr execBase{};
247248
void loadSharedObjects(Elf::Addr);
248249
Elf::Addr extractDtDebugFromDynamicSegment(const Elf::Phdr &phdr, Elf::Addr loadAddr, const char *);
249250
public:

process.cc

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -172,19 +172,16 @@ Process::load()
172172
auto auxv = getAUXV();
173173
if (auxv)
174174
processAUXV(*auxv);
175-
176-
// by now, we should know what executable was loaded for the process.
177-
if (!execImage)
178-
throw (Exception() << "no executable image located for process");
179-
180175
try {
181-
Elf::Addr r_debug_addr = findRDebugAddr();
182-
bool isStatic = r_debug_addr == 0 || r_debug_addr == Elf::Addr(-1);
176+
findRDebugAddr();
177+
bool isStatic = dt_debug == 0 || dt_debug == Elf::Addr(-1);
183178

184-
if (isStatic)
185-
addElfObject("", execImage, 0);
186-
else
187-
loadSharedObjects(r_debug_addr);
179+
if (isStatic) {
180+
if (execImage)
181+
addElfObject("", execImage, 0);
182+
} else {
183+
loadSharedObjects(dt_debug);
184+
}
188185
}
189186
catch (const Exception &) {
190187
// We were unable to read the link map.
@@ -297,13 +294,14 @@ Process::processAUXV(const Reader &auxio)
297294

298295
break;
299296
}
297+
300298
#endif
301299
case AT_PHDR:
302-
phOff = hdr;
303-
break;
300+
phOff = hdr;
301+
break;
304302
case AT_PHNUM:
305-
phNum = hdr;
306-
break;
303+
phNum = hdr;
304+
break;
307305
default:
308306
break;
309307
}
@@ -820,13 +818,17 @@ Process::loadSharedObjects(Elf::Addr rdebugAddr)
820818
// If we see the executable, just add it in and avoid going through the path
821819
// replacement work
822820
if (mapAddr == Elf::Addr(rDebug.r_map)) {
823-
auto loadAddr = entry - execImage->getHeader().e_entry;
824-
if (loadAddr != map.l_addr) {
825-
*context.debug << "calculated load address for executable from process entrypoint ("
826-
<< std::hex << loadAddr << ") does not match link map (" << map.l_addr
827-
<< "). Trusting link-map\n" << std::dec;
821+
if (execImage) {
822+
if (execBase == 0) {
823+
execBase = entry - execImage->getHeader().e_entry;
824+
}
825+
if (execBase != map.l_addr) {
826+
*context.debug << "calculated load address for executable from process entrypoint ("
827+
<< std::hex << execBase << ") does not match link map (" << map.l_addr
828+
<< "). Trusting link-map\n" << std::dec;
829+
}
830+
addElfObject("(exe)", execImage, map.l_addr);
828831
}
829-
addElfObject("(exe)", execImage, map.l_addr);
830832
continue;
831833
}
832834
// If we've loaded the VDSO, and we see it in the link map, just skip it.
@@ -869,7 +871,7 @@ Process::findRDebugAddr()
869871
* the difference is the load address.
870872
*/
871873

872-
if (dt_debug == 0) {
874+
if (dt_debug == 0 && execImage) {
873875
// Iterate over the PT_DYNAMIC segment of the loaded executable. (We
874876
// should not get here, as we should have found the program headers in
875877
// the AT_PHDR auxv entry, and done this already
@@ -884,7 +886,7 @@ Process::findRDebugAddr()
884886
* library, which doesn't have an _r_debug symbol. Use the address of
885887
* _r_debug in the interpreter
886888
*/
887-
if (dt_debug == 0 && interpBase && execImage->getInterpreter() != "") {
889+
if (dt_debug == 0 && execImage && interpBase && execImage->getInterpreter() != "") {
888890
try {
889891
addElfObject(execImage->getInterpreter(), nullptr, interpBase);
890892
dt_debug = resolveSymbol("_r_debug", false,
@@ -909,7 +911,7 @@ Process::findSegment(Elf::Addr addr)
909911
if (it != objects.begin()) {
910912
--it;
911913
auto obj = it->second.object(context);
912-
if (it->first + obj->endVA() >= addr) {
914+
if (obj && it->first + obj->endVA() >= addr) {
913915
auto segment = obj->getSegmentForAddress(addr - it->first);
914916
if (segment)
915917
return std::make_tuple(it->first, obj, segment);
@@ -926,6 +928,8 @@ Process::resolveSymbolDetail(const char *name, bool includeDebug,
926928
if (!match(loaded.second.name()))
927929
continue;
928930
auto obj = loaded.second.object(context);
931+
if (!obj)
932+
continue;
929933
auto [sym,idx] = obj->findDynamicSymbol(name);
930934
if (sym.st_shndx != SHN_UNDEF)
931935
return std::make_tuple(obj, loaded.first, sym);

pstack.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,9 @@ emain(int argc, char **argv, Context &context)
376376
#ifdef DEBUGINFOD
377377
.add("debuginfod", 'R', "use debuginfod client", Flags::setf( context.options.withDebuginfod ) )
378378
#endif
379+
.add("no-local-files", Flags::LONGONLY,
380+
"don't assume local files match the process's view, and don't open them",
381+
Flags::setf( context.options.noLocalFiles ) )
379382

380383
.parse(argc, argv);
381384

0 commit comments

Comments
 (0)