remove extra parens from debug print, as it has too many
[gnash.git] / utilities / dumpshm.cpp
blob5438906978613b1c9a4b1e44b0dbc4b262855eea
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
3 // Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
23 #include "GnashSystemIOHeaders.h" // write()
24 #include <cstdarg>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <fcntl.h>
28 #include <cerrno>
30 extern "C"{
31 #ifdef HAVE_GETOPT_H
32 #include <getopt.h>
33 #endif
34 #ifndef __GNUC__
35 extern int optind, getopt(int, char *const *, const char *);
36 extern char *optarg;
37 #endif
39 #include <dirent.h>
40 #include <sys/types.h>
41 #if !defined(HAVE_WINSOCK_H) && !defined(__riscos__) && !defined(__OS2__) && !defined(__amigaos4__)
42 #include <sys/mman.h>
43 #include <sys/shm.h>
44 #include <sys/ipc.h>
45 #elif !defined(__riscos__) && !defined(__OS2__) && !defined(__amigaos4__)
46 #include <windows.h>
47 #include <process.h>
48 #include <io.h>
49 #endif
50 #include <iostream>
51 #include <iomanip>
52 #include <fstream>
53 #include <string>
54 #include <map>
55 #if defined(__STDC_HOSTED__) || !defined(__GNUC__)
56 #include <sstream>
57 #else
58 #include <strstream>
59 #endif
60 #include <cstdio>
61 #include <cerrno>
63 #ifdef ENABLE_NLS
64 # include <clocale>
65 #endif
67 #include "log.h"
68 #include "rc.h"
69 #include "shm.h"
70 #include "gnash.h"
71 #include "amf.h"
72 #include "lcshm.h"
74 using namespace std;
75 using namespace gnash;
77 #ifdef BOOST_NO_EXCEPTIONS
78 namespace boost
81 void throw_exception(std::exception const & e)
83 std::abort();
86 #endif
88 // #error "No supported shared memory type for this platform"
90 static void usage (void);
91 void dump_ctrl(void *ptr);
92 void dump_shm(bool convert, bool out);
93 key_t list_lcs();
95 const int PIDSTART = 20000;
96 const int PIDEND = 23000;
97 const int LINELEN = 80;
98 const unsigned int LOOPCNT = 5;
99 const int DEFAULT_SHM_SIZE = 64528;
101 #ifndef SHM_STAT
102 const int SHM_STAT = 13;
103 const int SHM_INFO = 14;
104 #endif
106 namespace {
107 gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
108 gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
111 const char *DUMPSHM_VERSION = "0.5";
114 main(int argc, char *argv[])
116 int c;
117 bool listfiles = false;
118 bool sysv = false;
119 bool convert = false;
120 int size = 0;
121 string filespec, realname, tmpname;
122 vector<const char *> dirlist;
124 // Enable native language support, i.e. internationalization
125 #ifdef ENABLE_NLS
126 std::setlocale (LC_ALL, "");
127 bindtextdomain (PACKAGE, LOCALEDIR);
128 textdomain (PACKAGE);
129 #endif
130 // scan for the two main standard GNU options
131 for (c = 0; c < argc; c++) {
132 if (strcmp("--help", argv[c]) == 0) {
133 usage();
134 exit(EXIT_SUCCESS);
136 if (strcmp("--version", argv[c]) == 0) {
137 printf (_("Gnash dumpshm version: %s, Gnash version: %s\n"),
138 DUMPSHM_VERSION, VERSION);
139 exit(EXIT_SUCCESS);
143 while ((c = getopt (argc, argv, "hircv")) != -1) {
144 switch (c) {
145 case 'h':
146 usage ();
147 break;
149 case 'r':
150 sysv = true;
151 convert = false;
152 break;
154 case 'c':
155 sysv = true;
156 convert = true;
157 break;
159 case 'i':
160 sysv = true;
161 listfiles = true;
162 break;
164 case 'v':
165 // turn on verbosity for the libraries
166 dbglogfile.setVerbosity();
167 break;
169 default:
170 usage ();
171 break;
176 // If no command line arguments have been supplied, do nothing but
177 // print the usage message.
178 if (argc < 2) {
179 usage();
180 exit(EXIT_SUCCESS);
183 #if defined(USE_SYSV_SHM) && defined(HAVE_IPC_INFO)
184 // Just list the shared memory segments
185 if (listfiles && sysv) {
186 list_lcs();
187 exit(EXIT_SUCCESS);
189 #endif
191 if (optind <= argc - 1) {
192 if (*argv[optind] == '-') {
193 filespec = '-';
197 if (sysv) {
198 if (filespec == "-") {
199 dump_shm(convert, true);
200 } else {
201 dump_shm(convert, false);
204 exit(EXIT_SUCCESS);
207 if (size == 0) {
208 size = DEFAULT_SHM_SIZE;
211 // get the file name from the command line
212 if (optind < argc) {
213 filespec = argv[optind];
214 if (!convert) {
215 log_debug(_("Will use \"%s\" for memory segment file"), filespec);
221 // Dump the older style SYS V shared memory segments
222 void
223 dump_shm(bool convert, bool out)
225 // These are here for debugging purposes. It
226 char *shmaddr;
228 key_t key = rcfile.getLCShmKey();
230 if (key == 0) {
231 log_debug(_("No LcShmKey set in ~/.gnashrc, trying to find it ourselves"));
232 #if defined(USE_SYSV_SHM) && defined(HAVE_IPC_INFO)
233 key = list_lcs();
234 #endif
237 int size = 64528; // 1007 bytes less than unsigned
239 if (key == 0) {
240 log_debug(_("No shared memory segments found!"));
241 return;
243 if (dbglogfile.getVerbosity()) {
244 log_debug(_("Existing SHM Key is: %s, Size is: %s"),
245 boost::io::group(hex, showbase, key), size);
248 amf::LcShm lc;
249 lc.connect(key);
250 lc.dump();
252 // If the -c convert options was specified, dump the memory segment to disk.
253 // This makes it easy to store them as well as to examine them in great detail.
254 if (convert) {
255 int fd = open("segment.raw",O_WRONLY|O_CREAT, S_IRWXU);
256 if (fd == -1) {
257 perror("open");
259 log_debug(_("Writing memory segment to disk: \"segment.raw\""));
260 shmaddr = lc.getAddr();
261 write(fd, shmaddr, size);
262 if (out) {
263 #if 0
264 log_debug(_("The data is: 0x%s"), hexify((uint8_t *)shmaddr, size, false));
265 #endif
268 close(fd);
271 exit (EXIT_SUCCESS);
274 #if defined(USE_SYSV_SHM) && defined(HAVE_IPC_INFO)
275 key_t
276 list_lcs()
278 int maxid, shmid, id;
279 struct shmid_ds shmseg;
281 // #ifdef USE_POSIX_SHM
282 // if (library_dir != NULL) {
283 // for (i=0; entry>0; i++) {
284 // entry = readdir(library_dir);
285 // if (entry != NULL) {
286 // cout << "Found segment: " << entry->d_name << endl;
287 // }
288 // }
289 // } else {
290 // cout << _("Sorry, we can only list the files on systems with"
291 // " disk based shared memory") << endl;
292 // }
293 // #eendif
295 // If we're using SYSV shared memory, we can get a list of shared memory segments.
296 // By examing the size of each one, we can make a reasonable guess if it's one
297 // used for flash. As permissions apply, this will only list the segments created
298 // by the user running dumpshm.
299 // struct shm_info shm_info;
300 // maxid = shmctl(0, SHM_INFO, (struct shmid_ds *) (void *) &shm_info);
301 struct shmid_ds shm_info;
302 maxid = shmctl(0, SHM_INFO, &shm_info);
303 if (maxid < 0) {
304 log_debug(_("kernel not configured for shared memory"));
305 return 0;
308 // struct shminfo shminfo;
309 if ((shmctl(0, IPC_INFO, &shm_info)) < 0) {
310 return 0;
312 for (id = 0; id <= maxid; id++) {
313 shmid = shmctl(id, SHM_STAT, &shmseg);
314 if (shmid < 0) {
315 continue;
317 #ifdef IPC_PERM_KEY
318 if (shmseg.shm_segsz == 64528) {
319 log_debug(_("Found it! \"set LCShmKey %s\" in your ~/.gnashrc"),
320 boost::io::group(hex, showbase,
321 shmseg.shm_perm.IPC_PERM_KEY));
322 log_debug(_("Last changed on: %s"), ctime(&shmseg.shm_ctime));
323 log_debug(_("Last attached on: %s"), ctime(&shmseg.shm_atime));
324 log_debug(_("Last detached on: %s"), ctime(&shmseg.shm_dtime));
325 return shmseg.shm_perm.IPC_PERM_KEY;
327 #endif // end of IPC_PERM_KEY
329 // #else
330 // # error "No supported shared memory type for this platform"
331 //#endif // end of USE_POSIX_SHM
333 // Didn't find any segments of the right size
334 return static_cast<key_t>(0);
336 #endif // end of USE_SYSV_SHM & HAVE_IPC_INFO
338 /// \brief Display the command line arguments
339 static void
340 usage (void)
342 cerr << _("This program dumps the internal data of a shared memory segment")
343 << endl;
344 cerr << _("Usage: dumpshm [hdsanlif] filename") << endl;
345 cerr << _("-h\tHelp") << endl;
346 cerr << _("-i\tList segments") << endl;
347 cerr << _("-r\tDump SYSV segments") << endl;
348 cerr << _("-c\tDump SYSV segments to disk") << endl;
349 cerr << _("-v\tVerbose output") << endl;
350 exit (EXIT_FAILURE);
353 /// \brief Dumps the internal data of the found ShmControl
354 /// block. We do our own dumping, rather than letting
355 /// ShmControl::dump() do it, cause that's for debugging,
356 /// and this is for user display purposes.
357 void dump_ctrl(void *inmem)
359 Shm *ptr = static_cast<Shm *>(inmem);
361 cerr << _("\tBase address of this segment: ")
362 << static_cast<void *>(ptr->getAddr()) << endl;
363 cerr << _("\tFilespec: ") << ptr->getName() << endl;
364 cerr << _("\t# Bytes allocated: ") << ptr->getAllocated() << endl;
365 cerr << _("\tTotal # of bytes: ") << ptr->getSize() << endl;
368 // Local Variables:
369 // mode: C++
370 // indent-tabs-mode: t
371 // End: