@@ -170,17 +170,16 @@ Process::load()
170170 if (auxv)
171171 processAUXV (*auxv);
172172
173- if (!execImage)
174- throw (Exception () << " no executable image located for process" );
175-
176173 try {
177174 Elf::Addr r_debug_addr = findRDebugAddr ();
178175 bool isStatic = r_debug_addr == 0 || r_debug_addr == Elf::Addr (-1 );
179176
180- if (isStatic)
181- addElfObject (" " , execImage, 0 );
182- else
177+ if (isStatic) {
178+ if (execImage)
179+ addElfObject (" " , execImage, 0 );
180+ } else {
183181 loadSharedObjects (r_debug_addr);
182+ }
184183 }
185184 catch (const Exception &) {
186185 // We were unable to read the link map.
@@ -218,14 +217,35 @@ auxtype2str(int auxtype) {
218217#undef AUX_TYPE
219218}
220219
220+ namespace {
221+ Elf::Addr
222+ extractDtDebugFromDynamicSegment (Process &proc, const Elf::Phdr &phdr, Elf::Addr loadAddr, const char *loc) {
223+ auto dynReader = proc.io ->view (" PT_DYNAMIC segment" , phdr.p_vaddr + loadAddr, phdr.p_filesz );
224+ ReaderArray<Elf::Dyn> dynamic (*dynReader);
225+ for (auto &dyn : dynamic) {
226+ if (dyn.d_tag == DT_DEBUG && dyn.d_un .d_ptr != 0 ) {
227+ if (proc.context .verbose )
228+ *proc.context .debug << " found rdebugaddr via DT_DEBUG at "
229+ << std::hex << dyn.d_un .d_ptr << std::dec << " in " << loc << " \n " ;
230+ return dyn.d_un .d_ptr ;
231+ }
232+ }
233+ return 0 ;
234+ }
235+ }
236+
237+
221238void
222239Process::processAUXV (const Reader &auxio)
223240{
241+ Elf::Addr phOff = 0 ;
242+ size_t phNum = 0 ;
243+
224244 for (auto &aux : ReaderArray<Elf::auxv_t >(auxio)) {
225245 Elf::Addr hdr = aux.a_un .a_val ;
246+ if (aux.a_type == AT_NULL)
247+ break ;
226248 switch (aux.a_type ) {
227- case AT_NULL: // Indicates end of the AUXV vector.
228- return ;
229249 case AT_ENTRY: {
230250 if (context.verbose > 2 )
231251 *context.debug << " auxv: AT_ENTRY=" << hdr << std::endl;
@@ -283,12 +303,48 @@ Process::processAUXV(const Reader &auxio)
283303
284304 break ;
285305 }
306+
286307#endif
308+ case AT_PHDR:
309+ phOff = hdr;
310+ break ;
311+ case AT_PHNUM:
312+ phNum = hdr;
313+ break ;
287314 default :
288315 if (context.verbose > 2 )
289316 *context.debug << " auxv: " << auxtype2str ( aux.a_type ) << " : " << hdr << std::endl;
290317 }
291318 }
319+ if (phOff != 0 && phNum != 0 ) {
320+ auto view = io->view (" phdrs" , phOff, sizeof (Elf::Phdr) * phNum);
321+ ReaderArray<Elf::Phdr> headers { *view };
322+ std::optional<Elf::Phdr> ptDynamic;
323+
324+ std::vector<Elf::Addr> notes;
325+ try {
326+ for ( auto phdr : headers ) {
327+ switch (phdr.p_type ) {
328+ case PT_PHDR:
329+ // that's the diff between the va's in the process vs the image.
330+ execBase = phOff - phdr.p_vaddr ;
331+ break ;
332+ case PT_NOTE:
333+ notes.push_back (phdr.p_vaddr );
334+ break ;
335+ case PT_DYNAMIC:
336+ ptDynamic = phdr;
337+ break ;
338+ }
339+ }
340+ }
341+ catch (const Exception &ex) {
342+ // We may not have a full image of the phdrs.
343+ }
344+
345+ if (ptDynamic && dt_debug == 0 )
346+ dt_debug = extractDtDebugFromDynamicSegment (*this , *ptDynamic, execBase, " aux vector" );
347+ }
292348}
293349
294350static bool
@@ -729,13 +785,17 @@ Process::loadSharedObjects(Elf::Addr rdebugAddr)
729785 // If we see the executable, just add it in and avoid going through the path
730786 // replacement work
731787 if (mapAddr == Elf::Addr (rDebug.r_map )) {
732- auto loadAddr = entry - execImage->getHeader ().e_entry ;
733- if (loadAddr != map.l_addr ) {
734- *context.debug << " calculated load address for executable from process entrypoint ("
735- << std::hex << loadAddr << " ) does not match link map (" << map.l_addr
736- << " ). Trusting link-map\n " << std::dec;
788+ if (execImage) {
789+ if (execBase == 0 ) {
790+ execBase = entry - execImage->getHeader ().e_entry ;
791+ }
792+ if (execBase != map.l_addr ) {
793+ *context.debug << " calculated load address for executable from process entrypoint ("
794+ << std::hex << execBase << " ) does not match link map (" << map.l_addr
795+ << " ). Trusting link-map\n " << std::dec;
796+ }
797+ addElfObject (" (exe)" , execImage, map.l_addr );
737798 }
738- addElfObject (" (exe)" , execImage, map.l_addr );
739799 continue ;
740800 }
741801 // If we've loaded the VDSO, and we see it in the link map, just skip it.
@@ -769,34 +829,43 @@ Process::findRDebugAddr()
769829 * supplied by the kernel, and also the executable's desired entrypoint -
770830 * the difference is the load address.
771831 */
772- Elf::Off loadAddr = entry - execImage->getHeader ().e_entry ;
773-
774- // Find DT_DEBUG in the process's dynamic section.
775- for (auto &segment : execImage->getSegments (PT_DYNAMIC)) {
776- // Read from the process, not the executable - the linker will have updated the content.
777- auto dynReader = io->view (" PT_DYNAMIC segment" , segment.p_vaddr + loadAddr, segment.p_filesz );
778- ReaderArray<Elf::Dyn> dynamic (*dynReader);
779- for (auto &dyn : dynamic)
780- if (dyn.d_tag == DT_DEBUG && dyn.d_un .d_ptr != 0 )
781- return dyn.d_un .d_ptr ;
782- }
783- /*
784- * If there's no DT_DEBUG, we've probably got someone executing a shared
785- * library, which doesn't have an _r_debug symbol. Use the address of
786- * _r_debug in the interpreter
787- */
788- if (interpBase && execImage->getInterpreter () != " " ) {
789- try {
790- addElfObject (execImage->getInterpreter (), nullptr , interpBase);
791- return resolveSymbol (" _r_debug" , false ,
792- [this ](const std::string_view name) {
793- return execImage->getInterpreter () == name;
794- });
832+ if (dt_debug == 0 && execImage) {
833+ Elf::Off loadAddr = entry - execImage->getHeader ().e_entry ;
834+
835+ // Find DT_DEBUG in the process's dynamic section.
836+ for (auto &segment : execImage->getSegments (PT_DYNAMIC)) {
837+ // Read from the process, not the executable - the linker will have updated the content.
838+ auto dynReader = io->view (" PT_DYNAMIC segment" , segment.p_vaddr + loadAddr, segment.p_filesz );
839+ ReaderArray<Elf::Dyn> dynamic (*dynReader);
840+ for (auto &dyn : dynamic) {
841+ if (dyn.d_tag == DT_DEBUG && dyn.d_un .d_ptr != 0 ) {
842+ dt_debug = dyn.d_un .d_ptr ;
843+ break ;
844+ }
845+ }
846+ if (dt_debug)
847+ break ;
795848 }
796- catch (...) {
849+ }
850+ if (dt_debug == 0 && interpBase && execImage) {
851+ /*
852+ * If there's no DT_DEBUG, we've probably got someone executing a shared
853+ * library, which doesn't have an _r_debug symbol. Use the address of
854+ * _r_debug in the interpreter
855+ */
856+ if (interpBase && execImage->getInterpreter () != " " ) {
857+ try {
858+ addElfObject (execImage->getInterpreter (), nullptr , interpBase);
859+ return resolveSymbol (" _r_debug" , false ,
860+ [this ](const std::string_view name) {
861+ return execImage->getInterpreter () == name;
862+ });
863+ }
864+ catch (...) {
865+ }
797866 }
798867 }
799- return 0 ;
868+ return dt_debug ;
800869}
801870
802871std::tuple<Elf::Addr, Elf::Object::sptr, const Elf::Phdr *>
@@ -806,7 +875,7 @@ Process::findSegment(Elf::Addr addr)
806875 if (it != objects.begin ()) {
807876 --it;
808877 auto obj = it->second .object (context);
809- if (it->first + obj->endVA () >= addr) {
878+ if (obj && it->first + obj->endVA () >= addr) {
810879 auto segment = obj->getSegmentForAddress (addr - it->first );
811880 if (segment)
812881 return std::make_tuple (it->first , obj, segment);
@@ -823,6 +892,8 @@ Process::resolveSymbolDetail(const char *name, bool includeDebug,
823892 if (!match (loaded.second .name ()))
824893 continue ;
825894 auto obj = loaded.second .object (context);
895+ if (!obj)
896+ continue ;
826897 auto [sym,idx] = obj->findDynamicSymbol (name);
827898 if (sym.st_shndx != SHN_UNDEF)
828899 return std::make_tuple (obj, loaded.first , sym);
0 commit comments