Lorsqu’un bogue survient en production, il n’est pas toujours aisé de reproduire le problème sur une plateforme de développement pour le corriger par la suite. C’est là que ce type d’outil intervient, car il permet de générer un dump mémoire du processus à problème. En d’autres termes, il permet d’obtenir une copie de la mémoire virtuelle (pile, heap, code assembleur, etc.). Ce contenu est utile pour visualiser une instance gelée du processus et repérer la ligne de code qui a mené au crash de l’application. Nota bene : ProcDump pour Linux génère uniquement des copies de la mémoire vive et des registres d’un processeur. En cela, l’outil est moins complet que la version Windows. Ci-dessous, la liste des options disponibles.
Un détour dans le code source de l’outil permet de voir que la version Linux s’appuie sur l’outil de développement GNU gcore.
Code C : | Sélectionner tout |
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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | int WriteCoreDumpInternal(struct CoreDumpWriter *self) { char date[DATE_LENGTH]; char command[BUFFER_LENGTH]; char ** outputBuffer; char lineBuffer[BUFFER_LENGTH]; char coreDumpFileName[BUFFER_LENGTH]; int lineLength; int i; int rc = 0; time_t rawTime; pid_t gcorePid; struct tm* timerInfo = NULL; FILE *commandPipe = NULL; const char *desc = CoreDumpTypeStrings[self->Type]; char *name = sanitize(self->Config->ProcessName); pid_t pid = self->Config->ProcessId; // allocate output buffer outputBuffer = (char**)malloc(sizeof(char*) * MAX_LINES); if(outputBuffer == NULL){ Log(error, INTERNAL_ERROR); Trace("WriteCoreDumpInternal: failed gcore output buffer allocation"); exit(-1); } // get time for current dump generated rawTime = time(NULL); if((timerInfo = localtime(&rawTime)) == NULL){ Log(error, INTERNAL_ERROR); Trace("WriteCoreDumpInternal: failed localtime."); exit(-1); } strftime(date, 26, "%Y-%m-%d_%H:%M:%S", timerInfo); // assemble the command if(sprintf(command, "gcore -o %s_%s_%s %d 2>&1", name, desc, date, pid) < 0){ Log(error, INTERNAL_ERROR); Trace("WriteCoreDumpInternal: failed sprintf gcore command"); exit(-1); } // assemble filename if(sprintf(coreDumpFileName, "%s_%s_%s.%d", name, desc, date, pid) < 0){ Log(error, INTERNAL_ERROR); Trace("WriteCoreDumpInternal: failed sprintf core file name"); exit(-1); } free(name); // generate core dump for given process commandPipe = popen2(command, "r", &gcorePid); self->Config->gcorePid = gcorePid; if(commandPipe == NULL){ Log(error, "An error occured while generating the core dump"); Trace("WriteCoreDumpInternal: Failed to open pipe to gcore"); exit(1); } // read all output from gcore command for(i = 0; i < MAX_LINES && fgets(lineBuffer, sizeof(lineBuffer), commandPipe) != NULL; i++) { lineLength = strlen(lineBuffer); // get # of characters read outputBuffer[i] = (char*)malloc(sizeof(char) * lineLength); if(outputBuffer[i] != NULL) { strncpy(outputBuffer[i], lineBuffer, lineLength - 1); // trim newline off outputBuffer[i][lineLength-1] = '\0'; // append null character } else { Log(error, INTERNAL_ERROR); Trace("WriteCoreDumpInternal: failed to allocate gcore error message buffer"); exit(-1); } } // close pipe reading from gcore self->Config->gcorePid = NO_PID; // reset gcore pid so that signal handler knows we aren't dumping pclose(commandPipe); // check if gcore was able to generate the dump if(strstr(outputBuffer[i-1], "gcore: failed") != NULL){ Log(error, "An error occured while generating the core dump"); // log gcore message and free up memory for(int j = 0; j < i; j++){ if(outputBuffer[j] != NULL){ Log(error, "GCORE - %s", outputBuffer[j]); free(outputBuffer[j]); } } free(outputBuffer); exit(1); } self->Config->NumberOfDumpsCollected++; // safe to increment in crit section if (self->Config->NumberOfDumpsCollected >= self->Config->NumberOfDumpsToCollect) { SetEvent(&self->Config->evtQuit.event); // shut it down, we're done here rc = 1; } // validate that core dump file was generated if(access(coreDumpFileName, F_OK) != -1) { if(self->Config->nQuit){ // if we are in a quit state from interrupt delete partially generated core dump file if(sprintf(command, "rm -f %s", coreDumpFileName) < 0){ Trace("WriteCoreDumpInternal: Failed to print rm command"); exit(-1); } if(system(command) < 0){ Trace("WriteCoreDumpInternal: Failed to remove partial core dump"); exit(-1); } } else{ // log out sucessful core dump generated Log(info, "Core dump %d generated: %s", self->Config->NumberOfDumpsCollected, coreDumpFileName); } } return rc; } |
La décision de Microsoft de porter cet utilitaire de débogage vers Linux intervient deux mois après que Scott Guthrie – vice-président de Microsoft responsable de la division Cloud et Entreprise – a annoncé que près de la moitié des machines virtuelles Azure tournent sous Linux. Entre les lignes, il vient que l’adoption croissante du système d’exploitation open source sur sa plateforme cloud est l’un des moteurs de ce type d’initiatives qui vont se multiplier avec le temps.
En effet, ProcDump fait partie d’une boîte constituée d’une dizaine d’outils utiles pour le débogage, l’analyse des performances, la scrutation de processus, la vérification de l’intégrité des fichiers, etc. Bref, des « must have » pour les administrateurs système et les chercheurs en sécurité. Le prochain outil que Microsoft a promis sur cette liste est ProcMon – un outil qui permet d’effectuer le suivi et l’affichage en temps réel des activités sur un système de fichiers.
Le portage des outils SysInternals sur Linux fait suite à la mise à disposition de .Net Core pour Linux ainsi qu’a celle de Microsoft SQL Server pour l’OS open source (le SGBD était jusque là l’un des rares à ne pas tourner sous Linux). La firme de Redmond y gagne, car il s’agit grosso modo d’initiatives destinées à garder la main sur sa plus grosse source de revenus actuelle – le cloud. Vu sous un certain angle, c’est aussi la communauté open source qui s’en sort haut la main. En effet, on est rendus au stade où c’est « Microsoft qui développe des applications pour Linux » et qui cède plus de 600 000 brevets pour protéger le système d'exploitation open source.
Sources : Twitter, GitHub
Et vous ?
Qu’en pensez-vous ?
Le jeu d’outils SysInternals est-il meilleur que celui disponible en natif sous Linux ?
Que vous inspire l’intérêt grandissant de Microsoft pour Linux ? Quel impact sur l’écosystème IT sur le long terme ?
Qui sera le grand vainqueur au finish ? Microsoft ou la communauté ?
Voir aussi :
Une nouvelle distribution « optimisée » pour le sous-système Windows pour Linux est disponible sur le Microsoft Store pour un coût
Rachat de GitHub par Microsoft : la fondation Linux livre son analyse de la situation et affirme avoir « hâte de voir les améliorations » sur GitHub
Quelles sont les entreprises qui contribuent le plus aux projets open source ? Microsoft positionné en tête sur GitHub
Microsoft rend un échantillon du sous-système Windows pour Linux open source à l'intention des mainteneurs de distributions