xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- ThreadElfCore.cpp -------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Target/RegisterContext.h"
10 #include "lldb/Target/StopInfo.h"
11 #include "lldb/Target/Target.h"
12 #include "lldb/Target/UnixSignals.h"
13 #include "lldb/Target/Unwind.h"
14 #include "lldb/Utility/DataExtractor.h"
15 #include "lldb/Utility/LLDBLog.h"
16 #include "lldb/Utility/Log.h"
17 #include "lldb/Utility/ProcessInfo.h"
18 
19 #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
20 #include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
21 #include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
22 #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
23 #include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
24 #ifdef LLDB_ENABLE_ALL
25 #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h"
26 #endif // LLDB_ENABLE_ALL
27 #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
28 #include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h"
29 #include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
30 #include "Plugins/Process/Utility/RegisterContextOpenBSD_i386.h"
31 #include "Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h"
32 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
33 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
34 #include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h"
35 #include "ProcessElfCore.h"
36 #include "RegisterContextLinuxCore_x86_64.h"
37 #include "RegisterContextPOSIXCore_arm.h"
38 #include "RegisterContextPOSIXCore_arm64.h"
39 #include "RegisterContextPOSIXCore_loongarch64.h"
40 #include "RegisterContextPOSIXCore_mips64.h"
41 #include "RegisterContextPOSIXCore_powerpc.h"
42 #include "RegisterContextPOSIXCore_ppc64le.h"
43 #include "RegisterContextPOSIXCore_riscv32.h"
44 #include "RegisterContextPOSIXCore_riscv64.h"
45 #ifdef LLDB_ENABLE_ALL
46 #include "RegisterContextPOSIXCore_s390x.h"
47 #endif // LLDB_ENABLE_ALL
48 #include "RegisterContextPOSIXCore_x86_64.h"
49 #include "ThreadElfCore.h"
50 
51 #include <memory>
52 
53 using namespace lldb;
54 using namespace lldb_private;
55 
56 // Construct a Thread object with given data
ThreadElfCore(Process & process,const ThreadData & td)57 ThreadElfCore::ThreadElfCore(Process &process, const ThreadData &td)
58     : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(),
59       m_gpregset_data(td.gpregset), m_notes(td.notes),
60       m_siginfo_bytes(std::move(td.siginfo_bytes)), m_signo(td.signo) {}
61 
~ThreadElfCore()62 ThreadElfCore::~ThreadElfCore() { DestroyThread(); }
63 
RefreshStateAfterStop()64 void ThreadElfCore::RefreshStateAfterStop() {
65   GetRegisterContext()->InvalidateIfNeeded(false);
66 }
67 
GetRegisterContext()68 RegisterContextSP ThreadElfCore::GetRegisterContext() {
69   if (!m_reg_context_sp) {
70     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
71   }
72   return m_reg_context_sp;
73 }
74 
75 RegisterContextSP
CreateRegisterContextForFrame(StackFrame * frame)76 ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
77   RegisterContextSP reg_ctx_sp;
78   uint32_t concrete_frame_idx = 0;
79   Log *log = GetLog(LLDBLog::Thread);
80 
81   if (frame)
82     concrete_frame_idx = frame->GetConcreteFrameIndex();
83 
84   bool is_linux = false;
85   if (concrete_frame_idx == 0) {
86     if (m_thread_reg_ctx_sp)
87       return m_thread_reg_ctx_sp;
88 
89     ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get());
90     ArchSpec arch = process->GetArchitecture();
91     RegisterInfoInterface *reg_interface = nullptr;
92 
93     switch (arch.GetTriple().getOS()) {
94     case llvm::Triple::FreeBSD: {
95       switch (arch.GetMachine()) {
96       case llvm::Triple::aarch64:
97       case llvm::Triple::arm:
98         break;
99       case llvm::Triple::ppc:
100         reg_interface = new RegisterContextFreeBSD_powerpc32(arch);
101         break;
102       case llvm::Triple::ppc64:
103       case llvm::Triple::ppc64le:
104         reg_interface = new RegisterContextFreeBSD_powerpc64(arch);
105         break;
106       case llvm::Triple::mips64:
107         reg_interface = new RegisterContextFreeBSD_mips64(arch);
108         break;
109       case llvm::Triple::x86:
110         reg_interface = new RegisterContextFreeBSD_i386(arch);
111         break;
112       case llvm::Triple::x86_64:
113         reg_interface = new RegisterContextFreeBSD_x86_64(arch);
114         break;
115       default:
116         break;
117       }
118       break;
119     }
120 
121     case llvm::Triple::NetBSD: {
122       switch (arch.GetMachine()) {
123       case llvm::Triple::aarch64:
124         break;
125       case llvm::Triple::x86:
126         reg_interface = new RegisterContextNetBSD_i386(arch);
127         break;
128       case llvm::Triple::x86_64:
129         reg_interface = new RegisterContextNetBSD_x86_64(arch);
130         break;
131       default:
132         break;
133       }
134       break;
135     }
136 
137     case llvm::Triple::Linux: {
138       is_linux = true;
139       switch (arch.GetMachine()) {
140       case llvm::Triple::aarch64:
141         break;
142       case llvm::Triple::ppc64le:
143         reg_interface = new RegisterInfoPOSIX_ppc64le(arch);
144         break;
145 #ifdef LLDB_ENABLE_ALL
146       case llvm::Triple::systemz:
147         reg_interface = new RegisterContextLinux_s390x(arch);
148         break;
149 #endif // LLDB_ENABLE_ALL
150       case llvm::Triple::x86:
151         reg_interface = new RegisterContextLinux_i386(arch);
152         break;
153       case llvm::Triple::x86_64:
154         reg_interface = new RegisterContextLinux_x86_64(arch);
155         break;
156       default:
157         break;
158       }
159       break;
160     }
161 
162     case llvm::Triple::OpenBSD: {
163       switch (arch.GetMachine()) {
164       case llvm::Triple::aarch64:
165         break;
166       case llvm::Triple::x86:
167         reg_interface = new RegisterContextOpenBSD_i386(arch);
168         break;
169       case llvm::Triple::x86_64:
170         reg_interface = new RegisterContextOpenBSD_x86_64(arch);
171         break;
172       default:
173         break;
174       }
175       break;
176     }
177 
178     default:
179       break;
180     }
181 
182     if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64 &&
183         arch.GetMachine() != llvm::Triple::arm &&
184         arch.GetMachine() != llvm::Triple::loongarch64 &&
185         arch.GetMachine() != llvm::Triple::riscv64 &&
186         arch.GetMachine() != llvm::Triple::riscv32) {
187       LLDB_LOGF(log, "elf-core::%s:: Architecture(%d) or OS(%d) not supported",
188                 __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS());
189       assert(false && "Architecture or OS not supported");
190     }
191 
192     switch (arch.GetMachine()) {
193     case llvm::Triple::aarch64:
194       m_thread_reg_ctx_sp = RegisterContextCorePOSIX_arm64::Create(
195           *this, arch, m_gpregset_data, m_notes);
196       break;
197     case llvm::Triple::arm:
198       m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_arm>(
199           *this, std::make_unique<RegisterInfoPOSIX_arm>(arch), m_gpregset_data,
200           m_notes);
201       break;
202     case llvm::Triple::loongarch64:
203       m_thread_reg_ctx_sp = RegisterContextCorePOSIX_loongarch64::Create(
204           *this, arch, m_gpregset_data, m_notes);
205       break;
206     case llvm::Triple::riscv32:
207       m_thread_reg_ctx_sp = RegisterContextCorePOSIX_riscv32::Create(
208           *this, arch, m_gpregset_data, m_notes);
209       break;
210     case llvm::Triple::riscv64:
211       m_thread_reg_ctx_sp = RegisterContextCorePOSIX_riscv64::Create(
212           *this, arch, m_gpregset_data, m_notes);
213       break;
214     case llvm::Triple::mipsel:
215     case llvm::Triple::mips:
216       m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>(
217           *this, reg_interface, m_gpregset_data, m_notes);
218       break;
219     case llvm::Triple::mips64:
220     case llvm::Triple::mips64el:
221       m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>(
222           *this, reg_interface, m_gpregset_data, m_notes);
223       break;
224     case llvm::Triple::ppc:
225     case llvm::Triple::ppc64:
226       m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_powerpc>(
227           *this, reg_interface, m_gpregset_data, m_notes);
228       break;
229     case llvm::Triple::ppc64le:
230       m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_ppc64le>(
231           *this, reg_interface, m_gpregset_data, m_notes);
232       break;
233 #ifdef LLDB_ENABLE_ALL
234     case llvm::Triple::systemz:
235       m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_s390x>(
236           *this, reg_interface, m_gpregset_data, m_notes);
237       break;
238 #endif // LLDB_ENABLE_ALL
239     case llvm::Triple::x86:
240     case llvm::Triple::x86_64:
241       if (is_linux) {
242         m_thread_reg_ctx_sp = std::make_shared<RegisterContextLinuxCore_x86_64>(
243               *this, reg_interface, m_gpregset_data, m_notes);
244       } else {
245         m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_x86_64>(
246               *this, reg_interface, m_gpregset_data, m_notes);
247       }
248       break;
249     default:
250       break;
251     }
252 
253     reg_ctx_sp = m_thread_reg_ctx_sp;
254   } else {
255     reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
256   }
257   return reg_ctx_sp;
258 }
259 
260 llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
GetSiginfo(size_t max_size) const261 ThreadElfCore::GetSiginfo(size_t max_size) const {
262   if (m_siginfo_bytes.empty())
263     return llvm::createStringError(llvm::inconvertibleErrorCode(),
264                                    "no siginfo note");
265 
266   return llvm::MemoryBuffer::getMemBufferCopy(m_siginfo_bytes,
267                                               "siginfo note bytes");
268 }
269 
CalculateStopInfo()270 bool ThreadElfCore::CalculateStopInfo() {
271   ProcessSP process_sp(GetProcess());
272   if (!process_sp)
273     return false;
274 
275   PlatformSP platform_sp = process_sp->GetTarget().GetPlatform();
276   if (platform_sp) {
277     lldb::StopInfoSP stopinfo_sp = platform_sp->GetStopInfoFromSiginfo(*this);
278     // The platform SP can optionally handle creating the stop info from the
279     // siginfo value however it's not guaraunteed to be implemented on every
280     // platform, so if we fall through this case, we create from just the signo.
281     if (stopinfo_sp) {
282       SetStopInfo(std::move(stopinfo_sp));
283       return true;
284     }
285   }
286 
287   SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, m_signo));
288   return true;
289 }
290 
291 // Parse PRSTATUS from NOTE entry
ELFLinuxPrStatus()292 ELFLinuxPrStatus::ELFLinuxPrStatus() {
293   memset(this, 0, sizeof(ELFLinuxPrStatus));
294 }
295 
GetSize(const lldb_private::ArchSpec & arch)296 size_t ELFLinuxPrStatus::GetSize(const lldb_private::ArchSpec &arch) {
297   constexpr size_t mips_linux_pr_status_size_o32 = 96;
298   constexpr size_t mips_linux_pr_status_size_n32 = 72;
299   constexpr size_t num_ptr_size_members = 10;
300   if (arch.IsMIPS()) {
301     std::string abi = arch.GetTargetABI();
302     assert(!abi.empty() && "ABI is not set");
303     if (abi == "n64")
304       return sizeof(ELFLinuxPrStatus);
305     else if (abi == "o32")
306       return mips_linux_pr_status_size_o32;
307     // N32 ABI
308     return mips_linux_pr_status_size_n32;
309   }
310   switch (arch.GetCore()) {
311   case lldb_private::ArchSpec::eCore_x86_32_i386:
312   case lldb_private::ArchSpec::eCore_x86_32_i486:
313     return 72;
314   default:
315     if (arch.GetAddressByteSize() == 8)
316       return sizeof(ELFLinuxPrStatus);
317     else
318       return sizeof(ELFLinuxPrStatus) - num_ptr_size_members * 4;
319   }
320 }
321 
Parse(const DataExtractor & data,const ArchSpec & arch)322 Status ELFLinuxPrStatus::Parse(const DataExtractor &data,
323                                const ArchSpec &arch) {
324   Status error;
325   if (GetSize(arch) > data.GetByteSize()) {
326     error = Status::FromErrorStringWithFormat(
327         "NT_PRSTATUS size should be %zu, but the remaining bytes are: %" PRIu64,
328         GetSize(arch), data.GetByteSize());
329     return error;
330   }
331 
332   // Read field by field to correctly account for endianess of both the core
333   // dump and the platform running lldb.
334   offset_t offset = 0;
335   si_signo = data.GetU32(&offset);
336   si_code = data.GetU32(&offset);
337   si_errno = data.GetU32(&offset);
338 
339   pr_cursig = data.GetU16(&offset);
340   offset += 2; // pad
341 
342   pr_sigpend = data.GetAddress(&offset);
343   pr_sighold = data.GetAddress(&offset);
344 
345   pr_pid = data.GetU32(&offset);
346   pr_ppid = data.GetU32(&offset);
347   pr_pgrp = data.GetU32(&offset);
348   pr_sid = data.GetU32(&offset);
349 
350   pr_utime.tv_sec = data.GetAddress(&offset);
351   pr_utime.tv_usec = data.GetAddress(&offset);
352 
353   pr_stime.tv_sec = data.GetAddress(&offset);
354   pr_stime.tv_usec = data.GetAddress(&offset);
355 
356   pr_cutime.tv_sec = data.GetAddress(&offset);
357   pr_cutime.tv_usec = data.GetAddress(&offset);
358 
359   pr_cstime.tv_sec = data.GetAddress(&offset);
360   pr_cstime.tv_usec = data.GetAddress(&offset);
361 
362   return error;
363 }
364 
365 static struct compat_timeval
copy_timespecs(const ProcessInstanceInfo::timespec & oth)366 copy_timespecs(const ProcessInstanceInfo::timespec &oth) {
367   using sec_t = decltype(compat_timeval::tv_sec);
368   using usec_t = decltype(compat_timeval::tv_usec);
369   return {static_cast<sec_t>(oth.tv_sec), static_cast<usec_t>(oth.tv_usec)};
370 }
371 
372 std::optional<ELFLinuxPrStatus>
Populate(const lldb::ThreadSP & thread_sp)373 ELFLinuxPrStatus::Populate(const lldb::ThreadSP &thread_sp) {
374   ELFLinuxPrStatus prstatus{};
375   prstatus.pr_pid = thread_sp->GetID();
376   lldb::ProcessSP process_sp = thread_sp->GetProcess();
377   ProcessInstanceInfo info;
378   if (!process_sp->GetProcessInfo(info))
379     return std::nullopt;
380 
381   prstatus.pr_ppid = info.GetParentProcessID();
382   prstatus.pr_pgrp = info.GetProcessGroupID();
383   prstatus.pr_sid = info.GetProcessSessionID();
384   prstatus.pr_utime = copy_timespecs(info.GetUserTime());
385   prstatus.pr_stime = copy_timespecs(info.GetSystemTime());
386   prstatus.pr_cutime = copy_timespecs(info.GetCumulativeUserTime());
387   prstatus.pr_cstime = copy_timespecs(info.GetCumulativeSystemTime());
388   return prstatus;
389 }
390 
391 // Parse PRPSINFO from NOTE entry
ELFLinuxPrPsInfo()392 ELFLinuxPrPsInfo::ELFLinuxPrPsInfo() {
393   memset(this, 0, sizeof(ELFLinuxPrPsInfo));
394 }
395 
GetSize(const lldb_private::ArchSpec & arch)396 size_t ELFLinuxPrPsInfo::GetSize(const lldb_private::ArchSpec &arch) {
397   constexpr size_t mips_linux_pr_psinfo_size_o32_n32 = 128;
398   if (arch.IsMIPS()) {
399     uint8_t address_byte_size = arch.GetAddressByteSize();
400     if (address_byte_size == 8)
401       return sizeof(ELFLinuxPrPsInfo);
402     return mips_linux_pr_psinfo_size_o32_n32;
403   }
404 
405   switch (arch.GetCore()) {
406   case lldb_private::ArchSpec::eCore_s390x_generic:
407   case lldb_private::ArchSpec::eCore_x86_64_x86_64:
408     return sizeof(ELFLinuxPrPsInfo);
409   case lldb_private::ArchSpec::eCore_x86_32_i386:
410   case lldb_private::ArchSpec::eCore_x86_32_i486:
411     return 124;
412   default:
413     return 0;
414   }
415 }
416 
Parse(const DataExtractor & data,const ArchSpec & arch)417 Status ELFLinuxPrPsInfo::Parse(const DataExtractor &data,
418                                const ArchSpec &arch) {
419   Status error;
420   ByteOrder byteorder = data.GetByteOrder();
421   if (GetSize(arch) > data.GetByteSize()) {
422     error = Status::FromErrorStringWithFormat(
423         "NT_PRPSINFO size should be %zu, but the remaining bytes are: %" PRIu64,
424         GetSize(arch), data.GetByteSize());
425     return error;
426   }
427   size_t size = 0;
428   offset_t offset = 0;
429 
430   pr_state = data.GetU8(&offset);
431   pr_sname = data.GetU8(&offset);
432   pr_zomb = data.GetU8(&offset);
433   pr_nice = data.GetU8(&offset);
434   if (data.GetAddressByteSize() == 8) {
435     // Word align the next field on 64 bit.
436     offset += 4;
437   }
438 
439   pr_flag = data.GetAddress(&offset);
440 
441   if (arch.IsMIPS()) {
442     // The pr_uid and pr_gid is always 32 bit irrespective of platforms
443     pr_uid = data.GetU32(&offset);
444     pr_gid = data.GetU32(&offset);
445   } else {
446     // 16 bit on 32 bit platforms, 32 bit on 64 bit platforms
447     pr_uid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1);
448     pr_gid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1);
449   }
450 
451   pr_pid = data.GetU32(&offset);
452   pr_ppid = data.GetU32(&offset);
453   pr_pgrp = data.GetU32(&offset);
454   pr_sid = data.GetU32(&offset);
455 
456   size = 16;
457   data.ExtractBytes(offset, size, byteorder, pr_fname);
458   offset += size;
459 
460   size = 80;
461   data.ExtractBytes(offset, size, byteorder, pr_psargs);
462   offset += size;
463 
464   return error;
465 }
466 
467 std::optional<ELFLinuxPrPsInfo>
Populate(const lldb::ProcessSP & process_sp)468 ELFLinuxPrPsInfo::Populate(const lldb::ProcessSP &process_sp) {
469   ProcessInstanceInfo info;
470   if (!process_sp->GetProcessInfo(info))
471     return std::nullopt;
472 
473   return Populate(info, process_sp->GetState());
474 }
475 
476 std::optional<ELFLinuxPrPsInfo>
Populate(const lldb_private::ProcessInstanceInfo & info,lldb::StateType process_state)477 ELFLinuxPrPsInfo::Populate(const lldb_private::ProcessInstanceInfo &info,
478                            lldb::StateType process_state) {
479   ELFLinuxPrPsInfo prpsinfo{};
480   prpsinfo.pr_pid = info.GetProcessID();
481   prpsinfo.pr_nice = info.GetPriorityValue().value_or(0);
482   prpsinfo.pr_zomb = 0;
483   if (auto zombie_opt = info.IsZombie(); zombie_opt.value_or(false)) {
484     prpsinfo.pr_zomb = 1;
485   }
486   /**
487    * In the linux kernel this comes from:
488    * state = READ_ONCE(p->__state);
489    * i = state ? ffz(~state) + 1 : 0;
490    * psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i];
491    *
492    * So we replicate that here. From proc_pid_stats(5)
493    * R = Running
494    * S = Sleeping on uninterrutible wait
495    * D = Waiting on uninterruptable disk sleep
496    * T = Tracing stop
497    * Z = Zombie
498    * W = Paging
499    */
500   switch (process_state) {
501   case lldb::StateType::eStateSuspended:
502     prpsinfo.pr_sname = 'S';
503     prpsinfo.pr_state = 1;
504     break;
505   case lldb::StateType::eStateStopped:
506     [[fallthrough]];
507   case lldb::StateType::eStateStepping:
508     prpsinfo.pr_sname = 'T';
509     prpsinfo.pr_state = 3;
510     break;
511   case lldb::StateType::eStateUnloaded:
512     [[fallthrough]];
513   case lldb::StateType::eStateRunning:
514     prpsinfo.pr_sname = 'R';
515     prpsinfo.pr_state = 0;
516     break;
517   default:
518     break;
519   }
520 
521   /**
522    * pr_flags is left as 0. The values (in linux) are specific
523    * to the kernel. We recover them from the proc filesystem
524    * but don't put them in ProcessInfo because it would really
525    * become very linux specific and the utility here seems pretty
526    * dubious
527    */
528 
529   if (info.EffectiveUserIDIsValid())
530     prpsinfo.pr_uid = info.GetUserID();
531 
532   if (info.EffectiveGroupIDIsValid())
533     prpsinfo.pr_gid = info.GetGroupID();
534 
535   if (info.ParentProcessIDIsValid())
536     prpsinfo.pr_ppid = info.GetParentProcessID();
537 
538   if (info.ProcessGroupIDIsValid())
539     prpsinfo.pr_pgrp = info.GetProcessGroupID();
540 
541   if (info.ProcessSessionIDIsValid())
542     prpsinfo.pr_sid = info.GetProcessSessionID();
543 
544   constexpr size_t fname_len = std::extent_v<decltype(prpsinfo.pr_fname)>;
545   static_assert(fname_len > 0, "This should always be non zero");
546   const llvm::StringRef fname = info.GetNameAsStringRef();
547   auto fname_begin = fname.begin();
548   std::copy_n(fname_begin, std::min(fname_len, fname.size()),
549               prpsinfo.pr_fname);
550   prpsinfo.pr_fname[fname_len - 1] = '\0';
551   auto args = info.GetArguments();
552   auto argentry_iterator = std::begin(args);
553   char *psargs = prpsinfo.pr_psargs;
554   char *psargs_end = std::end(prpsinfo.pr_psargs);
555   while (psargs < psargs_end && argentry_iterator != args.end()) {
556     llvm::StringRef argentry = argentry_iterator->ref();
557     size_t len =
558         std::min<size_t>(std::distance(psargs, psargs_end), argentry.size());
559     auto arg_iterator = std::begin(argentry);
560     psargs = std::copy_n(arg_iterator, len, psargs);
561     if (psargs != psargs_end)
562       *(psargs++) = ' ';
563     ++argentry_iterator;
564   }
565   *(psargs - 1) = '\0';
566   return prpsinfo;
567 }
568